From eb86b4313f972897d5895001a95d86c6a4145cfa Mon Sep 17 00:00:00 2001 From: Steve Lascos Date: Wed, 17 Jan 2018 21:16:55 -0500 Subject: [PATCH] internal memory AudioDelay seems to work, starton on external support --- src/AudioEffectAnalogDelay.cpp | 140 +++++++---------- src/AudioEffectAnalogDelay.h | 15 +- src/LibBasicFunctions.cpp | 139 +++++++++++++---- src/LibBasicFunctions.h | 44 ++++-- src/LibMemoryManagement.cpp | 265 ++++----------------------------- src/LibMemoryManagement.h | 83 +++-------- 6 files changed, 257 insertions(+), 429 deletions(-) diff --git a/src/AudioEffectAnalogDelay.cpp b/src/AudioEffectAnalogDelay.cpp index 43dcf37..19c86a2 100644 --- a/src/AudioEffectAnalogDelay.cpp +++ b/src/AudioEffectAnalogDelay.cpp @@ -9,38 +9,38 @@ namespace BAGuitar { -AudioEffectAnalogDelay::AudioEffectAnalogDelay(INTERNAL_MEMORY, float maxDelay) +AudioEffectAnalogDelay::AudioEffectAnalogDelay(float maxDelay) : AudioStream(1, m_inputQueueArray) { - m_memory = new MemAudioBlock(maxDelay); + m_memory = new AudioDelay(maxDelay); for (int i=0; iclear(); +// m_memory = &slot; +// for (int i=0; iclear(); } void AudioEffectAnalogDelay::update(void) { - audio_block_t *inputAudioBlock = receiveReadOnly(); // get the next block of input samplestransmit(inputAudioBlock, 0); + audio_block_t *inputAudioBlock = receiveReadOnly(); // get the next block of input samples if (!inputAudioBlock) { return; @@ -66,39 +66,8 @@ void AudioEffectAnalogDelay::update(void) 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 - if (inputAudioBlock) { - // valid block - m_memory->writeAdvance16(inputAudioBlock->data, AUDIO_BLOCK_SAMPLES); - } else { - // write zeros instead - m_memory->zeroAdvance16(AUDIO_BLOCK_SAMPLES); - } - } else { - // internal memory only requires updating the queue of audio block pointers. - MemAudioBlock *memory = reinterpret_cast(m_memory); - - // check to see if the queue has reached full size yet - //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; + audio_block_t *blockToRelease = m_memory->addBlock(inputAudioBlock); + if (blockToRelease) release(blockToRelease); //Serial.print("Active channels: "); Serial.print(m_activeChannels, HEX); Serial.println(""); @@ -111,13 +80,12 @@ void AudioEffectAnalogDelay::update(void) if (!m_externalMemory) { // 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 //Serial.println(String("Directly sending queue offset ") + queuePosition.index); - blockToOutput= memory->getQueueBack(queuePosition.index); // could be nullptr! + blockToOutput= m_memory->getBlock(queuePosition.index); // could be nullptr! if (blockToOutput) transmit(blockToOutput); continue; } else { @@ -130,7 +98,8 @@ void AudioEffectAnalogDelay::update(void) // copy the output data if (!blockToOutput) continue; // skip this channel due to failure // copy over data - m_memory->read16(blockToOutput->data, 0, m_channelOffsets[channel], AUDIO_BLOCK_SAMPLES); + m_memory->getSamples(blockToOutput, m_channelOffsets[channel]); + //m_memory->read16(blockToOutput->data, 0, m_channelOffsets[channel], AUDIO_BLOCK_SAMPLES); transmit(blockToOutput); release(blockToOutput); } @@ -143,25 +112,26 @@ bool AudioEffectAnalogDelay::delay(unsigned channel, float milliseconds) size_t delaySamples = calcAudioSamples(milliseconds); - if (!m_externalMemory) { - // Internal memory (AudioStream buffers) - MemAudioBlock *memory = reinterpret_cast(m_memory); - - QueuePosition queuePosition = calcQueuePosition(milliseconds); - 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; - } - } +// if (!m_externalMemory) { +// // Internal memory (AudioStream buffers) +// +// QueuePosition queuePosition = calcQueuePosition(milliseconds); +// Serial.println(String("CONFIG(") + m_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; +//// } +// } + QueuePosition queuePosition = calcQueuePosition(milliseconds); + Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); 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 { - // External memory - if (delaySamples > m_memory->getSize()) { - // error, the external memory is not large enough - 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 { +//// // External memory +//// if (delaySamples > m_memory->getSize()) { +//// // error, the external memory is not large enough +//// return false; +//// } +// } + QueuePosition queuePosition = calcQueuePosition(delaySamples); + Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); m_channelOffsets[channel] = delaySamples; m_activeChannels |= 1< +//#include #include -#include "LibMemoryManagement.h" +#include "LibBasicFunctions.h" namespace BAGuitar { @@ -22,9 +22,10 @@ public: static constexpr int MAX_DELAY_CHANNELS = 8; AudioEffectAnalogDelay() = delete; - AudioEffectAnalogDelay(INTERNAL_MEMORY, float maxDelay); - AudioEffectAnalogDelay(INTERNAL_MEMORY, size_t numSamples); - AudioEffectAnalogDelay(EXTERNAL_MEMORY, MemSlot &slot); // requires sufficiently sized pre-allocated memory + AudioEffectAnalogDelay(float maxDelay); + AudioEffectAnalogDelay(size_t numSamples); + + AudioEffectAnalogDelay(ExtMemSlot &slot); // requires sufficiently sized pre-allocated memory virtual ~AudioEffectAnalogDelay() {} virtual void update(void); @@ -36,9 +37,9 @@ private: audio_block_t *m_inputQueueArray[1]; unsigned m_activeChannels = 0; bool m_externalMemory = false; - MemBufferIF *m_memory = nullptr; + AudioDelay *m_memory = nullptr; - size_t m_numQueues = 0; + //size_t m_numQueues = 0; size_t m_channelOffsets[MAX_DELAY_CHANNELS]; size_t m_callCount = 0; diff --git a/src/LibBasicFunctions.cpp b/src/LibBasicFunctions.cpp index 43bc0c2..7505f36 100644 --- a/src/LibBasicFunctions.cpp +++ b/src/LibBasicFunctions.cpp @@ -5,57 +5,140 @@ * Author: slascos */ +#include "Audio.h" #include "LibBasicFunctions.h" namespace BAGuitar { -AudioDelay::AudioDelay(MemType type, size_t maxSamples) +size_t calcAudioSamples(float milliseconds) { - m_type = type; - if (type == MemType::INTERNAL) { - // INTERNAL memory consisting of audio_block_t data structures. - QueuePosition pos = calcQueuePosition(maxSamples); - m_ringBuffer = new RingBuffer(pos.index+2); // If the delay is in queue x, we need to overflow into x+1, thus x+2 total buffers. - } else { - // TODO EXTERNAL memory + return (size_t)((milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f); +} - } +QueuePosition calcQueuePosition(size_t numSamples) +{ + QueuePosition queuePosition; + queuePosition.index = (int)(numSamples / AUDIO_BLOCK_SAMPLES); + queuePosition.offset = numSamples % AUDIO_BLOCK_SAMPLES; + return queuePosition; +} +QueuePosition calcQueuePosition(float milliseconds) { + size_t numSamples = (int)((milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f); + return calcQueuePosition(numSamples); } -AudioDelay::AudioDelay(MemType type, float delayTimeMs) -: AudioDelay(type, calcAudioSamples(delayTimeMs)) +size_t calcOffset(QueuePosition position) { + return (position.index*AUDIO_BLOCK_SAMPLES) + position.offset; +} + +AudioDelay::AudioDelay(size_t maxSamples) +: m_slot(nullptr) +{ + m_type = MemType::MEM_INTERNAL; + + // INTERNAL memory consisting of audio_block_t data structures. + QueuePosition pos = calcQueuePosition(maxSamples); + m_ringBuffer = new RingBuffer(pos.index+2); // If the delay is in queue x, we need to overflow into x+1, thus x+2 total buffers. } -AudioDelay::~AudioDelay() +AudioDelay::AudioDelay(float maxDelayTimeMs) +: AudioDelay(calcAudioSamples(maxDelayTimeMs)) { - if (m_ringBuffer) delete m_ringBuffer; + } -bool AudioDelay::addBlock(audio_block_t *block) +AudioDelay::AudioDelay(ExtMemSlot &slot) +: m_slot(slot) { - if (m_type != MemType::INTERNAL) return false; // ERROR + m_type = MemType::MEM_EXTERNAL; +} - // purposefully don't check if block is valid, the ringBuffer can support nullptrs - if ( m_ringBuffer->size() < m_ringBuffer->max_size() ) { - // pop before adding - release(m_ringBuffer->front()); - m_ringBuffer->pop_front(); - } +AudioDelay::~AudioDelay() +{ + if (m_ringBuffer) delete m_ringBuffer; +} - // add the new buffer - m_ringBuffer->push_back(block); +audio_block_t* AudioDelay::addBlock(audio_block_t *block) +{ + if (m_type == MemType::MEM_INTERNAL) { + // INTERNAL memory + audio_block_t *blockToRelease = nullptr; + // purposefully don't check if block is valid, the ringBuffer can support nullptrs + if ( m_ringBuffer->size() >= m_ringBuffer->max_size() ) { + // pop before adding + blockToRelease = m_ringBuffer->front(); + m_ringBuffer->pop_front(); + } + + // add the new buffer + m_ringBuffer->push_back(block); + return blockToRelease; + } else { + // EXTERNAL memory + m_slot.writeAdvance16(block->data, AUDIO_BLOCK_SAMPLES); + return nullptr; + + } } -void AudioDelay::getSamples(audio_block_t *dest, size_t offset, size_t numSamples = AUDIO_BLOCK_SAMPLES) +audio_block_t* AudioDelay::getBlock(size_t index) { - QueuePosition pos = calcQueuePosition(offset); - size_t readOffset = pos.offset; - size_t index = pos.index; + if (m_type == MemType::MEM_INTERNAL) { + return m_ringBuffer->at(m_ringBuffer->get_index_from_back(index)); + } else { + return nullptr; + } +} - // Audio is stored in reverse order. That means the first sample (in time) goes in the last location in the audio block. +bool AudioDelay::getSamples(audio_block_t *dest, size_t offset, size_t numSamples) +{ + if (!dest) return false; + + if (m_type == MemType::MEM_INTERNAL) { + QueuePosition position = calcQueuePosition(offset); + size_t index = position.index; + + if (position.offset == 0) { + // single transfer + audio_block_t *currentQueue = m_ringBuffer->at(m_ringBuffer->get_index_from_back(index)); + memcpy(static_cast(dest->data), static_cast(currentQueue->data), numSamples * sizeof(int16_t)); + return true; + } + + // Otherwise we need to break the transfer into two memcpy because it will go across two source queues. + // Audio is stored in reverse order. That means the first sample (in time) goes in the last location in the audio block. + int16_t *destStart = dest->data; + audio_block_t *currentQueue; + int16_t *srcStart; + + // Break the transfer into two. Copy the 'older' data first then the 'newer' data with respect to current time. + currentQueue = m_ringBuffer->at(m_ringBuffer->get_index_from_back(index+1)); // The latest buffer is at the back. We need index+1 counting from the back. + srcStart = (currentQueue->data + AUDIO_BLOCK_SAMPLES - position.offset); + size_t numData = position.offset; + memcpy(static_cast(destStart), static_cast(srcStart), numData * sizeof(int16_t)); + + + currentQueue = m_ringBuffer->at(m_ringBuffer->get_index_from_back(index)); // now grab the queue where the 'first' data sample was + destStart += numData; // we already wrote numData so advance by this much. + srcStart = (currentQueue->data); + numData = AUDIO_BLOCK_SAMPLES - numData; + memcpy(static_cast(destStart), static_cast(srcStart), numData * sizeof(int16_t)); + + return true; + + } else { + // EXTERNAL Memory + if (numSamples < m_slot.size() ) { + m_slot.read16FromCurrent(dest->data, offset, numSamples); + return true; + } else { + // numSampmles is > than total slot size + return false; + } + } } diff --git a/src/LibBasicFunctions.h b/src/LibBasicFunctions.h index 3031166..cee3b26 100644 --- a/src/LibBasicFunctions.h +++ b/src/LibBasicFunctions.h @@ -9,7 +9,8 @@ #include #include "Arduino.h" -#include "Audio.H" +#include "Audio.h" + #include "LibMemoryManagement.h" #ifndef SRC_LIBBASICFUNCTIONS_H_ @@ -17,29 +18,46 @@ namespace BAGuitar { +struct QueuePosition { + int offset; + int index; +}; +QueuePosition calcQueuePosition(float milliseconds); +QueuePosition calcQueuePosition(size_t numSamples); +size_t calcAudioSamples(float milliseconds); +size_t calcOffset(QueuePosition position); + +template class RingBuffer; // forward declare -enum MemType : unsigned { - INTERNAL, - EXTERNAL +enum class MemType : unsigned { + MEM_INTERNAL = 0, + MEM_EXTERNAL }; struct INTERNAL_MEMORY {}; struct EXTERNAL_MEMORY {}; class AudioDelay { - +public: AudioDelay() = delete; - AudioDelay(MemType type, size_t maxSamples); - AudioDelay(MemType type, float delayTimeMs); + AudioDelay(size_t maxSamples); + AudioDelay(float maxDelayTimeMs); + AudioDelay(ExtMemSlot &slot); ~AudioDelay(); - void addBlock(audio_block_t *block); + // Internal memory member functions + audio_block_t *addBlock(audio_block_t *blockIn); + audio_block_t *getBlock(size_t index); + bool getSamples(audio_block_t *dest, size_t offset, size_t numSamples = AUDIO_BLOCK_SAMPLES); + + // External memory member functions + //bool writeBlock(audio_blocK_t *blockIn); - void getSamples(size_t offset, size_t numSamples); private: MemType m_type; - RingBuffer *m_ringBuffer = nullptr; + RingBuffer *m_ringBuffer = nullptr; + ExtMemSlot &m_slot; }; template @@ -101,7 +119,7 @@ public: return m_buffer[m_head-1]; } - size_t getBackIndex(size_t offset = 0) const { + size_t get_index_from_back(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); @@ -129,6 +147,10 @@ public: return m_buffer[index]; } + T at(size_t index) const { + return m_buffer[index]; + } + void print() const { for (int idx=0; idxdata); diff --git a/src/LibMemoryManagement.cpp b/src/LibMemoryManagement.cpp index 137c507..9a25772 100644 --- a/src/LibMemoryManagement.cpp +++ b/src/LibMemoryManagement.cpp @@ -9,242 +9,23 @@ namespace BAGuitar { bool ExternalSramManager::m_configured = false; MemConfig ExternalSramManager::m_memConfig[BAGuitar::NUM_MEM_SLOTS]; -size_t calcAudioSamples(float milliseconds) -{ - return (size_t)((milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f); -} - -QueuePosition calcQueuePosition(size_t numSamples) -{ - QueuePosition queuePosition; - queuePosition.index = (int)(numSamples / AUDIO_BLOCK_SAMPLES); - queuePosition.offset = numSamples % AUDIO_BLOCK_SAMPLES; - return queuePosition; -} -QueuePosition calcQueuePosition(float milliseconds) { - size_t numSamples = (int)((milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f); - return calcQueuePosition(numSamples); -} - -size_t calcOffset(QueuePosition position) -{ - return (position.index*AUDIO_BLOCK_SAMPLES) + position.offset; -} - -///////////////////////////////////////////////////////////////////////////// -// MEM BUFFER IF -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// MEM VIRTUAL -///////////////////////////////////////////////////////////////////////////// -MemAudioBlock::MemAudioBlock(size_t numSamples) -: 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; -// -// // Preload the queue with nullptrs to set the queue depth to the correct size -// for (int i=0; i < numQueues; i++) { -// m_queues.push_back(nullptr); -// } -} - -MemAudioBlock::MemAudioBlock(float milliseconds) -: MemAudioBlock(calcAudioSamples(milliseconds)) -{ -} - -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; -} - -bool MemAudioBlock::clear() -{ - for (size_t i=0; i < m_queues.size(); i++) { - if (m_queues[i]) { - memset(m_queues[i]->data, 0, AUDIO_BLOCK_SAMPLES * sizeof(int16_t)); - } - } - return true; -} - -bool MemAudioBlock::write16(size_t offset, int16_t *srcDataPtr, size_t numData) -{ - // Calculate the queue position - auto position = calcQueuePosition(offset); - int writeOffset = position.offset; - size_t index = position.index; - - if ( (index+1) > m_queues.size()) return false; // out of range - - // 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 *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++; - } else { - // transfer ends in this audio block - numSamplesToWrite = samplesRemaining; - //writeOffset += numSamplesToWrite; - } - - // perform the transfer - if (!m_queues[index]) { - // no allocated audio block, skip the copy - } else { - if (srcDataPtr) { - memcpy(destStart, static_cast(srcStart), numSamplesToWrite * sizeof(int16_t)); - } else { - memset(destStart, 0, numSamplesToWrite * sizeof(int16_t)); - } - } - writeOffset = 0; - index++; - srcStart += numSamplesToWrite; - samplesRemaining -= numSamplesToWrite; - } - m_currentPosition.offset = writeOffset; - m_currentPosition.index = index; - return true; -} - -inline bool MemAudioBlock::zero16(size_t offset, size_t numData) -{ - return write16(offset, nullptr, 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); - size_t index = position.index; - - // Break the transfer in two. Note that the audio is stored first sample (in time) last (in memory). - - int16_t *destStart = dest; - audio_block_t *currentQueue; - int16_t *srcStart; - - // 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)); - - - 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("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); - - return true; -} - -// If this function hits the end of the queues it will wrap to the start -bool MemAudioBlock::writeAdvance16(int16_t *dataPtr, size_t numData) -{ - auto globalOffset = calcOffset(m_currentPosition); - auto end = globalOffset + numData; - - if ( end >= (m_queues.size() * AUDIO_BLOCK_SAMPLES) ) { - // transfer will wrap, so break into two - auto samplesToWrite = end - globalOffset; - // write the first chunk - write16(globalOffset, dataPtr, samplesToWrite); - // write the scond chunk - int16_t *ptr; - if (dataPtr) { - // valid dataptr, advance the pointer - ptr = dataPtr+samplesToWrite; - } else { - // dataPtr was nullptr - ptr = nullptr; - } - write16(0, ptr, numData-samplesToWrite); - } else { - // no wrap - write16(globalOffset, dataPtr, numData); - } - return true; -} - -bool MemAudioBlock::zeroAdvance16(size_t numData) -{ - return writeAdvance16(nullptr, numData); -} ///////////////////////////////////////////////////////////////////////////// // MEM SLOT ///////////////////////////////////////////////////////////////////////////// -bool MemSlot::clear() +bool ExtMemSlot::clear() { if (!m_valid) { return false; } m_spi->zero16(m_start, m_size); return true; } -bool MemSlot::write16(size_t offset, int16_t *dataPtr, size_t dataSize) +bool ExtMemSlot::write16(size_t offset, int16_t *dataPtr, size_t dataSize) { if (!m_valid) { return false; } - if ((offset + dataSize-1) <= m_end) { - m_spi->write16(offset, reinterpret_cast(dataPtr), dataSize); // cast audio data to uint + size_t writeStart = m_start + offset; + if ((writeStart + dataSize-1) <= m_end) { + m_spi->write16(writeStart, reinterpret_cast(dataPtr), dataSize); // cast audio data to uint return true; } else { // this would go past the end of the memory slot, do not perform the write @@ -252,11 +33,12 @@ bool MemSlot::write16(size_t offset, int16_t *dataPtr, size_t dataSize) } } -bool MemSlot::zero16(size_t offset, size_t dataSize) +bool ExtMemSlot::zero16(size_t offset, size_t dataSize) { if (!m_valid) { return false; } - if ((offset + dataSize-1) <= m_end) { - m_spi->zero16(offset, dataSize); // cast audio data to uint + size_t writeStart = m_start + offset; + if ((writeStart + dataSize-1) <= m_end) { + m_spi->zero16(writeStart, dataSize); // cast audio data to uint return true; } else { // this would go past the end of the memory slot, do not perform the write @@ -264,11 +46,13 @@ bool MemSlot::zero16(size_t offset, size_t dataSize) } } -bool MemSlot::read16(int16_t *dest, size_t destOffset, size_t srcOffset, size_t numData) +bool ExtMemSlot::read16(int16_t *dest, size_t srcOffset, size_t numData) { if (!dest) return false; // invalid destination - if ((srcOffset + (numData*sizeof(int16_t))-1) <= m_end) { - m_spi->read16(srcOffset, reinterpret_cast(dest), numData); + size_t readOffset = m_start + srcOffset; + + if ((readOffset + (numData*sizeof(int16_t))-1) <= m_end) { + m_spi->read16(readOffset, reinterpret_cast(dest), numData); return true; } else { // this would go past the end of the memory slot, do not perform the write @@ -276,7 +60,20 @@ bool MemSlot::read16(int16_t *dest, size_t destOffset, size_t srcOffset, size_t } } -bool MemSlot::writeAdvance16(int16_t *dataPtr, size_t dataSize) +size_t ExtMemSlot::read16FromCurrent(int16_t *dest, size_t currentOffset, size_t numData) +{ + size_t readStart; + if (m_currentPosition + currentOffset <= m_end) { + readStart = m_currentPosition + currentOffset; + } else { + // this offset will wrap the memory slot + size_t numBytesToEnd = m_end - m_currentPosition + 1; + readStart = m_start + (currentOffset - numBytesToEnd); + } + m_spi->read16(dest, readStart, numData); +} + +bool ExtMemSlot::writeAdvance16(int16_t *dataPtr, size_t dataSize) { if (!m_valid) { return false; } if (m_currentPosition + dataSize-1 <= m_end) { @@ -295,7 +92,7 @@ bool MemSlot::writeAdvance16(int16_t *dataPtr, size_t dataSize) return true; } -bool MemSlot::zeroAdvance16(size_t dataSize) +bool ExtMemSlot::zeroAdvance16(size_t dataSize) { if (!m_valid) { return false; } if (m_currentPosition + dataSize-1 <= m_end) { @@ -344,14 +141,14 @@ size_t ExternalSramManager::availableMemory(BAGuitar::MemSelect mem) return m_memConfig[mem].totalAvailable; } -bool ExternalSramManager::requestMemory(MemSlot &slot, float delayMilliseconds, BAGuitar::MemSelect mem) +bool ExternalSramManager::requestMemory(ExtMemSlot &slot, float delayMilliseconds, BAGuitar::MemSelect mem) { // 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, mem); } -bool ExternalSramManager::requestMemory(MemSlot &slot, size_t sizeBytes, BAGuitar::MemSelect mem) +bool ExternalSramManager::requestMemory(ExtMemSlot &slot, size_t sizeBytes, BAGuitar::MemSelect mem) { if (m_memConfig[mem].totalAvailable >= sizeBytes) { // there is enough available memory for this request diff --git a/src/LibMemoryManagement.h b/src/LibMemoryManagement.h index 319a18f..22821a5 100644 --- a/src/LibMemoryManagement.h +++ b/src/LibMemoryManagement.h @@ -11,7 +11,7 @@ #include -#include "Audio.h" +//#include "Audio.h" #include "BAHardware.h" #include "BASpiMemory.h" @@ -19,14 +19,6 @@ namespace BAGuitar { -struct QueuePosition { - int offset; - int index; -}; -QueuePosition calcQueuePosition(float milliseconds); -QueuePosition calcQueuePosition(size_t numSamples); -size_t calcAudioSamples(float milliseconds); - struct MemConfig { size_t size; size_t totalAvailable; @@ -34,66 +26,27 @@ struct MemConfig { BASpiMemory *m_spi = nullptr; }; -class ExternalSramManager; // forward declare so MemSlot can setup friendship +class ExternalSramManager; // forward declare so ExtMemSlot can setup friendship -class MemBufferIF { +class ExtMemSlot { public: - size_t getSize() const { return m_size; } - virtual bool clear() = 0; - virtual bool write16(size_t offset, int16_t *dataPtr, size_t numData) = 0; - virtual bool zero16(size_t offset, size_t numData) = 0; - virtual bool read16(int16_t *dest, size_t destOffset, size_t srcOffset, size_t numData) = 0; - virtual bool writeAdvance16(int16_t *dataPtr, size_t numData) = 0; - virtual bool zeroAdvance16(size_t numData) = 0; - virtual ~MemBufferIF() {} -protected: - bool m_valid = false; - size_t m_size = 0; -}; -class MemAudioBlock : public MemBufferIF { -public: - //MemAudioBlock(); - MemAudioBlock() = delete; - MemAudioBlock(size_t numSamples); - MemAudioBlock(float milliseconds); - - virtual ~MemAudioBlock(); - - bool push(audio_block_t *block); - audio_block_t *pop(); - 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; - bool read16(int16_t *dest, size_t destOffset, size_t srcOffset, size_t numSamples); - bool writeAdvance16(int16_t *dataPtr, size_t numData) override; - bool zeroAdvance16(size_t numData) override; -private: - //size_t m_numQueues; - BAGuitar::RingBuffer m_queues; - QueuePosition m_currentPosition = {0,0}; - -}; - - -class MemSlot : public MemBufferIF { -public: - - bool clear() override; - bool write16(size_t offset, int16_t *dataPtr, size_t numData) override; - bool zero16(size_t offset, size_t numData) override; - bool read16(int16_t *dest, size_t destOffset, size_t srcOffset, size_t numData); - bool writeAdvance16(int16_t *dataPtr, size_t numData) override; - bool zeroAdvance16(size_t numData) override; + bool clear(); + bool write16(size_t offset, int16_t *dataPtr, size_t numData); + bool zero16(size_t offset, size_t numData); + bool read16(int16_t *dest, size_t srcOffset, size_t numData); + bool writeAdvance16(int16_t *dataPtr, size_t numData); + bool zeroAdvance16(size_t numData); + size_t read16FromCurrent(int16_t *dest, size_t Offset, size_t numData); + size_t size() const { return m_size; } private: friend ExternalSramManager; - size_t m_start; - size_t m_end; - size_t m_currentPosition; + bool m_valid = false; + size_t m_start = 0; + size_t m_end = 0; + size_t m_currentPosition = 0; + size_t m_size = 0; BASpiMemory *m_spi = nullptr; }; @@ -105,8 +58,8 @@ public: virtual ~ExternalSramManager(); size_t availableMemory(BAGuitar::MemSelect mem); - bool requestMemory(MemSlot &slot, float delayMilliseconds, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0); - bool requestMemory(MemSlot &slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0); + bool requestMemory(ExtMemSlot &slot, float delayMilliseconds, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0); + bool requestMemory(ExtMemSlot &slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0); private: static bool m_configured;