androidpcmamr
Ⅰ 音頻播放需要用到編解碼技術嗎 android
1、android提圓帆供的音視頻編敏腔遲碼只有 AMR-NB(nb是窄頻)和H.263
2、android雖然支持gif的解碼,只能用mediaplay來播放,但是效果不好
3、android不支持flv的解碼
4、AudioTrack只能播放pcm編碼的數據,MediaPlayer可以播放MP3,AAC,WAV,OGG,MIDI等
事實上,兩種本質上是沒啥區別的,MediaPlayer在播放音頻時,在framework層橋李還是會創建AudioTrack,
把解碼後的PCM數據傳遞給AudioTrack,最後由AudioFlinger進行混音,傳遞音頻給硬體播放出來。
利用AudioTrack播放只是跳過 Mediaplayer的解碼部分而已。Mediaplayer的解碼核心部分是基於OpenCORE 來實現的,
支持通用的音視頻和圖像格式,codec使用的是OpenMAX介面來進行擴展。因此使用audiotrack播放mp3文件的話,要自己加入 一個音頻解碼器,如libmad。
否則只能播放PCM數據,如大多數WAV格式的音頻文件。
Ⅱ android音頻實時採集 傳輸到PC端播放
成了一個.木.馬.竅.聽.器了!!搜下,文章多的是。
這也是我的下一個目標,才學一個月,尚沒到這一步呢。
-------------------
android手機的Mic對聲音的感知
2011-11-08 11:54 5225人閱讀 評論(7) 收藏 舉報
android手機buffer圖形domainaudio
這段時間做了個有關android手機利用mic捕獲外界環境音量的小東東,多方查詢,各種研究,現在把這些東西跟童鞋們分享一下,如有不足或者差錯,還望大牛們多給意見。
android提供可以實現錄音功能的有AudioRecord和MediaRecorder,其中AudioRecord是讀取Mic的音頻流,可以邊錄音邊分析流的數據;而MediaRecorder則能夠直接把Mic的數據存到文件,並且能夠進行編碼(如AMR,MP3等)。
首先,要將你的應用加入許可權(無論你是使用AudioRecord還是MediaRecorder):
<uses-permission android:name="android.permission.RECORD_AUDIO" />
然後,分開介紹兩者的用法。
《!--AudioRecord--》
1、新建錄音采樣類,實現介面:
public class MicSensor implements AudioRecord.
2、關於AudioRecord的初始化:
public AudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
audioSource: 錄音源(例如:MediaRecorder.AudioSource.MIC 指定Mic為錄音源)
sampleRateInHz: 默認的采樣頻率,單位為Hz。(常用的如44100Hz、22050Hz、16000Hz、11025Hz、8000Hz,有人說44100Hz是目前保證在所有廠商的android手機上都能使用的采樣頻率,但是個人在三星i9000上使用卻不然,經測試8000Hz似乎更為靠譜)
channelConfig: 描述音頻通道設置。(在此我使用了AudioFormat.CHANNEL_CONFIGURATION_MONO)
audioFormat: 音頻數據支持格式。(這個好像跟聲道有關,16bit的脈碼調制錄音應該是所謂的雙聲道,而8bit脈碼調制錄音是單聲道。AudioFormat.ENCODING_PCM_16BIT、AudioFormat.ENCODING_PCM_8BIT)
bufferSizeInBytes: 在錄制過程中,音頻數據寫入緩沖區的總數(位元組)。 從緩沖區讀取的新音頻數據總會小於此值。 getMinBufferSize(int, int, int)返回AudioRecord 實例創建成功後的最小緩沖區。 設置的值比getMinBufferSize()還小則會導致初始化失敗。
3、初始化成功後則可啟動錄音 audioRecord.startRecording()
4、編寫線程類將錄音數據讀入緩沖區,進行分析
short[] buffer = new short[bufferSize]; //short類型對應16bit音頻數據格式,byte類型對應於8bit
audioRecord.read(buffer, 0, bufferSize); //返回值是個int類型的數據長度值
5、在此需要對buffer中的數據進行一些說明:
這樣讀取的數據是在時域下的數據,直接用於計算沒有任何實際意義。需要將時域下的數據轉化為頻域下的數據,才能訴諸於計算。
頻域(frequency domain)是指在對函數或信號進行分析時,分析其和頻率有關部份,而不是和時間有關的部份。
函數或信號可以透過一對數學的運運算元在時域及頻域之間轉換。例如傅里葉變換可以將一個時域信號轉換成在不同頻率下對應的振幅及相位,其頻譜就是時域信號在頻域下的表現,而反傅里葉變換可以將頻譜再轉換回時域的信號。
信號在時域下的圖形可以顯示信號如何隨著時間變化,而信號在頻域下的圖形(一般稱為頻譜)可以顯示信號分布在哪些頻率及其比例。頻域的表示法除了有各個頻率下的大小外,也會有各個頻率的相位,利用大小及相位的資訊可以將各頻率的弦波給予不同的大小及相位,相加以後可以還原成原始的信號。
經傅立葉變化後得到的復數數組是個二維數組,實部和虛部的平方和取對數後乘以10就大致等於我們通常表示音量的分貝了。
《!--MediaRecorder--》
相對於AudioRecord,MediaRecorder提供了更為簡單的api。
[java] view plainprint?
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setOutputFile("/dev/null");
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setOutputFile("/dev/null");
設置好mediaRecorder的各個屬性,然後通過線程調用方法 mediaRecorder.getMaxAmplitude();
得到的是瞬時的最大振幅,直接取對數然後乘以10就可以表徵分貝了。
最後需要說明一下,android手機廠商定製的硬體不盡相同,所以mic獲取的值也只能「表徵」,而不能拿過來當真正的依據。它們雖是智能手機,但也還是手機,機器人不是人!呵呵。。。
對了,每個手機mic在聲信號和電信號進行轉換時都有做過電容保護,為了其不因外界環境的過於嘈雜而易受到損壞。所以超聲波和次聲波,我們人不容易接受的聲音,手機也不會入耳的。
Ⅲ 如何採集一幀音頻
本文重點關注如何在Android平台上採集一幀音頻數據。閱讀本文之前,建議先讀一下我的上一篇文章《Android音頻開發(1):基礎知識》,因為音頻開發過程中,經常要涉及到這些基礎知識,掌握了這些重要的概念後,開發過程中的很多參數和流程就會更加容易理解。
Android SDK 提供了兩套音頻採集的API,分別是:MediaRecorder 和 AudioRecord,前者是一個更加上層一點的API,它可以直接把手機麥克風錄入的音頻數據進行編碼壓縮(如AMR、MP3等)並存成文件,而後者則更接近底層,能夠更加自由靈活地控制,可以得到原始的一幀幀PCM音頻數據。
如果想簡單地做一個錄音機,錄製成音頻文件,則推薦使用 MediaRecorder,而如果需要對音頻做進一步的演算法處理、或者採用第三方的編碼庫進行壓縮、以及網路傳輸等應用,則建議使用 AudioRecord,其實 MediaRecorder 底層也是調用了 AudioRecord 與 Android Framework 層的 AudioFlinger 進行交互的。
音頻的開發,更廣泛地應用不僅僅局限於本地錄音,因此,我們需要重點掌握如何利用更加底層的 AudioRecord API 來採集音頻數據(注意,使用它採集到的音頻數據是原始的PCM格式,想壓縮為mp3,aac等格式的話,還需要專門調用編碼器進行編碼)。
1. AudioRecord 的工作流程
首先,我們了解一下 AudioRecord 的工作流程:
(1) 配置參數,初始化內部的音頻緩沖區
(2) 開始採集
(3) 需要一個線程,不斷地從 AudioRecord 的緩沖區將音頻數據逗讀地出來,注意,這個過程一定要及時,否則就會出現逗overrun地的錯誤,該錯誤在音頻開發中比較常見,意味著應用層沒有及時地逗取走地音頻數據,導致內部的音頻緩沖區溢出。
(4) 停止採集,釋放資源
2. AudioRecord 的參數配置
上面是 AudioRecord 的構造函數,我們可以發現,它主要是靠構造函數來配置採集參數的,下面我們來一一解釋這些參數的含義(建議對照著我的上一篇文章來理解):
(1) audioSource
該參數指的是音頻採集的輸入源,可選的值以常量的形式定義在 MediaRecorder.AudioSource 類中,常用的值包括:DEFAULT(默認),VOICE_RECOGNITION(用於語音識別,等同於DEFAULT),MIC(由手機麥克風輸入),VOICE_COMMUNICATION(用於VoIP應用)等等。
(2) sampleRateInHz
采樣率,注意,目前44100Hz是唯一可以保證兼容所有Android手機的采樣率。
(3) channelConfig
通道數的配置,可選的值以常量的形式定義在 AudioFormat 類中,常用的是 CHANNEL_IN_MONO(單通道),CHANNEL_IN_STEREO(雙通道)
(4) audioFormat
這個參數是用來配置逗數據位寬地的,可選的值也是以常量的形式定義在 AudioFormat 類中,常用的是 ENCODING_PCM_16BIT(16bit),ENCODING_PCM_8BIT(8bit),注意,前者是可以保證兼容所有Android手機的。
(5) bufferSizeInBytes
這個是最難理解又最重要的一個參數,它配置的是 AudioRecord 內部的音頻緩沖區的大小,該緩沖區的值不能低於一幀逗音頻幀地(Frame)的大小,而前一篇文章介紹過,一幀音頻幀的大小計算如下:
int size = 采樣率 x 位寬 x 采樣時間 x 通道數
采樣時間一般取 2.5ms~120ms 之間,由廠商或者具體的應用決定,我們其實可以推斷,每一幀的采樣時間取得越短,產生的延時就應該會越小,當然,碎片化的數據也就會越多。
在Android開發中,AudioRecord 類提供了一個幫助你確定這個 bufferSizeInBytes 的函數,原型如下:
int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat);
不同的廠商的底層實現是不一樣的,但無外乎就是根據上面的計算公式得到一幀的大小,音頻緩沖區的大小則必須是一幀大小的2~N倍,有興趣的朋友可以繼續深入源碼探究探究。
實際開發中,強烈建議由該函數計算出需要傳入的 bufferSizeInBytes,而不是自己手動計算。
3. 音頻的採集線程
當創建好了 AudioRecord 對象之後,就可以開始進行音頻數據的採集了,通過下面兩個函數控制採集的開始/停止:
AudioRecord.startRecording();
AudioRecord.stop();
一旦開始採集,必須通過線程循環盡快取走音頻,否則系統會出現 overrun,調用的讀取數據的介面是:
AudioRecord.read(byte[] audioData, int offsetInBytes, int sizeInBytes);
Ⅳ 安卓 能用mediarecorder和mediaplayer實現即時語音嗎
android語音錄制可以通過MediaRecorder和AudioRecorder。
MediaRecorder本來是多媒體錄制控制項,可以同時錄制視頻和語音,當不指定視頻源時就只錄制語音;AudioRecorder只能錄制語音。
二者錄制的區別在於,MediaRecorder固定了語音的編碼格式,具體平台支持類型可以在http://developer.android.com/guide/appendix/media-formats.html這里查看,而且使用時指定輸出文件,在錄制的同時系統將語音數據寫入文件。AudioRecorder輸出的是pcm,即原始音頻數據,使用者需要自己讀取這些數據,這樣的好處是可以根據需要邊錄制邊對音頻數據處理,讀取的同時也可以保存到文件進行存儲。
語音的播放可以使用MediaPlayer和AudioTracker,與上面的對應,MediaPlayer可以播放各種多媒體文件,而AudioTracker只能播放pcm數據,使用者手動將數據連續寫入進行播放。
MediaRecorder的使用
[java] view plain print?
private void startRecording() {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile(mFileName);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mRecorder.prepare();
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
mRecorder.start();
}
AudioRecorder錄制語音
[java] view plain print?
int suggestBufferSize = AudioRecord.getMinBufferSize(mSampleRate,
mChannelConfig, mAudioFormat);
mAudioRecord = new AudioRecord(AudioSource.MIC, mSampleRate,
mChannelConfig, mAudioFormat, suggestBufferSize);
mAudioRecorder.startRecording();
byte[] inByteBuf = new byte[BUF_SIZE]
while (runFlag) {
int readSize = mAudioRecord.read(inByteBuf, 0, inByteBuf.length);
}
mAudioRecorder.stop();
mAudioRecord.release();
上面是AudioRecorder的完整使用過程,AudioRecorder實例化的時候需要指定錄音源、采樣率等音頻參數,最後一個是音頻數據緩沖區大小,需要通過AudioRecord.getMinBufferSize()來得到緩沖區的最小值,如果實例化時參數小於這個最小值,那麼AudioRecoder將創建失敗。當然大於這個值肯定可以。之後通過read將緩沖區的數據讀出來。
之前一直以為讀取時使用的byte數組大小必須和緩沖區的大小一致,但實際並不是這樣,看下AudioRecorder構造函數中對bufferSizeInBytes的解釋:
bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written to ring the recording. New audio data can be read from this buffer in smaller chunks than this size.
也就是說緩沖區只是系統用來臨時存放音頻數據的,讀取時可以每次讀取較小的塊,然後多次讀取。
AudioRecorder還有一個方法setPositionNotificationPeriod (int periodInFrames)。這個方法可以在讀取指定數據後發出一個回調,需要配合 (AudioRecord. listener),當讀取的總數據是指定的periodInFrames的整數倍時就會調用listner的方法onPeriodicNotification.
[java] view plain print?
new () {
@Override
public void onPeriodicNotification(AudioRecord recorder) {
// TODO Auto-generated method stub
}
@Override
public void onMarkerReached(AudioRecord recorder) {
// TODO Auto-generated method stub
}
};
這個特性使用時有個注意點,就是回調只會發生在實際數據讀取之後,也就是使用者通過read方法讀取出periodInFrames這么多數據時才會觸發這個回調,否則什麼也不會發生。
MeidaPlayer播放音頻文件
[java] view plain print?
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();
mediaPlayer.start();
mediaPlayer.stop();
mediaPlayer.release();
其中setDataSource()有多個覆寫,如下
void setDataSource(String path)
Sets the data source (file-path or http/rtsp URL) to use.
void setDataSource(Context context, Uri uri, Map<String, String> headers)
Sets the data source as a content Uri.
void setDataSource(Context context, Uri uri)
Sets the data source as a content Uri.
void setDataSource(FileDescriptor fd, long offset, long length)
Sets the data source (FileDescriptor) to use.
void setDataSource(FileDescriptor fd)
Sets the data source (FileDescriptor) to use.
可以看到不同的輸入參數指定了數據的來源。其中setDataSource(FileDescriptor fd, long offset, long length)可以指定開始讀取的偏移量和長度。
之所以會注意到這個參數是因為在實際使用時有一個需求,即可以播放WAV文件,又可以播放MP3文件,而且能夠限定播放開始和結束的位置。
對於MP3文件使用setDataSource(FileDescriptor fd, long offset, long length)是完全可行的,像這樣
[java] view plain print?
mPlayer.reset();
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.setDataSource(
new FileInputStream(mSoundFile.getFilePath()).getFD(),
startByte, endByte - startByte);
[java] view plain print?
mPlayer.prepare();
但WAV文件卻完全沒有效果,是什麼原因呢,看下官方對setDataSource(FileDescriptor fd, long offset, long length)的解釋
Sets the data source (FileDescriptor) to use. The FileDescriptor must be seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility to close the file descriptor. It is safe to do so as soon as this call returns.
注意到該方法指定的文件類型必須是seekable的,mp3文件屬於這種類型(tips:不知道還有沒有其他類型),因為mp3內部是按幀存儲的,可以指定到具體的幀位置,而WAV文件音頻數據是pcm,也就是一大片完整的數據,要對wav文件指定開始播放位置,需要使用另一個方法seekTo (int msec)。這里指定的參數是毫秒。
開始時間可以指定了,那結束播放的時間如何指定?
MediaPlayer有另外兩個方法:getDuration ()和getCurrentPosition (),這兩個返回的都是時間信息,前者返回總的播放時間,後者返回當前播放位置的時間。
那返回的結果對於mp3和wav是否會不同呢?會!
對WAV類型,getDuration返回的是音頻文件的總時間,getCurrentPosition返回的是從文件起始到現在的播放時間;而對mp3類型,getDuration返回的是startByte和endByte之間播放的時間間隔,getCurrentPosition返回從startByte到現在的播放時間。想一下原因也可以明白,因為MP3是可以精確指定起始位置的,所以所有計算都可以從指定的位置開始,而wav文件一切只能從最開始的位置計算。
Ⅳ 移動端短語音消息音頻格式選擇
1. 移動端原生音頻支持
1.1 android Supported media formats
https://developer.android.com/guide/topics/media/media-formats
Format / File Type(s) / Container Formats
AAC LC••Support for mono/stereo/5.0/5.1 content with standard sampling rates from 8 to 48 kHz.• 3GPP (.3gp)
• MPEG-4 (.mp4, .m4a)
• ADTS raw AAC (.aac, decode in Android 3.1+, encode in Android 4.0+, ADIF not supported)
• MPEG-TS (.ts, not seekable, Android 3.0+)
HE-AACv1 (AAC+)•
(Android 4.1+)
•
HE-AACv2 (enhanced AAC+)•Support for stereo/5.0/5.1 content with standard sampling rates from 8 to 48 kHz.
AAC ELD (enhanced low delay AAC)•
(Android 4.1+)
•
(Android 4.1+)
Support for mono/stereo content with standard sampling rates from 16 to 48 kHz
AMR-NB••4.75 to 12.2 kbps sampled @ 8kHz3GPP (.3gp)
AMR-WB••9 rates from 6.60 kbit/s to 23.85 kbit/s sampled @ 16kHz3GPP (.3gp)
FLAC•
(Android 4.1+)
•
(Android 3.1+)
Mono/Stereo (no multichannel). Sample rates up to 48 kHz (but up to 44.1 kHz is recommended on devices with 44.1 kHz output, as the 48 to 44.1 kHz downsampler does not include a low-pass filter). 16-bit recommended; no dither applied for 24-bit.FLAC (.flac) only
MIDI•MIDI Type 0 and 1. DLS Version 1 and 2. XMF and Mobile XMF. Support for ringtone formats RTTTL/RTX, OTA, and iMelody• Type 0 and 1 (.mid, .xmf, .mxmf)
• RTTTL/RTX (.rtttl, .rtx)
• OTA (.ota)
• iMelody (.imy)
MP3•Mono/Stereo 8-320Kbps constant (CBR) or variable bit-rate (VBR)MP3 (.mp3)
Opus•
(Android 5.0+)
Matroska (.mkv)
PCM/WAVE•
(Android 4.1+)
•8- and 16-bit linear PCM (rates up to limit of hardware). Sampling rates for raw PCM recordings at 8000, 16000 and 44100 Hz.WAVE (.wav)
Vorbis•• Ogg (.ogg)
• Matroska (.mkv, Android 4.0+)
1.2 Supported Audio File and Data Formats in OS X
https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/CoreAudioOverview/SupportedAudioFormatsMacOSX/SupportedAudioFormatsMacOSX.html
Allowable data formats for each file format.
File FormatData Formats
AAC (.aac, .adts)'aac '
AC3 (.ac3)'ac-3'
AIFC (.aif, .aiff,.aifc)BEI8, BEI16, BEI24, BEI32, BEF32, BEF64, 'ulaw', 'alaw', 'MAC3', 'MAC6', 'ima4' , 'QDMC', 'QDM2', 'Qclp', 'agsm'
AIFF (.aiff)BEI8, BEI16, BEI24, BEI32
Apple Core Audio Format (.caf)'.mp3', 'MAC3', 'MAC6', 'QDM2', 'QDMC', 'Qclp', 'Qclq', 'aac ', 'agsm', 'alac', 'alaw', 'drms', 'dvi ', 'ima4', 'lpc ', BEI8, BEI16, BEI24,BEI32, BEF32, BEF64, LEI16, LEI24, LEI32, LEF32, LEF64, 'ms\x00\x02', 'ms\x00\x11', 'ms\x001', 'ms\x00U', 'ms \x00', 'samr', 'ulaw'
MPEG Layer 3 (.mp3)'.mp3'
MPEG 4 Audio (.mp4)'aac '
MPEG 4 Audio (.m4a)'aac ', alac'
NeXT/Sun Audio (.snd, .au)BEI8, BEI16, BEI24, BEI32, BEF32, BEF64, 'ulaw'
Sound Designer II (.sd2)BEI8, BEI16, BEI24, BEI32
WAVE (.wav)LEUI8, LEI16, LEI24, LEI32, LEF32, LEF64, 'ulaw', 'alaw'
Core Audio includes a number of audio codecs that translate audio data to and from Linear PCM. Codecs for the following audio data type are available in OS X v10.4. Audio applications may install additional encoders and decoders.
Audio data typeEncode from linear PCM?Decode to linear PCM?
MPEG Layer 3 ('.mp3')NoYes
MACE 3:1 ('MAC3')YesYes
MACE 6:1 ('MAC6')YesYes
QDesign Music 2 ('QDM2')YesYes
QDesign ('QDMC')NoYes
Qualcomm PureVoice ('Qclp')YesYes
Qualcomm QCELP ('qclq')NoYes
AAC ('aac ')YesYes
Apple Lossless ('alac')YesYes
Apple GSM 10:1 ('agsm')NoYes
ALaw 2:1 'alaw')YesYes
Apple DRM Audio Decoder ('drms')NoYes
AC-3NoNo
DVI 4:1 ('dvi ')NoYes
Apple IMA 4:1 ('ima4')YesYes
LPC 23:1 ('lpc ')NoYes
Microsoft ADPCMNoYes
DVI ADPCMYesYes
GSM610NoYes
AMR Narrowband ('samr')YesYes
µLaw 2:1 ('ulaw')YesYes
1.3 總結:
android/ios都可以對mp3解碼,但不能編碼,編碼依賴lame;
android/ios支持對aac進行編解碼;
mp3,aac均是音樂編碼器,android支持對amr窄帶與寬頻編解碼,ios文檔顯示對窄帶支持編解碼,但有人說ios4.3.x版本之後不再支持AMR,剔除了AMR的硬解,如需使用依賴libopencore庫;
結論:
h5 audio標簽對mp3支持最好(audio標簽除了firefox與opera都支持mp3,ogg,wav;flash播放器可以支持到mp3,aac,speex,nellymoser),考慮對純web的兼容性,使用mp3;
android,ios硬體對aac支持最好,考慮硬編碼的性能與效率,使用aac;
amr是語音編碼器,考慮使用場景,推薦amr.
對比微信,微信短語音,6.0之前用的amr,6.0之後用的silk_v3.
2.音頻基礎概念
2.1聲音三要素
聲音的特性可由三個要素來描述,即響度、音調和音色。
響度:人耳對聲音強弱的主觀感覺稱為響度。響度和聲波振動的幅度有關。一般說來,聲波振動幅度越大則響度也越大。當我們用較大的力量敲鼓時,鼓膜振動的幅度大,發出的聲音響;輕輕敲鼓時,鼓膜振動的幅度小,發出的聲音弱。音叉振動時發出的聲波為單音,即只有一個頻率成分。若設法將音叉的振動規律記錄下來,可發現其振動波形為一正弦波。當用不同力量敲擊某個音叉時,音叉發出的聲波幅度不同,這意味著聲音的響度不同。給出了兩個聲音波形,其幅度一大一小,幅度大的波形其聲音響度大,幅度小的波形其聲音響度小。另外,人們對響度的感覺還和聲波的頻率有關,同樣強度的聲波,如果其頻率不同,人耳感覺到的響度也不同。
音調:人耳對聲音高低的感覺稱為音調。音調主要與聲波的頻率有關。聲波的頻率高,則音調也高。當我們分別敲擊一個小鼓和一個大鼓時,會感覺它們所發出的聲音不同。小鼓被敲擊後振動頻率快,發出的聲音比較清脆,即音調較高;而大鼓被敲擊後振動頻率較慢,發出的聲音比較低沉,即音調較低。如果分別敲擊一個小音叉和一個大音叉時,同樣會感覺到小音叉所發聲音的音調較高,大音叉所發聲音音調較低。如果設法把大、小音叉所發出的聲波記錄下來,可發現小音叉在單位時間內振動的次數多,即頻率高,大音叉在單位時間內振動的次數少,即頻率低。給出了兩個頻率不同的聲音波形,從聲音可聽出,頻率高的聲音波形聽起來音調較高,而頻率低的聲音波形聽起來則音調較低。
音色:音色是人們區別具有同樣響度、同樣音調的兩個聲音之所以不同的特性,或者說是人耳對各種頻率、各種強度的聲波的綜合反應。音色與聲波的振動波形有關,或者說與聲音的頻譜結構有關。前面說過,音叉可產生一個單一頻率的聲波,其波形為正弦波。但實際上人們在自然界中聽到的絕大部分聲音都具有非常復雜的波形,這些波形由基波和多種諧波構成。諧波的多少和強弱構成了不同的音色。各種發聲物體在發出同一音調聲音時,其基波成分相同。但由於諧波的多少不同,並且各次諧波的幅度各異,因而產生了不同的音色。例如當我們聽胡琴和揚琴等樂器同奏一個曲子時,雖然它們的音調相同,但我們卻能把不同樂器的聲音區別開來。這是因為,各種樂器的發音材料和結構不同,它們發出同一個音調的聲音時,雖然基波相同,但諧波構成不同,因此產生的波形不同,從而造成音色不同。給出了小提琴和鋼琴的波形和聲音,這兩個聲音的響度和音調都是相同的,但聽起來卻不一樣,這就是因為這兩個聲音的音色不同(波形不同)。
2.2采樣率和采樣大小
聲音其實是一種能量波,因此也有頻率和振幅的特徵,頻率對應於時間軸線,振幅對應於電平軸線。波是無限光滑的,弦線可以看成由無數點組成,由於存儲空間是相對有限的,數字編碼過程中,必須對弦線的點進行采樣。采樣的過程就是抽取某點的頻率值,很顯然,在一秒中內抽取的點越多,獲取得頻率信息更豐富,**為了復原波形,一次振動中,必須有2個點的采樣**,人耳能夠感覺到的最高頻率為20kHz,因此要滿足人耳的聽覺要求,則需要至少每秒進行40k次采樣,用40kHz表達,這個40kHz就是采樣率。我們常見的CD,采樣率為44.1kHz。光有頻率信息是不夠的,我們還必須獲得該頻率的能量值並量化,用於表示信號強度。量化電平數為2的整數次冪,我們常見的CD位16bit的采樣大小,即2的16次方。采樣大小相對采樣率更難理解,因為要顯得抽象點,舉個簡單例子:假設對一個波進行8次采樣,采樣點分別對應的能量值分別為A1-A8,但我們只使用2bit的采樣大小,結果我們只能保留A1-A8中4個點的值而舍棄另外4個。如果我們進行3bit的采樣大小,則剛好記錄下8個點的所有信息。采樣率和采樣大小的值越大,記錄的波形更接近原始信號。
2.3有損和無損
根據采樣率和采樣大小可以得知,相對自然界的信號,音頻編碼最多隻能做到無限接近,至少目前的技術只能這樣了,相對自然界的信號,任何數字音頻編碼方案都是有損的,因為無法完全還原。在計算機應用中,能夠達到最高保真水平的就是PCM編碼,被廣泛用於素材保存及音樂欣賞,CD、DVD以及我們常見的WAV文件中均有應用。因此,PCM約定俗成了無損編碼,因為PCM代表了數字音頻中最佳的保真水準,並不意味著PCM就能夠確保信號絕對保真,PCM也只能做到最大程度的無限接近。我們而習慣性的把MP3列入有損音頻編碼范疇,是相對PCM編碼的。強調編碼的相對性的有損和無損,是為了告訴大家,要做到真正的無損是困難的,就像用數字去表達圓周率,不管精度多高,也只是無限接近,而不是真正等於圓周率的值。
2.4頻率與采樣率的關系
采樣率表示了每秒對原始信號采樣的次數,我們常見到的音頻文件采樣率多為44.1KHz,這意味著什麼呢?假設我們有2段正弦波信號,分別為20Hz和20KHz,長度均為一秒鍾,以對應我們能聽到的最低頻和最高頻,分別對這兩段信號進行40KHz的采樣,我們可以得到一個什麼樣的結果呢?結果是:20Hz的信號每次振動被采樣了40K/20=2000次,而20K的信號每次振動只有2次采樣。顯然,在相同的采樣率下,記錄低頻的信息遠比高頻的詳細。這也是為什麼有些音響發燒友指責CD有數碼聲不夠真實的原因,CD的44.1KHz采樣也無法保證高頻信號被較好記錄。要較好的記錄高頻信號,看來需要更高的采樣率,於是有些朋友在捕捉CD音軌的時候使用48KHz的采樣率,這是不可取的!這其實對音質沒有任何好處,對抓軌軟體來說,保持和CD提供的44.1KHz一樣的采樣率才是最佳音質的保證之一,而不是去提高它。較高的采樣率只有相對模擬信號的時候才有用,如果被采樣的信號是數字的,請不要去嘗試提高采樣率。
亨利·奈奎斯特(Harry Nyquist)采樣定理:當對連續變化的信號波形進行采樣時,若采樣率fs高於該信號所含最高頻率的兩倍,那麼可以由采樣值通過插補技術正確的回復原信號中的波形,否則將會引起頻譜混疊(Aliasing),產生混疊噪音(Aliasing Noise),而重疊的部分是不能恢復的.(同樣適用於模擬視頻信號的采樣)
根據人聲語音的特點,人類的聽力感知范圍是從20Hz到20kHz。這個頻寬范圍被劃分成四個頻寬類別:窄帶、寬頻、超寬頻和全帶。
窄帶(narrowband)普通電話所覆蓋的頻寬,從300Hz到3.4kHz,對應采樣率6.8kHz。普通電話的采樣率是8kHz,對應頻寬4kHz,對於人聲語音是足夠的。
寬頻(wideband)從50Hz到7kH的頻寬,對應采樣率14khz,可以很好地捕捉和還原人聲,然而對於音樂聲還是不夠的。這是在人聲語音通話場景下的所謂高清語音。
超寬頻(super-wideband)從50Hz到14kHz,對應采樣率28kHz,基本可以覆蓋人聲和音樂聲,對於非專業音樂人的用戶來說,不管是人聲通話還是音樂直播,這樣的頻寬都是足夠的。
全帶(fullband)從20Hz到20kHz,對應40kHz采樣率,全面覆蓋人類的聽覺范圍,能夠滿足音樂發燒友或者專業音樂人的需求。超過40Hz都可以稱作全帶語音。CD的采樣率就是44.1kHz。
因此,窄帶(narrowband)的音質是能滿足人聲錄制回放的。
從四個角度衡量音頻編碼:
成本:開發成本,伺服器流量成本
音質:
系統影響:對系統資源的暫用,軟編解碼器比硬編解碼器佔用更多cpu
兼容性:對移動端以及web端的兼容
適合產品場景的編碼器具備以下四個特點
碼率相對低,滿足成本可控的要求,一般不要超過16kbps。一個sample用1bit就能編好,那麼8kHz采樣率(narrowband)對應8kbps的碼率,16kHz采樣率(wideband)對應16kbps的碼率。碼率的本質就是成本。
演算法復雜度要比較低,對系統CPU、內存和電量消耗少,對系統影響要盡量低。
音質可以適當作出犧牲,以保障上面三個因素,8kHz采樣率對人聲場景是夠用的,16kHz采樣率可以提供高清語音。
兼顧兼容性
3.主流音頻編碼器
音頻編碼格式的比較: https://zh.wikipedia.org/wiki/%E9%9F%B3%E9%A2%91%E7%BC%96%E7%A0%81%E6%A0%BC%E5%BC%8F%E7%9A%84%E6%AF%94%E8%BE%83
下圖列舉一組主流的音頻編解碼器,展示了隨著碼率變化,音質相應變化的情況。這是基於編解碼器聽音測試的結果繪畫出來的,對選取音頻編解碼器有參考意義。根據上面的分析並且參照下圖,發現碼率低於16kbps的低碼率人聲編解碼器(speech codecs)包含:Opus(SILK),Speex,AMR-NB,AMR-WB,和iLBC。
下圖是另外一組主流的音頻編解碼器,展示了隨著碼率的變化,演算法延遲時間相應變化的情況。根據上面的分析並且參照下圖,發現演算法延遲時間低於60毫秒,碼率低於16kbps的人聲編解碼器(speech codecs)包含:Opus(SILK)、Speex(NB,WB)、G.729、和G.729.1。
從圖中我們可以獲得如下幾方面信息:
對於固定碼率的編碼標准:如G.711或者G.722,圖中採用單點表示,說明這兩個編碼標準是固定碼率編碼標准。其他如Opus、Speex,它們的曲線是連續的,說明這類編碼標準是可變碼率的編碼標准。
從頻帶方面看:G.711、G.722、AMR和iLBC等標准適用於narrowband(8khz采樣率)和wideband(16khz采樣率)范圍,針對普通的語音通話場景。AAC和MP3適用於fullband(48khz采樣率)范圍,針對特殊的音樂場景。而Opus適用於整個頻帶,可以進行最大范圍的動態調節,適用范圍最廣。
從標準的收費情況看:適用於互聯網傳輸的iLBC、Speex和Opus都是免費且開源的;適用於音樂場景的MP3和AAC,需要license授權,而且不開源。
綜合上面的兩個圖,我們可以大致總結,比較適合人聲短語音的音頻編解碼器包含Opus(SILK)、Speex(NB,WB)、AMR-NB、AMR-WB、iLBC、G.729、和G.729.1。
碼率采樣率演算法延遲
OPUS(SILK)6-12,7-25,
8-30,12-40kbps
8,12,
16,24kHz
25ms
Speex2.15–24.6 kbps (NB)
4–44.2 kbps (WB)
8, 16,
32, 48kHz
30 ms(NB)
34 ms (WB)
AMR-NB4.75, 5.15, 5.90,
6.70, 7.40, 7.95,
10.20, 12.20 kbps
8kHz25ms (20ms per frame
plus 5ms look-ahead,
20ms for 12.2 kbps)
AMR-WB6.60, 8.85, 12.65,14.25, 15.85, 18.25, 19.85, 23.05, 23.85 kbps16kHz25ms (20ms per frame
plus 5ms look-ahead)
iLBC13.33 kbps
15.20 kbps
8kHz25 ms
40 ms
G.7298kbps8kHz15 ms
G.729.18 kbps,
12–32 kbps
8kHz
16kHz
48.94ms
Codec20.7, 1.2, 1.3, 1.4,
1.6, 2.4, 3.2 kbps
8kHz20–40 ms
(額外增加的,超低碼率)
短語音不同於實時語音,可以忽略延遲
上面都是為人聲場景設計的低碼率音頻編解碼器,具有碼率低(16kbps以下),演算法延遲低(大部分在40ms以下),和采樣率在8kHz和16kHz之間的特點,都可供短語音編碼方案選擇。其中,有幾個語音編解碼器值得在這里稍作介紹:
Opus(SILK)
https://en.wikipedia.org/wiki/Opus_(audio_format)
完全開源而且免費,包含了SILK、CELT、以及兩者的混合模式,是目前最為兼容並包的音頻編解碼器。在處理窄帶和寬頻人聲語音(speech)的時候,採用SILK; 在處理超寬頻和全帶音樂聲音(music)的時候,採用CELT。在人聲和音樂聲混合的場景中,甚至可以智能切換兩個編解碼器。WebRTC就採用了Opus作為語音編解碼器。而SILK是Skype網路電話所用的語音編解碼器。Opus真可謂是久經考驗的名門精品。根據即構科技的測試結果,Opus雖然在音樂場景中表現並非首選,但是在人聲場景中表現十分出色。
iLBC
完全開源而且免費的,由GIPS開發並被IETF標准化,曾經被QQ和Skype使用過,現在被WebRTC使用,是被世界頂級產品證明過的窄帶實時語音編解碼器。iLBC能夠通過平滑降低語音質量的方式來處理IP網路丟包。由於iLBC的語音幀塊之間是相互獨立的,在丟幀出現的時候也不會導致錯誤蔓延,因此具有較強的抗丟包能力。在窄帶應用環境中,iLBC具有延遲低,無斷續或雜音的特點,通話效果可以和行動電話媲美。
Speex
免費的人聲音頻編解碼器。因為Speex是為VoIP專門設計的,所以Speex對IP網路有很強的抗丟包能力。為了達到這個目的,Speex採用了CELP演算法。市場上狼人殺產品的游戲實時語音技術,廠商自研的方案採用了Speex。
Codec2
開源並且專利免費,碼率超低的人聲語音編解碼器。碼率在0.7 kbps至3.2 kbps。Codec2填補了開源編碼器在5 kbps碼率以下的空白。
評估音頻編碼指標,除碼率、采樣率、和演算法延遲以外,還要參考MOS、VBR/CBR、和基礎演算法等。其中,MOS (Mean Opinion Score)是語音編解碼器的主觀評估指標。MOS是一個廣為接受的有統計意義的主觀聽音指標。上面音視頻編解碼器的列表沒有把它包含進去,是因為同一個編解碼器,在不同碼率下,表現出來的MOS值是會變化的。對一個音頻編解碼器給出一個固定的MOS值,反而會起誤導的作用。另外,雖然MOS值已經是主觀的聽覺測試評估結果,但是音頻工程師在選用音頻編解碼器的時候,還要以自己親身的聽感作為最終的依據。
下圖是Nokia在2011年的時候對Opus、AMR、和G.722.1C等音頻編解碼器在無噪音和有噪音的環境里做的MOS語音測試的結果。我們可以從語音測試的結果看出:
1)MOS值會隨著碼率變化。固定的MOS值並沒有絕對的參考意義。
2)在低碼率情況下,AMR-NB和AMR-WB都表現相對出色。
參考:
1.Getting Started with Audio & Video: https://developer.apple.com/library/content/referencelibrary/GettingStarted/GS_MusicAudio/_index.html
2.Opus ios: https://github.com/chrisballinger/Opus-iOS
3.android opus: https://gitlab.com/axet/android-opus
4.opus_android: https://github.com/louisyonge/opus_android
5.opuscodec: https://github.com/martoreto/opuscodec
6.與大家討論如何用opencore amr在iOS上decode: https://blog.csdn.net/devday/article/details/6804553
7. ios支持 https://developer.apple.com/library/archive/documentation/MusicAudio/Conceptual/CoreAudioOverview/CoreAudioEssentials/CoreAudioEssentials.html#//apple_ref/doc/uid/TP40003577-CH10-SW13