|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES
// OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// � 2007 Gary W. Schwede and Stream Computers, Inc. All rights reserved.
// Contact: gary at streamcomputers dot com. Permission to incorporate
// all or part of this code in your application is given on the condition
// that this notice accompanies it in your code and documentation.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Forms;
using StreamComputers.Utilities;
namespace StreamComputers.Riff
{
/// <summary>
/// RiffWaveWriter assembles a RIFF WAVE file to be written to disk, sets properties,
/// and exposes methods for writing data to the file. Construct an instance of
/// RiffWaveWriter and keep it around until the application is finished writing the file,
/// then call Close() to clean up its resources.
/// </summary>
public sealed class RiffWaveWriter : RiffWaveManager
{
private BinaryWriter m_Writer = null;
#region properties
public WaveFormatTag FormatTag
{
get { return m_FormatTag; }
set { m_FormatTag = value; }
}
public short Channels
{
get { return m_Channels;}
set { m_Channels = value; }
}
public int SamplesPerSecond
{
get { return m_SamplesPerSecond;}
set { m_SamplesPerSecond = value; }
}
public int AverageBytesPerSecond
{
get { return m_AverageBytesPerSecond;}
set { m_AverageBytesPerSecond = value; }
}
public short BlockAlign
{
get { return m_BlockAlign;}
set { m_BlockAlign = value; }
}
public short BitsPerSample
{
get { return m_BitsPerSample;}
set { m_BitsPerSample = value; }
}
public long StreamLength
{
get { return m_StreamLength;}
set { m_StreamLength = value; }
}
public long DataStart
{
get { return m_DataStart;}
set { m_DataStart = value; }
}
public long DataLength
{
get { return m_DataLength;}
set { m_DataLength = value; }
}
#endregion
public RiffWaveWriter(string fileName)
{
try
{
m_Stream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite);
DebugConsole.WriteLine("Set Wave properties for new file!");
}
catch (Exception e)
{
MessageBox.Show("RiffWaveWriter(string fileName) failed: " + e);
Cleanup();
ZeroAllInfo();
throw;
}
}
#region Methods to write RIFF WAVE files
// Failed to find valid data header, so zero out the header information.
private void ZeroAllInfo()
{
m_AverageBytesPerSecond = 0;
m_BitsPerSample = 0;
m_BlockAlign = 0;
m_Channels = 0;
m_DataLength = 0;
m_DataStart = 0;
m_FormatTag = 0;
m_SamplesPerSecond = 0;
m_StreamLength = 0;
}
/// <summary>
/// Sets properties to values appropriate for standard CD-quality
/// 16-bit 44.1KHz stereo samples
/// </summary>
public void SetCD16Info()
{
m_FormatTag = WaveFormatTag.Pcm;
m_Channels = 2;
m_SamplesPerSecond = 44100;
m_AverageBytesPerSecond = 44100*2*2;
m_BlockAlign = 2*2;
m_BitsPerSample = 16;
}
/// <summary>
/// Writes header information to RIFF WAVE file. Properties must be set
/// before call.
/// Leaves writer pointer at start of data field, and zeros m_DataLength.
/// </summary>
public void WriteHeader()
{
m_Writer = new BinaryWriter(m_Stream);
// uberheader
m_Writer.Write(EncodeChars("RIFF"));
Int32 i = 0; // placeholder for (filesize - 8)
m_Writer.Write(i); // byte position = 4
m_Writer.Write(EncodeChars("WAVE"));
// fmt chunk (without extra format bytes)
m_Writer.Write(EncodeChars("fmt "));
i = 16;
m_Writer.Write(i);
m_Writer.Write((short) m_FormatTag);
m_Writer.Write(m_Channels);
m_Writer.Write(m_SamplesPerSecond);
m_Writer.Write(m_AverageBytesPerSecond);
m_Writer.Write(m_BlockAlign);
m_Writer.Write(m_BitsPerSample);
// data chunk
m_Writer.Write(EncodeChars("data"));
i = 0; // placeholder for data length
m_Writer.Write(i); // byte position 0x28, 40 decimal
Debug.Assert(m_Stream.Position == 44);
m_DataLength = 0;
}
private byte[] EncodeChars(string s)
{
byte[] es = new byte[s.Length];
es = Encoding.ASCII.GetBytes(s);
return es;
}
/// <summary>
/// Appends PCM16Data frames to a RiffWaveWriter-managed file.
/// </summary>
/// <param name="buf">PCM16Frame[] buffer to write to file</param>
public void WritePCM16DataFrames(Pcm16Frame[] buf)
{
Debug.Assert(buf.Length <= Int32.MaxValue, "WritePCM16DataFrames called with buffer too big.");
int i = 0;
for (; i < buf.Length; i++)
{
m_Writer.Write(buf[i].Lch);
m_Writer.Write(buf[i].Rch);
}
m_DataLength += buf.Length*m_BlockAlign;
}
/// <summary>
/// Finishes writing chunk length fields to a RIFF WAVE file but does not close it.
/// </summary>
public void WriteFinal()
{
// RIFF spec wants uint, stream length is really a long
Debug.Assert(m_Writer.BaseStream.Length <= Int32.MaxValue,
"RiffWaveWriter.WriteFinal() saw file too big for an int32 length");
int size = (int) m_Writer.BaseStream.Length;
m_Writer.BaseStream.Position = 4;
m_Writer.Write(size - 8);
m_Writer.BaseStream.Position = 40;
m_Writer.Write(m_DataLength);
}
#endregion
#region Finalization
// Flushes and closes the file and releases resources.
public override void Close()
{
Dispose();
}
protected override void Cleanup()
{
try
{
if(m_Writer != null)
{
m_Writer.Flush();
m_Writer.Close();
}
}
finally
{
base.Cleanup();
}
}
#endregion
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
My life and career have been a bit unusual (mostly in good ways). So, I'm grateful every day for the opportunities God's given me to do different things and see different aspects of life.
Education: B.S. Physics '73 (atmospheric physics, sounding rockets), M.S. Computer Science '76 (radio astronomy, fuzzy controllers, music pattern recognition and visualization) New Mexico Tech; Ph.D. Engineering '83 (parallel computer architecture, digital signal processing, economics) U.C. Berkeley.
I'm married to Susan, a wonderful woman whom I met in a Computer Architecture class at U.C. Berkeley.
Professional activities: Digital systems engineer, digital audio pioneer, founder or key in several tech startups, consulting engineer, expert witness. I'm currently developing a multithreading framework in C# .NET, that makes it almost easy to write correct programs for multicore processors. I'm also implementing a new transform for recognizing, editing, and processing signals, especially sound.
I'm an occasional essayist, public speaker, and podcaster, and free-market space advocate. I enjoy good wine, good music, good friends, and cats.
If you think your project could use a different point of view, I'm available for consulting work in the San Francisco Bay area, or (preferrably) via the net.