Channel的音頻引擎是我自己寫的,保存文件一直想找開源庫但就是找不著。。 於是就有了以下簡單粗暴打點辦法: 首先是WAV的文件格式: 起始地址 占用空間 本地址數字的含義 00H 4byte RIFF,資源交換文件標誌。 04H 4byte 從下一個地址開始到文件尾的總位元組數。高位位元組在後面,這 ...
Channel的音頻引擎是我自己寫的,保存文件一直想找開源庫但就是找不著。。
於是就有了以下簡單粗暴打點辦法:
首先是WAV的文件格式:
起始地址 |
占用空間 |
本地址數字的含義 |
00H |
4byte |
RIFF,資源交換文件標誌。 |
04H |
4byte |
從下一個地址開始到文件尾的總位元組數。高位位元組在後面,這裡就是001437ECH,換成十進位是1325036byte,算上這之前的8byte就正好1325044byte了。 |
08H |
4byte |
WAVE,代表wav文件格式。 |
0CH |
4byte |
FMT ,波形格式標誌 |
10H |
4byte |
00000010H,16PCM,用16bit的數據表示一個量化結果。 |
14H |
2byte |
為1時表示線性PCM編碼,大於1時表示有壓縮的編碼。這裡是0001H。 |
16H |
2byte |
1為單聲道,2為雙聲道,這裡是0001H。 |
18H |
4byte |
採樣頻率,這裡是00002B11H,也就是11025Hz。 |
1CH |
4byte |
Byte率=採樣頻率*音頻通道數*每次採樣得到的樣本位數/8,00005622H,也就是22050Byte/s=11025*1*16/2。 |
20H |
2byte |
塊對齊=通道數*每次採樣得到的樣本位數/8,0002H,也就是2=1*16/8。 |
22H |
2byte |
樣本數據位數,0010H即16,一個量化樣本占2byte。 |
24H |
4byte |
data,一個標誌而已。 |
28H |
4byte |
Wav文件實際音頻數據所占的大小,這裡是001437C8H即1325000,再加上2CH就正好是1325044,整個文件的大小。 |
2CH |
不定 |
量化數據。 |
於是我們可以反著來,做一個寫WAV的方法
1 namespace Channel.Core 2 { 3 public class WriteWAVFile 4 { 5 #region Public_Properties 6 7 public enum WaveBitFormat 8 { 9 Bit8=1, 10 Bit16=2, 11 Bit32=4 12 } 13 public WaveBitFormat Waveformat { get; set; } 14 public float[] Data { get; set; } 15 public string Path { get; set; } 16 public bool zipped { get; set; } 17 public int zipObject { get; set; } 18 19 #endregion 20 21 #region MainMethod 22 23 public void WriteWave() 24 { 25 FileStream fs = new FileStream(Path, FileMode.OpenOrCreate); 26 //StreamWriter sw = new StreamWriter(fs); 27 fs.Position = 0; 28 29 //寫入‘riff’文件標記 30 byte[] riff = new byte[4]; 31 riff[0]= Convert.ToByte(82); 32 riff[1] = Convert.ToByte(73); 33 riff[2] = Convert.ToByte(70); 34 riff[3] = Convert.ToByte(70); 35 fs.WriteByte(riff[0]);//fs.Position++; 36 fs.WriteByte(riff[1]); //fs.Position++; 37 fs.WriteByte(riff[2]); //fs.Position++; 38 fs.WriteByte(riff[3]); //fs.Position++; 39 40 41 //寫入文件長度 42 System.Numerics.BigInteger len = 0; 43 len = (int)Waveformat * Data.Length + 36; 44 byte[] length = len.ToByteArray(); 45 if(length.Count()==4) 46 { 47 fs.WriteByte(length[0]); //fs.Position++; 48 fs.WriteByte(length[1]); //fs.Position++; 49 fs.WriteByte(length[2]); //fs.Position++; 50 fs.WriteByte(length[3]); //fs.Position++; 51 } 52 else if (length.Count() == 3) 53 { 54 fs.WriteByte(length[0]); //fs.Position++; 55 fs.WriteByte(length[1]); //fs.Position++; 56 fs.WriteByte(length[2]); //fs.Position++; 57 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 58 } 59 else if(length.Count()==2) 60 { 61 fs.WriteByte(length[0]); //fs.Position++; 62 fs.WriteByte(length[1]); //fs.Position++; 63 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 64 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 65 } 66 67 //寫入“wave fmt” 68 fs.WriteByte(Convert.ToByte(87)); //fs.Position++; 69 fs.WriteByte(Convert.ToByte(65)); //fs.Position++; 70 fs.WriteByte(Convert.ToByte(86)); //fs.Position++; 71 fs.WriteByte(Convert.ToByte(69)); //fs.Position++; 72 73 fs.WriteByte(Convert.ToByte(102)); //fs.Position++; 74 fs.WriteByte(Convert.ToByte(109)); //fs.Position++; 75 fs.WriteByte(Convert.ToByte(116)); //fs.Position++; 76 fs.WriteByte(Convert.ToByte(32)); //fs.Position++; 77 78 //寫入播放位數 79 switch (Waveformat ) 80 { 81 case WaveBitFormat.Bit8: 82 fs.WriteByte(Convert.ToByte(8)); //fs.Position++; 83 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 84 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 85 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 86 break; 87 case WaveBitFormat.Bit16: 88 fs.WriteByte(Convert.ToByte(16)); //fs.Position++; 89 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 90 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 91 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 92 break; 93 case WaveBitFormat.Bit32: 94 fs.WriteByte(Convert.ToByte(32)); //fs.Position++; 95 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 96 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 97 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 98 break; 99 default: 100 break; 101 } 102 103 //是否壓縮 104 if(zipped) 105 { 106 fs.WriteByte(Convert.ToByte(zipObject)); //fs.Position++; 107 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 108 } 109 else 110 { 111 fs.WriteByte(Convert.ToByte(1)); //fs.Position++; 112 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 113 } 114 115 //聲道 116 if(ChannelCount==1 ) 117 { 118 fs.WriteByte(Convert.ToByte(1)); //fs.Position++; 119 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 120 } 121 else 122 { 123 fs.WriteByte(Convert.ToByte(2)); //fs.Position++; 124 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 125 } 126 127 //採樣頻率 預設 0000AC44H (44100) 128 System.Numerics.BigInteger fre = 0; 129 fre = Frequency; 130 byte[] freq = fre.ToByteArray(); 131 if (freq.Count() == 4) 132 { 133 fs.WriteByte(freq[0]); //fs.Position++; 134 fs.WriteByte(freq[1]); //fs.Position++; 135 fs.WriteByte(freq[2]); //fs.Position++; 136 fs.WriteByte(freq[3]); //fs.Position++; 137 } 138 else if (freq.Count() == 3) 139 { 140 fs.WriteByte(freq[0]); //fs.Position++; 141 fs.WriteByte(freq[1]); //fs.Position++; 142 fs.WriteByte(freq[2]); //fs.Position++; 143 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 144 } 145 else if (freq.Count() == 2) 146 { 147 fs.WriteByte(freq[0]); //fs.Position++; 148 fs.WriteByte(freq[1]); //fs.Position++; 149 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 150 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 151 } 152 153 //Freq*Channel*Bit/8 154 System.Numerics.BigInteger res11 = 0; 155 res11 = Frequency*(int)Waveformat*ChannelCount; 156 byte[] res1 = res11.ToByteArray(); 157 if (res1.Count() == 4) 158 { 159 fs.WriteByte(res1[0]); //fs.Position++; 160 fs.WriteByte(res1[1]); //fs.Position++; 161 fs.WriteByte(res1[2]); //fs.Position++; 162 fs.WriteByte(res1[3]); //fs.Position++; 163 } 164 else if (res1.Count() == 3) 165 { 166 fs.WriteByte(res1[0]); //fs.Position++; 167 fs.WriteByte(res1[1]); //fs.Position++; 168 fs.WriteByte(res1[2]); //fs.Position++; 169 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 170 } 171 else if (res1.Count() == 2) 172 { 173 fs.WriteByte(res1[0]); //fs.Position++; 174 fs.WriteByte(res1[1]); //fs.Position++; 175 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 176 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 177 } 178 179 //channel*bit/8 180 System.Numerics.BigInteger res22 = 0; 181 res22 =(int)Waveformat * ChannelCount; 182 byte[] res2 = res22.ToByteArray(); 183 if (res2.Count() == 2) 184 { 185 fs.WriteByte(res2[0]); //fs.Position++; 186 fs.WriteByte(res2[1]); //fs.Position++; 187 } 188 else if (res2.Count() == 1) 189 { 190 fs.WriteByte(res2[0]); //fs.Position++; 191 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 192 } 193 194 //位數(沒錯要寫兩遍) 195 switch (Waveformat) 196 { 197 case WaveBitFormat.Bit8: 198 fs.WriteByte(Convert.ToByte(8)); //fs.Position++; 199 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 200 break; 201 case WaveBitFormat.Bit16: 202 fs.WriteByte(Convert.ToByte(16)); //fs.Position++; 203 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 204 break; 205 case WaveBitFormat.Bit32: 206 fs.WriteByte(Convert.ToByte(32));// fs.Position++; 207 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 208 break; 209 default: 210 break; 211 } 212 213 //data標記 214 fs.WriteByte(Convert.ToByte(100)); //fs.Position++; 215 fs.WriteByte(Convert.ToByte(97)); //fs.Position++; 216 fs.WriteByte(Convert.ToByte(116)); //fs.Position++; 217 fs.WriteByte(Convert.ToByte(97)); //fs.Position++; 218 219 //數據大小 220 len = (int)Waveformat * Data.Length; 221 byte[] lengthD = len.ToByteArray(); 222 if (lengthD.Count() == 4) 223 { 224 fs.WriteByte(lengthD[0]); //fs.Position++; 225 fs.WriteByte(lengthD[1]); //fs.Position++; 226 fs.WriteByte(lengthD[2]); //fs.Position++; 227 fs.WriteByte(lengthD[3]); //fs.Position++; 228 } 229 else if (lengthD.Count() == 3) 230 { 231 fs.WriteByte(lengthD[0]); //fs.Position++; 232 fs.WriteByte(lengthD[1]); //fs.Position++; 233 fs.WriteByte(lengthD[2]); //fs.Position++; 234 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 235 } 236 else if (lengthD.Count() == 2) 237 { 238 fs.WriteByte(lengthD[0]); //fs.Position++; 239 fs.WriteByte(lengthD[1]); //fs.Position++; 240 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 241 fs.WriteByte(Convert.ToByte(0)); //fs.Position++; 242 } 243 244 //數據 245 foreach (float dataitem in Data) 246 { 247 byte[] target32; 248 byte[] target16; 249 target32 = BitConverter.GetBytes(dataitem); 250 int i =Convert.ToInt32( dataitem * 32768); 251 //string h16 = i.ToString("X"); 252 //string h161=h16.Substring(4, 4); 253 target16 = BitConverter.GetBytes(i); 254 255 switch (Waveformat) 256 { 257 case WaveBitFormat.Bit8: 258 //fs.WriteByte(Convert.ToByte(8)); fs.Position++; 259 //fs.WriteByte(Convert.ToByte(0)); fs.Position++; 260 break; 261 case WaveBitFormat.Bit16: 262 fs.WriteByte(target16[0]); //fs.Position++; 263 fs.WriteByte(target16[1]); //fs.Position++; 264 break; 265 case WaveBitFormat.Bit32: 266 fs.WriteByte(target32[0]); //fs.Position++; 267 fs.WriteByte(target32[1]); //fs.Position++; 268 fs.WriteByte(target32[2]); //fs.Position++; 269 fs.WriteByte(target32[3]); //fs.Position++; 270 break; 271 default: 272 break; 273 } 274 } 275 276 //Ending 277 fs.Flush(); 278 fs.Close(); 279 } 280 281 #endregion 282 public int ChannelCount { get; set; } 283 public int Frequency { get; set; } 284 } 285 }
看代碼中的註釋就知道用處了
下麵是如何調用:
1 private void saveToolStripMenuItem_Click(object sender, EventArgs e) 2 { 3 SaveFileDialog o = new SaveFileDialog(); 4 o.ShowDialog(); 5 Channel.Core.WriteWAVFile ww = new Core.WriteWAVFile();//新建實例 6 ww.ChannelCount = 1;//聲道數 7 ww.Data = wavePainterExtended1.DataProperty;//數據 8 ww.Frequency = 44100;//採樣頻率 9 ww.Path = o.FileName;//保存位置 10 ww.Waveformat = Core.WriteWAVFile.WaveBitFormat.Bit16;//16bit 11 ww.zipObject = 1;//空值 12 ww.zipped = false;//不壓縮 13 ww.WriteWave();//執行 14 }
運行圖片:
以及保存前後的文件(數據我做了反相處理)