From 6b59f022b387960ae06f5dc2fe6b74bcf6a6ca5d Mon Sep 17 00:00:00 2001 From: Steve Lascos Date: Fri, 19 Jan 2018 16:19:51 -0500 Subject: [PATCH] cleand up AudioEffectAnalogDelay, added wet/dry mix and feedback controls, removed independent channels --- src/AudioEffectAnalogDelay.cpp | 123 +++++++++++++++++---------------- src/AudioEffectAnalogDelay.h | 22 +++--- src/LibBasicFunctions.cpp | 12 ++++ src/LibBasicFunctions.h | 7 ++ 4 files changed, 98 insertions(+), 66 deletions(-) diff --git a/src/AudioEffectAnalogDelay.cpp b/src/AudioEffectAnalogDelay.cpp index 2298d1c..0dfa4f1 100644 --- a/src/AudioEffectAnalogDelay.cpp +++ b/src/AudioEffectAnalogDelay.cpp @@ -13,18 +13,12 @@ AudioEffectAnalogDelay::AudioEffectAnalogDelay(float maxDelay) : AudioStream(1, m_inputQueueArray) { m_memory = new AudioDelay(maxDelay); - for (int i=0; igetRingBuffer()->size() > 0) { + audio_block_t *releaseBlock = m_memory->getRingBuffer()->front(); + m_memory->getRingBuffer()->pop_front(); + if (releaseBlock) release(releaseBlock); + } + } + } + if (m_callCount < 1024) { if (inputAudioBlock) { transmit(inputAudioBlock, 0); @@ -59,10 +76,12 @@ void AudioEffectAnalogDelay::update(void) m_callCount++; Serial.println(String("AudioEffectAnalgDelay::update: ") + m_callCount); - audio_block_t *blockToRelease = m_memory->addBlock(inputAudioBlock); - if (blockToRelease) release(blockToRelease); + // Preprocessing + audio_block_t *preProcessed = allocate(); + m_preProcessing(preProcessed, inputAudioBlock, m_previousBlock); - Serial.print("Active channels: "); Serial.print(m_activeChannels, HEX); Serial.println(""); + audio_block_t *blockToRelease = m_memory->addBlock(preProcessed); + if (blockToRelease) release(blockToRelease); // if (inputAudioBlock) { // transmit(inputAudioBlock, 0); @@ -70,44 +89,25 @@ void AudioEffectAnalogDelay::update(void) // } // return; - // For each active channel, output the delayed audio + // OUTPUT PROCESSING audio_block_t *blockToOutput = nullptr; - for (int channel=0; channelgetBlock(queuePosition.index); // could be nullptr! - if (blockToOutput) transmit(blockToOutput); - continue; - } else { - blockToOutput = allocate(); // allocate if spanning 2 queues - } - } else { - // external memory - blockToOutput = allocate(); // allocate always for external memory - } - - // copy the output data - if (!blockToOutput) continue; // skip this channel due to failure - // copy over data - m_memory->getSamples(blockToOutput, m_channelOffsets[channel]); - - transmit(blockToOutput); - release(blockToOutput); - } + blockToOutput = allocate(); + + // copy the output data + if (!blockToOutput) return; // skip this time due to failure + // copy over data + m_memory->getSamples(blockToOutput, m_delaySamples); + // perform the mix + m_postProcessing(blockToOutput, inputAudioBlock, blockToOutput); + transmit(blockToOutput); + + release(inputAudioBlock); + release(m_previousBlock); + m_previousBlock = blockToOutput; } -bool AudioEffectAnalogDelay::delay(unsigned channel, float milliseconds) +void AudioEffectAnalogDelay::delay(float milliseconds) { - if (channel > MAX_DELAY_CHANNELS-1) // channel id too high - return false; - size_t delaySamples = calcAudioSamples(milliseconds); if (!m_memory) { Serial.println("delay(): m_memory is not valid"); } @@ -128,16 +128,11 @@ bool AudioEffectAnalogDelay::delay(unsigned channel, float milliseconds) } } - m_channelOffsets[channel] = delaySamples; - m_activeChannels |= 1< MAX_DELAY_CHANNELS-1) // channel id too high - return false; - if (!m_memory) { Serial.println("delay(): m_memory is not valid"); } if (!m_externalMemory) { @@ -152,14 +147,26 @@ bool AudioEffectAnalogDelay::delay(unsigned channel, size_t delaySamples) slot->enable(); } } - m_channelOffsets[channel] = delaySamples; - m_activeChannels |= 1<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 && dry && wet) { + alphaBlend(out, dry, wet, m_mix); + } else if (dry) { + memcpy(out->data, dry->data, sizeof(int16_t) * AUDIO_BLOCK_SAMPLES); + } } } diff --git a/src/AudioEffectAnalogDelay.h b/src/AudioEffectAnalogDelay.h index 678bce0..92cbfc0 100644 --- a/src/AudioEffectAnalogDelay.h +++ b/src/AudioEffectAnalogDelay.h @@ -15,8 +15,6 @@ namespace BAGuitar { - - class AudioEffectAnalogDelay : public AudioStream { public: static constexpr int MAX_DELAY_CHANNELS = 8; @@ -28,20 +26,28 @@ public: virtual ~AudioEffectAnalogDelay(); virtual void update(void); - bool delay(unsigned channel, float milliseconds); - bool delay(unsigned channel, size_t delaySamples); - void disable(unsigned channel); + void delay(float milliseconds); + void delay(size_t delaySamples); + void feedback(float feedback) { m_feedback = feedback; } + void mix(float mix) { m_mix = mix; } + void enable() { m_enable = true; } + void disable() { m_enable = false; } private: audio_block_t *m_inputQueueArray[1]; - unsigned m_activeChannels = 0; + bool m_enable = false; bool m_externalMemory = false; AudioDelay *m_memory = nullptr; - //size_t m_numQueues = 0; - size_t m_channelOffsets[MAX_DELAY_CHANNELS]; + size_t m_delaySamples = 0; + float m_feedback = 0.0f; + float m_mix = 0.0f; size_t m_callCount = 0; + + audio_block_t *m_previousBlock = nullptr; + 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); }; } diff --git a/src/LibBasicFunctions.cpp b/src/LibBasicFunctions.cpp index d7f3a45..a94bb53 100644 --- a/src/LibBasicFunctions.cpp +++ b/src/LibBasicFunctions.cpp @@ -32,6 +32,18 @@ size_t calcOffset(QueuePosition position) return (position.index*AUDIO_BLOCK_SAMPLES) + position.offset; } +audio_block_t alphaBlend(audio_block_t *out, audio_block_t *dry, audio_block_t* wet, float mix) +{ + for (int i=0; i< AUDIO_BLOCK_SAMPLES; i++) { + out->data[i] = (dry->data[i] * (1 - mix)) + (wet->data[i] * mix); + } +} + +void clearAudioBlock(audio_block_t *block) +{ + memset(block->data, 0, sizeof(int16_t)*AUDIO_BLOCK_SAMPLES); +} + AudioDelay::AudioDelay(size_t maxSamples) : m_slot(nullptr) diff --git a/src/LibBasicFunctions.h b/src/LibBasicFunctions.h index 57b00df..cdaa811 100644 --- a/src/LibBasicFunctions.h +++ b/src/LibBasicFunctions.h @@ -68,6 +68,11 @@ size_t calcAudioSamples(float milliseconds); /// specified position. size_t calcOffset(QueuePosition position); +void clearAudioBlock(audio_block_t *block); + + +audio_block_t alphaBlend(audio_block_t *out, audio_block_t *dry, audio_block_t* wet, float mix); + template class RingBuffer; // forward declare so AudioDelay can use it. @@ -133,6 +138,8 @@ public: /// @returns pointer to the underlying ExtMemSlot. ExtMemSlot *getSlot() const { return m_slot; } + RingBuffer *getRingBuffer() const { return m_ringBuffer; } + private: /// enumerates whether the underlying memory buffer uses INTERNAL or EXTERNAL memory