b. 打开MP3音频文件,用minimad.c中的参考解码流程进行解码。MP3解码mad_decoder_run()过程中,会通过input()回调函数加载更多的码流用于解码,解码完一帧,会通过output()回调函数播放等处理解码出来的音频数据,如果解码出现错误,通过error()回调函数进行错误的处理。
static int decode(void)
{
structmad_decoder decoder;
intresult;
/*configure input, output, and error functions */
mad_decoder_init(&decoder,0,
input,0 /* header */, 0 /* filter */, output,
error,0 /* message */);
/*start decoding */
result= mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
/*release the decoder */
mad_decoder_finish(&decoder);
returnresult;
}
c. input()回调函数加载更多的码流用于解码,从SD卡加载码流填充满缓存MadInputBuffer,libmad会读取一帧的码流长度数据用于解码,剩余的数据会被留作下一帧的解码,通过mad_stream_buffer()上报码流的位置及可用大小。文件结束后,停止播放,关闭文件,返回MAD_FLOW_STOP告知码流结束。
static enum mad_flow input(void *data,
struct mad_stream *stream)
{
unsigned char *ReadStart;
unsigned int ReadSize, ReturnSize;
int Remaining;
FRESULT Res;
switch (FileState) {
case 0:
ReadStart= MadInputBuffer;
ReadSize= FILE_IO_BUFFER_SIZE;
Remaining= 0;
FileState= 1;
break;
case 1:
/*Get the remaining frame */
Remaining= stream->bufend - stream->next_frame;
memmove(MadInputBuffer,stream->next_frame, Remaining);
ReadStart= MadInputBuffer + Remaining;
ReadSize= FILE_IO_BUFFER_SIZE - Remaining;
break;
default:
I2S_TxStop();
f_close(&file);
returnMAD_FLOW_STOP;
}
/* read the file from SDCard */
Res = f_read(&file, ReadStart,ReadSize, &ReturnSize);
if (Res != RES_OK) {
f_close(&file);
returnMAD_FLOW_BREAK;
}
/* if the file is over */
if (ReadSize > ReturnSize) {
FileState= 2;
}
mad_stream_buffer(stream,MadInputBuffer, ReturnSize+Remaining);
return MAD_FLOW_CONTINUE;
}
d. output()回调函数把解码出来的音频数据加载到音频输出流进行播放。第一帧解码完成后,可以从mad_header结构体获取MP3的采样率、通道数等等音频格式,对I2S音频驱动初始化。解码的左声道数据放在pcm->samples[0]缓存,右声道数据放在pcm->samples[1]缓存,每次解码一帧包含pcm->length个音频数据,一个一个填充到音频输出缓存,如果输出缓存满,则等待播放完一帧后,继续填充。
static enum mad_flow output(void *data,
struct mad_header const *header,
struct mad_pcm *pcm)
{
unsigned int nchannels, nsamples;
mad_fixed_t const *left_ch, *right_ch;
static int Index;
if (!Playing) {
PRINTF("Mode:%srn", header->mode==1?"Mono":"Stereo");
PRINTF("Samplerate:%d Hzrn", header->samplerate);
PRINTF("Bitrate:%d bpsrn", header->bitrate);
I2S_SetSamplerate(header->samplerate);
I2S_TxStart();
WriteIndex= I2SState.TxWriteIndex + 1;
Index= 0;
Playing= 1;
}
/* pcm->samplerate contains thesampling frequency */
nchannels = pcm->channels;
nsamples = pcm->length;
left_ch = pcm->samples[0];
right_ch = pcm->samples[1];
while (nsamples--) {
signedshort letf_sample, right_sample;
/*output sample(s) in 16-bit signed little-endian PCM */
letf_sample= scale(*left_ch++);
if(nchannels == 2) {
right_sample= scale(*right_ch++);
}else {
right_sample= letf_sample;
}
while(WriteIndex == I2SState.TxReadIndex) {
}
//Samplepair is 4 bytes, 16-bit mode
if(WriteIndex != I2SState.TxReadIndex) {
I2SState.TxBuffer[I2SState.TxWriteIndex][Index]= (letf_sample&0xffff)
| (right_sample<<16);
Index++;
if(Index >= AUDIO_FRAME_SIZE) {
Index= 0;
I2SState.TxWriteIndex= WriteIndex;
if(WriteIndex >= AUDIO_NUM_BUFFERS-1) {
WriteIndex= 0;
}else {
WriteIndex++;
}
}
}
}
return MAD_FLOW_CONTINUE;
}
e. error()回调函数进行错误的处理。
static enum mad_flow error(void *data,
struct mad_stream *stream,
struct mad_frame *frame)
{
returnMAD_FLOW_CONTINUE;
}
播放<<同一首歌>>MP3文件the same song.mp3如下:
4. 附录MDK工程,包含SD卡文件读写代码,I2S音频播放驱动,MP3文件播放的实现、<<同一首歌>>MP3文件the samesong.mp3。