a律pcm编解码
2014-04-24 16:14:42 cc20032706 阅读数 1781

一 什么是音频的采样率和采样大小 

自然界中的声音非常复杂,波形极其复杂,通常我们采用的是脉冲代码调制编码。即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。
抽样:在音频采集中叫做采样率。 由于声音其实是一种能量波,因此也有频率和振幅的特征,频率对应于时间轴线,振幅对应于电平轴线。波是无限光滑的,弦线可以看成由无数点组成,由于存储空间是相对有限的,数字编码过程中,必须对弦线的点进行采样。采样的过程就是抽取某点的频率值,很显然,在一秒中内抽取的点越多,获取得频率信息更丰富,为了复原波形,一次振动中,必须有2个点的采样,人耳能够感觉到的最高频率为20kHz,因此要满足人耳的听觉要求,则需要至少每秒进行40k次采样,用40kHz表达,这个40kHz就是采样率。我们常见的CD,采样率为44.1kHz。
 量化:我们这里的采样大小就是量化的过程,将该频率的能量值并量化,用于表示信号强度。量化电平数为 2的整数次幂,我们常见的CD位16bit的采样大小,即2的16次方。 编码: 根据采样率和采样大小可以得知,相对自然界的信号,音频编码最多只能做到无限接近,至少目前的技术只能这样了,相对自然界的信号,任何数字音频编码方案都是有损的,因为无法完全还原。在计算机应用中,能够达到最高保真水平的就是PCM编码,被广泛用于素材保存及音乐欣赏,CD、DVD以及我们常见的WAV文件中均有应用。因此,PCM约定俗成了无损编码,因为PCM代表了数字音频中最佳的保真水准,并不意味着PCM就能够确保信号绝对保真,PCM也只能做到最大程度的无限接近。我们而习惯性的把MP3列入有损音频编码范畴,是相对PCM编码的。强调编码的相对性的有损和无损,是为了告诉大家,要做到真正的无损是困难的,就像用数字去表达圆周率,不管精度多高,也只是无限接近,而不是真正等于圆周率的值
为什么要使用音频压缩技术
 
要算一个PCM音频流的码率是一件很轻松的事情,采样率值×采样大小值×声道数bps。一个采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的WAV文件,它的数据速率则为 44.1K×16×2 =1411.2 Kbps。我们常说128K的MP3,对应的WAV的参数,就是这个1411.2 Kbps,这个参数也被称为数据带宽,它和ADSL中的带宽是一个概念。将码率除以8,就可以得到这个WAV的数据速率,即176.4KB/s。这表示存储一秒钟采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的音频信号,需要176.4KB的空间,1分钟则约为10.34M,这对大部分用户是不可接受的,尤其是喜欢在电脑上听音乐的朋友,要降低磁盘占用,只有2种方法,降低采样指标或者压缩。降低指标是不可取的,因此专家们研发了各种压缩方案。由于用途和针对的目标市场不一样,各种音频压缩编码所达到的音质和压缩比都不一样,在后面的文章中我们都会一一提到。有一点是可以肯定的,他们都压缩过。

频率与采样率的关系
 
采样率表示了每秒对原始信号采样的次数,我们常见到的音频文件采样率多为44.1KHz,这意味着什么呢?假设我们有2段正弦波信号,分别为20Hz和20KHz,长度均为一秒钟,以对应我们能听到的最低频和最高频,分别对这两段信号进行 40KHz的采样,我们可以得到一个什么样的结果呢?结果是:20Hz的信号每次振动被采样了40K/20=2000次,而20K的信号每次振动只有2次采样。显然,在相同的采样率下,记录低频的信息远比高频的详细。这也是为什么有些音响发烧友指责CD有数码声不够真实的原因,CD的44.1KHz采样也无法保证高频信号被较好记录。要较好的记录高频信号,看来需要更高的采样率,于是有些朋友在捕捉CD音轨的时候使用48KHz的采样率,这是不可取的!这其实对音质没有任何好处,对抓轨软件来说,保持和CD提供的44.1KHz一样的采样率才是最佳音质的保证之一,而不是去提高它。较高的采样率只有相对模拟信号的时候才有用,如果被采样的信号是数字的,请不要去尝试提高采样率。

流特征
 
随着网络的发展,人们对在线收听音乐提出了要求,因此也要求音频文件能够一边读一边播放,而不需要把这个文件全部读出后然后回放,这样就可以做到不用下载就可以实现收听了。也可以做到一边编码一边播放,正是这种特征,可以实现在线的直播,架设自己的数字广播电台成为了现实。  
 
 

二 android中AudioRecord采集音频的参数说明

 

在android中采集音频的api是android.media.AudioRecord类

其中构造器的几个参数就是标准的声音采集参数

以下是参数的含义解释

public AudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)

Since: API Level 3

Class constructor.

Parameters

audioSource

the recording source. See MediaRecorder.AudioSource for recording source definitions.

音频源:指的是从哪里采集音频。这里我们当然是从麦克风采集音频,所以此参数的值为MIC

sampleRateInHz

the sample rate expressed in Hertz. Examples of rates are (but not limited to) 44100, 22050 and 11025.

采样率:音频的采样频率,每秒钟能够采样的次数,采样率越高,音质越高。给出的实例是44100、22050、11025但不限于这几个参数。例如要采集低质量的音频就可以使用4000、8000等低采样率。

channelConfig

describes the configuration of the audio channels. SeeCHANNEL_IN_MONO and CHANNEL_IN_STEREO

声道设置:android支持双声道立体声和单声道。MONO单声道,STEREO立体声

audioFormat

the format in which the audio data is represented. SeeENCODING_PCM_16BIT and ENCODING_PCM_8BIT

编码制式和采样大小:采集来的数据当然使用PCM编码(脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。) android支持的采样大小16bit 或者8bit。当然采样大小越大,那么信息量越多,音质也越高,现在主流的采样大小都是16bit,在低质量的语音传输的时候8bit足够了。

bufferSizeInBytes

the total size (in bytes) of the buffer where audio data is written to during the recording. New audio data can be read from this buffer in smaller chunks than this size. SeegetMinBufferSize(int, int, int)to determine the minimum required buffer size for the successful creation of an AudioRecord instance. Using values smaller than getMinBufferSize() will result in an initialization failure.

采集数据需要的缓冲区的大小,如果不知道最小需要的大小可以在getMinBufferSize()查看。

 

 // 音频获取源
private int audioSource = MediaRecorder.AudioSource.MIC;
// 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
private static int sampleRateInHz = 44100;
// 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
private static int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
// 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
复制代码
          File file = new File(Environment.getExternalStorageDirectory()
                        .getAbsolutePath() + "/test.pcm");
                // 删除录音文件
                if (file.exists())
                    file.delete();
                // 创建录音文件
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    throw new IllegalStateException("Failed to create "
                            + file.toString());
                }
                try {
                    // Create a DataOuputStream to write the audio data into the
                    // saved file.
                    FileOutputStream fos = new FileOutputStream(file);// 建立一个可存取字节的文件
                    // Create a new AudioRecord object to record the audio.
                    // 获得满足条件的最小缓冲区大小
                    bufferSizeInBytes = AudioRecord.getMinBufferSize(
                            sampleRateInHz, channelConfig, audioFormat);
                    // 创建AudioRecord对象
                    audioRecord = new AudioRecord(audioSource, sampleRateInHz,
                            channelConfig, audioFormat, bufferSizeInBytes);
                    byte[] buffer = new byte[bufferSizeInBytes];
                    audioRecord.startRecording();
                    isRecording = true;
                    while (isRecording) {
                        audioRecord.read(buffer, 0, bufferSizeInBytes);
                        fos.write(buffer);
                    }
                    audioRecord.stop();
                    audioRecord.stop();
                    audioRecord.release();// 释放资源
                    audioRecord = null;
                    fos.close();
                } catch (Throwable t) {
                    Log.e("AudioRecord", "Recording Failed");
                }
复制代码
复制代码
// 放音的文件
                File file = new File(Environment.getExternalStorageDirectory()
                        .getAbsolutePath() + "/test.pcm");
                FileInputStream in = null;
                try {
                    in = new FileInputStream(file);
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                // 获得满足条件的最小缓冲区大小
                bufferSizeInBytes = AudioRecord.getMinBufferSize(
                        sampleRateInHz, channelConfig, audioFormat);
                byte[] buffer = new byte[bufferSizeInBytes];
                int byteread=0;
                AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                        sampleRateInHz, channelConfig, audioFormat,
                        bufferSizeInBytes, AudioTrack.MODE_STREAM);
                // 放音
                audioTrack.play();
                try {
                    while ((byteread = in.read(buffer)) != -1) {
                        System.out.write(buffer, 0, byteread);
                        System.out.flush();
                        audioTrack.write(buffer, 0, bufferSizeInBytes);
                    }
                } catch (Exception e) {
                    Log.e("AudioTrack", "Playback Failed");
                }
2019-03-17 16:35:43 qq_43103848 阅读数 631

一、通信系统信源
通信系统的信源有两大类:模拟信号和数字信号。例如:话筒输出的语音信号属于模拟信号; 而文字、计算机数据属于数字信号。 数字信号相比于模拟信号有抗干扰能力强、无噪声积累的优点。因此,若输入是模拟信号,则在数字通信系统的信源编码部分需对输入模拟信号进行数字化。
数字化需要三个步骤:抽样、量化和编码。抽样是指用每隔一定时间的信号样值序列来代替原来在时间上连续的信号,也就是在时间上将模拟信号离散化。量化是用有限个幅度值近似原来连续变化的幅度值, 把模拟信号的连续幅度变为有限数量的有一定间隔的离散值。 编码则是按照一定的规律, 把量化后的值用二进制数字表示,然后转换成二值或多值的数字信号流。
三个步骤如下图所示:

在这里插入图片描述
二、抽样信号的非均匀量化编码( 13 折线法)
(1)脉冲编码调制简介
模拟信号抽样后变成时间离散的信号,经过量化后,此抽样信号才能成为数字信号。分析可知:最简单的均匀量化器对于小输入信号很不利。为了改善小信号时的信号量噪比,在实际应用中常采用非均匀量化。非均匀量化时,量化间隔随信号抽样值的不同而变化。信号样值小时,量化间隔 v也小;信号抽样值大时,量化间隔 v也变大。
实际应用中,用 13 折线法近似 A压缩律,来进行非均匀量化。图中横坐标 x 在 0 至 1 区间中分为不均匀的 8 段。1/2 至 1 间的线段称为第8 段;1/4 至 1/2 间的线段称为第 7 段;1/8 至 1/4 间的线段称为第 6 段;依此类推。图中纵坐标 y 则均匀地划分作 8 段。将与这 8 段相应的座标点 (x, y) 相连,就得到了一条折线。
在这里插入图片描述
在语音通信中,通常采用 8 位的 PCM编码就能够保证满意的通信质量。在 13 折线法中采用的折叠码有 8 位。第一位 c1 表示量化值的极性正负。后面的 7 位分为段落码和段内码两部分,用于表示量化值的绝对值。其中第 2 至 4位(c2 c3 c4) 是段落码,共计 3 位,可以表示 8 种斜率的段落;其他 4 位(c5 --c8)为段内码,可以表示每一段落内的 16 种量化电平。段内码代表的 16 个量化电平是均匀划分的。所以,这 7 位码总共能表示 7 2 =128 种量化值。

在下面的表中给出了段落码和段内码的编码规则。

在这里插入图片描述
在上述编码方法中,段内码是按量化间隔均匀编码的,但是因为各个段落的斜率不等,长度不等,故不同段落的量化间隔是不同的。其中第 1 和 2 段最短,斜率最大,其横坐标 x 的归一化动态范围只有 1/128。再将其等分为 16 小段后,每一小段的动态范围只有 (1/128)/(1/16) = 1/2048 。第 8 段最长,其横坐标 x的动态范围为 1/2 。将其 16等分后,每段长度为 1/32。假若采用均匀量化而仍希望对于小电压保持有同样的动态范围 1/2048,则需要用 11 位的码组才行。现在采用非均匀量化,只需要 7 位就够了。

2017-08-09 10:26:53 pashanhu6402 阅读数 343

一 什么是音频的采样率和采样大小 

自然界中的声音非常复杂,波形极其复杂,通常我们采用的是脉冲代码调制编码。即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。
抽样:在音频采集中叫做采样率。 由于声音其实是一种能量波,因此也有频率和振幅的特征,频率对应于时间轴线,振幅对应于电平轴线。波是无限光滑的,弦线可以看成由无数点组成,由于存储空间是相对有限的,数字编码过程中,必须对弦线的点进行采样。采样的过程就是抽取某点的频率值,很显然,在一秒中内抽取的点越多,获取得频率信息更丰富,为了复原波形,一次振动中,必须有2个点的采样,人耳能够感觉到的最高频率为20kHz,因此要满足人耳的听觉要求,则需要至少每秒进行40k次采样,用40kHz表达,这个40kHz就是采样率。我们常见的CD,采样率为44.1kHz。
 量化:我们这里的采样大小就是量化的过程,将该频率的能量值并量化,用于表示信号强度。量化电平数为 2的整数次幂,我们常见的CD位16bit的采样大小,即2的16次方。 编码: 根据采样率和采样大小可以得知,相对自然界的信号,音频编码最多只能做到无限接近,至少目前的技术只能这样了,相对自然界的信号,任何数字音频编码方案都是有损的,因为无法完全还原。在计算机应用中,能够达到最高保真水平的就是PCM编码,被广泛用于素材保存及音乐欣赏,CD、DVD以及我们常见的WAV文件中均有应用。因此,PCM约定俗成了无损编码,因为PCM代表了数字音频中最佳的保真水准,并不意味着PCM就能够确保信号绝对保真,PCM也只能做到最大程度的无限接近。我们而习惯性的把MP3列入有损音频编码范畴,是相对PCM编码的。强调编码的相对性的有损和无损,是为了告诉大家,要做到真正的无损是困难的,就像用数字去表达圆周率,不管精度多高,也只是无限接近,而不是真正等于圆周率的值
为什么要使用音频压缩技术
 
要算一个PCM音频流的码率是一件很轻松的事情,采样率值×采样大小值×声道数bps。一个采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的WAV文件,它的数据速率则为 44.1K×16×2 =1411.2 Kbps。我们常说128K的MP3,对应的WAV的参数,就是这个1411.2 Kbps,这个参数也被称为数据带宽,它和ADSL中的带宽是一个概念。将码率除以8,就可以得到这个WAV的数据速率,即176.4KB/s。这表示存储一秒钟采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的音频信号,需要176.4KB的空间,1分钟则约为10.34M,这对大部分用户是不可接受的,尤其是喜欢在电脑上听音乐的朋友,要降低磁盘占用,只有2种方法,降低采样指标或者压缩。降低指标是不可取的,因此专家们研发了各种压缩方案。由于用途和针对的目标市场不一样,各种音频压缩编码所达到的音质和压缩比都不一样,在后面的文章中我们都会一一提到。有一点是可以肯定的,他们都压缩过。

频率与采样率的关系
 
采样率表示了每秒对原始信号采样的次数,我们常见到的音频文件采样率多为44.1KHz,这意味着什么呢?假设我们有2段正弦波信号,分别为20Hz和20KHz,长度均为一秒钟,以对应我们能听到的最低频和最高频,分别对这两段信号进行 40KHz的采样,我们可以得到一个什么样的结果呢?结果是:20Hz的信号每次振动被采样了40K/20=2000次,而20K的信号每次振动只有2次采样。显然,在相同的采样率下,记录低频的信息远比高频的详细。这也是为什么有些音响发烧友指责CD有数码声不够真实的原因,CD的44.1KHz采样也无法保证高频信号被较好记录。要较好的记录高频信号,看来需要更高的采样率,于是有些朋友在捕捉CD音轨的时候使用48KHz的采样率,这是不可取的!这其实对音质没有任何好处,对抓轨软件来说,保持和CD提供的44.1KHz一样的采样率才是最佳音质的保证之一,而不是去提高它。较高的采样率只有相对模拟信号的时候才有用,如果被采样的信号是数字的,请不要去尝试提高采样率。

流特征
 
随着网络的发展,人们对在线收听音乐提出了要求,因此也要求音频文件能够一边读一边播放,而不需要把这个文件全部读出后然后回放,这样就可以做到不用下载就可以实现收听了。也可以做到一边编码一边播放,正是这种特征,可以实现在线的直播,架设自己的数字广播电台成为了现实。  
 
 

二 android中AudioRecord采集音频的参数说明

 

在android中采集音频的api是android.media.AudioRecord类

其中构造器的几个参数就是标准的声音采集参数

以下是参数的含义解释

public AudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)

Since: API Level 3

Class constructor.

Parameters

audioSource

the recording source. See MediaRecorder.AudioSource for recording source definitions.

音频源:指的是从哪里采集音频。这里我们当然是从麦克风采集音频,所以此参数的值为MIC

sampleRateInHz

the sample rate expressed in Hertz. Examples of rates are (but not limited to) 44100, 22050 and 11025.

采样率:音频的采样频率,每秒钟能够采样的次数,采样率越高,音质越高。给出的实例是44100、22050、11025但不限于这几个参数。例如要采集低质量的音频就可以使用4000、8000等低采样率。

channelConfig

describes the configuration of the audio channels. See CHANNEL_IN_MONO and CHANNEL_IN_STEREO

声道设置:android支持双声道立体声和单声道。MONO单声道,STEREO立体声

audioFormat

the format in which the audio data is represented. See ENCODING_PCM_16BIT and ENCODING_PCM_8BIT

编码制式和采样大小:采集来的数据当然使用PCM编码(脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。) android支持的采样大小16bit 或者8bit。当然采样大小越大,那么信息量越多,音质也越高,现在主流的采样大小都是16bit,在低质量的语音传输的时候8bit足够了。

bufferSizeInBytes

the total size (in bytes) of the buffer where audio data is written to during the recording. New audio data can be read from this buffer in smaller chunks than this size. SeegetMinBufferSize(int, int, int) to determine the minimum required buffer size for the successful creation of an AudioRecord instance. Using values smaller than getMinBufferSize() will result in an initialization failure.

采集数据需要的缓冲区的大小,如果不知道最小需要的大小可以在getMinBufferSize()查看。

 

 // 音频获取源
private int audioSource = MediaRecorder.AudioSource.MIC;
// 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
private static int sampleRateInHz = 44100;
// 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
private static int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
// 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
复制代码
          File file = new File(Environment.getExternalStorageDirectory()
                        .getAbsolutePath() + "/test.pcm");
                // 删除录音文件
                if (file.exists())
                    file.delete();
                // 创建录音文件
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    throw new IllegalStateException("Failed to create "
                            + file.toString());
                }
                try {
                    // Create a DataOuputStream to write the audio data into the
                    // saved file.
                    FileOutputStream fos = new FileOutputStream(file);// 建立一个可存取字节的文件
                    // Create a new AudioRecord object to record the audio.
                    // 获得满足条件的最小缓冲区大小
                    bufferSizeInBytes = AudioRecord.getMinBufferSize(
                            sampleRateInHz, channelConfig, audioFormat);
                    // 创建AudioRecord对象
                    audioRecord = new AudioRecord(audioSource, sampleRateInHz,
                            channelConfig, audioFormat, bufferSizeInBytes);
                    byte[] buffer = new byte[bufferSizeInBytes];
                    audioRecord.startRecording();
                    isRecording = true;
                    while (isRecording) {
                        audioRecord.read(buffer, 0, bufferSizeInBytes);
                        fos.write(buffer);
                    }
                    audioRecord.stop();
                    audioRecord.stop();
                    audioRecord.release();// 释放资源
                    audioRecord = null;
                    fos.close();
                } catch (Throwable t) {
                    Log.e("AudioRecord", "Recording Failed");
                }
复制代码
复制代码
// 放音的文件
                File file = new File(Environment.getExternalStorageDirectory()
                        .getAbsolutePath() + "/test.pcm");
                FileInputStream in = null;
                try {
                    in = new FileInputStream(file);
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                // 获得满足条件的最小缓冲区大小
                bufferSizeInBytes = AudioRecord.getMinBufferSize(
                        sampleRateInHz, channelConfig, audioFormat);
                byte[] buffer = new byte[bufferSizeInBytes];
                int byteread=0;
                AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                        sampleRateInHz, channelConfig, audioFormat,
                        bufferSizeInBytes, AudioTrack.MODE_STREAM);
                // 放音
                audioTrack.play();
                try {
                    while ((byteread = in.read(buffer)) != -1) {
                        System.out.write(buffer, 0, byteread);
                        System.out.flush();
                        audioTrack.write(buffer, 0, bufferSizeInBytes);
                    }
                } catch (Exception e) {
                    Log.e("AudioTrack", "Playback Failed");
                }
2014-11-15 14:21:48 anlun 阅读数 499

一 什么是音频的采样率和采样大小 

自然界中的声音非常复杂,波形极其复杂,通常我们采用的是脉冲代码调制编码。即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。
抽样:在音频采集中叫做采样率。 由于声音其实是一种能量波,因此也有频率和振幅的特征,频率对应于时间轴线,振幅对应于电平轴线。波是无限光滑的,弦线可以看成由无数点组成,由于存储空间是相对有限的,数字编码过程中,必须对弦线的点进行采样。采样的过程就是抽取某点的频率值,很显然,在一秒中内抽取的点越多,获取得频率信息更丰富,为了复原波形,一次振动中,必须有2个点的采样,人耳能够感觉到的最高频率为20kHz,因此要满足人耳的听觉要求,则需要至少每秒进行40k次采样,用40kHz表达,这个40kHz就是采样率。我们常见的CD,采样率为44.1kHz。
 量化:我们这里的采样大小就是量化的过程,将该频率的能量值并量化,用于表示信号强度。量化电平数为 2的整数次幂,我们常见的CD位16bit的采样大小,即2的16次方。编码: 根据采样率和采样大小可以得知,相对自然界的信号,音频编码最多只能做到无限接近,至少目前的技术只能这样了,相对自然界的信号,任何数字音频编码方案都是有损的,因为无法完全还原。在计算机应用中,能够达到最高保真水平的就是PCM编码,被广泛用于素材保存及音乐欣赏,CD、DVD以及我们常见的WAV文件中均有应用。因此,PCM约定俗成了无损编码,因为PCM代表了数字音频中最佳的保真水准,并不意味着PCM就能够确保信号绝对保真,PCM也只能做到最大程度的无限接近。我们而习惯性的把MP3列入有损音频编码范畴,是相对PCM编码的。强调编码的相对性的有损和无损,是为了告诉大家,要做到真正的无损是困难的,就像用数字去表达圆周率,不管精度多高,也只是无限接近,而不是真正等于圆周率的值
为什么要使用音频压缩技术
 
要算一个PCM音频流的码率是一件很轻松的事情,采样率值×采样大小值×声道数bps。一个采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的WAV文件,它的数据速率则为 44.1K×16×2 =1411.2 Kbps。我们常说128K的MP3,对应的WAV的参数,就是这个1411.2 Kbps,这个参数也被称为数据带宽,它和ADSL中的带宽是一个概念。将码率除以8,就可以得到这个WAV的数据速率,即176.4KB/s。这表示存储一秒钟采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的音频信号,需要176.4KB的空间,1分钟则约为10.34M,这对大部分用户是不可接受的,尤其是喜欢在电脑上听音乐的朋友,要降低磁盘占用,只有2种方法,降低采样指标或者压缩。降低指标是不可取的,因此专家们研发了各种压缩方案。由于用途和针对的目标市场不一样,各种音频压缩编码所达到的音质和压缩比都不一样,在后面的文章中我们都会一一提到。有一点是可以肯定的,他们都压缩过。

频率与采样率的关系
 
采样率表示了每秒对原始信号采样的次数,我们常见到的音频文件采样率多为44.1KHz,这意味着什么呢?假设我们有2段正弦波信号,分别为20Hz和20KHz,长度均为一秒钟,以对应我们能听到的最低频和最高频,分别对这两段信号进行 40KHz的采样,我们可以得到一个什么样的结果呢?结果是:20Hz的信号每次振动被采样了40K/20=2000次,而20K的信号每次振动只有2次采样。显然,在相同的采样率下,记录低频的信息远比高频的详细。这也是为什么有些音响发烧友指责CD有数码声不够真实的原因,CD的44.1KHz采样也无法保证高频信号被较好记录。要较好的记录高频信号,看来需要更高的采样率,于是有些朋友在捕捉CD音轨的时候使用48KHz的采样率,这是不可取的!这其实对音质没有任何好处,对抓轨软件来说,保持和CD提供的44.1KHz一样的采样率才是最佳音质的保证之一,而不是去提高它。较高的采样率只有相对模拟信号的时候才有用,如果被采样的信号是数字的,请不要去尝试提高采样率。

流特征
 
随着网络的发展,人们对在线收听音乐提出了要求,因此也要求音频文件能够一边读一边播放,而不需要把这个文件全部读出后然后回放,这样就可以做到不用下载就可以实现收听了。也可以做到一边编码一边播放,正是这种特征,可以实现在线的直播,架设自己的数字广播电台成为了现实。  
 
 

二 android中AudioRecord采集音频的参数说明

 

在android中采集音频的api是android.media.AudioRecord类

其中构造器的几个参数就是标准的声音采集参数

以下是参数的含义解释

public AudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)

Since: API Level 3

Class constructor.

Parameters

audioSource

the recording source. See MediaRecorder.AudioSource for recording source definitions.

音频源:指的是从哪里采集音频。这里我们当然是从麦克风采集音频,所以此参数的值为MIC

sampleRateInHz

the sample rate expressed in Hertz. Examples of rates are (but not limited to) 44100, 22050 and 11025.

采样率:音频的采样频率,每秒钟能够采样的次数,采样率越高,音质越高。给出的实例是44100、22050、11025但不限于这几个参数。例如要采集低质量的音频就可以使用4000、8000等低采样率。

channelConfig

describes the configuration of the audio channels. SeeCHANNEL_IN_MONO and CHANNEL_IN_STEREO

声道设置:android支持双声道立体声和单声道。MONO单声道,STEREO立体声

audioFormat

the format in which the audio data is represented. SeeENCODING_PCM_16BIT and ENCODING_PCM_8BIT

编码制式和采样大小:采集来的数据当然使用PCM编码(脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。) android支持的采样大小16bit 或者8bit。当然采样大小越大,那么信息量越多,音质也越高,现在主流的采样大小都是16bit,在低质量的语音传输的时候8bit足够了。

bufferSizeInBytes

the total size (in bytes) of the buffer where audio data is written to during the recording. New audio data can be read from this buffer in smaller chunks than this size. SeegetMinBufferSize(int, int, int) to determine the minimum required buffer size for the successful creation of an AudioRecord instance. Using values smaller than getMinBufferSize() will result in an initialization failure.

采集数据需要的缓冲区的大小,如果不知道最小需要的大小可以在getMinBufferSize()查看。

 

 // 音频获取源
private int audioSource = MediaRecorder.AudioSource.MIC;
// 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
private static int sampleRateInHz = 44100;
// 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
private static int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
// 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
复制代码
          File file = new File(Environment.getExternalStorageDirectory()
                        .getAbsolutePath() + "/test.pcm");
                // 删除录音文件
                if (file.exists())
                    file.delete();
                // 创建录音文件
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    throw new IllegalStateException("Failed to create "
                            + file.toString());
                }
                try {
                    // Create a DataOuputStream to write the audio data into the
                    // saved file.
                    FileOutputStream fos = new FileOutputStream(file);// 建立一个可存取字节的文件
                    // Create a new AudioRecord object to record the audio.
                    // 获得满足条件的最小缓冲区大小
                    bufferSizeInBytes = AudioRecord.getMinBufferSize(
                            sampleRateInHz, channelConfig, audioFormat);
                    // 创建AudioRecord对象
                    audioRecord = new AudioRecord(audioSource, sampleRateInHz,
                            channelConfig, audioFormat, bufferSizeInBytes);
                    byte[] buffer = new byte[bufferSizeInBytes];
                    audioRecord.startRecording();
                    isRecording = true;
                    while (isRecording) {
                        audioRecord.read(buffer, 0, bufferSizeInBytes);
                        fos.write(buffer);
                    }
                    audioRecord.stop();
                    audioRecord.stop();
                    audioRecord.release();// 释放资源
                    audioRecord = null;
                    fos.close();
                } catch (Throwable t) {
                    Log.e("AudioRecord", "Recording Failed");
                }
复制代码
复制代码
// 放音的文件
                File file = new File(Environment.getExternalStorageDirectory()
                        .getAbsolutePath() + "/test.pcm");
                FileInputStream in = null;
                try {
                    in = new FileInputStream(file);
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                // 获得满足条件的最小缓冲区大小
                bufferSizeInBytes = AudioRecord.getMinBufferSize(
                        sampleRateInHz, channelConfig, audioFormat);
                byte[] buffer = new byte[bufferSizeInBytes];
                int byteread=0;
                AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                        sampleRateInHz, channelConfig, audioFormat,
                        bufferSizeInBytes, AudioTrack.MODE_STREAM);
                // 放音
                audioTrack.play();
                try {
                    while ((byteread = in.read(buffer)) != -1) {
                        System.out.write(buffer, 0, byteread);
                        System.out.flush();
                        audioTrack.write(buffer, 0, bufferSizeInBytes);
                    }
                } catch (Exception e) {
                    Log.e("AudioTrack", "Playback Failed");
                }
复制代码

移动开发qq群:59516399

 

2013-03-01 11:04:32 key123zhangxing 阅读数 828

本文转自:http://www.cnblogs.com/nanguabing/archive/2012/12/16/2820732.html

一 什么是音频的采样率和采样大小 

自然界中的声音非常复杂,波形极其复杂,通常我们采用的是脉冲代码调制编码。即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。
抽样:在音频采集中叫做采样率。 由于声音其实是一种能量波,因此也有频率和振幅的特征,频率对应于时间轴线,振幅对应于电平轴线。波是无限光滑的,弦线可以看成由无数点组成,由于存储空间是相对有限的,数字编码过程中,必须对弦线的点进行采样。采样的过程就是抽取某点的频率值,很显然,在一秒中内抽取的点越多,获取得频率信息更丰富,为了复原波形,一次振动中,必须有2个点的采样,人耳能够感觉到的最高频率为20kHz,因此要满足人耳的听觉要求,则需要至少每秒进行40k次采样,用40kHz表达,这个40kHz就是采样率。我们常见的CD,采样率为44.1kHz。
量化:我们这里的采样大小就是量化的过程,将该频率的能量值并量化,用于表示信号强度。量化电平数为 2的整数次幂,我们常见的CD位16bit的采样大小,即2的16次方。 编码: 根据采样率和采样大小可以得知,相对自然界的信号,音频编码最多只能做到无限接近,至少目前的技术只能这样了,相对自然界的信号,任何数字音频编码方案都是有损的,因为无法完全还原。在计算机应用中,能够达到最高保真水平的就是PCM编码,被广泛用于素材保存及音乐欣赏,CD、DVD以及我们常见的WAV文件中均有应用。因此,PCM约定俗成了无损编码,因为PCM代表了数字音频中最佳的保真水准,并不意味着PCM就能够确保信号绝对保真,PCM也只能做到最大程度的无限接近。我们而习惯性的把MP3列入有损音频编码范畴,是相对PCM编码的。强调编码的相对性的有损和无损,是为了告诉大家,要做到真正的无损是困难的,就像用数字去表达圆周率,不管精度多高,也只是无限接近,而不是真正等于圆周率的值
为什么要使用音频压缩技术

要算一个PCM音频流的码率是一件很轻松的事情,采样率值×采样大小值×声道数bps。一个采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的WAV文件,它的数据速率则为 44.1K×16×2 =1411.2 Kbps。我们常说128K的MP3,对应的WAV的参数,就是这个1411.2 Kbps,这个参数也被称为数据带宽,它和ADSL中的带宽是一个概念。将码率除以8,就可以得到这个WAV的数据速率,即176.4KB/s。这表示存储一秒钟采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的音频信号,需要176.4KB的空间,1分钟则约为10.34M,这对大部分用户是不可接受的,尤其是喜欢在电脑上听音乐的朋友,要降低磁盘占用,只有2种方法,降低采样指标或者压缩。降低指标是不可取的,因此专家们研发了各种压缩方案。由于用途和针对的目标市场不一样,各种音频压缩编码所达到的音质和压缩比都不一样,在后面的文章中我们都会一一提到。有一点是可以肯定的,他们都压缩过。

频率与采样率的关系

采样率表示了每秒对原始信号采样的次数,我们常见到的音频文件采样率多为44.1KHz,这意味着什么呢?假设我们有2段正弦波信号,分别为20Hz和20KHz,长度均为一秒钟,以对应我们能听到的最低频和最高频,分别对这两段信号进行 40KHz的采样,我们可以得到一个什么样的结果呢?结果是:20Hz的信号每次振动被采样了40K/20=2000次,而20K的信号每次振动只有2次采样。显然,在相同的采样率下,记录低频的信息远比高频的详细。这也是为什么有些音响发烧友指责CD有数码声不够真实的原因,CD的44.1KHz采样也无法保证高频信号被较好记录。要较好的记录高频信号,看来需要更高的采样率,于是有些朋友在捕捉CD音轨的时候使用48KHz的采样率,这是不可取的!这其实对音质没有任何好处,对抓轨软件来说,保持和CD提供的44.1KHz一样的采样率才是最佳音质的保证之一,而不是去提高它。较高的采样率只有相对模拟信号的时候才有用,如果被采样的信号是数字的,请不要去尝试提高采样率。

流特征

随着网络的发展,人们对在线收听音乐提出了要求,因此也要求音频文件能够一边读一边播放,而不需要把这个文件全部读出后然后回放,这样就可以做到不用下载就可以实现收听了。也可以做到一边编码一边播放,正是这种特征,可以实现在线的直播,架设自己的数字广播电台成为了现实。 
 
 

二 android中AudioRecord采集音频的参数说明

 

在android中采集音频的api是android.media.AudioRecord类

其中构造器的几个参数就是标准的声音采集参数

以下是参数的含义解释

public AudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)

Since: API Level 3

Class constructor.

Parameters

audioSource

the recording source. See MediaRecorder.AudioSource for recording source definitions.

音频源:指的是从哪里采集音频。这里我们当然是从麦克风采集音频,所以此参数的值为MIC

sampleRateInHz

the sample rate expressed in Hertz. Examples of rates are (but not limited to) 44100, 22050 and 11025.

采样率:音频的采样频率,每秒钟能够采样的次数,采样率越高,音质越高。给出的实例是44100、22050、11025但不限于这几个参数。例如要采集低质量的音频就可以使用4000、8000等低采样率。

channelConfig

describes the configuration of the audio channels. See CHANNEL_IN_MONO and CHANNEL_IN_STEREO

声道设置:android支持双声道立体声和单声道。MONO单声道,STEREO立体声

audioFormat

the format in which the audio data is represented. See ENCODING_PCM_16BIT and ENCODING_PCM_8BIT

编码制式和采样大小:采集来的数据当然使用PCM编码(脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。) android支持的采样大小16bit 或者8bit。当然采样大小越大,那么信息量越多,音质也越高,现在主流的采样大小都是16bit,在低质量的语音传输的时候8bit足够了。

bufferSizeInBytes

the total size (in bytes) of the buffer where audio data is written to during the recording. New audio data can be read from this buffer in smaller chunks than this size. SeegetMinBufferSize(int, int, int) to determine the minimum required buffer size for the successful creation of an AudioRecord instance. Using values smaller than getMinBufferSize() will result in an initialization failure.

采集数据需要的缓冲区的大小,如果不知道最小需要的大小可以在getMinBufferSize()查看。

// 音频获取源 
    private int audioSource = MediaRecorder.AudioSource.MIC; 
    // 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025 
    private static int sampleRateInHz = 44100; 
    // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道 
    private static int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO; 
    // 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。 
    private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT; 
File file = new File(Environment.getExternalStorageDirectory()
                        .getAbsolutePath() + "/test.pcm");
                // 删除录音文件
                if (file.exists())
                    file.delete();
                // 创建录音文件
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    throw new IllegalStateException("Failed to create "
                            + file.toString());
                }
                try {
                    // Create a DataOuputStream to write the audio data into the
                    // saved file.
                    FileOutputStream fos = new FileOutputStream(file);// 建立一个可存取字节的文件
                    // Create a new AudioRecord object to record the audio.
                    // 获得满足条件的最小缓冲区大小
                    bufferSizeInBytes = AudioRecord.getMinBufferSize(
                            sampleRateInHz, channelConfig, audioFormat);
                    // 创建AudioRecord对象
                    audioRecord = new AudioRecord(audioSource, sampleRateInHz,
                            channelConfig, audioFormat, bufferSizeInBytes);
                    byte[] buffer = new byte[bufferSizeInBytes];
                    audioRecord.startRecording();
                    isRecording = true;
                    while (isRecording) {
                        audioRecord.read(buffer, 0, bufferSizeInBytes);
                        fos.write(buffer);
                    }
                    audioRecord.stop();
                    audioRecord.stop();
                    audioRecord.release();// 释放资源
                    audioRecord = null;
                    fos.close();
                } catch (Throwable t) {
                    Log.e("AudioRecord", "Recording Failed");
                }
// 放音的文件
                File file = new File(Environment.getExternalStorageDirectory()
                        .getAbsolutePath() + "/test.pcm");
                FileInputStream in = null;
                try {
                    in = new FileInputStream(file);
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                // 获得满足条件的最小缓冲区大小
                bufferSizeInBytes = AudioRecord.getMinBufferSize(
                        sampleRateInHz, channelConfig, audioFormat);
                byte[] buffer = new byte[bufferSizeInBytes];
                int byteread=0;
                AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                        sampleRateInHz, channelConfig, audioFormat,
                        bufferSizeInBytes, AudioTrack.MODE_STREAM);
                // 放音
                audioTrack.play();
                try {
                    while ((byteread = in.read(buffer)) != -1) {
                        System.out.write(buffer, 0, byteread);
                        System.out.flush();
                        audioTrack.write(buffer, 0, bufferSizeInBytes);
                    }
                } catch (Exception e) {
                    Log.e("AudioTrack", "Playback Failed");
                }


android pcm编解码

阅读数 997

android pcm编解码

阅读数 1061

没有更多推荐了,返回首页