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.


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31529038/viewspace-2654280/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/31529038/viewspace-2654280/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值