diff --git a/src/AudioEffectAnalogDelay.cpp b/src/AudioEffectAnalogDelay.cpp index ff2ec8a..43dcf37 100644 --- a/src/AudioEffectAnalogDelay.cpp +++ b/src/AudioEffectAnalogDelay.cpp @@ -18,6 +18,15 @@ AudioEffectAnalogDelay::AudioEffectAnalogDelay(INTERNAL_MEMORY, float maxDelay) } } +AudioEffectAnalogDelay::AudioEffectAnalogDelay(INTERNAL_MEMORY, size_t numSamples) +: AudioStream(1, m_inputQueueArray) +{ + m_memory = new MemAudioBlock(numSamples); + for (int i=0; i 1400) { +// if (inputAudioBlock) release(inputAudioBlock); +// return; +// } + m_callCount++; + Serial.println(String("AudioEffectAnalgDelay::update: ") + m_callCount); + if (m_externalMemory) { // external mem requires an actual write to memory with the new data block @@ -45,13 +79,30 @@ void AudioEffectAnalogDelay::update(void) } else { // internal memory only requires updating the queue of audio block pointers. MemAudioBlock *memory = reinterpret_cast(m_memory); - memory->push(inputAudioBlock); // MemAudioBlock supports nullptrs, no need to check // check to see if the queue has reached full size yet - if (memory->getNumQueues() > m_numQueues) { + //Serial.println(String("memory queues:") + memory->getNumQueues() + String(" m_numQueues:") + m_numQueues); + if (memory->getNumQueues() >= m_numQueues) { release(memory->pop()); } + + // now push in the newest audio block + //Serial.println(String("push ") + (uint32_t)inputAudioBlock); + memory->push(inputAudioBlock); // MemAudioBlock supports nullptrs, no need to check + //Serial.println("done memory->push()"); + +// audio_block_t *output = memory->getQueueBack(); +// Serial.println("got the output"); +// if (output) { +// transmit(output, 0); +// } +// Serial.println("Done transmit"); } +// return; + + + //Serial.print("Active channels: "); Serial.print(m_activeChannels, HEX); Serial.println(""); + // For each active channel, output the delayed audio audio_block_t *blockToOutput = nullptr; @@ -62,10 +113,13 @@ void AudioEffectAnalogDelay::update(void) // internal memory MemAudioBlock *memory = reinterpret_cast(m_memory); QueuePosition queuePosition = calcQueuePosition(m_channelOffsets[channel]); + Serial.println(String("Position info: ") + queuePosition.index + " : " + queuePosition.offset); if (queuePosition.offset == 0) { // only one queue needs to be read out - blockToOutput= memory->getQueue(queuePosition.index); // could be nullptr! - transmit(blockToOutput); + //Serial.println(String("Directly sending queue offset ") + queuePosition.index); + blockToOutput= memory->getQueueBack(queuePosition.index); // could be nullptr! + if (blockToOutput) transmit(blockToOutput); + continue; } else { blockToOutput = allocate(); // allocate if spanning 2 queues } @@ -91,8 +145,43 @@ bool AudioEffectAnalogDelay::delay(unsigned channel, float milliseconds) if (!m_externalMemory) { // Internal memory (AudioStream buffers) + MemAudioBlock *memory = reinterpret_cast(m_memory); + QueuePosition queuePosition = calcQueuePosition(milliseconds); - size_t numQueues = queuePosition.index+1; + Serial.println(String("CONFIG(") + memory->getMaxSize() + String("): delay: queue position ") + queuePosition.index + String(":") + queuePosition.offset); + // we have to take the queue position and add 1 to get the number of queues. But we need to add one more since this + // is the start of the audio buffer, and the AUDIO_BLOCK_SAMPLES will then flow into the next one, so add 2 overall. + size_t numQueues = queuePosition.index+2; + if (numQueues > m_numQueues) + m_numQueues = numQueues; + } else { + // External memory + if (delaySamples > m_memory->getSize()) { + // error, the external memory is not large enough + return false; + } + } + + m_channelOffsets[channel] = delaySamples; + m_activeChannels |= 1< MAX_DELAY_CHANNELS-1) // channel id too high + return false; + + if (!m_externalMemory) { + // Internal memory (AudioStream buffers) + MemAudioBlock *memory = reinterpret_cast(m_memory); + + //QueuePosition queuePosition = calcQueuePosition(milliseconds); + QueuePosition queuePosition = calcQueuePosition(delaySamples); + Serial.println(String("CONFIG(") + memory->getMaxSize() + String("): delay: queue position ") + queuePosition.index + String(":") + queuePosition.offset); + // we have to take the queue position and add 1 to get the number of queues. But we need to add one more since this + // is the start of the audio buffer, and the AUDIO_BLOCK_SAMPLES will then flow into the next one, so add 2 overall. + size_t numQueues = queuePosition.index+2; if (numQueues > m_numQueues) m_numQueues = numQueues; } else { diff --git a/src/AudioEffectAnalogDelay.h b/src/AudioEffectAnalogDelay.h index c14066b..e6be2bb 100644 --- a/src/AudioEffectAnalogDelay.h +++ b/src/AudioEffectAnalogDelay.h @@ -23,11 +23,13 @@ public: AudioEffectAnalogDelay() = delete; AudioEffectAnalogDelay(INTERNAL_MEMORY, float maxDelay); + AudioEffectAnalogDelay(INTERNAL_MEMORY, size_t numSamples); AudioEffectAnalogDelay(EXTERNAL_MEMORY, MemSlot &slot); // requires sufficiently sized pre-allocated memory virtual ~AudioEffectAnalogDelay() {} virtual void update(void); bool delay(unsigned channel, float milliseconds); + bool delay(unsigned channel, size_t delaySamples); void disable(unsigned channel); private: @@ -38,6 +40,8 @@ private: size_t m_numQueues = 0; size_t m_channelOffsets[MAX_DELAY_CHANNELS]; + + size_t m_callCount = 0; }; } diff --git a/src/LibBasicFunctions.h b/src/LibBasicFunctions.h index 386fabf..02146aa 100644 --- a/src/LibBasicFunctions.h +++ b/src/LibBasicFunctions.h @@ -24,6 +24,7 @@ public: RingBuffer() = delete; RingBuffer(const size_t maxSize) : m_maxSize(maxSize) { m_buffer = new T[maxSize]; + //Serial.println(String("New RingBuffer: max size is ") + m_maxSize); } virtual ~RingBuffer(){ if (m_buffer) delete [] m_buffer; @@ -31,23 +32,28 @@ public: int push_back(T element) { + Serial.println(String("RingBuffer::push_back...") + m_head + String(":") + m_tail + String(":") + m_size); if ( (m_head == m_tail) && (m_size > 0) ) { // overflow Serial.println("RingBuffer::push_back: overflow"); + while(1) {} // TODO REMOVE return -1; } m_buffer[m_head] = element; - if (m_head < m_maxSize-1) { + if (m_head < (m_maxSize-1) ) { m_head++; } else { m_head = 0; } m_size++; + //Serial.println(" ...Done push"); + return 0; } int pop_front() { + if (m_size == 0) { // buffer is empty Serial.println("RingBuffer::pop_front: buffer is empty\n"); @@ -59,6 +65,7 @@ public: m_tail = 0; } m_size--; + Serial.println(String("RingBuffer::pop_front: ") + m_head + String(":") + m_tail + String(":") + m_size); return 0; } @@ -66,17 +73,41 @@ public: return m_buffer[m_tail]; } + T back() const { + return m_buffer[m_head-1]; + } + + size_t getBackIndex(size_t offset = 0) const { + // the target at m_head - 1 - offset or m_maxSize + m_head -1 - offset; + size_t idx = (m_maxSize + m_head -1 - offset); + + if ( idx >= m_maxSize) { + idx -= m_maxSize; + } + + //Serial.println(String("BackIndex is ") + idx + String(" address: ") + (uint32_t)m_buffer[idx] + String(" data: ") + (uint32_t)m_buffer[idx]->data); +// for (int i=0; idata); +// } + return idx; + } + size_t size() const { - size_t size = 0; - if (m_head == m_tail) { size = 0; } - else if (m_head > m_tail) { size = (m_head - m_tail); } - else { size = (m_tail - m_head + 1); } - return size; + //Serial.println(String("RingBuffer::size: ") + m_head + String(":") + m_tail + String(":") + m_size); + return m_size; } + size_t getMaxSize() const { return m_maxSize; } + T& operator[] (size_t index) { return m_buffer[index]; } + + void print() const { + for (int idx=0; idxdata); + } + } private: size_t m_head=0; size_t m_tail=0; diff --git a/src/LibMemoryManagment.cpp b/src/LibMemoryManagement.cpp similarity index 73% rename from src/LibMemoryManagment.cpp rename to src/LibMemoryManagement.cpp index 576ff67..137c507 100644 --- a/src/LibMemoryManagment.cpp +++ b/src/LibMemoryManagement.cpp @@ -6,12 +6,10 @@ namespace BAGuitar { - - bool ExternalSramManager::m_configured = false; MemConfig ExternalSramManager::m_memConfig[BAGuitar::NUM_MEM_SLOTS]; -inline size_t calcAudioSamples(float milliseconds) +size_t calcAudioSamples(float milliseconds) { return (size_t)((milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f); } @@ -42,7 +40,7 @@ size_t calcOffset(QueuePosition position) // MEM VIRTUAL ///////////////////////////////////////////////////////////////////////////// MemAudioBlock::MemAudioBlock(size_t numSamples) -: m_queues((numSamples + AUDIO_BLOCK_SAMPLES - 1)/AUDIO_BLOCK_SAMPLES) +: m_queues(((numSamples + AUDIO_BLOCK_SAMPLES - 1)/AUDIO_BLOCK_SAMPLES) +1) { // // round up to an integer multiple of AUDIO_BLOCK_SAMPLES // int numQueues = (numSamples + AUDIO_BLOCK_SAMPLES - 1)/AUDIO_BLOCK_SAMPLES; @@ -63,14 +61,28 @@ MemAudioBlock::~MemAudioBlock() } +// the index is referenced from the head +audio_block_t *MemAudioBlock::getQueueBack(size_t offset) +{ + +// for (int i=0; idata); +// } +// Serial.println(String("Returning ") + (uint32_t)m_queues[m_queues.getBackIndex(offset)]); + return m_queues[m_queues.getBackIndex(offset)]; +} + bool MemAudioBlock::push(audio_block_t *block) { + //Serial.println("MemAudioBlock::push()"); m_queues.push_back(block); + //Serial.println("MemAudioBlock::push() done"); return true; } audio_block_t* MemAudioBlock::pop() { + //Serial.println("MemAudioBlock::pop()"); audio_block_t* block = m_queues.front(); m_queues.pop_front(); return block; @@ -86,7 +98,7 @@ bool MemAudioBlock::clear() return true; } -bool MemAudioBlock::write16(size_t offset, int16_t *dataPtr, size_t numData) +bool MemAudioBlock::write16(size_t offset, int16_t *srcDataPtr, size_t numData) { // Calculate the queue position auto position = calcQueuePosition(offset); @@ -98,33 +110,38 @@ bool MemAudioBlock::write16(size_t offset, int16_t *dataPtr, size_t numData) // loop over a series of memcpys until all data is transferred. size_t samplesRemaining = numData; + int16_t *srcStart = srcDataPtr; // this will increment during each loop iteration + while (samplesRemaining > 0) { size_t numSamplesToWrite; - void *start = static_cast(m_queues[index]->data + writeOffset); + void *destStart = static_cast(m_queues[index]->data + writeOffset); // determine if the transfer will complete or will hit the end of a block first if ( (writeOffset + samplesRemaining) > AUDIO_BLOCK_SAMPLES ) { // goes past end of the queue numSamplesToWrite = (AUDIO_BLOCK_SAMPLES - writeOffset); - writeOffset = 0; - index++; + //writeOffset = 0; + //index++; } else { // transfer ends in this audio block numSamplesToWrite = samplesRemaining; - writeOffset += numSamplesToWrite; + //writeOffset += numSamplesToWrite; } // perform the transfer if (!m_queues[index]) { // no allocated audio block, skip the copy } else { - if (dataPtr) { - memcpy(start, dataPtr, numSamplesToWrite * sizeof(int16_t)); + if (srcDataPtr) { + memcpy(destStart, static_cast(srcStart), numSamplesToWrite * sizeof(int16_t)); } else { - memset(start, 0, numSamplesToWrite * sizeof(int16_t)); + memset(destStart, 0, numSamplesToWrite * sizeof(int16_t)); } } + writeOffset = 0; + index++; + srcStart += numSamplesToWrite; samplesRemaining -= numSamplesToWrite; } m_currentPosition.offset = writeOffset; @@ -140,44 +157,43 @@ inline bool MemAudioBlock::zero16(size_t offset, size_t numData) bool MemAudioBlock::read16(int16_t *dest, size_t destOffset, size_t srcOffset, size_t numSamples) { if (!dest) return false; // destination is not valid + (void)destOffset; // not supported with audio_block_t; + //Serial.println("*************************************************************************"); + //Serial.println(String("read16():") + (uint32_t)dest + String(":") + destOffset + String(":") + srcOffset + String(":") + numSamples); // Calculate the queue position auto position = calcQueuePosition(srcOffset); - int readOffset = position.offset; size_t index = position.index; - if ( (index+1) > m_queues.size()) return false; // out of range + // Break the transfer in two. Note that the audio is stored first sample (in time) last (in memory). - // loop over a series of memcpys until all data is transferred. - size_t samplesRemaining = numSamples; + int16_t *destStart = dest; + audio_block_t *currentQueue; + int16_t *srcStart; - while (samplesRemaining > 0) { - size_t numSamplesToRead; + // Break the transfer into two. Note that the audio + //Serial.println("Calling getQueue"); + currentQueue = getQueueBack(index+1); // buffer indexes go backwards from the back + //Serial.println(String("Q. Address: ") + (uint32_t)currentQueue + String(" Data: ") + (uint32_t)currentQueue->data); + srcStart = (currentQueue->data + AUDIO_BLOCK_SAMPLES - position.offset); + size_t numData = position.offset; + //Serial.println(String("Source Start1: ") + (uint32_t)currentQueue->data + String(" Dest start1: ") + (uint32_t)dest); + //Serial.println(String("copying to ") + (uint32_t)destStart + String(" from ") + (uint32_t)srcStart + String(" numData= ") + numData); + memcpy(static_cast(destStart), static_cast(srcStart), numData * sizeof(int16_t)); - void *srcStart = static_cast(m_queues[index]->data + readOffset); - void *destStart = static_cast(dest + destOffset); - // determine if the transfer will complete or will hit the end of a block first - if ( (readOffset + samplesRemaining) > AUDIO_BLOCK_SAMPLES ) { - // goes past end of the queue - numSamplesToRead = (AUDIO_BLOCK_SAMPLES - readOffset); - readOffset = 0; - index++; - } else { - // transfer ends in this audio block - numSamplesToRead = samplesRemaining; - readOffset += numSamplesToRead; - } + currentQueue = getQueueBack(index); // buffer indexes go backwards from the back + //Serial.println(String("Q. Address: ") + (uint32_t)currentQueue + String(" Data: ") + (uint32_t)currentQueue->data); + destStart += numData; + srcStart = (currentQueue->data); + numData = AUDIO_BLOCK_SAMPLES - numData; + //Serial.println(String("Source Start2: ") + (uint32_t)currentQueue->data + String(" Dest start2: ") + (uint32_t)dest); + //Serial.println(String("copying to ") + (uint32_t)destStart + String(" from ") + (uint32_t)srcStart + String(" numData= ") + numData); + memcpy(static_cast(destStart), static_cast(srcStart), numData * sizeof(int16_t)); + + //m_queues.print(); + //Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); - // perform the transfer - if (!m_queues[index]) { - // no allocated audio block, copy zeros - memset(destStart, 0, numSamplesToRead * sizeof(int16_t)); - } else { - memcpy(srcStart, destStart, numSamplesToRead * sizeof(int16_t)); - } - samplesRemaining -= numSamplesToRead; - } return true; } diff --git a/src/LibMemoryManagement.h b/src/LibMemoryManagement.h index 118fbfd..ea163b8 100644 --- a/src/LibMemoryManagement.h +++ b/src/LibMemoryManagement.h @@ -62,8 +62,9 @@ public: bool push(audio_block_t *block); audio_block_t *pop(); - audio_block_t *getQueue(size_t index) { return m_queues[index]; } + audio_block_t *getQueueBack(size_t offset=0); size_t getNumQueues() const { return m_queues.size(); } + size_t getMaxSize() const { return m_queues.getMaxSize(); } bool clear() override; bool write16(size_t offset, int16_t *dataPtr, size_t numData) override; bool zero16(size_t offset, size_t numSamples) override;