- #include "wave.h"
- #include "mp3.h"
- #include "string.h"
- #include "mp3dec.h"
- #include "wm8978.h"
- #include "i2s.h"
- //__align(8)
- //uint16_t Mp3DecodeBuf[DECODEBUFSIZE];
- short *Mp3DecodeBuf;
- FIL Mp3File;
- mp3Info Mp3Info;
- uint8_t* Readptr; //MP3解码读指针
- int32_t ByteLeft;//buffer还剩余的有效数据
- uint8_t InitMp3InfoFlag;
- HMP3Decoder Mp3Decoder;
- uint32_t DmaBufSize;
- /*==========================================================*/
- unsigned char DACbz_mp3;
- unsigned char CH_mp3;
- unsigned int DApc_mp3;
- unsigned char buffer_switch;
- HMP3Decoder hMP3Decoder;
- FIL f_MP3;
- //int16_t *buffer1={0x00};
- //int16_t *buffer2={0x00};
- short *buffer1;
- short *buffer2;
- void TIM3_IRQHandler(void)
- {
- if(TIM3->SR&0X0001)//溢出中断
- {
- if(CH_mp3==1)//单声道
- {
- if(buffer_switch==0)
- {
- DAC->DHR12R1=(((uint16_t)buffer1[DApc_mp3]+0x8000)>>4);//*10/volume;
- DAC->DHR12R2=(((uint16_t)buffer1[DApc_mp3]+0x8000)>>4);//*10/volume;
- DApc_mp3++;
- DAC->SWTRIGR|=0x03;//软件启动两个通道的转换
- }
- else
- {
- DAC->DHR12R1=(((uint16_t)buffer2[DApc_mp3]+0x8000)>>4);//*10/volume;
- DAC->DHR12R2=(((uint16_t)buffer2[DApc_mp3]+0x8000)>>4);//*10/volume;
- DApc_mp3++;
- DAC->SWTRIGR|=0x03;//软件启动两个通道的转换
- }
- }
- else //if(CH_mp3==2)//立体声 10110010 10110010
- {
- if(buffer_switch==0)
- {
- DAC->DHR12R1=(((uint16_t)buffer1[DApc_mp3]+0x8000)>>4);//*10/volume;
- DApc_mp3++;
- DAC->DHR12R2=(((uint16_t)buffer1[DApc_mp3]+0x8000)>>4);//*10/volume;
- DApc_mp3++;
- DAC->SWTRIGR|=0x03;//软件启动两个通道的转换
- }
- else
- {
- DAC->DHR12R1=(((uint16_t)buffer2[DApc_mp3]+0x8000)>>4);//*10/volume;
- DApc_mp3++;
- DAC->DHR12R1=(((uint16_t)buffer2[DApc_mp3]+0x8000)>>4);//*10/volume;
- DApc_mp3++;
- DAC->SWTRIGR|=0x03;//软件启动两个通道的转换
- }
- }
- if(DApc_mp3==2304)/// //1帧MP3输出2304数据
- {
- DApc_mp3=0;
- DACbz_mp3=1;
- }
- }
- TIM3->SR&=~(1<<0);//清除中断标志位
- }
- //设置NVIC分组
- //NVIC_Group:NVIC分组 0~4 总共5组
- //CHECK OK
- //091209
- void MY_NVIC_PriorityGroupConfig(unsigned char NVIC_Group)
- {
- uint32_t temp,temp1;
- temp1=(~NVIC_Group)&0x07;//取后三位
- temp1<<=8;
- temp=SCB->AIRCR; //读取先前的设置
- temp&=0X0000F8FF; //清空先前分组
- temp|=0X05FA0000; //写入钥匙
- temp|=temp1;
- SCB->AIRCR=temp; //设置分组
- }
- //设置NVIC
- //NVIC_PreemptionPriority:抢占优先级
- //NVIC_SubPriority :响应优先级
- //NVIC_Channel :中断编号
- //NVIC_Group :中断分组 0~4
- //注意优先级不能超过设定的组的范围!否则会有意想不到的错误
- //组划分:
- //组0:0位抢占优先级,4位响应优先级
- //组1:1位抢占优先级,3位响应优先级
- //组2:2位抢占优先级,2位响应优先级
- //组3:3位抢占优先级,1位响应优先级
- //组4:4位抢占优先级,0位响应优先级
- //NVIC_SubPriority和NVIC_PreemptionPriority的原则是,数值越小,越优先
- //CHECK OK
- //100329
- void MY_NVIC_Init(unsigned char NVIC_PreemptionPriority,unsigned char NVIC_SubPriority,unsigned char NVIC_Channel,unsigned char NVIC_Group)
- {
- uint32_t temp;
- unsigned char IPRADDR=NVIC_Channel/4; //每组只能存4个,得到组地址
- unsigned char IPROFFSET=NVIC_Channel%4;//在组内的偏移
- IPROFFSET=IPROFFSET*8+4; //得到偏移的确切位置
- MY_NVIC_PriorityGroupConfig(NVIC_Group);//设置分组
- temp=NVIC_PreemptionPriority<<(4-NVIC_Group);
- temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
- temp&=0xf;//取低四位
- if(NVIC_Channel<32)NVIC->ISER[0]|=1<<NVIC_Channel;//使能中断位(要清除的话,相反操作就OK)
- else NVIC->ISER[1]|=1<<(NVIC_Channel-32);
- NVIC->IP[IPRADDR]|=temp<<IPROFFSET;//设置响应优先级和抢断优先级
- }
- //通用定时器4中断初始化
- //这里始终选择为APB1的2倍,而APB1为36M
- //arr:自动重装值。
- //psc:时钟预分频数
- //这里使用的是定时器4!
- void Timer3_Init(unsigned int arr,unsigned int psc)
- {
- RCC->APB1ENR|=1<<1;//TIM3时钟使能
- TIM3->ARR=arr; //设定计数器自动重装值//刚好1ms
- TIM3->PSC=psc; //预分频器7200,得到10Khz的计数时钟
- //这两个东东要同时设置才可以使用中断
- TIM3->DIER|=1<<0; //允许更新中断
- TIM3->DIER|=1<<6; //允许触发中断
-
- TIM3->CR1|=0x01; //使能定时器3
- MY_NVIC_Init(1,3,0x1D,2);//抢占1,子优先级3,组2
- }
- //DAC通道1输出初始化 要用双通道的还要加上DAC2的初始化
- /*void Dac1_Init(void)
- {
- RCC->APB2ENR|=1<<2; //使能PORTA时钟
- RCC->APB1ENR|=1<<29; //使能DAC时钟
- GPIOA->CRL&=0XFFF0FFFF;
- GPIOA->CRL|=0X00000000;//PA4 模拟输入(虽然是输入,但是STM32 内部会连接在DAC 模拟输出上
- DAC->CR|=1<<0; //使能DAC1
- DAC->CR|=0<<1; //DAC1输出缓存使能 BOFF1=0
- DAC->CR|=0<<2; //不使用触发功能 TEN1=0
- DAC->CR|=0<<3; //DAC TIM6 TRGO,不过要TEN1=1才行
- DAC->CR|=0<<6; //不使用波形发生
- DAC->CR|=0<<8; //屏蔽、幅值设置
- DAC->CR|=0<<12; //DAC1 DMA不使能
- DAC->DHR12R1=0;
- DAC->DHR12L1=0;
- DAC->SWTRIGR|=0x01;//通道1软件启动转换
- }*/
- void DAC1_SetData(unsigned int data)
- {
- DAC->DHR12R1=data;//通道1的12位右对齐数据
- DAC->SWTRIGR|=0x01;//软件启动转换
- }
- void DAC2_SetData(unsigned int data)
- {
- DAC->DHR12R2=data;//通道2的12位右对齐数据
- DAC->SWTRIGR|=0x02;//软件启动转换
- }
- void Dac1_Init(void)//DAC channel1 Configuration
- {
- unsigned int tmpreg1=0,tmpreg2=0;
- RCC->APB2ENR|=1<<2;//使能PORTA时钟
- RCC->APB1ENR|=0x20000000;//使能DAC时钟
- GPIOA->CRL&=0XFF00FFFF;
- GPIOA->CRL|=0X00440000;//PA4,5 浮空输入
- tmpreg1=DAC->CR;//Get the DAC CR value
- tmpreg1&=~(0x00000FFE<<0x00000000);//Clear BOFFx, TENx, TSELx, WAVEx and MAMPx bits
- tmpreg2=(0x0000003C|0x00000000|0x00000800|0x00000000);
- tmpreg1|=tmpreg2<<0x00000000;//Calculate CR register value depending on DAC_Channel
- DAC->CR=tmpreg1;//Write to DAC CR
- DAC->CR|=0x00000001<<0x00000000;//DAC Channel1使能,PA4自动连接到DAC
- DAC1_SetData(0x000);
- tmpreg1=DAC->CR;//Get the DAC CR value
- tmpreg1&=~(0x00000FFE<<0x00000010);//Clear BOFFx, TENx, TSELx, WAVEx and MAMPx bits
- tmpreg2=(0x0000003C|0x00000000|0x00000800|0x00000000);
- tmpreg1|=tmpreg2<<0x00000010;//Calculate CR register value depending on DAC_Channel
- DAC->CR=tmpreg1;//Write to DAC CR
- DAC->CR|=0x00000001<<0x00000010;//DAC Channel2使能,PA5自动连接到DAC
- DAC2_SetData(0x000);
- }
- /************************************************************************************/
- /*
- * File Name : Convert_Stereo μ¥éùμàμ?á¢ì?éù×a??
- * Description : I have do some modification in Subband() function due to the long time of
- * decode.Using PolyphaseMono() function which is used in decode mono mp3,to decode
- * Stereo,so must use this funtion to convert mono to Stereo.
- * Input : Adress of buffer data
- * Output : None
- * Return : None
- */
- /************************************************************************************/
- void Convert_Stereo(short *buffer)
- {
- int i,j,k=0;
- for(i=0;i<(2304/64);i++) //36
- {
- for(j=31+i*64,k=j+32;j>=0+i*64;j--,k-=2)
- {
- buffer[k]=buffer[j];
- buffer[k-1]=buffer[j];
- }
- }
- }
- /***********************************************************************************/
- /*
- * File Name : Convert_Mono
- * Description : ?o3?oóμ?μ¥éùμàMP3?a???÷μ??ò?ü£???ì?211152°?×?£??a??1|?ü*????±?μ¥éùμàμ?á¢ì?éù?£
- * Input : Adress of buffer data
- * Output : None
- * Return : None
- */
- /***********************************************************************************/
- void Convert_Mono(short *buffer)
- {
- int i;
- for (i = 1152 - 1; i >= 0; i--)
- {
- buffer[i * 2] = buffer[i];
- buffer[i * 2 + 1] = buffer[i];
- }
- }
- /*void mp3play(void)//MP3播放,这个函数在压缩包里面有
- {
- // int err;
- uint32_t br;
- FRESULT res;
- short *Outpcmbuf;//输出数据指针
- int bytesLeft;
- unsigned char *readBuf;//输入数据缓存
- unsigned char *readPtr;//读取数据指针
- signed long offset;
- unsigned char init;
- Outpcmbuf=buffer1;
- MP3FrameInfo mp3FrameInfo;
- //LCD_Clear(WHITE); //黑屏
- hMP3Decoder=MP3InitDecoder(); //初始化解码器
- Dac1_Init(); //用DAC播放
- res=f_open(&f_MP3,"0:/music/0001.MP3",FA_OPEN_EXISTING|FA_READ);//打开MP3文件
- printf("res=%d\r\n", res);
- bytesLeft=0; //复位计数器
- while(1)
- {
- res=f_read(&f_MP3,readBuf,4096,(UINT*)&br); //读出2048个字节
- //printf("res=%d\r\n", res);
- //printf("br=%d\r\n", br);
- if(res!=FR_OK||br==0) break;
- //printf("read mp3 success!\n");
- readPtr=readBuf;
- bytesLeft = br;
- buffer_switch=0; //双缓存切换标志
- init=0;
- while(1)
- {
- offset=MP3FindSyncWord(readPtr, bytesLeft);//寻找下一帧头 帧同步
- if(offset<0)break;
- //printf("MP3FindSyncWord success!\n");
- readPtr+=offset; //data start point
- bytesLeft-=offset; //in buffer
- MP3Decode(hMP3Decoder,&readPtr,&bytesLeft,Outpcmbuf,0);//解码
- // err=MP3Decode(hMP3Decoder,&readPtr,&bytesLeft,Outpcmbuf,0);//解码
- if(bytesLeft<4096) //补充数据
- {
- //printf("bytesLeft<4096!\n");
- memmove(readBuf,readPtr,bytesLeft);
- res=f_read(&f_MP3,readBuf+bytesLeft,4096-bytesLeft,(UINT*)&br);
- if((res)||(br==0)) break;
- //printf("read mp3 success!\n");
- if(br<4096-bytesLeft)
- memset(readBuf+bytesLeft+br,0,4096-bytesLeft-br);
- bytesLeft=4096;
- readPtr=readBuf;
- }
- MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); //获得解码
- if(init==0) //根据MP3帧信息初始化音频接口
- {
- //printf("enter Timer4_Init!\n");
- Timer3_Init(1000000/(mp3FrameInfo.samprate),71);// 1MHz的计数频率,产生和采样率一样的中断频率
- CH_mp3=mp3FrameInfo.nChans; //几声道
- //LCD_ShowNum(60+80,160,mp3FrameInfo.outputSamps,5,16); //打印=2304 //PCM 数据个数
- init=1;// //1帧MP3输出2304pcm数据
- }
- if(mp3FrameInfo.nChans==1)Convert_Mono(Outpcmbuf);//单声道
- else Convert_Stereo(Outpcmbuf);//立体声
- while(!DACbz_mp3); //等待转换完成
- DACbz_mp3=0; //定时器中断会置1
- if(buffer_switch == 0) //双缓存切换
- {
- Outpcmbuf=buffer1;
- buffer_switch = 1;
- }
- else
- {
- Outpcmbuf=buffer2;
- buffer_switch = 0;
- }
- //LED=!LED;
- }
- f_close(&f_MP3);//关闭文件
- }
- TIM4->CR1&=~0x01;//关定时器,切歌时不产生噪音
- DAC->CR&=0<<0; //关闭DAC1
- }
- ==========================================================*/
- uint8_t PlayMp3File(char* path)
- {
- uint8_t res=0;
- uint32_t br=0;
- //uint32_t Mp3DataStart=0;
- CloseFileFlag=0;
- EndFileFlag=0;
- FillBufFlag=0xFF;
- //ID3V2_TagHead *TagHead;
-
- Mp3DecodeBuf=buffer1;
- Mp3Decoder=MP3InitDecoder();
- if(Mp3Decoder==0)
- {
- printf("Init Mp3Decoder failed!\r\n");
- //res=4;
- //break;
- }
-
- Dac1_Init();
- res=f_open(&Mp3File,(TCHAR*)path,FA_READ);
- while(1)
- {
- if(res!=FR_OK)
- {
- printf("Open file failed!\r\n");
- res=1;
- break;
- }
- CloseFileFlag=1;
- res=f_read(&Mp3File,TempBuf,WAVEFILEBUFSIZE,&br);
- if(res!=FR_OK)
- {
- printf("Read file failed!\r\n");
- res=2;
- break;
- }
- /*TagHead=(ID3V2_TagHead*)TempBuf;
- //得到MP3数据的开始位置
- if(strncmp("ID3",(const char*)TagHead->id,3)==0)
- {
- Mp3Info.DataStart=((uint32_t)TagHead->size[0]<<21)|((uint32_t)TagHead->size[1]<<14)|((uint32_t)TagHead->size[2]<<7)|TagHead->size[3];
- f_lseek(&Mp3File,Mp3DataStart);
- res=f_read(&Mp3File,TempBuf,WAVEFILEBUFSIZE,&br);
- if(res!=FR_OK||br==0)
- {
- printf("Read file failed!\r\n");
- res=3;
- break;
- }
- }
- Mp3Decoder=MP3InitDecoder();
- if(Mp3Decoder==0)
- {
- printf("Init Mp3Decoder failed!\r\n");
- res=4;
- break;
- }*/
- Readptr=TempBuf;
- ByteLeft=br;
- /*InitMp3InfoFlag=0;
- while(EndFileFlag==0)
- {
- res=FillMp3Buf(WaveFileBuf);
- if(res==0)
- break;
- }
- res=My_I2S2_Init(Mp3Info.bitsPerSample,Mp3Info.samprate);
- printf("%d\r\n",res);
- DmaBufSize=Mp3Info.OutSamples*Mp3Info.bitsPerSample*4/(8*Mp3Info.nChans);
- printf("DmaBufSize=%d\r\n",DmaBufSize);*/
- FillMp3Buf(WaveFileBuf+DmaBufSize/2);
- //break;
- }
- /*if(res!=0)
- {
- printf("res=%d\r\n",res);
- if(CloseFileFlag)
- {
- f_close(&Mp3File);
- CloseFileFlag=0;
- }
- MP3FreeDecoder(Mp3Decoder);
- return res;
- }
- HAL_I2S_Transmit_DMA(&hi2s2,(uint16_t *)WaveFileBuf,DmaBufSize/2);
- while(1)
- {
- if(EndFileFlag==0)
- {
- if(FillBufFlag==0)
- {
- FillMp3Buf(WaveFileBuf);
- FillBufFlag=0xFF;
- }
- else
- if(FillBufFlag==1)
- {
- FillMp3Buf(&WaveFileBuf[DmaBufSize/2]);
- FillBufFlag=0xFF;
- }
- }
- else
- if(EndFileFlag==3)
- {
- HAL_I2S_DMAStop(&hi2s2);
- //printf("sr=%d\r\n",hi2s2.Instance->SR);
- //printf("cr2=%d\r\n",hi2s2.Instance->CR2);
- //printf("cfgr=%d\r\n",hi2s2.Instance->I2SCFGR);
- __HAL_I2S_ENABLE(&hi2s2);
- res=I2S_WaitFlagStateUntilTimeout(&hi2s2, I2S_FLAG_BSY, SET, 20);
- //printf("res=%d\r\n",res);
- __HAL_I2S_DISABLE(&hi2s2);
- //printf("sr=%d\r\n",hi2s2.Instance->SR);
- break;
- }
- }
- if(CloseFileFlag)*/
- f_close(&Mp3File);
-
- TIM4->CR1&=~0x01;//关定时器,切歌时不产生噪音
- DAC->CR&=0<<0; //关闭DAC1
- MP3FreeDecoder(Mp3Decoder);
- return 0;
- }
- uint32_t FillMp3Buf(uint8_t *Buf)
- {
- uint32_t br=0;
- int32_t Offset;
- int32_t err=0;
- //int32_t i;
- uint16_t *PlayPtr;
- //uint16_t *Mp3Ptr;
- MP3FrameInfo Mp3FrameInfo;
- int8_t init=0;
- Offset=MP3FindSyncWord(Readptr,ByteLeft); //在readptr位置,开始查找同步字符
- if(Offset<0) //没有找到同步字符,跳出帧解码循环
- {
- printf("Can not play the file!\r\n");
- return 1;
- }
- Readptr+=Offset; //MP3读指针偏移到同步字符处.
- ByteLeft-=Offset; //buffer里面的有效数据个数,必须减去偏移量
- //printf("ByteLeft=%d\r\n",ByteLeft);
- if(ByteLeft<MAINBUF_SIZE*2)//当数组内容小于2倍MAINBUF_SIZE的时候,必须补充新的数据进来.
- {
- memmove(TempBuf,Readptr,ByteLeft);//移动readptr所指向的数据到buffer里面,数据量大小为:bytesleft
- /*
- ReadBytesNum=WAVEFILEBUFSIZE-ByteLeft;
- if(ReadBytesNum%2)
- ReadBytesNum-=1;
- f_read(&Mp3File,TempBuf+ByteLeft,ReadBytesNum,&br);//补充余下的数据
- printf("rd=%d,br=%d\r\n",ReadBytesNum,br);
- if(br<ReadBytesNum)
- {
- memset(TempBuf+ByteLeft+br,0,WAVEFILEBUFSIZE-ByteLeft-br);
- //EndFileFlag=1;
- }
- ByteLeft=ByteLeft+ReadBytesNum;
- */
- f_read(&Mp3File,TempBuf+ByteLeft,WAVEFILEBUFSIZE-ByteLeft,&br);//补充余下的数据
- //printf("rd=%d,br=%d\r\n",WAVEFILEBUFSIZE-ByteLeft,br);
- if(br<WAVEFILEBUFSIZE-ByteLeft)
- {
- memset(TempBuf+ByteLeft+br,0,WAVEFILEBUFSIZE-ByteLeft-br);
- EndFileFlag=1;
- }
- ByteLeft=WAVEFILEBUFSIZE;
- Readptr=TempBuf;
- }
- err=MP3Decode(Mp3Decoder,&Readptr,&ByteLeft,Mp3DecodeBuf,0);//解码一帧MP3数据
- //printf("Decode error:%d\r\n",err);
- if(err!=0)
- {
- printf("Decode error:%d\r\n",err);
- return 2;
- }
- if(InitMp3InfoFlag==0)
- {
- MP3GetLastFrameInfo(Mp3Decoder,&Mp3FrameInfo); //得到刚刚解码的MP3帧信息
- Mp3Info.bitsPerSample=Mp3FrameInfo.bitsPerSample;
- Mp3Info.nChans=Mp3FrameInfo.nChans;
- Mp3Info.OutSamples=Mp3FrameInfo.outputSamps;
- Mp3Info.samprate=Mp3FrameInfo.samprate;
- printf("bitsPerSample=%d\r\n",Mp3Info.bitsPerSample);
- printf("nChans=%d\r\n",Mp3Info.nChans);
- printf("OutSamples=%d\r\n",Mp3Info.OutSamples);
- printf("samprate=%d\r\n",Mp3Info.samprate);
- InitMp3InfoFlag=1;
- if(init==0) //根据MP3帧信息初始化音频接口
- {
- Timer3_Init(1000000/(Mp3Info.samprate),71);// 1MHz的计数频率,产生和采样率一样的中断频率
- CH_mp3=Mp3Info.nChans; //几声道
- init=1;// //1帧MP3输出2304pcm数据
- }
- if(Mp3Info.nChans==1)Convert_Mono(Mp3DecodeBuf);//单声道
- else Convert_Stereo(Mp3DecodeBuf);//立体声
- while(!DACbz_mp3); //等待转换完成
- DACbz_mp3=0; //定时器中断会置1
- if(buffer_switch == 0) //双缓存切换
- {
- Mp3DecodeBuf=buffer1;
- buffer_switch = 1;
- }
- else
- {
- Mp3DecodeBuf=buffer2;
- buffer_switch = 0;
- }
-
- if(Mp3Info.bitsPerSample!=16)
- {
- printf("Can not play the file!\r\n");
- return 3;
- }
- }
- //Mp3Ptr=Mp3DecodeBuf;
- PlayPtr=(uint16_t*)Buf;
- /*if(Mp3Info.nChans==2)
- {
- for(i=0;i<Mp3Info.OutSamples;i++)
- {
- PlayPtr[i]=Mp3Ptr[i];
- }
- }
- else
- {
- for(i=0;i<Mp3Info.OutSamples;i++)
- {
- PlayPtr[0]=Mp3Ptr[0];
- PlayPtr[1]=Mp3Ptr[0];
- PlayPtr+=2;
- Mp3Ptr+=1;
- }
- }*/
- return 0;
- }