After the introduction in the previous sections, you must have a preliminary understanding of St. In the subsequent sections, I will propose some important algorithms and implementations of St. First, let's talk about the implementation of digital filters. Throughout the st processing process, the bool buseaafilter value can be used to determine whether a digital filter is used only when the sound sample is resampled. This is implemented in processsamples, a member function of the ratetransposer class.
// Transposes sample rate by applying anti-alias filter to prevent folding.
// Returns amount of samples returned in the "DEST" buffer.
// The maximum amount of samples that can be returned at a time is set
// The 'set _ returnbuffer_size 'function.
Void ratetransposer: processsamples (const sampletype * SRC, uint nsamples)
{
Uint count;
Uint sizereq;
If (nsamples = 0) return;
Assert (paafilter );
// If anti-alias filter is turned off, simply transpose without applying
// The Filter
If (buseaafilter = false)
{
Sizereq = (uint) (float) nsamples/Frate + 1.0f );
Count = transpose (outputbuffer. ptrend (sizereq), SRC, nsamples );
Outputbuffer. putsamples (count );
Return;
}
// Transpose with anti-Alias Filter
If (Frate <1.0f)
{
Upsample (SRC, nsamples );
}
Else
{
Downsample (SRC, nsamples );
}
}
The following describes the implementation of the ratetransposer class member functions upsample and downsample:
// Transposes up the sample rate, causing the observed playback 'rate' of
// Sound to decrease
Void ratetransposer: upsample (const sampletype * SRC, uint nsamples)
{
Uint count, sizetemp, num;
Sizetemp = (uint) (float) nsamples/Frate + 16366f );
Count = transpose (storebuffer. ptrend (sizetemp), SRC, nsamples );
Storebuffer. putsamples (count );
Num = storebuffer. numsamples ();
Count = paafilter-> evaluate (outputbuffer. ptrend (Num ),
Storebuffer. ptrbegin (), num, (uint) numchannels );
Outputbuffer. putsamples (count );
Storebuffer. effecesamples (count );
}
And
// Transposes down the sample rate, causing the observed playback 'rate' of
// Sound to increase
Void ratetransposer: downsample (const sampletype * SRC, uint nsamples)
{
Uint count, sizetemp;
Storebuffer. putsamples (SRC, nsamples );
Assert (tempbuffer. isempty ());
Sizetemp = storebuffer. numsamples ();
Count = paafilter-> evaluate (tempbuffer. ptrend (sizetemp ),
Storebuffer. ptrbegin (), sizetemp, (uint) numchannels );
If (COUNT = 0) return;
Storebuffer. effecesamples (count );
Sizetemp = (uint) (float) nsamples/Frate + 16366f );
Count = transpose (outputbuffer. ptrend (sizetemp), tempbuffer. ptrbegin (), count );
Outputbuffer. putsamples (count );
}
The two functions are similar. upsample implements frame skipping to accelerate the playback speed. Therefore, the output data volume must be smaller than the original data volume, so you can directly process the output. As for downsample, frame insertion is required to reduce the playback speed, the output data volume is much larger than the original data, so some processing is required. Instead, the current input buffer is sent to the memory management model of the St (FIFO) until the input buffer is processed completely, to output a new buffer. It is not difficult to find that both functions use the paafilter pointer and call the Evaluate Method to Calculate the output value of the digital filter. Refer to the implementation of the aafilter class (Digital Filter) mentioned above. The cutoff frequency and filter parameters are important parts of the digital filter. Therefore, you can define these two variables first.
# Define length 33 // set the length of the filter to 33 // it must be an odd number in order to use the filter in (N-1)/2 Symmetric
Static double H [length] = {0}; // Initialize all the filter parameters as 0
Static float fcutoff = 0.0; // The initialization cutoff frequency is 0.
Compile a setrate function to calculate the cutoff frequency. For more information, see the implementation of the ratetransposer class member function void ratetransposer: setrate (float newrate, newrate is equal to the ratio of the new speed to the original speed. Then, different formulas are used to calculate the ratio, that is, the ratio of the Slow playback speed, in either case, the calculated cutoff frequency ranges from 0 ~ In the range of 0.5.
Void setrate (float newrate)
{
If (newrate> 1.0f)
Fcutoff = 0.5f/newrate;
Else
Fcutoff = 0.5f * newrate;
}
Then define a void ccoeffs (uint length, float FC) function to calculate the filter parameters. The first parameter is the filter length, and the second parameter is the cutoff frequency. The specific implementation uses the Hamming window as the window function.
Void ccoeffs (uint length, float FC)
{
Uint I = 0;
Double temp = 0, sum = 0, scalecoeff = 0;
Uint ulength = length-1;
For (I = 0; I <length; I ++)
{
Temp = I-ulength/2;
If (temp! = 0)
DH [I] = sin (2 * pI * fc * temp)/temp;
Else
DH [I] = 2 * pI * fc;
DH [I] = DH [I] * (0.54-0.46 * Cos (2 * pI * I/ulength ));
Sum + = DH [I];
}
For (I = 0; I <length; I ++)
{
DH [I] = DH [I]/sum;
}
}
With the digital filter parameters, you can filter digital signals. Set the system input to X [N], and the unit Impact Response of the digital filter to H [N]. then the system outputs y [N] = x [N] * H [N] = H [N] * X [N] = E (H [I] X [n- i]), * For convolution, e is the accumulation of H [I] X [n-I] from 0 to L, I = [0, L], and L is the length of the filter. Assume that the system processes 16-bit dual-channel audio data. The function is written as follows: SRC is the first address of the input data, DEST is the first address of the output data, samples is the number of incoming samples, and length is the length of the digital filter,
Uint evaluatestereo (short * DEST, short * SRC, uint samples, uint length)
{
Uint I = 0, j = 0;
Long suml = 0, sumr = 0;
Uint ulength = 2 * (samples-length );
Short * pdest = DEST;
For (j = 2 * (length-1); j <ulength; j + = 2)
{
Suml = sumr = 0;
For (I = 0; I <length; I ++)
{
Suml + = SRC [J-2 * I + 0] * H [I];
Sumr + = SRC [J-2 * I + 1] * H [I];
}
Pdest [0] = (short) suml;
Pdest [1] = (short) sumr;
Pdest ++;
}
Return samples-length;
}
The complete example is as follows:
// Filter 16-bit PCM encoded wav files.
// Author: Walnut
# Include <stdio. h>
# Include <stdlib. h>
# Include <math. h>
# Define PI 3.1415926
# Define length 33
# Ifndef uint
Typedef unsigned int uint;
# Endif
Typedef struct
{
Char riff_char [4];
Int package_len;
Char wave [4];
} Wavriff;
Typedef struct
{
Char FMT [4];
Int format_len;
Short fixed;
Short channel_number;
Int sample_rate;
Int byte_rate;
Short byte_per_sample;
Short bits_per_sample;
} Wavformat;
Typedef struct
{
Char data_field [4];
Uint data_len;
} Wavdata;
Typedef struct
{
Wavriff riff;
Wavformat format;
Wavdata data;
} Wavheader;
Static double H [length] = {0 };
Static float fcutoff = 0.0;
Short inbuffer [4096];
Short outbuffer [4096];
Void ccoeffs (uint length, float FC );
Void setrate (float newrate );
Uint evaluatestereo (short * DEST, short * SRC, uint samples, uint length );
Void setrate (float newrate)
{
If (newrate> 1.0f)
Fcutoff = 0.5f/newrate;
Else
Fcutoff = 0.5f * newrate;
}
Void ccoeffs (uint length, float FC)
{
Uint I = 0;
Double temp = 0, sum = 0;
Uint ulength = length-1;
For (I = 0; I <length; I ++)
{
Temp = I-ulength/2;
If (temp! = 0)
H [I] = sin (2 * pI * fc * temp)/temp;
Else
H [I] = 2 * pI * fc;
H [I] = H [I] * (0.54-0.46 * Cos (2 * pI * I/ulength ));
Sum + = H [I];
}
For (I = 0; I <length; I ++)
{
H [I] = H [I]/sum;
}
}
Uint evaluatestereo (short * DEST, short * SRC, uint samples, uint length)
{
Uint I = 0, j = 0;
Long suml = 0, sumr = 0;
Uint ulength = 2 * (samples-length );
Short * pdest = DEST;
For (j = 2 * (length-1); j <ulength; j + = 2)
{
Suml = sumr = 0;
For (I = 0; I <length; I ++)
{
Suml + = SRC [J-2 * I + 0] * H [I];
Sumr + = SRC [J-2 * I + 1] * H [I];
}
Pdest [0] = (short) suml;
Pdest [1] = (short) sumr;
Pdest ++;
}
Return samples-length;
}
Int main (INT Arg, char ** argc)
{
File * pin = NULL, * pout = NULL;
Short * pinbuffer = NULL;
Wavheader * wheader = NULL;
Uint isamples = 0, numbytes = 0, totalbytes = 0;
If (ARG <3)
{
Printf ("Usage: % s input.wav output.wav/N", argc [0]);
Return-1;
}
Wheader = (wavheader *) malloc (sizeof (wavheader ));
Setrate (0.5f );
Ccoeffs (length, fcutoff );
# If 0
For (uint I = 0; I <length; I ++)
{
Printf ("H [% d] % F/R/N", I, H [I]);
}
# Endif
Pin = fopen (argc [1], "rb ");
Pout = fopen (argc [2], "WB ");
Numbytes = fread (wheader, 1, sizeof (wavheader), pin );
Fwrite (wheader, 1, sizeof (wavheader), pout );
While (! Feof (PIN ))
{
Numbytes = fread (inbuffer, 1,4096, pin );
Numbytes = numbytes> 2;
If (numbytes <length)
Break;
Isamples = evaluatestereo (outbuffer, inbuffer, numbytes, length );
Isamples = isamples <2;
Fwrite (outbuffer, 1, isamples, pout );
Totalbytes + = isamples;
}
Fseek (pout, 0, seek_set );
Wheader-> data. data_len = totalbytes;
Wheader-> riff. package_len = totalbytes + sizeof (wavheader)-4 * sizeof (char)-sizeof (INT );
Fwrite (wheader, 1, sizeof (wavheader), pout );
Free (wheader );
Fclose (PIN );
Fclose (pout );
Return 0;
}
PS: After filtering, the sound quality decreases due to some high-frequency components.
This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/suhetao/archive/2010/09/18/5892382.aspx