wip - linear parameter automation is now working

master
Steve Lascos 6 years ago
parent ec4a6b26d5
commit 7c2e4d4e90
  1. 13
      src/AudioEffectSOS.h
  2. 8
      src/BAHardware.h
  3. 16
      src/LibBasicFunctions.h
  4. 10
      src/common/AudioDelay.cpp
  5. 8
      src/common/ExternalSramManager.cpp
  6. 108
      src/common/ParameterAutomation.cpp
  7. 5
      src/effects/AudioEffectAnalogDelay.cpp
  8. 74
      src/effects/AudioEffectSOS.cpp

@ -46,6 +46,8 @@ public:
// *** CONSTRUCTORS *** // *** CONSTRUCTORS ***
AudioEffectSOS() = delete; AudioEffectSOS() = delete;
AudioEffectSOS(float maxDelayMs);
AudioEffectSOS(size_t numSamples);
/// Construct an analog delay using external SPI via an ExtMemSlot. The amount of /// 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. /// delay will be determined by the amount of memory in the slot.
@ -66,6 +68,9 @@ public:
/// Note that audio still passes through when bypass is enabled. /// Note that audio still passes through when bypass is enabled.
void bypass(bool byp) { m_bypass = byp; } void bypass(bool byp) { m_bypass = byp; }
/// Activate the gate automation. Input gate will open, then close.
void trigger() { m_inputGateAuto.trigger(); }
/// Set the output volume. This affect both the wet and dry signals. /// Set the output volume. This affect both the wet and dry signals.
/// @details The default is 1.0. /// @details The default is 1.0.
/// @param vol Sets the output volume between -1.0 and +1.0 /// @param vol Sets the output volume between -1.0 and +1.0
@ -74,7 +79,7 @@ public:
// ** ENABLE / DISABLE ** // ** ENABLE / DISABLE **
/// Enables audio processing. Note: when not enabled, CPU load is nearly zero. /// Enables audio processing. Note: when not enabled, CPU load is nearly zero.
void enable() { m_enable = true; } void enable();
/// Disables audio process. When disabled, CPU load is nearly zero. /// Disables audio process. When disabled, CPU load is nearly zero.
void disable() { m_enable = false; } void disable() { m_enable = false; }
@ -123,12 +128,12 @@ private:
float m_volume = 1.0f; float m_volume = 1.0f;
// Automated Controls // Automated Controls
BALibrary::ParameterAutomation<float> m_inputGateAuto = BALibrary::ParameterAutomationSequence<float> m_inputGateAuto =
BALibrary::ParameterAutomation<float>(0.0f, 1.0f, 0.0f, BALibrary::ParameterAutomation<float>::Function::LINEAR); BALibrary::ParameterAutomationSequence<float>(3);
// Private functions // Private functions
void m_preProcessing (audio_block_t *out, audio_block_t *input, audio_block_t *delayedSignal); 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 *dry, audio_block_t *wet); void m_postProcessing(audio_block_t *out, audio_block_t *input);
}; };
} }

@ -74,11 +74,17 @@ constexpr size_t MEM_MAX_ADDR[NUM_MEM_SLOTS] = { 131071, 131071 };
/**************************************************************************//** /**************************************************************************//**
* General Purpose SPI Interfaces * General Purpose SPI Interfaces
*****************************************************************************/ *****************************************************************************/
enum SpiDeviceId : unsigned { enum class SpiDeviceId : unsigned {
SPI_DEVICE0 = 0, ///< Arduino SPI device SPI_DEVICE0 = 0, ///< Arduino SPI device
SPI_DEVICE1 = 1 ///< Arduino SPI1 device SPI_DEVICE1 = 1 ///< Arduino SPI1 device
}; };
constexpr int SPI_MAX_ADDR = 131071; ///< Max address size per chip 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 #else

@ -153,6 +153,12 @@ public:
/// @returns a pointer to the requested audio_block_t /// @returns a pointer to the requested audio_block_t
audio_block_t *getBlock(size_t index); audio_block_t *getBlock(size_t index);
/// Returns the max possible delay samples. For INTERNAL memory, the delay can be equal to
/// the full maxValue specified. For EXTERNAL memory, the max delay is actually one audio
/// block less then the full size to prevent wrapping.
/// @returns the maximum delay offset in units of samples.
size_t getMaxDelaySamples();
/// Retrieve an audio block (or samples) from the buffer. /// Retrieve an audio block (or samples) from the buffer.
/// @details when using INTERNAL memory, only supported size is AUDIO_BLOCK_SAMPLES. When using /// @details when using INTERNAL memory, only supported size is AUDIO_BLOCK_SAMPLES. When using
/// EXTERNAL, a size smaller than AUDIO_BLOCK_SAMPLES can be requested. /// EXTERNAL, a size smaller than AUDIO_BLOCK_SAMPLES can be requested.
@ -167,6 +173,8 @@ public:
/// @returns pointer to the underlying ExtMemSlot. /// @returns pointer to the underlying ExtMemSlot.
ExtMemSlot *getSlot() const { return m_slot; } ExtMemSlot *getSlot() const { return m_slot; }
/// Ween using INTERNAL memory, thsi function can return a pointer to the underlying RingBuffer that contains /// Ween using INTERNAL memory, thsi function can return a pointer to the underlying RingBuffer that contains
/// audio_block_t * pointers. /// audio_block_t * pointers.
/// @returns pointer to the underlying RingBuffer /// @returns pointer to the underlying RingBuffer
@ -183,6 +191,7 @@ private:
MemType m_type; ///< when 0, INTERNAL memory, when 1, external MEMORY. MemType m_type; ///< when 0, INTERNAL memory, when 1, external MEMORY.
RingBuffer<audio_block_t *> *m_ringBuffer = nullptr; ///< When using INTERNAL memory, a RingBuffer will be created. RingBuffer<audio_block_t *> *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. 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.
}; };
/**************************************************************************//** /**************************************************************************//**
@ -317,6 +326,7 @@ class ParameterAutomation
public: public:
enum class Function : unsigned { enum class Function : unsigned {
NOT_CONFIGURED = 0, ///< Initial, unconfigured stage NOT_CONFIGURED = 0, ///< Initial, unconfigured stage
HOLD, ///< f(x) = constant
LINEAR, ///< f(x) = x LINEAR, ///< f(x) = x
EXPONENTIAL, ///< f(x) = e^x EXPONENTIAL, ///< f(x) = e^x
LOGARITHMIC, ///< f(x) = ln(x) LOGARITHMIC, ///< f(x) = ln(x)
@ -350,9 +360,10 @@ private:
T m_startValue; T m_startValue;
T m_endValue; T m_endValue;
bool m_running = false; bool m_running = false;
T m_currentValueX; ///< the current value of x in f(x) float m_currentValueX; ///< the current value of x in f(x)
size_t m_duration; size_t m_duration;
T m_coeffs[3]; ///< some general coefficient storage float m_coeffs[3]; ///< some general coefficient storage
bool m_positiveSlope = true;
}; };
@ -380,6 +391,7 @@ private:
ParameterAutomation<T> *m_paramArray[MAX_PARAMETER_SEQUENCES]; ParameterAutomation<T> *m_paramArray[MAX_PARAMETER_SEQUENCES];
int m_currentIndex = 0; int m_currentIndex = 0;
int m_numStages = 0; int m_numStages = 0;
bool m_running = false;
}; };
} // BALibrary } // BALibrary

@ -34,6 +34,7 @@ AudioDelay::AudioDelay(size_t maxSamples)
// INTERNAL memory consisting of audio_block_t data structures. // INTERNAL memory consisting of audio_block_t data structures.
QueuePosition pos = calcQueuePosition(maxSamples); QueuePosition pos = calcQueuePosition(maxSamples);
m_ringBuffer = new RingBuffer<audio_block_t *>(pos.index+2); // If the delay is in queue x, we need to overflow into x+1, thus x+2 total buffers. m_ringBuffer = new RingBuffer<audio_block_t *>(pos.index+2); // If the delay is in queue x, we need to overflow into x+1, thus x+2 total buffers.
m_maxDelaySamples = maxSamples;
} }
AudioDelay::AudioDelay(float maxDelayTimeMs) AudioDelay::AudioDelay(float maxDelayTimeMs)
@ -46,6 +47,7 @@ AudioDelay::AudioDelay(ExtMemSlot *slot)
{ {
m_type = (MemType::MEM_EXTERNAL); m_type = (MemType::MEM_EXTERNAL);
m_slot = slot; m_slot = slot;
m_maxDelaySamples = (slot->size() / sizeof(int16_t)) - AUDIO_BLOCK_SAMPLES;
} }
AudioDelay::~AudioDelay() AudioDelay::~AudioDelay()
@ -93,6 +95,11 @@ audio_block_t* AudioDelay::getBlock(size_t index)
return ret; return ret;
} }
size_t AudioDelay::getMaxDelaySamples()
{
return m_maxDelaySamples;
}
bool AudioDelay::getSamples(audio_block_t *dest, size_t offsetSamples, size_t numSamples) bool AudioDelay::getSamples(audio_block_t *dest, size_t offsetSamples, size_t numSamples)
{ {
if (!dest) { if (!dest) {
@ -159,8 +166,9 @@ bool AudioDelay::getSamples(audio_block_t *dest, size_t offsetSamples, size_t nu
return true; return true;
} else { } else {
// numSampmles is > than total slot size // numSamples is > than total slot size
Serial.println("getSamples(): ERROR numSamples > total slot size"); Serial.println("getSamples(): ERROR numSamples > total slot size");
Serial.println(numSamples + String(" > ") + m_slot->size());
return false; return false;
} }
} }

@ -37,8 +37,8 @@ ExternalSramManager::ExternalSramManager(unsigned numMemories)
// Initialize the static memory configuration structs // Initialize the static memory configuration structs
if (!m_configured) { if (!m_configured) {
for (unsigned i=0; i < NUM_MEM_SLOTS; i++) { for (unsigned i=0; i < NUM_MEM_SLOTS; i++) {
m_memConfig[i].size = MEM_MAX_ADDR[i]; m_memConfig[i].size = MEM_MAX_ADDR[i]+1;
m_memConfig[i].totalAvailable = MEM_MAX_ADDR[i]; m_memConfig[i].totalAvailable = MEM_MAX_ADDR[i]+1;
m_memConfig[i].nextAvailable = 0; m_memConfig[i].nextAvailable = 0;
m_memConfig[i].m_spi = nullptr; m_memConfig[i].m_spi = nullptr;
@ -111,7 +111,9 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGu
return true; return true;
} else { } else {
// there is not enough memory available for the request // 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; return false;
} }
} }

@ -28,6 +28,7 @@ namespace BALibrary {
// ParameterAutomation // ParameterAutomation
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
constexpr int LINEAR_SLOPE = 0; constexpr int LINEAR_SLOPE = 0;
template <class T> template <class T>
ParameterAutomation<T>::ParameterAutomation() ParameterAutomation<T>::ParameterAutomation()
{ {
@ -64,10 +65,20 @@ void ParameterAutomation<T>::reconfigure(T startValue, T endValue, size_t durati
m_function = function; m_function = function;
m_startValue = startValue; m_startValue = startValue;
m_endValue = endValue; m_endValue = endValue;
m_currentValueX = startValue; m_currentValueX = static_cast<float>(startValue);
m_duration = durationSamples; m_duration = durationSamples;
m_running = false; m_running = false;
if (endValue >= startValue) {
// value is increasing
m_positiveSlope = true;
} else {
// value is decreasing
m_positiveSlope = false;
}
float duration = m_duration / static_cast<float>(AUDIO_BLOCK_SAMPLES);
// Pre-compute any necessary coefficients // Pre-compute any necessary coefficients
switch(m_function) { switch(m_function) {
case Function::EXPONENTIAL : case Function::EXPONENTIAL :
@ -80,9 +91,14 @@ void ParameterAutomation<T>::reconfigure(T startValue, T endValue, size_t durati
break; break;
// Default will be same as LINEAR // Default will be same as LINEAR
case Function::HOLD :
m_coeffs[LINEAR_SLOPE] = (1.0f / static_cast<float>(duration)); // convert duration from ms to sec
break;
case Function::LINEAR : case Function::LINEAR :
default : default :
m_coeffs[LINEAR_SLOPE] = (endValue - startValue) / static_cast<T>(m_duration); // The number of parameter updates will be duration in samples divided by audio sample block size since
// we only update once per block.
m_coeffs[LINEAR_SLOPE] = static_cast<float>(endValue - startValue) / duration; // convert duration from ms to sec
break; break;
} }
} }
@ -91,13 +107,33 @@ void ParameterAutomation<T>::reconfigure(T startValue, T endValue, size_t durati
template <class T> template <class T>
void ParameterAutomation<T>::trigger() void ParameterAutomation<T>::trigger()
{ {
m_currentValueX = m_startValue; if (m_function == Function::HOLD) {
// The HOLD function will move currentValueX from 0 to 1.0 over the desired duration,
// but will always return the startValue.
m_currentValueX = 0.0f;
} else {
m_currentValueX = static_cast<float>(m_startValue);
}
m_running = true; m_running = true;
//Serial.println("ParameterAutomation<T>::trigger() called");
} }
template <class T> template <class T>
T ParameterAutomation<T>::getNextValue() T ParameterAutomation<T>::getNextValue()
{ {
if (m_running == false) {
return m_startValue;
}
if (m_function == Function::HOLD) {
// HOLD is treated as a special case
m_currentValueX += m_coeffs[LINEAR_SLOPE];
if (m_currentValueX >= 1.0) {
m_running = false;
}
return m_startValue;
}
switch(m_function) { switch(m_function) {
case Function::EXPONENTIAL : case Function::EXPONENTIAL :
break; break;
@ -107,24 +143,28 @@ T ParameterAutomation<T>::getNextValue()
break; break;
case Function::LOOKUP_TABLE : case Function::LOOKUP_TABLE :
break; break;
// Default will be same as LINEAR
case Function::LINEAR : case Function::LINEAR :
default : default :
// output = m_currentValueX + slope // output = m_currentValueX + slope
m_currentValueX += m_coeffs[LINEAR_SLOPE]; m_currentValueX += m_coeffs[LINEAR_SLOPE];
if (m_currentValueX >= m_endValue) {
m_currentValueX = m_endValue;
m_running = false;
}
break; break;
} }
return m_currentValueX;
// Check if the automation is finished.
if ( ( m_positiveSlope && (m_currentValueX >= m_endValue)) ||
(!m_positiveSlope && (m_currentValueX <= m_endValue)) ) {
m_running = false;
return m_endValue;
} else {
return static_cast<T>(m_currentValueX);
}
} }
// Template instantiation // Template instantiation
//template class MyStack<int, 6>; //template class MyStack<int, 6>;
template class ParameterAutomation<float>; template class ParameterAutomation<float>;
template class ParameterAutomation<int>;
template class ParameterAutomation<unsigned>;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// ParameterAutomationSequence // ParameterAutomationSequence
@ -132,7 +172,6 @@ template class ParameterAutomation<float>;
template <class T> template <class T>
ParameterAutomationSequence<T>::ParameterAutomationSequence(int numStages) ParameterAutomationSequence<T>::ParameterAutomationSequence(int numStages)
{ {
//m_paramArray = malloc(sizeof(ParameterAutomation<T>*) * numStages);
if (numStages < MAX_PARAMETER_SEQUENCES) { if (numStages < MAX_PARAMETER_SEQUENCES) {
for (int i=0; i<numStages; i++) { for (int i=0; i<numStages; i++) {
m_paramArray[i] = new ParameterAutomation<T>(); m_paramArray[i] = new ParameterAutomation<T>();
@ -147,35 +186,63 @@ ParameterAutomationSequence<T>::ParameterAutomationSequence(int numStages)
template <class T> template <class T>
ParameterAutomationSequence<T>::~ParameterAutomationSequence() ParameterAutomationSequence<T>::~ParameterAutomationSequence()
{ {
//if (m_paramArray) { for (int i=0; i<m_numStages; i++) {
for (int i=0; i<m_numStages; i++) { if (m_paramArray[i]) {
if (m_paramArray[i]) { delete m_paramArray[i];
delete m_paramArray[i];
}
} }
// delete m_paramArray; }
//}
} }
template <class T> template <class T>
void ParameterAutomationSequence<T>::setupParameter(int index, T startValue, T endValue, size_t durationSamples, typename ParameterAutomation<T>::Function function) void ParameterAutomationSequence<T>::setupParameter(int index, T startValue, T endValue, size_t durationSamples, typename ParameterAutomation<T>::Function function)
{ {
m_paramArray[index]->reconfigure(startValue, endValue, durationSamples, function); m_paramArray[index]->reconfigure(startValue, endValue, durationSamples, function);
m_currentIndex = 0;
} }
template <class T> template <class T>
void ParameterAutomationSequence<T>::setupParameter(int index, T startValue, T endValue, float durationMilliseconds, typename ParameterAutomation<T>::Function function) void ParameterAutomationSequence<T>::setupParameter(int index, T startValue, T endValue, float durationMilliseconds, typename ParameterAutomation<T>::Function function)
{ {
m_paramArray[index]->reconfigure(startValue, endValue, durationMilliseconds, function); m_paramArray[index]->reconfigure(startValue, endValue, durationMilliseconds, function);
m_currentIndex = 0;
} }
template <class T> template <class T>
void ParameterAutomationSequence<T>::trigger(void) void ParameterAutomationSequence<T>::trigger(void)
{ {
m_currentIndex = 0; m_currentIndex = 0;
for (int i=0; i<m_numStages; i++) { m_paramArray[0]->trigger();
m_paramArray[i]->trigger(); m_running = true;
//Serial.println("ParameterAutomationSequence<T>::trigger() called");
}
template <class T>
T ParameterAutomationSequence<T>::getNextValue()
{
// Get the next value
T nextValue = m_paramArray[m_currentIndex]->getNextValue();
if (m_running) {
//Serial.println(String("ParameterAutomationSequence<T>::getNextValue() is ") + nextValue
// + String(" from stage ") + m_currentIndex);
// If current stage is done, trigger the next
if (m_paramArray[m_currentIndex]->isFinished()) {
Serial.println(String("Finished stage ") + m_currentIndex);
m_currentIndex++;
if (m_currentIndex >= m_numStages) {
// Last stage already finished
m_running = false;
m_currentIndex = 0;
} else {
// trigger the next stage
m_paramArray[m_currentIndex]->trigger();
}
}
} }
return nextValue;
} }
template <class T> template <class T>
@ -188,6 +255,7 @@ bool ParameterAutomationSequence<T>::isFinished()
break; break;
} }
} }
m_running = !finished;
return finished; return finished;
} }

@ -166,6 +166,11 @@ void AudioEffectAnalogDelay::delay(float milliseconds)
{ {
size_t delaySamples = calcAudioSamples(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_memory) { Serial.println("delay(): m_memory is not valid"); }
if (!m_externalMemory) { if (!m_externalMemory) {

@ -19,18 +19,51 @@ constexpr int MIDI_CONTROL = 1;
constexpr float MAX_GATE_OPEN_TIME_MS = 3000.0f; constexpr float MAX_GATE_OPEN_TIME_MS = 3000.0f;
constexpr float MAX_GATE_CLOSE_TIME_MS = 3000.0f; constexpr float MAX_GATE_CLOSE_TIME_MS = 3000.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) AudioEffectSOS::AudioEffectSOS(ExtMemSlot *slot)
: AudioStream(1, m_inputQueueArray) : AudioStream(1, m_inputQueueArray)
{ {
m_memory = new AudioDelay(slot); m_memory = new AudioDelay(slot);
m_maxDelaySamples = (slot->size() / sizeof(int16_t));
m_delaySamples = m_maxDelaySamples;
m_externalMemory = true; m_externalMemory = true;
} }
AudioEffectSOS::~AudioEffectSOS() AudioEffectSOS::~AudioEffectSOS()
{ {
if (m_memory) delete m_memory;
}
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<float>::Function::LINEAR);
m_inputGateAuto.setupParameter(GATE_HOLD_STAGE, 1.0f, 1.0f, 1000.0f, ParameterAutomation<float>::Function::HOLD);
m_inputGateAuto.setupParameter(GATE_CLOSE_STAGE, 1.0f, 0.0f, 1000.0f, ParameterAutomation<float>::Function::LINEAR);
} }
void AudioEffectSOS::update(void) void AudioEffectSOS::update(void)
@ -58,7 +91,7 @@ void AudioEffectSOS::update(void)
} }
// Check is block is bypassed, if so either transmit input directly or create silence // Check is block is bypassed, if so either transmit input directly or create silence
if (m_bypass == true) { if ( (m_bypass == true) || (!inputAudioBlock) ) {
// transmit the input directly // transmit the input directly
if (!inputAudioBlock) { if (!inputAudioBlock) {
// create silence // create silence
@ -73,6 +106,8 @@ void AudioEffectSOS::update(void)
return; return;
} }
if (!inputAudioBlock) return;
// Otherwise perform normal processing // Otherwise perform normal processing
// In order to make use of the SPI DMA, we need to request the read from memory first, // 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. // then do other processing while it fills in the back.
@ -83,6 +118,8 @@ void AudioEffectSOS::update(void)
// get the data. If using external memory with DMA, this won't be filled until // get the data. If using external memory with DMA, this won't be filled until
// later. // later.
m_memory->getSamples(blockToOutput, m_delaySamples); 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 // If using DMA, we need something else to do while that read executes, so
// move on to input preprocessing // move on to input preprocessing
@ -95,6 +132,8 @@ void AudioEffectSOS::update(void)
// consider doing the BBD post processing here to use up more time while waiting // consider doing the BBD post processing here to use up more time while waiting
// for the read data to come back // for the read data to come back
audio_block_t *blockToRelease = m_memory->addBlock(preProcessed); 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 // BACK TO OUTPUT PROCESSING
@ -105,13 +144,19 @@ void AudioEffectSOS::update(void)
} }
// perform the wet/dry mix mix // perform the wet/dry mix mix
//m_postProcessing(blockToOutput, inputAudioBlock, blockToOutput); m_postProcessing(blockToOutput, blockToOutput);
transmit(blockToOutput); transmit(blockToOutput);
release(inputAudioBlock); release(inputAudioBlock);
release(m_previousBlock);
if (m_previousBlock)
release(m_previousBlock);
m_previousBlock = blockToOutput; m_previousBlock = blockToOutput;
if (m_blockToRelease == m_previousBlock) {
Serial.println("ERROR: POINTER COLLISION");
}
if (m_blockToRelease) release(m_blockToRelease); if (m_blockToRelease) release(m_blockToRelease);
m_blockToRelease = blockToRelease; m_blockToRelease = blockToRelease;
} }
@ -121,12 +166,13 @@ void AudioEffectSOS::gateOpenTime(float milliseconds)
{ {
// TODO - change the paramter automation to an automation sequence // TODO - change the paramter automation to an automation sequence
m_openTimeMs = milliseconds; m_openTimeMs = milliseconds;
//m_inputGateAuto.reconfigure(); m_inputGateAuto.setupParameter(GATE_OPEN_STAGE, 0.0f, 1.0f, m_openTimeMs, ParameterAutomation<float>::Function::LINEAR);
} }
void AudioEffectSOS::gateCloseTime(float milliseconds) void AudioEffectSOS::gateCloseTime(float milliseconds)
{ {
m_closeTimeMs = milliseconds; m_closeTimeMs = milliseconds;
m_inputGateAuto.setupParameter(GATE_CLOSE_STAGE, 1.0f, 0.0f, m_closeTimeMs, ParameterAutomation<float>::Function::LINEAR);
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@ -149,7 +195,7 @@ void AudioEffectSOS::processMidi(int channel, int control, int value)
(m_midiConfig[GATE_CLOSE_TIME][MIDI_CONTROL] == control)) { (m_midiConfig[GATE_CLOSE_TIME][MIDI_CONTROL] == control)) {
// Gate Close Time // Gate Close Time
gateCloseTime(val * MAX_GATE_CLOSE_TIME_MS); gateCloseTime(val * MAX_GATE_CLOSE_TIME_MS);
Serial.println(String("AudioEffectSOS::gate close time (ms): ") + m_openTimeMs); Serial.println(String("AudioEffectSOS::gate close time (ms): ") + m_closeTimeMs);
return; return;
} }
@ -180,8 +226,8 @@ void AudioEffectSOS::processMidi(int channel, int control, int value)
if ((m_midiConfig[GATE_TRIGGER][MIDI_CHANNEL] == channel) && if ((m_midiConfig[GATE_TRIGGER][MIDI_CHANNEL] == channel) &&
(m_midiConfig[GATE_TRIGGER][MIDI_CONTROL] == control)) { (m_midiConfig[GATE_TRIGGER][MIDI_CONTROL] == control)) {
// The gate is trigged by any value // The gate is trigged by any value
m_inputGateAuto.trigger();
Serial.println(String("AudioEffectSOS::Gate Triggered!")); Serial.println(String("AudioEffectSOS::Gate Triggered!"));
m_inputGateAuto.trigger();
return; return;
} }
} }
@ -203,17 +249,25 @@ void AudioEffectSOS::m_preProcessing (audio_block_t *out, audio_block_t *input,
if ( out && input && delayedSignal) { if ( out && input && delayedSignal) {
// Multiply the input signal by the automated gate value // Multiply the input signal by the automated gate value
// Multiply the delayed signal by the user set feedback value // Multiply the delayed signal by the user set feedback value
// then mix together.
float gateVol = m_inputGateAuto.getNextValue(); float gateVol = m_inputGateAuto.getNextValue();
//float gateVol = 1.0f;
audio_block_t tempAudioBuffer; audio_block_t tempAudioBuffer;
gainAdjust(out, input, gateVol, 0); // last paremeter is coeff shift, 0 bits gainAdjust(out, input, gateVol, 0); // last paremeter is coeff shift, 0 bits
gainAdjust(&tempAudioBuffer, delayedSignal, m_feedback, 0); // last paremeter is coeff shift, 0 bits gainAdjust(&tempAudioBuffer, delayedSignal, m_feedback, 0); // last parameter is coeff shift, 0 bits
combine(out, out, &tempAudioBuffer); combine(out, out, &tempAudioBuffer);
} else if (input) { } else if (input) {
memcpy(out->data, input->data, sizeof(int16_t) * AUDIO_BLOCK_SAMPLES); memcpy(out->data, input->data, sizeof(int16_t) * AUDIO_BLOCK_SAMPLES);
} }
} }
void AudioEffectSOS::m_postProcessing(audio_block_t *out, audio_block_t *in)
{
gainAdjust(out, out, m_volume, 0);
}
} // namespace BAEffects } // namespace BAEffects

Loading…
Cancel
Save