1. 程式人生 > >Android音訊開發(4):如何儲存和解析wav檔案

Android音訊開發(4):如何儲存和解析wav檔案

無論是文字、影象還是聲音,都必須以一定的格式來組織和儲存起來,這樣播放器才知道以怎樣的方式去解析這一段資料,例如,對於原始的影象資料,我們常見的格式有 YUV、Bitmap,而對於音訊來說,最簡單常見的格式就是 wav 格式了。

wav 格式,與 bitmap 一樣,都是微軟開發的一種檔案格式規範,它們都有一個相似之處,就是整個檔案分為兩部分,第一部分是“檔案頭”,記錄重要的引數資訊,對於音訊而言,就包括:取樣率、通道數、位寬等等,對於影象而言,就包括:影象的寬高、色彩位數等等;第二部分是“資料塊”,即一幀一幀的二進位制資料,對於音訊而言,就是原始的 PCM 資料;對於影象而言,就是 RGB 資料。

前面幾篇文章講了如何利用 Android 平臺的 API 完成原始音訊訊號的採集和播放,而本文則重點關注如何在 Android 平臺上,將採集到的 PCM 音訊資料儲存到 wav 檔案,同時,也介紹如何讀取和解析 wav 檔案。

而文章最後,我還會給出一段 AudioDemo 程式,該程式將最近的幾篇文章涉及到的程式碼綜合起來了,演示了一個完整的 Android 音訊從採集到播放的全過程。

下面言歸正傳,講講如何讀寫 wav 檔案格式。

1. 檔案頭

wKioL1btPw_xefJSAABiQscQxNA841.png

我們可以簡單地分析一下這個 wav 格式頭,它主要分為三個部分:

第一部分,屬於最“頂層”的資訊塊,通過“ChunkID”來表示這是一個 “RIFF”格式的檔案,通過“Format”填入“WAVE”來標識這是一個 wav 檔案。而“ChunkSize”則記錄了整個 wav 檔案的位元組數。

第二部分,屬於“fmt”資訊塊,主要記錄了本 wav 音訊檔案的詳細音訊引數資訊,例如:通道數、取樣率、位寬等等(含義請參考我的第一篇文章《Android音訊開發(1):基礎知識》

第三部分,屬於“data”資訊塊,由“Subchunk2Size”這個欄位來記錄後面儲存的二進位制原始音訊資料的長度。

分析到這裡,我想大家應該就明白了,其實,做一種多媒體格式的解析,也不是一件特別複雜的事,說白了,格式就是一種規範,告訴你,我的二進位制資料是怎麼儲存的,你應該按照什麼樣的方式來解析。

具體而言,我們可以定義一個如下的 Java 類來抽象和描述 wav 檔案頭:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

/*

*  COPYRIGHT NOTICE  

*  Copyright (C) 2016, Jhuster <[email protected]>

*  https://github.com/Jhuster/AudioDemo

*   

*  @license under the Apache License, Version 2.0 

*

*  @file    WavFileHeader.java

*  

*  @date    2016/03/19

*/

package com.jhuster.audiodemo.api;

public class WavFileHeader {    

public String mChunkID = "RIFF";

public int mChunkSize = 0;    

public String mFormat = "WAVE";

public String mSubChunk1ID = "fmt ";

public int mSubChunk1Size = 16;

public short mAudioFormat = 1;    

public short mNumChannel = 1;

public int mSampleRate = 8000;

public int mByteRate = 0;

public short mBlockAlign = 0;

public short mBitsPerSample = 8;

public String mSubChunk2ID = "data";

public int mSubChunk2Size  = 0;

public WavFileHeader() {

}

public WavFileHeader(int sampleRateInHz, int bitsPerSample, int channels) {          

mSampleRate = sampleRateInHz;

mBitsPerSample = (short)bitsPerSample;

mNumChannel = (short)channels;                

mByteRate = mSampleRate*mNumChannel*mBitsPerSample/8;

mBlockAlign = (short)(mNumChannel*mBitsPerSample/8);

}

}

具體每一個欄位的含義,可以參考我上面給出的連結,下面我們再看看如何讀寫 wav 檔案。

2. 讀寫 wav 檔案

文章開頭已經說過,其實說白了,wav 檔案就是一段“檔案頭”+“音訊二進位制資料”,因此:

(1)寫 wav 檔案,其實就是先寫入一個 wav 檔案頭,然後再繼續寫入音訊二進位制資料即可

(2)讀 wav 檔案,其實也就是先讀一個 wav 檔案頭,然後再繼續讀出音訊二進位制資料即可

那麼,在動手寫程式碼之前,有兩點你需要搞清楚:

(1) wav 檔案頭中,有哪些是“變化的”,哪些是“不變的”?

比如:檔案頭開頭的“RIFF”字串就是“不變的”部分,而用來記錄音訊資料總長度的“Subchunk2Size”變數就是屬於“變化的”部分,因為,再音訊資料沒有徹底全部寫完之前,你是無法知道一共寫入了多少位元組的音訊資料的,因此,這個部分,需要用一個變數記錄起來,到全部寫完之後,再使用 Java 的“RandomAccessFile”類,將檔案指標跳轉到“Subchunk2Size”欄位,改寫一下預設值即可。

(2) 如何把 int、short 變數與 byte[] 的轉換

因為 wav 檔案都是二進位制的方式讀寫,因此,“WavFileHeader”類中定義的變數都需要轉換為byte位元組流,具體轉換方法如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

private static byte[] intToByteArray(int data) {

return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(data).array();

}

private static byte[] shortToByteArray(short data) {

return ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(data).array();

private static short byteArrayToShort(byte[] b) {

return ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).getShort();

}

private static int byteArrayToInt(byte[] b) {

return ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).getInt();

}

關於 wav 檔案讀寫的類我已經幫大家“封裝”好了,並且結合著前面幾篇文章給出的音訊採集和播放的程式碼,完成了一個 AudioDemo 程式,放在我的 Github 上了,歡迎大家下載執行測試,然後結合著程式碼具體學習 Android 音訊相關技術,程式碼地址:

注:本系列文章的所有程式碼,以後都會併入到該 demo 專案中。

相關推薦

Android音訊開發4如何儲存解析wav檔案

無論是文字、影象還是聲音,都必須以一定的格式來組織和儲存起來,這樣播放器才知道以怎樣的方式去解析這一段資料,例如,對於原始的影象資料,我們常見的格式有 YUV、Bitmap,而對於音訊來說,最簡單常見的格式就是 wav 格式了。 wav 格式,與 bitmap 一樣,都是

Android音訊開發1基礎知識

Android音訊開發(1):基礎知識 導讀 人的說話頻率基本上為300Hz~3400Hz,但是人耳朵聽覺頻率基本上為20Hz~20000Hz。 對於人類的語音訊號而言,實際處理一般經過以下步驟: 人嘴說話——>聲電轉換——>抽樣(模數轉換)——>量化(將數字訊號用適當的數值表示)——&g

多媒體開發12解碼aac到wav檔案

簡單來說,aac是一種音訊編碼格式,需要解碼後才能用於音訊輸出。aac編碼格式,已經是一種很常見的音訊編碼格式,以至於很多系統都支援aac的編解碼,比如iOS上的AudioConverterRef介面、Android上的MediaCodec介面等。 但是,不要以為用了系統的介面就是用了硬體解碼,因為,這個系統

使用bottle進行web開發4HTTPError

instead bject hat red uil tle ott class not from bottle import error @error(404) def error404(error): return ‘Nothing here, sorry‘

tensorflow學習4儲存模型Saver.save()的引數命名機制以及restore並建立手寫字型識別引擎

前言 上一章中我們講到如何訓練一個網路,點選檢視部落格,這章我們來講tensorflow在儲存網路的時候是怎麼給不同的引數命名的,以及怎麼將儲存的引數重新restore到重構的網路結構中的。最後利用重構的網路去預測一張包含數字(0-9)的圖片(任意畫素)。

Android專案開發4-忘記密碼---驗證碼驗證頁面功能實現

任務描述 根據所學知識點完成 1、實現activity_forget.xml佈局檔案 2、實現activity_forget.java程式碼檔案中的如下功能: --2.1點選獲取驗證碼,按鈕自動開始3

ArcGISEngine二次開發4屬性查詢2

屬性查詢(2) 使用IGeometry介面TrackPolygon方法建立物件實現屬性查詢 使用ISpatialFilter介面SpatialRel屬性定義Intersects取交集為查詢物件 之後將查詢到的(FindField方法)屬性顯示在新的wind

ONVIF協議網路攝像機IPC客戶端程式開發4使用gSOAP生成Web Services框架程式碼

1. 專欄導讀 本專欄第一篇文章「專欄開篇」列出了專欄的完整目錄,按目錄順序閱讀,有助於你的理解,專欄前面文章講過的知識點(或程式碼段),後面文章不會贅述。為了節省篇幅,突出重點,在文章中展示的示例程式碼僅僅是關鍵程式碼,你可以在「專欄開篇」中獲取完整程式碼。

android Bluetooth 開發開啟、關閉、搜尋、允許搜尋、檢視

相關專案的下載連結繼本專案之後實現了語音識別:點選開啟連結1.承接上一篇文章,本篇文章主要實現了藍芽的開啟 關閉 允許搜尋 檢視配對裝置2. BluetoothInit,主要實現了部件的初始化,按鈕的點選事件,通過ListVIew顯示本地配對的藍芽裝置,ListView的點選

~雜記4阿里華為rtos 的接管中斷邏輯探索

1、首先在某晶片的啟動檔案中,給出的中斷向量表全是指向同一個函式。(一開始我以為是錯的,自己改成各個預設中斷服務函式的入口,這樣就成了非接管中斷)。 部分程式碼如下,其中irq_handler就是那個統一的中斷服務函式。他被定義在排程檔案los_dispatch中。 __Vectors:

四國軍棋引擎開發4子力判斷局面評估初步

1.子力判斷 子力判斷在局面評估中起著非常重要的作用,在前一篇文章中已經介紹了子力判斷的部分,那時相對還比較粗糙,這次會更細緻的分析並優化上一次的不足。 pLineup->type用來代表棋子的型別,這裡是用列舉變數來表示,要注意級別大的變數值小,如40的值是5,39的值是6,

pytorch學習筆記儲存載入模型

# 儲存和載入整個模型 torch.save(model_object, 'model.pkl') model = torch.load('model.pkl') # 僅儲存和載入模型引數(推薦使

Performanced C++ 經驗規則4靜態多型,亦敵亦友

這一篇,我們討論C++中靜態和多型的關係。我們都知道,C++並不是一門“動態”語言,雖然它提供了同樣強大於其它動態語言的多型性,但很多時候,我們之所以選擇C++,看重中正是其“靜態”所帶來的High Performance。所謂靜態,通常是指,在程式執行的過程,是“靜止”不變,固定的(特別是記憶體地

使用Eclipse RCP進行桌面程式開發檢視透檢視

Eclipse RCP開發中,和使用者進行互動最多的介面,應該是檢視了,而透檢視就是將已有的檢視、選單、工具欄、編輯器等等進行組合和佈局。看完這一節,我們就可以建立如下圖這樣的程式介面了。 首先我們來介紹一下檢視,建立一個檢視其實非常簡單,只要從org.eclipse.ui

Android開發2資料儲存之一SharedPrefrences檔案讀寫

一、資料儲存 本文主要講前兩種儲存方式,其中檔案讀寫只記錄Internal Storage方式 1. SharedPrefrences方式 輕量級NVP方式儲存,以XML的檔案方式儲存,適合少量資料的儲存。 NVP:Name/Value pair, 名稱/值 對。 2.

Android-影象識別專案OpenCV4開發思路以及問題

六、開發思路   搭建好環境和做好各種準備功夫,接下來就開始我們的開發之路。   首先,我們先檢視一下官方教程文件,看有沒有我們需要的例子。我找到了一個二維影象識別的例子:      這個教程是用C++寫的,用計算特徵點來比對兩幅影象。如果我們用這個演算法可得到特徵點的匹

即時通訊音視訊開發音訊基礎及編碼原理入門

前言 即時通訊應用中的實時音視訊技術,幾乎是IM開發中的最後一道高牆。原因在於:實時音視訊技術 = 音視訊處理技術 + 網路傳輸技術 的橫向技術應用集合體,而公共網際網路不是為了實時通訊設計的。 系列文章 《即時通訊音視訊開發(五):認識主流視訊編碼技術H.264》 《即時

即時通訊音視訊開發如何開始音訊編解碼技術的學習

前言 即時通訊應用中的實時音視訊技術,幾乎是IM開發中的最後一道高牆。原因在於:實時音視訊技術 = 音視訊處理技術 + 網路傳輸技術 的橫向技術應用集合體,而公共網際網路不是為了實時通訊設計的。 系列文章 《即時通訊音視訊開發(四):視訊編解碼之預測技術介紹》 《即時通訊音

iOS開發簡記4錄音AVAudioRecorder

fail pst 記錄 通道 cdn amp enabled 廣州 指定 錄音,聲音的采集,一般有兩種實現辦法,一是使用AVAudioRecorder,一是使用AudioUnit。如果只是簡單的錄音,使用AVAudioRecorder就可以了,如果想更靈活地處理剛錄到的聲音

Android studio3.0對於百度地圖api開發4——百度地圖地圖覆蓋物製作

       承接上文未完的繼續介紹,上文內容:https://blog.csdn.net/qq_41562408/article/details/82810484主要實現百度地圖的定位以及對於地圖覆蓋物進行簡單介紹,這篇文章便是對於地圖覆蓋物進行,經過閱讀開發文件,我們會發