因工具需要 对 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 /// 播放时长 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 }