libsndfile usage joining and mixing .wav files
I need help getting started with libsndfile.
I have four .wav files (all the same sample rate).
I want to join the first two together,then the next two together,
Then mix the result开发者_开发知识库ing 2 .wav files into one.
For mixing two wav files.
#include <cstdio>
#include <sndfile.h>
#include <windows.h>
#include <cstdlib>
#include <cmath>
#define BUFFER_LEN 1024
#define MAX_CHANNELS 6
static void data_processing (double *data, int count, int channels) ;
int main (void) {
static double data [BUFFER_LEN] ;
static double data2 [BUFFER_LEN] ;
static double outdata [BUFFER_LEN] ;
SNDFILE *infile, *outfile, *infile2 ;
SF_INFO sfinfo ;
int readcount ;
SF_INFO sfinfo2 ;
int readcount2 ;
const char *infilename = "inputOne.wav" ;
const char *infilename2 = "inputTwo.wav" ;
const char *outfilename = "output.wav" ;
if (! (infile = sf_open (infilename, SFM_READ, &sfinfo))) {
/* Open failed so print an error message. */
printf ("Not able to open input file %s.\n", infilename) ;
/* Print the error message from libsndfile. */
puts (sf_strerror (NULL)) ;
return 1 ;
} ;
if (sfinfo.channels > MAX_CHANNELS) {
printf ("Not able to process more than %d channels\n", MAX_CHANNELS) ;
return 1 ;
} ;
if (! (infile2 = sf_open (infilename2, SFM_READ, &sfinfo2))) {
/* Open failed so print an error message. */
printf ("Not able to open input file %s.\n", infilename2) ;
/* Print the error message from libsndfile. */
puts (sf_strerror (NULL)) ;
return 1 ;
} ;
if (sfinfo2.channels > MAX_CHANNELS) {
printf ("Not able to process more than %d channels\n", MAX_CHANNELS) ;
return 1 ;
} ;
/* Open the output file. */
if (! (outfile = sf_open (outfilename, SFM_WRITE, &sfinfo))) {
printf ("Not able to open output file %s.\n", outfilename) ;
puts (sf_strerror (NULL)) ;
return 1 ;
} ;
while ((readcount = sf_read_double (infile, data, BUFFER_LEN)) &&
(readcount2 = sf_read_double (infile2, data2, BUFFER_LEN))) {
data_processing (data, readcount, sfinfo.channels) ;
data_processing(data2, readcount2, sfinfo2.channels) ;
for(int i=0; i < 1024;++i) {
outdata[i] = (data[i] + data2[i]) -(data[i])*(data2[i])/65535;
}
sf_write_double (outfile, outdata , readcount) ;
} ;
/* Close input and output files. */
sf_close (infile) ;
sf_close (infile2) ;
sf_close (outfile) ;
system("PAUSE");
return 0 ;
} /* main */
static void data_processing(double *data, int count, int channels) {
double channel_gain [MAX_CHANNELS] = { 0.5, 0.8, 0.1, 0.4, 0.4, 0.9 } ;
int k, chan ;
for (chan = 0 ; chan < channels ; chan ++)
for (k = chan ; k < count ; k+= channels)
data [k] *= channel_gain [chan] ;
return ;
} /* data_processing */
This is how i am mixing two simple wav files which are 16 bit signals.
First of all audio mixing is not easy as one might think. There might be many ambiguities after joining two signals. In my case it is working just fine as much as i need it, but if you need exact results you might need to google more for exact superimposing signals over each other.
For joining two wav files you can just read your first wav file copy the data in the result wav file and finally append the data of the second wav file to the result wav file.
This link might also be useful for you http://www.vttoth.com/digimix.htm
This is old, but I'm reading it, so somebody else inevitably will do so.
I agree in general with nishantmishra regarding the use of libsndfile, but this mixing algorithm would cause a certain amount of distortion if it was doing as the author expects:
outdata[i] = (data[i] + data2[i]) -(data[i])*(data2[i])/65535;
(In reality, that last term only adds a little bit of low-level noise...before reading V-Toth's article I thought it was an interesting form of dither), Assuming this was applied in a way that works as intended (floating point audio ranges from -1.0 to 1.0, so dividing by 65535 reduces the product by 96 dB, which makes it inaudible for 16-bit audio). If you actually want to implement this method, then read on in V Toth's posting about doing this for signed data.
Whether signed or unsigned, you will be adding inter-modulation distortion (even if it isn't nasty audible, it will be there). In other words, this would work great for voice, or low bit-rate (telephone) audio where the distortion in the transmission channel far exceeds the intermodulation distortion added by product of channels.
If you are just processing two files, and not doing so in real-time (play-back as you read blocks from the file or stream), you can normalize both files, apply mix gain such that gain1+gain2 = 1.0, and sum them together. These low resolution challenges as mentioned by V Toth are not a large concern with 32-bit float or 64-bit double.
Finally, if you are concerned about one source being too quiet while the other is silent, then you can apply a dynamic range compressor cross-linked to the other channel. Another tactic is to apply the same algorithm, but to the envelopes of the audio, and not to individual samples:
outEnvelope[i] = (envelope1[i] + envelope2[i]) \
-(envelope1[i])*(envelope2[i]);
outdata[i]=outEnvelope[i]*(data[i] + data2[i]);
Where envelope =
envelope1[i]=sqrt(lowPassFilter(data[i]*data[i]));//moving RMS representation
And the low pas filter cutoff frequency is something on the order of <10Hz to minimize harmonic distortion.
Really, I think all you want to do most times is to drop that last term and use this line:
outdata[i] = (data[i] + data2[i]);
As long as the sum of channel_gain[] = 1.0, you will get a good result. The code by nishantmishra works well because that last distortion-adding term is reduced to the noise floor, so you may as well save CPU time and eliminate it.
精彩评论