1. MP3的总体结构图
本MP3播放器是基于CooCox实时操作系统开发的,它能够播放Wave文件和MP3文件,其中MP3文件是通过软件解码之后进行播放的。另外,使用UCGUI来设计MP3的界面,通过触摸屏来进行相应的控制,这让用户使用更加方面。它主要由以下几个模块组成:SD卡模块、播放Wave文件模块、播放MP3文件模块、按键控制模块、触摸屏控制模块和LCD显示模块。设计中使用多任务来管理各个模块,并利用CooCox操作系统的调度机制,协调各个模块的执行。图1-1为MP3的总体结构图。
图1-1 MP3总体结构图
各个模块的主要功能如下:
(1)SD卡模块
SD卡模块主要是管理SD卡中的音频文件,它读写SD卡里的文件,根据文件的类型(.wav或.mp3)分别选择Wav模块或MP3模块播放对应的音频文件。
(2)播放Wav模块
主要是用来播放SD卡里的Wav文件。
(3)播放MP3模块
先对SD卡里的MP3文件进行解码,然后播放解码后的PCM(Pulse Code Modulation,脉冲编码调制)数据。
(4)按键控制模块
使用开发板上的USR-LEFT和USR-RIGHT按钮在MP3的歌曲选择列表中选择歌曲。
(5)触摸屏控制模块
程序中通过触摸屏来对MP3播放器进行控制,可以通过触摸屏控制MP3播放、暂停、停止、切换到上一首、切换到下一首、打开歌曲选择列表、选择歌曲等等。
(6)LCD显示模块
LCD显示模块是基于UCGUI开发的,主要是用来显示MP3播放界面(包括停止、上一首、播放、暂停、下一首、打开等按钮)、歌曲选择界面、播放进度及时间。该图形用户界面的移植比较简单,只需要将开发板LCD的驱动程序添加进UCGUI,再经过一些配置修改就可完成,具体可见下面的UCGUI移植过程。LCD显示模块包括4个功能部分,即播放界面的显示、歌曲选择列表的显示、歌曲名的同步显示、播放进度以及播放时间的显示。图1-2为LCD显示模块结构图。
图1-2 LCD模块图
2.MP3播放器的设计
2.1 任务创建
如前一节介绍所说,总共创建了8个任务,分别如下:
void SDCardTask(void) // 从SD卡中读取文件,并判断文件的类型
void PlayWaveTask(void) // 用于播放Wav文件
void DecodeTask(void) // 用于解码及播放MP3文件
void ProgbarTask(void) // 用于显示进度条及歌曲播放时间
void LRCShowTask(void) // 用于显示当前播放歌曲的歌词
void ReadButtonTask(void) // 读用户按钮,用于歌曲选择列表中
void TouchScreenTask(void) // 读取触摸屏状态,对MP3播放器进行控制
void GUITask(void) // 用于在LCD屏上显示MP3播放界面
2.2 各任务的详细介绍
(1)SD卡任务
SD卡任务的详细流程如图2-1所示:
>>>图2-1 SD卡任务的流程图
本程序中SD卡任务很简单,它根据文件的下标MusicFileOffset从SD卡中读取对应文件的文件名,然后判断这个文件是不是Wav文件,如果是就发送一个事件标志PlayWaveTask_EvtFlag给PlayWaveTask任务,让它播放Wav文件;相应的如果是MP3文件,就发送事件标志DecodeTask_EvtFlag给DecodeTask任务,让它播放MP3文件。
(2)播放Wav任务
播放Wav文件的任务主要流程如图2-2所示:
图2-2 播放Wav文件的流程图
PlayWaveTask任务中使用CoWaitForSingleFlag(PlayWaveTask_EvtFlag, 0);语句来等待事件标志PlayWaveTask_EvtFlag,在PlayWaveTask_EvtFlag标志没有发送过来的情况下,该任务一直处于等待状态。当SD卡任务发送PlayWaveTask_EvtFlag标志过来时,该任务就处于就绪状态了,然后它就按照上述流程开始播放Wav文件。
(3)播放MP3任务
播放MP3任务的详细流程如图2-3所示:
图2-3 播放MP3文件的流程图
开始时DecodeTask任务处于等待状态,直到SD卡任务发送DecodeTask_EvtFlag事件标志过来时,它就处于就绪状态了,接下来就可以解码和播放MP3文件了。
DecodeTask与PlayWaveTask的执行流程差不多,唯一的区别是PlayWaveTask任务可以直接播放SD卡里的Wav文件,而DecodeTask任务则需要先把SD卡里的MP3数据经过解码之后转换成PCM数据,然后直接播放PCM数据。
(4)按键任务
按键控制任务的详细流程如图2-4所示:
图2-4 读取按键任务的流程图
从流程图中可以看出,开发板上的USR-LEFT或USR-RIGHT按钮只有在MP3处于歌曲选择界面的时候才可用,其他时候按下没有效果。
(5)触摸屏任务
触摸屏任务的详细流程如图2-5所示:
图2-5 触摸屏任务的流程图
触摸屏任务是整个MP3设计的关键,因为所有MP3的控制都是通过触摸屏来进行的。在MP3显示不同界面时,按下触摸屏上同一个地方所执行的功能是不一样的。
当MP3处于播放界面的时候,在界面的最下方会出现5个按钮图标,功能从左到右分别为停止、上一首、播放、下一首、打开,当按下播放按钮后,那么MP3开始播放音乐,这时播放按钮图标变成了暂停按钮图标,这时就可以按下暂停按钮了。
当按下MP3播放界面的Open按钮后,LCD屏上就会显示当前的歌曲选择列表,这时就可以使用开发板上的USR-LEFT或USR-RIGHT按键来进行歌曲的选择了。此时LCD屏的左下角和右下角分别有OK和Back两个图标,按下OK就会回到MP3播放界面,并播放所选择的歌曲,按下Back也会返回到MP3播放界面,但这时播放的是进入歌曲选择界面之前的音乐。
按下触摸屏上不同的按钮之后,具体所执行的动作如下:
① 按下停止按钮
·挂起进度条任务,让进度条回到最开始
·停止Wav文件或MP3文件的播放,挂起SD卡任务
·如果之前界面上显示的是暂停按钮,就让它显示为播放按钮
② 按下切换到上一首按钮
·文件偏移标志MusicFileOffset减1,停止当前音乐的播放,激活SD卡任务
③ 按下播放按钮
·播放按钮图标变为暂停按钮图标
·唤醒进度条任务,让它显示当前播放进度和时间
·如果之前音乐没有播放完就继续播放,否则激活SD卡任务,重新开始播放
④ 按下暂停按钮
·暂停按钮图标变为播放按钮图标
·挂起进度条任务
·暂停Wav文件或MP3文件的播放
⑤ 按下切换到下一首按钮
·文件偏移标志MusicFileOffset加1,停止当前音乐的播放,激活SD卡任务
⑥ 按下打开按钮
·停止Wav文件或MP3文件的播放的播放,记录当前文件偏移标志,挂起SD卡任务
·删除MP3播放界面上的控件
·显示歌曲选择列表界面
⑦ 按下OK按钮
·删除歌曲选择列表界面上的控件
·显示MP3播放界面
·改变文件偏移标志MusicFileOffset,唤醒SD卡任务
⑧ 按下Back按钮
·删除歌曲选择列表界面上的控件
·显示MP3播放界面
·唤醒SD卡任务,播放进入歌曲选择界面之前的音乐
(6)进度条任务
歌曲的播放进度与歌曲的播放也是同步的,需要一个单独的任务来实现。该任务的实现比较简单,每延时1s,设置一次播放进度条的值,这个值是每次增加1的,这样就可以实现播放进度的显示。
在该任务中还实现了播放时间的显示,歌曲播放的总时间在PlayWavTask任务或DecodeTask任务中获取,播放时间也是同步显示的,跟播放进度的处理一样,每延时1s,时间值加1。
(7)歌词显示任务
这里只能显示LRC格式的歌词,而且歌词名必须与歌曲名完全一致才可识别。
LRC 歌词是一种包含着“[*:*]”形式的“标签(tag)”的、基于纯文本的歌词专用格式。最早由郭祥祥先生(Djohan)提出并在其程序中得到应用。这种歌词文件既可以用来实现卡拉OK功能(需要专门程序),又能以普通的文字处理软件查看、编辑。当然,实际操作时通常是用专门的LRC歌词编辑软件进行高效编辑的。LRC格式的歌词文件读取起来比较简单,这里就不详细介绍了。程序中大致处理流程是这样的:
在播放音乐之前,先把歌词文件的每个时间标签标示的一行存储到一个链表中。然后在歌词显示任务中,在LCD屏上显示一行歌词之后,等待一段时间(这个时间差与前后两行歌词的时间标签有关),然后再显示下一行歌词,直到显示结束。
(8)GUI任务
GUI任务中主要初始化UCGUI,以及显示MP3的播放界面,内容如下:
void GUITask(void)
{
GUITask_EvtFlag = CoCreateFlag(1, 0);
GUI_Init();
CoSetFlag(GUITask_EvtFlag);
while (1)
{
CoWaitForSingleFlag(GUITask_EvtFlag, 0);
/* MP3进入主界面 */
MP3_GUISel = MP3_GUI_MAIN;
Draw_MP3_Interface();
}
}
到目前为止,MP3的设计结束了,附件里是我们MP3设计具体实现时的一些代码,有兴趣的读者可以下载一看。
MP3源码:CooCox_MP3v1.5.rar
文章评论(0条评论)
登录后参与讨论