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

📄 mp3player.c

📁 基于stm32的MP3播放器
💻 C
字号:
#include "COMM.h"  

u16 f_kbps=0;//歌曲文件位率	

//进度条,时间,比特率 等事实信息显示控制
void MP3_PROG(u32 pos,u32 lenth)
{	
	static u16 playtime=0;//播放时间标记	     
	float propos=0;	
	u16 time=0;// 时间变量
	u16 temp=0;

	if(f_kbps==0xffff)//未更新过
	{
		playtime=0;
		f_kbps=GetHeadInfo();	   //获得比特率
	}
	POINT_COLOR=GREEN;
	BACK_COLOR=MP3COLOR4;	    

	if(lenth)
	{
		propos=(float)pos*512/lenth;//得到百分比 	
		if(propos>1)propos=1;//限制propos的范围
	}else return;//文件为空,返回    

  	if(f_kbps)//对位率不为0 的文件
	{
		time=(lenth/f_kbps)/125;//总时间
		time=propos*time;       //得到当前比例时间
	}else time=GetDecodeTime(); //对位率为0的文件,得到解码时间
 	
	propos=propos*180;//得到实际长度 
	TFT_ProBar((u8)propos);//显示进度条	  
	if(time!=playtime)//1s时间到,更新显示数据
	{
		  
		temp=GetHeadInfo(); //获得比特率	   				 
		if(temp)
		{
			f_kbps=temp;//更新KBPS	
			time=(((float)lenth/f_kbps)/125)*(propos/180);//更新时间	 
		}
		playtime=time;//更新时间 	 
		 
		//显示播放时间			 
		TFT_ShowNum(87,72,time/60,12,0); //分钟	   
		TFT_ShowChar(99,72,':',12,0);   
		TFT_ShowNum(105,72,time%60,12,0);//秒钟 
		TFT_ShowChar(117,72,'/',12,0);	 
		//显示总时间
		if(f_kbps)time=(lenth/f_kbps)/125;//得到秒钟数   (文件长度(字节)/(1000/8)/比特率=持续秒钟数    	  
		else time=0;//非法位率
		TFT_ShowNum(123,72,time/60,12,0);//显示总分钟数

		TFT_ShowChar(135,72,':',12,0);  	  
		TFT_ShowNum(141,72,time%60,12,0);//显示总秒钟数  
		//显示位率			   
		TFT_Show3Num(168,72,f_kbps,12,0);
		TFT_ShowChar(186,72,'k',12,0);
		TFT_ShowChar(192,72,'b',12,0);
		TFT_ShowChar(198,72,'p',12,0);
		TFT_ShowChar(204,72,'s',12,0);
	}   		 
}
u8 *MP3_VOL[5]={" 音量 "," 高音 "," 低音 ","左声道","右声道"};
u8 *MP3_OTHER[3]={"频谱显示","歌词显示","退出播放"};
 		  
//检测数据合法性
void VOL_Data_Check(u8 volx,u8 *datax)
{
	switch(volx)
	{
		case 0:	//主音量
			if(*datax>64)*datax=64;
			if(*datax<1)*datax=1;
			break;
		case 1:	//高音			  
		case 2:	//低音
			if(*datax>15)*datax=15;
			if(*datax<1)*datax=1;
			break;
		case 3: //左声道
		case 4:	//右声道
			if(*datax>32)*datax=32;
			if(*datax<1)*datax=1;
			break;
		case 5://超重音
			if(*datax>1)*datax=1;
			break;		    
	}
}
//显示数据
void MP3_MsgBox_Data(u16 *sysmsg,u8 menu,u8 key)
{
	u16 volx;	   
	BACK_COLOR=MP3COLOR6;//背景色
	POINT_COLOR=RED;
	TFT_Fill(58,259,138,275,MP3COLOR6);//抹掉上次数据
	switch(menu)
	{
		case 0://音效模式		 
			if(key==7)INITDSP++;	 
			else if(key==8)
			{
				if(INITDSP==0)INITDSP=4;//数据合法性判断
				else INITDSP--; 
			}					    	
			if(INITDSP>4)INITDSP=0;				   
			TFT_ShowNum(82,259,INITDSP+1,16,0);//显示数据
			break;
		case 1:
			volx=(*sysmsg>>2)&0x07;
			if(key==7)voltemp[volx]++;	 
			else if(key==8)voltemp[volx]--; 
			VOL_Data_Check(volx,&voltemp[volx]);//数据合法性判断  
			TFT_ShowNum(82,259,voltemp[volx],16,0);//显示数据
			break;
		case 2:	
			volx=(*sysmsg>>5)&0x03;	 
			if(key==7){volx++;if(volx>2)volx=0;}	 
			else if(key==8) 
			{
				if(volx)volx--;
				else volx=2;
			} 				    						    	 
			*sysmsg&=0XFF9F;
			*sysmsg|=volx<<5; 					   
			Show_Str(58,259,MP3_OTHER[volx],0);
			break;   
	}
	//第三栏信息更新
	BACK_COLOR=MP3COLOR3;//背景色
	POINT_COLOR=GRED;
	for(volx=0;volx<3;volx++)TFT_ShowNum(26+60*volx,47,voltemp[volx],16,0);//显示音量信息  
	TFT_ShowNum(206,47,INITDSP+1,16,0);//显示音效信息  
}
//显示MP3目录表的信息
//*menu	  :先前的目录号
//*sysmsg :但前运行标志信息
//curmenu:当前目录号
void MP3_MsgBox_Menu(u16 *sysmsg,u8 *menu,u8 curmenu)
{
	u16 temp;   	 
	BACK_COLOR=MP3COLOR6;  
	//显示音效部分
	temp=(*sysmsg>>9)&0x01;
	if(curmenu==0)
	{
		POINT_COLOR=RED;  
		if(*menu==curmenu)//再次点击
		{
			temp=!temp;								  
			*sysmsg&=0XFDFF;
			*sysmsg|=temp<<9;
		}
		*menu=curmenu;
	}	 						
	else POINT_COLOR=GREEN;	  
	if(temp)Show_Str_Mid(8,227,"存音效",0,48);
	else Show_Str_Mid(8,227," 音效 ",0,48); 
	//显示音量
	temp=(*sysmsg>>2)&0x07;	   
	if(curmenu==1)
	{
		POINT_COLOR=RED;
		if(*menu==curmenu)//再次点击
		{
			temp++;
			if(temp>=5)temp=0;						   	 
			*sysmsg&=0XFFE3;
			*sysmsg|=temp<<2;
			temp=(*sysmsg>>2)&0x07;
		}
		*menu=curmenu;
	}	 
	else POINT_COLOR=GREEN;	  
	Show_Str_Mid(64,227,MP3_VOL[temp],0,48);
	//其他选择			    	 
	if(curmenu==2)
	{
		*menu=curmenu;
		POINT_COLOR=RED;  	 
	}
	else POINT_COLOR=GREEN;	 
	Show_Str_Mid(120,227," 其他 ",0,48);	 
}

							  
//RGB音乐彩灯控制
//val:0~100的数据	
void Mus_RGB_LED(u8 rval,u8 gval,u8 bval)
{	
	float ftemp;
	ftemp=(float)MAX_Red/100;
	rval=ftemp*rval;//得到红色分量值
	ftemp=(float)255/100;
	gval=ftemp*gval;//得到红色分量值
	bval=ftemp*bval;//得到红色分量值
	LED_R=rval;
	LED_G=gval;
	LED_B=bval;
}
							  	 
//播放选定的歌曲 					  
//index:当前播放的歌曲索引
//total:总共音乐文件的个数
//关于音乐的几乎所有控制都在这个里面
u8 Mus_Play(FileInfoStruct *FileName,u16 index,u16 total)
{	 
    unsigned long bfactor=0; //物理扇区,绝对地址
    unsigned long bcluster=0;//物理簇号
	u32 file_pos=0;          //记录文件播放的长度 
    u8 count=0; 			 //扇区计数器,用于换簇
    u16 i,n;
    u8 key,menux=1;
	u8 keycnt;	 //按键计数器
	u8 FFT_LRC=0;//默认FFT

 	u8 *BUFFER=(u8*)MCUBuffer;//指向JPEG的开始512字节
	u8 *spedate=(u8*)MCUBuffer+512;//当前频谱分析的结果寄存器
  	u8 *topval=(u8*)MCUBuffer+526; //FFT柱的最高点记录表
	u8 *flyval=(u8*)MCUBuffer+540; //FFT柱的悬浮点记录表
			  	   
	u8 mark=1;		//标记
	u8 timer=0;		//频谱定时器
	u32 topstay1;   //最高点频点延时1
	u32 topstay2;	//最高点频点延时2
	//bit0~9用来标记功能 ,默认全部循环
	//bit0,1:循环模式;bit2,3,4:音量设置;bit5,6:其他设置
	//bit7:超重低音标记;bit8:是否有歌词;bit9:音效存/取标记
	u16 sysfun=1;
	u16 temp;		  
	u8 forpreclust;//快进快退需要的簇数  									 
 	 		   															 
	timer3_init();//初始化歌词显示定时器
	INITDSP=FM24C16_ReadOneByte(30);//调用DSP值
	if(INITDSP>4)//未初始化,则初始化
	{
		INITDSP=0;			
		for(temp=0;temp<31;temp++)FM24C16_WriteOneByte(temp,0);//全部清空
	}else read_dsp();  //已经初始化过了	读取DSP效果	  
	init_pt2314(MP3_Audio);//设置声音

	MUS_RGB_Status=FM24C16_ReadOneByte(487);//读取音乐彩灯标志		  
	if(FFT_LRC==0)
	{
		LED_R=0;
		LED_G=0;
		LED_B=0;	
		ENRGB(MUS_RGB_Status);//使能音乐彩灯(如果设置MUS_RGB_Status位的话)			 
	}else ENRGB(0);		      //关闭彩灯
	Read_VS_Set();//读取VS1003的设置

RESTART:

	forpreclust=FileName->F_Size/(SectorsPerClust*BytesPerSector*50);//每次前进/后退 2%所需要的簇数	   
	if(forpreclust<2)forpreclust=2;//最少也要两个簇
	//fft部分,变量清空
	topstay1=0;
	topstay2=0;
	file_pos=0;	  
	keycnt=0;
	f_kbps=0xffff;//文件位率设置为不可能值
	count=0;	  //扇区计数器

    bfactor=fatClustToSect(FileName->F_StartCluster);//得到开始簇对应的扇区
	bcluster=FileName->F_StartCluster;				 //得到文件开始簇号	
	printf("F_StartCluster:%d\n",FileName->F_StartCluster);
	   
	//从当前目录下找歌词文件,有,则标记.	 
	if(FindLrcFile(Cur_Dir_Cluster,FileName->F_ShortName))
	{								   
		sysfun|=1<<8;     //标记有歌词
		Lrc_Read_Init();  //初始化歌词读取
	}else sysfun&=~(1<<8);//标记没有歌词
								  
	Mp3Reset();       //硬复位
	Vs1003SoftReset();//软复位VS1003
	LoadPatch();      //加载频谱分析代码 
 	Load_Gui_Mp3(sysfun);//加载播放界面

	timer=5;//设置到一个不可能的值,初始化信息栏						 
	MP3_MsgBox_Menu(&sysfun,&timer,menux);//加载信息栏
	MP3_MsgBox_Data(&sysfun,menux,1);     //加载数据 
	//显示但前文件夹下的歌曲数目,及当前歌曲的索引
	BACK_COLOR=MP3COLOR4;
	POINT_COLOR=GREEN; 
	TFT_Show3Num(30,72,index,12,0);
	TFT_ShowChar(48,72,'/',12,0); 
	TFT_Show3Num(54,72,total,12,0); 
	//显示歌曲标题
	POINT_COLOR=WHITE;
	Show_Str_Mid(0,24,FileName->F_Name,0x01,240); //显示歌曲名字
	//FFT数据清空
	for(i=0;i<14;i++)//清空相关数据
	{
		topval[i]=0;		 	    
		flyval[i]=0;
		spedate[i]=0;
	}								  
	key=0;		 	    
	Pen_Point.Key_Sta=Key_Up;//释放按键			
	while(1)   //播放音乐的主循环
    {
        if(SD_ReadSingleBlock(bfactor,BUFFER))break;//读取一个扇区的数据 
        i=0;  	  
        count++;//扇区计数器 
		do      //主播放循环
        {  
			while((GPIOC->IDR&MP3_DREQ)==0&&((sysfun&0X0400)==0)) //等待高/进行频谱显示/非暂停 
			{
				if(FFT_LRC==0)//频谱模式
				{
					if(mark)
					{
						GetSpec(spedate);//得到频谱数据
						if(MUS_RGB_Status==1)Mus_RGB_LED(topval[1],topval[10],topval[7]);//使能了渐变模式	   
						else if(MUS_RGB_Status==2)Mus_RGB_LED(spedate[1],spedate[10],spedate[7]);//使能了跳变模式

						MP3_PROG(file_pos,FileName->F_Size);//MP3进度显示/播放时间  
					}
					else TFT_ShowFFT(spedate,topval,flyval,&topstay1,&topstay2);//频谱显示     	  
					timer++; 
					if(timer>=3)//FFT最高的悬浮点控制 
					{
						Top_Delet_FFT(flyval,&topstay1,&topstay2);//删除高端
						timer=0; 
					}   
				}else 	    //歌词模式
				{					   											    
					if(mark&&sysfun&(1<<8))LyricDisplayCtrl();//存在歌词,则显示
					else if(mark==0)MP3_PROG(file_pos,FileName->F_Size);//MP3进度显示/播放时间 				  
					//printf("end\n");
				}	
				mark=!mark;
			}	 
			if((GPIOC->IDR&MP3_DREQ)!=0&&((sysfun&0X0400)==0))  //非暂停,送数据给VS1003
			{			   	 
	            for(n=0;n<32;n++)Vs1003_DATA_Write(BUFFER[i++]);//发送音乐数据    
			} 
			if((Pen_Point.Key_Sta==Key_Down||NPEN)&&Pen_Point.Key_LSta)key=Touch_To_Num(3);//得到按键值 
			if(PEN)//按键松开了,状态改变(状态机)
			{
				Pen_Point.Key_LSta=1;
				keycnt=0;
				Pen_Point.Key_Sta=Key_Up;
			}
			if(key)//有按键按下
			{
				Pen_Point.Key_LSta=0;
				switch(key)
				{
					case 1://循环模式更改
						temp=sysfun&0x03;
						temp++;
						if(temp>1)temp=0;//只用其中两个,单曲循环/全部循环
						//显示循环模式		  
						BACK_COLOR=MP3COLOR4;
						POINT_COLOR=GREEN;
						TFT_ShowButton(214,72,temp+2);//加载循环模式   
						sysfun&=0XFFFC;
						sysfun|=temp;//更改标志位	
						break;
					case 2://Supper Bass 部分
						temp=(sysfun>>7)&0x01;	   
						voltemp[5]=temp;//记录超重低音值
						temp=!temp;	 
						init_pt2314(MP3_Audio);//设置生效
						//显示超重低音部分		 
						BACK_COLOR=MP3COLOR5;
						POINT_COLOR=GRED;  
						if(temp)Show_Str_Mid(0,102,"Supper Bass",0,240);
						else Show_Str_Mid(0,102,"           ",0,240);//清除显

⌨️ 快捷键说明

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