Click here to Skip to main content
15,891,951 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hey guys, I have been doing some experimenting with WAV files and I need to be able to play an WAV file from a stream. What I am going to be doing is opening a file, getting the raw data of the wav file. I do this by using this class provided by NightFox:

http://www.codeproject.com/KB/audio-video/CSharpWAVClassAndMixing.aspx

Then when I have the raw data, I extract it using the WAVFile's built in function GetNextSampleAs16Bit().

Here is the class that I have made:


C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

// I want to be able to input a list of shorts, and it will give me 
// a playable stream internal wav file. 

namespace Aurasen
{
    class InternalWAVFile
    {
        private MemoryStream mMemoryStream;
        private bool mStereo;
        private int mSampleRateHz;
        private short mBitsPerSample;
        private int mDataSizeBytes;


        public InternalWAVFile(short[] samples, bool pStereo, int pSampleRateHz, short pBitsPerSample)
        {
            if (mMemoryStream != null)
            {
                mMemoryStream.Close();
                mMemoryStream.Dispose();
                mMemoryStream = null;
            }

            mMemoryStream = new MemoryStream();
            mStereo = pStereo;
            mSampleRateHz = pSampleRateHz;
            mBitsPerSample = pBitsPerSample;

            Create();

            foreach (short s in samples)
            {
                byte[] buffer = BitConverter.GetBytes(s);
                if (!BitConverter.IsLittleEndian)
                    Array.Reverse(buffer);
                AddSample_ByteArray(buffer);
            }
            mMemoryStream.Close();
        }

        public MemoryStream GetStream()
        {
            return mMemoryStream;
        }

        private void AddSample_ByteArray(byte[] pSample)
        {
            try
            {
                int numBytes = pSample.GetLength(0);
                mMemoryStream.Write(pSample, 0, numBytes);
            }
            catch
            {

            }
        }


        // Adds the header to the memory stream so that now I can add the data
        private void Create()
        {
            try
            {
                // set the member data from the params
                byte mNumChannels = mStereo ? (byte)2 : (byte)1;
                char[] mWAVHeader = new char[4];
                char[] mRIFFType = new char[4];
                "RIFF".CopyTo(0, mWAVHeader, 0, 4);
                "WAVE".CopyTo(0, mRIFFType, 0, 4);

                // RIFF chunk (12 bytes total)
                // Write the chunk IDD ("RIFF", 4 bytes)
                byte[] buffer = StrToByteArray("RIFF");
                mMemoryStream.Write(buffer, 0, 4);      // gets stuck here..won't write to the stream
                if (mWAVHeader == null)
                    mWAVHeader = new char[4];
                "RIFF".CopyTo(0, mWAVHeader, 0, 4);
                // File size size (4 bytes) - This will be 0 for now
                Array.Clear(buffer, 0, buffer.GetLength(0));
                mMemoryStream.Write(buffer, 0, 4);
                // RIFF type ("WAVE")
                buffer = StrToByteArray("WAVE");
                mMemoryStream.Write(buffer, 0, 4);
                if (mRIFFType == null)
                    mRIFFType = new char[4];
                "WAVE".CopyTo(0, mRIFFType, 0, 4);

                // Format chunk (24 bytes total)
                // "fmt " (ASCII characters)
                buffer = StrToByteArray("fmt ");
                mMemoryStream.Write(buffer, 0, 4);
                // Length of format chunk (always 16, 4 bytes)
                Array.Clear(buffer, 0, buffer.GetLength(0));
                buffer[0] = 16;
                if (!BitConverter.IsLittleEndian)
                    Array.Reverse(buffer);
                mMemoryStream.Write(buffer, 0, 4);
                // 2 bytes (always 1)
                Array.Clear(buffer, 0, buffer.GetLength(0));
                buffer[0] = 1;
                if (!BitConverter.IsLittleEndian)
                    Array.Reverse(buffer, 0, 2);
                mMemoryStream.Write(buffer, 0, 2);
                // # of channels (2 bytes)
                Array.Clear(buffer, 0, buffer.GetLength(0));
                buffer[0] = mNumChannels;
                if (!BitConverter.IsLittleEndian)
                    Array.Reverse(buffer, 0, 2);
                mMemoryStream.Write(buffer, 0, 2);
                // Sample rate (4 bytes)
                buffer = BitConverter.GetBytes(mSampleRateHz);
                if (!BitConverter.IsLittleEndian)
                    Array.Reverse(buffer);
                mMemoryStream.Write(buffer, 0, 4);
                // Calculate the # of bytes per sample: 1=8 bit Mono, 2=8 bit Stereo or
                // 16 bit Mono, 4=16 bit Stereo
                short bytesPerSample = 0;
                if (mStereo)
                    bytesPerSample = (short)((mBitsPerSample / 8) * 2);
                else
                    bytesPerSample = (short)(mBitsPerSample / 8);
                // Write the # of bytes per second (4 bytes)
                int mBytesPerSec = mSampleRateHz * bytesPerSample;
                buffer = BitConverter.GetBytes(mBytesPerSec);
                if (!BitConverter.IsLittleEndian)
                    Array.Reverse(buffer);
                mMemoryStream.Write(buffer, 0, 4);
                // Write the # of bytes per sample (2 bytes)
                byte[] buffer_2bytes = BitConverter.GetBytes(bytesPerSample);
                if (!BitConverter.IsLittleEndian)
                    Array.Reverse(buffer_2bytes);
                mMemoryStream.Write(buffer_2bytes, 0, 2);
                // Bits per sample (2 bytes)
                buffer_2bytes = BitConverter.GetBytes(mBitsPerSample);
                if (!BitConverter.IsLittleEndian)
                    Array.Reverse(buffer_2bytes);
                mMemoryStream.Write(buffer_2bytes, 0, 2);

                // Data chunk
                // "data" (ASCII characters)
                buffer = StrToByteArray("data");
                mMemoryStream.Write(buffer, 0, 4);
                // Length of data to follow (4 bytes) - This will be 0 for now
                Array.Clear(buffer, 0, buffer.GetLength(0));
                mMemoryStream.Write(buffer, 0, 4);
                mDataSizeBytes = 0;

                // Total of 44 bytes written up to this point.

                // The rest of the file is the audio data
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        private static byte[] StrToByteArray(String pStr)
        {
            System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
            return encoding.GetBytes(pStr);
        }
    }
}


But for some reason when I used this function to play audio like this:

All it does is say the Header information is corrupted, even though I am using the same method of building a wav file content as the creator of the WAVFile class uses.
Does anyone have any suggestions?

C#
class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("hi");
            WAVFile audioFile = new WAVFile();
            string warning = audioFile.Open("11.wav", WAVFile.WAVFileMode.READ);

            short[] audioSample = new short[audioFile.NumSamples];
            if (warning == "")
            {
                for (int sampleNum = 0; sampleNum < audioFile.NumSamples; ++sampleNum)
                {
                    audioSample[sampleNum] = audioFile.GetNextSampleAs16Bit();
                }
            }
            InternalWAVFile iwf = new InternalWAVFile(audioSample, audioFile.IsStereo, audioFile.SampleRateHz, audioFile.BitsPerSample);
            MemoryStream ms = iwf.GetStream();

            if (null == ms)
                Console.WriteLine("stream is null");
            else
            {
                Console.WriteLine("Not null");
                Audio a = new Audio();
                Console.WriteLine("Going to play");
                a.Play(ms, Microsoft.VisualBasic.AudioPlayMode.Background);
                Console.WriteLine("Played");
            }
        }
    }
Posted
Updated 6-Oct-16 3:41am
Comments
shubhangi waghmare 28-Aug-13 5:38am    
Where is WaveFile Class.Above code giving error..

First of all, address this problem to the author of the article Nightfox. At the button of the article page, click "New Message" — the author will receive notification.

—SA
 
Share this answer
 
hello
you must to write close function for stream. It must have data size.
C#
public InternalWAVFile(short[] samples, bool pStereo, int pSampleRateHz, short pBitsPerSample)
       {
           if (mMemoryStream != null)
           {
               mMemoryStream.Close();
               mMemoryStream.Dispose();
               mMemoryStream = null;
           }

           mMemoryStream = new MemoryStream();
           mStereo = pStereo;
           mSampleRateHz = pSampleRateHz;
           mBitsPerSample = pBitsPerSample;

           Create();

           foreach (short s in samples)
           {
               byte[] buffer = BitConverter.GetBytes(s);
               if (!BitConverter.IsLittleEndian)
                   Array.Reverse(buffer);
               AddSample_ByteArray(buffer);
           }
           // File size: Offset 4, 4 bytes
           mMemoryStream.Seek(4, 0);
           // Note: Per the WAV file spec, we need to write file size - 8 bytes.
           // The header is 44 bytes, and 44 - 8 = 36, so we write
           // mDataBytesWritten + 36.
           // 2009-03-17: Now using FileSizeBytes - 8 (to avoid mDataBytesWritten).
           //mFileStream.Write(BitConverter.GetBytes(mDataBytesWritten+36), 0, 4);
           int size = (int)FileSizeBytes - 8;
           byte[] buffer2 = BitConverter.GetBytes(size);
           if (!BitConverter.IsLittleEndian)
               Array.Reverse(buffer2);
           mMemoryStream.Write(buffer2, 0, 4);
           // Data size: Offset 40, 4 bytes
           mMemoryStream.Seek(40, 0);
           //mFileStream.Write(BitConverter.GetBytes(mDataBytesWritten), 0, 4);
           size = (int)(FileSizeBytes - mDataStartPos);
           buffer2 = BitConverter.GetBytes(size);
           if (!BitConverter.IsLittleEndian)
               Array.Reverse(buffer2);
           mMemoryStream.Write(buffer2, 0, 4);
           mMemoryStream.Seek(0, 0);
          // mMemoryStream.Close();
       }
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900