You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

95 lines
3.5 KiB

* AudioFilter90Deg_F32.cpp
* 22 March 2020
* Bob Larkin, in support of the library:
* Chip Audette, OpenAudio, Apr 2017
* -------------------
* There are two channels that update synchronously, but operate
* independently. The I-channel, coresponding to a "Left"
* audio channel, is filtered with an N coefficient
* Hilbert Transform in FIR form.
* The Q-channel, or "Right" channel, is simply
* delayed by the (N-1)/2 sample periods. The phase between
* the two outputs is 90-Degrees. The amplitude response cuts off low
* frequencies and depends on N.
* The I-channel FIR is a Hilbert Transform and this has every other term 0.
* These need not be multiplied-and-accumulated, but for now, we do. By the
* time the indexes are calculated, it may be quicker to process everything.
* Additionally, to not require a half-sample delay, the number of terms in
* the Hilbert FIR needs to be odd.
* MIT License, Use at your own risk.
#include "AudioFilter90Deg_F32.h"
void AudioFilter90Deg_F32::update(void)
audio_block_f32_t *block_i, *block_q, *blockOut_i=NULL;
uint16_t i;
// Get first input, i, that will be filtered
block_i = AudioStream_F32::receiveWritable_f32(0);
if (!block_i) {
if(errorPrint) Serial.println("FIL90-ERR: No i input memory");
// Get second input, q, that will be delayed
block_q = AudioStream_F32::receiveWritable_f32(1);
if (!block_q){
if(errorPrint) Serial.println("FIL90-ERR: No q input memory");
// If there's no coefficient table, give up.
if (coeff_p == NULL) {
if(errorPrint) Serial.println("FIL90-ERR: No Hilbert FIR coefficients");
// Try to get a block for the FIR output
blockOut_i = AudioStream_F32::allocate_f32();
if (!blockOut_i){ // Didn't have any
if(errorPrint) Serial.println("FIL90-ERR: No out 0 block");
// Apply the Hilbert transform FIR. This includes multiplies by zero.
// Is there any way to play with the indexes and not multiply by zero
// without spending more time than is saved? How about something like
// pick right nn, then for(j=0; j<fir_length; j+=2) {sum += coef[j] * data[j+nn];}
arm_fir_f32(&Ph90Deg_inst, block_i->data, blockOut_i->data, block_i->length);
AudioStream_F32::release(block_i); // Not needed further
// Now enter block_size points to the delay loop and move earlier points to re-used block
float32_t *pin, *pout;
pin = &(block_q->data[0]); // point to beginning of block_q
for(i=0; i<block_size; i++) { // Let it wrap around at 256
in_index = delayBufferMask & in_index; // Index into delay buffer, wrapping
delayData[in_index] = *pin++; // Put ith q data to circular delay buffer
// And similarly, output with a delay, i.e., a buffer offset
pout = &(block_q->data[0]); // Re-use the input block
for(i=0; i<block_size; i++) {
out_index = delayBufferMask & out_index; // Index into delay buffer, wrapping
*pout++ = delayData[out_index];
//transmit the data
AudioStream_F32::transmit(blockOut_i, 0); // send the FIR outputs
AudioStream_F32::release (blockOut_i);
AudioStream_F32::transmit(block_q, 1); // and the delayed outputs
AudioStream_F32::release (block_q);