Wave文件編碼:保存文件

来源:http://www.cnblogs.com/ARCONICsoftwares/archive/2017/02/01/6359876.html
-Advertisement-
Play Games

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         }

運行圖片:

以及保存前後的文件(數據我做了反相處理)

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 好久沒有更新博客,算算時間,已經有4年了,好吧,今天突發奇想,想把今天安裝Windows 10的過程給記錄下來。 2015年的時候,微軟就發佈了Windows 10,當時正版的Win7、Win8都可以直接升級上來,但是當時Windows 10 問題重重,真心沒有興趣,也不敢升級。 這些天,看了不少關 ...
  • 資源組是由一個或多個資源組成的組,WSFC的故障轉移是以資源組為單位的,資源組中的資源是相互依賴的,相互關聯。一個資源所依賴的其他資源必須和該資源處於同一個資源組,跨資源組的依賴關係是不存在的。在任何時候,每個資源組都僅屬於集群中的一個結點,該結點就是資源組的活躍結點,由活躍結點為應用程式提供服務。 ...
  • #!/bin/bashexport chknum=1 #shell攪拌存放目錄(輸出日誌文件執行後也存於該目錄)echo 3 > /wls/wls81/shellsyncwhile [ $chknum -ge 0 ]doecho " " >> trace.logmt=`free | tr [:bla ...
  • 隱藏技能 在當前路徑打開命令行 點擊文件夾內的空白處,你會看到右鍵彈出菜單多了個選項 “在此處打開命令視窗”,省去了打開命令行再cd到當前路徑的麻煩。 快捷鍵 打開快捷菜單 : 視窗操作菜單 : 常用自帶程式 打開命令行 : 輸入 打開服務管理器 : 輸入 打開註冊表管理器 : 輸入 ...
  • 要發送HTML格式郵件,需要設置MailMessage對象的IsBodyHtml屬性,設置為true。類MailMessage在命名空間System.Net.Mail下。using System.Net.Mail;發送HTML格式的郵件在HoverTreeTop項目中已經實現,併發送成功。需依賴於H ...
  • 首先,需要在資料庫中創建一個表,以在test資料庫創建tableNo表為例: 然後在資料庫中 --> 可編程性 --> 存儲過程 --> 新建存儲過程 ,也可以在sql中執行代碼如下: 其次在.NET中的DAL層創建一個CommonService類,代碼如下: using System.Data; ...
  • INotifyPropertyChanged 在WPF MVVM模式開發中,實現INotifyPropertyChanged的ViewModel是非常重要且常見的類: 在類里,需要響應變化的屬性都需要在Setter里調用屬性變化的方法: 這樣的寫法,一個兩個屬性還好,在有很多屬性的情況下,就顯得有一 ...
  • 首先需要引用命名空間 ,同時也需要右擊'引用' --> '添加引用' --> '程式集' --> '框架' --> 'System.Configuration',SqlHelper屬於三層中的DAL層: using System.Data; using System.Data.SqlClient; ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...