範例程式:錄音
「CIOS音訊核心」當中,不論是語音活動偵測(Voice Activity Detection)、語音辨識(Speech Recognition)、錄音、外部環境偵測或是聲源位置探測,都是使用這個功能。
如果您需要自己處理全部的流程,要使用 「CIOS音訊核心」錄音功能,需要處理五個主要的部分:
- 導流管的繼承
- 選取音訊設備
- 設定音訊參數
- 啟動音訊驅動介面
- 處理音訊串流程序
virtual bool Record (Conduit * conduit , CaDeviceIndex deviceId , int channelCount , CaSampleFormat sampleFormat , int sampleRate , int frameCount , CaStreamFlags streamFlags = 0 , int sleepInterval = 50 ) ;
參數 |
說明 |
conduit |
導
流管。 |
deviceId |
音訊設備編號。 |
channelCount |
聲道數量。 |
sampleFormat |
取樣格式。格式請參考《CaSampleFormat》。 |
sampleRate |
取樣頻率。「CIOS音訊核心」支援的範圍為8000-192000,某些 音訊驅動介面可能不支援特定取樣頻率。 |
frameCount |
每次取樣的數量,一般建議為0.1秒或0.2秒。 如果您的取樣頻率是44100或48000,那麼這個frameCount值一般建議為4410、8820 或是4800、9600。 |
streamFlags |
串流狀態,一般為0,一般而言你不需要設定這個值,這是為某些特定音訊驅動
介面功能而給定的參數。 |
sleepInterval |
偵測播放狀態的時間間隔,一般建議值為50~250微秒,盡可能不要太長。 |
使用範例
Core core ;MyOwnConduit * conduit = new MyOwnConduit () ;
...
core . Record ( conduit , 1 , 2 , cafInt16 , 44100 , 4410 , 0 , 100 ) ;
...
如果您需要無阻塞的錄音方式,請參考《播放音訊檔》當中的線緒實作方法。
導流管的繼承
完整的繼承處理 方式,請參考《導流管的繼承處理》、 《LinearConduit》或是《BridgeConduit》。如果您只需要自行處理音訊數據,那麼導流管當中僅需處理兩個函式,obtain函式只要留空白或是直接返回Complete即可:
virtual int put (void) = 0 ;
virtual void finish (ConduitDirection direction = NoDirection ,FinishCondition condition = Correct ) = 0 ;
put函式處理StreamIO Input,處理的方式大體如下:
int MyOwnConduit::put (void)
{
if ( ... condition is ready for audio input ... ) {
... copy your audio input into Input.Buffer ...
// example code in BridgeConduit.cpp : Buffer . put ( Input . Buffer , Input . Total ( ) ) ;
return Continue ;
}
if ( ... condition is audio input is completely empty ... ) {
return Complete ;
}
if ( ... condition has something unexpected ... ) {
return Abort ;
}
return Postpone ;
}
整個錄音串流被結束時,Stream會主動呼叫finish。
void MyOwnConduit::finish (ConduitDirection direction,FinishCondition condition = Correct)
{
if ( InputDirection != direction ) return ;
... handle your own finishing conditions here ...
}
選取音訊設備
您需要透過取得DeviceInfo來得知音訊設備的細節,詳 細的設定請參考《DeviceInfo》。CaPlay當中的範例程式
void ListInputDevices(void)
{
Core core ;
core . Initialize ( ) ;
for (int i=0;i<core.DeviceCount();i++) {
DeviceInfo * dev ;
dev = core.GetDeviceInfo((CaDeviceIndex)i) ;
if ( NULL != dev && dev->maxInputChannels>0) {
printf("%4d : %s\n",i,dev->name) ;
} ;
} ;
core . Terminate ( ) ;
}
一般而言,錄音設備必須事先得知並取得編號,如果您沒有設定音訊設備的話,系統會自動選用:
virtual CaDeviceIndex DefaultInputDevice (void) ;
這個函式所設定的錄音設備。
由於某些作業系統底層音訊驅動程式實作的問題,這個錄音設備不見得可以正常運作。由於「CIOS音訊核心」使用這些底層的音訊驅動程式,如果錄音設備不能正常運作,在
「CIOS音訊核心」當中尋找解決途徑一般是徒勞無功的。
設定音訊參數
設定音訊參數需要設定StreamParameters, 詳細使用方法請見《StreamParameters》。一般而言,僅需要在宣告的時候,使用以下宣告即可設定音訊參數:
StreamParameters inputParameters ( deviceId , channelCount , sampleFormat ) ;
取樣頻率的設定,必須在設備打開的時候設定,請見《啟動音訊驅動介面》這一部分。
啟動音訊驅動介面
啟動及停止音訊驅動介面,需要以下步驟:
Core core ;
...
core . Initialize ( ) ;
//////////////////////////////////////////////////////////////////////////// ... configure input paraments here ... //////////////////////////////////////////////////////////////////////////// rt = core . Open ( &stream , &inputParameters , NULL , sampleRate , frameCount , streamFlags , conduit ) ; if ( ( NoError != rt ) || ( NULL == stream ) ) correct = false ; //////////////////////////////////////////////////////////////////////////// if ( correct ) { rt = core . Start ( stream ) ; if ( NoError != rt ) correct = false ;
////////////////////////////////////////////////////////////////////////// ... handle your stream process here ... ////////////////////////////////////////////////////////////////////////// if ( correct && ( 0 != core.IsStopped ( stream ) ) ) core.Stop ( stream ) ; } core . Close ( stream ) ; core . Terminate ( ) ;
...
處理音訊串流程序
音訊串流啟動以後,您需要偵測它是否被停止或是被啟動,下面兩個Core函式是您所需要的:
virtual CaError IsStopped (Stream * stream) ;
virtual CaError IsActive (Stream * stream) ;
範例:
while ( 1 == core . IsActive ( stream ) ) {
Timer :: Sleep ( sleepInterval ) ;
}
範例程式
/* Record specific device into conduit */
bool Core::Record ( Conduit * conduit ,
CaDeviceIndex deviceId ,
int channelCount ,
CaSampleFormat sampleFormat ,
int sampleRate ,
int frameCount ,
CaStreamFlags streamFlags ,
int sleepInterval )
{
if ( NULL == conduit ) return false ;
////////////////////////////////////////////////////////////////////////////
StreamParameters INSP ( deviceId , channelCount , sampleFormat ) ;
Stream * stream = NULL ;
CaError rt ;
bool correct = true ;
////////////////////////////////////////////////////////////////////////////
Initialize ( ) ;
////////////////////////////////////////////////////////////////////////////
INSP . suggestedLatency = GetDeviceInfo(deviceId)->defaultLowInputLatency ;
////////////////////////////////////////////////////////////////////////////
rt = Open ( &stream ,
&INSP ,
NULL ,
sampleRate ,
frameCount ,
streamFlags ,
conduit ) ;
if ( ( NoError != rt ) || ( NULL == stream ) ) correct = false ;
////////////////////////////////////////////////////////////////////////////
if ( correct ) {
rt = Start ( stream ) ;
if ( NoError != rt ) correct = false ;
////////////////////////////////////////////////////////////////////////////
while ( correct && ( 1 == IsActive ( stream ) ) ) {
Timer :: Sleep ( sleepInterval ) ;
} ;
//////////////////////////////////////////////////////////////////////////
if ( correct && ( 0 != IsStopped ( stream ) ) ) Stop ( stream ) ;
} ;
Close ( stream ) ;
Terminate ( ) ;
return correct ;
}