Skip to content

Instantly share code, notes, and snippets.

@cstroie
Created May 3, 2018 11:01
Show Gist options
  • Save cstroie/42c42d75923bc5a76d245a94d49322e2 to your computer and use it in GitHub Desktop.
Save cstroie/42c42d75923bc5a76d245a94d49322e2 to your computer and use it in GitHub Desktop.
/******************************* SOURCE LICENSE *********************************
Copyright (c) 2018 MicroModeler.
A non-exclusive, nontransferable, perpetual, royalty-free license is granted to the Licensee to
use the following Information for academic, non-profit, or government-sponsored research purposes.
Use of the following Information under this License is restricted to NON-COMMERCIAL PURPOSES ONLY.
Commercial use of the following Information requires a separately executed written license agreement.
This Information is distributed WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
******************************* END OF LICENSE *********************************/
// A commercial license for MicroModeler DSP can be obtained at http://www.micromodeler.com/launch.jsp
// Begin header file, bpfic.h
#ifndef BPFIC_H_ // Include guards
#define BPFIC_H_
static const int bpfic_numStages = 1;
static const int bpfic_coefficientLength = 5;
extern signed char bpfic_coefficients[5];
typedef struct
{
signed char state[4];
signed char output;
} bpficType;
typedef struct
{
signed char *pInput;
signed char *pOutput;
signed char *pState;
signed char *pCoefficients;
short count;
} bpfic_executionState;
bpficType *bpfic_create( void );
void bpfic_destroy( bpficType *pObject );
void bpfic_init( bpficType * pThis );
void bpfic_reset( bpficType * pThis );
#define bpfic_writeInput( pThis, input ) \
bpfic_filterBlock( pThis, &input, &pThis->output, 1 );
#define bpfic_readOutput( pThis ) \
pThis->output
int bpfic_filterBlock( bpficType * pThis, signed char * pInput, signed char * pOutput, unsigned int count );
#define bpfic_outputToFloat( output ) \
(( (1.0f/64) * (output) ))
#define bpfic_inputFromFloat( input ) \
((signed char)(128f * (input)))
void bpfic_filterBiquad_2_6_7( bpfic_executionState * pExecState );
#endif // BPFIC_H_
/******************************* SOURCE LICENSE *********************************
Copyright (c) 2018 MicroModeler.
A non-exclusive, nontransferable, perpetual, royalty-free license is granted to the Licensee to
use the following Information for academic, non-profit, or government-sponsored research purposes.
Use of the following Information under this License is restricted to NON-COMMERCIAL PURPOSES ONLY.
Commercial use of the following Information requires a separately executed written license agreement.
This Information is distributed WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
******************************* END OF LICENSE *********************************/
// A commercial license for MicroModeler DSP can be obtained at http://www.micromodeler.com/launch.jsp
#include "bpfic.h"
#include <stdlib.h> // For malloc/free
#include <string.h> // For memset
signed char bpfic_coefficients[5] =
{
// Scaled for a 8x8:16 Direct form 2 IIR filter with:
// Output shift = 7
// Input shift = 2
// Central shift = 6
// Input has a maximum value of 1, scaled by 2^7
// Output has a maximum value of 1.271437815229513, scaled by 2^6
74, 0, -74, 19, -55// b0 Q10(0.0727), b1 Q10(0.00), b2 Q10(-0.0727), a1 Q6(0.296), a2 Q6(-0.855)
};
bpficType *bpfic_create( void )
{
bpficType *result = (bpficType *)malloc( sizeof( bpficType ) ); // Allocate memory for the object
bpfic_init( result ); // Initialize it
return result; // Return the result
}
void bpfic_destroy( bpficType *pObject )
{
free( pObject );
}
void bpfic_init( bpficType * pThis )
{
bpfic_reset( pThis );
}
void bpfic_reset( bpficType * pThis )
{
memset( &pThis->state, 0, sizeof( pThis->state ) ); // Reset state to 0
pThis->output = 0; // Reset output
}
int bpfic_filterBlock( bpficType * pThis, signed char * pInput, signed char * pOutput, unsigned int count )
{
bpfic_executionState executionState; // The executionState structure holds call data, minimizing stack reads and writes
if( ! count ) return 0; // If there are no input samples, return immediately
executionState.pInput = pInput; // Pointers to the input and output buffers that each call to filterBiquad() will use
executionState.pOutput = pOutput; // - pInput and pOutput can be equal, allowing reuse of the same memory.
executionState.count = count; // The number of samples to be processed
executionState.pState = pThis->state; // Pointer to the biquad's internal state and coefficients.
executionState.pCoefficients = bpfic_coefficients; // Each call to filterBiquad() will advance pState and pCoefficients to the next biquad
// The 1st call to filter1_filterBiquad() reads from the caller supplied input buffer and writes to the output buffer.
// The remaining calls to filterBiquad() recycle the same output buffer, so that multiple intermediate buffers are not required.
bpfic_filterBiquad_2_6_7( &executionState ); // Run biquad #0
executionState.pInput = executionState.pOutput; // The remaining biquads will now re-use the same output buffer.
// At this point, the caller-supplied output buffer will contain the filtered samples and the input buffer will contain the unmodified input samples.
return count; // Return the number of samples processed, the same as the number of input samples
}
void bpfic_filterBiquad_2_6_7( bpfic_executionState * pExecState )
{
// Read state variables
signed char w0, x0;
signed char w1 = pExecState->pState[0];
signed char w2 = pExecState->pState[1];
// Read coefficients into work registers
signed char b0 = *(pExecState->pCoefficients++);
signed char b1 = *(pExecState->pCoefficients++);
signed char b2 = *(pExecState->pCoefficients++);
signed char a1 = *(pExecState->pCoefficients++);
signed char a2 = *(pExecState->pCoefficients++);
// Read source and target pointers
signed char *pInput = pExecState->pInput;
signed char *pOutput = pExecState->pOutput;
short count = pExecState->count;
short accumulator;
// Loop for all samples in the input buffer
while( count-- )
{
// Read input sample
x0 = *(pInput++);
// Run feedback part of filter
accumulator = (short)w2 * a2;
accumulator += (short)w1 * a1;
accumulator += (short)x0 << 2;
w0 = accumulator >> 6;
// Run feedforward part of filter
accumulator = (short)w0 * b0;
accumulator += (short)w1 * b1;
accumulator += (short)w2 * b2;
w2 = w1; // Shuffle history buffer
w1 = w0;
// Write output
*(pOutput++) = accumulator >> 7;
}
// Write state variables
*(pExecState->pState++) = w1;
*(pExecState->pState++) = w2;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment