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
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");
|
|
return;
|
|
}
|
|
|
|
// 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");
|
|
AudioStream_F32::release(block_i);
|
|
return;
|
|
}
|
|
|
|
// If there's no coefficient table, give up.
|
|
if (coeff_p == NULL) {
|
|
if(errorPrint) Serial.println("FIL90-ERR: No Hilbert FIR coefficients");
|
|
AudioStream_F32::release(block_i);
|
|
AudioStream_F32::release(block_q);
|
|
return;
|
|
}
|
|
|
|
// 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");
|
|
AudioStream_F32::release(block_i);
|
|
AudioStream_F32::release(block_q);
|
|
return;
|
|
}
|
|
|
|
// 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++;
|
|
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++;
|
|
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);
|
|
}
|
|
|
|
|