因工具需要 對 Wav 文件做處理 包含轉格 截取 淡入淡出處理 ,此處將代碼記下 以備後用。
View Code
1 /// <summary>
2 /// 文件截取處理
3 /// </summary>
4 public class WavScissorHelper
5 {
6 public static bool GetWavFileScissor(string OriginalAudioFilePath, string DestinedAudioFilePath, int beginCutTime, int endCutTime, ref string errorInfo)
7 {
8 if (!File.Exists(OriginalAudioFilePath))
9 {
10 errorInfo = string.Format("源文件:[{0}]不存在!", OriginalAudioFilePath);
11 return false;
12 }
13 if (!Directory.Exists(Path.GetDirectoryName(DestinedAudioFilePath)))
14 {
15 errorInfo = string.Format("文件夾:[{0}]不存在!", Path.GetDirectoryName(DestinedAudioFilePath));
16 return false;
17 }
18 if ((beginCutTime < 0) || (endCutTime < 0)
19 || (beginCutTime > endCutTime))
20 {
21 errorInfo = string.Format("截取時間[{0}][{1}]有誤!", beginCutTime, endCutTime);
22 return false;
23 }
24 try
25 {
26 WavFile oldFile = new WavFile(OriginalAudioFilePath);
27 if (endCutTime > oldFile.PlayTime)
28 {
29 errorInfo = string.Format("結束截取時間[{0}]大於音頻文件播放時間[{1}]!", endCutTime, oldFile.PlayTime);
30 return false;
31 }
32 int timeSpan = endCutTime - beginCutTime;
33
34 WavFile newFile = new WavFile(DestinedAudioFilePath);
35 newFile.WavFormat = oldFile.WavFormat;
36
37 byte[] newAudioBytes = new byte[oldFile.WavFormat.ByteRate * timeSpan];
38 Array.Copy(oldFile.AudioDataBytes, oldFile.WavFormat.ByteRate * beginCutTime, newAudioBytes, 0, newAudioBytes.Length);
39
40 newFile.WriteWavFile(newAudioBytes);
41 return true;
42 }
43 catch (Exception e)
44 {
45 return false;
46
47 }
48 }
49
50 }
51
52 /// <summary>
53 /// 淡入淡出處理
54 /// </summary>
55 public class WavFadeHelper
56 {
57 private WavFile _wavFile;
58
59 public WavFadeHelper(string wavFilePath)
60 {
61 _wavFile = new WavFile(wavFilePath);
62 }
63
64
65 public bool FadeAtFirstSec(FadeMode fadeMode, long fadeLength)
66 {
67 return FadeAtSec(fadeMode, 0, fadeLength);
68 }
69
70 public bool FadeAtEndSec(FadeMode fadeMode, long fadeLength)
71 {
72 long totalTime = _wavFile.PlayTime;
73 if (totalTime < fadeLength)
74 fadeLength = totalTime;
75 long startTime = totalTime - fadeLength;
76
77 return FadeAtSec(fadeMode, startTime, startTime + fadeLength);
78 }
79
80 public bool FadeAtSec(FadeMode fadeMode, long startSec, long endSec)
81 {
82 //總播放時間
83 long totalTime = _wavFile.PlayTime;
84
85 //采樣位數
86 // 16 bit 縱坐標為采樣系數 細化為 2^16= 65535份 16位二進制表示 [ 0000 0000 0000 0000 ]
87 // 即為2Byte (每單位時間內產生 2Byte 的音頻數據)
88
89 int byteNumPerSample = _wavFile.WavFormat.BitsPerSample / 8;
90
91 //采樣頻率
92 // 11025Hz 橫坐標為采樣頻率 單位時間為: 1/11025 s
93 //單位時間內產生的的音頻數據大小為 2Byte * 11025Hz * 聲道數
94
95
96 //audioData 是按字節處理 16bit采樣 每次獲取兩個字節進行處理
97
98 //開始位置 存儲單元索引
99 long startIndex = startSec * byteNumPerSample * _wavFile.WavFormat.SampleRate;
100 if (startIndex % byteNumPerSample > 0)
101 startIndex -= startIndex % byteNumPerSample;
102
103 //結束位置 存儲單元索引
104 long endIndex = endSec * byteNumPerSample * _wavFile.WavFormat.SampleRate;
105 if (endIndex > _wavFile.AudioDataBytes.Length - 1)
106 endIndex = _wavFile.AudioDataBytes.Length - 1;
107
108 //字節數組 音頻數據
109 byte[] audioDatas = _wavFile.AudioDataBytes;
110
111 //初始衰減率
112 double rate = 1.0;
113
114 //對每個單位時間內的 樣點幅值 進行衰減
115 //從淡化開始時間到結束時間共有 [ 采樣頻率 * 時間段(s) * 采樣位數/8(Byte) ] 個存儲單元
116 //每次取出 采樣位數/8(Byte) 個存儲單元進行衰減
117
118 // i 的值為每次衰減處理時的 字節讀取位置 (索引)
119 for (int i = (int)startIndex; i < endIndex; i += byteNumPerSample)
120 {
121 //衰減率的方向與淡入淡出有關
122 //衰減率的大小與當前讀取處理字節的索引位置有關
123 if (fadeMode == FadeMode.FadeOut)
124 rate = (double)(endIndex - i) / (endIndex - startIndex);
125 else
126 rate = (double)(i - startIndex) / (endIndex - startIndex);
127
128 //單位時間內的字節數為1 即采用8bit采樣位數 每次只需要對一個字節進行衰減
129 if (byteNumPerSample == 1)
130 {
131 //獲取需要衰減的字節值
132 byte audioData = audioDatas[i];
133
134 //進行衰減線性處理
135 byte changedAudioData = (byte)((double)audioData * rate);
136 //byte changedAudioData = Convert.ToByte((double)audioData * rate);
137
138 //對原來的值進行更改
139 audioDatas[i] = changedAudioData;
140 }
141 else if (byteNumPerSample == 2)
142 {
143 //16bit 量化 每單位時間產生2Byte數據 因此取 2Byte 的數據進行衰減處理
144 byte[] audioData = new byte[2];
145 Array.Copy(audioDatas, i, audioData, 0, 2);
146
147 //單個樣點幅值
148 double sample = 0;
149
150 //轉換為整數進行線性處理
151 sample = (double)BitConverter.ToInt16(audioData, 0) * rate;
152
153 //轉換為字節存儲
154 byte[] buffer = BitConverter.GetBytes(Convert.ToInt16(sample));
155 if (!BitConverter.IsLittleEndian)
156 Array.Reverse(buffer);
157
158 Array.Copy(buffer, 0, audioDatas, i, 2);
159 }
160 }
161 _wavFile.WriteWavFile(audioDatas);
162
163 return true;
164 }
165 }
166
167 /// <summary>
168 /// 淡入淡出模式
169 /// </summary>
170 public enum FadeMode
171 {
172 FadeIn,
173 FadeOut
174 }
175
176 /// <summary>
177 /// WAV 文件
178 /// </summary>
179 public class WavFile
180 {
181 private WavFormat _wavFormat; //文件格式
182 private long _fileLength; //文件長度
183 private string _filePath; //文件路徑
184 private byte[] _audioData; //語音數據
185
186 private WavFile() { }
187 public WavFile(string filePath)
188 {
189 _filePath = filePath;
190 }
191
192 /// <summary>
193 /// 文件格式
194 /// </summary>
195 public WavFormat WavFormat
196 {
197 get
198 {
199 if (_wavFormat == null)
200 _wavFormat = GetWavFormat();
201
202 return _wavFormat;
203 }
204 set { _wavFormat = value; }
205 }
206
207 /// <summary>
208 /// 文件大小
209 /// </summary>
210 public long FileLength
211 {
212 get
213 {
214 if (_wavFormat == null)
215 _wavFormat = GetWavFormat();
216
217 return _fileLength;
218 }
219 set { _fileLength = value; }
220 }
221
222 /// <summary>
223 /// 播放時長 www.2cto.com
224 /// </summary>
225 public long PlayTime
226 {
227 get
228 {
229 if (_wavFormat == null)
230 _wavFormat = GetWavFormat();
231
232 return _audioData.Length / _wavFormat.ByteRate;
233 }
234 }
235
236 /// <summary>
237 /// 語音數據
238 /// </summary>
239 public byte[] AudioDataBytes
240 {
241 get
242 {
243 if (_wavFormat == null)
244 _wavFormat = GetWavFormat();
245
246 return _audioData;
247 }
248 set { _audioData = value; }
249 }
250
251 /// <summary>
252 /// 設置Wav文件格式
253 /// </summary>
254 /// <param name="bitsPerSample">采樣位數</param>
255 /// <param name="channels">聲道數</param>
256 /// <param name="sampleRate">采樣率</param>
257 public void SetWavFormat(int bitsPerSample, int channels, int sampleRate)
258 {
259 _wavFormat = new WavFormat();
260 _wavFormat.BitsPerSample = bitsPerSample;
261 _wavFormat.Channels = channels;
262 _wavFormat.SampleRate = sampleRate;
263 }
264
265 /// <summary>
266 /// 寫文件
267 /// </summary>
268 /// <param name="audioData">音頻數據</param>
269 public void WriteWavFile(byte[] audioData)
270 {
271 WriteWavFile(_wavFormat, audioData, 0, audioData.Length);
272 }
273
274 /// <summary>
275 /// 寫文件
276 /// </summary>
277 /// <param name="wavFormat">文件格式</param>
278 /// <param name="audioData">音頻數據</param>
279 /// <param name="startIndex">audioData數組開始索引位置</param>
280 /// <param name="length">寫入audioData數組長度</param>
281 public void WriteWavFile(WavFormat wavFormat, byte[] audioData, int startIndex, int length)
282 {
283 FileStream fs = null;
284 BinaryWriter bw = null;
285 try
286 {
287 fs = new FileStream(_filePath, FileMode.Create, FileAccess.Write);
288 bw = new BinaryWriter(fs);
289 fs.Position = 0;
290 bw.Write(new char[4] { 'R', 'I', 'F', 'F' });
291 //ChunkFileSize
292 bw.Write((int)(length + 44 - 8));
293 bw.Write(new char[8] { 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' });
294 bw.Write((int)16);
295 bw.Write((short)1);
296 bw.Write((short)wavFormat.Channels);
297 bw.Write(wavFormat.SampleRate);
298 bw.Write((int)(wavFormat.SampleRate * ((wavFormat.BitsPerSample * wavFormat.Channels) / 8)));
299 bw.Write((short)((wavFormat.BitsPerSample * wavFormat.Channels) / 8));
300 bw.Write((short)wavFormat.BitsPerSample);
301 bw.Write(new char[4] { 'd', 'a', 't', 'a' });
302 bw.Write(length);
303 bw.Write(audioData, startIndex, length);
304 }
305 finally
306 {
307 if (bw != null)
308 bw.Close();
309 if (fs != null)
310 {
311 fs.Close();
312 fs.Dispose();
313 }
314 }
315 }
316
317 /// <summary>
318 /// 獲取Wav文件格式
319 /// </summary>
320 /// <returns></returns>
321 private WavFormat GetWavFormat()
322 {
323 FileStream fs = null;
324 BinaryReader br = null;
325 WavFormat wavFormat = new WavFormat();
326
327 try
328 {
329 fs = new FileStream(_filePath, FileMode.Open, FileAccess.Read);
330 br = new BinaryReader(fs);
331
332 _fileLength = fs.Length;
333
334 fs.Position = 22;
335 wavFormat.Channels = br.ReadInt16();
336 fs.Position = 24;
337 wavFormat.SampleRate = br.ReadInt32();
338 fs.Position = 28;
339 wavFormat.ByteRate = br.ReadInt32();
340 fs.Position = 34;
341 wavFormat.BitsPerSample = br.ReadInt16();
342
343 //The audio data
344 fs.Position = 44;
345 int dataByteSize = (int)(fs.Length - 44);
346 if (_audioData == null)
347 _audioData = new byte[dataByteSize];
348 fs.Read(_audioData, 0, dataByteSize);
349
350 }
351 finally
352 {
353 if (br != null)
354 br.Close();
355 if (fs != null)
356 {
357 fs.Close();
358 fs.Dispose();
359 }
360 }
361 return wavFormat;
362 }
363 }
364
365 /// <summary>
366 /// WAV 文件格式
367 /// </summary>
368 public class WavFormat
369 {
370 /// <summary>
371 /// 采樣位數
372 /// </summary>
373 public int BitsPerSample;
374 /// <summary>
375 /// 聲道數
376 /// </summary>
377 public int Channels;
378 /// <summary>
379 /// 采樣率
380 /// </summary>
381 public int SampleRate;
382 /// <summary>
383 /// 傳輸速率(播放速率)
384 /// </summary>
385 public long ByteRate;
386 }
摘自 MyNewID