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.

Monday, May 23, 2011

Asp.Net Audio Converter

Converts audio files with Alvas.Audio in Asp.Net application as easy as in Windows Forms, WPF, Windows Service and Console Apps. You need
  1. Upload audio file.
  2. Select your audio file from list on the server.
  3. Select audio format from list with available audio formats.
  4. Press “Convert” button and download result audio file.


You can see online demo and example code and Alvas.Audio.

Tuesday, May 10, 2011

Alvas.Audio and WPF

To use Windows Forms controls in Windows Presentation Foundation(WPF) applications you need:
  • To create RecorderEx or PlayerEx use a constructor with a parameter isConsole = true. Example: new RecorderEx (true); or PlayerEx (true);
  • Add reference to WindowsFormsIntegration assembly (in WindowsFormsIntegration.dll) to your project.
  • Add reference to System.Windows.Forms assembly (in System.Windows.Forms.dll) to your project.
  • In the Window element, add the following namespace mapping

    xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"


    in Window1.xaml. The wf namespace mapping establishes a reference to the assembly that contains the Windows Forms control.
  • Place WindowsFormsHost container with our control. For example, PropertyGrid

    <WindowsFormsHost Grid.Row="1" Grid.Column="0" >

        <wf:PropertyGrid x:Name="pgMain"/>

    </WindowsFormsHost>


  • You can add control into WindowsFormsHost container in run-time:
    • Place empty WindowsFormsHost container to our Window1.xaml

      <WindowsFormsHost Name="wfh" Grid.Row="1" Grid.Column="1" ></WindowsFormsHost>


    • and create WaveformVisualizer (from Alvas.Audio.dll) control and place it to WindowsFormsHost container in run-time

      private void InitWaveformVisualizer()

      {

          wfv = new WaveformVisualizer();

          wfh.Child = wfv;

      }

      private WaveformVisualizer wfv;


Full-featured examples in C# and VB.Net (WpfCs and WpfVb projects) you can see in Alvas.Audio Demos