Thursday, March 10, 2011

Write Wave Files

In the previous post was shown, how to read in Wave files byte by byte. Now I want to show, how to write them.
So this post is a complete reverse of the previous one, I will show how to write a previously read in Wave file again to the hard disk.
In the previous post I explained the structure and other basics about Wave files, so I here just post briefly the source code of 2 functions, with which the class WaveFile can be extended.
The principle is analogous to reading, one by one the 3 blocks "RIFF", "fmt " and "data" are written to a file.

        public void StoreWave(string path)
        {
            System.IO.FileStream fs = System.IO.File.OpenWrite(path); // open target file
            StoreChunk(fs, "RIFF"); // write RIFF chunk
            StoreChunk(fs, "fmt "); // write fmt chunk
            StoreChunk(fs, "data"); // write data chunk
        }

        private void StoreChunk(System.IO.FileStream fs, string chunkID)
        {
            System.Text.ASCIIEncoding Decoder = new ASCIIEncoding();
            // convert the name in bytes and write it
            fs.Write(Decoder.GetBytes(chunkID), 0, 4);

            if (chunkID == "RIFF")
            {
                // in the RIFF chunk, write FileSize and the audio format
                fs.Write(System.BitConverter.GetBytes(FileSize), 0, 4);
                fs.Write(Decoder.GetBytes(Format), 0, 4);
            }
            if (chunkID == "fmt ")
            {
                // in the fmt chunk, write its size as well as the other information
                fs.Write(System.BitConverter.GetBytes(FmtChunkSize), 0, 4);
                fs.Write(System.BitConverter.GetBytes(AudioFormat), 0, 2);
                fs.Write(System.BitConverter.GetBytes(NumChannels), 0, 2);
                fs.Write(System.BitConverter.GetBytes(SampleRate), 0, 4);
                fs.Write(System.BitConverter.GetBytes(ByteRate), 0, 4);
                fs.Write(System.BitConverter.GetBytes(BlockAlign), 0, 2);
                fs.Write(System.BitConverter.GetBytes(BitsPerSample), 0, 2);
            }
            if (chunkID == "data")
            {
                // in the data chunk, write the size of the data block
                fs.Write(System.BitConverter.GetBytes(DataSize), 0, 4);
                // then write the single samples for all audio channels 
                for (int i = 0; i < Data[0].Length; i++)
                {
                    for (int j = 0; j < NumChannels; j++)
                    {
                        fs.Write(System.BitConverter.GetBytes(Data[j][i]), 0, BlockAlign / NumChannels);
                    }
                }
            }
        }

A sample implementation, which reads in a Wave file and eventually writes it again to another file, could look as follows:

WaveFile WF1 = new WaveFile();
WF1.LoadWave(@"C:\Users\User\Desktop\mix.wav");
WF1.StoreWave(@"C:\Users\User\Desktop\stored.wav");

No comments:

Post a Comment