Android音视频处理之音频混音

数字音频基本概念

在实现功能之前,我们先来了解一下数字音频的有关属性:

采样频率(Sample Rate):每秒采集声音的数量,它用赫兹(Hz)来表示。(采样率越高越靠近原声音的波形)
采样精度(Bit Depth):指记录声音的动态范围,它以位(Bit)为单位。(声音的幅度差)
声音通道(Channel):声道数。比如左声道右声道。

采样量化后的音频最终是一串数字,声音的大小(幅度)会体现在这个每个数字数值大小上;而声音的高低(频率)和声音的音色(Timbre)都和时间维度有关,会体现在数字之间的差异上。

Android音视频处理之音频混音_第1张图片
音频的编码与解码

自然界中的声音非常复杂,波形极其复杂,通常我们采用的是脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。本篇文章介绍的混音就是对PCM数据做处理。

相对自然界的信号,任何数字音频编码方案都是有损的,因为无法完全还原。在计算机应用中,能够达到最高保真水平的就是PCM编码,平时常见的WAV文件就是在PCM数据前加上一个44字节的RIFF头部组成的。

音频信号在时域和频域上具有相关性,也即存在数据冗余,音频编码的实质是减少音频中的冗余。

那么,解码的目的就是让编码后的数据恢复成PCM源数据。

AAC,Mp3 --> Decoder --> Audio PCM Data

常见的音频编码格式有以下这些:

public static final String MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
public static final String MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
public static final String MIMETYPE_AUDIO_MPEG = "audio/mpeg";
public static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
public static final String MIMETYPE_AUDIO_QCELP = "audio/qcelp";
public static final String MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
public static final String MIMETYPE_AUDIO_OPUS = "audio/opus";
public static final String MIMETYPE_AUDIO_G711_ALAW = "audio/g711-alaw";
public static final String MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw";
public static final String MIMETYPE_AUDIO_RAW = "audio/raw";
public static final String MIMETYPE_AUDIO_FLAC = "audio/flac";
public static final String MIMETYPE_AUDIO_MSGSM = "audio/gsm";
public static final String MIMETYPE_AUDIO_AC3 = "audio/ac3";
public static final String MIMETYPE_AUDIO_EAC3 = "audio/eac3";
音频的混音

音频混音的原理: 量化的语音信号的叠加等价于空气中声波的叠加。

Android音视频处理之音频混音_第2张图片

反应到音频数据上,也就是把同一个声道的数值进行简单的相加,但是这样同时会产生一个问题,那就是相加的结果可能会溢出,当然为了解决这个问题已经有很多方案了,在这里我们采用简单的平均算法。

下面的演示程序适用于音频文件采样率、通道数、采样精度一样的情况:

/**
 * 混合音频,使用平均算法
 *
 * @param mixedBytes 输出混合后的数据到该byte数组
 * @param shorts1    需要混合的short数组1
 * @param shorts2    需要混合的short数组2
 */
private void mixRawAudioBytes(byte[] mixedBytes, short[] shorts1, short[] shorts2) {
    for (int i = 0; i < shorts2.length; i++) {
        shorts1[i] = (short) ((shorts2[i] + shorts1[i]) / 2);
    }

    for (int i = 0; i < shorts1.length; i++) {
        mixedBytes[i * 2] = (byte) (shorts1[i] & 0x00FF);
        mixedBytes[i * 2 + 1] = (byte) ((shorts1[i] & 0xFF00) >> 8);
    }
}

你可能感兴趣的:(Android音视频处理之音频混音)