Born2bwire
25+ Member ;-)
- Joined
- Nov 11, 2001
- Posts
- 3,700
- Likes
- 14
I thought it would be interesting if I put this in a new thread. I have been making a few impulse responses in Matlab to play around with in the convolver feature for Foobar. Matlab presents an ideal environment for people to make their filters because it allows you to build filters and easily generate the impulse responses. Even more importantly, you can go beyond simple equalizers.
Just a quick run through, an impulse response is the time domain output from a given filter that is fed an impulse signal. That is, if we send into our digital filter the input, h[0] = 1, then the output is our impulse response. This uniquely defines the filter and by convolving any digital stream with the impulse response we get the same output as if we ran it through the filter. It should be noted that convolution is not the always the best way to create effects. For example, an echo is marvelously inefficient using convolution. If we want to create an impulse signal in Matlab,
h=zeros(1024,1);
h(1)=.99;
wavwrite(h,44100,16,'Impulse');
This created an impulse signal of length 1024 samples. Technically, you only need one sample but this is here incase someone wants to pass the impulse through a filter of their own and get the impulse response for their own convolution filter. And if you run the impulse through the convolver, surprise, you get your original input back. Also, make sure you uncheck "Auto level adjust" to prevent clipping and to get the true output from your filter.
Let's say we want to create an echo that is 3dB down and has a .5 second delay. In Matlab we would simply do,
h = zeros(22050,1);
h(1)=.99; h(22051)=.5;
wavwrite(h,44100,16,'Echo');
We now have a superposition of the original sample and a sample that has been delayed 22050 samples, or .5 seconds. The wavwrite takes in amplitudes from [1 -1] so the amplitude of .5 for the delayed sample means that the sample is half-strengthed, or -3dB. Now if we want to create a continuing echo, for example, let’s have four echos that attenuate by -3dB every .25 seconds.
h=zeros(55125,1);
h(1)=.99; h(11026)=.5; h(22051)=.25; h(33076)=.125; h(44101)=.0625; h(55126)=.03125;
wavwrite(h,44100,16,'Echoing');
This is very inefficient since we have a convolusion of 55,125 samples for each output sample. The better way to do this would be to store registers in memory of previous samples and then just do a multiply and add to get the final output.
We can also easily create lowpass, highpass, or bandpass filters. For example, to create a 10th order Chebyshev lowpass filter with cutoff frequency of 1KHz and ripple magnitude of .5 dB,
[b,a] = cheby1(10,.5,1000/22050);
[h,t] = impz(b,a,1024,44100);
wavwrite(h,44100,16,'ChebyFilterLP');
The impz command will take in the polynomial coefficients of the numerator b and denominator a of the transfer function (H(z)) and create an impulse response of 1024 samples at a sampling rate of 44100 (in this case). So we can use the impz command to create any FIR filter that we desire.
Now let’s do something really interesting. Let’s make our own upsampler. To upsample by an integer amount, like 22.05KHz to 44.1KHz (X2), all you do is pad the file by zeros. So to upsample by two, we just add a zero inbetween each of our original samples. Now we need to run the data through an interpolation filter. If we actually look at our frequency domain after zero-padding, we actually have copies of the original sound in the upper frequency. For example, our original source occupied frequencies from DC to 11.025KHz. After zero-padding, we have a copy of the original sound that has been modulated up to occupy the 11.025KHz-22.05KHz region. So we use a filter to remove this and we can do this in our convolver. So let’s take a three second wave file, Clip22KHz.wav, upsample it to 44.1KHz, and save the unfiltered zero-padded signal. The clip is originally from a CD, which is bandlimited from 20Hz-20KHz, they leave 2.05KHz of unused bandwidth so that we can have a relaxed filter. Let us assumed that we retain an empty bandwidth of 1.025KHz after we downsampled (when the file is downsampled, the original empty bandwidth is removed, but if you were to upsample from 44.1Khz then you would be able to take advantage of it). The downsampled 22.05KHz sampled signal has an empty bandwidth of 1.025 KHz. Thus, we need to pass everything from 20Hz-10KHz and filter everything out above 12.05KHz. We can then make a filter whose transition band is between 10KHz-12KHz. So through a quick bit of trial and error, a type 2 Chebyshev filter with cut-off frequency of 12KHz, -90dB ripple, and 15 taps will allow us to have |H(z)|=1 up to 10KHz and will reach around -90dB by 12KHz.
Sample = wavread('Clip22KHz.wav');
Fs = 22050;
bits = 16;
Upsample = zeros(2*66152,2);
for n=1:66152
Upsample(2*n,: ) = Sample(n,: );
end
wavwrite(Upsample,2*Fs,16,'ClipUpsample');
[b,a] = cheby2(15,90,12000/22050);
[h,t] = impz(b,a,1024,44100);
wavwrite(2*h,44100,16,'UpsamplerLP');
To view the filter response, do,
freqz(b,a,44100,44100);
When you play back the unfiltered upsampled file, you should notice that the sound has been attenuated (by -3dB, or ½) and that it sounds distorted. If you watch the visualization in Foobar, you can see the modulated sound in the upper half of the frequency band. Now if you apply the filter, the upper frequency band is now gone and the file should play back without distortion and at the correct volume.
One other project that I have not tried out would be to create a noise reduction filter. My idea for this would be to record a second or two of tape hiss from the blank portion of a cassette tape or record. Then superimpose that on a good soundfile. Using the original soundfile as our desired output, we could use the noisy soundfile to train an adaptive filter. The converged adaptive filter could then be used to create an impulse response that can be used as a noise reducer for LP or cassette transfers. Don't know how successful this would be but I would imagine that we could effectively model hiss and rumble as white noise and thus be able to effectively filter it out.
We could also implement frequency shifting. The amount that a frequency is shifted is approximately the derivative of the phase response of the filter. So ideally, we create filters that have a linear phase shift (and thus the frequency shift is slight and constant across the band). So if you created a filter with |H(z)|=1 and a non-linear phase response, then you could create frequency shifting. I think I may have a filter response somewhere that does this. It was meant to take in a sharp impulse and return a chirp from smearing the frequencies.
You can get all of the sound samples that I used and created here:
https://netfiles.uiuc.edu/patkins/www/Impulse.wav
https://netfiles.uiuc.edu/patkins/www/Echo.wav
https://netfiles.uiuc.edu/patkins/www/Echoing.wav
https://netfiles.uiuc.edu/patkins/www/ChebyFilterLP.wav
https://netfiles.uiuc.edu/patkins/www/Clip22KHz.wav
https://netfiles.uiuc.edu/patkins/www/ClipUpsample.wav
https://netfiles.uiuc.edu/patkins/www/UpsamplerLP.wav
Just a quick run through, an impulse response is the time domain output from a given filter that is fed an impulse signal. That is, if we send into our digital filter the input, h[0] = 1, then the output is our impulse response. This uniquely defines the filter and by convolving any digital stream with the impulse response we get the same output as if we ran it through the filter. It should be noted that convolution is not the always the best way to create effects. For example, an echo is marvelously inefficient using convolution. If we want to create an impulse signal in Matlab,
h=zeros(1024,1);
h(1)=.99;
wavwrite(h,44100,16,'Impulse');
This created an impulse signal of length 1024 samples. Technically, you only need one sample but this is here incase someone wants to pass the impulse through a filter of their own and get the impulse response for their own convolution filter. And if you run the impulse through the convolver, surprise, you get your original input back. Also, make sure you uncheck "Auto level adjust" to prevent clipping and to get the true output from your filter.
Let's say we want to create an echo that is 3dB down and has a .5 second delay. In Matlab we would simply do,
h = zeros(22050,1);
h(1)=.99; h(22051)=.5;
wavwrite(h,44100,16,'Echo');
We now have a superposition of the original sample and a sample that has been delayed 22050 samples, or .5 seconds. The wavwrite takes in amplitudes from [1 -1] so the amplitude of .5 for the delayed sample means that the sample is half-strengthed, or -3dB. Now if we want to create a continuing echo, for example, let’s have four echos that attenuate by -3dB every .25 seconds.
h=zeros(55125,1);
h(1)=.99; h(11026)=.5; h(22051)=.25; h(33076)=.125; h(44101)=.0625; h(55126)=.03125;
wavwrite(h,44100,16,'Echoing');
This is very inefficient since we have a convolusion of 55,125 samples for each output sample. The better way to do this would be to store registers in memory of previous samples and then just do a multiply and add to get the final output.
We can also easily create lowpass, highpass, or bandpass filters. For example, to create a 10th order Chebyshev lowpass filter with cutoff frequency of 1KHz and ripple magnitude of .5 dB,
[b,a] = cheby1(10,.5,1000/22050);
[h,t] = impz(b,a,1024,44100);
wavwrite(h,44100,16,'ChebyFilterLP');
The impz command will take in the polynomial coefficients of the numerator b and denominator a of the transfer function (H(z)) and create an impulse response of 1024 samples at a sampling rate of 44100 (in this case). So we can use the impz command to create any FIR filter that we desire.
Now let’s do something really interesting. Let’s make our own upsampler. To upsample by an integer amount, like 22.05KHz to 44.1KHz (X2), all you do is pad the file by zeros. So to upsample by two, we just add a zero inbetween each of our original samples. Now we need to run the data through an interpolation filter. If we actually look at our frequency domain after zero-padding, we actually have copies of the original sound in the upper frequency. For example, our original source occupied frequencies from DC to 11.025KHz. After zero-padding, we have a copy of the original sound that has been modulated up to occupy the 11.025KHz-22.05KHz region. So we use a filter to remove this and we can do this in our convolver. So let’s take a three second wave file, Clip22KHz.wav, upsample it to 44.1KHz, and save the unfiltered zero-padded signal. The clip is originally from a CD, which is bandlimited from 20Hz-20KHz, they leave 2.05KHz of unused bandwidth so that we can have a relaxed filter. Let us assumed that we retain an empty bandwidth of 1.025KHz after we downsampled (when the file is downsampled, the original empty bandwidth is removed, but if you were to upsample from 44.1Khz then you would be able to take advantage of it). The downsampled 22.05KHz sampled signal has an empty bandwidth of 1.025 KHz. Thus, we need to pass everything from 20Hz-10KHz and filter everything out above 12.05KHz. We can then make a filter whose transition band is between 10KHz-12KHz. So through a quick bit of trial and error, a type 2 Chebyshev filter with cut-off frequency of 12KHz, -90dB ripple, and 15 taps will allow us to have |H(z)|=1 up to 10KHz and will reach around -90dB by 12KHz.
Sample = wavread('Clip22KHz.wav');
Fs = 22050;
bits = 16;
Upsample = zeros(2*66152,2);
for n=1:66152
Upsample(2*n,: ) = Sample(n,: );
end
wavwrite(Upsample,2*Fs,16,'ClipUpsample');
[b,a] = cheby2(15,90,12000/22050);
[h,t] = impz(b,a,1024,44100);
wavwrite(2*h,44100,16,'UpsamplerLP');
To view the filter response, do,
freqz(b,a,44100,44100);
When you play back the unfiltered upsampled file, you should notice that the sound has been attenuated (by -3dB, or ½) and that it sounds distorted. If you watch the visualization in Foobar, you can see the modulated sound in the upper half of the frequency band. Now if you apply the filter, the upper frequency band is now gone and the file should play back without distortion and at the correct volume.
One other project that I have not tried out would be to create a noise reduction filter. My idea for this would be to record a second or two of tape hiss from the blank portion of a cassette tape or record. Then superimpose that on a good soundfile. Using the original soundfile as our desired output, we could use the noisy soundfile to train an adaptive filter. The converged adaptive filter could then be used to create an impulse response that can be used as a noise reducer for LP or cassette transfers. Don't know how successful this would be but I would imagine that we could effectively model hiss and rumble as white noise and thus be able to effectively filter it out.
We could also implement frequency shifting. The amount that a frequency is shifted is approximately the derivative of the phase response of the filter. So ideally, we create filters that have a linear phase shift (and thus the frequency shift is slight and constant across the band). So if you created a filter with |H(z)|=1 and a non-linear phase response, then you could create frequency shifting. I think I may have a filter response somewhere that does this. It was meant to take in a sharp impulse and return a chirp from smearing the frequencies.
You can get all of the sound samples that I used and created here:
https://netfiles.uiuc.edu/patkins/www/Impulse.wav
https://netfiles.uiuc.edu/patkins/www/Echo.wav
https://netfiles.uiuc.edu/patkins/www/Echoing.wav
https://netfiles.uiuc.edu/patkins/www/ChebyFilterLP.wav
https://netfiles.uiuc.edu/patkins/www/Clip22KHz.wav
https://netfiles.uiuc.edu/patkins/www/ClipUpsample.wav
https://netfiles.uiuc.edu/patkins/www/UpsamplerLP.wav