/** * @brief Play the MP3 music file * */ void playMusic() { hMP3Decoder = MP3InitDecoder(); InitializeAudio(Audio44100HzSettings); SetAudioVolume(0xCF); PlayAudioWithCallback(AudioCallback, 0); }
void player_init(void) { PWM_RCC_Configuration(); //DAC_Configuration(); hMP3Decoder = MP3InitDecoder(); PWM_GPIO_Configuration(); PWM_TIM2_Configuration(); PWM_TIM1_Configuration(); buf = pvPortMalloc(sizeof(uint16_t)*BUF_LENGTH); buf2 = pvPortMalloc(sizeof(uint16_t)*BUF_LENGTH); }
void mp3_decoder_init(struct mp3_decoder* decoder) { RT_ASSERT(decoder != RT_NULL); /* init read session */ decoder->read_ptr = RT_NULL; decoder->bytes_left_before_decoding = decoder->bytes_left = 0; decoder->frames = 0; // decoder->read_buffer = rt_malloc(MP3_AUDIO_BUF_SZ); decoder->read_buffer = &mp3_fd_buffer[0]; if (decoder->read_buffer == RT_NULL) return; decoder->decoder = MP3InitDecoder(); /* open audio device */ decoder->snd_device = rt_device_find("snd"); if (decoder->snd_device != RT_NULL) { /* set tx complete call back function */ rt_device_set_tx_complete(decoder->snd_device, mp3_decoder_tx_done); rt_device_open(decoder->snd_device, RT_DEVICE_OFLAG_WRONLY); } }
int openFile(const char * name) { memset(&inf, 0, sizeof(inf)); readOff = readBuf; if((fp = fopen(name, "rb"))) { fileSize = get_fileSize(fp); char magic[3]; fread(&magic, 1, 3, fp); if(IS_ID3_V2(magic)) { parseID3_V2(fp); } else rewind(fp); if((dataLeft = fread(readBuf, 1, READ_BUF_SIZE, fp))==READ_BUF_SIZE) { mdecoder = MP3InitDecoder(); if(!findValidSync(&readOff, &dataLeft)) { MP3GetLastFrameInfo(mdecoder, &inf); bitrate = inf.bitrate; return 1; } } } return 0; }
int Mp3Decode(const char* pszFile) { int nResult = 0; BYTE* pInData = g_Mp3InBuffer; UINT unInDataLeft = 0; FIL fIn; UINT bEof = FALSE; UINT bOutOfData = FALSE; MP3FrameInfo mp3FrameInfo; uint32_t unDmaBufMode = 0; g_pMp3DmaBufferPtr = g_pMp3DmaBuffer; g_pMp3DecoderThread = chThdSelf(); FRESULT errFS = f_open(&fIn, pszFile, FA_READ); if(errFS != FR_OK) { chprintf((BaseChannel*)&SD2, "Mp3Decode: Failed to open file \"%s\" for reading, err=%d\r\n", pszFile, errFS); return -1; } HMP3Decoder hMP3Decoder = MP3InitDecoder(); if(hMP3Decoder == NULL) { chprintf((BaseChannel*)&SD2, "Mp3Decode: Failed to initialize mp3 decoder engine\r\n"); return -2; } chprintf((BaseChannel*)&SD2, "Mp3Decode: Start decoding \"%s\"\r\n", pszFile); char szArtist[80]; char szTitle[80]; palSetPad(GPIOD, 12); // green LED Mp3ReadId3V2Tag(&fIn, szArtist, sizeof(szArtist), szTitle, sizeof(szTitle)); palClearPad(GPIOD, 12); // green LED if(szArtist[0] != 0 || szTitle[0] != 0) { chprintf((BaseChannel*)&SD2, "Mp3Decode: Now playing (ID3v2): %s - %s\r\n", szArtist, szTitle); } int nDecodeRes = ERR_MP3_NONE; UINT unFramesDecoded = 0; do { if(unInDataLeft < (2 * MAINBUF_SIZE) && (!bEof)) { UINT unRead = Mp3FillReadBuffer(pInData, unInDataLeft, &fIn); unInDataLeft += unRead; pInData = g_Mp3InBuffer; if(unRead == 0) { bEof = 1; } } // find start of next MP3 frame - assume EOF if no sync found int nOffset = MP3FindSyncWord(pInData, unInDataLeft); if(nOffset < 0) { bOutOfData = TRUE; break; } pInData += nOffset; unInDataLeft -= nOffset; // decode one MP3 frame - if offset < 0 then bytesLeft was less than a full frame nDecodeRes = MP3Decode(hMP3Decoder, &pInData, (int*)&unInDataLeft, (short*)g_pMp3OutBuffer, 0); switch(nDecodeRes) { case ERR_MP3_NONE: { MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); if(unFramesDecoded == 0) { chprintf((BaseChannel*)&SD2, "Mp3Decode: %d Hz %d Bit %d Channels\r\n", mp3FrameInfo.samprate, mp3FrameInfo.bitsPerSample, mp3FrameInfo.nChans); if((mp3FrameInfo.samprate > 48000) || (mp3FrameInfo.bitsPerSample != 16) || (mp3FrameInfo.nChans != 2)) { chprintf((BaseChannel*)&SD2, "Mp3Decode: incompatible MP3 file.\r\n"); nResult = -5; break; } } if((unFramesDecoded) % 100 == 0) { chprintf((BaseChannel*)&SD2, "Mp3Decode: frame %u, bitrate=%d\r\n", unFramesDecoded, mp3FrameInfo.bitrate); } unFramesDecoded++; g_pMp3OutBufferPtr = g_pMp3OutBuffer; uint32_t unOutBufferAvail= mp3FrameInfo.outputSamps; while(unOutBufferAvail > 0) { // fill up the whole dma buffer uint32_t unDmaBufferSpace = 0; if(unDmaBufMode == 0) { // fill the whole buffer // dma buf ptr was reset to beginning of the buffer unDmaBufferSpace = g_pMp3DmaBuffer + MP3_DMA_BUFFER_SIZE - g_pMp3DmaBufferPtr; } else if(unDmaBufMode == 1) { // fill the first half of the buffer // dma buf ptr was reset to beginning of the buffer unDmaBufferSpace = g_pMp3DmaBuffer + (MP3_DMA_BUFFER_SIZE / 2) - g_pMp3DmaBufferPtr; } else { // fill the last half of the buffer // dma buf ptr was reset to middle of the buffer unDmaBufferSpace = g_pMp3DmaBuffer + MP3_DMA_BUFFER_SIZE - g_pMp3DmaBufferPtr; } uint32_t unCopy = unDmaBufferSpace > unOutBufferAvail ? unOutBufferAvail : unDmaBufferSpace; if(unCopy > 0) { memcpy(g_pMp3DmaBufferPtr, g_pMp3OutBufferPtr, unCopy * sizeof(uint16_t)); unOutBufferAvail -= unCopy; g_pMp3OutBufferPtr += unCopy; unDmaBufferSpace -= unCopy; g_pMp3DmaBufferPtr += unCopy; } if(unDmaBufferSpace == 0) { // dma buffer full // see if this was the first run if(unDmaBufMode == 0) { // on the first buffer fill up, // start the dma transfer if(EVAL_AUDIO_Init(OUTPUT_DEVICE_HEADPHONE, 80, (uint32_t)mp3FrameInfo.samprate)) { chprintf((BaseChannel *) &SD2, "Mp3Decode: audio init failed\r\n"); nResult = -4; break; } EVAL_AUDIO_Play(g_pMp3DmaBuffer, MP3_DMA_BUFFER_SIZE * sizeof(uint16_t)); } // we must wait for the dma stream tx interrupt here eventmask_t em = chEvtWaitAny((eventmask_t)2 | 4 | 8); if(em & 8) { // stop requested chprintf((BaseChannel*)&SD2, "Mp3Decode: Stop requested\r\n"); nResult = 1; break; } if((em & 2) && (em & 4)) { chprintf((BaseChannel*)&SD2, "Mp3Decode: DMA out of sync (HT and TC both set)\r\n"); nResult = -3; break; } if(unDmaBufMode == 0 || unDmaBufMode == 2) { // the dma event we expect is "half transfer" (=2) if(em & 2) { // set up first half mode unDmaBufMode = 1; g_pMp3DmaBufferPtr = g_pMp3DmaBuffer; } else { chprintf((BaseChannel*)&SD2, "Mp3Decode: DMA out of sync (expected HT, got TC)\r\n"); nResult = -3; break; } } else { // the dma event we expect is "transfer complete" (=4) if(em & 4) { // set up last half mode unDmaBufMode = 2; g_pMp3DmaBufferPtr = g_pMp3DmaBuffer + (MP3_DMA_BUFFER_SIZE / 2); } else { chprintf((BaseChannel*)&SD2, "Mp3Decode: DMA out of sync (expected TC, got HT)\r\n"); nResult = -3; } } } } break; } case ERR_MP3_MAINDATA_UNDERFLOW: { // do nothing - next call to decode will provide more mainData break; } case ERR_MP3_FREE_BITRATE_SYNC: { break; } case ERR_MP3_INDATA_UNDERFLOW: { chprintf((BaseChannel*)&SD2, "Mp3Decode: Decoding error ERR_MP3_INDATA_UNDERFLOW\r\n"); bOutOfData = TRUE; break; } default: { chprintf((BaseChannel*)&SD2, "Mp3Decode: Decoding error %d\r\n", nDecodeRes); bOutOfData = TRUE; break; } } } while((!bOutOfData) && (nResult == 0)); chprintf((BaseChannel*)&SD2, "Mp3Decode: Finished decoding\r\n"); MP3FreeDecoder(hMP3Decoder); if(EVAL_AUDIO_Stop(CODEC_PDWN_HW)) { chprintf((BaseChannel*)&SD2, "Mp3Decode: Failed to stop audio\r\n"); } EVAL_AUDIO_DeInit(); f_close(&fIn); // this is the only legit way I know // to remvove still pending event flags // from the thread chEvtWaitOneTimeout(2, 50); chEvtWaitOneTimeout(4, 50); return nResult; }
static void play_mp3(char* filename) { unsigned int br, btr; FRESULT res; bytes_left = FILE_READ_BUFFER_SIZE; read_ptr = file_read_buffer; if (FR_OK == f_open(&file, filename, FA_OPEN_EXISTING | FA_READ)) { // Read ID3v2 Tag char szArtist[120]; char szTitle[120]; Mp3ReadId3V2Tag(&file, szArtist, sizeof(szArtist), szTitle, sizeof(szTitle)); // Fill buffer f_read(&file, file_read_buffer, FILE_READ_BUFFER_SIZE, &br); // Play mp3 hMP3Decoder = MP3InitDecoder(); InitializeAudio(Audio44100HzSettings); SetAudioVolume(0xAF); PlayAudioWithCallback(AudioCallback, 0); for(;;) { /* * If past half of buffer, refill... * * When bytes_left changes, the audio callback has just been executed. This * means that there should be enough time to copy the end of the buffer * to the beginning and update the pointer before the next audio callback. * Getting audio callbacks while the next part of the file is read from the * file system should not cause problems. */ if (bytes_left < (FILE_READ_BUFFER_SIZE / 2)) { // Copy rest of data to beginning of read buffer memcpy(file_read_buffer, read_ptr, bytes_left); // Update read pointer for audio sampling read_ptr = file_read_buffer; // Read next part of file btr = FILE_READ_BUFFER_SIZE - bytes_left; res = f_read(&file, file_read_buffer + bytes_left, btr, &br); // Update the bytes left variable bytes_left = FILE_READ_BUFFER_SIZE; // Out of data or error or user button... Stop playback! if (br < btr || res != FR_OK || BUTTON) { StopAudio(); // Re-initialize and set volume to avoid noise InitializeAudio(Audio44100HzSettings); SetAudioVolume(0); // Close currently open file f_close(&file); // Wait for user button release while(BUTTON){}; // Return to previous function return; } } } } }
int main(void) { init(); currentWriteBuffer = mp3_data; currentReadBuffer = mp3_data2; mySPI_Init(); //Init SPI for comm with Pi //initialize SPI rx buffer counter rxIndex = 0; /* Enable the Rx buffer not empty interrupt */ SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE); /* send initial pulse for RPi to send data*/ GPIO_ToggleBits(GPIOD, GPIO_Pin_11); //sending end of pulse if (SPI_I2S_GetITStatus(SPI1, SPI_I2S_IT_RXNE) != SET) { GPIO_ToggleBits(GPIOD, GPIO_Pin_11); } //wait until data buffer loaded first time (change?) while (!dataRxComplete) { dataRxComplete = dataRxComplete; } //rxIndex = 0; //reset rxIndex (do in interrupt?) dataRxComplete = 0; flipBuffers(); hMP3Decoder = MP3InitDecoder(); //Send need more data GPIO signal InitializeAudio(Audio44100HzSettings); SetAudioVolume(0xCF); PlayAudioWithCallback(AudioCallback, 0); while(1) { // while(!dataRxComplete) // { // dataRxComplete = dataRxComplete; // } // dataRxComplete = 0; // // //flip buffers // char *tempBuffer = currentReadBuffer; // currentReadBuffer = currentWriteBuffer; // currentWriteBuffer = tempBuffer; // // // GPIO_ToggleBits(GPIOD, GPIO_Pin_11); // GPIO_ToggleBits(GPIOD, GPIO_Pin_11); } }
static void play_mp3(char* filename) { bool out_of_data; int cc; // Open file if (FR_OK == f_open(&file, filename, FA_OPEN_EXISTING | FA_READ)) { // Read ID3v2 Tag char szArtist[120]; char szTitle[120]; Mp3ReadId3V2Tag(&file, szArtist, sizeof(szArtist), szTitle, sizeof(szTitle)); ///////////////////////////////////////////////////////////buffer starts getting filled for first time // Start Initial fill of buffer hMP3Decoder = MP3InitDecoder(); for (cc = 0 ; cc < NUMBER_BUFFERS ; cc++ ) { out_of_data = fill_mp3_buffer(&file,cc); if ( out_of_data ) { break; } } // Initialize buffer counters buffer_read = 0; buffer_write = 0; ///////////////////////////////////////////////////////////////////////////////////////// // Play mp3 running_player = true; InitializeAudio(Audio44100HzSettings); // InitializeAudio(Audio32000HzSettings); SetAudioVolume(0xAF); PlayAudioWithCallback(AudioCallback, 0); ////////////////////////////////////////////////////////////////////////////////////////// for(;;) { /* * If we have an unused buffer, call fill_mp3_buffer to fill it. */ if ( buffer_read != buffer_write ) { // Refill the MP3 buffer out_of_data = fill_mp3_buffer(&file,buffer_write); if ( !out_of_data ) { buffer_write = ( buffer_write + 1 ) % NUMBER_BUFFERS; } // Out of data or error or user button... Stop playback! if (out_of_data || (exitMp3 == 1)) { StopAudio(); running_player = false; // Re-initialize and set volume to avoid noise InitializeAudio(Audio44100HzSettings); SetAudioVolume(0); // Close currently open file f_close(&file); return; } } else { // We don't have any work to do, shut down until interrupt (DMA transfer complete) __asm__ volatile ("wfi"); } } }
void labor6(void) { run = 1; syncword_address =0; spi_address = 0; pwmVal = 0; HMP3Decoder mp3dec; bytesLeft = 0; bytesTilSyncWord = 0; decodeRetVal = 0; errorCounter = 0; idx_ISR = 0; mainBuf_empty = 1; interrupt_Counter = 0; mseczaehlvar = 0; RCC_ClocksTypeDef RCC_Clocks; msec = 0; int i = 0; //Amplitude 1.0V (b_big) amplitude = b_big; spi_setup(); setup_TIM8_DAC_PWM(); mp3dec = MP3InitDecoder(); //SysTick end of count event each 10ms RCC_GetClocksFreq(&RCC_Clocks); SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000); TFT_cursor_off(); buf1.isEmpty = 1; buf2.isEmpty = 1; mp3OutBuffer = &buf1; //start with buf1 irsInBuffer = &buf1; TFT_cls(); TFT_gotoxy(1,1); TFT_puts("Frequenz: 5000"); while(B1 != 0 && B2 != 0) {} do { //Check Buttons read_buttons(); //ausgabe print_display(); //wenn der mainBuf leer ist, muss der durch readSPI mit mp3-daten gefuellt werden if (mainBuf_empty) { do { //Shift bytes to the beginning /** * Bsp: mainBufSize = 10 * readBytes = 7 --> bytesLeft = 3 * for(){ * mainBuffer[0] = mainBuffer[(10-3)+0] idx[0] = idx[7] * mainBuffer[1] = mainBuffer[(10-3)+1] idx[1] = ide[8] ... */ for(i = 0; i < bytesLeft; i++) { //die ungelesene bytes am anfang stellen mainBuf[i] = mainBuf[(MAINBUF_SIZE - bytesLeft) + i]; } //Reads size-bytes from current_SPI_Address and writes them into the given array ((mainBuffer + nBytesLeft)) //also nach diesem aufruf, ist der mainBuf voll und spiadresse muss verschoben werden spiFlashMemRead(SPI_MEM_WORK, spi_address, (mainBuf + bytesLeft), MAINBUF_SIZE - bytesLeft); //nach sync word in dem mainBuf suchen bytesTilSyncWord = MP3FindSyncWord(mainBuf, MAINBUF_SIZE); if (bytesTilSyncWord == 0) { //falls guelltige date gleich am anfang liegen spi_address = spi_address + (MAINBUF_SIZE - bytesLeft); } else if (bytesTilSyncWord < 0) {//fehler, kein sync word gefunden run = 0; } else if (bytesTilSyncWord > 0) {//falls skip word an der n-te adresse gefunden wurde, verschiebe ich die spiadresse um n, damit ich beim naechsten durchlauf vom flash nur die guelltige daten lese (also muell ueberspringen) spi_address = (spi_address - bytesLeft )+ bytesTilSyncWord; } bytesLeft = 0; //MUSS DAS HIER NICHT AUSSERHALB DER WHILE ?? DAMIT DIE NBYTES NICHT VERLOREN GEHEN } while(bytesTilSyncWord != 0 && run); mainBuf_empty = 0; //mainBuf ist voll } if (run) { //wenn kein fehler //wenn der mp3OutBuf voll ist ODER der MainBuf leer ist, dann warten (WAITING-LED) anschalten if (!mp3OutBuffer->isEmpty || mainBuf_empty) { setLED(WAITING_LED); } else { resetLED(WAITING_LED); bytesLeft = MAINBUF_SIZE; //in nBytesLeft steht wieviele daten aus dem MainBuf noch in dem mp3OutBuf uebertragen werden muessen ptrMainBuf = mainBuf; //mainBufPointer soll auf MainBuff zeigen, obwohl es bei der initialisierung schon gemacht wurde !! /** * para1: decoder instance * para2: buffer aus dem die daten decodet werden sollen * para3: (input) --> anzahl gueltige bytes, die gelesen werden sollen, * (output)--> input - gelesene bytes, also die bytes die noch gelesen werden muessen * para4: der buffer in dem geschrieben werden soll, der pointer wird geupdatet (bis wo der voll geschrieben wurde) */ //nach diesem aufruf ist der mp3OutBuf auf jeden fall voll decodeRetVal = MP3Decode(mp3dec, &ptrMainBuf, &bytesLeft, mp3OutBuffer->data, 0); //decodeResult -->(0 means no error, < 0 means error) mainBuf_empty = 1; //der mainBuf ist nicht komplett voll if (decodeRetVal < 0) { errorCounter++; } else { errorCounter = 0; } if (errorCounter > 2) { //fehler beim decode aufgetreten run = 0; } else { mp3OutBuffer->isEmpty = 0; //der mp3OutBuffer wurde voll geschrieben, bereit fuer die ISR if(mp3OutBuffer == &buf1) { //buffer ist voll, also wechseln mp3OutBuffer = &buf2; } else if (mp3OutBuffer == &buf2) { mp3OutBuffer = &buf1; } } } } } while (run); MP3FreeDecoder(mp3dec); }
int decoderMain(chanend pcmChan, chanend rxChan, chanend mp3Reset) { int bytesLeft, nRead, err, offset, outOfData, eofReached, nFrames; int reset; unsigned char readBuf[READBUF_SIZE], *readPtr; // unsigned char mp3_data // short outBuf[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP]; // short outBuf[256]; MP3FrameInfo mp3FrameInfo; HMP3Decoder hMP3Decoder; if ( (hMP3Decoder = MP3InitDecoder()) == 0 ) { return -2; // puts("Init died"); } bytesLeft = 0; outOfData = 0; eofReached = 0; readPtr = readBuf; nRead = 0; nFrames = 0; do { bytesLeft = RxNewFrame(readBuf, READBUF_SIZE, rxChan, mp3Reset); if (bytesLeft == 0) { break; } readPtr = readBuf; /* decode one MP3 frame - if offset < 0 then bytesLeft was less than a full frame */ err = MP3Decode(hMP3Decoder, &readPtr, &bytesLeft, NULL, 1, pcmChan); // err = MP3Decode(hMP3Decoder, &readPtr, &bytesLeft, NULL, 0, pcmChan); nFrames++; // printintln(nFrames); // Need to flush the PCM buffer for next frame decode // By outputting all ones to the channel // OutputToPCMBuf(0xffff, 0xffff, pcmChan); if (err) { /* error occurred */ switch (err) { case ERR_MP3_INDATA_UNDERFLOW: printstrln("HERE"); outOfData = 1; break; case ERR_MP3_MAINDATA_UNDERFLOW: /* do nothing - next call to decode will provide more mainData */ break; case ERR_MP3_FREE_BITRATE_SYNC: default: outOfData = 1; // printintln(err); // printstrln("\nHERE2"); // while (1); break; } } else { /* no error */ MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); } } while (!outOfData); // printstr("FINISHED: "); // printintln(err); MP3FreeDecoder(hMP3Decoder); // printDebug(1, debugChan); return 0; }
int init_mp3() { if(!hMP3Decoder) hMP3Decoder = MP3InitDecoder(); return 0; }
int main(int argc, char **argv) { int bytesLeft, nRead, err, offset, outOfData, eofReached; unsigned char readBuf[READBUF_SIZE], *readPtr; short outBuf[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP]; FILE *infile, *outfile; MP3FrameInfo mp3FrameInfo; HMP3Decoder hMP3Decoder; int startTime, endTime, diffTime, totalDecTime, nFrames; #ifdef ARM_ADS float audioSecs; #endif if (argc != 3) { printf("usage: mp3dec infile.mp3 outfile.pcm\n"); return -1; } infile = fopen(argv[1], "rb"); if (!infile) { printf("file open error\n"); return -1; } if (strcmp(argv[2], "nul")) { outfile = fopen(argv[2], "wb"); if (!outfile) { printf("file open error\n"); return -1; } } else { outfile = 0; /* nul output */ } DebugMemCheckInit(); InitTimer(); DebugMemCheckStartPoint(); if ( (hMP3Decoder = MP3InitDecoder()) == 0 ) return -2; DebugMemCheckEndPoint(); bytesLeft = 0; outOfData = 0; eofReached = 0; readPtr = readBuf; nRead = 0; totalDecTime = 0; nFrames = 0; do { /* somewhat arbitrary trigger to refill buffer - should always be enough for a full frame */ if (bytesLeft < 2*MAINBUF_SIZE && !eofReached) { nRead = FillReadBuffer(readBuf, readPtr, READBUF_SIZE, bytesLeft, infile); bytesLeft += nRead; readPtr = readBuf; if (nRead == 0) eofReached = 1; } /* find start of next MP3 frame - assume EOF if no sync found */ offset = MP3FindSyncWord(readPtr, bytesLeft); if (offset < 0) { outOfData = 1; break; } readPtr += offset; bytesLeft -= offset; /* decode one MP3 frame - if offset < 0 then bytesLeft was less than a full frame */ startTime = ReadTimer(); err = MP3Decode(hMP3Decoder, &readPtr, &bytesLeft, outBuf, 0); nFrames++; endTime = ReadTimer(); diffTime = CalcTimeDifference(startTime, endTime); totalDecTime += diffTime; #if defined ARM_ADS && defined MAX_ARM_FRAMES printf("frame %5d start = %10d, end = %10d elapsed = %10d ticks\r", nFrames, startTime, endTime, diffTime); fflush(stdout); #endif if (err) { /* error occurred */ switch (err) { case ERR_MP3_INDATA_UNDERFLOW: outOfData = 1; break; case ERR_MP3_MAINDATA_UNDERFLOW: /* do nothing - next call to decode will provide more mainData */ break; case ERR_MP3_FREE_BITRATE_SYNC: default: outOfData = 1; break; } } else { /* no error */ MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); if (outfile) fwrite(outBuf, mp3FrameInfo.bitsPerSample / 8, mp3FrameInfo.outputSamps, outfile); } #if defined ARM_ADS && defined MAX_ARM_FRAMES if (nFrames >= MAX_ARM_FRAMES) break; #endif } while (!outOfData); #ifdef ARM_ADS MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); audioSecs = ((float)nFrames * mp3FrameInfo.outputSamps) / ( (float)mp3FrameInfo.samprate * mp3FrameInfo.nChans); printf("\nTotal clock ticks = %d, MHz usage = %.2f\n", totalDecTime, ARMULATE_MUL_FACT * (1.0f / audioSecs) * totalDecTime * GetClockDivFactor() / 1e6f); printf("nFrames = %d, output samps = %d, sampRate = %d, nChans = %d\n", nFrames, mp3FrameInfo.outputSamps, mp3FrameInfo.samprate, mp3FrameInfo.nChans); #endif MP3FreeDecoder(hMP3Decoder); fclose(infile); if (outfile) fclose(outfile); FreeTimer(); DebugMemCheckFree(); return 0; }
/** * @brief mp3_player 进行mp3文件解码、播放 * @param filename:要播放的文件路径 * @retval none */ static void mp3_player(const char *filename) { int err, i, outputSamps, current_sample_rate = 0; int read_offset = 0; /* 读偏移指针 */ int bytes_left = 0; /* 剩余字节数 */ unsigned long Frames = 0; /* mP3帧计数 */ unsigned char *read_ptr = buffer; /* 缓冲区指针 */ HMP3Decoder Mp3Decoder; /* mp3解码器指针 */ //打开音频文件 fres = f_open (&file, filename, FA_READ ); //打开失败 if (fres!=FR_OK) { printf("read file %s error ! open another file\r\n",filename); fres = f_close (&file); if (++play_index>=file_num) //索引值加1 { play_index=0; //归0,所以如果所有文件都打开失败会一直循环 } return ; //文件无法打开,终止解码。进入下一次循环,读取下一个文件 } //打开成功 //初始化MP3解码器 Mp3Decoder = MP3InitDecoder(); //获取输入数据流,调用helix库解码,输出PCM数据,约20ms完成一次循环 //开始进入播放状态,期间中断会修改touch_even状态 while(player_state != S_SWITCH) //循环1, 如果touch_even不是切歌状态则继续呆在循环体里 { //有时出现解码错误,错误后继续在本循环体内,继续播放 //显示播放图标 Lcd_GramScan(1); LCD_Clear(12,88,8,145,BACKGROUND); Lcd_show_bmp(320-(103+((play_index-((current_page-1)*8))*18)),240-20,"/mp3player/ui_playing.bmp"); //读取mp3文件 fres = f_read(&file, buffer, sizeof(buffer), &rw_num); if(fres != FR_OK) { printf("读取%s失败! %d\r\n",filename,fres); break; //return; } read_ptr = buffer; //指向mp3输入流 bytes_left = rw_num; //实际读到的输入流大小大小 //按帧处理 while(player_state != S_SWITCH) //循环2,循环本过程播放音频,直到按了下一首、上一首 { if (player_state == S_STOP) { even_process(); //检查是否有事件需要处理 continue; //暂停的时候结束本次循环 } player_state = S_PLAY; //状态更新为正在播放 read_offset = MP3FindSyncWord(read_ptr, bytes_left); //寻找帧同步,返回第一个同步字的位置 if(read_offset < 0) //没有找到同步字 { break; //跳出循环2,回到循环1 } read_ptr += read_offset; //偏移至同步字的位置 bytes_left -= read_offset; //同步字之后的数据大小 if(bytes_left < 1024) //补充数据 { /* 注意这个地方因为采用的是DMA读取,所以一定要4字节对齐 */ i=(uint32_t)(bytes_left)&3; //判断多余的字节 if(i) i=4-i; //需要补充的字节 memcpy(buffer+i, read_ptr, bytes_left); //从对齐位置开始复制 read_ptr = buffer+i; //指向数据对齐位置 fres = f_read(&file, buffer+bytes_left+i, sizeof(buffer)-bytes_left-i, &rw_num);//补充数据 bytes_left += rw_num; //有效数据流大小 } err = MP3Decode(Mp3Decoder, &read_ptr, &bytes_left, outBuf[bufflag], 0); //开始解码 参数:mp3解码结构体、输入流指针、输入流大小、输出流指针、数据格式 Frames++; if (err != ERR_MP3_NONE) //错误处理 { switch (err) { case ERR_MP3_INDATA_UNDERFLOW: printf("ERR_MP3_INDATA_UNDERFLOW\r\n"); read_ptr = buffer; fres = f_read(&file, read_ptr, sizeof(buffer), &rw_num); bytes_left = rw_num; break; case ERR_MP3_MAINDATA_UNDERFLOW: /* do nothing - next call to decode will provide more mainData */ printf("ERR_MP3_MAINDATA_UNDERFLOW\r\n"); break; default: printf("UNKNOWN ERROR:%d\r\n", err); // 跳过此帧 if (bytes_left > 0) { bytes_left --; read_ptr ++; } break; } } else //解码无错误,准备把数据输出到PCM { MP3GetLastFrameInfo(Mp3Decoder, &Mp3FrameInfo); //获取解码信息 /* 根据解码信息设置采样率 */ if (Mp3FrameInfo.samprate != current_sample_rate) //采样率 { current_sample_rate = Mp3FrameInfo.samprate; printf(" \r\n Bitrate %dKbps", Mp3FrameInfo.bitrate/1000); printf(" \r\n Samprate %dHz", current_sample_rate); printf(" \r\n BitsPerSample %db", Mp3FrameInfo.bitsPerSample); printf(" \r\n nChans %d", Mp3FrameInfo.nChans); printf(" \r\n Layer %d", Mp3FrameInfo.layer); printf(" \r\n Version %d", Mp3FrameInfo.version); printf(" \r\n OutputSamps %d", Mp3FrameInfo.outputSamps); if(current_sample_rate >= I2S_AudioFreq_Default) //I2S_AudioFreq_Default = 2,正常的帧,每次都要改速率 { I2S_Freq_Config(current_sample_rate); //根据采样率修改iis速率 } } /* 输出到DAC */ outputSamps = Mp3FrameInfo.outputSamps; //PCM数据个数 if (outputSamps > 0) { if (Mp3FrameInfo.nChans == 1) //单声道 { //单声道数据需要复制一份到另一个声道 for (i = outputSamps - 1; i >= 0; i--) { outBuf[bufflag][i * 2] = outBuf[bufflag][i]; outBuf[bufflag][i * 2 + 1] = outBuf[bufflag][i]; } outputSamps *= 2; } //非单声道数据可直接由DMA传输到IIS交给DAC /* 等待DMA播放完,这段时间我们可以干其他的事,扫描事件进行处理 */ while((DMA1_Channel5->CCR&DMA_CCR1_EN) && !(DMA1->ISR&DMA1_IT_TC5)) { even_process(); } /*DMA传输完毕*/ DMA_ClearFlag(DMA1_FLAG_TC5 | DMA1_FLAG_TE5); DMA_I2S_Configuration((uint32_t)outBuf[bufflag], outputSamps); bufflag = 1 -bufflag; //切换buffer }//if (outputSamps > 0) }//else 解码正常 if(file.fptr==file.fsize) //如果指针指向了文件尾,表示数据全部读完 { printf("END\r\n"); if(play_index<file_num-1) //自动开始下一首歌曲 { play_index++; player_state = S_SWITCH; //进入切歌状态,跳出 } else { play_index = 0; player_state = S_SWITCH; } break; //跳出这首歌的播放状态 while break; } }//循环2 内 while(player_state != S_SWITCH) }//循环1 外 while(player_state != S_SWITCH) f_close(&file); //结束播放本歌曲,关闭文件 MP3FreeDecoder(Mp3Decoder); I2S_Stop(); }