// Generated by Fiview 0.9.6 . // All generated example code below is in the public domain. // Filter 1 // File: -i #1 // Guessed type: low-pass // // Frequency-response: // Peak gain: 1 // Guessed 100% gain: 1 // Regions between 50% (~-3dB) points: // 0Hz -> 399.999Hz (width 399.999Hz) // // Time-response: // Sampling rate is 44100Hz // 50% complete after 93 samples (0.00210884s) // 90% complete after 188 samples (0.00426304s) // 95% complete after 240 samples (0.00544218s) // 99% complete after 362 samples (0.00820862s) // 99.9% complete after 539 samples (0.0122222s) // 99.99% complete after 713 samples (0.0161678s) // Impulse response max deviation is at 85 samples (0.00192744s) // Impulse response ranges between -0.00502356 and 0.0184639 // // Original filter: // x 2.79983909751628e-10 // / 1 -1.9707804094591 0.973448617519361 // x 1 2 1 // / 1 -1.92648253911252 0.929090772994968 // x 1 2 1 // / 1 -1.90180230061198 0.90437712031445 // x 1 2 1 (LpBu6/=400) // // Filter descriptions: // LpBu6/=400 == Lowpass Butterworth filter, order 6, -3dB frequency 400 // // Example code (readable version) double process(register double val) { static double buf[6]; register double tmp, fir, iir; tmp= buf[0]; memmove(buf, buf+1, 5*sizeof(double)); val *= 2.799839097516281e-10; iir= val+1.970780409459098*buf[0]-0.9734486175193613*tmp; fir= iir+buf[0]+buf[0]+tmp; tmp= buf[1]; buf[1]= iir; val= fir; iir= val+1.926482539112519*buf[2]-0.9290907729949677*tmp; fir= iir+buf[2]+buf[2]+tmp; tmp= buf[3]; buf[3]= iir; val= fir; iir= val+1.901802300611979*buf[4]-0.9043771203144505*tmp; fir= iir+buf[4]+buf[4]+tmp; buf[5]= iir; val= fir; return val; } // Example code (functionally the same as the above code, but // optimised for cleaner compilation to efficient machine code) double process(register double val) { static double buf[6]; register double tmp, fir, iir; tmp= buf[0]; memmove(buf, buf+1, 5*sizeof(double)); iir= val * 2.799839097516281e-10; iir -= 0.9734486175193613*tmp; fir= tmp; iir -= -1.970780409459098*buf[0]; fir += buf[0]+buf[0]; fir += iir; tmp= buf[1]; buf[1]= iir; val= fir; iir= val; iir -= 0.9290907729949677*tmp; fir= tmp; iir -= -1.926482539112519*buf[2]; fir += buf[2]+buf[2]; fir += iir; tmp= buf[3]; buf[3]= iir; val= fir; iir= val; iir -= 0.9043771203144505*tmp; fir= tmp; iir -= -1.901802300611979*buf[4]; fir += buf[4]+buf[4]; fir += iir; buf[5]= iir; val= fir; return val; } // Example code for generating any of this class of filters at run-time double coef[7], buf[6]; void setup(double *coef) { coef[0]= 1 * fid_design_coef(coef+1, 6, "LpBu6", 44100, 400, 0, 1); } double process(double *coef, double *buf, register double val) { register double tmp, fir, iir; tmp= buf[0]; memmove(buf, buf+1, 5*sizeof(double)); iir= val * coef[0]; iir -= coef[1]*tmp; fir= tmp; iir -= coef[2]*buf[0]; fir += buf[0]+buf[0]; fir += iir; tmp= buf[1]; buf[1]= iir; val= fir; iir= val; iir -= coef[3]*tmp; fir= tmp; iir -= coef[4]*buf[2]; fir += buf[2]+buf[2]; fir += iir; tmp= buf[3]; buf[3]= iir; val= fir; iir= val; iir -= coef[5]*tmp; fir= tmp; iir -= coef[6]*buf[4]; fir += buf[4]+buf[4]; fir += iir; buf[5]= iir; val= fir; return val; } // Example using direct fidlib calls, and using the fidlib run-filter // code for execution, for maximum flexibility. #include "fidlib/fidlib.h" // May need adjusting FidFilter * setup() { FidFilter *filt0= fid_design("LpBu6", 44100, 400, 0, 1, 0); return filt0; } // // Run a couple of instances using fidlib: // // FidFilter *filt= setup(); // FidFunc *funcp; // FidRun *run= fid_run_new(filt, &funcp); // void *fbuf1= fid_run_newbuf(run); // void *fbuf2= fid_run_newbuf(run); // while (...) { // out_1= funcp(fbuf1, in_1); // out_2= funcp(fbuf2, in_2); // if (restart_required) fid_run_zapbuf(fbuf1); // ... // } // fid_run_freebuf(fbuf2); // fid_run_freebuf(fbuf1); // fid_run_free(run); // // Or check the frequency response: // resp= fid_response(filt, freq/rate); // // Example code using combined stages. WARNING: combined stages are // less accurate, and can also be unstable for high-order filters. double process(register double val) { static double buf[6]; register double tmp, fir, iir; tmp= buf[0]; memmove(buf, buf+1, 5*sizeof(double)); val *= 1; iir= val+5.799065249183596*buf[4]-14.01541419976008*buf[3] +18.06973832855442*buf[2]-13.10743510148092*buf[1] +5.07198438572536*buf[0]-0.8179386801413434*tmp; fir= 2.799839097516281e-10*iir+1.679903458509768e-09*buf[4] +4.199758646274421e-09*buf[3]+5.599678195032561e-09*buf[2] +4.199758646274421e-09*buf[1]+1.679903458509768e-09*buf[0] +2.799839097516281e-10*tmp; buf[5]= iir; val= fir; return val; } // Notes on use of example code: // ---------------------------- // // The example code above should be easy to adapt to your application. // It is designed to be readable, and any unnecessary assignments used // for readability's sake should optimise away on any decent compiler. // memmove() is used for shifting the buffer. This was found to be // faster than all other portable alternatives on GCC for ix86, // including copying longs. Copying doubles is slowest of all due to // conversion to/from the FPU's internal 80-bit format. // // The compilation-optimised version reorders the calculations into an // order that minimises the number of values the compiler has to // remember at any one time, giving us a better chance of decent code. // I dare say it could all be squeezed more, but you'd need to do // benchmarking to be sure that you are getting a real gain. Many // 'obvious' speed-up changes I tried actually slowed the code down -- // the behaviour of modern processors seems quite hard to predict in // this regard. // // Note that the code for handling runtime generated filters receives // clues from the filter-design code about which values are constant // and which vary, but it can't easily pick up other patterns within // the coefficients. So, perhaps this also leaves some room for // optimisation if squeezing out every last bit of performance is // important for your application. // // For generating filters at runtime, call setup(coef) first to // generate the coefficients, then use val= process(coef, buf, val) // for each sample. Zero the buf[] to reinitialise the filter at any // time. This should be easy to adapt to create banks or arrays of // similar filters. Within setup() you can safely change any of the // frequencies (including the sampling rate), but not the spec-string. // // To use the example code that generates filters at runtime, you will // also need the following extern declaration as a minimum: extern double fid_design_coef(double *coef, int n_coef, char *spec, double rate, double freq0, double freq1, int adj); // Alternatively you could #include the fidlib.h file. You will also // need to link with the fidlib.o object file. Probably it is easiest // just to copy the fidlib directory into your own application and // build it as part of it. // // The most general solution, using fidlib for both creating and // running the filters, has the advantage of flexibility (all the // filter parameters can be changed), with the cost of slightly lower // performance and memory efficiency. // // Remember that the fidlib code is covered under the LGPL, and this // means that you need to abide by the terms of the LGPL if you link // your application with the fidlib.o object or any other fidlib code // (which is needed if you use anything other than the hard-coded // example routines above). For one thing, this means that you need // to make the fidlib source available when you distribute your // completed app, including any changes to fidlib you may have made. // However, the LGPL doesn't stop you keeping your own (separate) // source code closed (more notes at http://uazu.net/license/). See // the COPYING_LIB file for full details of the license. // // Note that none of this code comes with any kind of legal warranty // for correctness or whatever. As Dr Tony Fisher put it on his page: // "Don't blame me if your aircraft falls out of the sky!"