Recording audio and save as Raw data (A-Law)

Jan 12, 2012 at 4:35 PM

Hi,

I'm working with the naudio c# example. I'm trying to record some audio from the mic, using the NAudioDemo RecordingDemo (recordingPanel.cs).

The process works fine.

My question is: how do I convert the produced wav to an a-Law raw byte array?

I suppose I could also write to a memorystream instead of writing to the disk, but this looks easy to me to be done.

I found this link

http://naudio.codeplex.com/discussions/83068

containing something I considered helpfull, but I couldn't come up with a solution.

Thanks in advance for any kind of help

Coordinator
Jan 13, 2012 at 8:36 AM

NAudio includes a fully managed A law encoder, in the ALawEncoder class, allowing you to pass in 16 bit samples and get out 8 bit a-law encoded bytes.

Alternatively, the simplest way to convert files would be to pass your WaveFileReader into a WaveFormatConversionStream (with target format of WaveFormat.CreateALawFormat(...)) and then pass that into WaveFileWriter.CreateWaveFile

Jan 13, 2012 at 2:04 PM

Thanks Mark, I went with the ALawEncoder class and it works like a charm.

I had a look here

 http://bit.ly/wp45x5 

and reused like this

        byte[] GetALawBytes(ref MemoryStream ms)
        {
            byte[] data = ms.ToArray();
            int length = ms.ToArray().Length;
            byte[] encoded = new byte[length/ 2];
            int outIndex = 0;
            
            for (int n = 0; n < length; n += 2)
            {
                encoded[outIndex++] = NAudio.Codecs.ALawEncoder.LinearToALawSample(BitConverter.ToInt16(data, n));
            }

            return encoded;
        }

To keep it simple, I saved the byte array to the disk and played the file with audacity. It works as intended!

Thanks!

Jan 13, 2012 at 3:12 PM

I have another question though: how do I strip the wav header from the memoryStream?

Or, on the other hand, how can I determine how long the wav header is? Is it like 16 bytes, 32? What else? In this case I could simply skip those bytes from being encoded.

Coordinator
Jan 13, 2012 at 3:53 PM

use the WaveFileReader - it can read from a MemoryStream, and then just call the Read method to get the actual audio data out.

Jan 17, 2012 at 4:44 PM

Hmm,

I'm having some troubles with the recorded audio. Basically the above function do the job pretty well.

But, there is some noise at the beginning of the file and this noise is a consequence of the fact that I'm encoding the wav header.

So, you told me to use wavefileREader and all the rest.

But...

I get this error when trying to read a memorystream containing the recorded audio

Invalid WAV file - No fmt chunk found

Looks like the fmt chucnk will be added when closing the writer, but since my writer is connected to a memorystream, the result is that my memorystream is empty.

To keep it simple, I post the code I'm using, I guess there is something wrong, but have no idea o'what.

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using NAudio;
using NAudio.Wave;
using System.IO;

namespace SoundsCS
{
    public partial class frmRecord : Form
    {
        public frmRecord()
        {
            InitializeComponent();
        }

        IWaveIn waveIn;
        WaveFileWriter writer;
        MemoryStream memStream;

        private void cmdStartRec_Click(object sender, EventArgs e)
        {
            if (waveIn == null)
            {
                memStream = new MemoryStream();
                
                waveIn = new WaveIn();
                waveIn.WaveFormat = new WaveFormat(8000, 1);

                writer = new WaveFileWriter(memStream, waveIn.WaveFormat);

                waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
                waveIn.RecordingStopped += new EventHandler(waveIn_RecordingStopped);
                waveIn.StartRecording();
                cmdStartRec.Enabled = false;
            }
        }

        void waveIn_RecordingStopped(object sender, EventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new EventHandler(waveIn_RecordingStopped), sender, e);
            }
            else
            {
                waveIn.Dispose();
                waveIn = null;

                ByteArrayToFile(@"C:\temp\miofile.raw", GetALawBytes(ref memStream));

                memStream.Position = 0;
                ByteArrayToFile(@"C:\temp\miofilewav.wav", memStream.ToArray());

                writer.Close();
                writer = null;

                cmdStartRec.Enabled = true;
                //progressBar1.Value = 0;
            }
        }

        void waveIn_DataAvailable(object sender, WaveInEventArgs e)
        {
            if (this.InvokeRequired)
            {
                //Debug.WriteLine("Data Available");
                this.BeginInvoke(new EventHandler<WaveInEventArgs>(waveIn_DataAvailable), sender, e);
            }
            else
            {
                //Debug.WriteLine("Flushing Data Available");
                writer.Write(e.Buffer, 0, e.BytesRecorded);
                int secondsRecorded = (int)(writer.Length / writer.WaveFormat.AverageBytesPerSecond);
                if (secondsRecorded >= 30)
                {
                    StopRecording();
                }
                else
                {
                    //progressBar1.Value = secondsRecorded;
                }
            }
        }

        void StopRecording()
        {
            //Debug.WriteLine("StopRecording");
            waveIn.StopRecording();
        }

        private void btnStopRec_Click(object sender, EventArgs e)
        {
            if (waveIn != null)
            {
                StopRecording();
            }
        }

        byte[] GetALawBytes(ref MemoryStream ms)
        {
            //Comment from here
            ms.Position = 0;
            WaveFileReader wfr = new WaveFileReader(ms);
            byte[] arr = new byte[0];
            int a = wfr.Read(arr, 0, (int)ms.Length);
            //to here to make it to work

            byte[] data = ms.ToArray();
            int length = ms.ToArray().Length;
            byte[] encoded = new byte[length / 2];
            int outIndex = 0;

            for (int n = 0; n < length; n += 2)
            {
                encoded[outIndex++] = NAudio.Codecs.ALawEncoder.LinearToALawSample(BitConverter.ToInt16(data, n));
            }

            return encoded;
        }

        public bool ByteArrayToFile(string _FileName, byte[] _ByteArray)
        {
            try
            {
                // Open file for reading

                System.IO.FileStream _FileStream = new System.IO.FileStream(_FileName, System.IO.FileMode.Create, System.IO.FileAccess.Write);

                // Writes a block of bytes to this stream using data from a byte array.
                _FileStream.Write(_ByteArray, 0, _ByteArray.Length);
                // close file stream
                _FileStream.Close();
                return true;
            }
            catch (Exception _Exception)
            {
                // Error
                MessageBox.Show("Exception caught in process: {0}", _Exception.ToString());
            }
            // error occured, return false
            return false;
        }
    }
}

The project only needs two commandButton, cmdStartRecord and btnStopRecord.

In the GetALawBytes function, commenting the first 4 lines of code will make the entire project to work. 

The final result is a .raw file playing as expected (but the noise).

The wav will not play at all.

Any suggestion? What I want to achieve is to extract the acutal audio data from the memorystream and save it as pure aLaw data.

Coordinator
Jan 17, 2012 at 6:33 PM

To write a WAV file, you must use the WaveFileWriter.

To read a .raw file, you should use the RawSourceWaveStream (or similar name, can't remember it off the top of my head) and tell it exactly what the format of the raw data is.

Mark