加载中…
个人资料
蓝人
蓝人
  • 博客等级:
  • 博客积分:0
  • 博客访问:135,849
  • 关注人气:61
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

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

(2019-08-20 14:31:21)
标签:

mtk

faq

实现这类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);

 

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

{

 

FS_Close(TTSParam.filehandle);

}

}

}

}

kal_int32tts_media_play(void)

{

 

 

 

kal_uint32read_size=0;

kal_int32audio_format;

kal_int32result;

Media_Statusaud_ret;

Media_PCM_Stream_ParamvpFormat;

void*param=NULL;

 

 

 

{

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

{

 

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

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有