cleanup up LibMemoryManagement.*

master
Steve Lascos 7 years ago
parent 9fd96aa5e3
commit 7cf4b57bc6
  1. 14
      src/AudioEffectAnalogDelay.cpp
  2. 6
      src/BAAudioControlWM8731.h
  3. 2
      src/BASpiMemory.h
  4. 49
      src/LibBasicFunctions.cpp
  5. 151
      src/LibMemoryManagement.cpp
  6. 189
      src/LibMemoryManagement.h

@ -71,7 +71,7 @@ void AudioEffectAnalogDelay::update(void)
m_callCount++; m_callCount++;
Serial.println(String("AudioEffectAnalgDelay::update: ") + m_callCount); Serial.println(String("AudioEffectAnalgDelay::update: ") + m_callCount);
m_memory->getSlot()->printStatus(); //m_memory->getSlot()->printStatus();
audio_block_t *blockToRelease = m_memory->addBlock(inputAudioBlock); audio_block_t *blockToRelease = m_memory->addBlock(inputAudioBlock);
// if (inputAudioBlock) { // if (inputAudioBlock) {
@ -113,7 +113,7 @@ void AudioEffectAnalogDelay::update(void)
if (!blockToOutput) continue; // skip this channel due to failure if (!blockToOutput) continue; // skip this channel due to failure
// copy over data // copy over data
m_memory->getSamples(blockToOutput, m_channelOffsets[channel]); m_memory->getSamples(blockToOutput, m_channelOffsets[channel]);
//m_memory->read16(blockToOutput->data, 0, m_channelOffsets[channel], AUDIO_BLOCK_SAMPLES);
transmit(blockToOutput); transmit(blockToOutput);
release(blockToOutput); release(blockToOutput);
} }
@ -126,6 +126,8 @@ bool AudioEffectAnalogDelay::delay(unsigned channel, float milliseconds)
size_t delaySamples = calcAudioSamples(milliseconds); size_t delaySamples = calcAudioSamples(milliseconds);
if (!m_memory) { Serial.println("delay(): m_memory is not valid"); }
if (!m_externalMemory) { if (!m_externalMemory) {
// internal memory // internal memory
QueuePosition queuePosition = calcQueuePosition(milliseconds); QueuePosition queuePosition = calcQueuePosition(milliseconds);
@ -134,10 +136,11 @@ bool AudioEffectAnalogDelay::delay(unsigned channel, float milliseconds)
// external memory // external memory
Serial.println(String("CONFIG: delay:") + delaySamples); Serial.println(String("CONFIG: delay:") + delaySamples);
ExtMemSlot *slot = m_memory->getSlot(); ExtMemSlot *slot = m_memory->getSlot();
if (!slot) { Serial.println("ERROR: slot ptr is not valid"); }
if (!slot->isEnabled()) { if (!slot->isEnabled()) {
slot->enable(); slot->enable();
} else { Serial.println("WEIRD: slot was not enabled");
Serial.println("ERROR: slot ptr is not valid");
} }
} }
@ -151,12 +154,15 @@ bool AudioEffectAnalogDelay::delay(unsigned channel, size_t delaySamples)
if (channel > MAX_DELAY_CHANNELS-1) // channel id too high if (channel > MAX_DELAY_CHANNELS-1) // channel id too high
return false; return false;
if (!m_memory) { Serial.println("delay(): m_memory is not valid"); }
if (!m_externalMemory) { if (!m_externalMemory) {
// internal memory // internal memory
QueuePosition queuePosition = calcQueuePosition(delaySamples); QueuePosition queuePosition = calcQueuePosition(delaySamples);
Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset); Serial.println(String("CONFIG: delay:") + delaySamples + String(" queue position ") + queuePosition.index + String(":") + queuePosition.offset);
} else { } else {
// external memory // external memory
Serial.println(String("CONFIG: delay:") + delaySamples);
ExtMemSlot *slot = m_memory->getSlot(); ExtMemSlot *slot = m_memory->getSlot();
if (!slot->isEnabled()) { if (!slot->isEnabled()) {
slot->enable(); slot->enable();

@ -22,8 +22,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/ *****************************************************************************/
#ifndef __INC_BAAUDIOCONTROLWM8731_H #ifndef __BAAUDIOCONTROLWM8731_H
#define __INC_BAAUDIOCONTROLWM8731_H #define __BAAUDIOCONTROLWM8731_H
namespace BAGuitar { namespace BAGuitar {
@ -128,4 +128,4 @@ private:
} /* namespace BAGuitar */ } /* namespace BAGuitar */
#endif /* __INC_BAAUDIOCONTROLWM8731_H */ #endif /* __BAAUDIOCONTROLWM8731_H */

@ -59,7 +59,7 @@ public:
void write16(size_t address, uint16_t data); void write16(size_t address, uint16_t data);
void write16(size_t address, uint16_t *data, size_t numWords); void write16(size_t address, uint16_t *data, size_t numWords);
void zero16(size_t address, size_t numBytes); void zero16(size_t address, size_t numWords);
/// read a single 8-bit data word from the specified address /// read a single 8-bit data word from the specified address
/// @param address the address in the SPI RAM to read from /// @param address the address in the SPI RAM to read from

@ -50,9 +50,10 @@ AudioDelay::AudioDelay(float maxDelayTimeMs)
} }
AudioDelay::AudioDelay(ExtMemSlot *slot) AudioDelay::AudioDelay(ExtMemSlot *slot)
: m_slot(slot) //: m_slot(slot)
{ {
m_type = MemType::MEM_EXTERNAL; m_type = MemType::MEM_EXTERNAL;
m_slot = slot;
} }
AudioDelay::~AudioDelay() AudioDelay::~AudioDelay()
@ -77,15 +78,24 @@ audio_block_t* AudioDelay::addBlock(audio_block_t *block)
return blockToRelease; return blockToRelease;
} else { } else {
// EXTERNAL memory // EXTERNAL memory
if (!m_slot) { Serial.println("addBlock(): m_slot is not valid"); }
//m_slot->writeAdvance16(block->data, AUDIO_BLOCK_SAMPLES); if (block) {
// 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; i<AUDIO_BLOCK_SAMPLES; i++) {
// m_slot->writeAdvance16(*srcPtr);
// srcPtr--;
// }
int16_t *srcPtr = block->data;
for (int i=0; i<AUDIO_BLOCK_SAMPLES; i++) {
m_slot->writeAdvance16(*srcPtr);
srcPtr++;
}
// 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; i<AUDIO_BLOCK_SAMPLES; i++) {
m_slot->writeAdvance16(*srcPtr);
srcPtr--;
} }
return block; return block;
@ -140,25 +150,36 @@ bool AudioDelay::getSamples(audio_block_t *dest, size_t offset, size_t numSample
} else { } else {
// EXTERNAL Memory // EXTERNAL Memory
if (numSamples <= m_slot->size() ) { if (numSamples*sizeof(int16_t) <= m_slot->size() ) {
int currentPosition = (int)m_slot->getWritePosition() - (int)AUDIO_BLOCK_SAMPLES; int currentPositionBytes = (int)m_slot->getWritePosition() - (int)(AUDIO_BLOCK_SAMPLES*sizeof(int16_t));
size_t offsetBytes = offset * sizeof(int16_t);
if ((int)offset <= currentPosition) { if ((int)offsetBytes <= currentPositionBytes) {
m_slot->setReadPosition(currentPosition - offset); m_slot->setReadPosition(currentPositionBytes - offsetBytes);
} else { } else {
// It's going to wrap around to the end of the slot // It's going to wrap around to the end of the slot
int readPosition = (int)m_slot->size() + currentPosition - offset; int readPosition = (int)m_slot->size() + currentPositionBytes - offsetBytes;
m_slot->setReadPosition((size_t)readPosition); m_slot->setReadPosition((size_t)readPosition);
} }
m_slot->printStatus();
// write the data to the destination block in reverse // write the data to the destination block in reverse
int16_t *destPtr = dest->data + AUDIO_BLOCK_SAMPLES-1; // int16_t *destPtr = dest->data + AUDIO_BLOCK_SAMPLES-1;
// for (int i=0; i<AUDIO_BLOCK_SAMPLES; i++) {
// *destPtr = m_slot->readAdvance16();
// destPtr--;
// }
int16_t *destPtr = dest->data;
for (int i=0; i<AUDIO_BLOCK_SAMPLES; i++) { for (int i=0; i<AUDIO_BLOCK_SAMPLES; i++) {
*destPtr = m_slot->readAdvance16(); *destPtr = m_slot->readAdvance16();
destPtr++;
} }
return true; return true;
} else { } else {
// numSampmles is > than total slot size // numSampmles is > than total slot size
Serial.println("getSamples(): ERROR numSamples > total slot size");
return false; return false;
} }
} }

@ -1,9 +1,26 @@
/*
* LibMemoryManagement.cpp
*
* Created on: Jan 19, 2018
* Author: slascos
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstring> #include <cstring>
#include <new> #include <new>
#include "Audio.h" #include "Audio.h"
#include "LibMemoryManagement.h" #include "LibMemoryManagement.h"
namespace BAGuitar { namespace BAGuitar {
@ -19,12 +36,21 @@ bool ExtMemSlot::clear()
return true; return true;
} }
bool ExtMemSlot::write16(size_t offset, int16_t *dataPtr, size_t dataSize) bool ExtMemSlot::setWritePosition(size_t offsetBytes)
{
if (m_start + offsetBytes <= m_end) {
m_currentWrPosition = m_start + offsetBytes;
return true;
} else { return false; }
}
bool ExtMemSlot::write16(size_t offsetBytes, int16_t *dest, size_t numWords)
{ {
if (!m_valid) { return false; } if (!m_valid) { return false; }
size_t writeStart = m_start + offset; size_t writeStart = m_start + offsetBytes; // 2x because int16 is two bytes per data
if ((writeStart + dataSize-1) <= m_end) { size_t numBytes = sizeof(int16_t)*numWords;
m_spi->write16(writeStart, reinterpret_cast<uint16_t*>(dataPtr), dataSize); // cast audio data to uint if ((writeStart + numBytes-1) <= m_end) {
m_spi->write16(writeStart, reinterpret_cast<uint16_t*>(dest), numWords); // cast audio data to uint
return true; return true;
} else { } else {
// this would go past the end of the memory slot, do not perform the write // this would go past the end of the memory slot, do not perform the write
@ -32,12 +58,23 @@ bool ExtMemSlot::write16(size_t offset, int16_t *dataPtr, size_t dataSize)
} }
} }
bool ExtMemSlot::zero16(size_t offset, size_t dataSize) bool ExtMemSlot::setReadPosition(size_t offsetBytes)
{
if (m_start + offsetBytes <= m_end) {
m_currentRdPosition = m_start + offsetBytes;
return true;
} else {
return false;
}
}
bool ExtMemSlot::zero16(size_t offsetBytes, size_t numWords)
{ {
if (!m_valid) { return false; } if (!m_valid) { return false; }
size_t writeStart = m_start + offset; size_t writeStart = m_start + offsetBytes;
if ((writeStart + dataSize-1) <= m_end) { size_t numBytes = sizeof(int16_t)*numWords;
m_spi->zero16(writeStart, dataSize); // cast audio data to uint if ((writeStart + numBytes-1) <= m_end) {
m_spi->zero16(writeStart, numWords); // cast audio data to uint
return true; return true;
} else { } else {
// this would go past the end of the memory slot, do not perform the write // this would go past the end of the memory slot, do not perform the write
@ -45,16 +82,17 @@ bool ExtMemSlot::zero16(size_t offset, size_t dataSize)
} }
} }
bool ExtMemSlot::read16(int16_t *dest, size_t srcOffset, size_t numData) bool ExtMemSlot::read16(int16_t *dest, size_t offsetBytes, size_t numWords)
{ {
if (!dest) return false; // invalid destination if (!dest) return false; // invalid destination
size_t readOffset = m_start + srcOffset; size_t readOffset = m_start + offsetBytes;
size_t numBytes = sizeof(int16_t)*numWords;
if ((readOffset + (numData*sizeof(int16_t))-1) <= m_end) { if ((readOffset + numBytes-1) <= m_end) {
m_spi->read16(readOffset, reinterpret_cast<uint16_t*>(dest), numData); m_spi->read16(readOffset, reinterpret_cast<uint16_t*>(dest), numWords);
return true; return true;
} else { } else {
// this would go past the end of the memory slot, do not perform the write // this would go past the end of the memory slot, do not perform the read
return false; return false;
} }
} }
@ -62,8 +100,8 @@ bool ExtMemSlot::read16(int16_t *dest, size_t srcOffset, size_t numData)
uint16_t ExtMemSlot::readAdvance16() uint16_t ExtMemSlot::readAdvance16()
{ {
uint16_t val = m_spi->read16(m_currentRdPosition); uint16_t val = m_spi->read16(m_currentRdPosition);
if (m_currentRdPosition < m_end) { if (m_currentRdPosition < m_end-1) {
m_currentRdPosition++; m_currentRdPosition +=2; // position is in bytes and we read two
} else { } else {
m_currentRdPosition = m_start; m_currentRdPosition = m_start;
} }
@ -71,70 +109,65 @@ uint16_t ExtMemSlot::readAdvance16()
} }
//void ExtMemSlot::read16FromPast(int16_t *dest, size_t currentOffset, size_t numData) bool ExtMemSlot::writeAdvance16(int16_t *src, size_t numWords)
//{
// 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<uint16_t*>(dest), numData);
//}
bool ExtMemSlot::writeAdvance16(int16_t *dataPtr, size_t dataSize)
{ {
if (!m_valid) { return false; } if (!m_valid) { return false; }
if (m_currentWrPosition + dataSize-1 <= m_end) { size_t numBytes = sizeof(int16_t)*numWords;
if (m_currentWrPosition + numBytes-1 <= m_end) {
// entire block fits in memory slot without wrapping // entire block fits in memory slot without wrapping
m_spi->write16(m_currentWrPosition, reinterpret_cast<uint16_t*>(dataPtr), dataSize); // cast audio data to uint. m_spi->write16(m_currentWrPosition, reinterpret_cast<uint16_t*>(src), numWords); // cast audio data to uint.
m_currentWrPosition += dataSize; m_currentWrPosition += numBytes;
} else { } else {
// this write will wrap the memory slot // this write will wrap the memory slot
size_t numBytes = m_end - m_currentWrPosition + 1; size_t wrBytes = m_end - m_currentWrPosition + 1;
m_spi->write16(m_currentWrPosition, reinterpret_cast<uint16_t*>(dataPtr), numBytes); size_t wrDataNum = wrBytes >> 1; // divide by two to get the number of data
size_t remainingBytes = dataSize - numBytes; // calculate the remaining bytes m_spi->write16(m_currentWrPosition, reinterpret_cast<uint16_t*>(src), wrDataNum);
m_spi->write16(m_start, reinterpret_cast<uint16_t*>(dataPtr + numBytes), remainingBytes); // write remaining bytes are start size_t remainingData = numWords - wrDataNum;
m_currentWrPosition = m_start + remainingBytes; m_spi->write16(m_start, reinterpret_cast<uint16_t*>(src + wrDataNum), remainingData); // write remaining bytes are start
m_currentWrPosition = m_start + (remainingData*sizeof(int16_t));
} }
return true; return true;
} }
bool ExtMemSlot::writeAdvance16(int16_t data)
bool ExtMemSlot::zeroAdvance16(size_t numWords)
{ {
if (!m_valid) { return false; } if (!m_valid) { return false; }
size_t numBytes = 2*numWords;
if (m_currentWrPosition + numBytes-1 <= m_end) {
// entire block fits in memory slot without wrapping
m_spi->zero16(m_currentWrPosition, numWords); // cast audio data to uint.
m_currentWrPosition += numBytes;
m_spi->write16(m_currentWrPosition, static_cast<uint16_t>(data));
if (m_currentWrPosition < m_end) {
m_currentWrPosition++;
} else { } else {
m_currentWrPosition = m_start; // this write will wrap the memory slot
size_t wrBytes = m_end - m_currentWrPosition + 1;
size_t wrDataNum = wrBytes >> 1;
m_spi->zero16(m_currentWrPosition, wrDataNum);
size_t remainingWords = numWords - wrDataNum; // calculate the remaining bytes
m_spi->zero16(m_start, remainingWords); // write remaining bytes are start
m_currentWrPosition = m_start + remainingWords*sizeof(int16_t);
} }
return true; return true;
} }
bool ExtMemSlot::zeroAdvance16(size_t dataSize)
bool ExtMemSlot::writeAdvance16(int16_t data)
{ {
if (!m_valid) { return false; } if (!m_valid) { return false; }
if (m_currentWrPosition + dataSize-1 <= m_end) {
// entire block fits in memory slot without wrapping
m_spi->zero16(m_currentWrPosition, dataSize); // cast audio data to uint.
m_currentWrPosition += dataSize;
m_spi->write16(m_currentWrPosition, static_cast<uint16_t>(data));
if (m_currentWrPosition < m_end-1) {
m_currentWrPosition+=2; // wrote two bytes
} else { } else {
// this write will wrap the memory slot m_currentWrPosition = m_start;
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_currentWrPosition = m_start + remainingBytes;
} }
return true; return true;
} }
bool ExtMemSlot::enable() const bool ExtMemSlot::enable() const
{ {
if (m_spi) { if (m_spi) {
@ -158,6 +191,7 @@ void ExtMemSlot::printStatus(void) const
{ {
Serial.println(String("valid:") + m_valid + String(" m_start:") + m_start + \ Serial.println(String("valid:") + m_valid + String(" m_start:") + m_start + \
String(" m_end:") + m_end + String(" m_currentWrPosition: ") + m_currentWrPosition + \ String(" m_end:") + m_end + String(" m_currentWrPosition: ") + m_currentWrPosition + \
String(" m_currentRdPosition: ") + m_currentRdPosition + \
String(" m_size:") + m_size); String(" m_size:") + m_size);
} }
@ -178,11 +212,6 @@ ExternalSramManager::ExternalSramManager(unsigned numMemories)
m_memConfig[i].nextAvailable = 0; m_memConfig[i].nextAvailable = 0;
m_memConfig[i].m_spi = nullptr; m_memConfig[i].m_spi = nullptr;
// if (i < numMemories) {
// m_memConfig[i].m_spi = new BAGuitar::BASpiMemory(static_cast<BAGuitar::SpiDeviceId>(i));
// } else {
// m_memConfig[i].m_spi = nullptr;
// }
} }
m_configured = true; m_configured = true;
} }
@ -204,7 +233,7 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, float delayMillisecond
{ {
// convert the time to numer of samples // convert the time to numer of samples
size_t delayLengthInt = (size_t)((delayMilliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f); size_t delayLengthInt = (size_t)((delayMilliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f);
return requestMemory(slot, delayLengthInt, mem); return requestMemory(slot, delayLengthInt * sizeof(int16_t), mem);
} }
bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem) bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem)

@ -1,87 +1,196 @@
/* /**************************************************************************//**
* ExtMemoryManagement.h * @file
* @author Steve Lascos
* @company Blackaddr Audio
* *
* Created on: Dec 23, 2017 * LibMemoryManagment is a class for providing access to external SPI based
* Author: slascos * SRAM with the optional convience of breaking it up into 'slots' which are smaller
*/ * memory entities.
* @details This class treats an external memory as a pool from which the user requests
* a block. When using that block, the user need not be concerned with where the pool
* it came from, they only deal with offsets from the start of their memory block. Ie.
* Your particular slot of memory appears to you to start at 0 and end at whatever size
* was requested.
*
* @copyright This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#ifndef SRC_LIBMEMORYMANAGEMENT_H_ #ifndef __LIBMEMORYMANAGEMENT_H
#define SRC_LIBMEMORYMANAGEMENT_H_ #define __LIBMEMORYMANAGEMENT_H
#include <cstddef> #include <cstddef>
//#include "Audio.h"
#include "BAHardware.h" #include "BAHardware.h"
#include "BASpiMemory.h" #include "BASpiMemory.h"
//#include "LibBasicFunctions.h"
namespace BAGuitar { namespace BAGuitar {
/**************************************************************************//**
* MemConfig contains the configuration information associated with a particular
* SPI interface.
*****************************************************************************/
struct MemConfig { struct MemConfig {
size_t size; size_t size; ///< the total size of the external SPI memory
size_t totalAvailable; size_t totalAvailable; ///< the number of bytes available (remaining)
size_t nextAvailable; size_t nextAvailable; ///< the starting point for the next available slot
BASpiMemory *m_spi = nullptr; BASpiMemory *m_spi = nullptr; ///< handle to the SPI interface
}; };
class ExternalSramManager; // forward declare so ExtMemSlot can setup friendship class ExternalSramManager; // forward declare so ExtMemSlot can declared friendship with it
/**************************************************************************//**
* ExtMemSlot provides a convenient interface to a particular slot of an
* external memory.
* @details the memory can be access randomly, as a single word, as a block of
* data, or as circular queue.
*****************************************************************************/
class ExtMemSlot { class ExtMemSlot {
public: public:
/// clear the entire contents of the slot by writing zeros
/// @returns true on success
bool clear(); bool clear();
bool setWritePosition(size_t offset) { m_currentWrPosition = m_start + offset; return true;} // TODO add range check
/// set a new write position (in bytes) for circular operation
/// @param offsetBytes moves the write pointer to the specified offset from the slot start
/// @returns true on success, else false if offset is beyond slot boundaries.
bool setWritePosition(size_t offsetBytes);
/// returns the currently set write pointer pointer
/// @returns the write position value
size_t getWritePosition() const { return m_currentWrPosition-m_start; } 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 /// set a new read position (in bytes) for circular operation
size_t getReadPosition() const { return m_currentRdPosition-m_start; } /// @param offsetBytes moves the read pointer to the specified offset from the slot start
/// @returns true on success, else false if offset is beyond slot boundaries.
bool setReadPosition(size_t offsetBytes);
bool write16(size_t offset, int16_t *dataPtr, size_t numData); /// returns the currently set read pointer pointer
bool zero16(size_t offset, size_t numData); /// @returns the read position value
bool read16(int16_t *dest, size_t srcOffset, size_t numData); size_t getReadPosition() const { return m_currentRdPosition-m_start; }
/// Write a block of 16-bit data to the memory at the specified offset
/// @param offsetBytes offset in bytes from start of slot
/// @param dataPtr pointer to start of block of 16-bit data
/// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error
bool write16(size_t offsetBytes, int16_t *dest, size_t numWords);
/// Write a block of zeros (16-bit) to the memory at the specified offset
/// @param offsetBytes offset in bytes from start of slot
/// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error
bool zero16(size_t offsetBytes, size_t numWords);
/// Read a block of 16-bit data from the memory at the specified location
/// @param dest pointer to destination for the read data
/// @param offsetBytes offset in bytes from start of slot
/// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error
bool read16(int16_t *dest, size_t offsetBytes, size_t numWords);
/// Read the next in memory during circular operation
/// @returns the next 16-bit data word in memory
uint16_t readAdvance16(); uint16_t readAdvance16();
bool writeAdvance16(int16_t *dataPtr, size_t numData);
/// Write a block of 16-bit data from the specified location in circular operation
/// @param src pointer to the start of the block of data to write to memory
/// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error
bool writeAdvance16(int16_t *src, size_t numWords);
/// Write a single 16-bit data to the next location in circular operation
/// @param data the 16-bit word to transfer
/// @returns true on success, else false on error
bool writeAdvance16(int16_t data); // write just one data bool writeAdvance16(int16_t data); // write just one data
bool zeroAdvance16(size_t numData);
//void read16FromPast(int16_t *dest, size_t Offset, size_t numData); /// Write a block of 16-bit data zeros in circular operation
/// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error
bool zeroAdvance16(size_t numWords);
/// Get the size of the memory slot
/// @returns size of the slot in bytes
size_t size() const { return m_size; } size_t size() const { return m_size; }
/// Ensures the underlying SPI interface is enabled
/// @returns true on success, false on error
bool enable() const; bool enable() const;
/// Checks whether underlying SPI interface is enabled
/// @returns true if enabled, false if not enabled
bool isEnabled() const; bool isEnabled() const;
/// DEBUG USE: prints out the slot member variables
void printStatus(void) const; void printStatus(void) const;
private: private:
friend ExternalSramManager; friend ExternalSramManager; ///< gives the manager access to the private variables
bool m_valid = false; bool m_valid = false; ///< After a slot is successfully configured by the manager it becomes valid
size_t m_start = 0; size_t m_start = 0; ///< the external memory address in bytes where this slot starts
size_t m_end = 0; size_t m_end = 0; ///< the external memory address in bytes where this slot ends (inclusive)
size_t m_currentWrPosition = 0; size_t m_currentWrPosition = 0; ///< current write pointer for circular operation
size_t m_currentRdPosition = 0; size_t m_currentRdPosition = 0; ///< current read pointer for circular operation
size_t m_size = 0; size_t m_size = 0; ///< size of this slot in bytes
SpiDeviceId m_spiId; SpiDeviceId m_spiId; ///< the SPI Device ID
BASpiMemory *m_spi = nullptr; BASpiMemory *m_spi = nullptr; ///< pointer to an instance of the BASpiMemory interface class
}; };
/**************************************************************************//**
* ExternalSramManager provides a class to handle dividing an external SPI RAM
* into independent slots for general use.
* @details the class does not support deallocated memory because this would cause
* fragmentation.
*****************************************************************************/
class ExternalSramManager final { class ExternalSramManager final {
public: public:
ExternalSramManager() = delete; ExternalSramManager() = delete;
ExternalSramManager(unsigned numMemories);
/// The manager is constructed by specifying how many external memories to handle allocations for
/// @param numMemories the number of external memories
ExternalSramManager(unsigned numMemories = 1);
virtual ~ExternalSramManager(); virtual ~ExternalSramManager();
size_t availableMemory(BAGuitar::MemSelect mem); /// Query the amount of available (unallocated) memory
/// @details note that currently, memory cannot be allocated.
/// @param mem specifies which memory to query, default is memory 0
/// @returns the available memory in bytes
size_t availableMemory(BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0);
/// Request memory be allocated for the provided slot
/// @param slot a pointer to the global slot object to which memory will be allocated
/// @param delayMilliseconds request the amount of memory based on required time for audio samples, rather than number of bytes.
/// @param mem specify which external memory to allocate from
/// @returns true on success, otherwise false on error
bool requestMemory(ExtMemSlot *slot, float delayMilliseconds, 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);
/// Request memory be allocated for the provided slot
/// @param slot a pointer to the global slot object to which memory will be allocated
/// @param sizeBytes request the amount of memory in bytes to request
/// @param mem specify which external memory to allocate from
/// @returns true on success, otherwise false on error
bool requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0);
private: private:
static bool m_configured; static bool m_configured; ///< there should only be one instance of ExternalSramManager in the whole project
static MemConfig m_memConfig[BAGuitar::NUM_MEM_SLOTS]; static MemConfig m_memConfig[BAGuitar::NUM_MEM_SLOTS]; ///< store the configuration information for each external memory
}; };
} }
#endif /* SRC_LIBMEMORYMANAGEMENT_H_ */ #endif /* __LIBMEMORYMANAGEMENT_H */

Loading…
Cancel
Save