We no longer sell products directly from the GHI Electronics website, click here for more details. Please find a Distributor to complete your online order. If you have any questions regarding this notice please contact us at support@ghielectronics.com.

WAV Audio Playback

Last modified October 29, 2015

Under construction While NETMF interpreter is not fast enough to play audio file, GHI Electronics libraries extend the system with a native PCM player. If raw PCM samples are available, they can be simply sent to the method to playback. If a WAV file is used, a simple code is needed to extract the PCM data from the file. Note that the file has to be 8-bit PCM, mono, no compression to work. The best way to play WAV files is to load from a storage device, like an SD cards. They are large in size and using an SD card will allow us to load chunks at once. For the sake of simplicity, this example loads the file from a resource. Just make sure the file is really small, like 10KB. Before adding the file to the project resources, the project extension need to be changed from WAV to DAT. Visual Studio tries to handle audio file differently and we do to want that. We want this file to be a simple raw data. Now, open the Resources.resx file in the Solution Explorer then drag and drop your audio file.

(image)

We can now load this resource in memory, which is why we want to keep the file small. To hear the sound, you need to wire an amplified speaker to the analog input pin, like speakers used with desktop PCs. A headphone may work as well. On the 3.5mm plug, connect the very tip of the plug to the analog output pin and also connect ground (GND) from the board to the upper sleeve on the plug. Tip: The example requires the GHI.Hardware assembly.

If you are not sure where to get a suitable audio files, search GHI Electronics codeshare for wav. Tip: This feature is excellent to play notifications, like saying words such as STOP and ALARM. Playing music compressed files, like MP3, is possible by adding an MP3 decoder chip.

Coming soon. See this for details https://www.ghielectronics.com/community/codeshare/entry/511

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

namespace NETMFBook
{
    public class Program
    {
        public class WAVE
        {
            int index;
            int dataSize;
            int sampleRate;

            /// <summary>
            /// Loads a WAV file. ONLY PCM 8-bit Mono.
            /// </summary>
            /// <param name="wav">WAV file bytes.</param>
            public WAVE(byte[] wav)
            {
                // see https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

                index = 0;
                if (wav[index + 0] != 'R' || wav[index + 1] != 'I' || wav[index + 2] != 'F' || wav[index + 3] != 'F')
                {
                    throw new Exception("File is not RIFF");
                }
                index += 4;
                // ChunkSize
                uint ChunkSize = Utility.ExtractValueFromArray(wav, index, 4);
                index += 4;
                //format
                if (wav[index + 0] != 'W' || wav[index + 1] != 'A' || wav[index + 2] != 'V' || wav[index + 3] != 'E')
                {
                    throw new Exception("File is not WAVE format");
                }
                index += 4;
                ////////////////////////////////////

                // fmt sub chunk //////////////////////
                //subchunk ID
                if (wav[index + 0] != 'f' || wav[index + 1] != 'm' || wav[index + 2] != 't' || wav[index + 3] != ' ')
                {
                    throw new Exception("Unexpected fmt subchunk!");
                }
                index += 4;
                bool BitVarSampleRate16;

                uint Subchunk1Size = Utility.ExtractValueFromArray(wav, index, 4);
                index += 4;
                if (Subchunk1Size == 16)
                {
                    BitVarSampleRate16 = true;
                }
                else if (Subchunk1Size == 18)
                {
                    BitVarSampleRate16 = false;
                }
                else
                {
                    throw new Exception("Invalid Subchunk1Size.");
                }

                ushort AudioFormat = (ushort)Utility.ExtractValueFromArray(wav, index, 2);
                index += 2;
                if (AudioFormat != 1)
                {
                    throw new Exception("AudioFormat invalid.");
                }

                ushort NumChannels = (ushort)Utility.ExtractValueFromArray(wav, index, 2);
                index += 2;
                if (NumChannels != 1)
                {
                    throw new Exception("Must be mono.");
                }

                sampleRate = (int)Utility.ExtractValueFromArray(wav, index, 4);
                index += 4;
                if (sampleRate != 8000)
                {
                    throw new Exception("Sample rate must be 8000KHz.");
                }

                ushort ByteRate = (ushort)Utility.ExtractValueFromArray(wav, index, 4);
                index += 4;

                ushort BlockAlign = (ushort)Utility.ExtractValueFromArray(wav, index, 2);
                index += 2;

                if (BitVarSampleRate16)
                {
                    ushort BitsPerSample = (ushort)Utility.ExtractValueFromArray(wav, index, 2);
                    index += 2;
                    if (BitsPerSample != 8)
                    {
                        throw new Exception("Must be 8 bit.");
                    }
                }
                else
                {
                    uint BitsPerSample = Utility.ExtractValueFromArray(wav, index, 4);
                    index += 4;
                    if (BitsPerSample != 8)
                    {
                        throw new Exception("Must be 8 bit.");
                    }
                }

                ///////////////////////////////////////////

                //// data sub-chunk ///////////////////////////////////////
                if (wav[index + 0] != 'd' || wav[index + 1] != 'a' || wav[index + 2] != 't' || wav[index + 3] != 'a')
                {
                    throw new Exception("Unexpected data subchunk!");
                }
                index += 4;

                uint Subchunk2Size = (ushort)Utility.ExtractValueFromArray(wav, index, 4);
                index += 4;

                dataSize = (int)Subchunk2Size;
                ////////////////////////////////////////////
            }

            public int GetDataIndex()
            {
                return index;
            }

            public int GetDataSize()
            {
                return dataSize;
            }

            public int GetSampleRate()
            {
                return sampleRate;
            }
        }
        public static void Main()
        {
            byte [] rawData = Resources.GetBytes(Resources.BinaryResources.scream);
            WAVE wav = new WAVE(rawData);

            while (true)
            {
                GHI.IO.Audio.PlayPcm(GHI.Pins.G80.AnalogOutput.PA4,
                    rawData, wav.GetDataIndex(), wav.GetDataSize(), wav.GetSampleRate());
                Thread.Sleep(1000);// Scream once a second!
            }
        }
    }
}
Leave feedback about this document.
Let us know if the information presented here was accurate, helpful and if you have any suggestions.
Leave feedback about this document.
Let us know if the information presented here was accurate, helpful and if you have any suggestions.

* Indicates required fields.
This form is only for feedback not support.
Review our how to find information guide on locating helpful resources.