MTK FAQ:如何实现连续的PCM流播放

实现这类PCM的播放(类似于TTS)思路及samplecode如下:

使用双buffer的机制,TTS使用一个,DSP使用另一个,两个大小一样。其中DSP使用的由DSP自行管理,TTS使用的由TTS自行管理。建议TTS使用ringbuffer的机制,设置一个写指针和一个读指针,分别指示TTS可以写入的开始位置和DSP可以读出的开始位置,两者的差为可以写入和可以读出的长度。

使用流程:

1.开始TTS合成.

2.合成出来第一段PCM数据后调用tts_media_play函数,开始播放,设置callback函数Pcm_play_callback。(在开始播放后,tts_media_play只应被调用一次,后面喂数据应该是由Pcm_play_callback来完成)

3.TTS继续合成数据,合成完后就放合适大小(通过计算读指针与写指针的差)的PCM数据到TTSbuffer写指针指示的位置中,并暂停下来等待DSP的event发生。TTSenging如果不能暂停就只能把多出来的数据丢弃。

4.等DSP有event发生底层就会自动调用Pcm_play_callback,如果是MEDIA_DATA_REQUEST的event,就从TTSbuffer里面拷贝合适大小(通过GetWriteBuffer获知DSP可以接受的数据,和TTSbuffer的写指针与读指针的差做比较,取其中的小者)的数据到DSPbuffer.如果DSP的event上来时TTS还来不及合成数据就立刻返回。

5.如果TTS把所有数据都合成完毕并全部传给了DSP的buffer,或者从DSP收到MEDIA_END,MEDIA_ERROR,MEDIA_TERMINATED,就调用Stop,Close,DataFinished停止播放。

下面是samplecode,供参考:

#defineTTS_BUFFER_LEN1*1024

typedefunsignedcharuint8;

typedefsignedcharint8;

typedefunsignedshortintuint16;

typedefsignedshortintint16;

typedefunsignedintuint32;

typedefsignedintint32;

structVParam

{

uint8*buf_p;

uint32buf_len;

uint32offset;

FS_HANDLEfilehandle;

MHdl*mhdl_handle;

}TTSParam;

kal_uint16tts_ring_buf[TTS_BUFFER_LEN];

voidtts_init(void)

{

TTSParam.buf_p=tts_ring_buf;

TTSParam.buf_len=0;

}

staticvoidPcm_play_callback(MHdl*mhdl,Media_Eventevent)

{

switch(event){

caseMEDIA_END:

caseMEDIA_ERROR:

caseMEDIA_TERMINATED:

{

TTSParam.mhdl_handle->Stop(TTSParam.mhdl_handle);

TTSParam.mhdl_handle->Close(TTSParam.mhdl_handle);

/*closethefile*/

FS_Close(TTSParam.filehandle);

break;

}

caseMEDIA_DATA_REQUEST:

{

kal_uint32read_size=0;

TTSParam.mhdl_handle->GetWriteBuffer(

TTSParam.mhdl_handle,

&TTSParam.buf_p,

&TTSParam.buf_len);

FS_Read(TTSParam.filehandle,TTSParam.buf_p,TTSParam.buf_len,&read_size);

if(read_size>0)

{

TTSParam.mhdl_handle->WriteDataDone(

TTSParam.mhdl_handle,

read_size);

TTSParam.mhdl_handle->FinishWriteData(TTSParam.mhdl_handle);

}

else

{

/*closethefile*/

FS_Close(TTSParam.filehandle);

}

}

}

}

kal_int32tts_media_play(void)

{

/*----------------------------------------------------------------*/

/*LocalVariables*/

/*----------------------------------------------------------------*/

kal_uint32read_size=0;

kal_int32audio_format;

kal_int32result;

Media_Statusaud_ret;

Media_PCM_Stream_ParamvpFormat;

void*param=NULL;

/*----------------------------------------------------------------*/

/*CodeBody*/

/*----------------------------------------------------------------*/

{

vpFormat.isStereo=0;

vpFormat.bitPerSample=16;

vpFormat.sampleFreq=8000;

param=&vpFormat;

TTSParam.filehandle=FS_Open(L"C:\\Images\\OutPcm.pcm",FS_READ_ONLY);

if((TTSParam.mhdl_handle=PCM_Strm_Open(Pcm_play_callback,param))==NULL)

{

return;

}

TTSParam.mhdl_handle->SetBuffer(

TTSParam.mhdl_handle,

(kal_uint8*)tts_ring_buf,

TTS_BUFFER_LEN*2);

TTSParam.mhdl_handle->GetWriteBuffer(

TTSParam.mhdl_handle,

&TTSParam.buf_p,

&TTSParam.buf_len);

FS_Read(TTSParam.filehandle,TTSParam.buf_p,TTSParam.buf_len*2,&read_size);

//hereshouldbeerrorhandlingforFS_Read

if(read_size>0)

{

TTSParam.mhdl_handle->WriteDataDone(

TTSParam.mhdl_handle,

read_size);

aud_ret=TTSParam.mhdl_handle->Play(TTSParam.mhdl_handle);

}

else

{

/*closethefile*/

FS_Close(TTSParam.filehandle);

}

}

}

voidtts_test1(void)

{

tts_init();

tts_media_play();

}

因为在singlebankflash的情况下,为了防止同时读写一个bank的情况发生,需要把wavetable的数据搬到RAM上,所以设置为RW数据。但如果你的flash本身是multibank,却开启了singlebanksupport,那么只要保证wavetable放在和FAT不相同的一个bank上,就可以不必搬到RAM上,亦即可以修改为const.

来源:http://bbs.16rd.com/thread-479503-1-1.html

你可能感兴趣的:(MTK FAQ:如何实现连续的PCM流播放)