WAVE文件格式是微軟RIFF規範的一個實例(用來存儲多媒體文件),RIFF文件頭由連續的chunk組成。WAVE文件是由一個大的"WAVE" chunk組成,這個大的chunk由一個”fmt”chunk和一個”data”chunk組成。
標準WAVE文件格式
這篇的目的是把多個WAVE文件合成爲一個只有一個文件頭,並把每個數據合併起來的文件。
WAVE的文件頭符合標準的RIFF文件結構。頭8字節由chunk ID爲”RIFF”和chunk size組成。
所以我們需知道合成後文件的chunk size、numchannels、samplerate和bitspersample。
代碼:
private void WaveHeaderIN(string spath)
{
FileStream fs = new FileStream(spath, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
length = (int)fs.Length - 8;
fs.Position = 22;
channels = br.ReadInt16();
fs.Position = 24;
samplerate = br.ReadInt32();
fs.Position = 34;
BitsPerSample = br.ReadInt16();
DataLength = (int)fs.Length - 44;
br.Close ();
fs.Close();
}
numchannels位於 WAVE文件第22位開始,並且有2字節。所以我們可以在第22位使用br.ReadInt16()來讀取到channels中。其它一樣。
合成文件的頭結構
代碼:
private void WaveHeaderOUT(string sPath)
{
FileStream fs = new FileStream(sPath, FileMode.Create, FileAccess.Write );
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(new char[4] { 'R', 'I', 'F', 'F' });
bw.Write(length);
bw.Write(new char[8] {'W','A','V','E','f','m','t',' '});
bw.Write((int)16);
bw.Write((short)1);
bw.Write(channels);
bw.Write(samplerate );
bw.Write((int)(samplerate * ((BitsPerSample * channels) / 8)));
bw.Write((short )((BitsPerSample * channels) / 8));
bw.Write(BitsPerSample);
bw.Write(new char[4] {'d','a','t','a'});
bw.Write(DataLength);
bw.Close();
fs.Close();
}
注意寫文件頭時要小心些。如果有些差錯,合成文件就沒法運行了。所以這裏我們用一組char類型來寫“RIFF“,而不是string。使用int類型存儲4個字節,使用short存儲2字節。
把所有文件的數據寫進合成文件中
public void Merge(string[] files, string outfile)
{
WaveIO wa_IN = new WaveIO();
WaveIO wa_out = new WaveIO();
wa_out.DataLength = 0;
wa_out.length = 0;
//Gather header data
foreach (string path in files)
{
wa_IN.WaveHeaderIN(@path);
wa_out.DataLength += wa_IN.DataLength;
wa_out.length += wa_IN.length;
}
//Reconstruct new header
wa_out.BitsPerSample = wa_IN.BitsPerSample;
wa_out.channels = wa_IN.channels;
wa_out.samplerate = wa_IN.samplerate;
wa_out.WaveHeaderOUT(@outfile);
foreach (string path in files)
{
FileStream fs = new FileStream(@path, FileMode.Open, FileAccess.Read);
byte[] arrfile = new byte[fs.Length - 44];
fs.Position = 44;
fs.Read(arrfile, 0, arrfile.Length);
fs.Close();
FileStream fo =
new FileStream(@outfile, FileMode.Append, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(fo);
bw.Write(arrfile);
bw.Close();
fo.Close();
}
}
首先我們得先計算輸出文件總長度和所有文件的數據長度,然後指定輸出文件的channels、samplerate和bitspersample,最後一件事情就是讀取所有文件的數據存儲到合成文件的44位後
現在我們需要做的就是調用Merge方法,並指定輸入和輸出文件。
代碼:
string[] files = new string[2] { @"C:/WINDOWS/Media/Windows XP Startup.wav",
@"C:/WINDOWS/Media/Windows XP Shutdown.wav" };
WaveIO wa = new WaveIO();
wa.Merge(files,@"c:/oou.wav");
播放合成文件:
Visual Studio 2005提供給我們一個播放聲音的類,因此我們不需要API和其它的東東.
代碼:
FileStream fs = new FileStream(@"c:/oou.wav", FileMode.Open,FileAccess.Read);
System.Media.SoundPlayer sp = new System.Media.SoundPlayer(fs);
sp.Play();
fs.Close();