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