// MP3 decode player void MP3Player(void) { FRESULT res; uint8_t *ReadStart; uint8_t *GuardPtr; volatile uint8_t u8PCMBufferTargetIdx = 0; volatile uint32_t pcmbuf_idx, i; volatile unsigned int Mp3FileOffset=0; uint16_t sampleL, sampleR; pcmbuf_idx = 0; memset((void *)&audioInfo, 0, sizeof(audioInfo)); /* Parse MP3 header */ MP3_ParseHeaderInfo(MP3_FILE); /* First the structures used by libmad must be initialized. */ mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); /* Open MP3 file */ res = f_open(&mp3FileObject, MP3_FILE, FA_OPEN_EXISTING | FA_READ); if (res != FR_OK) { printf("Open file error \r\n"); return; } /* Open I2S1 interface and set to slave mode, stereo channel, I2S format */ I2S_Open(I2S1, I2S_MODE_SLAVE, 16000, I2S_DATABIT_16, I2S_STEREO, I2S_FORMAT_I2S, I2S_I2S); /* Initialize WAU8822 codec */ WAU8822_Setup(); /* Configure wau8822 for specific sampling rate */ WAU8822_ConfigSampleRate(audioInfo.mp3SampleRate); /* Set MCLK and enable MCLK */ I2S_EnableMCLK(I2S1, 12000000); while(1) { if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN) { if(Stream.next_frame != NULL) { /* Get the remaining frame */ Remaining = Stream.bufend - Stream.next_frame; memmove(MadInputBuffer, Stream.next_frame, Remaining); ReadStart = MadInputBuffer + Remaining; ReadSize = FILE_IO_BUFFER_SIZE - Remaining; } else { ReadSize = FILE_IO_BUFFER_SIZE, ReadStart = MadInputBuffer, Remaining = 0; } /* read the file from SDCard */ res = f_read(&mp3FileObject, ReadStart, ReadSize, &ReturnSize); if((res != FR_OK) || f_eof(&mp3FileObject)) { printf("Stop !(%x)\n\r", res); goto stop; } /* if the file is over */ if (ReadSize > ReturnSize) { GuardPtr=ReadStart+ReadSize; memset(GuardPtr,0,MAD_BUFFER_GUARD); ReadSize+=MAD_BUFFER_GUARD; } Mp3FileOffset = Mp3FileOffset + ReturnSize; /* Pipe the new buffer content to libmad's stream decoder * facility. */ mad_stream_buffer(&Stream,MadInputBuffer,ReadSize+Remaining); Stream.error=(enum mad_error)0; } /* decode a frame from the mp3 stream data */ if(mad_frame_decode(&Frame,&Stream)) { if(MAD_RECOVERABLE(Stream.error)) { /*if(Stream.error!=MAD_ERROR_LOSTSYNC || Stream.this_frame!=GuardPtr) { }*/ continue; } else { /* the current frame is not full, need to read the remaining part */ if(Stream.error==MAD_ERROR_BUFLEN) { continue; } else { printf("Something error!!\n"); /* play the next file */ audioInfo.mp3FileEndFlag = 1; goto stop; } } } /* Once decoded the frame is synthesized to PCM samples. No errors * are reported by mad_synth_frame(); */ mad_synth_frame(&Synth,&Frame); // // decode finished, try to copy pcm data to audio buffer // if(audioInfo.mp3Playing) { //if next buffer is still full (playing), wait until it's empty if(aPCMBuffer_Full[u8PCMBufferTargetIdx] == 1) while(aPCMBuffer_Full[u8PCMBufferTargetIdx]); } else { if((aPCMBuffer_Full[0] == 1) && (aPCMBuffer_Full[1] == 1 )) { //all buffers are full, wait StartPlay(); } } for(i=0; i<(int)Synth.pcm.length; i++) { /* Get the left/right samples */ sampleL = Synth.pcm.samples[0][i]; sampleR = Synth.pcm.samples[1][i]; /* Fill PCM data to I2S(PDMA) buffer */ aPCMBuffer[u8PCMBufferTargetIdx][pcmbuf_idx++] = sampleR | (sampleL << 16); /* Need change buffer ? */ if(pcmbuf_idx == PCM_BUFFER_SIZE) { aPCMBuffer_Full[u8PCMBufferTargetIdx] = 1; //set full flag u8PCMBufferTargetIdx ^= 1; pcmbuf_idx = 0; // printf("change to ==>%d ..\n", u8PCMBufferTargetIdx); /* if next buffer is still full (playing), wait until it's empty */ if((aPCMBuffer_Full[u8PCMBufferTargetIdx] == 1) && (audioInfo.mp3Playing)) while(aPCMBuffer_Full[u8PCMBufferTargetIdx]); } } } stop: printf("Exit MP3\r\n"); mad_synth_finish(&Synth); mad_frame_finish(&Frame); mad_stream_finish(&Stream); f_close(&mp3FileObject); StopPlay(); }
/*---------------------------------------------------------------------------------------------------------*/ int32_t main(void) { int32_t i; /* This sample code is used to demo USB Audio Class + NAU8822. User can define PLAY_RATE in usbd_audio.h to support 48000Hz, 32000Hz, 16000Hz and 8000Hz. The audio is input from NAU8822 AUXIN. The audio is output by NAU8822 Headphone output. NAU8822 is connect with I2S1 (PA.4~PA.7) and controlled by I2C0 (PD.4, PD.5). NAU8822 clock source is also come from I2S1 (MCLK, PD.0). PC.1 is used to output clock (HCLK/8) to check HCLK frequency. */ /* Unlock Protected Regsiter */ SYS_UnlockReg(); /* Initial system & multi-function */ SYS_Init(); /* Initial UART0 for debug message */ UART0_Init(); printf("\n"); printf("+-------------------------------------------------------+\n"); printf("| NuMicro USB Audio CODEC Sample Code |\n"); printf("+-------------------------------------------------------+\n"); /* Init I2C0 to access NAU8822 */ I2C0_Init(); /* Initialize NAU8822 codec */ WAU8822_Setup(); I2S_Open(SPI1, I2S_MODE_SLAVE, PLAY_RATE, I2S_DATABIT_16, I2S_STEREO, I2S_FORMAT_I2S); /* Set MCLK and enable MCLK */ I2S_EnableMCLK(SPI1, 12000000); /* Fill dummy data to I2S TX for start I2S iteration */ for(i = 0; i < 4; i++) I2S_WRITE_TX_FIFO(SPI1, 0); /* Start I2S play iteration */ I2S_EnableInt(SPI1, I2S_FIFO_TXTH_INT_MASK | I2S_FIFO_RXTH_INT_MASK); USBD_Open(&gsInfo, UAC_ClassRequest, (SET_INTERFACE_REQ)UAC_SetInterface); /* Endpoint configuration */ UAC_Init(); USBD_Start(); NVIC_EnableIRQ(USBD_IRQn); NVIC_EnableIRQ(SPI1_IRQn); /* SPI (I2S) interrupt has higher frequency then USBD interrupt. Therefore, we need to set SPI (I2S) with higher priority to avoid SPI (I2S) interrupt pending too long time when USBD interrupt happen. */ NVIC_SetPriority(USBD_IRQn, 3); NVIC_SetPriority(SPI1_IRQn, 2); while(SYS->PDID) { uint8_t ch; uint32_t u32Reg, u32Data; extern int32_t kbhit(void); /* Adjust codec sampling rate to synch with USB. The adjustment range is +-0.005% */ AdjFreq(); /* Set audio volume according USB volume control settings */ VolumnControl(); /* User can change audio codec settings by I2C at run-time if necessary */ if(!kbhit()) { printf("\nEnter codec setting:\n"); // Get Register number ch = getchar(); u32Reg = ch - '0'; ch = getchar(); u32Reg = u32Reg * 10 + (ch - '0'); printf("%d\n", u32Reg); // Get data ch = getchar(); u32Data = (ch >= '0' && ch <= '9') ? ch - '0' : ch - 'a' + 10; ch = getchar(); u32Data = u32Data * 16 + ((ch >= '0' && ch <= '9') ? ch - '0' : ch - 'a' + 10); ch = getchar(); u32Data = u32Data * 16 + ((ch >= '0' && ch <= '9') ? ch - '0' : ch - 'a' + 10); printf("%03x\n", u32Data); I2C_WriteWAU8822(u32Reg, u32Data); } } }