iOS 音頻開發

?

音頻基礎知識

組成

音頻文件的組成:文件格式(或者音頻容器) + 數據格式(或者音頻編碼)。

文件格式(或音頻容器)是用于形容文件本身的格式。

我們可以通過多種不同的方法為真正的音頻數據編碼。例如CAF文件便是一種文件格式,它能夠包含MP3格式,線性PCM以及其它數據格式的音頻。

數據格式(或音頻編碼)

我們將從音頻編碼開始闡述(而不是文件格式),因為編碼是最重要的環節。

線性PCM:

這是表示線性脈沖編碼調制,主要是描寫用于將模擬聲音數據轉換成數字格式的技術。簡單地說也就是未壓縮的數據。因為數據是未壓縮的,所以我們便可以最快速地播放出音頻,而如果空間不是問題的話這便是iPhone音頻的優先代碼選擇。

音頻文件計算大小


聲卡對聲音的處理質量可以用三個基本參數來衡量,即采樣頻率、采樣位數和聲道數。

采樣頻率:

是指單位時間內的采樣次數。采樣頻率越大,采樣點之間的間隔就越小,數字化后得到的聲音就越逼真,但相應的數據量就越大。聲卡一般提供11.025kHz、22.05kHz和44.1kHz等不同的采樣頻率。

采樣位數:

是記錄每次采樣值數值大小的位數。采樣位數通常有8bits或16bits兩種,采樣位數越大,所能記錄聲音的變化度就越細膩,相應的數據量就越大。

聲道數

是指處理的聲音是單聲道還是立體聲。單聲道在聲音處理過程中只有單數據流,而立體聲則需要左、右聲道的兩個數據流。顯然,立體聲的效果要好,但相應的數據量要比單聲道的數據量加倍。

聲音數據量的計算公式為:

數據量(字節/秒)= (采樣頻率(Hz)× 采樣位數(bit) × 聲道數)/ 8

單聲道的聲道數為1,立體聲的聲道數為2。

【例1】請計算對于5分鐘雙聲道、16位采樣位數、44.1kHz采樣頻率聲音的不壓縮數據量是多少?
根據公式:數據量=(采樣頻率×采樣位數×聲道數×時間)/8
得,數據量(MB)=[44.1×1000×16×2×(5×60)] /(8×1024×1024)=50.47MB
計算時要注意幾個單位的換算細節:
時間單位換算:1分=60秒
采樣頻率單位換算:1kHz=1000Hz
數據量單位換算:1MB=1024×1024=1048576B

【例2】請計算對于雙聲道立體聲、采樣頻率為44.1kHz、采樣位數為16位的激光唱盤(CD-A),用一個650MB的CD-ROM可存放多長時間的音樂?
已知音頻文件大小的計算公式如下:
文件的字節數/每秒=采樣頻率(Hz)X采樣位數(位)X聲道數/8
根據上面的公式計算一秒鐘時間內的不壓縮數據量:(44.1×1000×16×2)/8=0.168MB/s
那么,一個650MB的CD-ROM可存放的時間為:(650/0.168)/(60×60)=1.07小時。


iOS 音頻轉碼

音頻轉碼使用的框架為:AudioToolBox

內存轉碼:

使用函數: AudioConverterFillComplexBuffer
    - (void)handleAudioPackets:(const void *)inputData numberOfBytes:(UInt32)numberOfBytes numberOfPackets:(UInt32)numberOfPackets packetDescriptions:(AudioStreamPacketDescription *)packetDescriptions { if (!_audioFileStream || !_parseAudioHeader || !_decodeConverterRef) return; AudioConvertInfo convertInfo = (AudioConvertInfo){ .done = NO, .numberOfPackets = numberOfPackets, .packetDescriptions = packetDescriptions, .audioBuffer = (AudioBuffer){ .mData = (void *)inputData, .mDataByteSize = numberOfBytes, .mNumberChannels = _sourceAsbd.mChannelsPerFrame } }; AudioBufferList decodedData; decodedData.mNumberBuffers = 1; decodedData.mBuffers[0].mNumberChannels = _canonicalAsbd.mChannelsPerFrame; decodedData.mBuffers[0].mDataByteSize = _decodeBufferSize; decodedData.mBuffers[0].mData = _decodeBuffer; UInt32 ioOutputDataPackets1, ioOutputDataPackets2; OSStatus decodingStatus, encodingStatus; while (1) { ioOutputDataPackets1 = numberOfPackets; decodingStatus = AudioConverterFillComplexBuffer(_decodeConverterRef, AudioConverterCallback, (void*)&convertInfo, &ioOutputDataPackets1, &decodedData, NULL); if (decodingStatus == OS_STATUS_DONE || decodingStatus == 0) { if (ioOutputDataPackets1 > 0) { // Start encoding AudioConvertInfo encodeConvertInfo = (AudioConvertInfo){ .done = NO, .numberOfPackets = ioOutputDataPackets1, .packetDescriptions = NULL, .audioBuffer = (AudioBuffer){ .mData = decodedData.mBuffers[0].mData, .mDataByteSize = decodedData.mBuffers[0].mDataByteSize, .mNumberChannels = _canonicalAsbd.mChannelsPerFrame } }; AudioBufferList encodedData; encodedData.mNumberBuffers = 1; encodedData.mBuffers[0].mNumberChannels = _destinationAsbd.mChannelsPerFrame; encodedData.mBuffers[0].mDataByteSize = _encodeBufferSize; encodedData.mBuffers[0].mData = _encodeBuffer; while (1) { ioOutputDataPackets2 = _encodePacketsPerBuffer; encodingStatus = AudioConverterFillComplexBuffer(_encodeConverterRef, AudioConverterCallback, (void*)&encodeConvertInfo, &ioOutputDataPackets2, &encodedData, _encodePacketDescriptions); if (encodingStatus == OS_STATUS_DONE || encodingStatus == 0) { //一個buffer 轉碼成功 } else { [self failureOccurred]; return; } if (encodingStatus == OS_STATUS_DONE) { break; } } // End encoding } } else { [self failureOccurred]; return; } if (decodingStatus == OS_STATUS_DONE) { break; } } }

文件轉碼:

使用函數 ExtAudioFileRead
void startConvert(ExtAudioConverterSettings* settings){ //Determine the proper buffer size and calculate number of packets per buffer //for CBR and VBR format UInt32 sizePerBuffer = 32*1024;//32KB is a good starting point UInt32 framesPerBuffer = sizePerBuffer/sizeof(SInt16); // allocate destination buffer SInt16 *outputBuffer = (SInt16 *)malloc(sizeof(SInt16) * sizePerBuffer); while (1) { AudioBufferList outputBufferList; outputBufferList.mNumberBuffers = 1; outputBufferList.mBuffers[0].mNumberChannels = settings->outputFormat.mChannelsPerFrame; outputBufferList.mBuffers[0].mDataByteSize = sizePerBuffer; outputBufferList.mBuffers[0].mData = outputBuffer; UInt32 framesCount = framesPerBuffer; CheckError(ExtAudioFileRead(settings->inputFile, &framesCount, &outputBufferList), "ExtAudioFileRead failed"); if (framesCount==0) { printf("Done reading from input file\n"); return; } CheckError(ExtAudioFileWrite(settings->outputFile, framesCount, &outputBufferList), "ExtAudioFileWrite failed"); } }

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284316.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284316.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284316.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【ArcGIS微課1000例】0045:ArcGIS制圖模板的自定義與使用方法

怎樣在ArcGIS中保存地圖模板以在地圖制圖與打印之前使用呢? 文章目錄 一、地圖模板簡介二、地圖模板創建1. 創建模板2. 創建縮略圖3. 保存模板三、地圖模板使用一、地圖模板簡介 使用ArcMap打開一個已有的地圖模板,【文件】→【新建】,任選一個模板,這里選擇一個傳統模板。…

api 接口開發理論 在php中調用接口以及編寫接口

如:http://localhost/openUser.php?actget_user_list&typejson 在這里openUser.php相當于一個接口,其中get_user_list 是一個API(獲取用戶列表),講求返回的數據類型為JSON格式。 你只需要在你PHP代碼中執行這條鏈…

怎么樣的框架對于開發者是友好的?

云原生離.NET開發到底有多遠?云原生的概念由來不久,故事從“上云”開始,伴隨dorker、k8s等技術的推出,以及CNCF與各大云廠商的共同加持,云原生逐漸被大家所熟知。云原生不依賴具體的云,不管公有云還是私有云…

JS 燒腦面試題大賞

本文精選了20多道具有一定迷惑性的js題,主要考察的是類型判斷、作用域、this指向、原型、事件循環等知識點,每道題都配有詳細傻瓜式的解析,偏向于初學者,大佬請隨意。 第1題 let a 1 function b(a) {a 2console.log(a) } b(a)…

蘋果ios用js的Date()出現NaN問題解決辦法

原文:蘋果ios用js的Date()出現NaN問題解決辦法ios使用如下方法獲得NaN,安卓手機則是正常計算,解決方法是換個這個時間的格式 new Date("2017-04-28 23:59:59").getTime() 換成如下方式就正常了,就是‘-’換成…

Thinkphp 驗證碼、文件上傳

一、驗證碼 驗證碼參數 例題&#xff1a;登錄時驗證下驗證碼 LoginController.class.php <?php namespace Home\Controller; use Think\Controller; class LoginController extends Controller {public function Login(){if(empty($_POST)){$this->display(); } e…

ArcGIS實驗教程——實驗四十七:數據驅動頁工具批量制作甘肅省各地級市人口七普專題圖集

本實驗詳細講解利用ArcGIS數據驅動頁工具,制作甘肅省各地級市人口七普專題圖集。 文章目錄 1. 數據驅動頁工具簡介2. 甘肅省各地級市人口七普專題圖集2.1 符號化及標注2.2 數據驅動頁的創建2.3 數據驅動頁面文本操作2.4 數據驅動頁的導出1. 數據驅動頁工具簡介 數據驅動頁面是…

為什么Java有GC調優而沒聽說過有CLR的GC調優?

前言在很多的場合我都遇到過一些群友提這樣的一些問題&#xff1a;為什么Java有GC調優而CLR沒有聽說過有GC調優呢&#xff1f;到底是Java的JVM GC比較強還是C#使用的.NET CLR的GC比較強呢&#xff1f;其實業內已經有幾位大佬的高贊文章和大家分享一下&#xff0c;主要討論JVM和…

Ubuntu16.04 - 安裝RabbitVCS,linux下的TortoiseSVN!!!

RabbitVCS 官網&#xff1a;http://rabbitvcs.org/ 1&#xff0c;添加PPA源。在shell里面執行下面命令&#xff1a; sudo add-apt-repository ppa:rabbitvcs/ppa 這個命令執行完畢后&#xff0c;查看執行結果看是否密鑰導入成功&#xff0c;成功截圖&#xff1a; 如果導入密鑰失…

8 種最坑的SQL錯誤用法

1、LIMIT 語句 2、隱式轉換 3、關聯更新、刪除 4、混合排序 5、EXISTS語句 6、條件下推 7、提前縮小范圍 8、中間結果集下推 總結 sql語句的執行順序&#xff1a; FROM <left_table>ON <join_condition><join_type>JOIN <right_table>WHERE &…

Vue根據菜單json數據動態按需加載路由Vue-router

每個菜單項對應一個頁面組件&#xff0c;根據菜單項動態按需加載路由 路由配置的正確寫法&#xff1a; /*router/index.js*/ import Vue from vue import Router from vue-router import url from ./url import store from ../storeVue.use(Router)const router new Router({/…

【ArcGIS微課1000例】0047:制圖表達(2)---河流漸變效果的實現

當我們在ArcMap中加載河流數據時,得到的效果往往如圖所示,僅僅是表示河流位置的線要素,既無法真實地反映河流的實際情況,同時在出圖的時候也遠沒有任何美化效果。 文章目錄 1.創建制圖表達2.添加幾何效果3.使用制圖規則4.使用制圖表達屬性覆蓋警告:這些操作會對您的數據庫…

操作系統思考 第二章 進程

第二章 進程 作者&#xff1a;Allen B. Downey 原文&#xff1a;Chapter 2 Processes 譯者&#xff1a;飛龍 協議&#xff1a;CC BY-NC-SA 4.0 2.1 抽象和虛擬化 在我們談論進程之前&#xff0c;我打算先定義幾個東西&#xff1a; 抽象&#xff08;Abstraction&#xff09;&…

1 句代碼,搞定 ASP.NET Core 綁定多個源到同一個類

問題有群友希望將路由中的信息綁定到一個Dto對象中&#xff1a;public class DDDDDto {[FromRoute(Name "collectionId")]public Guid collectionId { get; set; }[BindProperty(Name "relativeUrl")]public string relativeUrl { get; set; } }這樣就不用…

redux中間件的用法

1.定義 中間件就是一個函數&#xff0c;對store.dispatch方法進行了改造&#xff0c;在發出 Action 和執行 Reducer 這兩步之間&#xff0c;添加了其他功能。 2.舉例 日志中間件 import { applyMiddleware, createStore } from redux; import createLogger from redux-logger; …

設置git自動補全功能(windows版本)

目錄 下載 Git 的源代碼 在目錄中 git/contrib/completion/ 中找到 git-completion.bash 文件 將 git-completion.bash 文件改名為 .git-completion.bash 找到本機git安裝目錄 將.git-completion.bash文件復制到git安裝目錄下的etc文件夾 打開同目錄下的 bash.bashrc 文件&…

用Vue搭建一個應用盒子(二):datetime-picker

接著上次的進度&#xff0c;我們已經實現了一個todo-list。它已經具備了基本的功能&#xff0c;可以新建、編輯、刪除任務。但是美中不足的是&#xff0c;它的時間設定上只能通過輸入一段字符串來設定&#xff0c;很不社會。我們應該完成的效果是一個time-picker&#xff0c;日…

ArcGIS實驗教程——實驗四十八:ArcGIS制圖表達入門及案例教程

文章目錄 1. 制圖表達的概念1.1 什么是地圖表達1.2 使用制圖表達改善要素外觀1.3 制圖表達的優點2. 使用制圖表達2.1 創建制圖表達2.2 使用制圖表達來符號化圖層2.3 使用制圖表達規則3. 地圖表達實戰案例1.創建制圖表達2.添加幾何效果3.使用制圖規則4.使用制圖表達屬性覆蓋1. 制…

PAT (Advanced Level) 1070. Mooncake (25)

簡單貪心。先買性價比高的。 #include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<stack> #include<queue> #include<string> #include<algorithm> using namespace std;doub…

[轉]Java 18 還未用上,Java 19 最新兩大特性曝光

鐵打的 Java&#xff0c;流水的版本。 不久前&#xff0c;Java 18 才正式發布&#xff0c;遵循 Oracle 六個月發一版本的頻率&#xff0c;Java 19 將在今年 9 月出爐。這不&#xff0c;還沒等眾多開發者用上 Java 18&#xff0c;關于 Java 19 最新的兩個目標功能就被披露了出…