Further development

master
Steve Lascos 6 years ago
parent d2a8227f91
commit 03da5145b3
  1. 101
      src/AudioEffectAnalogDelay.cpp
  2. 4
      src/AudioEffectAnalogDelay.h
  3. 43
      src/LibBasicFunctions.h
  4. 96
      src/LibMemoryManagement.cpp
  5. 3
      src/LibMemoryManagement.h

@ -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<MAX_DELAY_CHANNELS; i++) {
m_channelOffsets[i] = 0;
}
}
// requires preallocated memory large enough
AudioEffectAnalogDelay::AudioEffectAnalogDelay(EXTERNAL_MEMORY, MemSlot &slot)
: AudioStream(1, m_inputQueueArray)
@ -31,7 +40,32 @@ AudioEffectAnalogDelay::AudioEffectAnalogDelay(EXTERNAL_MEMORY, MemSlot &slot)
void AudioEffectAnalogDelay::update(void)
{
audio_block_t *inputAudioBlock = receiveReadOnly(); // get the next block of input samples
audio_block_t *inputAudioBlock = receiveReadOnly(); // get the next block of input samplestransmit(inputAudioBlock, 0);
if (!inputAudioBlock) {
return;
}
// else {
// transmit(inputAudioBlock, 0);
// release(inputAudioBlock);
// return;
// }
if (m_callCount < 1024) {
if (inputAudioBlock) {
transmit(inputAudioBlock, 0);
release(inputAudioBlock);
}
m_callCount++; return;
}
// else if (m_callCount > 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<MemAudioBlock*>(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<MemAudioBlock*>(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<MemAudioBlock*>(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<<channel;
return true;
}
bool AudioEffectAnalogDelay::delay(unsigned channel, size_t delaySamples)
{
if (channel > MAX_DELAY_CHANNELS-1) // channel id too high
return false;
if (!m_externalMemory) {
// Internal memory (AudioStream buffers)
MemAudioBlock *memory = reinterpret_cast<MemAudioBlock*>(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 {

@ -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;
};
}

@ -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; i<m_maxSize; i++) {
// Serial.println(i + String(":") + (uint32_t)m_buffer[i]->data);
// }
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; idx<m_maxSize; idx++) {
Serial.println(idx + String(" address: ") + (uint32_t)m_buffer[idx] + String(" data: ") + (uint32_t)m_buffer[idx]->data);
}
}
private:
size_t m_head=0;
size_t m_tail=0;

@ -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; i<m_queues.getMaxSize(); i++) {
// Serial.println(i + String(":") + (uint32_t)m_queues[i]->data);
// }
// 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<void*>(m_queues[index]->data + writeOffset);
void *destStart = static_cast<void*>(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<const void*>(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<void*>(destStart), static_cast<void*>(srcStart), numData * sizeof(int16_t));
void *srcStart = static_cast<void*>(m_queues[index]->data + readOffset);
void *destStart = static_cast<void *>(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<void*>(destStart), static_cast<void*>(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;
}

@ -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;

Loading…
Cancel
Save