音频基础知识

组成

音频文件的组成:文件格式(或者音频容器) + 数据格式(或者音频编码)。

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

我们可以通过多种不同的方法为真正的音频数据编码。例如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");
}
}

iOS 音频开发的更多相关文章

  1. IOS 音频开发文件大小计算

    音频基础知识 音频文件计算大小 音频转码 标签(空格分隔): 调查 IOS音频 https://developer.apple.com/library/ios/documentation/MusicA ...

  2. iOS音频开发系列-概述篇

    概述 iOS中对于音频的处理,苹果提供了两个库. AVFoundation AudioToolbox 在iOS系统中apple对上述的流程进行了封装并提供了不同层次的接口

  3. iOS 音频开发之CoreAudio

    转自:http://www.cnblogs.com/javawebsoa/archive/2013/05/20/3089511.html 接 触过IOS音频开发的同学都知道,Core Audio 是I ...

  4. 一篇对iOS音频比较完善的文章

    转自:http://www.cnblogs.com/iOS-mt/p/4268532.html 感谢作者:梦想通 前言 从事音乐相关的app开发也已经有一段时日了,在这过程中app的播放器几经修改我也 ...

  5. iOS多线程开发

    概览 大家都知道,在开发过程中应该尽可能减少用户等待时间,让程序尽可能快的完成运算.可是无论是哪种语言开发的程序最终往往转换成汇编语言进而解释成机器码来执行.但是机器码是按顺序执行的,一个复杂的多步操 ...

  6. 浅谈iOS视频开发

     浅谈iOS视频开发 这段时间对视频开发进行了一些了解,在这里和大家分享一下我自己觉得学习步骤和资料,希望对那些对视频感兴趣的朋友有些帮助. 一.iOS系统自带播放器 要了解iOS视频开发,首先我们从 ...

  7. 开发者经验谈:如何一天时间搞定iOS游戏开发?

    开发者经验谈:如何一天时间搞定iOS游戏开发? 在一天时间里将完成iPhone游戏开发由梦想变为现实? 本文作者给出了从创意转变成现实的详细答案.使用苹果原生游戏引擎SpriteKit,遵循一定的原则 ...

  8. 20个可以帮你简化iOS app开发流程的工具

    这里推荐20个可以帮你简化iOS app开发流程的工具.很多开发者都使用过这些工具,涉及原型和设计.编程.测试以及最后的营销,基本上涵盖了整个开发过程. 原型和设计 有了一个很好的创意后,你要做的不是 ...

  9. iOS音频处理

    ios音频处理 1. iOS底层音频处理技术(带源代码) http://www.cocoachina.com/ios/20111122/3563.html 2.ios 音频入门 http://blog ...

随机推荐

  1. POJ 2315:Football Game(博弈论)

    [题目链接] http://poj.org/problem?id=2315 [题目大意] 两名球员轮流从N个球中挑出不多于M个射门,每个球半径都是R,离球门S. 每次只能踢出L以内的距离.进最后一个球 ...

  2. Java中泛型得到T.class

    例子: public class Test<T> { public Class<T> getTClass() { return (Class<T>) ((Param ...

  3. linux之touch命令修改文件的时间戳

    功能:对已经存在文件的时间进行修改,存取时间(access time).修改时间(modification time).对不存在的文件,进行创建新的空白文件. 语法:touch   [选项]  文件 ...

  4. Asp.Net生命周期和Http管道技术

    本篇主要介绍一下内容: 1.ASP.NET生命周期 2.Http运行时 3.Http管道技术 a)inetinfo.exe b)asp.net_isapi.dll c)aspnet_wp.exe d) ...

  5. js 的 slice方法

    slice() 方法可从已有的数组中返回选定的元素. string.slice( beginslice [, endSlice] ); 下面是参数的详细信息: beginSlice : 从零开始的索引 ...

  6. delphi 接口Interface

    学习 delphi 接口 一切都是纸老虎!!! 第四章          接口 前不久,有位搞软件的朋友给我出了个谜语.谜面是“相亲”,让我猜一软件术语.我大约想了一分钟,猜 出谜底是“面向对象”.我 ...

  7. scrapy-splash抓取动态数据例子九

    一.介绍 本例子用scrapy-splash抓取众视网网站给定关键字抓取咨询信息. 给定关键字:个性化:融合:电视 抓取信息内如下: 1.资讯标题 2.资讯链接 3.资讯时间 4.资讯来源 二.网站信 ...

  8. 用table表格来调整控件的格式

    由于想自己写一个web,所以也在学习html语言的一些东西,让我回忆起了大学时代曾对网页设计产生过兴趣,无奈那时候还没有自己的电脑,还常去网吧买个软盘下载一些图片,然后用fontpage做一些网页.后 ...

  9. asp.net 中点击button弹出模式对话框,选择值后返回到页面中(window.showModalDialog实现)

    <td>现从事专业</td><td>       <asp:TextBox ID="tbMajor" runat="server ...

  10. Struts2--百度百科

    Struts 2是Struts的下一代产品,是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架.其全新的Struts 2的体系结构与Struts 1的体系结构差别 ...