zoukankan      html  css  js  c++  java
  • C#实现Wav文件截取、淡入淡出处理(PCM 格式)

    因工具需要 对 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     }
  • 相关阅读:
    模块化工具require 学习笔记
    学习Jade模板引擎
    通过border来实现各种三角符号
    使用vscode 编译 sass
    Javascript 运行机制
    Vue调试工具 vue-devtools
    MVVM框架
    通信类
    面向对象
    原型和原型链
  • 原文地址:https://www.cnblogs.com/ryhan/p/2453988.html
Copyright © 2011-2022 走看看