#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;
}