This project has moved. For the latest updates, please go here.

Normalize WAV reconstructing a wav file

Aug 18, 2014 at 9:25 PM
I specifically needed to normalize audio. Not compress, normalize.

I was successfully able to use a WaveFileReader to load a file. Then used .ReadAsync to fill a byteArray with the data. I performed the necessary math and have a new normalized byteArray.

Q: How do I save it back out? Is there an example of this?
Coordinator
Aug 20, 2014 at 11:06 AM
You can save it back out with a WaveFileWriter. Just call Write and pass in your byte array
Aug 20, 2014 at 9:22 PM
Thank-you. I've been making good progress.

The issue I've run into is that my audio file is 8bit. I was able to read an 8bit wav to a byte[], and write it back out again, BUT, when I went to scale the data for normalization, it appears unsigned. So a multiplier just moves the whole waveform upwards, instead of scaling the negative side down. (hope you get what I mean)

Q: How should I read/write/manipulate the 8bit array to work with it as an SByte or signed 8-bit that it is? Some type of cast?

(PseudoCode)
       byte[] byteArray;
        wfr = new WaveFileReader("sine.wav");
         wavByteArray = new byte[wfr.Length];
         await WAV_ReadToByteArray(wfr, wavByteArray);
         NormalizeMono8bit22(wavByteArray);

      async Task<int> WAV_ReadToByteArray(WaveFileReader a, byte[] destination)
        {
            Task<int> dataRead = a.ReadAsync(destination, 0, (int)a.Length);
            int s = await dataRead;
            return s;
        }

      void NormalizeMono8bit22(byte[] source)
        {
            biggest = 0;
            for (int i = 0; i < source.Length; i++)
            {
                if (Math.Abs(source[i]) > biggest)
                    biggest = source[i];
            }

            float multiplier; 
            if (biggest <= 0)
                multiplier = 1;
            else
                multiplier = byte.MaxValue / biggest;

            for (int i = 0; i < source.Length; i++)
            {
                int maxVal = (int)(multiplier * source[i]);
                if (maxVal > byte.MaxValue)
                    source[i] = byte.MaxValue;
                else if (maxVal < byte.MinValue)
                    source[i] = byte.MinValue;
                else
                    source[i] = (byte)(source[i] * multiplier);
            }
        }
Aug 23, 2014 at 3:01 PM
Right. Well as far as I can tell there is no direct casting method deal with an 8 bit signed audio array in NAudio.
You have to read in the signed 8bit, and offset it by -128. If its stereo, you have to process each channel that way.

Then you can rescale it in a more intuitive way, using floats. When the result is finished, add back the 128 and write it back out.
That's what I did.