From 9fd96aa5e36aba8fd573af79a860072841bc69d3 Mon Sep 17 00:00:00 2001 From: Steve Lascos Date: Thu, 18 Jan 2018 21:01:39 -0500 Subject: [PATCH] Development checkin --- src/AudioEffectAnalogDelay.cpp | 94 +++++++++++----------- src/AudioEffectAnalogDelay.h | 5 +- src/BASpiMemory.cpp | 7 +- src/BASpiMemory.h | 9 ++- src/LibBasicFunctions.cpp | 33 ++++++-- src/LibBasicFunctions.h | 6 +- src/LibMemoryManagement.cpp | 140 +++++++++++++++++++++++++-------- src/LibMemoryManagement.h | 22 +++++- 8 files changed, 216 insertions(+), 100 deletions(-) diff --git a/src/AudioEffectAnalogDelay.cpp b/src/AudioEffectAnalogDelay.cpp index 19c86a2..97e2bfb 100644 --- a/src/AudioEffectAnalogDelay.cpp +++ b/src/AudioEffectAnalogDelay.cpp @@ -28,14 +28,19 @@ AudioEffectAnalogDelay::AudioEffectAnalogDelay(size_t numSamples) } // requires preallocated memory large enough -AudioEffectAnalogDelay::AudioEffectAnalogDelay(ExtMemSlot &slot) +AudioEffectAnalogDelay::AudioEffectAnalogDelay(ExtMemSlot *slot) : AudioStream(1, m_inputQueueArray) { -// m_memory = &slot; -// for (int i=0; iclear(); + m_memory = new AudioDelay(slot); + m_externalMemory = true; + for (int i=0; igetSlot()->printStatus(); audio_block_t *blockToRelease = m_memory->addBlock(inputAudioBlock); + +// if (inputAudioBlock) { +// transmit(inputAudioBlock, 0); +// release(inputAudioBlock); +// } +// return; + if (blockToRelease) release(blockToRelease); - //Serial.print("Active channels: "); Serial.print(m_activeChannels, HEX); Serial.println(""); + Serial.print("Active channels: "); Serial.print(m_activeChannels, HEX); Serial.println(""); // For each active channel, output the delayed audio @@ -92,6 +105,7 @@ void AudioEffectAnalogDelay::update(void) blockToOutput = allocate(); // allocate if spanning 2 queues } } else { + // external memory blockToOutput = allocate(); // allocate always for external memory } @@ -112,26 +126,21 @@ bool AudioEffectAnalogDelay::delay(unsigned channel, float milliseconds) size_t delaySamples = calcAudioSamples(milliseconds); -// 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; -//// } -// } + 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->isEnabled()) { + slot->enable(); + } else { + Serial.println("ERROR: slot ptr is not valid"); + } + } - 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; -//// } -// } - - QueuePosition queuePosition = calcQueuePosition(delaySamples); - Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); + 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 + ExtMemSlot *slot = m_memory->getSlot(); + if (!slot->isEnabled()) { + slot->enable(); + } + } m_channelOffsets[channel] = delaySamples; m_activeChannels |= 1<endTransaction(); digitalWrite(m_csPin, HIGH); + Serial.println("DONE!"); } // single address read @@ -239,10 +240,10 @@ uint16_t BASpiMemory::read16(size_t address) return data; } -void BASpiMemory::read16(size_t address, uint16_t *data, size_t numWords) +void BASpiMemory::read16(size_t address, uint16_t *dest, size_t numWords) { - uint16_t *dataPtr = data; + uint16_t *dataPtr = dest; m_spi->beginTransaction(m_settings); digitalWrite(m_csPin, LOW); m_spi->transfer16((SPI_READ_CMD << 8) | (address >> 16) ); diff --git a/src/BASpiMemory.h b/src/BASpiMemory.h index fc5046f..efc2acc 100644 --- a/src/BASpiMemory.h +++ b/src/BASpiMemory.h @@ -71,14 +71,21 @@ public: /// @param address the address in the SPI RAM to read from /// @return the data that was read uint16_t read16(size_t address); - void read16(size_t address, uint16_t *data, size_t numWords); + /// 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 + void read16(size_t address, uint16_t *dest, size_t numWords); + + bool isStarted() const { return m_started; } private: 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; }; diff --git a/src/LibBasicFunctions.cpp b/src/LibBasicFunctions.cpp index 7505f36..e78049a 100644 --- a/src/LibBasicFunctions.cpp +++ b/src/LibBasicFunctions.cpp @@ -49,7 +49,7 @@ AudioDelay::AudioDelay(float maxDelayTimeMs) } -AudioDelay::AudioDelay(ExtMemSlot &slot) +AudioDelay::AudioDelay(ExtMemSlot *slot) : m_slot(slot) { m_type = MemType::MEM_EXTERNAL; @@ -77,8 +77,17 @@ audio_block_t* AudioDelay::addBlock(audio_block_t *block) return blockToRelease; } else { // EXTERNAL memory - m_slot.writeAdvance16(block->data, AUDIO_BLOCK_SAMPLES); - return nullptr; + + //m_slot->writeAdvance16(block->data, AUDIO_BLOCK_SAMPLES); + + // Audio is stored in reverse in block so we need to write it backwards to external memory + // to maintain temporal coherency. + int16_t *srcPtr = block->data + AUDIO_BLOCK_SAMPLES - 1; + for (int i=0; iwriteAdvance16(*srcPtr); + srcPtr--; + } + return block; } @@ -131,8 +140,22 @@ bool AudioDelay::getSamples(audio_block_t *dest, size_t offset, size_t numSample } else { // EXTERNAL Memory - if (numSamples < m_slot.size() ) { - m_slot.read16FromCurrent(dest->data, offset, numSamples); + if (numSamples <= m_slot->size() ) { + int currentPosition = (int)m_slot->getWritePosition() - (int)AUDIO_BLOCK_SAMPLES; + + if ((int)offset <= currentPosition) { + m_slot->setReadPosition(currentPosition - offset); + } else { + // It's going to wrap around to the end of the slot + int readPosition = (int)m_slot->size() + currentPosition - offset; + m_slot->setReadPosition((size_t)readPosition); + } + + // write the data to the destination block in reverse + int16_t *destPtr = dest->data + AUDIO_BLOCK_SAMPLES-1; + for (int i=0; ireadAdvance16(); + } return true; } else { // numSampmles is > than total slot size diff --git a/src/LibBasicFunctions.h b/src/LibBasicFunctions.h index cee3b26..139625e 100644 --- a/src/LibBasicFunctions.h +++ b/src/LibBasicFunctions.h @@ -43,7 +43,7 @@ public: AudioDelay() = delete; AudioDelay(size_t maxSamples); AudioDelay(float maxDelayTimeMs); - AudioDelay(ExtMemSlot &slot); + AudioDelay(ExtMemSlot *slot); ~AudioDelay(); // Internal memory member functions @@ -52,12 +52,12 @@ public: 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); + ExtMemSlot *getSlot() const { return m_slot; } private: MemType m_type; RingBuffer *m_ringBuffer = nullptr; - ExtMemSlot &m_slot; + ExtMemSlot *m_slot = nullptr; }; template diff --git a/src/LibMemoryManagement.cpp b/src/LibMemoryManagement.cpp index 9a25772..9f413b1 100644 --- a/src/LibMemoryManagement.cpp +++ b/src/LibMemoryManagement.cpp @@ -2,13 +2,12 @@ #include #include +#include "Audio.h" + #include "LibMemoryManagement.h" namespace BAGuitar { -bool ExternalSramManager::m_configured = false; -MemConfig ExternalSramManager::m_memConfig[BAGuitar::NUM_MEM_SLOTS]; - ///////////////////////////////////////////////////////////////////////////// // MEM SLOT @@ -60,34 +59,59 @@ bool ExtMemSlot::read16(int16_t *dest, size_t srcOffset, size_t numData) } } -size_t ExtMemSlot::read16FromCurrent(int16_t *dest, size_t currentOffset, size_t numData) +uint16_t ExtMemSlot::readAdvance16() { - size_t readStart; - if (m_currentPosition + currentOffset <= m_end) { - readStart = m_currentPosition + currentOffset; + uint16_t val = m_spi->read16(m_currentRdPosition); + if (m_currentRdPosition < m_end) { + m_currentRdPosition++; } else { - // this offset will wrap the memory slot - size_t numBytesToEnd = m_end - m_currentPosition + 1; - readStart = m_start + (currentOffset - numBytesToEnd); + m_currentRdPosition = m_start; } - m_spi->read16(dest, readStart, numData); + return val; } + +//void ExtMemSlot::read16FromPast(int16_t *dest, size_t currentOffset, size_t numData) +//{ +// size_t readStart; +// if (m_currentPosition - currentOffset >= m_start) { +// readStart = m_currentPosition - currentOffset; +// } else { +// // this offset will wrap the memory slot +// size_t numBytesToStart = m_currentPosition; +// readStart = m_end - (currentOffset - numBytesToStart); +// } +// m_spi->read16(readStart, reinterpret_cast(dest), numData); +//} + bool ExtMemSlot::writeAdvance16(int16_t *dataPtr, size_t dataSize) { if (!m_valid) { return false; } - if (m_currentPosition + dataSize-1 <= m_end) { + if (m_currentWrPosition + dataSize-1 <= m_end) { // entire block fits in memory slot without wrapping - m_spi->write16(m_currentPosition, reinterpret_cast(dataPtr), dataSize); // cast audio data to uint. - m_currentPosition += dataSize; + m_spi->write16(m_currentWrPosition, reinterpret_cast(dataPtr), dataSize); // cast audio data to uint. + m_currentWrPosition += dataSize; } else { // this write will wrap the memory slot - size_t numBytes = m_end - m_currentPosition + 1; - m_spi->write16(m_currentPosition, reinterpret_cast(dataPtr), numBytes); + size_t numBytes = m_end - m_currentWrPosition + 1; + m_spi->write16(m_currentWrPosition, reinterpret_cast(dataPtr), numBytes); size_t remainingBytes = dataSize - numBytes; // calculate the remaining bytes m_spi->write16(m_start, reinterpret_cast(dataPtr + numBytes), remainingBytes); // write remaining bytes are start - m_currentPosition = m_start + remainingBytes; + m_currentWrPosition = m_start + remainingBytes; + } + 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) { + m_currentWrPosition++; + } else { + m_currentWrPosition = m_start; } return true; } @@ -95,26 +119,55 @@ bool ExtMemSlot::writeAdvance16(int16_t *dataPtr, size_t dataSize) bool ExtMemSlot::zeroAdvance16(size_t dataSize) { if (!m_valid) { return false; } - if (m_currentPosition + dataSize-1 <= m_end) { + if (m_currentWrPosition + dataSize-1 <= m_end) { // entire block fits in memory slot without wrapping - m_spi->zero16(m_currentPosition, dataSize); // cast audio data to uint. - m_currentPosition += dataSize; + m_spi->zero16(m_currentWrPosition, dataSize); // cast audio data to uint. + m_currentWrPosition += dataSize; } else { // this write will wrap the memory slot - size_t numBytes = m_end - m_currentPosition + 1; - m_spi->zero16(m_currentPosition, numBytes); + size_t numBytes = m_end - m_currentWrPosition + 1; + m_spi->zero16(m_currentWrPosition, numBytes); size_t remainingBytes = dataSize - numBytes; // calculate the remaining bytes m_spi->zero16(m_start, remainingBytes); // write remaining bytes are start - m_currentPosition = m_start + remainingBytes; + m_currentWrPosition = m_start + remainingBytes; } 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; +} + +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_size:") + m_size); +} + ///////////////////////////////////////////////////////////////////////////// // EXTERNAL SRAM MANAGER ///////////////////////////////////////////////////////////////////////////// +bool ExternalSramManager::m_configured = false; +MemConfig ExternalSramManager::m_memConfig[BAGuitar::NUM_MEM_SLOTS]; + ExternalSramManager::ExternalSramManager(unsigned numMemories) { // Initialize the static memory configuration structs @@ -123,7 +176,13 @@ ExternalSramManager::ExternalSramManager(unsigned numMemories) m_memConfig[i].size = MEM_MAX_ADDR[i]; m_memConfig[i].totalAvailable = MEM_MAX_ADDR[i]; m_memConfig[i].nextAvailable = 0; - m_memConfig[i].m_spi = new BAGuitar::BASpiMemory(static_cast(i)); + + m_memConfig[i].m_spi = nullptr; +// if (i < numMemories) { +// m_memConfig[i].m_spi = new BAGuitar::BASpiMemory(static_cast(i)); +// } else { +// m_memConfig[i].m_spi = nullptr; +// } } m_configured = true; } @@ -141,30 +200,45 @@ size_t ExternalSramManager::availableMemory(BAGuitar::MemSelect mem) return m_memConfig[mem].totalAvailable; } -bool ExternalSramManager::requestMemory(ExtMemSlot &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(ExtMemSlot &slot, size_t sizeBytes, BAGuitar::MemSelect mem) +bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem) { + 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_currentPosition = slot.m_start; // init to start of slot - slot.m_size = sizeBytes; - slot.m_spi = m_memConfig[mem].m_spi; + 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) { + m_memConfig[mem].m_spi = new BAGuitar::BASpiMemory(static_cast(mem)); + if (!m_memConfig[mem].m_spi) { + Serial.println("requestMemory: new failed! m_spi is a nullptr"); + } else { + 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].nextAvailable = slot->m_end+1; m_memConfig[mem].totalAvailable -= sizeBytes; - slot.m_valid = true; + slot->m_valid = true; + if (!slot->isEnabled()) { slot->enable(); } + slot->clear(); return true; } else { // there is not enough memory available for the request + return false; } } diff --git a/src/LibMemoryManagement.h b/src/LibMemoryManagement.h index 22821a5..9fedbc8 100644 --- a/src/LibMemoryManagement.h +++ b/src/LibMemoryManagement.h @@ -32,21 +32,35 @@ class ExtMemSlot { public: bool clear(); + bool setWritePosition(size_t offset) { m_currentWrPosition = m_start + offset; return true;} // TODO add range check + size_t getWritePosition() const { return m_currentWrPosition-m_start; } + + bool setReadPosition(size_t offset) { m_currentRdPosition = m_start + offset; return true;} // TODO add range check + size_t getReadPosition() const { return m_currentRdPosition-m_start; } + 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); + + uint16_t readAdvance16(); bool writeAdvance16(int16_t *dataPtr, size_t numData); + bool writeAdvance16(int16_t data); // write just one data bool zeroAdvance16(size_t numData); - size_t read16FromCurrent(int16_t *dest, size_t Offset, size_t numData); + //void read16FromPast(int16_t *dest, size_t Offset, size_t numData); size_t size() const { return m_size; } + bool enable() const; + bool isEnabled() const; + void printStatus(void) const; private: friend ExternalSramManager; bool m_valid = false; size_t m_start = 0; size_t m_end = 0; - size_t m_currentPosition = 0; + size_t m_currentWrPosition = 0; + size_t m_currentRdPosition = 0; size_t m_size = 0; + SpiDeviceId m_spiId; BASpiMemory *m_spi = nullptr; }; @@ -58,8 +72,8 @@ public: virtual ~ExternalSramManager(); size_t availableMemory(BAGuitar::MemSelect mem); - 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); + 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;