Search code examples
c#.net-coreopentkopenalwave

How do I merge two wave files into one in .Net Core?


I need to merge two wave files in .net core. So I choosed OpenTK as wrapper for OpenAL.

I tried to merge two wave files with same bits per sample and sapmle rate.

1) To do this I get this example

2) Make 2 byte areas:

var sound_data1 = LoadWave(path1, FileMode.Open), out channels, out bits_per_sample, out sample_rate);

var sound_data2 = LoadWave(path2, FileMode.Open), out channels, out bits_per_sample, out sample_rate);

3) Make sum for each byte and devide it to 2

for (int i = 0; i < sound_data1; i++)
{
result_sound_data[i] = (byte)((sound_data1[i] + sound_data2[i]) / 2);
}

4) then:

AL.BufferData(buffer, GetSoundFormat(channels, bits_per_sample), result_sound_data, result_sound_data.Length, sample_rate);

AL.Source(source, ALSourcei.Buffer, buffer);
AL.SourcePlay(source);

An finaly I got some damaged sound instead of mixed signal. How do I solve it?


Solution

  • Merging audio streams is apparently basically taking a sum of the corresponding samples in each input audio file. You can study the source code of this sample on codeproject. This code is maybe not the cleanest, but seems to do the job (I tested).

    Apart from handling the WAV file header, the actual merging logic for an array of input files is described here:

    // 8. Do the merging..
    // The basic algorithm for doing the merging is as follows:
    // while there is at least 1 sample remaining in any of the source files
    //    sample = 0
    //    for each source file
    //       if the source file has any samples remaining
    //          sample = sample + next available sample from the source file
    //    sample = sample / # of source files
    //    write the sample to the output file
    

    This is implemented in that code sample as follows, for 8-bit samples:

    while (SamplesRemain(scaledAudioFiles))
    {
        byte sample = 0;
        for (var i = 0; i < scaledAudioFiles.GetLength(0); ++i)
        {
            if (scaledAudioFiles[i].NumSamplesRemaining > 0)
            {
                sample += scaledAudioFiles[i].GetNextSample_8bit();
            }
        }
        sample /= (byte)(scaledAudioFiles.GetLength(0));
        outputFile.AddSample_8bit(sample);
    }
    

    The code in that sample is entirely compatible with .Net Core.

    If you just want to take that code and merge some .wav files, here's how to do just that (still, using the sample in question):

        private static void Main(string[] args) => WAVFile.MergeAudioFiles(
                new[] { "file1.wav", "file2.wav", "file3.wav" },
                "result.wav",
                Path.GetTempPath()
            );