DSPRelated.com
Forums

Open source generalized, audio range boxcar filter.

Started by Les Cargill October 31, 2009
What I'd like to do is have C++ source that contains a function
similar to this:

#typedef some_type VECTOR; // arrays of floats muy bueno...
#typedef FREQUENCY unsigned int;
#typedef ERRCODE int; // an enum, really
#define IN
#define OUT

ERRCODE boxcar(IN VECTOR *before, INOUT VECTOR *after, IN FREQUENCY 
hipass, IN FREQUENCY lowpass);

where:

   - hipass is always < lowpass, and
   - "after" must accept an equal number of elements to "before";

The application is pulse shaping of audio data to convert the
shaped pulses into sets of MIDI note on/note off events. I can
do this with COTS audio editors very easily, but I want an
"inline" solution. This will not be in-real-time, it will
be purely batch operation against .wav files on a Windows platform.

Dev tools are not Microsoft. I would rather use MingW.

If it is just a matter of translating the moment-generating function
how does that work?

--
Les Cargill
Les Cargill wrote:
> > What I'd like to do is have C++ source that contains a function > similar to this: > > #typedef some_type VECTOR; // arrays of floats muy bueno... > #typedef FREQUENCY unsigned int; > #typedef ERRCODE int; // an enum, really > #define IN > #define OUT > > ERRCODE boxcar(IN VECTOR *before, INOUT VECTOR *after, IN FREQUENCY > hipass, IN FREQUENCY lowpass); > > where: > > - hipass is always < lowpass, and > - "after" must accept an equal number of elements to "before"; > > The application is pulse shaping of audio data to convert the > shaped pulses into sets of MIDI note on/note off events. I can > do this with COTS audio editors very easily, but I want an > "inline" solution. This will not be in-real-time, it will > be purely batch operation against .wav files on a Windows platform. > > Dev tools are not Microsoft. I would rather use MingW. > > If it is just a matter of translating the moment-generating function > how does that work? > > -- > Les Cargill
Well, of course I found... a comp.dsp post ... containing this... "... An example of a recursive FIR filter is the "boxcar" filter, which just averages over a number of samples (y is output, x is input): y[n] = 1/N (x[n] + x[n-1] + ... + x[n-(N-1)] ). Its recursive form is y[n] = y[n-1] + 1/N (x[n] - x[n-N])." How does "N" relate to frequency, presumably relative to Fs? Is this "one end" of the boxcar? Or gee... I could actually... uh... just try it. But any wielding clue-sticks gratefully invited to whack my pointed head... -- Les Cargill
Les Cargill wrote:
> Les Cargill wrote: >> >> What I'd like to do is have C++ source that contains a function >> similar to this: >> >> #typedef some_type VECTOR; // arrays of floats muy bueno... >> #typedef FREQUENCY unsigned int; >> #typedef ERRCODE int; // an enum, really >> #define IN >> #define OUT >> >> ERRCODE boxcar(IN VECTOR *before, INOUT VECTOR *after, IN FREQUENCY >> hipass, IN FREQUENCY lowpass); >> >> where: >> >> - hipass is always < lowpass, and >> - "after" must accept an equal number of elements to "before"; >> >> The application is pulse shaping of audio data to convert the >> shaped pulses into sets of MIDI note on/note off events. I can >> do this with COTS audio editors very easily, but I want an >> "inline" solution. This will not be in-real-time, it will >> be purely batch operation against .wav files on a Windows platform. >> >> Dev tools are not Microsoft. I would rather use MingW. >> >> If it is just a matter of translating the moment-generating function >> how does that work? >> >> -- >> Les Cargill > > > Well, of course I found... a comp.dsp post ... containing > this... > > "... An example of a recursive FIR filter is the "boxcar" > filter, which just averages over a number of samples (y is output, x > is input): > > y[n] = 1/N (x[n] + x[n-1] + ... + x[n-(N-1)] ). > > Its recursive form is > > y[n] = y[n-1] + 1/N (x[n] - x[n-N])." > > How does "N" relate to frequency, presumably relative to Fs? Is > this "one end" of the boxcar? >
It doesn't, much. An averager (which is what a "boxcar" filter is understood to be - all coefficients the same) gives you, well, the average level (amplitude) of that block. Add a sqrt(x[n...]^^2)) and you get an rms (power) measure of the block. This might be used as an envelope follower, e.g. in a (musical) compressor algorithm. It is of course a form of low-pass filter; in the limit, you are left with whatever DC content the signal has (sum all samples of N periods of a sinusoid and the result is zero, as the negative values cancel out the positive ones). N above does not directly relate to frequency, as such - it signifies the number of samples in the block (or length of filter) - you sum 1024 samples and divide the result by 1024. However, it implies the amount of lowpass filtering; clearly a short averager will reveal more HF activity than a long one. In the limit, a two-sample averager (y[n] = 0.5 * (x[n] + x[n-1])) has a frequency response the shape of the first quadrant of a cosine, i.e. kills any energy at Nyquist, passes DC unchanged. All introductory dsp textbooks will show how this works. The recursive form given above eliminates duplicated computations - rather than add the same samples together each time, you just add the newest (x[n]) and remove the oldest (x[n-N]). How this relates to your original question I don't understand. Are you trying to extract blocks of audio as mini "samples", with an envelope, to be played via MIDI? Do you want to detect discrete (successive) pitches in an audio file and separate them out (Melodyne-style)? It might be easier if you just describe what exactly you want to do, and others on this list can then tell you how that might be done, and with what. Richard Dobson
Richard's suggestion of an envelope sounds like what you're describing
rather than a high and lowpass filter. You will find code for envelope
followers and synth related stuff on musicdsp.org. They're very common
for synths and keyboards to give you an attack-sustain-release type of
thing.
Richard Dobson wrote:
> Les Cargill wrote: >> Les Cargill wrote: >>> >>> What I'd like to do is have C++ source that contains a function >>> similar to this: >>> >>> #typedef some_type VECTOR; // arrays of floats muy bueno... >>> #typedef FREQUENCY unsigned int; >>> #typedef ERRCODE int; // an enum, really >>> #define IN >>> #define OUT >>> >>> ERRCODE boxcar(IN VECTOR *before, INOUT VECTOR *after, IN FREQUENCY >>> hipass, IN FREQUENCY lowpass); >>> >>> where: >>> >>> - hipass is always < lowpass, and >>> - "after" must accept an equal number of elements to "before"; >>> >>> The application is pulse shaping of audio data to convert the >>> shaped pulses into sets of MIDI note on/note off events. I can >>> do this with COTS audio editors very easily, but I want an >>> "inline" solution. This will not be in-real-time, it will >>> be purely batch operation against .wav files on a Windows platform. >>> >>> Dev tools are not Microsoft. I would rather use MingW. >>> >>> If it is just a matter of translating the moment-generating function >>> how does that work? >>> >>> -- >>> Les Cargill >> >> >> Well, of course I found... a comp.dsp post ... containing >> this... >> >> "... An example of a recursive FIR filter is the "boxcar" >> filter, which just averages over a number of samples (y is output, x >> is input): >> >> y[n] = 1/N (x[n] + x[n-1] + ... + x[n-(N-1)] ). >> >> Its recursive form is >> >> y[n] = y[n-1] + 1/N (x[n] - x[n-N])." >> >> How does "N" relate to frequency, presumably relative to Fs? Is >> this "one end" of the boxcar? >> > > It doesn't, much. An averager (which is what a "boxcar" filter is > understood to be - all coefficients the same) gives you, well, the > average level (amplitude) of that block. Add a sqrt(x[n...]^^2)) and > you get an rms (power) measure of the block. This might be used as an > envelope follower, e.g. in a (musical) compressor algorithm. It is of > course a form of low-pass filter; in the limit, you are left with > whatever DC content the signal has (sum all samples of N periods of a > sinusoid and the result is zero, as the negative values cancel out the > positive ones). > > N above does not directly relate to frequency, as such - it signifies > the number of samples in the block (or length of filter) - you sum 1024 > samples and divide the result by 1024. However, it implies the amount of > lowpass filtering; clearly a short averager will reveal more HF activity > than a long one. In the limit, a two-sample averager (y[n] = 0.5 * (x[n] > + x[n-1])) has a frequency response the shape of the first quadrant of a > cosine, i.e. kills any energy at Nyquist, passes DC unchanged. All > introductory dsp textbooks will show how this works. > > The recursive form given above eliminates duplicated computations - > rather than add the same samples together each time, you just add the > newest (x[n]) and remove the oldest (x[n-N]). > > How this relates to your original question I don't understand. Are you > trying to extract blocks of audio as mini "samples", with an envelope, > to be played via MIDI? Do you want to detect discrete (successive) > pitches in an audio file and separate them out (Melodyne-style)? It > might be easier if you just describe what exactly you want to do, and > others on this list can then tell you how that might be done, and with > what. >
All I want to do is translate a PCM stream into pulses. No pitch information, maybe velocity ( as proportional to amplitude ). I will then write a state machine to detect the pulses and translate them into MIDI events, output in text form to a file to be consumed by TXT2MIDI. End output is a .mid file. What experiments I've done show that whipping a bandpass filter on the data pretty much does this, if you select appropriate hi and lo pass frequencies. My ignorant assumption is that I can use a boxcar filter to emulate such a bandpass filter. And yes - I could just buy Drumagog. But that's no fun... Also also - if Octave is a blindingly better choice for this, do tell... I've only run QtOctave, and am unsure of ether non-Qt Octave can be run in pipes...
> > Richard Dobson
-- Les Cargill
Fully Half Baked wrote:
> Richard's suggestion of an envelope sounds like what you're describing > rather than a high and lowpass filter. You will find code for envelope > followers and synth related stuff on musicdsp.org. They're very common > for synths and keyboards to give you an attack-sustain-release type of > thing.
I've tried a few free "drum replacer" plugins, and I think what I object to about them is that they seem to *be* envelope followers, with a triggered threshold. When I applied a low pass/high pass filter on data sets I'm trying to transform, the results were much "cleaner" - you had nice tall spikes that would be relatively easy to detect by a state machine. I know one has a "filter" window, but I didn't spend enough time with it to actually construct a bandpass filter - the idea for the boxcar filter was later, thinking about pulse shaping and all that. -- Les Cargill
Les Cargill wrote:
> Fully Half Baked wrote: >> Richard's suggestion of an envelope sounds like what you're describing >> rather than a high and lowpass filter. You will find code for envelope >> followers and synth related stuff on musicdsp.org. They're very common >> for synths and keyboards to give you an attack-sustain-release type of >> thing. > > > I've tried a few free "drum replacer" plugins, and I think > what I object to about them is that they seem to *be* envelope > followers, with a triggered threshold. When I applied a > low pass/high pass filter on data sets I'm trying to transform, > the results were much "cleaner" - you had nice tall spikes that > would be relatively easy to detect by a state machine. > > I know one has a "filter" window, but I didn't spend enough time > with it to actually construct a bandpass filter - the idea for the > boxcar filter was later, thinking about pulse shaping and all > that. > > -- > Les Cargill
Full stop - I found the mother lode! 1) I needed a Chebyshev filter 2) This gens 'C' source from a wizard. http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html -- Les Cargill
Les Cargill wrote:
..
> > Full stop - I found the mother lode! > > 1) I needed a Chebyshev filter > 2) This gens 'C' source from a wizard. > > http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html >
If you are happy to stick to a single sample rate, sure. But if not, and you find you need to ~design~ the filter as well as simply use one, the journey is not yet complete. Richard Dobson
Richard Dobson wrote:
> Les Cargill wrote: > .. >> >> Full stop - I found the mother lode! >> >> 1) I needed a Chebyshev filter >> 2) This gens 'C' source from a wizard. >> >> http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html >> > > If you are happy to stick to a single sample rate, sure. But if not, and > you find you need to ~design~ the filter as well as simply use one, the > journey is not yet complete. > > > Richard Dobson >
Excellent point. I'm not 100% sure whether I will truly need to fully generalize this or not - I don't think this productizes*, and I value my dilletante status at this writing :) I realize, of course, that what you espouse is The Right Thing to Do. *might a good open source thing - not sure. It could certainly be implemented as a VST, but I really just want the thing for myself. I also have to get that code working - it isn't as I speak. The output veers off into nAn land - I stepped on something. -- Les Cargill
Les Cargill wrote:
> Richard Dobson wrote: >> Les Cargill wrote: >> .. >>> >>> Full stop - I found the mother lode! >>> >>> 1) I needed a Chebyshev filter >>> 2) This gens 'C' source from a wizard. >>> >>> http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html >>> >> >> If you are happy to stick to a single sample rate, sure. But if not, >> and you find you need to ~design~ the filter as well as simply use >> one, the journey is not yet complete. >> >> >> Richard Dobson >> > > > Excellent point. I'm not 100% sure whether I will truly need to fully > generalize this or not - I don't think this productizes*, and I value > my dilletante status at this writing :) I realize, of course, that > what you espouse is The Right Thing to Do. > > *might a good open source thing - not sure. It could certainly > be implemented as a VST, but I really just want the thing > for myself. > > I also have to get that code working - it isn't as I speak. The output > veers off into nAn land - I stepped on something. >
Found it - I was trying for a tenth-order filter. Cumulative rounding error was causing it to go ... "nonlinear". So I first switched to doubles for intermediate passes. That got me father. Then I had it performed three fourth-order passes instead, for... twelfth-order?. It *looks* like that's what it does, but I'm not really sure. At any rate, it works now. And I promise to read up on how to design these filters from "scratch" without depending on the webpage.
> -- > Les Cargill
-- Les Cargill