⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp3.h~

📁 用Mega32+VS1003做的MP3(FAT32文件系统浏览)——源代码
💻 H~
字号:
#ifndef _MP3_INCLUDED_
#define _MP3_INCLUDED_ 
//正点原子@scut 08/09/11
//很多部分参考网友(波仔)的
//实现功能:播放mp3/wma/wav/midi,支持mp3快进,前一首后一首选择,
//同时显示时间比特率和进度条
#include "vs1003.h" 
#include "fat.h" 
#include "snake.h"   

void deal_dsp(uchar keys);
uchar MaxFile=0;//此批次中,最大的文件个数   
bit bt30MS=0;//30MS 时间到   

//定时器1中断 30ms一次
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{   
    //static unsigned char *pp=pbuffer;//指向长文件名   
    TCNT1H=0xe2;
    TCNT1L=0xb3;//30MS 
    
    if(En_backlight)//使能背光打开
    {
        lasttime++;
        if(MenuOper==Ebook_Mode||(LYRIC&&ENLRC)||GAME_PLAY)lasttime=0;//TXT阅读/歌词显示模式下,背光一直打开 
        LCD_LED=1; 
        if(lasttime>150) //持续点亮4.5m
        {
            En_backlight=0;
            lasttime=0;
            LCD_LED=0;//关闭背光
        }
    }
    bt30MS=1;//标记中断 
} 
//定时器1,30ms中断
void timer_init()
{ 
    TCCR1A=0x00;
    TCCR1B=0x03;
    TCNT1H=0xe2;
    TCNT1L=0xb3;
    TIMSK=0x04;
    #asm("sei") 
} 

//在当前的目录中查找歌词文件,找到置相关数据至lyric中
//入口: 1.dircluster    当前目录的首簇号,若是FAT12或FAT16的根目录则为0
void FindLrcFile(unsigned long dircluster,unsigned char *strName)
{
	FIND_FILE_INFO	fp;
	direntry *de=0;	
	unsigned char  name[8];
	unsigned char i=0;     
	for(i=0;i<8;i++)name[i]=strName[i];//取前面八个字节  
	InitSetPath(&fp,dircluster);//初始化查找目录地址
	ReadBlock(fp.Sector);       //重新读取目录表 
	do 
	{  
		if(!ReadNextDirEntry(&fp)) {lyric.Clust=0;return;}//没找到任何歌词 
		de=(direntry *) BUFFER;
		de+=fp.Index; 
		if(*de->deName != 0xe5)
		{
			if((de->deAttributes&ATTR_LONG_FILENAME)!=ATTR_LONG_FILENAME)
			{
			    if((de->deAttributes& ATTR_DIRECTORY)!= ATTR_DIRECTORY)// is it a directory ?
			    {
			        for(i=0;i<8;i++)if(name[i]!=de->deName[i])break;                    
			        if(i==8) //主文件名比较正确 
			        {  
			   	        for(i=0;i<3;i++)//比较后缀
			   	        {
			   	            if((filetype[4][i])!=de->deExtension[i])break;//不符合 
			   	        }
			   	        if(i==3)break;//找到了符合的文件
			        }
			    }
	 	    } 
	    }
	    de++;
	    fp.Index++; 
	    if(de->deName[0]==0) { lyric.Clust=0;  return;} //文件的最后一项
	}while(1);  
	LYRIC=1; //标记找到歌词 
	lyric.first=1;  
	lyric.t_sec=lyric.t_ms=0;//初始化为0  
	lyric.so=0;
	lyric.sl=0;
	lyric.wl=0;  //初始位置
	lyric.filelen=(unsigned int)de->deFileSize; //保存歌词文件大小
	lyric.Clust=(unsigned long)((unsigned long)de->deHighClust<<16)+de->deStartCluster;//大小
} 
//check ok 08/09/06
//读取当前歌词文件的下一个字节
//支持自动换簇换扇区
unsigned char ReadChar(unsigned char *buf)
{  
	if(lyric.filelen>0)lyric.filelen--;//歌词长度减少  
	if(lyric.so!=64)//buffer溢出
	{
		return buf[lyric.so++];	
	}else//读取下一批数据
	{ 
		lyric.wl+=64;//扇区内偏移增加 64	
		if(lyric.wl>=512)//已跨扇区
		{ 
			lyric.wl=0;
			if(++lyric.sl>=SectorsPerCluster)//跨簇,几率不大
			{
				lyric.sl=0;//簇内偏移增加
				lyric.Clust=fatNextCluster(lyric.Clust);
				if(lyric.Clust==CLUST_EOFE)return 0xff;  //文件结束
			}              
		}	 
		SD_Read_Bytes(fatClustToSect(lyric.Clust)+lyric.sl,buf,lyric.wl,64);//从当前位置向后读取64字节
		lyric.so=0;
		return buf[lyric.so++];//先得到值,再加加!!!
	}
}  
//读取一句有效的歌词记录  
//check ok 08/09/06
//只支持单向时间
//如[xx:xx.xx][xx:xx.xx]....  则不支持  
void ReadLrcFileData(void)
{  
	unsigned char *lbuf=pbuffer+200;  
	unsigned char c;
	unsigned char i,bDot;  
	uchar work;  
	unsigned int tt;
	unsigned char *pp=pbuffer;//指向长文件名    
	lyric.t_sec=0xffff;lyric.t_ms=0; //时间清空 
	if(lyric.filelen==0) return;//歌词读取完了
	//从当前的位置读取歌词文件中的64个字节至缓冲区lbuf
	SD_Read_Bytes(fatClustToSect(lyric.Clust)+lyric.sl,lbuf,lyric.wl,64); 
	if(!lyric.first)//歌词还没有更新
	{  
		i=0;
		while(lyric.filelen>0)
		{
			c=ReadChar(lbuf);//从缓冲里面读取出一个字节    
			if(c!=0x0d)//没读到回车符号
			{	 
				if(++i<=50)*pp++=c;//读取二十八个字节到	
			}else//读到回车符号了
			{
				if(lyric.filelen>0) ReadChar(lbuf); //去除0x0a 
				break;
			}                      
		}
		*pp='\0'; 
		pp=pbuffer;  
		Cleardisplay(1);Cleardisplay(2);//清屏  
		LCD_write_String(1,0,pp,2);     //显示歌词 
	}        
	//读取下一句歌词
	lyric.first=0;      
	tt=0;work=0;
	bDot=0; 
	while(1)//歌词信息读取信息
	{ 
		if(lyric.filelen==0)return;
		c=ReadChar(lbuf);     //读取一个字节    
		if(work==0)  //支持 [xx:xx.xx] 及[xx:xx] 
		{     
			if(c=='[')work++;//开始读取时间 
		}else if(work==1)
		{
			if((c>='0')&&(c<='9'))//得到数据
			{
				tt=tt*10+(c-'0');//读取第一批时间
			}else if(c==':')     //上次读取的是分钟
			{
				lyric.t_sec=tt*60;tt=0;
			}else if(c=='.')//上次读取的是秒钟
			{     
				lyric.t_sec+=tt;tt=0;
				bDot = 1;
			}else if(c==']')//读取结束
			{           
				if(bDot==0)
				{
					lyric.t_sec+=tt;	
					lyric.t_ms=0;
				}else lyric.t_ms=tt/3; 
				c=ReadChar(lbuf);
				lyric.filelen++;//长度补偿   
				lyric.so--; 
				if(c!='['&&lyric.t_sec>=timer)break;//跳出歌词寻找 
				tt=0;work=0; bDot=0;  
			}else//读到非法数据 
			{
			    while(ReadChar(lbuf)!=0x0d);//非法数据忽略 
			    work=0;
			}
		}	 
	} 
}             
//check ok 08/09/06
// 歌词显示控制  
//同时控制显示解码时间   
//mnum 当前文件的序号 0~3
//注意:只支持单排时间的lrc正常显示
void LyricDisplayCtrl(uchar mnum)
{  
	static unsigned int time=0xffff;
	static unsigned char ms=0;  
	unsigned long lenth=0; 
	unsigned int t1;  
	if(!bt30MS)  return;//30ms未到
	ms+=3;//ms++
	bt30MS=0;  
	t1=GetDecodeTime(); //读取播放时间  
	if(t1!=time)//秒钟不合
	{
		time=t1;ms=0;//同步时间  
		timer=time;  //修改同步时间计数器(这个是歌词的准确计时器,不是显示的时间!) 
		             //如果这个乱了的话,歌词也会乱,所以快进后显示不了歌词
		//得到比特率
		t1=GetHeadInfo();  
        //显示歌曲长度             
        if(t1!=file_bps&&t1>0)//只有当kbps变化时才执行,提高系统速度
        {              
            //显示比特率Kbps
		    Show_mininum(6,93,t1/10);//显示高两位
		    show_minichar(6,105,t1%10);//显示最低位   
            file_bps=t1;//保存此次信息长度;
            //printf("BIT Rate is:%d\n",file_bps); 
            lenth=m_c[mnum].FileLen/125;//得到文件长度xxxx Kbps
            t1=lenth/t1;
            show_minichar(7,50,11); 
            Show_mininum(7,56,t1/60);//显示分钟
            show_minichar(7,68,10);
            Show_mininum(7,74,t1%60);//显示秒钟  
		}
		return;
	}
	if(!ENLRC||!LYRIC)return;//无歌词或者歌词被禁止使用  
	if(((t1==lyric.t_sec)&&(ms>=lyric.t_ms))||(t1>lyric.t_sec))
	{    
		ReadLrcFileData();  //读取歌曲数据并显示
	}   
}      
//显示歌曲名字
//num:歌曲序号           
void music_name(uchar mnum)
{
    uchar i;
    if(!ENLRC||!LYRIC)
    {   
        while(m_c[mnum].LongName[i]!='\0')//把短名字放中间显示
        {
            i++;
            if(i>21){i=22;break;}
        }                  
        i=66-3*i;//对13164液晶而言
        LCD_write_String(1,i,m_c[mnum].LongName,2);//无歌词/歌词显示不使能    
    }
}
//播放音乐(选中的)
//支持类型:mp3/wma/wav/midi
//check ok 08/09/05   
//返回状态值:next,用户要求播放下一首
//prev:用户要求播放上一首
//quit:结束播放 
uchar play(uchar mnum)
{
    unsigned long bfactor=0;
    unsigned long bcluster=0; 
    unsigned long prgpos=0;
    uchar count=0; 
    uint i;
    uchar n; 
    bit pause=1; 
    
    bcluster=m_c[mnum].Clust;  
    PLAYING=1;//播放模式标记    
    Audio_Ch=2;//选择mp3通道 
    LYRIC=0;//歌词标记清除
    bfactor=fatClustToSect(bcluster);
    vs1003_Reset();//软复位VS1003  
    FindLrcFile(CurDir.Clust,m_c[mnum].ShortName);//从当前目录找LRC
    Play_GUI();    //显示播放时的GUI
    MP3_msg(pause);//显示mp3的基本信息    
    music_name(mnum);  //显示歌名
    keyval=0;//键值清零
    while(1)
    {
        ReadBlock(bfactor);//放音乐  
        i=0;  
        do //主播放循环
        {  
            if((PINB&MP3_DATA_REQ)&&pause)
            {
                for(n=0;n<32;n++) 
                {     
                    vs1003_data_write(BUFFER[i++]);
                } 
            }   
            if(READY)//有按键响应
            {    
                keyval=key_process();//得到键值    
                switch(keyval) 
                {
                    case PREV://播放上一首
                    {  
                        if(times>3)   
                        {
                            for(i=0;i<20;i++)//向后偏移三十个簇
                            {
                                bcluster=fatNextCluster(bcluster);//偏移一个簇
                                if(bcluster==0x00)//读到文件簇尾
                                {
                                    vs1003_Reset();//软复位   
                                    if(!SINGLE)return NEXT;  //播放结束,播放下一首   
                                    else return 0;//单曲循环
                                }
                            } 
                            i=512;//快进   
                            count=8; 
                            bfactor=SectorsPerCluster;//大于65536
                            prgpos+=bfactor*10752; //progpos递增
                            prgpos-=512; 
                            break;
                        }  
                    }    
                    case NEXT://播放下一首
                    case QUIT://退出
                    { 
                        vs1003_Reset(); //软复位   
                        PLAYING=0;      //非播放模式   
                        return keyval; //返回  
                    }
                    case PLAY:pause=!pause;break;//暂停/播放   
                    case 168://歌词控制
                    {  
                        ENLRC=!ENLRC;//歌词显示使能与否 
                        Cleardisplay(1);Cleardisplay(2);//清除中间两行数据
                        music_name(mnum);//不使能 
                        break;
                    } 
		            case 106: //DSP保存
		            case 242: 
		            case 114: 
		            case 176: 
		            case 112:
		            {
		                deal_dsp(keyval); 
		                music_name(mnum);
		                break;  
		            }                   
                }          
                MP3_msg(pause);//改变后的界面信息
                keyval=0;//清除键值  
            }   
        }while(i<511);       
        LyricDisplayCtrl(mnum);//显示歌词控制
        LED=!LED;//观看系统相应速度   
        
        prgpos+=512;//进度条增加   
        Pro_msg(prgpos,mnum);//显示进度条    
        count++;
        bfactor++; //扇区加
        if(count>=SectorsPerCluster)//一个簇结束,换簇
        {
            count=0;
            bcluster=fatNextCluster(bcluster); 
            if(bcluster==0x00)break;  //文件结束
            bfactor=fatClustToSect(bcluster);
        }  
    }
    vs1003_Reset();//软复位   
    PLAYING=0;     //非播放模式   
    if(!SINGLE)return NEXT;//播放结束,播放下一首   
    else return 0;//单曲循环
}   
void deal_dsp(uchar keys)
{
    uchar t;   
    uchar d=0;
    switch(keys)
    {
        case 106:d=0;break; 
	    case 242:d=1;break; 
	    case 114:d=2;break; 
	    case 176:d=3;break; 
        case 112:d=4;break;        
    } 
    for(t=0;t<4;t++)                            
    {
        if(times>3)DSP[d][t]=voltemp[t];//保存dsp数值?    
        else voltemp[t]=DSP[d][t];//调出dsp?  
    }
    dspram=d;//dsp改变 
    if(times>3)//显示界面,其实这个时候都已经操作完了
    {
        Cleardisplay(4);//清屏   
        LCD_write_cstr(1,40,"DSP:");
        Show_char(1,74,d+'1',); 
        save_show();
        Play_GUI();//恢复先前的界面 
        READY=0;      
    }
    init_cd3315(Audio_Ch);//改变音量 
} 
#endif


















⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -