Development checkin

master
Steve Lascos 6 years ago
parent 988174912b
commit d2a8227f91
  1. 118
      src/AudioEffectAnalogDelay.cpp
  2. 45
      src/AudioEffectAnalogDelay.h
  3. 2
      src/BAGuitar.h
  4. 13
      src/BAHardware.h
  5. 4
      src/BASpiMemory.h
  6. 21
      src/LibBasicFunctions.cpp
  7. 80
      src/LibBasicFunctions.h
  8. 66
      src/LibExtMemoryManagement.h
  9. 119
      src/LibMemoryManagement.h
  10. 360
      src/LibMemoryManagment.cpp

@ -0,0 +1,118 @@
/*
* AudioEffectAnalogDelay.cpp
*
* Created on: Jan 7, 2018
* Author: slascos
*/
#include <new>
#include "AudioEffectAnalogDelay.h"
namespace BAGuitar {
AudioEffectAnalogDelay::AudioEffectAnalogDelay(INTERNAL_MEMORY, float maxDelay)
: AudioStream(1, m_inputQueueArray)
{
m_memory = new MemAudioBlock(maxDelay);
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)
{
m_memory = &slot;
for (int i=0; i<MAX_DELAY_CHANNELS; i++) {
m_channelOffsets[i] = 0;
}
m_memory->clear();
}
void AudioEffectAnalogDelay::update(void)
{
audio_block_t *inputAudioBlock = receiveReadOnly(); // get the next block of input samples
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<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) {
release(memory->pop());
}
}
// For each active channel, output the delayed audio
audio_block_t *blockToOutput = nullptr;
for (int channel=0; channel<MAX_DELAY_CHANNELS; channel++) {
if (!(m_activeChannels & (1<<channel))) continue; // If this channel is disable, skip to the next;
if (!m_externalMemory) {
// internal memory
MemAudioBlock *memory = reinterpret_cast<MemAudioBlock*>(m_memory);
QueuePosition queuePosition = calcQueuePosition(m_channelOffsets[channel]);
if (queuePosition.offset == 0) {
// only one queue needs to be read out
blockToOutput= memory->getQueue(queuePosition.index); // could be nullptr!
transmit(blockToOutput);
} else {
blockToOutput = allocate(); // allocate if spanning 2 queues
}
} else {
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->read16(blockToOutput->data, 0, m_channelOffsets[channel], AUDIO_BLOCK_SAMPLES);
transmit(blockToOutput);
release(blockToOutput);
}
}
bool AudioEffectAnalogDelay::delay(unsigned channel, float milliseconds)
{
if (channel > MAX_DELAY_CHANNELS-1) // channel id too high
return false;
size_t delaySamples = calcAudioSamples(milliseconds);
if (!m_externalMemory) {
// Internal memory (AudioStream buffers)
QueuePosition queuePosition = calcQueuePosition(milliseconds);
size_t numQueues = queuePosition.index+1;
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;
}
void AudioEffectAnalogDelay::disable(unsigned channel)
{
m_activeChannels &= ~(1<<channel);
}
}

@ -0,0 +1,45 @@
/*
* AudioEffectAnalogDelay.h
*
* Created on: Jan 7, 2018
* Author: slascos
*/
#ifndef SRC_AUDIOEFFECTANALOGDELAY_H_
#define SRC_AUDIOEFFECTANALOGDELAY_H_
#include <vector>
#include <Audio.h>
#include "LibMemoryManagement.h"
namespace BAGuitar {
class AudioEffectAnalogDelay : public AudioStream {
public:
static constexpr int MAX_DELAY_CHANNELS = 8;
AudioEffectAnalogDelay() = delete;
AudioEffectAnalogDelay(INTERNAL_MEMORY, float maxDelay);
AudioEffectAnalogDelay(EXTERNAL_MEMORY, MemSlot &slot); // requires sufficiently sized pre-allocated memory
virtual ~AudioEffectAnalogDelay() {}
virtual void update(void);
bool delay(unsigned channel, float milliseconds);
void disable(unsigned channel);
private:
audio_block_t *m_inputQueueArray[1];
unsigned m_activeChannels = 0;
bool m_externalMemory = false;
MemBufferIF *m_memory = nullptr;
size_t m_numQueues = 0;
size_t m_channelOffsets[MAX_DELAY_CHANNELS];
};
}
#endif /* SRC_AUDIOEFFECTANALOGDELAY_H_ */

@ -28,4 +28,6 @@
#include "BAGpio.h"
#include "BAAudioEffectDelayExternal.h"
#include "AudioEffectAnalogDelay.h"
#endif /* __SRC_BATGUITAR_H */

@ -23,6 +23,8 @@
#ifndef SRC_BAHARDWARE_H_
#define SRC_BAHARDWARE_H_
#include <cstdint>
/**************************************************************************//**
* BAGuitar is a namespace/Library for Guitar processing from Blackaddr Audio.
*****************************************************************************/
@ -62,15 +64,16 @@ enum MemSelect : unsigned {
MEM0 = 0, ///< SPI RAM MEM0
MEM1 = 1 ///< SPI RAM MEM1
};
constexpr int MEM0_MAX_ADDR = 131071; ///< Max address size per chip
constexpr int MEM1_MAX_ADDR = 131071; ///< Max address size per chip
constexpr size_t MEM_MAX_ADDR[NUM_MEM_SLOTS] = { 131071, 131071 };
//constexpr int MEM0_MAX_ADDR = 131071; ///< Max address size per chip
//constexpr int MEM1_MAX_ADDR = 131071; ///< Max address size per chip
/**************************************************************************//**
* General Purpose SPI Interfaces
*****************************************************************************/
enum class SpiDeviceId {
SPI_DEVICE0, ///< Arduino SPI device
SPI_DEVICE1 ///< Arduino SPI1 device
enum SpiDeviceId : unsigned {
SPI_DEVICE0 = 0, ///< Arduino SPI device
SPI_DEVICE1 = 1 ///< Arduino SPI1 device
};
constexpr int SPI_MAX_ADDR = 131071; ///< Max address size per chip

@ -57,7 +57,7 @@ public:
void zero(size_t address, size_t numBytes);
void write16(size_t address, uint16_t data);
void write16(size_t address, uint16_t *data, size_t numBytes);
void write16(size_t address, uint16_t *data, size_t numWords);
void zero16(size_t address, size_t numBytes);
@ -71,7 +71,7 @@ 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 numBytes);
void read16(size_t address, uint16_t *data, size_t numWords);
private:

@ -9,27 +9,6 @@
namespace BAGuitar {
void updateAudioMemorySlot(BASpiMemory *mem, MemSlot slot, audio_block_t *block)
{
if (block) {
if (slot.currentPosition + AUDIO_BLOCK_SAMPLES-1 <= slot.end) {
// entire block fits in memory slot without wrapping
mem->write16(slot.currentPosition, (uint16_t *)block->data, AUDIO_BLOCK_SAMPLES); // cast audio data to uint.
} else {
// this write will wrap the memory slot
size_t numBytes = slot.end - slot.currentPosition + 1;
mem->write16(slot.currentPosition, (uint16_t *)block->data, numBytes);
size_t remainingBytes = AUDIO_BLOCK_SAMPLES - numBytes; // calculate the remaining bytes
mem->write16(slot.start, (uint16_t *)block->data + numBytes, remainingBytes); // write remaining bytes are start
}
}
}
void zeroMemorySlot(BASpiMemory *mem, MemSlot slot)
{
mem->zero16(slot.start, slot.end-slot.start+1);
}
}

@ -5,17 +5,85 @@
* Author: slascos
*/
#include <cstddef>
#include <new>
#include "Arduino.h"
#ifndef SRC_LIBBASICFUNCTIONS_H_
#define SRC_LIBBASICFUNCTIONS_H_
#include "Audio.h"
#include "LibExtMemoryManagement.h"
#include "BASpiMemory.h"
namespace BAGuitar {
void updateAudioMemorySlot(BAGuitar::BASpiMemory *mem, MemSlot slot, audio_block_t *block);
void zeroMemorySlot(BAGuitar::BASpiMemory *mem, MemSlot slot);
struct INTERNAL_MEMORY {};
struct EXTERNAL_MEMORY {};
template <class T>
class RingBuffer {
public:
RingBuffer() = delete;
RingBuffer(const size_t maxSize) : m_maxSize(maxSize) {
m_buffer = new T[maxSize];
}
virtual ~RingBuffer(){
if (m_buffer) delete [] m_buffer;
}
int push_back(T element) {
if ( (m_head == m_tail) && (m_size > 0) ) {
// overflow
Serial.println("RingBuffer::push_back: overflow");
return -1;
}
m_buffer[m_head] = element;
if (m_head < m_maxSize-1) {
m_head++;
} else {
m_head = 0;
}
m_size++;
return 0;
}
int pop_front() {
if (m_size == 0) {
// buffer is empty
Serial.println("RingBuffer::pop_front: buffer is empty\n");
return -1;
}
if (m_tail < m_maxSize-1) {
m_tail++;
} else {
m_tail = 0;
}
m_size--;
return 0;
}
T front() const {
return m_buffer[m_tail];
}
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;
}
T& operator[] (size_t index) {
return m_buffer[index];
}
private:
size_t m_head=0;
size_t m_tail=0;
size_t m_size=0;
T *m_buffer = nullptr;
const size_t m_maxSize;
};
}

@ -1,66 +0,0 @@
/*
* ExtMemoryManagement.h
*
* Created on: Dec 23, 2017
* Author: slascos
*/
#ifndef SRC_LIBEXTMEMORYMANAGEMENT_H_
#define SRC_LIBEXTMEMORYMANAGEMENT_H_
#include <cstddef>
#include "BAHardware.h"
namespace BAGuitar {
struct MemConfig {
size_t size;
size_t totalAvailable;
size_t nextAvailable;
};
struct MemSlot {
size_t start;
size_t end;
size_t currentPosition;
};
class ExternalSramManager {
public:
ExternalSramManager() = delete;
ExternalSramManager(BAGuitar::MemSelect mem) {
// Initialize the static memory configuration structs
m_memConfig[MEM0].size = MEM0_MAX_ADDR;
m_memConfig[MEM0].totalAvailable = MEM0_MAX_ADDR;
m_memConfig[MEM0].nextAvailable = 0;
m_memConfig[MEM0].size = MEM0_MAX_ADDR;
m_memConfig[MEM0].totalAvailable = MEM0_MAX_ADDR;
m_memConfig[MEM0].nextAvailable = 0;
}
bool getMemory(BAGuitar::MemSelect mem, size_t size, MemSlot &slot) {
if (m_memConfig[mem].totalAvailable >= size) {
slot.start = m_memConfig[mem].nextAvailable;
slot.end = slot.start + size -1;
slot.currentPosition = slot.start;
// Update the mem config
m_memConfig[mem].nextAvailable = slot.end+1;
m_memConfig[mem].totalAvailable -= size;
return true;
} else {
return false;
}
}
static MemConfig m_memConfig[BAGuitar::NUM_MEM_SLOTS];
};
}
#endif /* SRC_LIBEXTMEMORYMANAGEMENT_H_ */

@ -0,0 +1,119 @@
/*
* ExtMemoryManagement.h
*
* Created on: Dec 23, 2017
* Author: slascos
*/
#ifndef SRC_LIBMEMORYMANAGEMENT_H_
#define SRC_LIBMEMORYMANAGEMENT_H_
#include <cstddef>
#include "Audio.h"
#include "BAHardware.h"
#include "BASpiMemory.h"
#include "LibBasicFunctions.h"
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;
size_t nextAvailable;
BASpiMemory *m_spi = nullptr;
};
class ExternalSramManager; // forward declare so MemSlot can setup friendship
class MemBufferIF {
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 *getQueue(size_t index) { return m_queues[index]; }
size_t getNumQueues() const { return m_queues.size(); }
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 <audio_block_t*> 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;
private:
friend ExternalSramManager;
size_t m_start;
size_t m_end;
size_t m_currentPosition;
BASpiMemory *m_spi = nullptr;
};
class ExternalSramManager final {
public:
ExternalSramManager() = delete;
ExternalSramManager(unsigned numMemories);
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);
private:
static bool m_configured;
static MemConfig m_memConfig[BAGuitar::NUM_MEM_SLOTS];
};
}
#endif /* SRC_LIBMEMORYMANAGEMENT_H_ */

@ -0,0 +1,360 @@
#include <cstring>
#include <new>
#include "LibMemoryManagement.h"
namespace BAGuitar {
bool ExternalSramManager::m_configured = false;
MemConfig ExternalSramManager::m_memConfig[BAGuitar::NUM_MEM_SLOTS];
inline 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)
{
// // 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()
{
}
bool MemAudioBlock::push(audio_block_t *block)
{
m_queues.push_back(block);
return true;
}
audio_block_t* 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 *dataPtr, 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;
while (samplesRemaining > 0) {
size_t numSamplesToWrite;
void *start = 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++;
} 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 (dataPtr) {
memcpy(start, dataPtr, numSamplesToWrite * sizeof(int16_t));
} else {
memset(start, 0, numSamplesToWrite * sizeof(int16_t));
}
}
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
// 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
// loop over a series of memcpys until all data is transferred.
size_t samplesRemaining = numSamples;
while (samplesRemaining > 0) {
size_t numSamplesToRead;
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;
}
// 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;
}
// 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()
{
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)
{
if (!m_valid) { return false; }
if ((offset + dataSize-1) <= m_end) {
m_spi->write16(offset, reinterpret_cast<uint16_t*>(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
return false;
}
}
bool MemSlot::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
return true;
} else {
// this would go past the end of the memory slot, do not perform the write
return false;
}
}
bool MemSlot::read16(int16_t *dest, size_t destOffset, 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<uint16_t*>(dest), numData);
return true;
} else {
// this would go past the end of the memory slot, do not perform the write
return false;
}
}
bool MemSlot::writeAdvance16(int16_t *dataPtr, size_t dataSize)
{
if (!m_valid) { return false; }
if (m_currentPosition + dataSize-1 <= m_end) {
// entire block fits in memory slot without wrapping
m_spi->write16(m_currentPosition, reinterpret_cast<uint16_t*>(dataPtr), dataSize); // cast audio data to uint.
m_currentPosition += dataSize;
} else {
// this write will wrap the memory slot
size_t numBytes = m_end - m_currentPosition + 1;
m_spi->write16(m_currentPosition, reinterpret_cast<uint16_t*>(dataPtr), numBytes);
size_t remainingBytes = dataSize - numBytes; // calculate the remaining bytes
m_spi->write16(m_start, reinterpret_cast<uint16_t*>(dataPtr + numBytes), remainingBytes); // write remaining bytes are start
m_currentPosition = m_start + remainingBytes;
}
return true;
}
bool MemSlot::zeroAdvance16(size_t dataSize)
{
if (!m_valid) { return false; }
if (m_currentPosition + 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;
} else {
// this write will wrap the memory slot
size_t numBytes = m_end - m_currentPosition + 1;
m_spi->zero16(m_currentPosition, 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;
}
return true;
}
/////////////////////////////////////////////////////////////////////////////
// EXTERNAL SRAM MANAGER
/////////////////////////////////////////////////////////////////////////////
ExternalSramManager::ExternalSramManager(unsigned numMemories)
{
// Initialize the static memory configuration structs
if (!m_configured) {
for (unsigned i=0; i < NUM_MEM_SLOTS; i++) {
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<BAGuitar::SpiDeviceId>(i));
}
m_configured = true;
}
}
ExternalSramManager::~ExternalSramManager()
{
for (unsigned i=0; i < NUM_MEM_SLOTS; i++) {
if (m_memConfig[i].m_spi) { delete m_memConfig[i].m_spi; }
}
}
size_t ExternalSramManager::availableMemory(BAGuitar::MemSelect mem)
{
return m_memConfig[mem].totalAvailable;
}
bool ExternalSramManager::requestMemory(MemSlot &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)
{
if (m_memConfig[mem].totalAvailable >= sizeBytes) {
// 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;
// Update the mem config
m_memConfig[mem].nextAvailable = slot.m_end+1;
m_memConfig[mem].totalAvailable -= sizeBytes;
slot.m_valid = true;
return true;
} else {
// there is not enough memory available for the request
return false;
}
}
}
Loading…
Cancel
Save