Skip to content

Instantly share code, notes, and snippets.

@cstroie
Last active May 3, 2018 10:50
Show Gist options
  • Save cstroie/8b4d1c873728a419b292cc4869ff287b to your computer and use it in GitHub Desktop.
Save cstroie/8b4d1c873728a419b292cc4869ff287b to your computer and use it in GitHub Desktop.
Chebyshev 3kHz LPF (http://www.micromodeler.com/dsp/)
/******************************* 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 "lpf.h"
#include <stdlib.h> // For malloc/free
#include <string.h> // For memset
signed char filter1_coefficients[5] =
{
// Scaled for a 8x8:16 Direct form 2 IIR filter with:
// Output shift = 7
// Input shift = 6
// Central shift = 6
// Input has a maximum value of 1, scaled by 2^7
// Output has a maximum value of 1.7569804453843585, scaled by 2^6
40, 80, 40, -70, -27// b0 Q6(0.623), b1 Q6(1.25), b2 Q6(0.623), a1 Q6(-1.10), a2 Q6(-0.416)
};
filter1Type *filter1_create( void )
{
filter1Type *result = (filter1Type *)malloc( sizeof( filter1Type ) ); // Allocate memory for the object
filter1_init( result ); // Initialize it
return result; // Return the result
}
void filter1_destroy( filter1Type *pObject )
{
free( pObject );
}
void filter1_init( filter1Type * pThis )
{
filter1_reset( pThis );
}
void filter1_reset( filter1Type * pThis )
{
memset( &pThis->state, 0, sizeof( pThis->state ) ); // Reset state to 0
pThis->output = 0; // Reset output
}
int filter1_filterBlock( filter1Type * pThis, signed char * pInput, signed char * pOutput, unsigned int count )
{
filter1_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 = filter1_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.
filter1_filterBiquad_6_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 filter1_filterBiquad_6_6_7( filter1_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 << 6;
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;
}
/******************************* 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, lpf.h
#ifndef FILTER1_H_ // Include guards
#define FILTER1_H_
static const int filter1_numStages = 1;
static const int filter1_coefficientLength = 5;
extern signed char filter1_coefficients[5];
typedef struct
{
signed char state[4];
signed char output;
} filter1Type;
typedef struct
{
signed char *pInput;
signed char *pOutput;
signed char *pState;
signed char *pCoefficients;
short count;
} filter1_executionState;
filter1Type *filter1_create( void );
void filter1_destroy( filter1Type *pObject );
void filter1_init( filter1Type * pThis );
void filter1_reset( filter1Type * pThis );
#define filter1_writeInput( pThis, input ) \
filter1_filterBlock( pThis, &input, &pThis->output, 1 );
#define filter1_readOutput( pThis ) \
pThis->output
int filter1_filterBlock( filter1Type * pThis, signed char * pInput, signed char * pOutput, unsigned int count );
#define filter1_outputToFloat( output ) \
(( (1.0f/64) * (output) ))
#define filter1_inputFromFloat( input ) \
((signed char)(128f * (input)))
void filter1_filterBiquad_6_6_7( filter1_executionState * pExecState );
#endif // FILTER1_H_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment