Search code examples
c++audioffmpeglibsndfile

Trying to mix two PCM audio sources


I have two audio files I read in using libsndfile.

SNDFILE* file1 = sf_open("D:\\audio1.wav", SFM_READ, &info);
SNDFILE* file2 = sf_open("D:\\audio2.wav", SFM_READ, &info2);

After I've done the previous I sample x-number of samples:

//Buffers that will hold the samples
short* buffer1 = new short[2 * sizeof(short) * 800000];
short* buffer2 = new short[2 * sizeof(short) * 800000];

// Read the samples using libsndfile
sf_readf_short(file1, buffer1, 800000);
sf_readf_short(file2, buffer2, 800000);

Now, I want to mix those two. I read that you need to get the left and right channel separately and then sum them up. I tried doing it like this:

short* mixdown = new short[channels * sizeof(short) * 800000];
for (int t = 0; t < 800000; ++t)
{
    mixdown[t] = buffer1[t] + buffer2[t] - ((buffer1[t]*buffer2[t]) / 65535);
    t++;
    mixdown[t] = buffer1[t] + buffer2[t] - ((buffer1[t]*buffer2[t]) / 65535);
}

After that I'm encoding the new audio using ffmpeg:

FILE* process2 = _popen("ffmpeg -y -f s16le -acodec pcm_s16le -ar 44100 -ac 2 -i - -f vob -ac 2 D:\\audioMixdown.wav", "wb");
fwrite(mixdown, 2 * sizeof(short) * 800000, 1, process2);

Now, the problem is that the audio from buffer1 sounds fine in the mixdown but the only thing "added" to the new audio is noise (like if it's an old audio recording) when I encode the mixdown to a file.

If I encode only one of the two to a file it works perfectly.

I have no idea why it's going wrong. I guess it has something to do with the mixing, obviously, but I don't know what I'm doing wrong. I got the mixing algorithm here but it doesn't give me the expected results.

I've also read other information on SO about people having similar questions but I couldn't figure it out with those.


Solution

  • Your mixing code is very odd - you seem to be adding a non-linear term which will result in distortion - it seems to be a hack specifically for 8 bit PCM where the dynamic range is very limited, but you probably don't need to worry about this for 16 bit PCM. For basic mixing you just want this:

    for (int t = 0; t < 800000 * 2; ++t)
    {
        mixdown[t] = (buffer1[t] + buffer2[t]) / 2;
    }
    

    Note that the divide by 2 is necessary to prevent distortion when you have two full scale signals. Note also that I've removed 2x loop unrolling.