I am working on a music project where I need to join several WAV files. My Code works fine, but you hear clearly a clicking noise between two joined WAV files. That is an huge issue.
I am an audio engineer. When I work, with e.g. consecutive samples in a DAW (Digital Audio Workstation) and I want to prevent this clicking noise between two WAV samples then I have to create a crossover fade (basically this is a fadeout on the first sample and a fade in on the next sample).
Therefore my question would be if I can create such a crossover fade while concatenating two WAV files. I need to get rid of the clicking noise between concatenated wave files.
I provide my C# code below how I concatenate WAV files. This works for WAV files which are in the same "format". I found this piece of Code on (How to join 2 or more .WAV files together programatically?). Further I found this FadeIn/FadeOut possibility but I do not know how to apply this on the code. Further, I do not know if this would prevent the clicking noise.
Thank you for advice and a solution. Hopefully Mark Heath reads this :).
Best regards, Alex
Wavefile format:
AverageBytesPerSecond: 264600 | BitsPerSample: 24 | BlockAlign: 6 | Channels: 2 | Encoding: PCM | Extra Size: 0 | SampleRate: 44100 |
public static void Concatenate(string outputFile, IEnumerable<string> sourceFiles)
{
byte[] buffer = new byte[6]; //1024 was the original. but my wave file format has the blockAlign 6. So 1024 was not working for me. 6 does.
WaveFileWriter waveFileWriter = null;
try
{
foreach (string sourceFile in sourceFiles)
{
using (WaveFileReader reader = new WaveFileReader(sourceFile))
{
if (waveFileWriter == null)
{
// first time in create new Writer
waveFileWriter = new WaveFileWriter(outputFile, reader.WaveFormat);
}
else
{
if (!reader.WaveFormat.Equals(waveFileWriter.WaveFormat))
{
throw new InvalidOperationException("Can't concatenate WAV Files that don't share the same format");
}
}
int read;
while ((read = reader.Read(buffer, 0, buffer.Length)) > 0)
{
waveFileWriter.WriteData(buffer, 0, read);
}
}
}
}
finally
{
if (waveFileWriter != null)
{
waveFileWriter.Dispose();
}
}
}
This sounded like fun :)
Here's a sample I wrote to do this. It accepts a list of input filename patterns (assumes current directory) and the name of the output file. It stitches the files together, fading out ~1 second at the end of one file, then fading in ~1 second of the next file, and so on. Note: It doesn't mix that ~1 second overlap. Didn't feel like doing that :)
I used the
ReadNextSampleFrame
methods on the WaveFileReader to read the data as IEEE floating-point samples (one float per channel). This makes it much easier to apply volume adjustments unilaterally without having to worry about the actual input PCM representation. On the output, it usesWriteSamples
on the writer to write the adjusted samples.My first go at this used an NAudio
FadeInFadeOutSampleProvider
. But I found a weird bug in there when you had more than one audio channel.So the code manually applies a volume to each sample read, ramping up the volume from 0.0 to 1.0 at the start of each file (except the first). It then copies the 'middle' of the file directly. Then at about 1 second before the end of the file (actually, (
WaveFormat.SampleRate
*WaveFormat.Channels
) samples before the end of the file), it ramps the volume back down from 1.0f to 0.0f.I tested it by using sox to generate a 5-second long 440Hz sine wave file, sampling rate = 96K, stereo, as follows:
The test was called as follows:
And here's the code: