一、何为声音
中学物理中我们知道,声音是物体振动产生的声波。声音通过介质(空气、固体、液体)传入到人耳中,带动听小骨振动,经过一系列的神经信号传递后,被人所感知。
声音是一种波。物体振动时会使介质(如空气)产生疏密变化,从而形成疏密相见的纵波。
既然声音是波,那么我们就可以用图的形式来表示它。
给定空间中某一点,该点的空气疏密随时间的变化如下:
波形图
下图是一个正弦波,其周期为0.002s,频率为500HZ。
频率(音调)
:声音1秒内周期性变化的次数
人耳的听觉范围在20Hz-20kHz。 低频的声音沉闷厚重,高频的声音尖锐刺耳。 高于 20kHz的声音为超声波。
振幅(响度)
:声音的大小
有的时候,我们用分贝(dB)形容声音大小。值得注意的是,dB是一个比值,是一个数值,没有任何单位标注。(功率强度之比的对数的10倍)
音调
:声音频率的高低叫做音调(Pitch),是声音的三个主要的主观属性,即音量(响度)、音调、音色(也称音品) 之一。表示人的听觉分辨一个声音的调子高低的程度。音调主要由声音的频率决定,同时也与声音强度有关
同等条件下,波长(频率)是决定音调高低的因素。
音量
:人主观上感觉声音的大小(俗称音量),由“振幅”(amplitude)和人离声源的距离决定,振幅越大响度越大,人和声源的距离越小,响度越大。(单位:分贝dB)
音色
:又称声音的品质,波形决定了声音的音色。声音因不同物体材料的特性而具有不同特性,音色本身是一种抽象的东西,但波形是把这个抽象直观的表现。音色不同,波形则不同。典型的音色波形有方波,锯齿波,正弦波,脉冲波等。不同的音色,通过波形,完全可以分辨的。
同等条件下,振幅是决定音量高低的因素。
同等条件下,波纹是决定音色因素。
通过上面简单的分析,我们已经知道声音的音量实际上就是由声波的振幅决定的,我们需要调整声波的振幅。播放一个视频,需要经历下面几步:
- 输入视频url
- 确定视频的封装格式
- 开始解封装
- 识别视频的轨道数据
- 分离轨道数据,音频轨道、视频轨道
解码视频数据为原始数据,解码音频数据为原始数据
- 做好音视频同步
- 渲染视频原始数据,播放音频原始数据
上面加黑标红的部分就是我们改变声音振幅的地方,只有将声音数据解码为原始数据,我们加工原始数据的音频流,然后送到AudioTrack或者OpenSL ES内部播放即可。
二、音频合成与分解
波的合成
波的分解
三、声音采集和存储
为了将模拟信号数字化,主要分为三个部分,采样,量化和编码
采样
:就是在时间轴上对信号进行数字化。根据奈奎斯特定律(也称为采样定理)
,按比声音最高频率2倍以上的频率对声音进行采样(也称为AD转换),对于高频率的音频信号,其频率范围(人耳能够听到的频率范围)是20Hz~20kHz
,所以采样频率一般为44.1kHz,这样就可以保证采样声音达到20kHz也能被数字化,从而使得经过数字化处理后,人耳听到声音质量不会被降低。而所谓的44.1kHz就是代表1秒会采样44100次。
量化
:量化是指在幅度轴上对信号进行数字化,比如用16比特的二进制信号来表示声音的一个采样,而16比特(一个short)所表示的范围是[-32768, 32767],共有65536个可能取值,因此最终模拟的音频信号在幅度上也分为了65536层。
编码
:所谓编码,就是按照一定的格式记录采样和量化后的数字数据,比如顺序或压缩存储,等等。
四、PCM存储
4.1、什么是PCM
PCM(Pulse Code Modulation,脉冲编码调制)音频数据是未经压缩的音频采样数据裸流
,它是由模拟信号经过采样、量化、编码转换成的标准数字音频数据。
描述PCM数据的6个参数:
1、Sample Rate
: 采样频率。8kHz(电话)、44.1kHz(CD)、48kHz(DVD)。
2、Sample Size
: 量化位数。通常该值为16bit。量化位数是音频文件的另一个参数。量化位数越大,声音的质量越高。常用的量化位数有8位、16位和32位。量化位数指用几位二进制数来存储采样获得的数据。量化位数为8,即指用8位二进制数来存储数据,如00010111。
3、Number of Channels
: 通道个数。常见的音频有立体声(stereo)和单声道(mono)两种类型,立体声包含左声道和右声道。另外还有环绕立体声等其它不太常用的类型。
4、Sign
: 表示样本数据是否是有符号位,比如用一字节表示的样本数据,有符号的话表示范围为-128 ~ 127,无符号是0 ~ 255。
5、Byte Ordering
: 字节序。字节序是little-endian还是big-endian。通常均为little-endian。字节序说明见第4节。
6、Integer Or Floating Point
: 整形或浮点型。大多数格式的PCM样本数据使用整形表示,而在一些对精度要求高的应用方面,使用浮点类型表示PCM样本数据。
以CD的音质为例:量化格式(有的地点描述为位深度)为16比特(2字节),采样率为44100,声道数为2,这些信息就表述了CD的音质。而对于声音格式,还有一个概念用来描述它的大小,称为数据比特率
,即1s内时间内的比特数目,它用于衡量音频数据单位时间内的容量大小。而对于CD音质的数据,比特率为多少了?计算如下:
44100 * 16 * 2 = 1378.125kbps
那么在1分钟内,这类CD音质的数据需要占据多大的存储空间?计算如下:
1378.125 * 60 / 8 / 1024 = 10.09MB
推荐的PCM数据播放工具:
1、ffplay, 使用示例如下:
//播放格式为f32le,单声道,采样频率48000Hz的PCM数据
ffplay -f f32le -ac 1 -ar 48000 pcm_audio
2、Audacity:一款免费开源的跨平台音频处理软件。
4.2、PCM数据格式
如果是单声道的音频文件,采样数据按时间的先后顺序依次存入(有的时候也会采用LRLRLR方式存储,只是另一个声道的数据为0),如果是双声道的话就按照LRLRLR的方式存储,存储的时候与字节序有关。big-endian模式如下图所示:
4.3、声道数
声道分为单声道与双声道。
单声道即为左右耳听到的声音相同。
双声道两耳听到的信息不同。相同的声音时间、采样频率和比特率的情况下,双声道文件的存储空间是单声道的两倍。但其会给人空间感,游戏和电影中常采用双声道,可达到“听声辨位”的效果。
示例声音如下:
4.4、PCM转WAV
public class PcmToWavUtil {
private int mBufferSize; //缓存的音频大小
private int mSampleRate = 8000;// 8000|16000
private int mChannelConfig = AudioFormat.CHANNEL_IN_STEREO; //立体声
private int mChannelCount = 2;
private int mEncoding = AudioFormat.ENCODING_PCM_16BIT;
public PcmToWavUtil() {
this.mBufferSize = AudioRecord.getMinBufferSize(mSampleRate, mChannelConfig, mEncoding);
}
/**
* @param sampleRate sample rate、采样率
* @param channelConfig channel、声道
* @param encoding Audio data format、音频格式
*/
public PcmToWavUtil(int sampleRate, int channelConfig, int channelCount, int encoding) {
this.mSampleRate = sampleRate;
this.mChannelConfig = channelConfig;
this.mChannelCount = channelCount;
this.mEncoding = encoding;
this.mBufferSize = AudioRecord.getMinBufferSize(mSampleRate, mChannelConfig, mEncoding);
}
/**
* pcm文件转wav文件
*
* @param inFilename 源文件路径
* @param outFilename 目标文件路径
*/
public void pcmToWav(String inFilename, String outFilename) {
FileInputStream in;
FileOutputStream out;
long totalAudioLen;
long totalDataLen;
long longSampleRate = mSampleRate;
int channels = mChannelCount;
long byteRate = 16 * mSampleRate * channels / 8;
byte[] data = new byte[mBufferSize];
try {
in = new FileInputStream(inFilename);
out = new FileOutputStream(outFilename);
totalAudioLen = in.getChannel().size();
totalDataLen = totalAudioLen + 36;
writeWaveFileHeader(out, totalAudioLen, totalDataLen,
longSampleRate, channels, byteRate);
while (in.read(data) != -1) {
out.write(data);
}
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 加入wav文件头
*/
private void writeWaveFileHeader(FileOutputStream out, long totalAudioLen,
long totalDataLen, long longSampleRate, int channels, long byteRate)
throws IOException {
byte[] header = new byte[44];
header[0] = 'R'; // RIFF/WAVE header
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
header[4] = (byte) (totalDataLen & 0xff);
header[5] = (byte) ((totalDataLen >> 8) & 0xff);
header[6] = (byte) ((totalDataLen >> 16) & 0xff);
header[7] = (byte) ((totalDataLen >> 24) & 0xff);
header[8] = 'W'; //WAVE
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f'; // 'fmt ' chunk
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 16; // 4 bytes: size of 'fmt ' chunk
header[17] = 0;
header[18] = 0;
header[19] = 0;
header[20] = 1; // format = 1
header[21] = 0;
header[22] = (byte) channels;
header[23] = 0;
header[24] = (byte) (longSampleRate & 0xff);
header[25] = (byte) ((longSampleRate >> 8) & 0xff);
header[26] = (byte) ((longSampleRate >> 16) & 0xff);
header[27] = (byte) ((longSampleRate >> 24) & 0xff);
header[28] = (byte) (byteRate & 0xff);
header[29] = (byte) ((byteRate >> 8) & 0xff);
header[30] = (byte) ((byteRate >> 16) & 0xff);
header[31] = (byte) ((byteRate >> 24) & 0xff);
header[32] = (byte) (2 * 16 / 8); // block align
header[33] = 0;
header[34] = 16; // bits per sample
header[35] = 0;
header[36] = 'd'; //data
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte) (totalAudioLen & 0xff);
header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
out.write(header, 0, 44);
}
}
五、音频编码
几种常用的压缩编码格式
1、WAV编码
WAV编码就是在PCM(Pulse Code Modulation,脉冲编码调制)前面加了44字节,分别用来描述PCM的采样率、声道数、数据格式等信息。
特点:音质非常好,大量软件都支持
适用场景:多媒体开发的中间文件、保存音乐和音效素材
2、MP3编码
MP3具有不错的压缩比,使用LAME编码(MP3编码格式的一种实现)的中高码率的MP3文件,听感上非常接近源WAV文件,当然在不同的应用场景下,应该调整合适的参数以达到最好的效果。
特点:音质在128Kbit/s以上表现还不错,压缩比比较高,大量软件和硬件都支持,兼容性好。
适用场景:高比特率下对兼容性有要求的音乐。
3、AAC编码
AAC是新一代的音频有损压缩技术,它通过一些附加的编码技术(比如PS,SBR),衍生出了LC-AAC,HE-AAC,HE-AAC v2三种主要的编码格式。
特点:在小于128Kbit/s的码率下表现优异,并且多用于视频中的音频编码。
适用场合:128Kbit/s以下的音频编码,多用于视频中音频轨的编码。
4、Ogg编码
Ogg是一种非常有潜力的编码,在各种码率下都有比较优秀的表现,尤其是在低码率场景下。Ogg除了音质好之外,还是完全免费的,这为Ogg获得更多的支持打好了基础。Ogg有着非常出色的算法,可以用更小的码率达到更好的音质,128kbit/s的Ogg比192Kbit/s甚至更高码率的MP3还要出色。但目前还没有媒体服务软件的支持,因此基于Ogg的数字广播还无法实现。Ogg目前受支持的情况还不够好,无论是软件上还是硬件上的支持,都无法和MP3相提并论。
特点:可以用比MP3更小的码率实现比MP3更好的音质,高中低码率下均有良好的表现,兼容性不够好,流媒体特性不支持。
适用场合:语音聊天的音频消息场景。