数字音频技术入门指南
数字音频技术入门指南
声音是由物体振动产生的物理现象。当物体发生振动时,其周围的空气压强会随之产生周期性变化,这种压强变化以波动的形式向周围传播,当传播到人耳时就被感知为声音。
波形特性
声音源于物体的振动,这种振动导致周围空气压强发生振荡,我们将这种振荡的数学表现形式称为波形

频率与采样
频率是周期的倒数,表示每秒内周期性变化的次数,单位为赫兹(Hz)。例如1000Hz表示每秒振动1000次。
| 声波类型 | 频率范围(单位Hz) |
|---|---|
| 次声波 | 0~20 |
| 可听声 | 20~20K |
| 超声波 | 20K~1G |
| 特超声波 | 1G~10T |
采样定理:采样频率需至少为信号频率的两倍
麦克风采集模拟信号20KHz → AD转换 → 计算机采样频率40KHz(常用48KHz、44.1KHz)→DA转换→扬声器播放
量化精度
每个采样点的数据位数,常用8bit、16bit、24bit
声道配置
单声道、双声道、3声道、4声道、6声道等
音频帧
音频帧的概念相对模糊,视频编码中可简单理解为一帧就是编码后的一幅图像
帧长定义:(1)每帧包含的采样点数及播放时长,例如mp3采用48k采样率,每帧包含1152个采样点,时长约2ms;aac每帧包含1024个采样点。累积够一帧数据后才进行编码处理 (2)也可指压缩后每帧的数据长度。
持续时间(秒) = 采样点数 / 采样频率 (HZ)
数据存储模式
交错存储:按帧顺序连续存放,先记录第1帧的左声道和右声道样本,再记录下一帧
| L | R | L | R | L | R | ... |
|---|
非交错存储:先记录一个周期内所有帧的左声道样本,再记录所有右声道样本
| L | L | L | ... | R | R | R |
|---|
Android音频开发
AudioRecord实现
在Android平台,通过android.media.AudioRecord类可以实现高度自定义的录音功能,采集到的是原始PCM格式数据
/**
* 音频录制器构造函数
* @param audioSource 录音音源类型
* 取值范围见MediaRecorder.AudioSource定义
* @param sampleRateInHz 采样率(赫兹)
* 44100Hz是唯一在所有设备上保证可用的采样率
* 其他如22050、16000、11025等可能在部分设备上不支持
* 使用SAMPLE_RATE_UNSPECIFIED则使用路由相关的默认值
* 可通过getSampleRate()获取实际选用的采样率
* @param channelConfig 声道配置
* 可选CHANNEL_IN_MONO(单声道)或CHANNEL_IN_STEREO(立体声)
* CHANNEL_IN_MONO在所有设备上保证可用
* @param audioFormat 返回音频数据的格式
* 可选ENCODING_PCM_8BIT、ENCODING_PCM_16BIT、ENCODING_PCM_FLOAT
* @param bufferSizeInBytes 缓冲区大小(字节)
* 录音过程中音频数据写入此缓冲区
* 可从此缓冲区读取小于此大小的数据块
* 可通过getMinBufferSize()获取创建实例所需的最小缓冲区大小
* 小于最小值将导致初始化失败
* @throws IllegalArgumentException 参数无效时抛出
*/
public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
audioSource: 录音音源配置
package android.media;
public class MediaRecorder implements AudioRouting,
AudioRecordingMonitor,
AudioRecordingMonitorClient,
MicrophoneDirection{
//内部音频源枚举类
public final class AudioSource {
private AudioSource() {}
//系统默认音源
public static final int DEFAULT = 0;
//主麦克风
public static final int MIC = 1;
//上行语音(对方可听到)
public static final int VOICE_UPLINK = 2;
//下行语音(自己可听到)
public static final int VOICE_DOWNLINK = 3;
//通话录音(双方声音)
public static final int VOICE_CALL = 4;
//录像机麦克风(与前置摄像头同向)
public static final int CAMCORDER = 5;
//语音识别专用
public static final int VOICE_RECOGNITION = 6;
//通话时摄像头旁的麦克风
public static final int VOICE_COMMUNICATION = 7;
//远程混音
public static final int REMOTE_SUBMIX = 8;
//未处理音频
public static final int UNPROCESSED = 9;
//语音表演
public static final int VOICE_PERFORMANCE = 10;
//回声参考
public static final int ECHO_REFERENCE = 1997;
//收音机调谐器
public static final int RADIO_TUNER = 1998;
//热词检测
public static final int HOTWORD = 1999;
//超声波
public static final int ULTRASOUND = 2000;
}
}
sampleRateInHz:采样率参数,决定每秒采集的音频样本数量
44100Hz是唯一确保所有设备支持的采样率,但22050、16000、11025等值在部分设备上也能正常工作
channelConfig: 声道配置常量,单声道使用CHANNEL_IN_MONO,立体声使用CHANNEL_IN_STEREO
//左前置声道
public static final int CHANNEL_IN_LEFT = 0x4;
//右前置声道
public static final int CHANNEL_IN_RIGHT = 0x8;
//前置声道
public static final int CHANNEL_IN_FRONT = 0x10;
//后置声道
public static final int CHANNEL_IN_BACK = 0x20;
//单声道等同于前置声道
public static final int CHANNEL_IN_MONO = CHANNEL_IN_FRONT;
//立体声为左右声道组合
public static final int CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT);
audioFormat: 量化位数配置,决定每个采样点的数据精度,推荐使用ENCODING_PCM_16BIT
public final class AudioFormat implements Parcelable {
//-----------------
//常量定义
//--------------------
//无效的音频数据格式
public static final int ENCODING_INVALID = 0;
//默认音频数据格式
public static final int ENCODING_DEFAULT = 1;
//需与core/jni/android_media_AudioFormat.h保持同步
//同时需与av/services/audiopolicy/managerdefault/ConfigParsingUtils.h同步
//PCM 16位每采样点,所有设备保证支持
public static final int ENCODING_PCM_16BIT = 2;
//PCM 8位每采样点,不保证所有设备支持
public static final int ENCODING_PCM_8BIT = 3;
//32位浮点每采样点
public static final int ENCODING_PCM_FLOAT = 4;
}
bufferSizeInBytes: 缓冲区大小参数,通过AudioRecord.getMinBufferSize方法计算最小所需缓冲区
//计算指定参数下的最小缓冲区大小
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)