diff --git a/src/AudioEffectAnalogChorus.h b/src/AudioEffectAnalogChorus.h index d0ee022..5dbd810 100644 --- a/src/AudioEffectAnalogChorus.h +++ b/src/AudioEffectAnalogChorus.h @@ -64,7 +64,6 @@ public: /// Construct an analog chorus using external SPI via an ExtMemSlot. The chorus will have /// the default average delay. /// @param slot A pointer to the ExtMemSlot to use for the delay. - AudioEffectAnalogChorus(BALibrary::ExtMemSlot *slot); // requires sufficiently sized pre-allocated memory virtual ~AudioEffectAnalogChorus(); ///< Destructor diff --git a/src/AudioEffectAnalogDelay.h b/src/AudioEffectAnalogDelay.h deleted file mode 100644 index 86d4ea6..0000000 --- a/src/AudioEffectAnalogDelay.h +++ /dev/null @@ -1,199 +0,0 @@ -/**************************************************************************//** - * @file - * @author Steve Lascos - * @company Blackaddr Audio - * - * AudioEffectAnalogDelay is a class for simulating a classic BBD based delay - * like the Boss DM-2. This class works with either internal RAM, or external - * SPI RAM for longer delays. The exteranl ram uses DMA to minimize load on the - * CPU. - * - * @copyright This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#ifndef __BAEFFECTS_BAAUDIOEFFECTANALOGDELAY_H -#define __BAEFFECTS_BAAUDIOEFFECTANALOGDELAY_H - -#include -#include "LibBasicFunctions.h" - -namespace BAEffects { - -/**************************************************************************//** - * AudioEffectAnalogDelay models BBD based analog delays. It provides controls - * for delay, feedback (or regen), mix and output level. All parameters can be - * controlled by MIDI. The class supports internal memory, or external SPI - * memory by providing an ExtMemSlot. External memory access uses DMA to reduce - * process load. - *****************************************************************************/ -class AudioEffectAnalogDelay : public AudioStream { -public: - - ///< List of AudioEffectAnalogDelay MIDI controllable parameters - enum { - BYPASS = 0, ///< controls effect bypass - DELAY, ///< controls the amount of delay - FEEDBACK, ///< controls the amount of echo feedback (regen) - MIX, ///< controls the the mix of input and echo signals - VOLUME, ///< controls the output volume level - NUM_CONTROLS ///< this can be used as an alias for the number of MIDI controls - }; - - enum class Filter { - DM3 = 0, - WARM, - DARK - }; - - // *** CONSTRUCTORS *** - AudioEffectAnalogDelay() = delete; - - /// Construct an analog delay using internal memory by specifying the maximum - /// delay in milliseconds. - /// @param maxDelayMs maximum delay in milliseconds. Larger delays use more memory. - AudioEffectAnalogDelay(float maxDelayMs); - - /// Construct an analog delay using internal memory by specifying the maximum - /// delay in audio samples. - /// @param numSamples maximum delay in audio samples. Larger delays use more memory. - AudioEffectAnalogDelay(size_t numSamples); - - /// Construct an analog delay using external SPI via an ExtMemSlot. The amount of - /// delay will be determined by the amount of memory in the slot. - /// @param slot A pointer to the ExtMemSlot to use for the delay. - AudioEffectAnalogDelay(BALibrary::ExtMemSlot *slot); // requires sufficiently sized pre-allocated memory - - virtual ~AudioEffectAnalogDelay(); ///< Destructor - - // *** PARAMETERS *** - - /// Set the delay in milliseconds. - /// @param milliseconds the request delay in milliseconds. Must be less than max delay. - void delay(float milliseconds); - - /// Set the delay in number of audio samples. - /// @param delaySamples the request delay in audio samples. Must be less than max delay. - void delay(size_t delaySamples); - - /// Set the delay as a fraction of the maximum delay. - /// The value should be between 0.0f and 1.0f - void delayFractionMax(float delayFraction); - - /// Bypass the effect. - /// @param byp when true, bypass wil disable the effect, when false, effect is enabled. - /// Note that audio still passes through when bypass is enabled. - void bypass(bool byp) { m_bypass = byp; } - - /// Get if the effect is bypassed - /// @returns true if bypassed, false if not bypassed - bool isBypass() { return m_bypass; } - - /// Toggle the bypass effect - void toggleBypass() { m_bypass = !m_bypass; } - - /// Set the amount of echo feedback (a.k.a regeneration). - /// @param feedback a floating point number between 0.0 and 1.0. - void feedback(float feedback) { m_feedback = feedback; } - - /// Set the amount of blending between dry and wet (echo) at the output. - /// @param mix When 0.0, output is 100% dry, when 1.0, output is 100% wet. When - /// 0.5, output is 50% Dry, 50% Wet. - void mix(float mix) { m_mix = mix; } - - /// Set the output volume. This affect both the wet and dry signals. - /// @details The default is 1.0. - /// @param vol Sets the output volume between -1.0 and +1.0 - void volume(float vol) {m_volume = vol; } - - // ** ENABLE / DISABLE ** - - /// Enables audio processing. Note: when not enabled, CPU load is nearly zero. - void enable() { m_enable = true; } - - /// Disables audio process. When disabled, CPU load is nearly zero. - void disable() { m_enable = false; } - - // ** MIDI ** - - /// Sets whether MIDI OMNI channel is processig on or off. When on, - /// all midi channels are used for matching CCs. - /// @param isOmni when true, all channels are processed, when false, channel - /// must match configured value. - void setMidiOmni(bool isOmni) { m_isOmni = isOmni; } - - /// Configure an effect parameter to be controlled by a MIDI CC - /// number on a particular channel. - /// @param parameter one of the parameter names in the class enum - /// @param midiCC the CC number from 0 to 127 - /// @param midiChannel the effect will only response to the CC on this channel - /// when OMNI mode is off. - void mapMidiControl(int parameter, int midiCC, int midiChannel = 0); - - /// process a MIDI Continous-Controller (CC) message - /// @param channel the MIDI channel from 0 to 15) - /// @param midiCC the CC number from 0 to 127 - /// @param value the CC value from 0 to 127 - void processMidi(int channel, int midiCC, int value); - - // ** FILTER COEFFICIENTS ** - - /// Set the filter coefficients to one of the presets. See AudioEffectAnalogDelay::Filter - /// for options. - /// @details See AudioEffectAnalogDelayFIlters.h for more details. - /// @param filter the preset filter. E.g. AudioEffectAnalogDelay::Filter::WARM - void setFilter(Filter filter); - - /// Override the default coefficients with your own. The number of filters stages affects how - /// much CPU is consumed. - /// @details The effect uses the CMSIS-DSP library for biquads which requires coefficents. - /// be in q31 format, which means they are 32-bit signed integers representing -1.0 to slightly - /// less than +1.0. The coeffShift parameter effectively multiplies the coefficients by 2^shift.
- /// Example: If you really want +1.5, must instead use +0.75 * 2^1, thus 0.75 in q31 format is - /// (0.75 * 2^31) = 1610612736 and coeffShift = 1. - /// @param numStages the actual number of filter stages you want to use. Must be <= MAX_NUM_FILTER_STAGES. - /// @param coeffs pointer to an integer array of coefficients in q31 format. - /// @param coeffShift Coefficient scaling factor = 2^coeffShift. - void setFilterCoeffs(int numStages, const int32_t *coeffs, int coeffShift); - - virtual void update(void); ///< update automatically called by the Teesny Audio Library - -private: - audio_block_t *m_inputQueueArray[1]; - bool m_isOmni = false; - bool m_bypass = true; - bool m_enable = false; - bool m_externalMemory = false; - BALibrary::AudioDelay *m_memory = nullptr; - size_t m_maxDelaySamples = 0; - audio_block_t *m_previousBlock = nullptr; - audio_block_t *m_blockToRelease = nullptr; - BALibrary::IirBiQuadFilterHQ *m_iir = nullptr; - - // Controls - int m_midiConfig[NUM_CONTROLS][2]; // stores the midi parameter mapping - size_t m_delaySamples = 0; - float m_feedback = 0.0f; - float m_mix = 0.0f; - float m_volume = 1.0f; - - void m_preProcessing(audio_block_t *out, audio_block_t *dry, audio_block_t *wet); - void m_postProcessing(audio_block_t *out, audio_block_t *dry, audio_block_t *wet); - - // Coefficients - void m_constructFilter(void); -}; - -} - -#endif /* __BAEFFECTS_BAAUDIOEFFECTANALOGDELAY_H */ diff --git a/src/AudioEffectSOS.h b/src/AudioEffectSOS.h deleted file mode 100644 index 2ab7e8d..0000000 --- a/src/AudioEffectSOS.h +++ /dev/null @@ -1,149 +0,0 @@ -/**************************************************************************//** - * @file - * @author Steve Lascos - * @company Blackaddr Audio - * - * AudioEffectSOS is a class f - * - * @copyright This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#ifndef __BAEFFECTS_BAAUDIOEFFECTSOS_H -#define __BAEFFECTS_BAAUDIOEFFECTSOS_H - -#include -#include "LibBasicFunctions.h" - -namespace BAEffects { - -/**************************************************************************//** - * AudioEffectSOS - *****************************************************************************/ -class AudioEffectSOS : public AudioStream { -public: - - ///< List of AudioEffectAnalogDelay MIDI controllable parameters - enum { - BYPASS = 0, ///< controls effect bypass - GATE_TRIGGER, ///< begins the gate sequence - GATE_OPEN_TIME, ///< controls how long it takes to open the gate - //GATE_HOLD_TIME, ///< controls how long the gate stays open at unity - GATE_CLOSE_TIME, ///< controls how long it takes to close the gate (release) - CLEAR_FEEDBACK_TRIGGER, ///< begins the sequence to clear out the looping feedback - FEEDBACK, ///< controls the amount of feedback, more gives longer SOS sustain - VOLUME, ///< controls the output volume level - NUM_CONTROLS ///< this can be used as an alias for the number of MIDI controls - }; - - // *** CONSTRUCTORS *** - AudioEffectSOS() = delete; - AudioEffectSOS(float maxDelayMs); - AudioEffectSOS(size_t numSamples); - - /// Construct an analog delay using external SPI via an ExtMemSlot. The amount of - /// delay will be determined by the amount of memory in the slot. - /// @param slot A pointer to the ExtMemSlot to use for the delay. - AudioEffectSOS(BALibrary::ExtMemSlot *slot); // requires sufficiently sized pre-allocated memory - - virtual ~AudioEffectSOS(); ///< Destructor - - void setGateLedGpio(int pinId); - - // *** PARAMETERS *** - void gateOpenTime(float milliseconds); - - void gateCloseTime(float milliseconds); - - void feedback(float feedback) { m_feedback = feedback; } - - /// Bypass the effect. - /// @param byp when true, bypass wil disable the effect, when false, effect is enabled. - /// Note that audio still passes through when bypass is enabled. - void bypass(bool byp) { m_bypass = byp; } - - /// Activate the gate automation. Input gate will open, then close. - void trigger() { m_inputGateAuto.trigger(); } - - /// Activate the delay clearing automation. Input signal will mute, gate will open, then close. - void clear() { m_clearFeedbackAuto.trigger(); } - - /// Set the output volume. This affect both the wet and dry signals. - /// @details The default is 1.0. - /// @param vol Sets the output volume between -1.0 and +1.0 - void volume(float vol) {m_volume = vol; } - - // ** ENABLE / DISABLE ** - - /// Enables audio processing. Note: when not enabled, CPU load is nearly zero. - void enable(); - - /// Disables audio process. When disabled, CPU load is nearly zero. - void disable() { m_enable = false; } - - // ** MIDI ** - - /// Sets whether MIDI OMNI channel is processig on or off. When on, - /// all midi channels are used for matching CCs. - /// @param isOmni when true, all channels are processed, when false, channel - /// must match configured value. - void setMidiOmni(bool isOmni) { m_isOmni = isOmni; } - - /// Configure an effect parameter to be controlled by a MIDI CC - /// number on a particular channel. - /// @param parameter one of the parameter names in the class enum - /// @param midiCC the CC number from 0 to 127 - /// @param midiChannel the effect will only response to the CC on this channel - /// when OMNI mode is off. - void mapMidiControl(int parameter, int midiCC, int midiChannel = 0); - - /// process a MIDI Continous-Controller (CC) message - /// @param channel the MIDI channel from 0 to 15) - /// @param midiCC the CC number from 0 to 127 - /// @param value the CC value from 0 to 127 - void processMidi(int channel, int midiCC, int value); - - virtual void update(void); ///< update automatically called by the Teesny Audio Library - -private: - audio_block_t *m_inputQueueArray[1]; - bool m_isOmni = false; - bool m_bypass = true; - bool m_enable = false; - BALibrary::AudioDelay *m_memory = nullptr; - bool m_externalMemory = true; - audio_block_t *m_previousBlock = nullptr; - audio_block_t *m_blockToRelease = nullptr; - size_t m_maxDelaySamples = 0; - int m_gateLedPinId = -1; - - // Controls - int m_midiConfig[NUM_CONTROLS][2]; // stores the midi parameter mapping - size_t m_delaySamples = 0; - float m_openTimeMs = 0.0f; - float m_closeTimeMs = 0.0f; - float m_feedback = 0.0f; - float m_volume = 1.0f; - - // Automated Controls - BALibrary::ParameterAutomationSequence m_inputGateAuto = BALibrary::ParameterAutomationSequence(3); - BALibrary::ParameterAutomationSequence m_clearFeedbackAuto = BALibrary::ParameterAutomationSequence(3); - - // Private functions - void m_preProcessing (audio_block_t *out, audio_block_t *input, audio_block_t *delayedSignal); - void m_postProcessing(audio_block_t *out, audio_block_t *input); -}; - -} - -#endif /* __BAEFFECTS_BAAUDIOEFFECTSOS_H */ diff --git a/src/AudioEffectTremolo.h b/src/AudioEffectTremolo.h deleted file mode 100644 index 58de0cd..0000000 --- a/src/AudioEffectTremolo.h +++ /dev/null @@ -1,126 +0,0 @@ -/**************************************************************************//** - * @file - * @author Steve Lascos - * @company Blackaddr Audio - * - * Tremolo is a classic volume modulate effect. - * - * @copyright This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY__BAEFFECTS_AUDIOEFFECTDELAYEXTERNAL_H; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#ifndef __BAEFFECTS_AUDIOEFFECTTREMOLO_H -#define __BAEFFECTS_AUDIOEFFECTTREMOLO_H - -#include -#include "LibBasicFunctions.h" - -namespace BAEffects { - -/**************************************************************************//** - * AudioEffectTremolo - *****************************************************************************/ -class AudioEffectTremolo : public AudioStream { -public: - - ///< List of AudioEffectTremolo MIDI controllable parameters - enum { - BYPASS = 0, ///< controls effect bypass - RATE, ///< controls the rate of the modulation - DEPTH, ///< controls the depth of the modulation - WAVEFORM, ///< select the modulation waveform - VOLUME, ///< controls the output volume level - NUM_CONTROLS ///< this can be used as an alias for the number of MIDI controls - }; - - // *** CONSTRUCTORS *** - AudioEffectTremolo(); - - virtual ~AudioEffectTremolo(); ///< Destructor - - // *** PARAMETERS *** - void rate(float rateValue); - - void depth(float depthValue) { m_depth = depthValue; } - - void setWaveform(BALibrary::Waveform waveform); - - - /// Bypass the effect. - /// @param byp when true, bypass wil disable the effect, when false, effect is enabled. - /// Note that audio still passes through when bypass is enabled. - void bypass(bool byp) { m_bypass = byp; } - - /// Get if the effect is bypassed - /// @returns true if bypassed, false if not bypassed - bool isBypass() { return m_bypass; } - - /// Toggle the bypass effect - void toggleBypass() { m_bypass = !m_bypass; } - - /// Set the output volume. This affect both the wet and dry signals. - /// @details The default is 1.0. - /// @param vol Sets the output volume between -1.0 and +1.0 - void volume(float vol) {m_volume = vol; } - - // ** ENABLE / DISABLE ** - - /// Enables audio processing. Note: when not enabled, CPU load is nearly zero. - void enable() { m_enable = true; } - - /// Disables audio process. When disabled, CPU load is nearly zero. - void disable() { m_enable = false; } - - // ** MIDI ** - - /// Sets whether MIDI OMNI channel is processig on or off. When on, - /// all midi channels are used for matching CCs. - /// @param isOmni when true, all channels are processed, when false, channel - /// must match configured value. - void setMidiOmni(bool isOmni) { m_isOmni = isOmni; } - - /// Configure an effect parameter to be controlled by a MIDI CC - /// number on a particular channel. - /// @param parameter one of the parameter names in the class enum - /// @param midiCC the CC number from 0 to 127 - /// @param midiChannel the effect will only response to the CC on this channel - /// when OMNI mode is off. - void mapMidiControl(int parameter, int midiCC, int midiChannel = 0); - - /// process a MIDI Continous-Controller (CC) message - /// @param channel the MIDI channel from 0 to 15) - /// @param midiCC the CC number from 0 to 127 - /// @param value the CC value from 0 to 127 - void processMidi(int channel, int midiCC, int value); - - - virtual void update(void); ///< update automatically called by the Teesny Audio Library - -private: - audio_block_t *m_inputQueueArray[1]; - BALibrary::LowFrequencyOscillatorVector m_osc; - int m_midiConfig[NUM_CONTROLS][2]; // stores the midi parameter mapping - bool m_isOmni = false; - bool m_bypass = true; - bool m_enable = false; - - float m_rate = 0.0f; - float m_depth = 0.0f; - BALibrary::Waveform m_waveform = BALibrary::Waveform::SINE; - float m_volume = 1.0f; - -}; - -} - -#endif /* __BAEFFECTS_AUDIOEFFECTTREMOLO_H */ diff --git a/src/BAAudioControlWM8731.h b/src/BAAudioControlWM8731.h deleted file mode 100644 index f0e5d6c..0000000 --- a/src/BAAudioControlWM8731.h +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************//** - * @file - * @author Steve Lascos - * @company Blackaddr Audio - * - * BAAudioContromWM8731 is a class for controlling a WM8731 Codec via I2C. - * @details The Codec power ups in a silent state, with non-optimal - * configuration. This class will enable codec and set some initial gain levels. - * The user can than use the API to changing settings for their specific needs. - * - * @copyright This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#ifndef __BALIBRARY_BAAUDIOCONTROLWM8731_H -#define __BALIBRARY_BAAUDIOCONTROLWM8731_H - -namespace BALibrary { - -constexpr int WM8731_NUM_REGS = 10; // Number of registers in the internal shadow array - -/**************************************************************************//** - * BAAudioControlWM8731 provides an API for configuring the internal registers - * of the WM8731 codec. - * @details Not every single command is provided, please ask if you need something - * added that is not already present. You can also directly write any register - * you wish with the writeI2C() method. - *****************************************************************************/ -class BAAudioControlWM8731 { -public: - BAAudioControlWM8731(); - virtual ~BAAudioControlWM8731(); - - /// Mute and power down the codec. - void disable(void); - - /// First disable, then cleanly power up and unmute the codec. - void enable(void); - - /// Set the input gain of the codec's PGA for the left (TRS Tip) channel. - /// @param val an interger value from 31 = +12dB . . 1.5dB steps down to 0 = -34.5dB - void setLeftInputGain(int val); - - /// Set the input gain of the codec's PGA for the right (TRS Ring) channel. - /// @param val an interger value from 31 = +12dB . . 1.5dB steps down to 0 = -34.5dB - void setRightInputGain(int val); - - /// Mute/unmute the Left (TRS Tip) channel at the ADC input. - /// @param val when true, channel is muted, when false, channel is unmuted - void setLeftInMute(bool val); - - /// Mute/unmute the Right (TRS Ring) channel at the ADC input. - /// @param val when true, channel is muted, when false, channel is unmuted - void setRightInMute(bool val); - - /// Links the Left/Right channel contols for mute and input gain. - /// @details when true, changing either the left or right gain/mute controls will - /// affect both channels. - /// @param val when true, channels are linked, when false, they are controlled separately - void setLinkLeftRightIn(bool val); - /// Swaps the left and right channels in the codec. - ///param val when true, channels are swapped, else normal. - void setLeftRightSwap(bool val); - - /// Set the volume for the codec's built-in headphone amp - /// @param volume the input volume level from 0.0f to 1.0f; - void setHeadphoneVolume(float volume); - - /// Mute/unmute the output DAC, affects both Left and Right output channels. - /// @param when true, output DAC is muted, when false, unmuted. - void setDacMute(bool val); - - /// Control when the DAC is feeding the output analog circuitry. - /// @param val when true, the DAC output is connected to the analog output. When - /// false, the DAC is disconnected. - void setDacSelect(bool val); - - /// ADC Bypass control. - /// @details This permits the analog audio from the Codec's PGA to bypass the ADC - /// and go directly to the analog output of the codec, bypassing the digital domain - /// entirely. - /// @param val when true, analog ADC input is fed directly to codec analog otuput. - void setAdcBypass(bool val); - - /// Digital High Pass Filter disable. RECOMMENDED ALWAYS TRUE! - /// @details this controls a HPF in the codec that attempts to remove the lowest - /// frequency (i.e. < 10 Hz) to improve headroom by dynamically measuring DC level. - /// In most cases, it introduces noise components by modulating the filter. This - /// is not suitable for applications where the audio is used for output, but might - /// be useful for applications like tuning, pitch detection, whre the noise components - /// can be tolerated. - /// @param val when true (recommended) the dynamic HPF is disabled, otherwise enabled. - void setHPFDisable(bool val); - - /// Activates the I2S interface on the codec. - /// @param val when true, I2S interface is active, when false it is disabled. - void setActivate(bool val); - - /// Soft-reset the codec. - /// @details This will cause the codec to reset its internal registers to default values. - void resetCodec(void); - - /// Write a custom command to the codec via I2C control interface. - /// @details See WM8731 datasheet for register map details. - /// @param addr The register address you wish to write to, range 0 to 15. - /// @param val the 9-bit data value you wish to write at the address specifed. - bool writeI2C(unsigned int addr, unsigned int val); - -protected: - // A shadow array for the registers on the codec since the interface is write-only. - int regArray[WM8731_NUM_REGS]; - -private: - // low-level write command - bool write(unsigned int reg, unsigned int val); - // resets the internal shadow register array - void resetInternalReg(void); - - bool m_wireStarted = false; - -}; - -} /* namespace BALibrary */ - -#endif /* __BALIBRARY_BAAUDIOCONTROLWM8731_H */ diff --git a/src/BAAudioEffectDelayExternal.h b/src/BAAudioEffectDelayExternal.h deleted file mode 100644 index 9e88b21..0000000 --- a/src/BAAudioEffectDelayExternal.h +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************//** - * @file - * @author Steve Lascos - * @company Blackaddr Audio - * - * BAAudioEffectDelayExternal is a class for using an external SPI SRAM chip - * as an audio delay line. The external memory can be shared among several - * different instances of BAAudioEffectDelayExternal by specifying the max delay - * length during construction. - * - * @copyright This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#ifndef __BAEFFECTS_BAAUDIOEFFECTDELAYEXTERNAL_H -#define __BAEFFECTS_BAAUDIOEFFECTDELAYEXTERNAL_H - -#include -#include "AudioStream.h" - -#include "BAHardware.h" - -namespace BAEffects { - -/**************************************************************************//** - * BAAudioEffectDelayExternal can use external SPI RAM for delay rather than - * the limited RAM available on the Teensy itself. - *****************************************************************************/ -class BAAudioEffectDelayExternal : public AudioStream -{ -public: - - /// Default constructor will use all memory available in MEM0 - BAAudioEffectDelayExternal(); - - /// Specifiy which external memory to use - /// @param type specify which memory to use - BAAudioEffectDelayExternal(BALibrary::MemSelect type); - - /// Specify external memory, and how much of the memory to use - /// @param type specify which memory to use - /// @param delayLengthMs maximum delay length in milliseconds - BAAudioEffectDelayExternal(BALibrary::MemSelect type, float delayLengthMs); - virtual ~BAAudioEffectDelayExternal(); - - /// set the actual amount of delay on a given delay tap - /// @param channel specify channel tap 1-8 - /// @param milliseconds specify how much delay for the specified tap - void delay(uint8_t channel, float milliseconds); - - /// Disable a delay channel tap - /// @param channel specify channel tap 1-8 - void disable(uint8_t channel); - - virtual void update(void); - - static unsigned m_usingSPICount[2]; // internal use for all instances - -private: - void initialize(BALibrary::MemSelect mem, unsigned delayLength = 1e6); - void read(uint32_t address, uint32_t count, int16_t *data); - void write(uint32_t address, uint32_t count, const int16_t *data); - void zero(uint32_t address, uint32_t count); - unsigned m_memoryStart; // the first address in the memory we're using - unsigned m_memoryLength; // the amount of memory we're using - unsigned m_headOffset; // head index (incoming) data into external memory - unsigned m_channelDelayLength[8]; // # of sample delay for each channel (128 = no delay) - unsigned m_activeMask; // which output channels are active - static unsigned m_allocated[2]; - audio_block_t *m_inputQueueArray[1]; - - BALibrary::MemSelect m_mem; - SPIClass *m_spi = nullptr; - int m_spiChannel = 0; - int m_misoPin = 0; - int m_mosiPin = 0; - int m_sckPin = 0; - int m_csPin = 0; - - void m_startUsingSPI(int spiBus); - void m_stopUsingSPI(int spiBus); -}; - - -} /* namespace BAEffects */ - -#endif /* __BAEFFECTS_BAAUDIOEFFECTDELAYEXTERNAL_H */ diff --git a/src/BAEffects.h b/src/BAEffects.h index c331137..f40eded 100644 --- a/src/BAEffects.h +++ b/src/BAEffects.h @@ -22,10 +22,6 @@ #include "BALibrary.h" // contains the Blackaddr hardware board definitions -#include "BAAudioEffectDelayExternal.h" -#include "AudioEffectAnalogDelay.h" -#include "AudioEffectSOS.h" -#include "AudioEffectTremolo.h" #include "AudioEffectAnalogChorus.h" #endif /* __BAEFFECTS_H */ diff --git a/src/BAGpio.h b/src/BAGpio.h deleted file mode 100644 index f7766af..0000000 --- a/src/BAGpio.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************//** - * @file - * @author Steve Lascos - * @company Blackaddr Audio - * - * BAGPio is convenience class for accessing the the various GPIOs available - * on the Teensy Guitar Audio series boards. - * - * @copyright This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#ifndef __BALIBRARY_BAGPIO_H -#define __BALIBRARY_BAGPIO_H - -#include "BAHardware.h" - -namespace BALibrary { - -/**************************************************************************//** - * BAGpio provides a convince class to easily control the direction and state - * of the GPIO pins available on the TGA headers. - * @details you can always control this directly with Arduino commands like - * digitalWrite(), etc. - *****************************************************************************/ -class BAGpio { -public: - /// Construct a GPIO object for controlling the various GPIO and user pins - BAGpio(); - virtual ~BAGpio(); - - /// Set the direction of the specified GPIO pin. - /// @param gpioId Specify a GPIO pin such as GPIO::GPIO0 - /// @param specify direction as INPUT or OUTPUT which are Arduino constants - void setGPIODirection(GPIO gpioId, int direction); - - /// Set the state of the specified GPIO to high - /// @param gpioId gpioId Specify a GPIO pin such as GPIO::GPIO0 - void setGPIO(GPIO gpioId); - - /// Clear the state of the specified GPIO pin. - /// @param gpioId gpioId Specify a GPIO pin such as GPIO::GPIO0 - void clearGPIO(GPIO gpioId); - - /// Toggle the state of the specified GPIO pin. Only works if configured as output. - /// @param gpioId gpioId Specify a GPIO pin such as GPIO::GPIO0 - /// @returns the new state of the pin - int toggleGPIO(GPIO gpioId); - - /// Turn on the user LED - void setLed(); - - /// Turn off the user LED - void clearLed(); - - /// Toggle the stage of the user LED - /// @returns the new stage of the user LED. - int toggleLed(); - -private: - uint8_t m_ledState; -}; - -} /* namespace BALibrary */ - -#endif /* __BALIBRARY_BAGPIO_H */ diff --git a/src/BAHardware.h b/src/BAHardware.h deleted file mode 100644 index 68e77db..0000000 --- a/src/BAHardware.h +++ /dev/null @@ -1,121 +0,0 @@ -/**************************************************************************//** - * @file - * @author Steve Lascos - * @company Blackaddr Audio - * - * This file contains specific definitions for each Blackaddr Audio hardware - * board. - * - * @copyright This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#ifndef __BALIBRARY_BAHARDWARE_H -#define __BALIBRARY_BAHARDWARE_H - -#include -#include -#include - -/**************************************************************************//** - * BALibrary is a namespace/Library for Guitar processing from Blackaddr Audio. - *****************************************************************************/ -namespace BALibrary { - -// uncomment the line that corresponds to your hardware -//#define TGA_PRO_REVA -#if (!defined(TGA_PRO_REVA) && !defined(TGA_PRO_REVB)) -#define TGA_PRO_REVA -#endif - -#if defined(TGA_PRO_REVA) || defined(TGA_PRO_REVB) - -constexpr uint8_t USR_LED_ID = 16; ///< Teensy IO number for the user LED. - -/**************************************************************************//** - * GPIOs and Testpoints are accessed via enumerated class constants. - *****************************************************************************/ -enum class GPIO : uint8_t { - GPIO0 = 2, - GPIO1 = 3, - GPIO2 = 4, - GPIO3 = 6, - - GPIO4 = 12, - GPIO5 = 32, - GPIO6 = 27, - GPIO7 = 28, - - TP1 = 34, - TP2 = 33 -}; - -/**************************************************************************//** - * Optionally installed SPI RAM - *****************************************************************************/ -constexpr unsigned NUM_MEM_SLOTS = 2; -enum MemSelect : unsigned { - MEM0 = 0, ///< SPI RAM MEM0 - MEM1 = 1 ///< SPI RAM MEM1 -}; - -/**************************************************************************//** - * Set the maximum address (byte-based) in the external SPI memories - *****************************************************************************/ -constexpr size_t MEM_MAX_ADDR[NUM_MEM_SLOTS] = { 131071, 131071 }; - - -/**************************************************************************//** - * General Purpose SPI Interfaces - *****************************************************************************/ -enum class SpiDeviceId : unsigned { - SPI_DEVICE0 = 0, ///< Arduino SPI device - SPI_DEVICE1 = 1 ///< Arduino SPI1 device -}; -constexpr int SPI_MAX_ADDR = 131071; ///< Max address size per chip -constexpr size_t SPI_MEM0_SIZE_BYTES = 131072; -constexpr size_t SPI_MEM0_MAX_AUDIO_SAMPLES = SPI_MEM0_SIZE_BYTES/sizeof(int16_t); - -constexpr size_t SPI_MEM1_SIZE_BYTES = 131072; -constexpr size_t SPI_MEM1_MAX_AUDIO_SAMPLES = SPI_MEM1_SIZE_BYTES/sizeof(int16_t); - - - -#else - -#error "No hardware declared" - -#endif - -#if defined (TGA_PRO_EXPAND_REV2) -/**************************************************************************//** - * Blackaddr Audio Expansion Board - *****************************************************************************/ -constexpr unsigned BA_EXPAND_NUM_POT = 3; -constexpr unsigned BA_EXPAND_NUM_SW = 2; -constexpr unsigned BA_EXPAND_NUM_LED = 2; -constexpr unsigned BA_EXPAND_NUM_ENC = 0; - -constexpr uint8_t BA_EXPAND_POT1_PIN = A16; // 35_A16_PWM -constexpr uint8_t BA_EXPAND_POT2_PIN = A17; // 36_A17_PWM -constexpr uint8_t BA_EXPAND_POT3_PIN = A18; // 37_SCL1_A18_PWM -constexpr uint8_t BA_EXPAND_SW1_PIN = 2; // 2)PWM -constexpr uint8_t BA_EXPAND_SW2_PIN = 3; // 3_SCL2_PWM -constexpr uint8_t BA_EXPAND_LED1_PIN = 4; // 4_SDA2_PWM -constexpr uint8_t BA_EXPAND_LED2_PIN = 6; // 6_PWM -#endif - -} // namespace BALibrary - - -#endif /* __BALIBRARY_BAHARDWARE_H */ diff --git a/src/BALibrary.h b/src/BALibrary.h index 9a0a3d3..456253c 100644 --- a/src/BALibrary.h +++ b/src/BALibrary.h @@ -20,15 +20,7 @@ #ifndef __BALIBRARY_H #define __BALIBRARY_H -#include "BAHardware.h" // contains the Blackaddr hardware board definitions - #include "BATypes.h" #include "LibBasicFunctions.h" -#include "LibMemoryManagement.h" - -#include "BAAudioControlWM8731.h" // Codec Control -#include "BASpiMemory.h" -#include "BAGpio.h" -#include "BAPhysicalControls.h" #endif /* __BALIBRARY_H */ diff --git a/src/BAPhysicalControls.h b/src/BAPhysicalControls.h deleted file mode 100644 index 859d698..0000000 --- a/src/BAPhysicalControls.h +++ /dev/null @@ -1,313 +0,0 @@ -/**************************************************************************//** - * @file - * @author Steve Lascos - * @company Blackaddr Audio - * - * BAPhysicalControls is a general purpose class for handling an array of - * pots, switches, rotary encoders and outputs (for LEDs or relays). - * - * @copyright This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ -#ifndef __BAPHYSICALCONTROLS_H -#define __BAPHYSICALCONTROLS_H - -#include -#include -#include - -namespace BALibrary { - -constexpr bool SWAP_DIRECTION = true; ///< Use when specifying direction should be swapped -constexpr bool NOSWAP_DIRECTION = false; ///< Use when specifying direction should not be swapped - -/// Convenience class for handling a digital output with regard to setting and toggling stage -class DigitalOutput { -public: - DigitalOutput() = delete; // delete the default constructor - - /// Construct an object to control the specified pin - /// @param pin the "Logical Arduino" pin number (not the physical pin number - DigitalOutput(uint8_t pin) : m_pin(pin) {} - - /// Set the output value - /// @param val when zero output is low, otherwise output his high - void set(int val); - - /// Toggle the output value current state - void toggle(void); - -private: - uint8_t m_pin; ///< store the pin associated with this output - int m_val = 0; ///< store the value to support toggling -}; - -/// Convenience class for handling digital inputs. This wraps Bounce with the abilty -/// to invert the polarity of the pin. -class DigitalInput : public Bounce { -public: - /// Create an input where digital low is return true. Most switches ground when pressed. - DigitalInput() : m_isPolarityInverted(true) {} - - /// Create an input and specify if input polarity is inverted. - /// @param isPolarityInverted when false, a high voltage on the pin returns true, 0V returns false. - DigitalInput(bool isPolarityInverted) : m_isPolarityInverted(isPolarityInverted) {} - - /// Read the state of the pin according to the polarity - /// @returns true when the input should be interpreted as the switch is closed, else false. - bool read() { return Bounce::read() != m_isPolarityInverted; } // logical XOR to conditionally invert polarity - - /// Set whether the input pin polarity - /// @param polarity when true, a low voltage on the pin is considered true by read(), else false. - void setPolarityInverted(bool polarity) { m_isPolarityInverted = polarity; } - - /// Check if input has toggled from low to high to low by looking for falling edges - /// @returns true if the switch has toggled - bool hasInputToggled(); - - /// Check if the input is asserted - /// @returns true if the switch is held - bool isInputAssert(); - - /// Get the raw input value (ignores polarity inversion) - /// @returns returns true is physical pin is high, else false - bool getPinInputValue(); - - /// Store the current switch state and return true if it has changed. - /// @param switchState variable to store switch state in - /// @returns true when switch stage has changed since last check - bool hasInputChanged(bool &switchState); - -private: - bool m_isPolarityInverted; - bool m_isPushed; -}; - -/// Convenience class for handling an analog pot as a control. When calibrated, -/// returns a float between 0.0 and 1.0. -class Potentiometer { -public: - /// Calibration data for a pot includes it's min and max value, as well as whether - /// direction should be swapped. Swapping depends on the physical orientation of the - /// pot. - struct Calib { - unsigned min; ///< The value from analogRead() when the pot is fully counter-clockwise (normal orientation) - unsigned max; ///< The value from analogRead() when the pot is fully clockwise (normal orientation) - bool swap; ///< when orientation is such that fully clockwise would give max reading, swap changes it to the min - }; - - Potentiometer() = delete; // delete the default constructor - - /// Construction requires the Arduino analog pin number, as well as calibration values. - /// @param analogPin The analog Arduino pin literal. This the number on the Teensy pinout preceeeded by an A in the local pin name. E.g. "A17". - /// @param minCalibration See Potentiometer::calibrate() - /// @param maxCalibration See Potentiometer::calibrate() - /// @param swapDirection Optional param. See Potentiometer::calibrate() - Potentiometer(uint8_t analogPin, unsigned minCalibration, unsigned maxCalibration, bool swapDirection = false); - - /// Get new value from the pot. - /// @param value reference to a float, the new value will be written here. Value is between 0.0 and 1.0f. - /// @returns true if the value has changed, false if it has not - bool getValue(float &value); - - /// Get the raw int value directly from analogRead() - /// @returns an integer between 0 and 1023. - int getRawValue(); - - /// Adjust the calibrate threshold. This is a factor that shrinks the calibration range slightly to - /// ensure the full range from 0.0f to 1.0f can be obtained. - /// @details temperature change can slightly alter the calibration values. This factor causes the value - /// to hit min or max just before the end of the pots travel to compensate. - /// @param thresholdFactor typical value is 0.01f to 0.05f - void adjustCalibrationThreshold(float thresholdFactor); - - /// Set the amount of feedback in the IIR filter used to smooth the pot readings - /// @details actual filter reponse deptnds on the rate you call getValue() - /// @param filterValue typical values are 0.80f to 0.95f - void setFeedbackFitlerValue(float fitlerValue); - - void setCalibrationValues(unsigned min, unsigned max, bool swapDirection); - - /// Call this static function before creating the object to obtain calibration data. The sequence - /// involves prompts over the Serial port. - /// @details E.g. call Potentiometer::calibrate(PIN). See BAExpansionCalibrate.ino in the library examples. - /// @param analogPin the Arduino analog pin number connected to the pot you wish to calibraate. - /// @returns populated Potentiometer::Calib structure - static Calib calibrate(uint8_t analogPin); - -private: - uint8_t m_pin; ///< store the Arduino pin literal, e.g. A17 - bool m_swapDirection; ///< swap when pot orientation is upside down - unsigned m_minCalibration; ///< stores the min pot value - unsigned m_maxCalibration; ///< stores the max pot value - unsigned m_lastValue = 0; ///< stores previous value - float m_feedbackFitlerValue = 0.9f; ///< feedback value for POT filter - float m_thresholdFactor = 0.05f; ///< threshold factor causes values pot to saturate faster at the limits, default is 5% - unsigned m_minCalibrationThresholded; ///< stores the min pot value after thresholding - unsigned m_maxCalibrationThresholded; ///< stores the max pot value after thresholding - unsigned m_rangeThresholded; ///< stores the range of max - min after thresholding -}; - -/// Convenience class for rotary (quadrature) encoders. Uses Arduino Encoder under the hood. -class RotaryEncoder : public Encoder { -public: - RotaryEncoder() = delete; // delete default constructor - - /// Constructor an encoder with the specified pins. Optionally swap direction and divide down the number of encoder ticks - /// @param pin1 the Arduino logical pin number for the 'A' on the encoder. - /// @param pin2 the Arduino logical pin number for the 'B' on the encoder. - /// @param swapDirection (OPTIONAL) set to true or false to obtain clockwise increments the counter-clockwise decrements - /// @param divider (OPTIONAL) controls the sensitivity of the divider. Use powers of 2. E.g. 1, 2, 4, 8, etc. - RotaryEncoder(uint8_t pin1, uint8_t pin2, bool swapDirection = false, int divider = 1) : Encoder(pin1,pin2), m_swapDirection(swapDirection), m_divider(divider) {} - - /// Get the delta (as a positive or negative number) since last call - /// @returns an integer representing the net change since last call - int getChange(); - - /// Set the divider on the internal counter. High resolution encoders without detents can be overly sensitive. - /// This will helf reduce sensisitive by increasing the divider. Default = 1. - /// @pram divider controls the sensitivity of the divider. Use powers of 2. E.g. 1, 2, 4, 8, etc. - void setDivider(int divider); - -private: - bool m_swapDirection; ///< specifies if increment/decrement should be swapped - int32_t m_lastPosition = 0; ///< store the last recorded position - int32_t m_divider; ///< divides down the magnitude of change read by the encoder. -}; - -/// Specifies the type of control -enum class ControlType : unsigned { - SWITCH_MOMENTARY = 0, ///< a momentary switch, which is only on when pressed. - SWITCH_LATCHING = 1, ///< a latching switch, which toggles between on and off with each press and release - ROTARY_KNOB = 2, ///< a rotary encoder knob - POT = 3, ///< an analog potentiometer - UNDEFINED = 255 ///< undefined or uninitialized -}; - -/// Tjis class provides convenient interface for combinary an arbitrary number of controls of different types into -/// one object. Supports switches, pots, encoders and digital outputs (useful for LEDs, relays). -class BAPhysicalControls { -public: - BAPhysicalControls() = delete; - - /// Construct an object and reserve memory for the specified number of controls. Encoders and outptus are optional params. - /// @param numSwitches the number of switches or buttons - /// @param numPots the number of analog potentiometers - /// @param numEncoders the number of quadrature encoders - /// @param numOutputs the number of digital outputs. E.g. LEDs, relays, etc. - BAPhysicalControls(unsigned numSwitches, unsigned numPots, unsigned numEncoders = 0, unsigned numOutputs = 0); - ~BAPhysicalControls() {} - - /// add a rotary encoders to the controls - /// @param pin1 the pin number corresponding to 'A' on the encoder - /// @param pin2 the pin number corresponding to 'B' on the encoder - /// @param swapDirection When true, reverses which rotation direction is positive, and which is negative - /// @param divider optional, for encoders with high resolution this divides down the rotation measurement. - /// @returns the index in the encoder vector the new encoder was placed at. - unsigned addRotary(uint8_t pin1, uint8_t pin2, bool swapDirection = false, int divider = 1); - - /// add a switch to the controls - /// @param pin the pin number connected to the switch - /// @param intervalMilliseconds, optional, specifies the filtering time to debounce a switch - /// @returns the index in the switch vector the new switch was placed at. - unsigned addSwitch(uint8_t pin, unsigned long intervalMilliseconds = 10); - - /// add a pot to the controls - /// @param pin the pin number connected to the wiper of the pot - /// @param minCalibration the value corresponding to lowest pot setting - /// @param maxCalibration the value corresponding to the highest pot setting - unsigned addPot(uint8_t pin, unsigned minCalibration, unsigned maxCalibration); - - /// add a pot to the controls - /// @param pin the pin number connected to the wiper of the pot - /// @param minCalibration the value corresponding to lowest pot setting - /// @param maxCalibration the value corresponding to the highest pot setting - /// @param swapDirection reverses the which direction is considered pot minimum value - /// @param range the pot raw value will be mapped into a range of 0 to range - unsigned addPot(uint8_t pin, unsigned minCalibration, unsigned maxCalibration, bool swapDirection); - - /// add an output to the controls - /// @param pin the pin number connected to the Arduino output - /// @returns a handle (unsigned) to the added output. Use this to access the output. - unsigned addOutput(uint8_t pin); - - /// Set the output specified by the provided handle - /// @param handle the handle that was provided previously by calling addOutput() - /// @param val the value to set the output. 0 is low, not zero is high. - void setOutput(unsigned handle, int val); - - /// Set the output specified by the provided handle - /// @param handle the handle that was provided previously by calling addOutput() - /// @param val the value to set the output. True is high, false is low. - void setOutput(unsigned handle, bool val); - - /// Toggle the output specified by the provided handle - /// @param handle the handle that was provided previously by calling addOutput() - void toggleOutput(unsigned handle); - - /// Retrieve the change in position on the specified rotary encoder - /// @param handle the handle that was provided previously by calling addRotary() - /// @returns an integer value. Positive is clockwise, negative is counter-clockwise rotation. - int getRotaryAdjustUnit(unsigned handle); - - /// Check if the pot specified by the handle has been updated. - /// @param handle the handle that was provided previously by calling addPot() - /// @param value a reference to a float, the pot value will be written to this variable. - /// @returns true if the pot value has changed since previous check, otherwise false - bool checkPotValue(unsigned handle, float &value); - - /// Get the raw uncalibrated value from the pot - /// @returns uncalibrated pot value - int getPotRawValue(unsigned handle); - - /// Override the calibration values with new values - /// @param handle handle the handle that was provided previously by calling addPot() - /// @param min the min raw value for the pot - /// @param max the max raw value for the pot - /// @param swapDirection when true, max raw value will mean min control value - /// @returns false when handle is out of range - bool setCalibrationValues(unsigned handle, unsigned min, unsigned max, bool swapDirection); - - /// Check if the switch has been toggled since last call - /// @param handle the handle that was provided previously by calling addSwitch() - /// @returns true if the switch changed state, otherwise false - bool isSwitchToggled(unsigned handle); - - /// Check if the switch is currently being pressed (held) - /// @param handle the handle that was provided previously by calling addSwitch() - /// @returns true if the switch is held in a pressed or closed state - bool isSwitchHeld(unsigned handle); - - /// Get the value of the switch - /// @param handle the handle that was provided previously by calling addSwitch() - /// @returns the value at the switch pin, either 0 or 1. - bool getSwitchValue(unsigned handle); - - /// Determine if a switch has changed value - /// @param handle the handle that was provided previously by calling addSwitch() - /// @param switchValue a boolean to store the new switch value - /// @returns true if the switch has changed - bool hasSwitchChanged(unsigned handle, bool &switchValue); - -private: - std::vector m_pots; ///< a vector of all added pots - std::vector m_encoders; ///< a vector of all added encoders - std::vector m_switches; ///< a vector of all added switches - std::vector m_outputs; ///< a vector of all added outputs -}; - - -} // BALibrary - - -#endif /* __BAPHYSICALCONTROLS_H */ diff --git a/src/BASpiMemory.h b/src/BASpiMemory.h deleted file mode 100644 index 92e83fc..0000000 --- a/src/BASpiMemory.h +++ /dev/null @@ -1,221 +0,0 @@ -/**************************************************************************//** - * @file - * @author Steve Lascos - * @company Blackaddr Audio - * - * BASpiMemory is convenience class for accessing the optional SPI RAMs on - * the GTA Series boards. BASpiMemoryDma works the same but uses DMA to reduce - * load on the processor. - * - * @copyright This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ -#ifndef __BALIBRARY_BASPIMEMORY_H -#define __BALIBRARY_BASPIMEMORY_H - -#include -#include - -#include "BATypes.h" -#include "BAHardware.h" - -namespace BALibrary { - -/**************************************************************************//** - * This wrapper class uses the Arduino SPI (Wire) library to access the SPI ram. - * @details The purpose of this class is primilary for functional testing since - * it currently support single-word access. High performance access should be - * done using DMA techniques in the Teensy library. - *****************************************************************************/ -class BASpiMemory { -public: - BASpiMemory() = delete; - /// Create an object to control either MEM0 (via SPI1) or MEM1 (via SPI2). - /// @details default is 20 Mhz - /// @param memDeviceId specify which MEM to control with SpiDeviceId. - BASpiMemory(SpiDeviceId memDeviceId); - /// Create an object to control either MEM0 (via SPI1) or MEM1 (via SPI2) - /// @param memDeviceId specify which MEM to control with SpiDeviceId. - /// @param speedHz specify the desired speed in Hz. - BASpiMemory(SpiDeviceId memDeviceId, uint32_t speedHz); - virtual ~BASpiMemory(); - - /// initialize and configure the SPI peripheral - virtual void begin(); - - /// write a single 8-bit word to the specified address - /// @param address the address in the SPI RAM to write to - /// @param data the value to write - void write(size_t address, uint8_t data); - - /// Write a block of 8-bit data to the specified address - /// @param address the address in the SPI RAM to write to - /// @param src pointer to the source data block - /// @param numBytes size of the data block in bytes - virtual void write(size_t address, uint8_t *src, size_t numBytes); - - /// Write a block of zeros to the specified address - /// @param address the address in the SPI RAM to write to - /// @param numBytes size of the data block in bytes - virtual void zero(size_t address, size_t numBytes); - - /// write a single 16-bit word to the specified address - /// @param address the address in the SPI RAM to write to - /// @param data the value to write - void write16(size_t address, uint16_t data); - - /// Write a block of 16-bit data to the specified address - /// @param address the address in the SPI RAM to write to - /// @param src pointer to the source data block - /// @param numWords size of the data block in 16-bit words - virtual void write16(size_t address, uint16_t *src, size_t numWords); - - /// Write a block of 16-bit zeros to the specified address - /// @param address the address in the SPI RAM to write to - /// @param numWords size of the data block in 16-bit words - virtual void zero16(size_t address, size_t numWords); - - /// read a single 8-bit data word from the specified address - /// @param address the address in the SPI RAM to read from - /// @return the data that was read - uint8_t read(size_t address); - - /// Read a block of 8-bit data from the specified address - /// @param address the address in the SPI RAM to write to - /// @param dest pointer to the destination - /// @param numBytes size of the data block in bytes - virtual void read(size_t address, uint8_t *dest, size_t numBytes); - - /// read a single 16-bit data word from the specified address - /// @param address the address in the SPI RAM to read from - /// @return the data that was read - uint16_t read16(size_t address); - - /// read a block 16-bit data word from the specified address - /// @param address the address in the SPI RAM to read from - /// @param dest the pointer to the destination - /// @param numWords the number of 16-bit words to transfer - virtual void read16(size_t address, uint16_t *dest, size_t numWords); - - /// Check if the class has been configured by a previous begin() call - /// @returns true if initialized, false if not yet initialized - bool isStarted() const { return m_started; } - -protected: - SPIClass *m_spi = nullptr; - SpiDeviceId m_memDeviceId; // the MEM device being control with this instance - uint8_t m_csPin; // the IO pin number for the CS on the controlled SPI device - SPISettings m_settings; // the Wire settings for this SPI port - bool m_started = false; - -}; - - -class BASpiMemoryDMA : public BASpiMemory { -public: - BASpiMemoryDMA() = delete; - - /// Create an object to control either MEM0 (via SPI1) or MEM1 (via SPI2). - /// @details default is 20 Mhz - /// @param memDeviceId specify which MEM to control with SpiDeviceId. - BASpiMemoryDMA(SpiDeviceId memDeviceId); - - /// Create an object to control either MEM0 (via SPI1) or MEM1 (via SPI2) - /// @param memDeviceId specify which MEM to control with SpiDeviceId. - /// @param speedHz specify the desired speed in Hz. - BASpiMemoryDMA(SpiDeviceId memDeviceId, uint32_t speedHz); - virtual ~BASpiMemoryDMA(); - - /// initialize and configure the SPI peripheral - void begin() override; - - /// Write a block of 8-bit data to the specified address. Be check - /// isWriteBusy() before sending the next DMA transfer. - /// @param address the address in the SPI RAM to write to - /// @param src pointer to the source data block - /// @param numBytes size of the data block in bytes - void write(size_t address, uint8_t *src, size_t numBytes) override; - - /// Write a block of zeros to the specified address. Be check - /// isWriteBusy() before sending the next DMA transfer. - /// @param address the address in the SPI RAM to write to - /// @param numBytes size of the data block in bytes - void zero(size_t address, size_t numBytes) override; - - /// Write a block of 16-bit data to the specified address. Be check - /// isWriteBusy() before sending the next DMA transfer. - /// @param address the address in the SPI RAM to write to - /// @param src pointer to the source data block - /// @param numWords size of the data block in 16-bit words - void write16(size_t address, uint16_t *src, size_t numWords) override; - - /// Write a block of 16-bit zeros to the specified address. Be check - /// isWriteBusy() before sending the next DMA transfer. - /// @param address the address in the SPI RAM to write to - /// @param numWords size of the data block in 16-bit words - void zero16(size_t address, size_t numWords) override; - - /// Read a block of 8-bit data from the specified address. Be check - /// isReadBusy() before sending the next DMA transfer. - /// @param address the address in the SPI RAM to write to - /// @param dest pointer to the destination - /// @param numBytes size of the data block in bytes - void read(size_t address, uint8_t *dest, size_t numBytes) override; - - /// read a block 16-bit data word from the specified address. Be check - /// isReadBusy() before sending the next DMA transfer. - /// @param address the address in the SPI RAM to read from - /// @param dest the pointer to the destination - /// @param numWords the number of 16-bit words to transfer - void read16(size_t address, uint16_t *dest, size_t numWords) override; - - /// Check if a DMA write is in progress - /// @returns true if a write DMA is in progress, else false - bool isWriteBusy() const; - - /// Check if a DMA read is in progress - /// @returns true if a read DMA is in progress, else false - bool isReadBusy() const; - - /// Readout the 8-bit contents of the DMA storage buffer to the specified destination - /// @param dest pointer to the destination - /// @param numBytes number of bytes to read out - /// @param byteOffset, offset from the start of the DMA buffer in bytes to begin reading - void readBufferContents(uint8_t *dest, size_t numBytes, size_t byteOffset = 0); - - /// Readout the 8-bit contents of the DMA storage buffer to the specified destination - /// @param dest pointer to the destination - /// @param numWords number of 16-bit words to read out - /// @param wordOffset, offset from the start of the DMA buffer in words to begin reading - void readBufferContents(uint16_t *dest, size_t numWords, size_t wordOffset = 0); - -private: - - DmaSpiGeneric *m_spiDma = nullptr; - AbstractChipSelect *m_cs = nullptr; - - uint8_t *m_txCommandBuffer = nullptr; - DmaSpi::Transfer *m_txTransfer; - uint8_t *m_rxCommandBuffer = nullptr; - DmaSpi::Transfer *m_rxTransfer; - - uint16_t m_txXferCount; - uint16_t m_rxXferCount; - - void m_setSpiCmdAddr(int command, size_t address, uint8_t *dest); -}; - - -} /* namespace BALibrary */ - -#endif /* __BALIBRARY_BASPIMEMORY_H */ diff --git a/src/DmaSpi.h b/src/DmaSpi.h deleted file mode 100644 index 9f57c25..0000000 --- a/src/DmaSpi.h +++ /dev/null @@ -1,1024 +0,0 @@ -#ifndef DMASPI_H -#define DMASPI_H - -#include -#include - -#if(!defined(__arm__) && defined(TEENSYDUINO)) - #error This library is for teensyduino 1.21 on Teensy 3.0, 3.1 and Teensy LC only. -#endif - -#include -#include "DMAChannel.h" -#include - - -/** \brief Specifies the desired CS suppression -**/ -enum TransferType -{ - NORMAL, //*< The transfer will use CS at beginning and end **/ - NO_START_CS, //*< Skip the CS activation at the start **/ - NO_END_CS //*< SKip the CS deactivation at the end **/ -}; - -/** \brief An abstract base class that provides an interface for chip select classes. -**/ -class AbstractChipSelect -{ - public: - /** \brief Called to select a chip. The implementing class can do other things as well. - **/ - virtual void select(TransferType transferType = TransferType::NORMAL) = 0; - - /** \brief Called to deselect a chip. The implementing class can do other things as well. - **/ - virtual void deselect(TransferType transferType = TransferType::NORMAL) = 0; - - /** \brief the virtual destructor needed to inherit from this class **/ - virtual ~AbstractChipSelect() {} -}; - - -/** \brief "do nothing" chip select class **/ -class DummyChipSelect : public AbstractChipSelect -{ - void select(TransferType transferType = TransferType::NORMAL) override {} - - void deselect(TransferType transferType = TransferType::NORMAL) override {} -}; - -/** \brief "do nothing" chip select class that - * outputs a message through Serial when something happens -**/ -class DebugChipSelect : public AbstractChipSelect -{ - void select(TransferType transferType = TransferType::NORMAL) override {Serial.println("Debug CS: select()");} - void deselect(TransferType transferType = TransferType::NORMAL) override {Serial.println("Debug CS: deselect()");} -}; - -/** \brief An active low chip select class. This also configures the given pin. - * Warning: This class is hardcoded to manage a transaction on SPI (SPI0, that is). - * If you want to use SPI1: Use AbstractChipSelect1 (see below) - * If you want to use SPI2: Create AbstractChipSelect2 (adapt the implementation accordingly). - * Something more flexible is on the way. -**/ -class ActiveLowChipSelect : public AbstractChipSelect -{ - public: - /** Configures a chip select pin for OUTPUT mode, - * manages the chip selection and a corresponding SPI transaction - * - * The chip select pin is asserted \e after the SPI settings are applied - * and deasserted before the SPI transaction ends. - * \param pin the CS pin to use - * \param settings which SPI settings to apply when the chip is selected - **/ - ActiveLowChipSelect(const unsigned int& pin, const SPISettings& settings) - : pin_(pin), - settings_(settings) - { - pinMode(pin, OUTPUT); - digitalWriteFast(pin, 1); - } - - /** \brief begins an SPI transaction selects the chip (sets the pin to low) and - **/ - void select(TransferType transferType = TransferType::NORMAL) override - { - SPI.beginTransaction(settings_); - if (transferType == TransferType::NO_START_CS) { - return; - } - digitalWriteFast(pin_, 0); - } - - /** \brief deselects the chip (sets the pin to high) and ends the SPI transaction - **/ - void deselect(TransferType transferType = TransferType::NORMAL) override - { - if (transferType == TransferType::NO_END_CS) { - } else { - digitalWriteFast(pin_, 1); - } - SPI.endTransaction(); - } - private: - const unsigned int pin_; - const SPISettings settings_; - -}; - -#if defined(__MK66FX1M0__) -class ActiveLowChipSelect1 : public AbstractChipSelect -{ - public: - /** Equivalent to AbstractChipSelect, but for SPI1. - **/ - ActiveLowChipSelect1(const unsigned int& pin, const SPISettings& settings) - : pin_(pin), - settings_(settings) - { - pinMode(pin, OUTPUT); - digitalWriteFast(pin, 1); - } - - /** \brief begins an SPI transaction selects the chip (sets the pin to low) and - **/ - void select(TransferType transferType = TransferType::NORMAL) override - { - SPI1.beginTransaction(settings_); - if (transferType == TransferType::NO_START_CS) { - return; - } - digitalWriteFast(pin_, 0); - } - - /** \brief deselects the chip (sets the pin to high) and ends the SPI transaction - **/ - void deselect(TransferType transferType = TransferType::NORMAL) override - { - if (transferType == TransferType::NO_END_CS) { - } else { - digitalWriteFast(pin_, 1); - } - SPI1.endTransaction(); - } - private: - const unsigned int pin_; - const SPISettings settings_; - -}; -#endif - - -//#define DEBUG_DMASPI 1 - -#if defined(DEBUG_DMASPI) - #define DMASPI_PRINT(x) do {Serial.printf x ; Serial.flush();} while (0); -#else - #define DMASPI_PRINT(x) do {} while (0); -#endif - -namespace DmaSpi -{ - /** \brief describes an SPI transfer - * - * Transfers are kept in a queue (intrusive linked list) until they are processed by the DmaSpi driver. - * - **/ - class Transfer - { - public: - /** \brief The Transfer's current state. - * - **/ - enum State - { - idle, /**< The Transfer is idle, the DmaSpi has not seen it yet. **/ - eDone, /**< The Transfer is done. **/ - pending, /**< Queued, but not handled yet. **/ - inProgress, /**< The DmaSpi driver is currently busy executing this Transfer. **/ - error /**< An error occured. **/ - }; - - /** \brief Creates a Transfer object. - * \param pSource pointer to the data source. If this is nullptr, the fill value is used instead. - * \param transferCount the number of SPI transfers to perform. - * \param pDest pointer to the data sink. If this is nullptr, data received from the slave will be discarded. - * \param fill if pSource is nullptr, this value is sent to the slave instead. - * \param cs pointer to a chip select object. - * If not nullptr, cs->select() is called when the Transfer is started and cs->deselect() is called when the Transfer is finished. - **/ - Transfer(const uint8_t* pSource = nullptr, - const uint16_t& transferCount = 0, - volatile uint8_t* pDest = nullptr, - const uint8_t& fill = 0, - AbstractChipSelect* cs = nullptr, - TransferType transferType = TransferType::NORMAL - ) : m_state(State::idle), - m_pSource(pSource), - m_transferCount(transferCount), - m_pDest(pDest), - m_fill(fill), - m_pNext(nullptr), - m_pSelect(cs), - m_transferType(transferType) - { - DMASPI_PRINT(("Transfer @ %p\n", this)); - }; - - /** \brief Check if the Transfer is busy, i.e. may not be modified. - **/ - bool busy() const {return ((m_state == State::pending) || (m_state == State::inProgress) || (m_state == State::error));} - - /** \brief Check if the Transfer is done. - **/ - bool done() const {return (m_state == State::eDone);} - -// private: - volatile State m_state; - const uint8_t* m_pSource; - uint16_t m_transferCount; - volatile uint8_t* m_pDest; - uint8_t m_fill; - Transfer* m_pNext; - AbstractChipSelect* m_pSelect; - TransferType m_transferType; - }; -} // namespace DmaSpi - - -template -class AbstractDmaSpi -{ - public: - using Transfer = DmaSpi::Transfer; - - /** \brief arduino-style initialization. - * - * During initialization, two DMA channels are allocated. If that fails, this function returns false. - * If the channels could be allocated, those DMA channel fields that don't change during DMA SPI operation - * are initialized to the values they will have at runtime. - * - * \return true if initialization was successful; false otherwise. - * \see end() - **/ - static bool begin() - { - if(init_count_ > 0) - { - return true; // this is not particularly bad, so we can return true - } - init_count_++; - DMASPI_PRINT(("DmaSpi::begin() : ")); - // create DMA channels, might fail - if (!createDmaChannels()) - { - DMASPI_PRINT(("could not create DMA channels\n")); - return false; - } - state_ = eStopped; - // tx: known destination (SPI), no interrupt, finish silently - begin_setup_txChannel(); - if (txChannel_()->error()) - { - destroyDmaChannels(); - DMASPI_PRINT(("tx channel error\n")); - return false; - } - - // rx: known source (SPI), interrupt on completion - begin_setup_rxChannel(); - if (rxChannel_()->error()) - { - destroyDmaChannels(); - DMASPI_PRINT(("rx channel error\n")); - return false; - } - - return true; - } - - static void begin_setup_txChannel() {DMASPI_INSTANCE::begin_setup_txChannel_impl();} - static void begin_setup_rxChannel() {DMASPI_INSTANCE::begin_setup_rxChannel_impl();} - - /** \brief Allow the DMA SPI to start handling Transfers. This must be called after begin(). - * \see running() - * \see busy() - * \see stop() - * \see stopping() - * \see stopped() - **/ - static void start() - { - DMASPI_PRINT(("DmaSpi::start() : state_ = ")); - switch(state_) - { - case eStopped: - DMASPI_PRINT(("eStopped\n")); - state_ = eRunning; - beginPendingTransfer(); - break; - - case eRunning: - DMASPI_PRINT(("eRunning\n")); - break; - - case eStopping: - DMASPI_PRINT(("eStopping\n")); - state_ = eRunning; - break; - - default: - DMASPI_PRINT(("unknown\n")); - state_ = eError; - break; - } - } - - /** \brief check if the DMA SPI is in running state. - * \return true if the DMA SPI is in running state, false otherwise. - * \see start() - * \see busy() - * \see stop() - * \see stopping() - * \see stopped() - **/ - static bool running() {return state_ == eRunning;} - - /** \brief register a Transfer to be handled by the DMA SPI. - * \return false if the Transfer had an invalid transfer count (zero or greater than 32767), true otherwise. - * \post the Transfer state is Transfer::State::pending, or Transfer::State::error if the transfer count was invalid. - **/ - static bool registerTransfer(Transfer& transfer) - { - DMASPI_PRINT(("DmaSpi::registerTransfer(%p)\n", &transfer)); - if ((transfer.busy()) - || (transfer.m_transferCount == 0) // no zero length transfers allowed - || (transfer.m_transferCount >= 0x8000)) // max CITER/BITER count with ELINK = 0 is 0x7FFF, so reject - { - DMASPI_PRINT((" Transfer is busy or invalid, dropped\n")); - transfer.m_state = Transfer::State::error; - return false; - } - addTransferToQueue(transfer); - if ((state_ == eRunning) && (!busy())) - { - DMASPI_PRINT((" starting transfer\n")); - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - beginPendingTransfer(); - } - } - return true; - } - - - /** \brief Check if the DMA SPI is busy, which means that it is currently handling a Transfer. - \return true if a Transfer is being handled. - * \see start() - * \see running() - * \see stop() - * \see stopping() - * \see stopped() - **/ - static bool busy() - { - return (m_pCurrentTransfer != nullptr); - } - - /** \brief Request the DMA SPI to stop handling Transfers. - * - * The stopping driver may finish a current Transfer, but it will then not start a new, pending one. - * \see start() - * \see running() - * \see busy() - * \see stopping() - * \see stopped() - **/ - static void stop() - { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - switch(state_) - { - case eStopped: - break; - case eRunning: - if (busy()) - { - state_ = eStopping; - } - else - { - // this means that the DMA SPI simply has nothing to do - state_ = eStopped; - } - break; - case eStopping: - break; - default: - state_ = eError; - break; - } - } - } - - /** \brief See if the DMA SPI is currently switching from running to stopped state - * \return true if the DMA SPI is switching from running to stopped state - * \see start() - * \see running() - * \see busy() - * \see stop() - * \see stopped() - **/ - static bool stopping() { return (state_ == eStopping); } - - /** \brief See if the DMA SPI is stopped - * \return true if the DMA SPI is in stopped state, i.e. not handling pending Transfers - * \see start() - * \see running() - * \see busy() - * \see stop() - * \see stopping() - **/ - static bool stopped() { return (state_ == eStopped); } - - /** \brief Shut down the DMA SPI - * - * Deallocates DMA channels and sets the internal state to error (this might not be an intelligent name for that) - * \see begin() - **/ - static void end() - { - if (init_count_ == 0) - { - state_ = eError; - return; - } - if (init_count_ == 1) - { - init_count_--; - destroyDmaChannels(); - state_ = eError; - return; - } - else - { - init_count_--; - return; - } - } - - /** \brief get the last value that was read from a slave, but discarded because the Transfer didn't specify a sink - **/ - static uint8_t devNull() - { - return m_devNull; - } - - protected: - enum EState - { - eStopped, - eRunning, - eStopping, - eError - }; - - static void addTransferToQueue(Transfer& transfer) - { - transfer.m_state = Transfer::State::pending; - transfer.m_pNext = nullptr; - DMASPI_PRINT((" DmaSpi::addTransferToQueue() : queueing transfer\n")); - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - if (m_pNextTransfer == nullptr) - { - m_pNextTransfer = &transfer; - } - else - { - m_pLastTransfer->m_pNext = &transfer; - } - m_pLastTransfer = &transfer; - } - } - - static void post_finishCurrentTransfer() {DMASPI_INSTANCE::post_finishCurrentTransfer_impl();} - - static void finishCurrentTransfer() - { - if (m_pCurrentTransfer->m_pSelect != nullptr) - { - m_pCurrentTransfer->m_pSelect->deselect(m_pCurrentTransfer->m_transferType); - } - else - { - m_Spi.endTransaction(); - } - m_pCurrentTransfer->m_state = Transfer::State::eDone; - DMASPI_PRINT((" finishCurrentTransfer() @ %p\n", m_pCurrentTransfer)); - m_pCurrentTransfer = nullptr; - post_finishCurrentTransfer(); - } - - static bool createDmaChannels() - { - if (txChannel_() == nullptr) - { - return false; - } - if (rxChannel_() == nullptr) - { - delete txChannel_(); - return false; - } - return true; - } - - static void destroyDmaChannels() - { - if (rxChannel_() != nullptr) - { - delete rxChannel_(); - } - if (txChannel_() != nullptr) - { - delete txChannel_(); - } - } - - static DMAChannel* rxChannel_() - { - static DMAChannel* pChannel = new DMAChannel(); - return pChannel; - } - - static DMAChannel* txChannel_() - { - static DMAChannel* pChannel = new DMAChannel(); - return pChannel; - } - - static void rxIsr_() - { - DMASPI_PRINT(("DmaSpi::rxIsr_()\n")); - rxChannel_()->clearInterrupt(); - // end current transfer: deselect and mark as done - finishCurrentTransfer(); - - DMASPI_PRINT((" state = ")); - switch(state_) - { - case eStopped: // this should not happen! - DMASPI_PRINT(("eStopped\n")); - state_ = eError; - break; - case eRunning: - DMASPI_PRINT(("eRunning\n")); - beginPendingTransfer(); - break; - case eStopping: - DMASPI_PRINT(("eStopping\n")); - state_ = eStopped; - break; - case eError: - DMASPI_PRINT(("eError\n")); - break; - default: - DMASPI_PRINT(("eUnknown\n")); - state_ = eError; - break; - } - } - - static void pre_cs() {DMASPI_INSTANCE::pre_cs_impl();} - static void post_cs() {DMASPI_INSTANCE::post_cs_impl();} - - static void beginPendingTransfer() - { - if (m_pNextTransfer == nullptr) - { - DMASPI_PRINT(("DmaSpi::beginNextTransfer: no pending transfer\n")); - return; - } - - m_pCurrentTransfer = m_pNextTransfer; - DMASPI_PRINT(("DmaSpi::beginNextTransfer: starting transfer @ %p\n", m_pCurrentTransfer)); - m_pCurrentTransfer->m_state = Transfer::State::inProgress; - m_pNextTransfer = m_pNextTransfer->m_pNext; - if (m_pNextTransfer == nullptr) - { - DMASPI_PRINT((" this was the last in the queue\n")); - m_pLastTransfer = nullptr; - } - - // configure Rx DMA - if (m_pCurrentTransfer->m_pDest != nullptr) - { - // real data sink - DMASPI_PRINT((" real sink\n")); - rxChannel_()->destinationBuffer(m_pCurrentTransfer->m_pDest, - m_pCurrentTransfer->m_transferCount); - } - else - { - // dummy data sink - DMASPI_PRINT((" dummy sink\n")); - rxChannel_()->destination(m_devNull); - rxChannel_()->transferCount(m_pCurrentTransfer->m_transferCount); - } - - // configure Tx DMA - if (m_pCurrentTransfer->m_pSource != nullptr) - { - // real data source - DMASPI_PRINT((" real source\n")); - txChannel_()->sourceBuffer(m_pCurrentTransfer->m_pSource, - m_pCurrentTransfer->m_transferCount); - } - else - { - // dummy data source - DMASPI_PRINT((" dummy source\n")); - txChannel_()->source(m_pCurrentTransfer->m_fill); - txChannel_()->transferCount(m_pCurrentTransfer->m_transferCount); - } - - pre_cs(); - - // Select Chip - if (m_pCurrentTransfer->m_pSelect != nullptr) - { - m_pCurrentTransfer->m_pSelect->select(m_pCurrentTransfer->m_transferType); - } - else - { - m_Spi.beginTransaction(SPISettings()); - } - - post_cs(); - } - - static size_t init_count_; - static volatile EState state_; - static Transfer* volatile m_pCurrentTransfer; - static Transfer* volatile m_pNextTransfer; - static Transfer* volatile m_pLastTransfer; - static volatile uint8_t m_devNull; - //static SPICLASS& m_Spi; -}; - -template -size_t AbstractDmaSpi::init_count_ = 0; - -template -volatile typename AbstractDmaSpi::EState AbstractDmaSpi::state_ = eError; - -template -typename AbstractDmaSpi::Transfer* volatile AbstractDmaSpi::m_pNextTransfer = nullptr; - -template -typename AbstractDmaSpi::Transfer* volatile AbstractDmaSpi::m_pCurrentTransfer = nullptr; - -template -typename AbstractDmaSpi::Transfer* volatile AbstractDmaSpi::m_pLastTransfer = nullptr; - -template -volatile uint8_t AbstractDmaSpi::m_devNull = 0; - -#if defined(KINETISK) - -class DmaSpi0 : public AbstractDmaSpi -{ -public: - static void begin_setup_txChannel_impl() - { - txChannel_()->disable(); - txChannel_()->destination((volatile uint8_t&)SPI0_PUSHR); - txChannel_()->disableOnCompletion(); - txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX); - } - - static void begin_setup_rxChannel_impl() - { - rxChannel_()->disable(); - rxChannel_()->source((volatile uint8_t&)SPI0_POPR); - rxChannel_()->disableOnCompletion(); - rxChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_RX); - rxChannel_()->attachInterrupt(rxIsr_); - rxChannel_()->interruptAtCompletion(); - } - - static void pre_cs_impl() - { - SPI0_SR = 0xFF0F0000; - SPI0_RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS | SPI_RSER_TFFF_RE | SPI_RSER_TFFF_DIRS; - } - - static void post_cs_impl() - { - rxChannel_()->enable(); - txChannel_()->enable(); - } - - static void post_finishCurrentTransfer_impl() - { - SPI0_RSER = 0; - SPI0_SR = 0xFF0F0000; - } - -private: -}; - -extern DmaSpi0 DMASPI0; - -#if defined(__MK66FX1M0__) - -class DmaSpi1 : public AbstractDmaSpi -{ -public: - static void begin_setup_txChannel_impl() - { - txChannel_()->disable(); - txChannel_()->destination((volatile uint8_t&)SPI1_PUSHR); - txChannel_()->disableOnCompletion(); - txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI1_TX); - } - - static void begin_setup_rxChannel_impl() - { - rxChannel_()->disable(); - rxChannel_()->source((volatile uint8_t&)SPI1_POPR); - rxChannel_()->disableOnCompletion(); - rxChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI1_RX); - rxChannel_()->attachInterrupt(rxIsr_); - rxChannel_()->interruptAtCompletion(); - } - - static void pre_cs_impl() - { - SPI1_SR = 0xFF0F0000; - SPI1_RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS | SPI_RSER_TFFF_RE | SPI_RSER_TFFF_DIRS; - } - - static void post_cs_impl() - { - rxChannel_()->enable(); - txChannel_()->enable(); - } - - static void post_finishCurrentTransfer_impl() - { - SPI1_RSER = 0; - SPI1_SR = 0xFF0F0000; - } - -private: -}; - -/* -class DmaSpi2 : public AbstractDmaSpi -{ -public: - static void begin_setup_txChannel_impl() - { - txChannel_()->disable(); - txChannel_()->destination((volatile uint8_t&)SPI2_PUSHR); - txChannel_()->disableOnCompletion(); - txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI2_TX); - } - - static void begin_setup_rxChannel_impl() - { - rxChannel_()->disable(); - rxChannel_()->source((volatile uint8_t&)SPI2_POPR); - rxChannel_()->disableOnCompletion(); - rxChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI2_RX); - rxChannel_()->attachInterrupt(rxIsr_); - rxChannel_()->interruptAtCompletion(); - } - - static void pre_cs_impl() - { - SPI2_SR = 0xFF0F0000; - SPI2_RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS | SPI_RSER_TFFF_RE | SPI_RSER_TFFF_DIRS; - } - - static void post_cs_impl() - { - rxChannel_()->enable(); - txChannel_()->enable(); - } - - static void post_finishCurrentTransfer_impl() - { - SPI2_RSER = 0; - SPI2_SR = 0xFF0F0000; - } - -private: -}; -*/ - -extern DmaSpi1 DMASPI1; -//extern DmaSpi2 DMASPI2; -#endif // defined(__MK66FX1M0__) - -#elif defined(KINETISL) -class DmaSpi0 : public AbstractDmaSpi -{ -public: - static void begin_setup_txChannel_impl() - { - txChannel_()->disable(); - txChannel_()->destination((volatile uint8_t&)SPI0_DL); - txChannel_()->disableOnCompletion(); - txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX); - } - - static void begin_setup_rxChannel_impl() - { - rxChannel_()->disable(); - rxChannel_()->source((volatile uint8_t&)SPI0_DL); - rxChannel_()->disableOnCompletion(); - rxChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_RX); - rxChannel_()->attachInterrupt(rxIsr_); - rxChannel_()->interruptAtCompletion(); - } - - static void pre_cs_impl() - { - // disable SPI and enable SPI DMA requests - SPI0_C1 &= ~(SPI_C1_SPE); - SPI0_C2 |= SPI_C2_TXDMAE | SPI_C2_RXDMAE; - } - - static void post_cs_impl() - { - rxChannel_()->enable(); - txChannel_()->enable(); - } - - static void post_finishCurrentTransfer_impl() - { - SPI0_C2 = 0; - txChannel_()->clearComplete(); - rxChannel_()->clearComplete(); - } - -private: -}; - -class DmaSpi1 : public AbstractDmaSpi -{ -public: - static void begin_setup_txChannel_impl() - { - txChannel_()->disable(); - txChannel_()->destination((volatile uint8_t&)SPI1_DL); - txChannel_()->disableOnCompletion(); - txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI1_TX); - } - - static void begin_setup_rxChannel_impl() - { - rxChannel_()->disable(); - rxChannel_()->source((volatile uint8_t&)SPI1_DL); - rxChannel_()->disableOnCompletion(); - rxChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI1_RX); - rxChannel_()->attachInterrupt(rxIsr_); - rxChannel_()->interruptAtCompletion(); - } - - static void pre_cs_impl() - { - // disable SPI and enable SPI DMA requests - SPI1_C1 &= ~(SPI_C1_SPE); - SPI1_C2 |= SPI_C2_TXDMAE | SPI_C2_RXDMAE; - } - -// static void dumpCFG(const char *sz, uint32_t* p) -// { -// DMASPI_PRINT(("%s: %x %x %x %x \n", sz, p[0], p[1], p[2], p[3])); -// } - - static void post_cs_impl() - { - DMASPI_PRINT(("post_cs S C1 C2: %x %x %x\n", SPI1_S, SPI1_C1, SPI1_C2)); -// dumpCFG("RX", (uint32_t*)(void*)rxChannel_()->CFG); -// dumpCFG("TX", (uint32_t*)(void*)txChannel_()->CFG); - rxChannel_()->enable(); - txChannel_()->enable(); - } - - static void post_finishCurrentTransfer_impl() - { - SPI1_C2 = 0; - txChannel_()->clearComplete(); - rxChannel_()->clearComplete(); - } -private: -}; - -extern DmaSpi0 DMASPI0; -extern DmaSpi1 DMASPI1; - -#else - -#error Unknown chip - -#endif // KINETISK else KINETISL - -class DmaSpiGeneric -{ -public: - using Transfer = DmaSpi::Transfer; - - DmaSpiGeneric() { - m_spiDma0 = &DMASPI0; -#if defined(__MK66FX1M0__) - m_spiDma1 = &DMASPI1; -#endif - } - DmaSpiGeneric(int spiId) : DmaSpiGeneric() { - m_spiSelect = spiId; - } - - bool begin () { - switch(m_spiSelect) { - case 1 : return m_spiDma1->begin(); - default : - return m_spiDma0->begin(); - } - } - - void start () { - switch(m_spiSelect) { - case 1 : m_spiDma1->start(); return; - default : - m_spiDma0->start(); return; - } - } - - bool running () { - switch(m_spiSelect) { - case 1 : return m_spiDma1->running(); - default : - return m_spiDma0->running(); - } - } - - bool registerTransfer (Transfer& transfer) { - switch(m_spiSelect) { - case 1 : return m_spiDma1->registerTransfer(transfer); - default : - return m_spiDma0->registerTransfer(transfer); - } - } - - - bool busy () { - switch(m_spiSelect) { - case 1 : return m_spiDma1->busy(); - default : - return m_spiDma0->busy(); - } - } - - void stop () { - switch(m_spiSelect) { - case 1 : m_spiDma1->stop(); return; - default : - m_spiDma0->stop(); return; - } - } - - bool stopping () { - switch(m_spiSelect) { - case 1 : return m_spiDma1->stopping(); - default : - return m_spiDma0->stopping(); - } - } - - bool stopped () { - switch(m_spiSelect) { - case 1 : return m_spiDma1->stopped(); - default : - return m_spiDma0->stopped(); - } - } - - void end () { - switch(m_spiSelect) { - case 1 : m_spiDma1->end(); return; - default : - m_spiDma0->end(); return; - } - } - - uint8_t devNull () { - switch(m_spiSelect) { - case 1 : return m_spiDma1->devNull(); - default : - return m_spiDma0->devNull(); - } - } - -private: - int m_spiSelect = 0; - DmaSpi0 *m_spiDma0 = nullptr; -#if defined(__MK66FX1M0__) - DmaSpi1 *m_spiDma1 = nullptr; -#else - // just make it Spi0 so it compiles atleast - DmaSpi0 *m_spiDma1 = nullptr; -#endif - -}; - - -#endif // DMASPI_H diff --git a/src/LibBasicFunctions.h b/src/LibBasicFunctions.h index 407e5c5..3cf80b5 100644 --- a/src/LibBasicFunctions.h +++ b/src/LibBasicFunctions.h @@ -29,7 +29,6 @@ #include "Audio.h" #include "BATypes.h" -#include "LibMemoryManagement.h" #ifndef __BALIBRARY_LIBBASICFUNCTIONS_H #define __BALIBRARY_LIBBASICFUNCTIONS_H @@ -137,7 +136,6 @@ public: /// Construct an audio buffer using a slot configured with the BALibrary::ExternalSramManager /// @param slot a pointer to the slot representing the memory you wish to use for the buffer. - AudioDelay(ExtMemSlot *slot); ~AudioDelay(); @@ -208,8 +206,6 @@ public: /// When using EXTERNAL memory, this function can return a pointer to the underlying ExtMemSlot object associated /// with the buffer. /// @returns pointer to the underlying ExtMemSlot. - ExtMemSlot *getSlot() const { return m_slot; } - /// Ween using INTERNAL memory, thsi function can return a pointer to the underlying RingBuffer that contains @@ -227,7 +223,6 @@ private: MemType m_type; ///< when 0, INTERNAL memory, when 1, external MEMORY. RingBuffer *m_ringBuffer = nullptr; ///< When using INTERNAL memory, a RingBuffer will be created. - ExtMemSlot *m_slot = nullptr; ///< When using EXTERNAL memory, an ExtMemSlot must be provided. size_t m_maxDelaySamples = 0; ///< stores the number of audio samples in the AudioDelay. bool m_getSamples(int16_t *dest, size_t offsetSamples, size_t numSamples); ///< operates directly on int16_y buffers }; diff --git a/src/LibMemoryManagement.h b/src/LibMemoryManagement.h deleted file mode 100644 index 288e581..0000000 --- a/src/LibMemoryManagement.h +++ /dev/null @@ -1,212 +0,0 @@ -/**************************************************************************//** - * @file - * @author Steve Lascos - * @company Blackaddr Audio - * - * LibMemoryManagment is a class for providing access to external SPI based - * SRAM with the optional convience of breaking it up into 'slots' which are smaller - * memory entities. - * @details This class treats an external memory as a pool from which the user requests - * a block. When using that block, the user need not be concerned with where the pool - * it came from, they only deal with offsets from the start of their memory block. Ie. - * Your particular slot of memory appears to you to start at 0 and end at whatever size - * was requested. - * - * @copyright This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#ifndef __BALIBRARY_LIBMEMORYMANAGEMENT_H -#define __BALIBRARY_LIBMEMORYMANAGEMENT_H - -#include - -#include "BAHardware.h" -#include "BASpiMemory.h" - -namespace BALibrary { - -/**************************************************************************//** - * MemConfig contains the configuration information associated with a particular - * SPI interface. - *****************************************************************************/ -struct MemConfig { - size_t size; ///< the total size of the external SPI memory - size_t totalAvailable; ///< the number of bytes available (remaining) - size_t nextAvailable; ///< the starting point for the next available slot - BASpiMemory *m_spi = nullptr; ///< handle to the SPI interface -}; - -class ExternalSramManager; // forward declare so ExtMemSlot can declared friendship with it - -/**************************************************************************//** - * ExtMemSlot provides a convenient interface to a particular slot of an - * external memory. - * @details the memory can be access randomly, as a single word, as a block of - * data, or as circular queue. - *****************************************************************************/ -class ExtMemSlot { -public: - - /// clear the entire contents of the slot by writing zeros - /// @returns true on success - bool clear(); - - /// set a new write position (in bytes) for circular operation - /// @param offsetBytes moves the write pointer to the specified offset from the slot start - /// @returns true on success, else false if offset is beyond slot boundaries. - bool setWritePosition(size_t offsetBytes); - - /// returns the currently set write pointer pointer - /// @returns the write position value - size_t getWritePosition() const { return m_currentWrPosition-m_start; } - - /// set a new read position (in bytes) for circular operation - /// @param offsetBytes moves the read pointer to the specified offset from the slot start - /// @returns true on success, else false if offset is beyond slot boundaries. - bool setReadPosition(size_t offsetBytes); - - /// returns the currently set read pointer pointer - /// @returns the read position value - size_t getReadPosition() const { return m_currentRdPosition-m_start; } - - /// Write a block of 16-bit data to the memory at the specified offset - /// @param offsetWords offset in 16-bit words from start of slot - /// @param src pointer to start of block of 16-bit data - /// @param numWords number of 16-bit words to transfer - /// @returns true on success, else false on error - bool write16(size_t offsetWords, int16_t *src, size_t numWords); - - /// Write a block of zeros (16-bit) to the memory at the specified offset - /// @param offsetWords offset in 16-bit words from start of slot - /// @param numWords number of 16-bit words to transfer - /// @returns true on success, else false on error - bool zero16(size_t offsetWords, size_t numWords); - - /// Read a block of 16-bit data from the memory at the specified location - /// @param offsetWords offset in 16-bit words from start of slot - /// @param dest pointer to destination for the read data - /// @param numWords number of 16-bit words to transfer - /// @returns true on success, else false on error - bool read16(size_t offsetWords, int16_t *dest, size_t numWords); - - /// Read the next in memory during circular operation - /// @returns the next 16-bit data word in memory - uint16_t readAdvance16(); - - - /// Read the next block of numWords during circular operation - /// @details, dest is ignored when using DMA - /// @param dest pointer to the destination of the read. - /// @param numWords number of 16-bit words to transfer - /// @returns true on success, else false on error - bool readAdvance16(int16_t *dest, size_t numWords); - - /// Write a block of 16-bit data from the specified location in circular operation - /// @param src pointer to the start of the block of data to write to memory - /// @param numWords number of 16-bit words to transfer - /// @returns true on success, else false on error - bool writeAdvance16(int16_t *src, size_t numWords); - - /// Write a single 16-bit data to the next location in circular operation - /// @param data the 16-bit word to transfer - /// @returns true on success, else false on error - bool writeAdvance16(int16_t data); // write just one data - - /// Write a block of 16-bit data zeros in circular operation - /// @param numWords number of 16-bit words to transfer - /// @returns true on success, else false on error - bool zeroAdvance16(size_t numWords); - - /// Get the size of the memory slot - /// @returns size of the slot in bytes - size_t size() const { return m_size; } - - /// Ensures the underlying SPI interface is enabled - /// @returns true on success, false on error - bool enable() const; - - /// Checks whether underlying SPI interface is enabled - /// @returns true if enabled, false if not enabled - bool isEnabled() const; - - bool isUseDma() const { return m_useDma; } - - bool isWriteBusy() const; - - bool isReadBusy() const; - - /// DEBUG USE: prints out the slot member variables - void printStatus(void) const; - -private: - friend ExternalSramManager; ///< gives the manager access to the private variables - bool m_valid = false; ///< After a slot is successfully configured by the manager it becomes valid - size_t m_start = 0; ///< the external memory address in bytes where this slot starts - size_t m_end = 0; ///< the external memory address in bytes where this slot ends (inclusive) - size_t m_currentWrPosition = 0; ///< current write pointer for circular operation - size_t m_currentRdPosition = 0; ///< current read pointer for circular operation - size_t m_size = 0; ///< size of this slot in bytes - bool m_useDma = false; ///< when TRUE, BASpiMemoryDMA will be used. - SpiDeviceId m_spiId; ///< the SPI Device ID - BASpiMemory *m_spi = nullptr; ///< pointer to an instance of the BASpiMemory interface class -}; - - -/**************************************************************************//** - * ExternalSramManager provides a class to handle dividing an external SPI RAM - * into independent slots for general use. - * @details the class does not support deallocated memory because this would cause - * fragmentation. - *****************************************************************************/ -class ExternalSramManager final { -public: - ExternalSramManager(); - - /// The manager is constructed by specifying how many external memories to handle allocations for - /// @param numMemories the number of external memories - ExternalSramManager(unsigned numMemories); - virtual ~ExternalSramManager(); - - /// Query the amount of available (unallocated) memory - /// @details note that currently, memory cannot be allocated. - /// @param mem specifies which memory to query, default is memory 0 - /// @returns the available memory in bytes - size_t availableMemory(BALibrary::MemSelect mem = BALibrary::MemSelect::MEM0); - - /// Request memory be allocated for the provided slot - /// @param slot a pointer to the global slot object to which memory will be allocated - /// @param delayMilliseconds request the amount of memory based on required time for audio samples, rather than number of bytes. - /// @param mem specify which external memory to allocate from - /// @param useDma when true, DMA is used for SPI port, else transfers block until complete - /// @returns true on success, otherwise false on error - bool requestMemory(ExtMemSlot *slot, float delayMilliseconds, BALibrary::MemSelect mem = BALibrary::MemSelect::MEM0, bool useDma = false); - - /// Request memory be allocated for the provided slot - /// @param slot a pointer to the global slot object to which memory will be allocated - /// @param sizeBytes request the amount of memory in bytes to request - /// @param mem specify which external memory to allocate from - /// @param useDma when true, DMA is used for SPI port, else transfers block until complete - /// @returns true on success, otherwise false on error - bool requestMemory(ExtMemSlot *slot, size_t sizeBytes, BALibrary::MemSelect mem = BALibrary::MemSelect::MEM0, bool useDma = false); - -private: - static bool m_configured; ///< there should only be one instance of ExternalSramManager in the whole project - static MemConfig m_memConfig[BALibrary::NUM_MEM_SLOTS]; ///< store the configuration information for each external memory - -}; - - -} // BALibrary - -#endif /* __BALIBRARY_LIBMEMORYMANAGEMENT_H */ diff --git a/src/common/AudioDelay.cpp b/src/common/AudioDelay.cpp index 7b30c5f..fccd8fa 100644 --- a/src/common/AudioDelay.cpp +++ b/src/common/AudioDelay.cpp @@ -28,7 +28,6 @@ namespace BALibrary { // AudioDelay //////////////////////////////////////////////////// AudioDelay::AudioDelay(size_t maxSamples) -: m_slot(nullptr) { m_type = (MemType::MEM_INTERNAL); @@ -44,13 +43,6 @@ AudioDelay::AudioDelay(float maxDelayTimeMs) } -AudioDelay::AudioDelay(ExtMemSlot *slot) -{ - m_type = (MemType::MEM_EXTERNAL); - m_slot = slot; - m_maxDelaySamples = (slot->size() / sizeof(int16_t)) - AUDIO_BLOCK_SAMPLES; -} - AudioDelay::~AudioDelay() { if (m_ringBuffer) delete m_ringBuffer; @@ -74,16 +66,7 @@ audio_block_t* AudioDelay::addBlock(audio_block_t *block) m_ringBuffer->push_back(block); return blockToRelease; - } else { - // EXTERNAL memory - if (!m_slot) { Serial.println("addBlock(): m_slot is not valid"); } - - if (block) { - // this causes pops - m_slot->writeAdvance16(block->data, AUDIO_BLOCK_SAMPLES); - } - blockToRelease = block; - } + } return blockToRelease; } @@ -98,10 +81,6 @@ audio_block_t* AudioDelay::getBlock(size_t index) size_t AudioDelay::getMaxDelaySamples() { - if (m_type == MemType::MEM_EXTERNAL) { - // update the max delay sample size - m_maxDelaySamples = (m_slot->size() / sizeof(int16_t)) - AUDIO_BLOCK_SAMPLES; - } return m_maxDelaySamples; } @@ -160,37 +139,9 @@ bool AudioDelay::m_getSamples(int16_t *dest, size_t offsetSamples, size_t numSam memcpy(static_cast(destStart), static_cast(srcStart), numData * sizeof(int16_t)); return true; - - } else { - // EXTERNAL Memory - if (numSamples*sizeof(int16_t) <= m_slot->size() ) { // check for overflow - // current position is considered the write position subtracted by the number of samples we're going - // to read since this is the smallest delay we can get without reading past the write position into - // the "future". - int currentPositionBytes = (int)m_slot->getWritePosition() - (int)(numSamples*sizeof(int16_t)); - size_t offsetBytes = offsetSamples * sizeof(int16_t); - - if ((int)offsetBytes <= currentPositionBytes) { - // when we back up to read, we won't wrap over the beginning of the slot - m_slot->setReadPosition(currentPositionBytes - offsetBytes); - } else { - // It's going to wrap around to the from the beginning to the end of the slot. - int readPosition = (int)m_slot->size() + currentPositionBytes - offsetBytes; - m_slot->setReadPosition((size_t)readPosition); - } - - // Read the number of samples - m_slot->readAdvance16(dest, numSamples); - - return true; - } else { - // numSamples is > than total slot size - Serial.println("getSamples(): ERROR numSamples > total slot size"); - Serial.println(numSamples + String(" > ") + m_slot->size()); - return false; - } } + return false; } bool AudioDelay::interpolateDelay(int16_t *extendedSourceBuffer, int16_t *destBuffer, float fraction, size_t numSamples) @@ -203,28 +154,12 @@ bool AudioDelay::interpolateDelay(int16_t *extendedSourceBuffer, int16_t *destBu } /// @todo optimize this later - for (int i=0; i> 16) + ((frac2*extendedSourceBuffer[i+1]) >> 16); } return true; } -bool AudioDelay::interpolateDelayVector(int16_t *extendedSourceBuffer, int16_t *destBuffer, float *fractionVector, size_t numSamples) -{ - int16_t frac1Vec[numSamples]; - int16_t frac2Vec[numSamples]; - - for (int i=0; i(32767.0f * fractionVector[i]); - frac1Vec[i] = fracAsInt; - frac2Vec[i] = 32767-frac1Vec[i]; - - destBuffer[i] = (( frac1Vec[i] * extendedSourceBuffer[i]) >> 16) + ((frac2Vec[i] * extendedSourceBuffer[i+1]) >> 16); - } - - return true; -} - } diff --git a/src/common/ExtMemSlot.cpp b/src/common/ExtMemSlot.cpp deleted file mode 100644 index c857cbe..0000000 --- a/src/common/ExtMemSlot.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * ExtMemSlot.cpp - * - * Created on: Jan 19, 2018 - * Author: slascos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ -#include -#include - -#include "Audio.h" -#include "LibMemoryManagement.h" - -namespace BALibrary { - -///////////////////////////////////////////////////////////////////////////// -// MEM SLOT -///////////////////////////////////////////////////////////////////////////// -bool ExtMemSlot::clear() -{ - if (!m_valid) { return false; } - m_spi->zero16(m_start, m_size); - return true; -} - -bool ExtMemSlot::setWritePosition(size_t offsetBytes) -{ - if (m_start + offsetBytes <= m_end) { - m_currentWrPosition = m_start + offsetBytes; - return true; - } else { return false; } -} - -bool ExtMemSlot::write16(size_t offsetWords, int16_t *src, size_t numWords) -{ - if (!m_valid) { return false; } - size_t writeStart = m_start + sizeof(int16_t)*offsetWords; // 2x because int16 is two bytes per data - size_t numBytes = sizeof(int16_t)*numWords; - if ((writeStart + numBytes-1) <= m_end) { - m_spi->write16(writeStart, reinterpret_cast(src), numWords); // cast audio data to uint - return true; - } else { - // this would go past the end of the memory slot, do not perform the write - return false; - } -} - -bool ExtMemSlot::setReadPosition(size_t offsetBytes) -{ - if (m_start + offsetBytes <= m_end) { - m_currentRdPosition = m_start + offsetBytes; - return true; - } else { - return false; - } -} - -bool ExtMemSlot::zero16(size_t offsetWords, size_t numWords) -{ - if (!m_valid) { return false; } - size_t writeStart = m_start + sizeof(int16_t)*offsetWords; - size_t numBytes = sizeof(int16_t)*numWords; - if ((writeStart + numBytes-1) <= m_end) { - m_spi->zero16(writeStart, numWords); // cast audio data to uint - return true; - } else { - // this would go past the end of the memory slot, do not perform the write - return false; - } -} - -bool ExtMemSlot::read16(size_t offsetWords, int16_t *dest, size_t numWords) -{ - if (!dest) return false; // invalid destination - size_t readOffset = m_start + sizeof(int16_t)*offsetWords; - size_t numBytes = sizeof(int16_t)*numWords; - - if ((readOffset + numBytes-1) <= m_end) { - m_spi->read16(readOffset, reinterpret_cast(dest), numWords); - return true; - } else { - // this would go past the end of the memory slot, do not perform the read - return false; - } -} - -uint16_t ExtMemSlot::readAdvance16() -{ - uint16_t val = m_spi->read16(m_currentRdPosition); - if (m_currentRdPosition < m_end-1) { - m_currentRdPosition +=2; // position is in bytes and we read two - } else { - m_currentRdPosition = m_start; - } - return val; -} - -bool ExtMemSlot::readAdvance16(int16_t *dest, size_t numWords) -{ - if (!m_valid) { return false; } - size_t numBytes = sizeof(int16_t)*numWords; - - if (m_currentRdPosition + numBytes-1 <= m_end) { - // entire block fits in memory slot without wrapping - m_spi->read16(m_currentRdPosition, reinterpret_cast(dest), numWords); // cast audio data to uint. - m_currentRdPosition += numBytes; - - } else { - // this read will wrap the memory slot - size_t rdBytes = m_end - m_currentRdPosition + 1; - size_t rdDataNum = rdBytes >> 1; // divide by two to get the number of data - m_spi->read16(m_currentRdPosition, reinterpret_cast(dest), rdDataNum); - size_t remainingData = numWords - rdDataNum; - m_spi->read16(m_start, reinterpret_cast(dest + rdDataNum), remainingData); // write remaining bytes are start - m_currentRdPosition = m_start + (remainingData*sizeof(int16_t)); - } - return true; -} - - -bool ExtMemSlot::writeAdvance16(int16_t *src, size_t numWords) -{ - if (!m_valid) { return false; } - size_t numBytes = sizeof(int16_t)*numWords; - - if (m_currentWrPosition + numBytes-1 <= m_end) { - // entire block fits in memory slot without wrapping - m_spi->write16(m_currentWrPosition, reinterpret_cast(src), numWords); // cast audio data to uint. - m_currentWrPosition += numBytes; - - } else { - // this write will wrap the memory slot - size_t wrBytes = m_end - m_currentWrPosition + 1; - size_t wrDataNum = wrBytes >> 1; // divide by two to get the number of data - m_spi->write16(m_currentWrPosition, reinterpret_cast(src), wrDataNum); - size_t remainingData = numWords - wrDataNum; - m_spi->write16(m_start, reinterpret_cast(src + wrDataNum), remainingData); // write remaining bytes are start - m_currentWrPosition = m_start + (remainingData*sizeof(int16_t)); - } - return true; -} - - -bool ExtMemSlot::zeroAdvance16(size_t numWords) -{ - if (!m_valid) { return false; } - size_t numBytes = 2*numWords; - if (m_currentWrPosition + numBytes-1 <= m_end) { - // entire block fits in memory slot without wrapping - m_spi->zero16(m_currentWrPosition, numWords); // cast audio data to uint. - m_currentWrPosition += numBytes; - - } else { - // this write will wrap the memory slot - size_t wrBytes = m_end - m_currentWrPosition + 1; - size_t wrDataNum = wrBytes >> 1; - m_spi->zero16(m_currentWrPosition, wrDataNum); - size_t remainingWords = numWords - wrDataNum; // calculate the remaining bytes - m_spi->zero16(m_start, remainingWords); // write remaining bytes are start - m_currentWrPosition = m_start + remainingWords*sizeof(int16_t); - } - return true; -} - - -bool ExtMemSlot::writeAdvance16(int16_t data) -{ - if (!m_valid) { return false; } - - m_spi->write16(m_currentWrPosition, static_cast(data)); - if (m_currentWrPosition < m_end-1) { - m_currentWrPosition+=2; // wrote two bytes - } else { - m_currentWrPosition = m_start; - } - return true; -} - - -bool ExtMemSlot::enable() const -{ - if (m_spi) { - Serial.println("ExtMemSlot::enable()"); - m_spi->begin(); - return true; - } - else { - Serial.println("ExtMemSlot m_spi is nullptr"); - return false; - } -} - -bool ExtMemSlot::isEnabled() const -{ - if (m_spi) { return m_spi->isStarted(); } - else return false; -} - -bool ExtMemSlot::isWriteBusy() const -{ - if (m_useDma) { - return (static_cast(m_spi))->isWriteBusy(); - } else { return false; } -} - -bool ExtMemSlot::isReadBusy() const -{ - if (m_useDma) { - return (static_cast(m_spi))->isReadBusy(); - } else { return false; } -} - - -void ExtMemSlot::printStatus(void) const -{ - Serial.println(String("valid:") + m_valid + String(" m_start:") + m_start + \ - String(" m_end:") + m_end + String(" m_currentWrPosition: ") + m_currentWrPosition + \ - String(" m_currentRdPosition: ") + m_currentRdPosition + \ - String(" m_size:") + m_size); -} - -} - diff --git a/src/common/ExternalSramManager.cpp b/src/common/ExternalSramManager.cpp deleted file mode 100644 index 7083e0c..0000000 --- a/src/common/ExternalSramManager.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * LibMemoryManagement.cpp - * - * Created on: Jan 19, 2018 - * Author: slascos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ -#include -#include - -#include "Audio.h" -#include "LibMemoryManagement.h" - -namespace BALibrary { - -///////////////////////////////////////////////////////////////////////////// -// EXTERNAL SRAM MANAGER -///////////////////////////////////////////////////////////////////////////// -bool ExternalSramManager::m_configured = false; -MemConfig ExternalSramManager::m_memConfig[BALibrary::NUM_MEM_SLOTS]; - - -ExternalSramManager::ExternalSramManager(unsigned numMemories) -{ - // Initialize the static memory configuration structs - if (!m_configured) { - for (unsigned i=0; i < NUM_MEM_SLOTS; i++) { - m_memConfig[i].size = MEM_MAX_ADDR[i]+1; - m_memConfig[i].totalAvailable = MEM_MAX_ADDR[i]+1; - m_memConfig[i].nextAvailable = 0; - - m_memConfig[i].m_spi = nullptr; - } - m_configured = true; - } -} - -ExternalSramManager::ExternalSramManager() -: ExternalSramManager(1) -{ - -} - -ExternalSramManager::~ExternalSramManager() -{ - for (unsigned i=0; i < NUM_MEM_SLOTS; i++) { - if (m_memConfig[i].m_spi) { delete m_memConfig[i].m_spi; } - } -} - -size_t ExternalSramManager::availableMemory(BALibrary::MemSelect mem) -{ - return m_memConfig[mem].totalAvailable; -} - -bool ExternalSramManager::requestMemory(ExtMemSlot *slot, float delayMilliseconds, BALibrary::MemSelect mem, bool useDma) -{ - // convert the time to numer of samples - size_t delayLengthInt = (size_t)((delayMilliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f); - return requestMemory(slot, delayLengthInt * sizeof(int16_t), mem, useDma); -} - -bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BALibrary::MemSelect mem, bool useDma) -{ - - if (m_memConfig[mem].totalAvailable >= sizeBytes) { - Serial.println(String("Configuring a slot for mem ") + mem); - // there is enough available memory for this request - slot->m_start = m_memConfig[mem].nextAvailable; - slot->m_end = slot->m_start + sizeBytes -1; - slot->m_currentWrPosition = slot->m_start; // init to start of slot - slot->m_currentRdPosition = slot->m_start; // init to start of slot - slot->m_size = sizeBytes; - - if (!m_memConfig[mem].m_spi) { - if (useDma) { - m_memConfig[mem].m_spi = new BALibrary::BASpiMemoryDMA(static_cast(mem)); - slot->m_useDma = true; - } else { - m_memConfig[mem].m_spi = new BALibrary::BASpiMemory(static_cast(mem)); - slot->m_useDma = false; - } - if (!m_memConfig[mem].m_spi) { - } else { - Serial.println("Calling spi begin()"); - m_memConfig[mem].m_spi->begin(); - } - } - slot->m_spi = m_memConfig[mem].m_spi; - - // Update the mem config - m_memConfig[mem].nextAvailable = slot->m_end+1; - m_memConfig[mem].totalAvailable -= sizeBytes; - slot->m_valid = true; - if (!slot->isEnabled()) { slot->enable(); } - Serial.println("Clear the memory\n"); Serial.flush(); - slot->clear(); - Serial.println("Done Request memory\n"); Serial.flush(); - return true; - } else { - // there is not enough memory available for the request - Serial.println(String("ExternalSramManager::requestMemory(): Insufficient memory in slot, request/available: ") - + sizeBytes + String(" : ") - + m_memConfig[mem].totalAvailable); - return false; - } -} - -} - diff --git a/src/effects/AudioEffectAnalogChorus.cpp b/src/effects/AudioEffectAnalogChorus.cpp index 81b559d..74c77a9 100644 --- a/src/effects/AudioEffectAnalogChorus.cpp +++ b/src/effects/AudioEffectAnalogChorus.cpp @@ -31,21 +31,6 @@ AudioEffectAnalogChorus::AudioEffectAnalogChorus() m_lfo.setRateAudio(4.0f); // Default to 4 Hz } -// requires preallocated memory large enough -AudioEffectAnalogChorus::AudioEffectAnalogChorus(ExtMemSlot *slot) -: AudioStream(1, m_inputQueueArray) -{ - m_memory = new AudioDelay(slot); - m_maxDelaySamples = (slot->size() / sizeof(int16_t)); - m_averageDelaySamples = static_cast(calcAudioSamples(m_DEFAULT_AVERAGE_DELAY_MS)); - m_delayRange = static_cast(calcAudioSamples(m_DELAY_RANGE)); - - m_externalMemory = true; - m_constructFilter(); - m_lfo.setWaveform(Waveform::TRIANGLE); - m_lfo.setRateAudio(4.0f); // Default to 4 Hz -} - AudioEffectAnalogChorus::~AudioEffectAnalogChorus() { if (m_memory) delete m_memory; @@ -179,12 +164,6 @@ void AudioEffectAnalogChorus::update(void) // BACK TO OUTPUT PROCESSING - // Check if external DMA, if so, we need to be sure the read is completed - if (m_externalMemory && m_memory->getSlot()->isUseDma()) { - // Using DMA so we have to busy-wait here until DMA is done - while (m_memory->getSlot()->isReadBusy()) {} - } - double bufferIndexFloat; int delayIndex; for (int i=0, j=AUDIO_BLOCK_SAMPLES-1; igetSlot(); - - if (!slot) { Serial.println("ERROR: slot ptr is not valid"); } - if (!slot->isEnabled()) { - slot->enable(); - Serial.println("WEIRD: slot was not enabled"); - } - } } void AudioEffectAnalogChorus::rate(float rate) diff --git a/src/effects/AudioEffectAnalogDelay.cpp b/src/effects/AudioEffectAnalogDelay.cpp deleted file mode 100644 index f64f172..0000000 --- a/src/effects/AudioEffectAnalogDelay.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/* - * AudioEffectAnalogDelay.cpp - * - * Created on: Jan 7, 2018 - * Author: slascos - */ -#include -#include "AudioEffectAnalogDelayFilters.h" -#include "AudioEffectAnalogDelay.h" - -using namespace BALibrary; - -namespace BAEffects { - -constexpr int MIDI_CHANNEL = 0; -constexpr int MIDI_CONTROL = 1; - -AudioEffectAnalogDelay::AudioEffectAnalogDelay(float maxDelayMs) -: AudioStream(1, m_inputQueueArray) -{ - m_memory = new AudioDelay(maxDelayMs); - m_maxDelaySamples = calcAudioSamples(maxDelayMs); - m_constructFilter(); -} - -AudioEffectAnalogDelay::AudioEffectAnalogDelay(size_t numSamples) -: AudioStream(1, m_inputQueueArray) -{ - m_memory = new AudioDelay(numSamples); - m_maxDelaySamples = numSamples; - m_constructFilter(); -} - -// requires preallocated memory large enough -AudioEffectAnalogDelay::AudioEffectAnalogDelay(ExtMemSlot *slot) -: AudioStream(1, m_inputQueueArray) -{ - m_memory = new AudioDelay(slot); - m_maxDelaySamples = (slot->size() / sizeof(int16_t)); - m_externalMemory = true; - m_constructFilter(); -} - -AudioEffectAnalogDelay::~AudioEffectAnalogDelay() -{ - if (m_memory) delete m_memory; - if (m_iir) delete m_iir; -} - -// This function just sets up the default filter and coefficients -void AudioEffectAnalogDelay::m_constructFilter(void) -{ - // Use DM3 coefficients by default - m_iir = new IirBiQuadFilterHQ(DM3_NUM_STAGES, reinterpret_cast(&DM3), DM3_COEFF_SHIFT); -} - -void AudioEffectAnalogDelay::setFilterCoeffs(int numStages, const int32_t *coeffs, int coeffShift) -{ - m_iir->changeFilterCoeffs(numStages, coeffs, coeffShift); -} - -void AudioEffectAnalogDelay::setFilter(Filter filter) -{ - switch(filter) { - case Filter::WARM : - m_iir->changeFilterCoeffs(WARM_NUM_STAGES, reinterpret_cast(&WARM), WARM_COEFF_SHIFT); - break; - case Filter::DARK : - m_iir->changeFilterCoeffs(DARK_NUM_STAGES, reinterpret_cast(&DARK), DARK_COEFF_SHIFT); - break; - case Filter::DM3 : - default: - m_iir->changeFilterCoeffs(DM3_NUM_STAGES, reinterpret_cast(&DM3), DM3_COEFF_SHIFT); - break; - } -} - -void AudioEffectAnalogDelay::update(void) -{ - audio_block_t *inputAudioBlock = receiveReadOnly(); // get the next block of input samples - - // Check is block is disabled - if (m_enable == false) { - // do not transmit or process any audio, return as quickly as possible. - if (inputAudioBlock) release(inputAudioBlock); - - // release all held memory resources - if (m_previousBlock) { - release(m_previousBlock); m_previousBlock = nullptr; - } - if (!m_externalMemory) { - // when using internal memory we have to release all references in the ring buffer - while (m_memory->getRingBuffer()->size() > 0) { - audio_block_t *releaseBlock = m_memory->getRingBuffer()->front(); - m_memory->getRingBuffer()->pop_front(); - if (releaseBlock) release(releaseBlock); - } - } - return; - } - - // Check is block is bypassed, if so either transmit input directly or create silence - if (m_bypass == true) { - // transmit the input directly - if (!inputAudioBlock) { - // create silence - inputAudioBlock = allocate(); - if (!inputAudioBlock) { return; } // failed to allocate - else { - clearAudioBlock(inputAudioBlock); - } - } - transmit(inputAudioBlock, 0); - release(inputAudioBlock); - return; - } - - // Otherwise perform normal processing - // In order to make use of the SPI DMA, we need to request the read from memory first, - // then do other processing while it fills in the back. - audio_block_t *blockToOutput = nullptr; // this will hold the output audio - blockToOutput = allocate(); - if (!blockToOutput) return; // skip this update cycle due to failure - - // get the data. If using external memory with DMA, this won't be filled until - // later. - m_memory->getSamples(blockToOutput, m_delaySamples); - - // If using DMA, we need something else to do while that read executes, so - // move on to input preprocessing - - // Preprocessing - audio_block_t *preProcessed = allocate(); - // mix the input with the feedback path in the pre-processing stage - m_preProcessing(preProcessed, inputAudioBlock, m_previousBlock); - - // consider doing the BBD post processing here to use up more time while waiting - // for the read data to come back - audio_block_t *blockToRelease = m_memory->addBlock(preProcessed); - - - // BACK TO OUTPUT PROCESSING - // Check if external DMA, if so, we need to be sure the read is completed - if (m_externalMemory && m_memory->getSlot()->isUseDma()) { - // Using DMA - while (m_memory->getSlot()->isReadBusy()) {} - } - - // perform the wet/dry mix mix - m_postProcessing(blockToOutput, inputAudioBlock, blockToOutput); - transmit(blockToOutput); - - release(inputAudioBlock); - release(m_previousBlock); - m_previousBlock = blockToOutput; - - if (m_blockToRelease) release(m_blockToRelease); - m_blockToRelease = blockToRelease; -} - -void AudioEffectAnalogDelay::delay(float milliseconds) -{ - size_t delaySamples = calcAudioSamples(milliseconds); - - if (delaySamples > m_memory->getMaxDelaySamples()) { - // this exceeds max delay value, limit it. - delaySamples = m_memory->getMaxDelaySamples(); - } - - if (!m_memory) { Serial.println("delay(): m_memory is not valid"); } - - if (!m_externalMemory) { - // internal memory - //QueuePosition queuePosition = calcQueuePosition(milliseconds); - //Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); - } else { - // external memory - //Serial.println(String("CONFIG: delay:") + delaySamples); - ExtMemSlot *slot = m_memory->getSlot(); - - if (!slot) { Serial.println("ERROR: slot ptr is not valid"); } - if (!slot->isEnabled()) { - slot->enable(); - Serial.println("WEIRD: slot was not enabled"); - } - } - - m_delaySamples = delaySamples; -} - -void AudioEffectAnalogDelay::delay(size_t delaySamples) -{ - if (!m_memory) { Serial.println("delay(): m_memory is not valid"); } - - if (!m_externalMemory) { - // internal memory - //QueuePosition queuePosition = calcQueuePosition(delaySamples); - //Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); - } else { - // external memory - //Serial.println(String("CONFIG: delay:") + delaySamples); - ExtMemSlot *slot = m_memory->getSlot(); - if (!slot->isEnabled()) { - slot->enable(); - } - } - m_delaySamples = delaySamples; -} - -void AudioEffectAnalogDelay::delayFractionMax(float delayFraction) -{ - size_t delaySamples = static_cast(static_cast(m_memory->getMaxDelaySamples()) * delayFraction); - - if (delaySamples > m_memory->getMaxDelaySamples()) { - // this exceeds max delay value, limit it. - delaySamples = m_memory->getMaxDelaySamples(); - } - - if (!m_memory) { Serial.println("delay(): m_memory is not valid"); } - - if (!m_externalMemory) { - // internal memory - //QueuePosition queuePosition = calcQueuePosition(delaySamples); - //Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); - } else { - // external memory - //Serial.println(String("CONFIG: delay:") + delaySamples); - ExtMemSlot *slot = m_memory->getSlot(); - if (!slot->isEnabled()) { - slot->enable(); - } - } - m_delaySamples = delaySamples; -} - -void AudioEffectAnalogDelay::m_preProcessing(audio_block_t *out, audio_block_t *dry, audio_block_t *wet) -{ - if ( out && dry && wet) { - alphaBlend(out, dry, wet, m_feedback); - m_iir->process(out->data, out->data, AUDIO_BLOCK_SAMPLES); - } else if (dry) { - memcpy(out->data, dry->data, sizeof(int16_t) * AUDIO_BLOCK_SAMPLES); - } -} - -void AudioEffectAnalogDelay::m_postProcessing(audio_block_t *out, audio_block_t *dry, audio_block_t *wet) -{ - if (!out) return; // no valid output buffer - - if ( out && dry && wet) { - // Simulate the LPF IIR nature of the analog systems - //m_iir->process(wet->data, wet->data, AUDIO_BLOCK_SAMPLES); - alphaBlend(out, dry, wet, m_mix); - } else if (dry) { - memcpy(out->data, dry->data, sizeof(int16_t) * AUDIO_BLOCK_SAMPLES); - } - // Set the output volume - gainAdjust(out, out, m_volume, 1); - -} - - -void AudioEffectAnalogDelay::processMidi(int channel, int control, int value) -{ - - float val = (float)value / 127.0f; - - if ((m_midiConfig[DELAY][MIDI_CHANNEL] == channel) && - (m_midiConfig[DELAY][MIDI_CONTROL] == control)) { - // Delay - if (m_externalMemory) { m_maxDelaySamples = m_memory->getSlot()->size() / sizeof(int16_t); } - size_t delayVal = (size_t)(val * (float)m_maxDelaySamples); - delay(delayVal); - Serial.println(String("AudioEffectAnalogDelay::delay (ms): ") + calcAudioTimeMs(delayVal) - + String(" (samples): ") + delayVal + String(" out of ") + m_maxDelaySamples); - return; - } - - if ((m_midiConfig[BYPASS][MIDI_CHANNEL] == channel) && - (m_midiConfig[BYPASS][MIDI_CONTROL] == control)) { - // Bypass - if (value >= 65) { bypass(false); Serial.println(String("AudioEffectAnalogDelay::not bypassed -> ON") + value); } - else { bypass(true); Serial.println(String("AudioEffectAnalogDelay::bypassed -> OFF") + value); } - return; - } - - if ((m_midiConfig[FEEDBACK][MIDI_CHANNEL] == channel) && - (m_midiConfig[FEEDBACK][MIDI_CONTROL] == control)) { - // Feedback - Serial.println(String("AudioEffectAnalogDelay::feedback: ") + 100*val + String("%")); - feedback(val); - return; - } - - if ((m_midiConfig[MIX][MIDI_CHANNEL] == channel) && - (m_midiConfig[MIX][MIDI_CONTROL] == control)) { - // Mix - Serial.println(String("AudioEffectAnalogDelay::mix: Dry: ") + 100*(1-val) + String("% Wet: ") + 100*val ); - mix(val); - return; - } - - if ((m_midiConfig[VOLUME][MIDI_CHANNEL] == channel) && - (m_midiConfig[VOLUME][MIDI_CONTROL] == control)) { - // Volume - Serial.println(String("AudioEffectAnalogDelay::volume: ") + 100*val + String("%")); - volume(val); - return; - } - -} - -void AudioEffectAnalogDelay::mapMidiControl(int parameter, int midiCC, int midiChannel) -{ - if (parameter >= NUM_CONTROLS) { - return ; // Invalid midi parameter - } - m_midiConfig[parameter][MIDI_CHANNEL] = midiChannel; - m_midiConfig[parameter][MIDI_CONTROL] = midiCC; -} - -} - - diff --git a/src/effects/AudioEffectAnalogDelayFilters.h b/src/effects/AudioEffectAnalogDelayFilters.h deleted file mode 100644 index 473f9cd..0000000 --- a/src/effects/AudioEffectAnalogDelayFilters.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************//** - * @file - * @author Steve Lascos - * @company Blackaddr Audio - * - * This file constains precomputed co-efficients for the AudioEffectAnalogDelay - * class. - * - * @copyright This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ -#include - -namespace BAEffects { - -// The number of stages in the analog-response Biquad filter -constexpr unsigned MAX_NUM_FILTER_STAGES = 4; -constexpr unsigned NUM_COEFFS_PER_STAGE = 5; - -// Matlab/Octave can be helpful to design a filter. Once you have the IIR filter (bz,az) coefficients -// in the z-domain, they can be converted to second-order-sections. AudioEffectAnalogDelay is designed -// to accept up to a maximum of an 8th order filter, broken into four, 2nd order stages. -// -// Second order sections can be created with: -// [sos] = tf2sos(bz,az); -// The results coefficents must be converted the Q31 format required by the ARM CMSIS-DSP library. This means -// all coefficients must lie between -1.0 and +0.9999. If your (bz,az) coefficients exceed this, you must divide -// them down by a power of 2. For example, if your largest magnitude coefficient is -3.5, you must divide by -// 2^shift where 4=2^2 and thus shift = 2. You must then mutliply by 2^31 to get a 32-bit signed integer value -// that represents the required Q31 coefficient. - -// BOSS DM-3 Filters -// b(z) = 1.0e-03 * (0.0032 0.0257 0.0900 0.1800 0.2250 0.1800 0.0900 0.0257 0.0032) -// a(z) = 1.0000 -5.7677 14.6935 -21.3811 19.1491 -10.5202 3.2584 -0.4244 -0.0067 -constexpr unsigned DM3_NUM_STAGES = 4; -constexpr unsigned DM3_COEFF_SHIFT = 2; -constexpr int32_t DM3[5*MAX_NUM_FILTER_STAGES] = { - 536870912, 988616936, 455608573, 834606945, -482959709, - 536870912, 1031466345, 498793368, 965834205, -467402235, - 536870912, 1105821939, 573646688, 928470657, -448083489, - 2339, 5093, 2776, 302068995, 4412722 -}; - - -// Blackaddr WARM Filter -// Butterworth, 8th order, cutoff = 2000 Hz -// Matlab/Octave command: [bz, az] = butter(8, 2000/44100/2); -// b(z) = 1.0e-05 * (0.0086 0.0689 0.2411 0.4821 0.6027 0.4821 0.2411 0.0689 0.0086_ -// a(z) = 1.0000 -6.5399 18.8246 -31.1340 32.3473 -21.6114 9.0643 -2.1815 0.2306 -constexpr unsigned WARM_NUM_STAGES = 4; -constexpr unsigned WARM_COEFF_SHIFT = 2; -constexpr int32_t WARM[5*MAX_NUM_FILTER_STAGES] = { - 536870912,1060309346,523602393,976869875,-481046241, - 536870912,1073413910,536711084,891250612,-391829326, - 536870912,1087173998,550475248,835222426,-333446881, - 46,92,46,807741349,-304811072 -}; - -// Blackaddr DARK Filter -// Chebychev Type II, 8th order, stopband = 60db, cutoff = 1000 Hz -// Matlab command: [bz, az] = cheby2(8, 60, 1000/44100/2); -// b(z) = 0.0009 -0.0066 0.0219 -0.0423 0.0522 -0.0423 0.0219 -0.0066 0.0009 -// a(z) = 1.0000 -7.4618 24.3762 -45.5356 53.1991 -39.8032 18.6245 -4.9829 0.5836 -constexpr unsigned DARK_NUM_STAGES = 4; -constexpr unsigned DARK_COEFF_SHIFT = 1; -constexpr int32_t DARK[5*MAX_NUM_FILTER_STAGES] = { - 1073741824,-2124867808,1073741824,2107780229,-1043948409, - 1073741824,-2116080466,1073741824,2042553796,-979786242, - 1073741824,-2077777790,1073741824,1964779896,-904264933, - 957356,-1462833,957356,1896884898,-838694612 -}; - -}; diff --git a/src/effects/AudioEffectDelayExternal.cpp b/src/effects/AudioEffectDelayExternal.cpp deleted file mode 100644 index 1f1c215..0000000 --- a/src/effects/AudioEffectDelayExternal.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/* - * BAAudioEffectDelayExternal.cpp - * - * Created on: November 1, 2017 - * Author: slascos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ - -#include "BAAudioEffectDelayExternal.h" - -using namespace BALibrary; - -namespace BAEffects { - -#define SPISETTING SPISettings(20000000, MSBFIRST, SPI_MODE0) - -struct MemSpiConfig { - unsigned mosiPin; - unsigned misoPin; - unsigned sckPin; - unsigned csPin; - unsigned memSize; -}; - -constexpr MemSpiConfig Mem0Config = {7, 8, 14, 15, 65536 }; -constexpr MemSpiConfig Mem1Config = {21, 5, 20, 31, 65536 }; - -unsigned BAAudioEffectDelayExternal::m_usingSPICount[2] = {0,0}; - -BAAudioEffectDelayExternal::BAAudioEffectDelayExternal() -: AudioStream(1, m_inputQueueArray) -{ - initialize(MemSelect::MEM0); -} - -BAAudioEffectDelayExternal::BAAudioEffectDelayExternal(MemSelect mem) -: AudioStream(1, m_inputQueueArray) -{ - initialize(mem); -} - -BAAudioEffectDelayExternal::BAAudioEffectDelayExternal(BALibrary::MemSelect type, float delayLengthMs) -: AudioStream(1, m_inputQueueArray) -{ - unsigned delayLengthInt = (delayLengthMs*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f; - initialize(type, delayLengthInt); -} - -BAAudioEffectDelayExternal::~BAAudioEffectDelayExternal() -{ - if (m_spi) delete m_spi; -} - -void BAAudioEffectDelayExternal::delay(uint8_t channel, float milliseconds) { - - if (channel >= 8) return; - if (milliseconds < 0.0) milliseconds = 0.0; - uint32_t n = (milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f; - n += AUDIO_BLOCK_SAMPLES; - if (n > m_memoryLength - AUDIO_BLOCK_SAMPLES) - n = m_memoryLength - AUDIO_BLOCK_SAMPLES; - m_channelDelayLength[channel] = n; - unsigned mask = m_activeMask; - if (m_activeMask == 0) m_startUsingSPI(m_spiChannel); - m_activeMask = mask | (1<= 8) return; - uint8_t mask = m_activeMask & ~(1<data); - m_headOffset += AUDIO_BLOCK_SAMPLES; - } else { - // write wraps across end-of-memory - n = m_memoryLength - m_headOffset; - write(m_headOffset, n, block->data); - m_headOffset = AUDIO_BLOCK_SAMPLES - n; - write(0, m_headOffset, block->data + n); - } - release(block); - } else { - // if no input, store zeros, so later playback will - // not be random garbage previously stored in memory - if (m_headOffset + AUDIO_BLOCK_SAMPLES <= m_memoryLength) { - zero(m_headOffset, AUDIO_BLOCK_SAMPLES); - m_headOffset += AUDIO_BLOCK_SAMPLES; - } else { - n = m_memoryLength - m_headOffset; - zero(m_headOffset, n); - m_headOffset = AUDIO_BLOCK_SAMPLES - n; - zero(0, m_headOffset); - } - } - - // transmit the delayed outputs - for (channel = 0; channel < 8; channel++) { - if (!(m_activeMask & (1<data); - } else { - // read wraps across end-of-memory - n = m_memoryLength - read_offset; - read(read_offset, n, block->data); - read(0, AUDIO_BLOCK_SAMPLES - n, block->data + n); - } - transmit(block, channel); - release(block); - } -} - -unsigned BAAudioEffectDelayExternal::m_allocated[2] = {0, 0}; - -void BAAudioEffectDelayExternal::initialize(MemSelect mem, unsigned delayLength) -{ - unsigned samples = 0; - unsigned memsize, avail; - - m_activeMask = 0; - m_headOffset = 0; - m_mem = mem; - - switch (mem) { - case MemSelect::MEM0 : - { - memsize = Mem0Config.memSize; - m_spi = &SPI; - m_spiChannel = 0; - m_misoPin = Mem0Config.misoPin; - m_mosiPin = Mem0Config.mosiPin; - m_sckPin = Mem0Config.sckPin; - m_csPin = Mem0Config.csPin; - - m_spi->setMOSI(m_mosiPin); - m_spi->setMISO(m_misoPin); - m_spi->setSCK(m_sckPin); - m_spi->begin(); - break; - } - case MemSelect::MEM1 : - { -#if defined(__MK64FX512__) || defined(__MK66FX1M0__) - memsize = Mem1Config.memSize; - m_spi = &SPI1; - m_spiChannel = 1; - m_misoPin = Mem1Config.misoPin; - m_mosiPin = Mem1Config.mosiPin; - m_sckPin = Mem1Config.sckPin; - m_csPin = Mem1Config.csPin; - - m_spi->setMOSI(m_mosiPin); - m_spi->setMISO(m_misoPin); - m_spi->setSCK(m_sckPin); - m_spi->begin(); -#endif - break; - } - - } - - pinMode(m_csPin, OUTPUT); - digitalWriteFast(m_csPin, HIGH); - - avail = memsize - m_allocated[mem]; - - if (delayLength > avail) samples = avail; - m_memoryStart = m_allocated[mem]; - m_allocated[mem] += samples; - m_memoryLength = samples; - - zero(0, m_memoryLength); - -} - - -void BAAudioEffectDelayExternal::read(uint32_t offset, uint32_t count, int16_t *data) -{ - uint32_t addr = m_memoryStart + offset; - addr *= 2; - - m_spi->beginTransaction(SPISETTING); - digitalWriteFast(m_csPin, LOW); - m_spi->transfer16((0x03 << 8) | (addr >> 16)); - m_spi->transfer16(addr & 0xFFFF); - - while (count) { - *data++ = (int16_t)(m_spi->transfer16(0)); - count--; - } - digitalWriteFast(m_csPin, HIGH); - m_spi->endTransaction(); - -} - -void BAAudioEffectDelayExternal::write(uint32_t offset, uint32_t count, const int16_t *data) -{ - uint32_t addr = m_memoryStart + offset; - - addr *= 2; - m_spi->beginTransaction(SPISETTING); - digitalWriteFast(m_csPin, LOW); - m_spi->transfer16((0x02 << 8) | (addr >> 16)); - m_spi->transfer16(addr & 0xFFFF); - while (count) { - int16_t w = 0; - if (data) w = *data++; - m_spi->transfer16(w); - count--; - } - digitalWriteFast(m_csPin, HIGH); - m_spi->endTransaction(); - -} - -/////////////////////////////////////////////////////////////////// -// PRIVATE METHODS -/////////////////////////////////////////////////////////////////// -void BAAudioEffectDelayExternal::zero(uint32_t address, uint32_t count) { - write(address, count, NULL); -} - -#ifdef SPI_HAS_NOTUSINGINTERRUPT -inline void BAAudioEffectDelayExternal::m_startUsingSPI(int spiBus) { - if (spiBus == 0) { - m_spi->usingInterrupt(IRQ_SOFTWARE); - } else if (spiBus == 1) { - m_spi->usingInterrupt(IRQ_SOFTWARE); - } - m_usingSPICount[spiBus]++; -} - -inline void BAAudioEffectDelayExternal::m_stopUsingSPI(int spiBus) { - if (m_usingSPICount[spiBus] == 0 || --m_usingSPICount[spiBus] == 0) - { - if (spiBus == 0) { - m_spi->notUsingInterrupt(IRQ_SOFTWARE); - } else if (spiBus == 1) { - m_spi->notUsingInterrupt(IRQ_SOFTWARE); - } - - } -} - -#else -inline void BAAudioEffectDelayExternal::m_startUsingSPI(int spiBus) { - if (spiBus == 0) { - m_spi->usingInterrupt(IRQ_SOFTWARE); - } else if (spiBus == 1) { - m_spi->usingInterrupt(IRQ_SOFTWARE); - } - -} -inline void BAAudioEffectDelayExternal::m_stopUsingSPI(int spiBus) { -} - -#endif - - -} /* namespace BAEffects */ diff --git a/src/effects/AudioEffectSOS.cpp b/src/effects/AudioEffectSOS.cpp deleted file mode 100644 index 2512261..0000000 --- a/src/effects/AudioEffectSOS.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* - * AudioEffectSOS.cpp - * - * Created on: Apr 14, 2018 - * Author: blackaddr - */ - -#include "AudioEffectSOS.h" -#include "LibBasicFunctions.h" - -using namespace BALibrary; - -namespace BAEffects { - -constexpr int MIDI_CHANNEL = 0; -constexpr int MIDI_CONTROL = 1; - -constexpr float MAX_GATE_OPEN_TIME_MS = 3000.0f; -constexpr float MAX_GATE_CLOSE_TIME_MS = 1000.0f; - -constexpr int GATE_OPEN_STAGE = 0; -constexpr int GATE_HOLD_STAGE = 1; -constexpr int GATE_CLOSE_STAGE = 2; - -AudioEffectSOS::AudioEffectSOS(float maxDelayMs) -: AudioStream(1, m_inputQueueArray) -{ - m_memory = new AudioDelay(maxDelayMs); - m_maxDelaySamples = calcAudioSamples(maxDelayMs); - m_externalMemory = false; -} - -AudioEffectSOS::AudioEffectSOS(size_t numSamples) -: AudioStream(1, m_inputQueueArray) -{ - m_memory = new AudioDelay(numSamples); - m_maxDelaySamples = numSamples; - m_externalMemory = false; -} - -AudioEffectSOS::AudioEffectSOS(ExtMemSlot *slot) -: AudioStream(1, m_inputQueueArray) -{ - m_memory = new AudioDelay(slot); - m_externalMemory = true; -} - -AudioEffectSOS::~AudioEffectSOS() -{ - if (m_memory) delete m_memory; -} - -void AudioEffectSOS::setGateLedGpio(int pinId) -{ - m_gateLedPinId = pinId; - pinMode(static_cast(m_gateLedPinId), OUTPUT); -} - -void AudioEffectSOS::enable(void) -{ - m_enable = true; - if (m_externalMemory) { - // Because we hold the previous output buffer for an update cycle, the maximum delay is actually - // 1 audio block mess then the max delay returnable from the memory. - m_maxDelaySamples = m_memory->getMaxDelaySamples(); - Serial.println(String("SOS Enabled with delay length ") + m_maxDelaySamples + String(" samples")); - } - m_delaySamples = m_maxDelaySamples; - m_inputGateAuto.setupParameter(GATE_OPEN_STAGE, 0.0f, 1.0f, 1000.0f, ParameterAutomation::Function::EXPONENTIAL); - m_inputGateAuto.setupParameter(GATE_HOLD_STAGE, 1.0f, 1.0f, m_maxDelaySamples, ParameterAutomation::Function::HOLD); - m_inputGateAuto.setupParameter(GATE_CLOSE_STAGE, 1.0f, 0.0f, 1000.0f, ParameterAutomation::Function::EXPONENTIAL); - - m_clearFeedbackAuto.setupParameter(GATE_OPEN_STAGE, 1.0f, 0.0f, 1000.0f, ParameterAutomation::Function::EXPONENTIAL); - m_clearFeedbackAuto.setupParameter(GATE_HOLD_STAGE, 0.0f, 0.0f, m_maxDelaySamples, ParameterAutomation::Function::HOLD); - m_clearFeedbackAuto.setupParameter(GATE_CLOSE_STAGE, 0.0f, 1.0f, 1000.0f, ParameterAutomation::Function::EXPONENTIAL); -} - -void AudioEffectSOS::update(void) -{ - audio_block_t *inputAudioBlock = receiveReadOnly(); // get the next block of input samples - - // Check is block is disabled - if (m_enable == false) { - // do not transmit or process any audio, return as quickly as possible. - if (inputAudioBlock) release(inputAudioBlock); - - // release all held memory resources - if (m_previousBlock) { - release(m_previousBlock); m_previousBlock = nullptr; - } - if (!m_externalMemory) { - // when using internal memory we have to release all references in the ring buffer - while (m_memory->getRingBuffer()->size() > 0) { - audio_block_t *releaseBlock = m_memory->getRingBuffer()->front(); - m_memory->getRingBuffer()->pop_front(); - if (releaseBlock) release(releaseBlock); - } - } - return; - } - - // Check is block is bypassed, if so either transmit input directly or create silence - if ( (m_bypass == true) || (!inputAudioBlock) ) { - // transmit the input directly - if (!inputAudioBlock) { - // create silence - inputAudioBlock = allocate(); - if (!inputAudioBlock) { return; } // failed to allocate - else { - clearAudioBlock(inputAudioBlock); - } - } - transmit(inputAudioBlock, 0); - release(inputAudioBlock); - return; - } - - if (!inputAudioBlock) return; - - // Otherwise perform normal processing - // In order to make use of the SPI DMA, we need to request the read from memory first, - // then do other processing while it fills in the back. - audio_block_t *blockToOutput = nullptr; // this will hold the output audio - blockToOutput = allocate(); - if (!blockToOutput) return; // skip this update cycle due to failure - - // get the data. If using external memory with DMA, this won't be filled until - // later. - m_memory->getSamples(blockToOutput, m_delaySamples); - //Serial.println(String("Delay samples:") + m_delaySamples); - //Serial.println(String("Use dma: ") + m_memory->getSlot()->isUseDma()); - - // If using DMA, we need something else to do while that read executes, so - // move on to input preprocessing - - // Preprocessing - audio_block_t *preProcessed = allocate(); - // mix the input with the feedback path in the pre-processing stage - m_preProcessing(preProcessed, inputAudioBlock, m_previousBlock); - - // consider doing the BBD post processing here to use up more time while waiting - // for the read data to come back - audio_block_t *blockToRelease = m_memory->addBlock(preProcessed); - //audio_block_t *blockToRelease = m_memory->addBlock(inputAudioBlock); - //Serial.println("Done adding new block"); - - - // BACK TO OUTPUT PROCESSING - // Check if external DMA, if so, we need to be sure the read is completed - if (m_externalMemory && m_memory->getSlot()->isUseDma()) { - // Using DMA - while (m_memory->getSlot()->isReadBusy()) {} - } - - // perform the wet/dry mix mix - m_postProcessing(blockToOutput, blockToOutput); - transmit(blockToOutput); - - release(inputAudioBlock); - - if (m_previousBlock) - release(m_previousBlock); - m_previousBlock = blockToOutput; - - if (m_blockToRelease == m_previousBlock) { - Serial.println("ERROR: POINTER COLLISION"); - } - - if (m_blockToRelease) release(m_blockToRelease); - m_blockToRelease = blockToRelease; -} - - -void AudioEffectSOS::gateOpenTime(float milliseconds) -{ - // TODO - change the paramter automation to an automation sequence - m_openTimeMs = milliseconds; - m_inputGateAuto.setupParameter(GATE_OPEN_STAGE, 0.0f, 1.0f, m_openTimeMs, ParameterAutomation::Function::EXPONENTIAL); - //m_clearFeedbackAuto.setupParameter(GATE_OPEN_STAGE, 1.0f, 0.0f, m_openTimeMs, ParameterAutomation::Function::EXPONENTIAL); -} - -void AudioEffectSOS::gateCloseTime(float milliseconds) -{ - m_closeTimeMs = milliseconds; - m_inputGateAuto.setupParameter(GATE_CLOSE_STAGE, 1.0f, 0.0f, m_closeTimeMs, ParameterAutomation::Function::EXPONENTIAL); - //m_clearFeedbackAuto.setupParameter(GATE_CLOSE_STAGE, 0.0f, 1.0f, m_closeTimeMs, ParameterAutomation::Function::EXPONENTIAL); -} - -//////////////////////////////////////////////////////////////////////// -// MIDI PROCESSING -//////////////////////////////////////////////////////////////////////// -void AudioEffectSOS::processMidi(int channel, int control, int value) -{ - - float val = (float)value / 127.0f; - - if ((m_midiConfig[GATE_OPEN_TIME][MIDI_CHANNEL] == channel) && - (m_midiConfig[GATE_OPEN_TIME][MIDI_CONTROL] == control)) { - // Gate Open Time - gateOpenTime(val * MAX_GATE_OPEN_TIME_MS); - Serial.println(String("AudioEffectSOS::gate open time (ms): ") + m_openTimeMs); - return; - } - - if ((m_midiConfig[GATE_CLOSE_TIME][MIDI_CHANNEL] == channel) && - (m_midiConfig[GATE_CLOSE_TIME][MIDI_CONTROL] == control)) { - // Gate Close Time - gateCloseTime(val * MAX_GATE_CLOSE_TIME_MS); - Serial.println(String("AudioEffectSOS::gate close time (ms): ") + m_closeTimeMs); - return; - } - - if ((m_midiConfig[FEEDBACK][MIDI_CHANNEL] == channel) && - (m_midiConfig[FEEDBACK][MIDI_CONTROL] == control)) { - // Feedback - Serial.println(String("AudioEffectSOS::feedback: ") + 100*val + String("%")); - feedback(val); - return; - } - - if ((m_midiConfig[VOLUME][MIDI_CHANNEL] == channel) && - (m_midiConfig[VOLUME][MIDI_CONTROL] == control)) { - // Volume - Serial.println(String("AudioEffectSOS::volume: ") + 100*val + String("%")); - volume(val); - return; - } - - if ((m_midiConfig[BYPASS][MIDI_CHANNEL] == channel) && - (m_midiConfig[BYPASS][MIDI_CONTROL] == control)) { - // Bypass - if (value >= 65) { bypass(false); Serial.println(String("AudioEffectSOS::not bypassed -> ON") + value); } - else { bypass(true); Serial.println(String("AudioEffectSOS::bypassed -> OFF") + value); } - return; - } - - if ((m_midiConfig[GATE_TRIGGER][MIDI_CHANNEL] == channel) && - (m_midiConfig[GATE_TRIGGER][MIDI_CONTROL] == control)) { - // The gate is triggered by any value - Serial.println(String("AudioEffectSOS::Gate Triggered!")); - m_inputGateAuto.trigger(); - return; - } - - if ((m_midiConfig[CLEAR_FEEDBACK_TRIGGER][MIDI_CHANNEL] == channel) && - (m_midiConfig[CLEAR_FEEDBACK_TRIGGER][MIDI_CONTROL] == control)) { - // The gate is triggered by any value - Serial.println(String("AudioEffectSOS::Clear feedback Triggered!")); - m_clearFeedbackAuto.trigger(); - return; - } -} - -void AudioEffectSOS::mapMidiControl(int parameter, int midiCC, int midiChannel) -{ - if (parameter >= NUM_CONTROLS) { - return ; // Invalid midi parameter - } - m_midiConfig[parameter][MIDI_CHANNEL] = midiChannel; - m_midiConfig[parameter][MIDI_CONTROL] = midiCC; -} - -////////////////////////////////////////////////////////////////////// -// PRIVATE FUNCTIONS -////////////////////////////////////////////////////////////////////// -void AudioEffectSOS::m_preProcessing (audio_block_t *out, audio_block_t *input, audio_block_t *delayedSignal) -{ - if ( out && input && delayedSignal) { - // Multiply the input signal by the automated gate value - // Multiply the delayed signal by the user set feedback value - // Then combine the two - - float gateVol = m_inputGateAuto.getNextValue(); - float feedbackAdjust = m_clearFeedbackAuto.getNextValue(); - audio_block_t tempAudioBuffer; - - gainAdjust(out, input, gateVol, 0); // last paremeter is coeff shift, 0 bits - gainAdjust(&tempAudioBuffer, delayedSignal, m_feedback*feedbackAdjust, 0); // last parameter is coeff shift, 0 bits - combine(out, out, &tempAudioBuffer); - - } else if (input) { - memcpy(out->data, input->data, sizeof(int16_t) * AUDIO_BLOCK_SAMPLES); - } - - // Update the gate LED - if (m_gateLedPinId >= 0) { - if (m_inputGateAuto.isFinished() && m_clearFeedbackAuto.isFinished()) { - digitalWriteFast(m_gateLedPinId, 0x0); - } else { - digitalWriteFast(m_gateLedPinId, 0x1); - } - } -} - -void AudioEffectSOS::m_postProcessing(audio_block_t *out, audio_block_t *in) -{ - gainAdjust(out, out, m_volume, 0); -} - - -} // namespace BAEffects - - - diff --git a/src/effects/AudioEffectTremolo.cpp b/src/effects/AudioEffectTremolo.cpp deleted file mode 100644 index 0bb4d67..0000000 --- a/src/effects/AudioEffectTremolo.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - * AudioEffectTremolo.cpp - * - * Created on: Jan 7, 2018 - * Author: slascos - */ -#include // std::roundf -#include "AudioEffectTremolo.h" - -using namespace BALibrary; - -namespace BAEffects { - -constexpr int MIDI_CHANNEL = 0; -constexpr int MIDI_CONTROL = 1; - -constexpr float MAX_RATE_HZ = 20.0f; - -AudioEffectTremolo::AudioEffectTremolo() -: AudioStream(1, m_inputQueueArray) -{ - m_osc.setWaveform(m_waveform); -} - -AudioEffectTremolo::~AudioEffectTremolo() -{ -} - -void AudioEffectTremolo::update(void) -{ - audio_block_t *inputAudioBlock = receiveWritable(); // get the next block of input samples - - // Check is block is disabled - if (m_enable == false) { - // do not transmit or process any audio, return as quickly as possible. - if (inputAudioBlock) release(inputAudioBlock); - return; - } - - // Check is block is bypassed, if so either transmit input directly or create silence - if (m_bypass == true) { - // transmit the input directly - if (!inputAudioBlock) { - // create silence - inputAudioBlock = allocate(); - if (!inputAudioBlock) { return; } // failed to allocate - else { - clearAudioBlock(inputAudioBlock); - } - } - transmit(inputAudioBlock, 0); - release(inputAudioBlock); - return; - } - - // DO PROCESSING - // apply modulation wave - float *mod = m_osc.getNextVector(); - for (auto i=0; idata[i]); - inputAudioBlock->data[i] = (int16_t)sample; - } - //Serial.println(String("mod: ") + mod[0]); - - - - //float mod = (m_osc.getNext()+1.0f)/2.0f; // value between -1.0 and +1.0f - //float modVolume = (1.0f - m_depth) + mod*m_depth; // value between 0 to depth - //float finalVolume = m_volume * modVolume; - - // Set the output volume - //gainAdjust(inputAudioBlock, inputAudioBlock, finalVolume, 1); - - transmit(inputAudioBlock); - release(inputAudioBlock); -} - -void AudioEffectTremolo::rate(float rateValue) -{ - float rateAudioBlock = rateValue * MAX_RATE_HZ; - m_osc.setRateAudio(rateAudioBlock); -} - -void AudioEffectTremolo::setWaveform(Waveform waveform) -{ - m_waveform = waveform; - m_osc.setWaveform(waveform); -} - -void AudioEffectTremolo::processMidi(int channel, int control, int value) -{ - - float val = (float)value / 127.0f; - - if ((m_midiConfig[BYPASS][MIDI_CHANNEL] == channel) && - (m_midiConfig[BYPASS][MIDI_CONTROL] == control)) { - // Bypass - if (value >= 65) { bypass(false); Serial.println(String("AudioEffectTremolo::not bypassed -> ON") + value); } - else { bypass(true); Serial.println(String("AudioEffectTremolo::bypassed -> OFF") + value); } - return; - } - - if ((m_midiConfig[RATE][MIDI_CHANNEL] == channel) && - (m_midiConfig[RATE][MIDI_CONTROL] == control)) { - // Rate - rate(val); - Serial.println(String("AudioEffectTremolo::rate: ") + m_rate); - return; - } - - if ((m_midiConfig[DEPTH][MIDI_CHANNEL] == channel) && - (m_midiConfig[DEPTH][MIDI_CONTROL] == control)) { - // Depth - depth(val); - Serial.println(String("AudioEffectTremolo::depth: ") + m_depth); - return; - } - - if ((m_midiConfig[WAVEFORM][MIDI_CHANNEL] == channel) && - (m_midiConfig[WAVEFORM][MIDI_CONTROL] == control)) { - // Waveform - if (value < 16) { - m_waveform = Waveform::SINE; - } else if (value < 32) { - m_waveform = Waveform::TRIANGLE; - } else if (value < 48) { - m_waveform = Waveform::SQUARE; - } else if (value < 64) { - m_waveform = Waveform::SAWTOOTH; - } else if (value < 80) { - m_waveform = Waveform::RANDOM; - } - - Serial.println(String("AudioEffectTremolo::waveform: ") + static_cast(m_waveform)); - return; - } - - if ((m_midiConfig[VOLUME][MIDI_CHANNEL] == channel) && - (m_midiConfig[VOLUME][MIDI_CONTROL] == control)) { - // Volume - Serial.println(String("AudioEffectTremolo::volume: ") + 100*val + String("%")); - volume(val); - return; - } - -} - -void AudioEffectTremolo::mapMidiControl(int parameter, int midiCC, int midiChannel) -{ - if (parameter >= NUM_CONTROLS) { - return ; // Invalid midi parameter - } - m_midiConfig[parameter][MIDI_CHANNEL] = midiChannel; - m_midiConfig[parameter][MIDI_CONTROL] = midiCC; -} - -} - - - diff --git a/src/peripherals/BAAudioControlWM8731.cpp b/src/peripherals/BAAudioControlWM8731.cpp deleted file mode 100644 index f2d635e..0000000 --- a/src/peripherals/BAAudioControlWM8731.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/* - * BAAudioControlWM8731.cpp - * - * Created on: May 22, 2017 - * Author: slascos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ - -#include -#include "BAAudioControlWM8731.h" - -namespace BALibrary { - -// use const instead of define for proper scoping -constexpr int WM8731_I2C_ADDR = 0x1A; - -// The WM8731 register map -constexpr int WM8731_REG_LLINEIN = 0; -constexpr int WM8731_REG_RLINEIN = 1; -constexpr int WM8731_REG_LHEADOUT = 2; -constexpr int WM8731_REG_RHEADOUT = 3; -constexpr int WM8731_REG_ANALOG =4; -constexpr int WM8731_REG_DIGITAL = 5; -constexpr int WM8731_REG_POWERDOWN = 6; -constexpr int WM8731_REG_INTERFACE = 7; -constexpr int WM8731_REG_SAMPLING = 8; -constexpr int WM8731_REG_ACTIVE = 9; -constexpr int WM8731_REG_RESET = 15; - -// Register Masks and Shifts -// Register 0 -constexpr int WM8731_LEFT_INPUT_GAIN_ADDR = 0; -constexpr int WM8731_LEFT_INPUT_GAIN_MASK = 0x1F; -constexpr int WM8731_LEFT_INPUT_GAIN_SHIFT = 0; -constexpr int WM8731_LEFT_INPUT_MUTE_ADDR = 0; -constexpr int WM8731_LEFT_INPUT_MUTE_MASK = 0x80; -constexpr int WM8731_LEFT_INPUT_MUTE_SHIFT = 7; -constexpr int WM8731_LINK_LEFT_RIGHT_IN_ADDR = 0; -constexpr int WM8731_LINK_LEFT_RIGHT_IN_MASK = 0x100; -constexpr int WM8731_LINK_LEFT_RIGHT_IN_SHIFT = 8; -// Register 1 -constexpr int WM8731_RIGHT_INPUT_GAIN_ADDR = 1; -constexpr int WM8731_RIGHT_INPUT_GAIN_MASK = 0x1F; -constexpr int WM8731_RIGHT_INPUT_GAIN_SHIFT = 0; -constexpr int WM8731_RIGHT_INPUT_MUTE_ADDR = 1; -constexpr int WM8731_RIGHT_INPUT_MUTE_MASK = 0x80; -constexpr int WM8731_RIGHT_INPUT_MUTE_SHIFT = 7; -constexpr int WM8731_LINK_RIGHT_LEFT_IN_ADDR = 1; -constexpr int WM8731_LINK_RIGHT_LEFT_IN_MASK = 0x100; -constexpr int WM8731_LINK_RIGHT_LEFT_IN_SHIFT = 8; -// Register 2 -constexpr int WM8731_LEFT_HEADPHONE_VOL_ADDR = 2; -constexpr int WM8731_LEFT_HEADPHONE_VOL_MASK = 0x7F; -constexpr int WM8731_LEFT_HEADPHONE_VOL_SHIFT = 0; -constexpr int WM8731_LEFT_HEADPHONE_ZCD_ADDR = 2; -constexpr int WM8731_LEFT_HEADPHONE_ZCD_MASK = 0x80; -constexpr int WM8731_LEFT_HEADPHONE_ZCD_SHIFT = 7; -constexpr int WM8731_LEFT_HEADPHONE_LINK_ADDR = 2; -constexpr int WM8731_LEFT_HEADPHONE_LINK_MASK = 0x100; -constexpr int WM8731_LEFT_HEADPHONE_LINK_SHIFT = 8; -// Register 3 -constexpr int WM8731_RIGHT_HEADPHONE_VOL_ADDR = 3; -constexpr int WM8731_RIGHT_HEADPHONE_VOL_MASK = 0x7F; -constexpr int WM8731_RIGHT_HEADPHONE_VOL_SHIFT = 0; -constexpr int WM8731_RIGHT_HEADPHONE_ZCD_ADDR = 3; -constexpr int WM8731_RIGHT_HEADPHONE_ZCD_MASK = 0x80; -constexpr int WM8731_RIGHT_HEADPHONE_ZCD_SHIFT = 7; -constexpr int WM8731_RIGHT_HEADPHONE_LINK_ADDR = 3; -constexpr int WM8731_RIGHT_HEADPHONE_LINK_MASK = 0x100; -constexpr int WM8731_RIGHT_HEADPHONE_LINK_SHIFT = 8; -// Register 4 -constexpr int WM8731_ADC_BYPASS_ADDR = 4; -constexpr int WM8731_ADC_BYPASS_MASK = 0x8; -constexpr int WM8731_ADC_BYPASS_SHIFT = 3; -constexpr int WM8731_DAC_SELECT_ADDR = 4; -constexpr int WM8731_DAC_SELECT_MASK = 0x10; -constexpr int WM8731_DAC_SELECT_SHIFT = 4; -// Register 5 -constexpr int WM8731_DAC_MUTE_ADDR = 5; -constexpr int WM8731_DAC_MUTE_MASK = 0x8; -constexpr int WM8731_DAC_MUTE_SHIFT = 3; -constexpr int WM8731_HPF_DISABLE_ADDR = 5; -constexpr int WM8731_HPF_DISABLE_MASK = 0x1; -constexpr int WM8731_HPF_DISABLE_SHIFT = 0; -// Register 7 -constexpr int WM8731_LRSWAP_ADDR = 5; -constexpr int WM8731_LRSWAP_MASK = 0x20; -constexpr int WM8731_LRSWAPE_SHIFT = 5; - -// Register 9 -constexpr int WM8731_ACTIVATE_ADDR = 9; -constexpr int WM8731_ACTIVATE_MASK = 0x1; - - -// Reset the internal shadow register array to match -// the reset state of the codec. -void BAAudioControlWM8731::resetInternalReg(void) { - // Set to reset state - regArray[0] = 0x97; - regArray[1] = 0x97; - regArray[2] = 0x79; - regArray[3] = 0x79; - regArray[4] = 0x0a; - regArray[5] = 0x8; - regArray[6] = 0x9f; - regArray[7] = 0xa; - regArray[8] = 0; - regArray[9] = 0; -} - -BAAudioControlWM8731::BAAudioControlWM8731() -{ - resetInternalReg(); -} - -BAAudioControlWM8731::~BAAudioControlWM8731() -{ -} - -// Powerdown and disable the codec -void BAAudioControlWM8731::disable(void) -{ - - //Serial.println("Disabling codec"); - if (m_wireStarted == false) { Wire.begin(); m_wireStarted = true; } - - // set OUTPD to '1' (powerdown), which is bit 4 - regArray[WM8731_REG_POWERDOWN] |= 0x10; - write(WM8731_REG_POWERDOWN, regArray[WM8731_REG_POWERDOWN]); - delay(100); // wait for power down - - // power down the rest of the supplies - write(WM8731_REG_POWERDOWN, 0x9f); // complete codec powerdown - delay(100); - - resetCodec(); -} - -// Powerup and unmute the codec -void BAAudioControlWM8731::enable(void) -{ - - disable(); // disable first in case it was already powered up - - //Serial.println("Enabling codec"); - if (m_wireStarted == false) { Wire.begin(); m_wireStarted = true; } - // Sequence from WAN0111.pdf - - // Begin configuring the codec - resetCodec(); - delay(100); // wait for reset - - // Power up all domains except OUTPD and microphone - regArray[WM8731_REG_POWERDOWN] = 0x12; - write(WM8731_REG_POWERDOWN, regArray[WM8731_REG_POWERDOWN]); - delay(100); // wait for codec powerup - - - setAdcBypass(false); // causes a slight click - setDacSelect(true); - setHPFDisable(true); - setLeftInputGain(0x17); // default input gain - setRightInputGain(0x17); - setLeftInMute(false); // no input mute - setRightInMute(false); - setDacMute(false); // unmute the DAC - - // link, but mute the headphone outputs - regArray[WM8731_REG_LHEADOUT] = WM8731_LEFT_HEADPHONE_LINK_MASK; - write(WM8731_REG_LHEADOUT, regArray[WM8731_REG_LHEADOUT]); // volume off - regArray[WM8731_REG_RHEADOUT] = WM8731_RIGHT_HEADPHONE_LINK_MASK; - write(WM8731_REG_RHEADOUT, regArray[WM8731_REG_RHEADOUT]); - - /// Configure the audio interface - write(WM8731_REG_INTERFACE, 0x02); // I2S, 16 bit, MCLK slave - regArray[WM8731_REG_INTERFACE] = 0x2; - - write(WM8731_REG_SAMPLING, 0x20); // 256*Fs, 44.1 kHz, MCLK/1 - regArray[WM8731_REG_SAMPLING] = 0x20; - delay(100); // wait for interface config - - // Activate the audio interface - setActivate(true); - delay(100); - - write(WM8731_REG_POWERDOWN, 0x02); // power up outputs - regArray[WM8731_REG_POWERDOWN] = 0x02; - delay(500); // wait for output to power up - - //Serial.println("Done codec config"); - - - delay(100); // wait for mute ramp - -} - -// Set the PGA gain on the Left channel -void BAAudioControlWM8731::setLeftInputGain(int val) -{ - regArray[WM8731_LEFT_INPUT_GAIN_ADDR] &= ~WM8731_LEFT_INPUT_GAIN_MASK; - regArray[WM8731_LEFT_INPUT_GAIN_ADDR] |= - ((val << WM8731_LEFT_INPUT_GAIN_SHIFT) & WM8731_LEFT_INPUT_GAIN_MASK); - write(WM8731_LEFT_INPUT_GAIN_ADDR, regArray[WM8731_LEFT_INPUT_GAIN_ADDR]); -} - -// Mute control on the ADC Left channel -void BAAudioControlWM8731::setLeftInMute(bool val) -{ - if (val) { - regArray[WM8731_LEFT_INPUT_MUTE_ADDR] |= WM8731_LEFT_INPUT_MUTE_MASK; - } else { - regArray[WM8731_LEFT_INPUT_MUTE_ADDR] &= ~WM8731_LEFT_INPUT_MUTE_MASK; - } - write(WM8731_LEFT_INPUT_MUTE_ADDR, regArray[WM8731_LEFT_INPUT_MUTE_ADDR]); -} - -// Link the gain/mute controls for Left and Right channels -void BAAudioControlWM8731::setLinkLeftRightIn(bool val) -{ - if (val) { - regArray[WM8731_LINK_LEFT_RIGHT_IN_ADDR] |= WM8731_LINK_LEFT_RIGHT_IN_MASK; - regArray[WM8731_LINK_RIGHT_LEFT_IN_ADDR] |= WM8731_LINK_RIGHT_LEFT_IN_MASK; - } else { - regArray[WM8731_LINK_LEFT_RIGHT_IN_ADDR] &= ~WM8731_LINK_LEFT_RIGHT_IN_MASK; - regArray[WM8731_LINK_RIGHT_LEFT_IN_ADDR] &= ~WM8731_LINK_RIGHT_LEFT_IN_MASK; - } - write(WM8731_LINK_LEFT_RIGHT_IN_ADDR, regArray[WM8731_LINK_LEFT_RIGHT_IN_ADDR]); - write(WM8731_LINK_RIGHT_LEFT_IN_ADDR, regArray[WM8731_LINK_RIGHT_LEFT_IN_ADDR]); -} - -// Set the PGA input gain on the Right channel -void BAAudioControlWM8731::setRightInputGain(int val) -{ - regArray[WM8731_RIGHT_INPUT_GAIN_ADDR] &= ~WM8731_RIGHT_INPUT_GAIN_MASK; - regArray[WM8731_RIGHT_INPUT_GAIN_ADDR] |= - ((val << WM8731_RIGHT_INPUT_GAIN_SHIFT) & WM8731_RIGHT_INPUT_GAIN_MASK); - write(WM8731_RIGHT_INPUT_GAIN_ADDR, regArray[WM8731_RIGHT_INPUT_GAIN_ADDR]); -} - -// Mute control on the input ADC right channel -void BAAudioControlWM8731::setRightInMute(bool val) -{ - if (val) { - regArray[WM8731_RIGHT_INPUT_MUTE_ADDR] |= WM8731_RIGHT_INPUT_MUTE_MASK; - } else { - regArray[WM8731_RIGHT_INPUT_MUTE_ADDR] &= ~WM8731_RIGHT_INPUT_MUTE_MASK; - } - write(WM8731_RIGHT_INPUT_MUTE_ADDR, regArray[WM8731_RIGHT_INPUT_MUTE_ADDR]); -} - -// Left/right swap control -void BAAudioControlWM8731::setLeftRightSwap(bool val) -{ - if (val) { - regArray[WM8731_LRSWAP_ADDR] |= WM8731_LRSWAP_MASK; - } else { - regArray[WM8731_LRSWAP_ADDR] &= ~WM8731_LRSWAP_MASK; - } - write(WM8731_LRSWAP_ADDR, regArray[WM8731_LRSWAP_ADDR]); -} - -void BAAudioControlWM8731::setHeadphoneVolume(float volume) -{ - // the codec volume goes from 0x30 to 0x7F. Anything below 0x30 is mute. - // 0dB gain is 0x79. Total range is 0x50 (80) possible values. - unsigned vol; - constexpr unsigned RANGE = 80.0f; - if (volume < 0.0f) { - vol = 0; - } else if (volume > 1.0f) { - vol = 0x7f; - } else { - vol = 0x2f + static_cast(volume * RANGE); - } - regArray[WM8731_LEFT_HEADPHONE_VOL_ADDR] &= ~WM8731_LEFT_HEADPHONE_VOL_MASK; // clear the volume first - regArray[WM8731_LEFT_HEADPHONE_VOL_ADDR] |= - ((vol << WM8731_LEFT_HEADPHONE_VOL_SHIFT) & WM8731_LEFT_HEADPHONE_VOL_MASK); - write(WM8731_LEFT_HEADPHONE_VOL_ADDR, regArray[WM8731_LEFT_HEADPHONE_VOL_ADDR]); -} - -// Dac output mute control -void BAAudioControlWM8731::setDacMute(bool val) -{ - if (val) { - regArray[WM8731_DAC_MUTE_ADDR] |= WM8731_DAC_MUTE_MASK; - } else { - regArray[WM8731_DAC_MUTE_ADDR] &= ~WM8731_DAC_MUTE_MASK; - } - write(WM8731_DAC_MUTE_ADDR, regArray[WM8731_DAC_MUTE_ADDR]); -} - -// Switches the DAC audio in/out of the output path -void BAAudioControlWM8731::setDacSelect(bool val) -{ - if (val) { - regArray[WM8731_DAC_SELECT_ADDR] |= WM8731_DAC_SELECT_MASK; - } else { - regArray[WM8731_DAC_SELECT_ADDR] &= ~WM8731_DAC_SELECT_MASK; - } - write(WM8731_DAC_SELECT_ADDR, regArray[WM8731_DAC_SELECT_ADDR]); -} - -// Bypass sends the ADC input audio (analog) directly to analog output stage -// bypassing all digital processing -void BAAudioControlWM8731::setAdcBypass(bool val) -{ - if (val) { - regArray[WM8731_ADC_BYPASS_ADDR] |= WM8731_ADC_BYPASS_MASK; - } else { - regArray[WM8731_ADC_BYPASS_ADDR] &= ~WM8731_ADC_BYPASS_MASK; - } - write(WM8731_ADC_BYPASS_ADDR, regArray[WM8731_ADC_BYPASS_ADDR]); -} - -// Enable/disable the dynamic HPF (recommended, it creates noise) -void BAAudioControlWM8731::setHPFDisable(bool val) -{ - if (val) { - regArray[WM8731_HPF_DISABLE_ADDR] |= WM8731_HPF_DISABLE_MASK; - } else { - regArray[WM8731_HPF_DISABLE_ADDR] &= ~WM8731_HPF_DISABLE_MASK; - } - write(WM8731_HPF_DISABLE_ADDR, regArray[WM8731_HPF_DISABLE_ADDR]); -} - -// Activate/deactive the I2S audio interface -void BAAudioControlWM8731::setActivate(bool val) -{ - if (val) { - write(WM8731_ACTIVATE_ADDR, WM8731_ACTIVATE_MASK); - } else { - write(WM8731_ACTIVATE_ADDR, 0); - } - -} - -// Trigger the on-chip codec reset -void BAAudioControlWM8731::resetCodec(void) -{ - write(WM8731_REG_RESET, 0x0); - resetInternalReg(); -} - -// Direct write control to the codec -bool BAAudioControlWM8731::writeI2C(unsigned int addr, unsigned int val) -{ - return write(addr, val); -} - -// Low level write control for the codec via the Teensy I2C interface -bool BAAudioControlWM8731::write(unsigned int reg, unsigned int val) -{ - bool done = false; - - while (!done) { - Wire.beginTransmission(WM8731_I2C_ADDR); - Wire.write((reg << 1) | ((val >> 8) & 1)); - Wire.write(val & 0xFF); - if (byte error = Wire.endTransmission() ) { - (void)error; // supress warning about unused variable - //Serial.println(String("Wire::Error: ") + error + String(" retrying...")); - } else { - done = true; - //Serial.println("Wire::SUCCESS!"); - } - } - - return true; -} - -} /* namespace BALibrary */ diff --git a/src/peripherals/BAGpio.cpp b/src/peripherals/BAGpio.cpp deleted file mode 100644 index e2d3c79..0000000 --- a/src/peripherals/BAGpio.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * BAGpio.cpp - * - * Created on: November 1, 2017 - * Author: slascos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ - -#include "Arduino.h" -#include "BAGpio.h" - -namespace BALibrary { - -BAGpio::BAGpio() -{ - // Set all GPIOs to input - pinMode(static_cast(GPIO::GPIO0), INPUT); - pinMode(static_cast(GPIO::GPIO1), INPUT); - pinMode(static_cast(GPIO::GPIO2), INPUT); - pinMode(static_cast(GPIO::GPIO3), INPUT); - pinMode(static_cast(GPIO::GPIO4), INPUT); - pinMode(static_cast(GPIO::GPIO5), INPUT); - pinMode(static_cast(GPIO::GPIO6), INPUT); - pinMode(static_cast(GPIO::GPIO7), INPUT); - pinMode(static_cast(GPIO::TP1), INPUT); - pinMode(static_cast(GPIO::TP2), INPUT); - - // Set the LED ot ouput - pinMode(USR_LED_ID, OUTPUT); - clearLed(); // turn off the LED - -} - -BAGpio::~BAGpio() -{ -} - -void BAGpio::setGPIODirection(GPIO gpioId, int direction) -{ - pinMode(static_cast(gpioId), direction); -} -void BAGpio::setGPIO(GPIO gpioId) -{ - digitalWrite(static_cast(gpioId), 0x1); -} -void BAGpio::clearGPIO(GPIO gpioId) -{ - digitalWrite(static_cast(gpioId), 0); - -} -int BAGpio::toggleGPIO(GPIO gpioId) -{ - int data = digitalRead(static_cast(gpioId)); - digitalWrite(static_cast(gpioId), ~data); - return ~data; -} - -void BAGpio::setLed() -{ - digitalWrite(USR_LED_ID, 0x1); - m_ledState = 1; -} -void BAGpio::clearLed() -{ - digitalWrite(USR_LED_ID, 0); - m_ledState = 0; -} -int BAGpio::toggleLed() -{ - m_ledState = ~m_ledState; - digitalWrite(USR_LED_ID, m_ledState); - return m_ledState; -} - - -} /* namespace BALibrary */ diff --git a/src/peripherals/BAPhysicalControls.cpp b/src/peripherals/BAPhysicalControls.cpp deleted file mode 100644 index 5904455..0000000 --- a/src/peripherals/BAPhysicalControls.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* - * BAPhysicalControls.cpp - * - * This file provides a class for handling physical controls such as - * switches, pots and rotary encoders. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ -#include "BAPhysicalControls.h" - -// These calls must be define in order to get vector to work on arduino -namespace std { -void __throw_bad_alloc() { - Serial.println("Unable to allocate memory"); - abort(); -} -void __throw_length_error( char const*e ) { - Serial.print("Length Error :"); Serial.println(e); - abort(); -} -} - -namespace BALibrary { - -BAPhysicalControls::BAPhysicalControls(unsigned numSwitches, unsigned numPots, unsigned numEncoders, unsigned numOutputs) { - if (numSwitches > 0) { - m_switches.reserve(numSwitches); - } - if (numPots > 0) { - m_pots.reserve(numPots); - } - if (numEncoders > 0) { - m_encoders.reserve(numEncoders); - } - if (numOutputs > 0) { - m_outputs.reserve(numOutputs); - } - -} - -unsigned BAPhysicalControls::addRotary(uint8_t pin1, uint8_t pin2, bool swapDirection, int divider) { - m_encoders.emplace_back(pin1, pin2, swapDirection, divider); - pinMode(pin1, INPUT); - pinMode(pin2, INPUT); - return m_encoders.size()-1; -} - -unsigned BAPhysicalControls::addSwitch(uint8_t pin, unsigned long intervalMilliseconds) { - //m_switches.emplace_back(pin, intervalMilliseconds);' - m_switches.emplace_back(); - m_switches.back().attach(pin); - m_switches.back().interval(10); - pinMode(pin, INPUT); - return m_switches.size()-1; -} - -unsigned BAPhysicalControls::addPot(uint8_t pin, unsigned minCalibration, unsigned maxCalibration) { - m_pots.emplace_back(pin, minCalibration, maxCalibration); - pinMode(pin, INPUT); - return m_pots.size()-1; -} - -unsigned BAPhysicalControls::addPot(uint8_t pin, unsigned minCalibration, unsigned maxCalibration, bool swapDirection) { - m_pots.emplace_back(pin, minCalibration, maxCalibration, swapDirection); - pinMode(pin, INPUT); - return m_pots.size()-1; -} - -unsigned BAPhysicalControls::addOutput(uint8_t pin) { - m_outputs.emplace_back(pin); - pinMode(pin, OUTPUT); - return m_outputs.size()-1; -} - -void BAPhysicalControls::setOutput(unsigned handle, int val) { - if (handle >= m_outputs.size()) { return; } - m_outputs[handle].set(val); -} - -void BAPhysicalControls::setOutput(unsigned handle, bool val) { - if (handle >= m_outputs.size()) { return; } - unsigned value = val ? 1 : 0; - m_outputs[handle].set(value); -} - -void BAPhysicalControls::toggleOutput(unsigned handle) { - if (handle >= m_outputs.size()) { return; } - m_outputs[handle].toggle(); -} - - -int BAPhysicalControls::getRotaryAdjustUnit(unsigned handle) { - if (handle >= m_encoders.size()) { return 0; } // handle is greater than number of encoders - - int encoderAdjust = m_encoders[handle].getChange(); - if (encoderAdjust != 0) { - // clip the adjust to maximum abs value of 1. - int encoderAdjust = (encoderAdjust > 0) ? 1 : -1; - } - - return encoderAdjust; -} - -bool BAPhysicalControls::checkPotValue(unsigned handle, float &value) { - if (handle >= m_pots.size()) { return false;} // handle is greater than number of pots - return m_pots[handle].getValue(value); -} - -int BAPhysicalControls::getPotRawValue(unsigned handle) -{ - if (handle >= m_pots.size()) { return false;} // handle is greater than number of pots - return m_pots[handle].getRawValue(); -} - -bool BAPhysicalControls::setCalibrationValues(unsigned handle, unsigned min, unsigned max, bool swapDirection) -{ - if (handle >= m_pots.size()) { return false;} // handle is greater than number of pots - m_pots[handle].setCalibrationValues(min, max, swapDirection); - return true; -} - -bool BAPhysicalControls::isSwitchToggled(unsigned handle) { - if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches - DigitalInput &sw = m_switches[handle]; - - return sw.hasInputToggled(); -} - -bool BAPhysicalControls::isSwitchHeld(unsigned handle) -{ - if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches - DigitalInput &sw = m_switches[handle]; - - return sw.isInputAssert(); -} - -bool BAPhysicalControls::getSwitchValue(unsigned handle) -{ - if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches - DigitalInput &sw = m_switches[handle]; - - return sw.read(); -} - -bool BAPhysicalControls::hasSwitchChanged(unsigned handle, bool &switchValue) -{ - if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches - DigitalInput &sw = m_switches[handle]; - - return sw.hasInputChanged(switchValue); -} - -/////////////////////////// -// DigitalInput -/////////////////////////// -bool DigitalInput::hasInputToggled() { - - update(); - if (fell() && (m_isPolarityInverted == false)) { - // switch fell and polarity is not inverted - return true; - } else if (rose() && (m_isPolarityInverted == true)) { - // switch rose and polarity is inveretd - return true; - } else { - return false; - } -} - -bool DigitalInput::isInputAssert() -{ - update(); - // if polarity is inverted, return the opposite state - bool retValue = Bounce::read() ^ m_isPolarityInverted; - return retValue; -} - -bool DigitalInput::getPinInputValue() -{ - update(); - return Bounce::read(); -} - -bool DigitalInput::hasInputChanged(bool &switchState) -{ - update(); - if (rose()) { - // return true if not inverted - switchState = m_isPolarityInverted ? false : true; - return true; - } else if (fell()) { - // return false if not inverted - switchState = m_isPolarityInverted ? true : false; - return true; - } else { - // return current value - switchState = Bounce::read() != m_isPolarityInverted; - return false; - } -} - -/////////////////////////// -// DigitalOutput -/////////////////////////// -void DigitalOutput::set(int val) { - m_val = val; - digitalWriteFast(m_pin, m_val); -} - -void DigitalOutput::toggle(void) { - m_val = !m_val; - digitalWriteFast(m_pin, m_val); -} - -/////////////////////////// -// Potentiometer -/////////////////////////// -Potentiometer::Potentiometer(uint8_t analogPin, unsigned minCalibration, unsigned maxCalibration, bool swapDirection) - : m_pin(analogPin), m_swapDirection(swapDirection), m_minCalibration(minCalibration), m_maxCalibration(maxCalibration) -{ - adjustCalibrationThreshold(m_thresholdFactor); // Calculate the thresholded values -} - - -void Potentiometer::setFeedbackFitlerValue(float fitlerValue) -{ - m_feedbackFitlerValue = fitlerValue; -} - -bool Potentiometer::getValue(float &value) { - - bool newValue = true; - - unsigned val = analogRead(m_pin); // read the raw value - - // constrain it within the calibration values, them map it to the desired range. - val = constrain(val, m_minCalibration, m_maxCalibration); - - // Use an IIR filter to smooth out the noise in the pot readings - unsigned valFilter = static_cast( (1.0f - m_feedbackFitlerValue)*val + (m_feedbackFitlerValue*m_lastValue)); - - if (valFilter == m_lastValue) { - newValue = false; - } - m_lastValue = valFilter; - - // - if (valFilter < m_minCalibrationThresholded) { value = 0.0f; } - else if (valFilter > m_maxCalibrationThresholded) { value = 1.0f; } - else { - value = static_cast(valFilter - m_minCalibrationThresholded) / static_cast(m_rangeThresholded); - } - - if (m_swapDirection) { - value = 1.0f - value; - } - return newValue; -} - -int Potentiometer::getRawValue() { - return analogRead(m_pin); -} - -// Recalculate thresholded limits based on thresholdFactor -void Potentiometer::adjustCalibrationThreshold(float thresholdFactor) -{ - m_thresholdFactor = thresholdFactor; - // the threshold is specificed as a fraction of the min/max range. - unsigned threshold = static_cast((m_maxCalibration - m_minCalibration) * thresholdFactor); - - // Update the thresholded values - m_minCalibrationThresholded = m_minCalibration + threshold; - m_maxCalibrationThresholded = m_maxCalibration - threshold; - m_rangeThresholded = m_maxCalibrationThresholded - m_minCalibrationThresholded; -} - -void Potentiometer::setCalibrationValues(unsigned min, unsigned max, bool swapDirection) -{ - m_minCalibration = min; - m_maxCalibration = max; - m_swapDirection = swapDirection; - adjustCalibrationThreshold(m_thresholdFactor); -} - -Potentiometer::Calib Potentiometer::calibrate(uint8_t pin) { - Calib calib; - - Serial.print("Calibration pin "); Serial.println(pin); - Serial.println("Move the pot fully counter-clockwise to the minimum setting and press any key then ENTER"); - while (true) { - delay(100); - if (Serial.available() > 0) { - calib.min = analogRead(pin); - while (Serial.available()) { Serial.read(); } - break; - } - } - - Serial.println("Move the pot fully clockwise to the maximum setting and press any key then ENTER"); - while (true) { - delay(100); - if (Serial.available() > 0) { - calib.max = analogRead(pin); - while (Serial.available()) { Serial.read(); } - break; - } - } - - if (calib.min > calib.max) { - unsigned tmp = calib.max; - calib.max = calib.min; - calib.min = tmp; - calib.swap = true; - } - - Serial.print("The calibration for pin "); Serial.print(pin); - Serial.print(" is min:"); Serial.print(calib.min); - Serial.print(" max:"); Serial.print(calib.max); - Serial.print(" swap: "); Serial.println(calib.swap); - - return calib; -} - - -int RotaryEncoder::getChange() { - int32_t newPosition = read(); - int delta = newPosition - m_lastPosition; - m_lastPosition = newPosition; - if (m_swapDirection) { delta = -delta; } - return delta/m_divider; -} - -void RotaryEncoder::setDivider(int divider) { - m_divider = divider; -} - -} // BALibrary - - - - diff --git a/src/peripherals/BASpiMemory.cpp b/src/peripherals/BASpiMemory.cpp deleted file mode 100644 index a1fab91..0000000 --- a/src/peripherals/BASpiMemory.cpp +++ /dev/null @@ -1,471 +0,0 @@ -/* - * BASpiMemory.cpp - * - * Created on: May 22, 2017 - * Author: slascos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version.* - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ - -#include "Arduino.h" -#include "BASpiMemory.h" - -namespace BALibrary { - -// MEM0 Settings -constexpr int SPI_CS_MEM0 = 15; -constexpr int SPI_MOSI_MEM0 = 7; -constexpr int SPI_MISO_MEM0 = 8; -constexpr int SPI_SCK_MEM0 = 14; - -// MEM1 Settings -constexpr int SPI_CS_MEM1 = 31; -constexpr int SPI_MOSI_MEM1 = 21; -constexpr int SPI_MISO_MEM1 = 5; -constexpr int SPI_SCK_MEM1 = 20; - -// SPI Constants -constexpr int SPI_WRITE_MODE_REG = 0x1; -constexpr int SPI_WRITE_CMD = 0x2; -constexpr int SPI_READ_CMD = 0x3; -constexpr int SPI_ADDR_2_MASK = 0xFF0000; -constexpr int SPI_ADDR_2_SHIFT = 16; -constexpr int SPI_ADDR_1_MASK = 0x00FF00; -constexpr int SPI_ADDR_1_SHIFT = 8; -constexpr int SPI_ADDR_0_MASK = 0x0000FF; - -constexpr int CMD_ADDRESS_SIZE = 4; -constexpr int MAX_DMA_XFER_SIZE = 0x4000; - -BASpiMemory::BASpiMemory(SpiDeviceId memDeviceId) -{ - m_memDeviceId = memDeviceId; - m_settings = {20000000, MSBFIRST, SPI_MODE0}; -} - -BASpiMemory::BASpiMemory(SpiDeviceId memDeviceId, uint32_t speedHz) -{ - m_memDeviceId = memDeviceId; - m_settings = {speedHz, MSBFIRST, SPI_MODE0}; -} - -// Intitialize the correct Arduino SPI interface -void BASpiMemory::begin() -{ - switch (m_memDeviceId) { - case SpiDeviceId::SPI_DEVICE0 : - m_csPin = SPI_CS_MEM0; - m_spi = &SPI; - m_spi->setMOSI(SPI_MOSI_MEM0); - m_spi->setMISO(SPI_MISO_MEM0); - m_spi->setSCK(SPI_SCK_MEM0); - m_spi->begin(); - break; - -#if defined(__MK64FX512__) || defined(__MK66FX1M0__) - case SpiDeviceId::SPI_DEVICE1 : - m_csPin = SPI_CS_MEM1; - m_spi = &SPI1; - m_spi->setMOSI(SPI_MOSI_MEM1); - m_spi->setMISO(SPI_MISO_MEM1); - m_spi->setSCK(SPI_SCK_MEM1); - m_spi->begin(); - break; -#endif - - default : - // unreachable since memDeviceId is an enumerated class - return; - } - - pinMode(m_csPin, OUTPUT); - digitalWrite(m_csPin, HIGH); - m_started = true; - -} - -BASpiMemory::~BASpiMemory() { -} - -// Single address write -void BASpiMemory::write(size_t address, uint8_t data) -{ - m_spi->beginTransaction(m_settings); - digitalWrite(m_csPin, LOW); - m_spi->transfer(SPI_WRITE_CMD); - m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT); - m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT); - m_spi->transfer((address & SPI_ADDR_0_MASK)); - m_spi->transfer(data); - m_spi->endTransaction(); - digitalWrite(m_csPin, HIGH); -} - -// Single address write -void BASpiMemory::write(size_t address, uint8_t *src, size_t numBytes) -{ - uint8_t *dataPtr = src; - - m_spi->beginTransaction(m_settings); - digitalWrite(m_csPin, LOW); - m_spi->transfer(SPI_WRITE_CMD); - m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT); - m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT); - m_spi->transfer((address & SPI_ADDR_0_MASK)); - - for (size_t i=0; i < numBytes; i++) { - m_spi->transfer(*dataPtr++); - } - m_spi->endTransaction(); - digitalWrite(m_csPin, HIGH); -} - - -void BASpiMemory::zero(size_t address, size_t numBytes) -{ - m_spi->beginTransaction(m_settings); - digitalWrite(m_csPin, LOW); - m_spi->transfer(SPI_WRITE_CMD); - m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT); - m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT); - m_spi->transfer((address & SPI_ADDR_0_MASK)); - - for (size_t i=0; i < numBytes; i++) { - m_spi->transfer(0); - } - m_spi->endTransaction(); - digitalWrite(m_csPin, HIGH); -} - -void BASpiMemory::write16(size_t address, uint16_t data) -{ - m_spi->beginTransaction(m_settings); - digitalWrite(m_csPin, LOW); - m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) ); - m_spi->transfer16(address & 0xFFFF); - m_spi->transfer16(data); - m_spi->endTransaction(); - digitalWrite(m_csPin, HIGH); -} - -void BASpiMemory::write16(size_t address, uint16_t *src, size_t numWords) -{ - uint16_t *dataPtr = src; - - m_spi->beginTransaction(m_settings); - digitalWrite(m_csPin, LOW); - m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) ); - m_spi->transfer16(address & 0xFFFF); - - for (size_t i=0; itransfer16(*dataPtr++); - } - - m_spi->endTransaction(); - digitalWrite(m_csPin, HIGH); -} - -void BASpiMemory::zero16(size_t address, size_t numWords) -{ - m_spi->beginTransaction(m_settings); - digitalWrite(m_csPin, LOW); - m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) ); - m_spi->transfer16(address & 0xFFFF); - - for (size_t i=0; itransfer16(0); - } - - m_spi->endTransaction(); - digitalWrite(m_csPin, HIGH); - Serial.println("DONE!"); -} - -// single address read -uint8_t BASpiMemory::read(size_t address) -{ - int data; - - m_spi->beginTransaction(m_settings); - digitalWrite(m_csPin, LOW); - m_spi->transfer(SPI_READ_CMD); - m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT); - m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT); - m_spi->transfer((address & SPI_ADDR_0_MASK)); - data = m_spi->transfer(0); - m_spi->endTransaction(); - digitalWrite(m_csPin, HIGH); - return data; -} - - -void BASpiMemory::read(size_t address, uint8_t *dest, size_t numBytes) -{ - uint8_t *dataPtr = dest; - - m_spi->beginTransaction(m_settings); - digitalWrite(m_csPin, LOW); - m_spi->transfer(SPI_READ_CMD); - m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT); - m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT); - m_spi->transfer((address & SPI_ADDR_0_MASK)); - - for (size_t i=0; itransfer(0); - } - - m_spi->endTransaction(); - digitalWrite(m_csPin, HIGH); -} - -uint16_t BASpiMemory::read16(size_t address) -{ - - uint16_t data; - m_spi->beginTransaction(m_settings); - digitalWrite(m_csPin, LOW); - m_spi->transfer16((SPI_READ_CMD << 8) | (address >> 16) ); - m_spi->transfer16(address & 0xFFFF); - data = m_spi->transfer16(0); - m_spi->endTransaction(); - - digitalWrite(m_csPin, HIGH); - return data; -} - -void BASpiMemory::read16(size_t address, uint16_t *dest, size_t numWords) -{ - - uint16_t *dataPtr = dest; - m_spi->beginTransaction(m_settings); - digitalWrite(m_csPin, LOW); - m_spi->transfer16((SPI_READ_CMD << 8) | (address >> 16) ); - m_spi->transfer16(address & 0xFFFF); - - for (size_t i=0; itransfer16(0); - } - - m_spi->endTransaction(); - digitalWrite(m_csPin, HIGH); -} - -///////////////////////////////////////////////////////////////////////////// -// BASpiMemoryDMA -///////////////////////////////////////////////////////////////////////////// -BASpiMemoryDMA::BASpiMemoryDMA(SpiDeviceId memDeviceId) -: BASpiMemory(memDeviceId) -{ - int cs; - switch (memDeviceId) { - case SpiDeviceId::SPI_DEVICE0 : - cs = SPI_CS_MEM0; - m_cs = new ActiveLowChipSelect(cs, m_settings); - break; -#if defined(__MK66FX1M0__) - case SpiDeviceId::SPI_DEVICE1 : - cs = SPI_CS_MEM1; - m_cs = new ActiveLowChipSelect1(cs, m_settings); - break; -#endif - default : - cs = SPI_CS_MEM0; - } - - // add 4 bytes to buffer for SPI CMD and 3 bytes of address - m_txCommandBuffer = new uint8_t[CMD_ADDRESS_SIZE]; - m_rxCommandBuffer = new uint8_t[CMD_ADDRESS_SIZE]; - m_txTransfer = new DmaSpi::Transfer[2]; - m_rxTransfer = new DmaSpi::Transfer[2]; -} - -BASpiMemoryDMA::BASpiMemoryDMA(SpiDeviceId memDeviceId, uint32_t speedHz) -: BASpiMemory(memDeviceId, speedHz) -{ - int cs; - switch (memDeviceId) { - case SpiDeviceId::SPI_DEVICE0 : - cs = SPI_CS_MEM0; - m_cs = new ActiveLowChipSelect(cs, m_settings); - break; -#if defined(__MK66FX1M0__) - case SpiDeviceId::SPI_DEVICE1 : - cs = SPI_CS_MEM1; - m_cs = new ActiveLowChipSelect1(cs, m_settings); - break; -#endif - default : - cs = SPI_CS_MEM0; - } - - m_txCommandBuffer = new uint8_t[CMD_ADDRESS_SIZE]; - m_rxCommandBuffer = new uint8_t[CMD_ADDRESS_SIZE]; - m_txTransfer = new DmaSpi::Transfer[2]; - m_rxTransfer = new DmaSpi::Transfer[2]; -} - -BASpiMemoryDMA::~BASpiMemoryDMA() -{ - delete m_cs; - if (m_txTransfer) delete [] m_txTransfer; - if (m_rxTransfer) delete [] m_rxTransfer; - if (m_txCommandBuffer) delete [] m_txCommandBuffer; - if (m_rxCommandBuffer) delete [] m_txCommandBuffer; -} - -void BASpiMemoryDMA::m_setSpiCmdAddr(int command, size_t address, uint8_t *dest) -{ - dest[0] = command; - dest[1] = ((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT); - dest[2] = ((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT); - dest[3] = ((address & SPI_ADDR_0_MASK)); -} - -void BASpiMemoryDMA::begin(void) -{ - switch (m_memDeviceId) { - case SpiDeviceId::SPI_DEVICE0 : - m_csPin = SPI_CS_MEM0; - m_spi = &SPI; - m_spi->setMOSI(SPI_MOSI_MEM0); - m_spi->setMISO(SPI_MISO_MEM0); - m_spi->setSCK(SPI_SCK_MEM0); - m_spi->begin(); - //m_spiDma = &DMASPI0; - m_spiDma = new DmaSpiGeneric(); - break; - -#if defined(__MK66FX1M0__) // DMA on SPI1 is only supported on T3.6 - case SpiDeviceId::SPI_DEVICE1 : - m_csPin = SPI_CS_MEM1; - m_spi = &SPI1; - m_spi->setMOSI(SPI_MOSI_MEM1); - m_spi->setMISO(SPI_MISO_MEM1); - m_spi->setSCK(SPI_SCK_MEM1); - m_spi->begin(); - m_spiDma = new DmaSpiGeneric(1); - //m_spiDma = &DMASPI1; - break; -#endif - - default : - // unreachable since memDeviceId is an enumerated class - return; - } - - m_spiDma->begin(); - m_spiDma->start(); - - m_started = true; -} - - - -// SPI must build up a payload that starts the teh CMD/Address first. It will cycle -// through the payloads in a circular buffer and use the transfer objects to check if they -// are done before continuing. -void BASpiMemoryDMA::write(size_t address, uint8_t *src, size_t numBytes) -{ - size_t bytesRemaining = numBytes; - uint8_t *srcPtr = src; - size_t nextAddress = address; - while (bytesRemaining > 0) { - m_txXferCount = min(bytesRemaining, static_cast(MAX_DMA_XFER_SIZE)); - while ( m_txTransfer[1].busy()) {} // wait until not busy - m_setSpiCmdAddr(SPI_WRITE_CMD, nextAddress, m_txCommandBuffer); - m_txTransfer[1] = DmaSpi::Transfer(m_txCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS); - m_spiDma->registerTransfer(m_txTransfer[1]); - - while ( m_txTransfer[0].busy()) {} // wait until not busy - m_txTransfer[0] = DmaSpi::Transfer(srcPtr, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS); - m_spiDma->registerTransfer(m_txTransfer[0]); - bytesRemaining -= m_txXferCount; - srcPtr += m_txXferCount; - nextAddress += m_txXferCount; - } -} - - -void BASpiMemoryDMA::zero(size_t address, size_t numBytes) -{ - size_t bytesRemaining = numBytes; - size_t nextAddress = address; - while (bytesRemaining > 0) { - m_txXferCount = min(bytesRemaining, static_cast(MAX_DMA_XFER_SIZE)); - while ( m_txTransfer[1].busy()) {} // wait until not busy - m_setSpiCmdAddr(SPI_WRITE_CMD, nextAddress, m_txCommandBuffer); - m_txTransfer[1] = DmaSpi::Transfer(m_txCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS); - m_spiDma->registerTransfer(m_txTransfer[1]); - - while ( m_txTransfer[0].busy()) {} // wait until not busy - m_txTransfer[0] = DmaSpi::Transfer(nullptr, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS); - m_spiDma->registerTransfer(m_txTransfer[0]); - bytesRemaining -= m_txXferCount; - nextAddress += m_txXferCount; - } -} - - -void BASpiMemoryDMA::write16(size_t address, uint16_t *src, size_t numWords) -{ - write(address, reinterpret_cast(src), sizeof(uint16_t)*numWords); -} - -void BASpiMemoryDMA::zero16(size_t address, size_t numWords) -{ - zero(address, sizeof(uint16_t)*numWords); -} - - -void BASpiMemoryDMA::read(size_t address, uint8_t *dest, size_t numBytes) -{ - size_t bytesRemaining = numBytes; - uint8_t *destPtr = dest; - size_t nextAddress = address; - while (bytesRemaining > 0) { - m_setSpiCmdAddr(SPI_READ_CMD, nextAddress, m_rxCommandBuffer); - - while ( m_rxTransfer[1].busy()) {} - m_rxTransfer[1] = DmaSpi::Transfer(m_rxCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS); - m_spiDma->registerTransfer(m_rxTransfer[1]); - - m_rxXferCount = min(bytesRemaining, static_cast(MAX_DMA_XFER_SIZE)); - while ( m_rxTransfer[0].busy()) {} - m_rxTransfer[0] = DmaSpi::Transfer(nullptr, m_rxXferCount, destPtr, 0, m_cs, TransferType::NO_START_CS); - m_spiDma->registerTransfer(m_rxTransfer[0]); - - bytesRemaining -= m_rxXferCount; - destPtr += m_rxXferCount; - nextAddress += m_rxXferCount; - } -} - - -void BASpiMemoryDMA::read16(size_t address, uint16_t *dest, size_t numWords) -{ - read(address, reinterpret_cast(dest), sizeof(uint16_t)*numWords); -} - - -bool BASpiMemoryDMA::isWriteBusy(void) const -{ - return (m_txTransfer[0].busy() or m_txTransfer[1].busy()); -} - -bool BASpiMemoryDMA::isReadBusy(void) const -{ - return (m_rxTransfer[0].busy() or m_rxTransfer[1].busy()); -} - -} /* namespace BALibrary */ diff --git a/src/peripherals/DmaSpi.cpp b/src/peripherals/DmaSpi.cpp deleted file mode 100644 index 2653f6f..0000000 --- a/src/peripherals/DmaSpi.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "DmaSpi.h" - -#if defined(KINETISK) -DmaSpi0 DMASPI0; -#if defined(__MK66FX1M0__) -DmaSpi1 DMASPI1; -//DmaSpi2 DMASPI2; -#endif -#elif defined (KINETISL) -DmaSpi0 DMASPI0; -DmaSpi1 DMASPI1; -#else -#endif // defined