Switched some 16-bit function offsets from bytes to words

master
Steve Lascos 7 years ago
parent 7c614e6450
commit cf7528ee8a
  1. 6
      src/LibBasicFunctions.cpp
  2. 180
      src/LibBasicFunctions.h
  3. 14
      src/LibMemoryManagement.cpp
  4. 18
      src/LibMemoryManagement.h

@ -144,7 +144,7 @@ audio_block_t* AudioDelay::getBlock(size_t index)
return ret; return ret;
} }
bool AudioDelay::getSamples(audio_block_t *dest, size_t offset, size_t numSamples) bool AudioDelay::getSamples(audio_block_t *dest, size_t offsetSamples, size_t numSamples)
{ {
if (!dest) { if (!dest) {
Serial.println("getSamples(): dest is invalid"); Serial.println("getSamples(): dest is invalid");
@ -152,7 +152,7 @@ bool AudioDelay::getSamples(audio_block_t *dest, size_t offset, size_t numSample
} }
if (m_type == (MemType::MEM_INTERNAL)) { if (m_type == (MemType::MEM_INTERNAL)) {
QueuePosition position = calcQueuePosition(offset); QueuePosition position = calcQueuePosition(offsetSamples);
size_t index = position.index; size_t index = position.index;
audio_block_t *currentQueue0 = m_ringBuffer->at(m_ringBuffer->get_index_from_back(index)); audio_block_t *currentQueue0 = m_ringBuffer->at(m_ringBuffer->get_index_from_back(index));
@ -195,7 +195,7 @@ bool AudioDelay::getSamples(audio_block_t *dest, size_t offset, size_t numSample
// EXTERNAL Memory // EXTERNAL Memory
if (numSamples*sizeof(int16_t) <= m_slot->size() ) { if (numSamples*sizeof(int16_t) <= m_slot->size() ) {
int currentPositionBytes = (int)m_slot->getWritePosition() - (int)(AUDIO_BLOCK_SAMPLES*sizeof(int16_t)); int currentPositionBytes = (int)m_slot->getWritePosition() - (int)(AUDIO_BLOCK_SAMPLES*sizeof(int16_t));
size_t offsetBytes = offset * sizeof(int16_t); size_t offsetBytes = offsetSamples * sizeof(int16_t);
if ((int)offsetBytes <= currentPositionBytes) { if ((int)offsetBytes <= currentPositionBytes) {
m_slot->setReadPosition(currentPositionBytes - offsetBytes); m_slot->setReadPosition(currentPositionBytes - offsetBytes);

@ -131,16 +131,19 @@ public:
/// @details when using INTERNAL memory, only supported size is AUDIO_BLOCK_SAMPLES. When using /// @details when using INTERNAL memory, only supported size is AUDIO_BLOCK_SAMPLES. When using
/// EXTERNAL, a size smaller than AUDIO_BLOCK_SAMPLES can be requested. /// EXTERNAL, a size smaller than AUDIO_BLOCK_SAMPLES can be requested.
/// @param dest pointer to the target audio block to write the samples to. /// @param dest pointer to the target audio block to write the samples to.
/// @param offset data will start being transferred offset samples from the start of the audio buffer /// @param offsetSamples data will start being transferred offset samples from the start of the audio buffer
/// @param numSamples default value is AUDIO_BLOCK_SAMPLES, so typically you don't have to specify this parameter. /// @param numSamples default value is AUDIO_BLOCK_SAMPLES, so typically you don't have to specify this parameter.
/// @returns true on success, false on error. /// @returns true on success, false on error.
bool getSamples(audio_block_t *dest, size_t offset, size_t numSamples = AUDIO_BLOCK_SAMPLES); bool getSamples(audio_block_t *dest, size_t offsetSamples, size_t numSamples = AUDIO_BLOCK_SAMPLES);
/// When using EXTERNAL memory, this function can return a pointer to the underlying ExtMemSlot object associated /// When using EXTERNAL memory, this function can return a pointer to the underlying ExtMemSlot object associated
/// with the buffer. /// with the buffer.
/// @returns pointer to the underlying ExtMemSlot. /// @returns pointer to the underlying ExtMemSlot.
ExtMemSlot *getSlot() const { return m_slot; } ExtMemSlot *getSlot() const { return m_slot; }
/// Ween using INTERNAL memory, thsi function can return a pointer to the underlying RingBuffer that contains
/// audio_block_t * pointers.
/// @returns pointer to the underlying RingBuffer
RingBuffer<audio_block_t*> *getRingBuffer() const { return m_ringBuffer; } RingBuffer<audio_block_t*> *getRingBuffer() const { return m_ringBuffer; }
private: private:
@ -168,8 +171,19 @@ private:
class IirBiQuadFilter { class IirBiQuadFilter {
public: public:
IirBiQuadFilter() = delete; IirBiQuadFilter() = delete;
/// Construct a Biquad filter with specified number of stages, coefficients and scaling.
/// @details See CMSIS-DSP documentation for more details
/// @param numStages number of biquad stages. Each stage has 5 coefficients.
/// @param coeffs pointer to an array of Q31 fixed-point coefficients (range -1 to +0.999...)
/// @param coeffShift coeffs are multiplied by 2^coeffShift to support coefficient range scaling
IirBiQuadFilter(unsigned numStages, const int32_t *coeffs, int coeffShift = 0); IirBiQuadFilter(unsigned numStages, const int32_t *coeffs, int coeffShift = 0);
virtual ~IirBiQuadFilter(); virtual ~IirBiQuadFilter();
/// Process the data using the configured IIR filter
/// @details output and input can be the same pointer if in-place modification is desired
/// @param output pointer to where the output results will be written
/// @param input pointer to where the input data will be read from
/// @param numSampmles number of samples to process
bool process(int16_t *output, int16_t *input, size_t numSamples); bool process(int16_t *output, int16_t *input, size_t numSamples);
private: private:
const unsigned NUM_STAGES; const unsigned NUM_STAGES;
@ -180,30 +194,58 @@ private:
int32_t *m_state = nullptr; int32_t *m_state = nullptr;
}; };
/**************************************************************************//**
* A High-precision version of IirBiQuadFilter often necessary for complex, multistage
* filters. This class uses CMSIS-DSP biquads with 64-bit internal precision instead
* of 32-bit.
*****************************************************************************/
class IirBiQuadFilterHQ { class IirBiQuadFilterHQ {
public: public:
IirBiQuadFilterHQ() = delete; IirBiQuadFilterHQ() = delete;
/// Construct a Biquad filter with specified number of stages, coefficients and scaling.
/// @details See CMSIS-DSP documentation for more details
/// @param numStages number of biquad stages. Each stage has 5 coefficients.
/// @param coeffs pointer to an array of Q31 fixed-point coefficients (range -1 to +0.999...)
/// @param coeffShift coeffs are multiplied by 2^coeffShift to support coefficient range scaling
IirBiQuadFilterHQ(unsigned numStages, const int32_t *coeffs, int coeffShift = 0); IirBiQuadFilterHQ(unsigned numStages, const int32_t *coeffs, int coeffShift = 0);
virtual ~IirBiQuadFilterHQ(); virtual ~IirBiQuadFilterHQ();
/// Process the data using the configured IIR filter
/// @details output and input can be the same pointer if in-place modification is desired
/// @param output pointer to where the output results will be written
/// @param input pointer to where the input data will be read from
/// @param numSampmles number of samples to process
bool process(int16_t *output, int16_t *input, size_t numSamples); bool process(int16_t *output, int16_t *input, size_t numSamples);
private: private:
const unsigned NUM_STAGES; const unsigned NUM_STAGES;
int32_t *m_coeffs = nullptr; int32_t *m_coeffs = nullptr;
// ARM DSP Math library filter instance // ARM DSP Math library filter instance
arm_biquad_cas_df1_32x64_ins_q31 m_iirCfg; arm_biquad_cas_df1_32x64_ins_q31 m_iirCfg;
int64_t *m_state = nullptr; int64_t *m_state = nullptr;
}; };
/**************************************************************************//**
* A single-precision floating-point biquad using CMSIS-DSP hardware instructions.
* @details Use this when IirBiQuadFilterHQ is insufficient, since that version
* is still faster with 64-bit fixed-point arithmetic.
*****************************************************************************/
class IirBiQuadFilterFloat { class IirBiQuadFilterFloat {
public: public:
IirBiQuadFilterFloat() = delete; IirBiQuadFilterFloat() = delete;
/// Construct a Biquad filter with specified number of stages and coefficients
/// @details See CMSIS-DSP documentation for more details
/// @param numStages number of biquad stages. Each stage has 5 coefficients.
/// @param coeffs pointer to an array of Q31 fixed-point coefficients (range -1 to +0.999...)
IirBiQuadFilterFloat(unsigned numStages, const float *coeffs); IirBiQuadFilterFloat(unsigned numStages, const float *coeffs);
virtual ~IirBiQuadFilterFloat(); virtual ~IirBiQuadFilterFloat();
/// Process the data using the configured IIR filter
/// @details output and input can be the same pointer if in-place modification is desired
/// @param output pointer to where the output results will be written
/// @param input pointer to where the input data will be read from
/// @param numberSampmles number of samples to process
bool process(float *output, float *input, size_t numSamples); bool process(float *output, float *input, size_t numSamples);
private: private:
const unsigned NUM_STAGES; const unsigned NUM_STAGES;
@ -215,132 +257,6 @@ private:
}; };
///**************************************************************************//**
// * Customer RingBuffer with random access
// *****************************************************************************/
//template <class T>
//class RingBuffer {
//public:
// RingBuffer() = delete;
//
// /// Construct a RingBuffer of specified max size
// /// @param maxSize number of entries in ring buffer
// RingBuffer(const size_t maxSize) : m_maxSize(maxSize) {
// m_buffer = new T[maxSize]();
// }
// virtual ~RingBuffer(){
// if (m_buffer) delete [] m_buffer;
// }
//
// /// Add an element to the back of the queue
// /// @param element element to add to queue
// /// returns 0 if success, otherwise error
// 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");
// return -1;
// }
//
// m_buffer[m_head] = element;
// if (m_head < (m_maxSize-1) ) {
// m_head++;
// } else {
// m_head = 0;
// }
// m_size++;
//
// return 0;
// }
//
// /// Remove the element at teh front of the queue
// /// @returns 0 if success, otherwise error
// 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--;
// //Serial.println(String("RingBuffer::pop_front: ") + m_head + String(":") + m_tail + String(":") + m_size);
// return 0;
// }
//
// /// Get the element at the front of the queue
// /// @returns element at front of queue
// T front() const {
// return m_buffer[m_tail];
// }
//
// /// get the element at the back of the queue
// /// @returns element at the back of the queue
// T back() const {
// return m_buffer[m_head-1];
// }
//
// /// Get a previously pushed elememt
// /// @param offset zero is last pushed, 1 is second last, etc.
// /// @returns the absolute index corresponding to the requested offset.
// 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);
//
// if ( idx >= m_maxSize) {
// idx -= m_maxSize;
// }
//
// return idx;
// }
//
// /// get the current size of the queue
// /// @returns size of the queue
// size_t size() const {
// return m_size;
// }
//
// /// get the maximum size the queue can hold
// /// @returns maximum size of the queue
// size_t max_size() const {
// return m_maxSize;
// }
//
// /// get the element at the specified absolute index
// /// @param index element to retrieve from absolute queue position
// /// @returns the request element
// T& operator[] (size_t index) {
// return m_buffer[index];
// }
//
// /// get the element at the specified absolute index
// /// @param index element to retrieve from absolute queue position
// /// @returns the request element
// T at(size_t index) const {
// return m_buffer[index];
// }
//
// /// DEBUG: Prints the status of the Ringbuffer. NOte using this much printing will usually cause audio glitches
// void print() const {
// for (int idx=0; idx<m_maxSize; idx++) {
// Serial.print(idx + String(" address: ")); Serial.print((uint32_t)m_buffer[idx], HEX);
// Serial.print(" data: "); Serial.println((uint32_t)m_buffer[idx]->data, HEX);
// }
// }
//private:
// size_t m_head=0; ///< back of the queue
// size_t m_tail=0; ///< front of the queue
// size_t m_size=0; ///< current size of the qeueu
// T *m_buffer = nullptr; ///< pointer to the allocated buffer array
// const size_t m_maxSize; ///< maximum size of the queue
//};
} }

@ -44,13 +44,13 @@ bool ExtMemSlot::setWritePosition(size_t offsetBytes)
} else { return false; } } else { return false; }
} }
bool ExtMemSlot::write16(size_t offsetBytes, int16_t *dest, size_t numWords) bool ExtMemSlot::write16(size_t offsetWords, int16_t *src, size_t numWords)
{ {
if (!m_valid) { return false; } if (!m_valid) { return false; }
size_t writeStart = m_start + offsetBytes; // 2x because int16 is two bytes per data size_t writeStart = m_start + sizeof(int16_t)*offsetWords; // 2x because int16 is two bytes per data
size_t numBytes = sizeof(int16_t)*numWords; size_t numBytes = sizeof(int16_t)*numWords;
if ((writeStart + numBytes-1) <= m_end) { if ((writeStart + numBytes-1) <= m_end) {
m_spi->write16(writeStart, reinterpret_cast<uint16_t*>(dest), numWords); // cast audio data to uint m_spi->write16(writeStart, reinterpret_cast<uint16_t*>(src), 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
@ -68,10 +68,10 @@ bool ExtMemSlot::setReadPosition(size_t offsetBytes)
} }
} }
bool ExtMemSlot::zero16(size_t offsetBytes, size_t numWords) bool ExtMemSlot::zero16(size_t offsetWords, size_t numWords)
{ {
if (!m_valid) { return false; } if (!m_valid) { return false; }
size_t writeStart = m_start + offsetBytes; size_t writeStart = m_start + sizeof(int16_t)*offsetWords;
size_t numBytes = sizeof(int16_t)*numWords; size_t numBytes = sizeof(int16_t)*numWords;
if ((writeStart + numBytes-1) <= m_end) { if ((writeStart + numBytes-1) <= m_end) {
m_spi->zero16(writeStart, numWords); // cast audio data to uint m_spi->zero16(writeStart, numWords); // cast audio data to uint
@ -82,10 +82,10 @@ bool ExtMemSlot::zero16(size_t offsetBytes, size_t numWords)
} }
} }
bool ExtMemSlot::read16(int16_t *dest, size_t offsetBytes, size_t numWords) bool ExtMemSlot::read16(size_t offsetWords, int16_t *dest, size_t numWords)
{ {
if (!dest) return false; // invalid destination if (!dest) return false; // invalid destination
size_t readOffset = m_start + offsetBytes; size_t readOffset = m_start + sizeof(int16_t)*offsetWords;
size_t numBytes = sizeof(int16_t)*numWords; size_t numBytes = sizeof(int16_t)*numWords;
if ((readOffset + numBytes-1) <= m_end) { if ((readOffset + numBytes-1) <= m_end) {

@ -81,24 +81,24 @@ public:
size_t getReadPosition() const { return m_currentRdPosition-m_start; } size_t getReadPosition() const { return m_currentRdPosition-m_start; }
/// Write a block of 16-bit data to the memory at the specified offset /// Write a block of 16-bit data to the memory at the specified offset
/// @param offsetBytes offset in bytes from start of slot /// @param offsetWords offset in 16-bit words from start of slot
/// @param dataPtr pointer to start of block of 16-bit data /// @param src pointer to start of block of 16-bit data
/// @param numWords number of 16-bit words to transfer /// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error /// @returns true on success, else false on error
bool write16(size_t offsetBytes, int16_t *dest, size_t numWords); bool write16(size_t offsetWords, int16_t *src, size_t numWords);
/// Write a block of zeros (16-bit) to the memory at the specified offset /// Write a block of zeros (16-bit) to the memory at the specified offset
/// @param offsetBytes offset in bytes from start of slot /// @param offsetWords offset in 16-bit words from start of slot
/// @param numWords number of 16-bit words to transfer /// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error /// @returns true on success, else false on error
bool zero16(size_t offsetBytes, size_t numWords); bool zero16(size_t offsetWords, size_t numWords);
/// Read a block of 16-bit data from the memory at the specified location /// Read a block of 16-bit data from the memory at the specified location
/// @param offsetWords offset in 16-bit words from start of slot
/// @param dest pointer to destination for the read data /// @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 /// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error /// @returns true on success, else false on error
bool read16(int16_t *dest, size_t offsetBytes, size_t numWords); bool read16(size_t offsetWords, int16_t *dest, size_t numWords);
/// Read the next in memory during circular operation /// Read the next in memory during circular operation
/// @returns the next 16-bit data word in memory /// @returns the next 16-bit data word in memory
@ -188,7 +188,7 @@ public:
/// @param slot a pointer to the global slot object to which memory will be allocated /// @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 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 /// @param mem specify which external memory to allocate from
/// @param dmaBufferSize When > 0, DMA mode is used with the specified DMA buffer size /// @param useDma when true, DMA is used for SPI port, else transfers block until complete
/// @returns true on success, otherwise false on error /// @returns true on success, otherwise false on error
bool requestMemory(ExtMemSlot *slot, float delayMilliseconds, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, bool useDma = false); bool requestMemory(ExtMemSlot *slot, float delayMilliseconds, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, bool useDma = false);
@ -196,7 +196,7 @@ public:
/// @param slot a pointer to the global slot object to which memory will be allocated /// @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 sizeBytes request the amount of memory in bytes to request
/// @param mem specify which external memory to allocate from /// @param mem specify which external memory to allocate from
/// @param dmaBufferSize When > 0, DMA mode is used with the specified DMA buffer size /// @param useDma when true, DMA is used for SPI port, else transfers block until complete
/// @returns true on success, otherwise false on error /// @returns true on success, otherwise false on error
bool requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, bool useDma = false); bool requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, bool useDma = false);

Loading…
Cancel
Save