Friday, July 22, 2011

Console and multithreaded recording and playback

Question: How to use RecorderEx and PlayerEx in console application or Windows Service?

Answer: In order to use RecorderEx and PlayerEx in a console application or Windows Service need to create instances of these classes by using a parameterized constructor:
new RecorderEx(true) and new PlayerEx(true), respectively. The same is true for multi-threaded recorder and player.

Below is an example of full duplex Recorder and Player.

using System;

using Alvas.Audio;

 

namespace AudioConsCs

{

    class Program

    {

 

        static void Main(string[] args)

        {

            rex.Data += new RecorderEx.DataEventHandler(rex_Data);

            rex.Open += new EventHandler(rex_Open);

            rex.Close += new EventHandler(rex_Close);

            rex.Format = pcmFormat;

            rex.StartRecord();

            Console.WriteLine("Please press enter to exit!");

            Console.ReadLine();

            rex.StopRecord();

        }

 

        static RecorderEx rex = new RecorderEx(true);

        static PlayerEx play = new PlayerEx(true);

        static IntPtr pcmFormat = AudioCompressionManager.GetPcmFormat(1, 16, 44100);

 

        static void rex_Open(object sender, EventArgs e)

        {

            play.OpenPlayer(pcmFormat);

            play.StartPlay();

        }

 

        static void rex_Close(object sender, EventArgs e)

        {

            play.ClosePlayer();

        }

 

        static void rex_Data(object sender, DataEventArgs e)

        {

            byte[] data = e.Data;

            play.AddData(data);

        }

    }

}

Below is an example of multithreaded full duplex Recorder and Player in Windows Service.

/*

 * rem run cmd as administrator

 * rem install service

 * \\Windows\Microsoft.NET\Framework\v2.0.50727\installutil AudioWindowsServiceCs.exe

 * rem uninstall service

 * \\Windows\Microsoft.NET\Framework\v2.0.50727\installutil AudioWindowsServiceCs.exe /u

 */

using System;

using System.ServiceProcess;

using System.Threading;

using Alvas.Audio;

 

namespace AudioWindowsServiceCs

{

    public partial class AudioService : ServiceBase

    {

        public AudioService()

        {

            InitializeComponent();

        }

 

        protected override void OnStart(string[] args)

        {

            Thread t = new Thread(Start);

            t.Start();

        }

 

        protected override void OnStop()

        {

            rex.StopRecord();

        }

 

        static void Start()

        {

            rex.Data += new RecorderEx.DataEventHandler(rex_Data);

            rex.Open += new EventHandler(rex_Open);

            rex.Close += new EventHandler(rex_Close);

            rex.Format = pcmFormat;

            rex.StartRecord();

        }

 

        static RecorderEx rex = new RecorderEx(true);

        static PlayerEx play = new PlayerEx(true);

        static IntPtr pcmFormat = AudioCompressionManager.GetPcmFormat(1, 16, 44100);

 

        static void rex_Open(object sender, EventArgs e)

        {

            play.OpenPlayer(pcmFormat);

            play.StartPlay();

        }

 

        static void rex_Close(object sender, EventArgs e)

        {

            play.ClosePlayer();

        }

 

        static void rex_Data(object sender, DataEventArgs e)

        {

            byte[] data = e.Data;

            play.AddData(data);

        }

    }

}


Download examples and Alvas.Audio Trial

Friday, July 15, 2011

Vox audio file format

Question: I found that your vox converter doesn't handle vox files from the Orator phone dictation system right.

Answer: There are so many questions about Vox format. What is the Vox format? Vox audio file format is a headerless audio format data, which generally contains Dialogic_ADPCM, but may also include A-law, Mu-law, PCM, and any other type of audio data.
It means that vox file doesn't have the header and extention ".vox" doesn't say anything at all. Therefore it is very important to know in which format you have the audio data in the vox file!

See code below for the different types of Vox files.

        //Dialogic_ADPCM

        private static void Vox2Wav(string voxFile, int samplesPerSec)

        {

            BinaryReader br = new BinaryReader(File.OpenRead(voxFile));

            IntPtr format = AudioCompressionManager.GetPcmFormat(1, 16, samplesPerSec);

            WaveWriter ww = new WaveWriter(File.Create(voxFile + ".wav"),

                AudioCompressionManager.FormatBytes(format));

            Vox.Vox2Wav(br, ww);

            br.Close();

            ww.Close();

        }

 

 

        private void VoxConv2(string voxFile)

        {

            //CCITT u-Law, 8000 Hz, 1 channels

            WaveFormat wf = new WaveFormat();

            wf.wFormatTag = AudioCompressionManager.MuLawFormatTag;

            wf.nChannels = 1;

            wf.nSamplesPerSec = 8000;

            FormatDetails[] formatList = AudioCompressionManager.GetFormatList(wf);

            IntPtr format = formatList[0].FormatHandle;

            RawReader rr = new RawReader(File.OpenRead(voxFile), format);

            byte[] data = rr.ReadData();

            rr.Close();

            WaveWriter ww = new WaveWriter(File.Create(voxFile + ".wav"),

                AudioCompressionManager.FormatBytes(format));

            ww.WriteData(data);

            ww.Close();

        }

 

        static void Raw2Wav(string fileName)

        {

            //A-Law mono at 8000 HZ

            WaveFormat wf = new WaveFormat();

            wf.wFormatTag = AudioCompressionManager.ALawFormatTag;

            wf.nChannels = 1;

            wf.nSamplesPerSec = 8000;

            FormatDetails[] formatList = AudioCompressionManager.GetFormatList(wf);

            IntPtr format = formatList[0].FormatHandle;

            RawReader rr = new RawReader(File.OpenRead(fileName), format);

            byte[] data = rr.ReadData();

            rr.Close();

            WaveWriter ww = new WaveWriter(File.Create(fileName + ".wav"),

                AudioCompressionManager.FormatBytes(format));

            ww.WriteData(data);

            ww.Close();

        }


For more examples of working with vox files you can find on How to.. page. The search string "vox" gives at least 79 matches.

Wednesday, June 8, 2011

Removes DC offset

DC offset is an offsetting of a signal from zero. It occurs when hardware, such as a sound card, adds DC offset to the recorded audio signal.
DC offset is shift of the red line comparatively to the black one on figure below.


To remove the DC offset is used AudioCompressionManager.RemoveDcOffset method. See code below


        static void RemoveDcOffset(string fileName)

        {

            DsReader dr = new DsReader(fileName);

            IntPtr format = dr.ReadFormat();

            byte[] data = dr.ReadData();

            // Removes DC offset.

            byte[] dataNew = AudioCompressionManager.RemoveDcOffset(format, data);

            dr.Close();

            WaveWriter ww = new WaveWriter(File.Create(fileName + ".wav"),

                AudioCompressionManager.FormatBytes(format));

            ww.WriteData(dataNew);

            ww.Close();

        }

Alvas.Audio Trial

Monday, May 30, 2011

Converts Mp3 Joint Stereo to mono

Question: Have you got any issues with "Joint-Stereo" MP3's?
I have a customer who sends me the attached MP3 and when I convert it to a mono format, it effectively cancels out the audio.




Answer: The problem is that in Mp3 Joint Stereo sound file mirror is opposite. For example the left channel = -1, and the right channel = +1.
When converting a file into single channels are merged: -1 + 1 = 0. So you hear the silence.
You can solve this problem in that way. Instead of combining the channels keep only one channel (left or right).

The code below solves this problem.


        private void Mp3ToUlaw()

        {

            string FileName = @"d:\Work\10\SBL 6 Year 0511.mp3";

            Mp3Reader mr = new Mp3Reader(File.OpenRead(FileName));

            IntPtr formatMp3 = mr.ReadFormat();

            IntPtr formatPcm = AudioCompressionManager.GetCompatibleFormat(formatMp3, AudioCompressionManager.PcmFormatTag);

            byte[] dataMp3 = mr.ReadData();

            byte[] dataPcm = AudioCompressionManager.Convert(formatMp3, formatPcm, dataMp3, false);

            mr.Close();

            IntPtr format8000 = AudioCompressionManager.GetPcmFormat(2, 16, 8000);

            byte[] data8000 = AudioCompressionManager.Resample(formatPcm, dataPcm, format8000);

            IntPtr formatMono = IntPtr.Zero;

            byte[] dataLeft = null;

            byte[] dataRight = null;

            AudioCompressionManager.SplitStereo(format8000, data8000, ref formatMono, ref dataLeft, ref dataRight);


            //mono 8bit 8Khz u-law format

            IntPtr format = AudioCompressionManager.GetCompatibleFormat(formatMono, AudioCompressionManager.MuLawFormatTag);

            byte[] data = AudioCompressionManager.Convert(formatMono, format, dataLeft, false);

            WaveWriter ww = new WaveWriter(File.Create(FileName + ".wav"),

                AudioCompressionManager.FormatBytes(format));

            ww.WriteData(data);

            ww.Close();

        }

Sunday, May 29, 2011

Resampling and noise

Very often we have to change the sampling rate, number of channels and the size of a sample when converting from one format to another. You can use AudioCompression.Convert method for these purposes. Unfortunately, for the uncompressed PCM -> PCM this leads to a significant reduction in sound quality and appearance of extraneous noise. We can verify this by example.


private void Convert()

{

    string fileName = @"Original.WAV";

    IntPtr formatNew = AudioCompressionManager.GetPcmFormat(2, 16, 44100);

    string fileNameNew = fileName + ".Convert.Wav";

    for (int i = 0; i < 100; i++)

    {

        WaveReader wr = new WaveReader(File.OpenRead(fileName));

        IntPtr format = wr.ReadFormat();

        byte[] data = wr.ReadData();

        wr.Close();

        byte[] dataNew = AudioCompressionManager.Convert(format, formatNew, data, false);

        WaveWriter ww = new WaveWriter(File.Create(fileNameNew),

            AudioCompressionManager.FormatBytes(formatNew));

        ww.WriteData(dataNew);

        ww.Close();

        fileName = fileNameNew;

        //Previous format

        formatNew = format;

    }

}


Fortunately, Alvas.Audio library has AudioCompression.Resample method. It is a wrapper over Resampler DMO object.
If we rewrite the code above using AudioCompression.Resample method, we get much better sound quality.


private void Resample()

{

    string fileName = @"Original.WAV";

    IntPtr formatNew = AudioCompressionManager.GetPcmFormat(2, 16, 44100);

    string fileNameNew = fileName + ".Resample.Wav";

    for (int i = 0; i < 100; i++)

    {

        WaveReader wr = new WaveReader(File.OpenRead(fileName));

        IntPtr format = wr.ReadFormat();

        byte[] data = wr.ReadData();

        wr.Close();

        byte[] dataNew = AudioCompressionManager.Resample(format, data, formatNew);

        WaveWriter ww = new WaveWriter(File.Create(fileNameNew),

            AudioCompressionManager.FormatBytes(formatNew));

        ww.WriteData(dataNew);

        ww.Close();

        fileName = fileNameNew;

        //Previous format

        formatNew = format;

    }

}


You can compare the sound of these 3 files.


As a bonus AudioCompression.Resample method can encode and decode the PCM 24 and 32 bit, more than 2 channels, and also 32-bit IEEE Float audio format.


Summary: For encode and decode a compressed format to PCM AudioCompression.Convert fits perfectly, but for resampling use AudioCompression.Resample method.

Thursday, May 26, 2011

Audio Readers

  • Audio Readers is a hierarchy of Alvas.Audio classes that implement IAudioReader interface used to read format and audio data.
    • AudioReader is a base class for the readers that can read an audio data from the stream. This class is abstract.
      • AuReader class reads an audio data from the .AU and .SND streams.
      • AviReader class reads audio data from the Avi stream.
      • WaveReader class reads WAVE (waveform audio format) data from the stream.
      • RawReader class reads an audio data from the headerless stream. Slinear, Gsm, A-law, mu-law etc. For that, you need to specify explicitly the format of the audio data that they contain.
      • Mp3Reader class reads audio data from the Mp3 stream.
    • DsReader class reads audio data using DirectShow. List of supported formats can be expanded with additional DirectShow filters installed.
      Use Combined_Community_Codec_Pack, K-Lite_Codec_Pack or Ffdshow to expand the list of supported formats.
      At the moment, can only work with files stored on disk.

Three methods of IAudioReader interface most commonly used.


            string fileName = "Your audio file.wav";

            IAudioReader ir = new WaveReader(File.OpenRead(fileName));

            IntPtr format = ir.ReadFormat();// Reads an audio format.

            byte[] data = ir.ReadData();// Reads all audio data from the stream.

            ir.Close();// Closes the current reader and the underlying stream.


To read the audio data portions of 1 second, you can use the following code.


            string fileName = "Your audio file.mp3";

            IAudioReader ir = new Mp3Reader(File.OpenRead(fileName));

            IntPtr format = ir.ReadFormat();// Reads an audio format.

            int skipSeconds = 0;

            const int readSeconds = 1;

            while (true)

            {

                // Reads audio data starts at skipSeconds position and readSeconds duration.

                byte[] data = ir.ReadData(skipSeconds, readSeconds);

                if (data.Length == 0)

                {

                    break;

                }

                skipSeconds += readSeconds;

            }

            ir.Close();// Closes the current reader and the underlying stream.


To read the audio data by portions that are smaller than 1 second, you can use the following code.


            string fileName = "Your audio file.pcm";

            //Specifies the format of audio data

            IntPtr format = AudioCompressionManager.GetPcmFormat(2, 16, 44100);

            IAudioReader ir = new RawReader(File.OpenRead(fileName), format);

            const int miliseconds = 500;

            int skipBytes = 0;

            // Converts from milliseconds to bytes for current stream.

            int readBytes = ir.Milliseconds2Bytes(miliseconds);

            while (true)

            {

                // Reads audio data starts at skipBytes position and readBytes length.

                byte[] data = ir.ReadDataInBytes(skipBytes, readBytes);

                if (data.Length == 0)

                {

                    break;

                }

                skipBytes += readBytes;

            }

            ir.Close();// Closes the current reader and the underlying stream.



The following code allows to determine the audio stream duration in milliseconds and the audio data size in bytes.


            string fileName = "Your audio file.snd";

            IAudioReader ir = new AuReader(File.OpenRead(fileName));

            // Gets audio stream duration in milliseconds.

            int durationInMS = ir.GetDurationInMS();

            // Gets audio stream length in bytes.

            int lengthInBytes = ir.GetLengthInBytes();

            ir.Close();// Closes the current reader and the underlying stream.



Avi files are video files. They may not contain audio data. To determine this AviReader class has HasAudio property.
DsReader HasAudio equal false means that the file contains no audio data or audio file format is unknown, ie no suitable DirectShow filter.



            using (AviReader ar = new AviReader(File.OpenRead("your.avi")))

            {

                if (ar.HasAudio)

                {

                    // ...

                }

            }

            using (DsReader dr = new DsReader("Your audio file"))

            {

                if (dr.HasAudio)

                {

                    // ...

                }

            }


Enjoy.

Wednesday, May 25, 2011

Audio and File formats

Audio file formats can be with a header, without header and with header in each packet of audio data.




  • Wav file is a classic audio format with a header. It is also called container format, because it may contain an audio data in a different format, which is specified in the header.
  • Headerless(Raw audio format) audio files can contain only audio data. Therefore, we must know exactly the format of the audio data. These files usually have .raw, .sln, .pcm, .alaw, .ulaw, .gsm and other file extensions.
  • MP3 format contains a header in each packet of audio data. Therefore, this format is suitable for broadcasting audio over the network.