日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android音频开发(4):如何存储和解析wav文件

發布時間:2024/9/21 Android 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android音频开发(4):如何存储和解析wav文件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

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

?

wav 格式,與 bitmap 一樣,都是微軟開發的一種文件格式規范,它們都有一個相似之處,就是整個文件分為兩部分,第一部分是“文件頭”,記錄重要的參數信息,對于音頻而言,就包括:采樣率、通道數、位寬等等,對于圖像而言,就包括:圖像的寬高、色彩位數等等;第二部分是“數據塊”,即一幀一幀的二進制數據,對于音頻而言,就是原始的 PCM 數據;對于圖像而言,就是 RGB 數據。

?

前面幾篇文章講了如何利用?Android?平臺的 API 完成原始音頻信號的采集和播放,而本文則重點關注如何在 Android 平臺上,將采集到的 PCM 音頻數據保存到 wav 文件,同時,也介紹如何讀取和解析 wav 文件。

?

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

?

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

?

1. 文件頭

?

首先,我們了解一下 wav 格式的“文件頭”,可以參考這篇文章:《WAVE PCM soundfile format》

?

?

我們可以簡單地分析一下這個 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?<lujun.hust@gmail.com>

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

?*???

?*??@license?under?the?Apache?License,?Version?2.0?

?*

?*??@file????WavFileHeader.java

?*??

?*??@version?1.0?????

?*??@author??Jhuster

?*??@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 音頻相關技術,代碼地址:

?

https://github.com/Jhuster/AudioDemo

?

注:本系列文章的所有代碼,以后都會并入到該 demo 項目中。

?

3. 小結

?

免費學習更多精品課程,登錄樂搏學院官網http://h.learnbo.cn/

或關注我們的官方微博微信,還有更多驚喜哦~

本文出自 “Jhuster的專欄” 博客,請務必保留此出處http://ticktick.blog.51cto.com/823160/1750593

轉載于:https://my.oschina.net/learnbo/blog/761182

總結

以上是生活随笔為你收集整理的Android音频开发(4):如何存储和解析wav文件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。