void decode(uint16_t *outbuf) { offset = MP3FindSyncWord(readPtr, READBUF_SIZE); if(offset < 0) { stop(); } else { readPtr += offset; //data start point bytesLeft -= offset; //in buffer MP3Decode(hMP3Decoder, &readPtr, &bytesLeft, outbuf, 0); if (bytesLeft < READBUF_SIZE) { memmove(readBuf,readPtr,bytesLeft); fr = f_read(&fil, readBuf + bytesLeft, READBUF_SIZE - bytesLeft, &cnt); if (cnt < READBUF_SIZE - bytesLeft); memset(readBuf + bytesLeft + cnt, 0, READBUF_SIZE - bytesLeft - cnt); bytesLeft=READBUF_SIZE; readPtr=readBuf; if(fr || cnt == 0){ stop(); next_song(); } } //MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); //if(mp3FrameInfo.outputSamps != 2304) decode(outbuf); } }
int decSamples(int length, short * destBuf, void * context) { int samps =0; /* Otherwhise we can possibly overwrite the data behind the buffer */ if(length >= MAX_NGRAN*inf.nChans*MAX_NSAMP) { int ret = 0; decode: /* Possible buffer-underrun */ if(dataLeft < READ_BUF_SIZE) { deFragReadbuf(readBuf, &readOff, dataLeft); ret = fread(readBuf+dataLeft, 1, READ_BUF_SIZE-dataLeft, fp); dataLeft += ret; if(feof(fp) && !dataLeft) return DEC_EOF; } /* check for errors */ if((ret = MP3Decode(mdecoder, &readOff, &dataLeft, destBuf,0))) { switch(ret) { case ERR_MP3_FREE_BITRATE_SYNC: case ERR_MP3_OUT_OF_MEMORY : case ERR_MP3_NULL_POINTER : case ERR_UNKNOWN : printf("HELIX MP3 ERROR: %d\n", ret); return DEC_ERR; default: findValidSync(&readOff, &dataLeft); printf("Seeking error!\n"); goto decode; } } /* GCC can't know channels being only 1 or 2 */ samps = inf.outputSamps >> (inf.nChans-1); }
/* * Called by the audio driver when it is time to provide data to * one of the audio buffers (while the other buffer is sent to the * CODEC using DMA). One mp3 frame is decoded at a time and * provided to the audio driver. */ static void AudioCallback(void *context, int buffer) { static int16_t audio_buffer0[4096]; static int16_t audio_buffer1[4096]; int i=0; int offset, err; int outOfData = 0; int16_t *samples; if (buffer) { samples = audio_buffer0; GPIO_SetBits(GPIOD, GPIO_Pin_13); GPIO_ResetBits(GPIOD, GPIO_Pin_14); } else { samples = audio_buffer1; GPIO_SetBits(GPIOD, GPIO_Pin_14); GPIO_ResetBits(GPIOD, GPIO_Pin_13); } offset = MP3FindSyncWord((unsigned char*)read_ptr, bytes_left); bytes_left -= offset; read_ptr += offset; err = MP3Decode(hMP3Decoder, (unsigned char**)&read_ptr, (int*)&bytes_left, samples, 0); 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); // Duplicate data in case of mono to maintain playback speed if (mp3FrameInfo.nChans == 1) { for(i = mp3FrameInfo.outputSamps;i >= 0;i--) { samples[2 * i]=samples[i]; samples[2 * i + 1]=samples[i]; } mp3FrameInfo.outputSamps *= 2; } } if (!outOfData) { ProvideAudioBuffer(samples, mp3FrameInfo.outputSamps); } }
/* * Called by the audio driver when it is time to provide data to * one of the audio buffers (while the other buffer is sent to the * CODEC using DMA). One mp3 frame is decoded at a time and * provided to the audio driver. */ static void AudioCallback(void *context, int buffer) { static int16_t audio_buffer0[4096]; static int16_t audio_buffer1[4096]; int offset, err; int outOfData = 0; static const char *read_ptr = mp3_data; static int bytes_left = MP3_SIZE; int16_t *samples; if (buffer) { samples = audio_buffer0; } else { samples = audio_buffer1; } offset = MP3FindSyncWord((unsigned char*)read_ptr, bytes_left); bytes_left -= offset; if (bytes_left <= 10000) { read_ptr = mp3_data; bytes_left = MP3_SIZE; offset = MP3FindSyncWord((unsigned char*)read_ptr, bytes_left); } read_ptr += offset; err = MP3Decode(hMP3Decoder, (unsigned char**)&read_ptr, &bytes_left, samples, 0); 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 (!outOfData) { ProvideAudioBuffer(samples, mp3FrameInfo.outputSamps); } }
int decode_mp3(aica_decoder_t *dat) { int offset = 0, i = 0; int bytes = dat->length; unsigned char *buf = (unsigned char*)dat->base; short *out = (short*)dat->out; offset = MP3FindSyncWord(buf, bytes); if(offset < 0) { return -1; } buf += offset; bytes -= offset; if(MP3Decode(hMP3Decoder, &buf, &bytes, out, 0)) { return -1; } MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); for(i = 0; i < mp3FrameInfo.nChans; i++) { mp3_chan[i].cmd = AICA_CH_CMD_START | AICA_CH_START_DELAY; mp3_chan[i].base = dat->chan[i]; mp3_chan[i].type = AICA_SM_16BIT; mp3_chan[i].length = (mp3FrameInfo.outputSamps / mp3FrameInfo.nChans); mp3_chan[i].loop = 1; mp3_chan[i].loopstart = 0; mp3_chan[i].loopend = (mp3FrameInfo.outputSamps / mp3FrameInfo.nChans); mp3_chan[i].freq = mp3FrameInfo.samprate; mp3_chan[i].vol = 255; mp3_chan[i].pan = 0; memcpy((void*)(chans + dat->chan[i]), &mp3_chan[i], sizeof(aica_channel_t)); chans[dat->chan[i]].pos = 0; aica_play(dat->chan[i], 0); } return mp3FrameInfo.nChans; }
int mp3_decoder_run(struct mp3_decoder* decoder) { int err; rt_uint16_t* buffer; rt_uint32_t delta; RT_ASSERT(decoder != RT_NULL); if ((decoder->read_ptr == RT_NULL) || decoder->bytes_left < 2*MAINBUF_SIZE) { if(mp3_decoder_fill_buffer(decoder) != 0) return -1; } // rt_kprintf("read offset: 0x%08x\n", decoder->read_ptr - decoder->read_buffer); decoder->read_offset = MP3FindSyncWord(decoder->read_ptr, decoder->bytes_left); if (decoder->read_offset < 0) { /* discard this data */ rt_kprintf("outof sync, byte left: %d\n", decoder->bytes_left); decoder->bytes_left = 0; return 0; } decoder->read_ptr += decoder->read_offset; delta = decoder->read_offset; decoder->bytes_left -= decoder->read_offset; if (decoder->bytes_left < 1024) { /* fill more data */ if(mp3_decoder_fill_buffer(decoder) != 0) return -1; } /* get a decoder buffer */ buffer = (rt_uint16_t*)sbuf_alloc(); decoder->bytes_left_before_decoding = decoder->bytes_left; err = MP3Decode(decoder->decoder, &decoder->read_ptr, (int*)&decoder->bytes_left, (short*)buffer, 0); delta += (decoder->bytes_left_before_decoding - decoder->bytes_left); current_offset += delta; decoder->frames++; if (err != ERR_MP3_NONE) { switch (err) { case ERR_MP3_INDATA_UNDERFLOW: rt_kprintf("ERR_MP3_INDATA_UNDERFLOW\n"); decoder->bytes_left = 0; if(mp3_decoder_fill_buffer(decoder) != 0) { /* release this memory block */ sbuf_release(buffer); return -1; } break; case ERR_MP3_MAINDATA_UNDERFLOW: /* do nothing - next call to decode will provide more mainData */ rt_kprintf("ERR_MP3_MAINDATA_UNDERFLOW\n"); break; default: rt_kprintf("unknown error: %d, left: %d\n", err, decoder->bytes_left); // skip this frame if (decoder->bytes_left > 0) { decoder->bytes_left --; decoder->read_ptr ++; } else { // TODO RT_ASSERT(0); } break; } /* release this memory block */ sbuf_release(buffer); } else { int outputSamps; /* no error */ MP3GetLastFrameInfo(decoder->decoder, &decoder->frame_info); /* set sample rate */ if (decoder->frame_info.samprate != current_sample_rate) { current_sample_rate = decoder->frame_info.samprate; rt_device_control(decoder->snd_device, CODEC_CMD_SAMPLERATE, ¤t_sample_rate); } /* write to sound device */ outputSamps = decoder->frame_info.outputSamps; if (outputSamps > 0) { if (decoder->frame_info.nChans == 1) { int i; for (i = outputSamps - 1; i >= 0; i--) { buffer[i * 2] = buffer[i]; buffer[i * 2 + 1] = buffer[i]; } outputSamps *= 2; } rt_device_write(decoder->snd_device, 0, buffer, outputSamps * sizeof(rt_uint16_t)); } else { /* no output */ sbuf_release(buffer); } } 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 AudioCallback(void *context, int buffer) { static int16_t audio_buffer0[4096]; static int16_t audio_buffer1[4096]; int offset; int outOfData = 0; static int bytes_left = MP3_SIZE; int16_t *samples; if (buffer) { samples = audio_buffer0; GPIO_SetBits(GPIOD, GPIO_Pin_13); GPIO_ResetBits(GPIOD, GPIO_Pin_14); } else { samples = audio_buffer1; GPIO_SetBits(GPIOD, GPIO_Pin_14); GPIO_ResetBits(GPIOD, GPIO_Pin_13); } offset = MP3FindSyncWord((unsigned char*)read_ptr, bytes_left); if (offset != -1) { bytes_left -= offset; } /* else { bytes_left = 0; //end of buffer, toggle buffers }*/ //Played the entire buffer, loop back to play from the front of the buffer if (bytes_left <= 1000) { flipBuffers(); bytes_left = MP3_SIZE; offset = MP3FindSyncWord((unsigned char*)read_ptr, bytes_left); } if(offset < MP3_SIZE && offset >= 0) { read_ptr += offset; } //if (*read_ptr == 0xFF) //{ err = MP3Decode(hMP3Decoder, (unsigned char**)&read_ptr, &bytes_left, samples, 0); //} if (err && (err != -9)) { // error occurred switch (err) { case ERR_MP3_INDATA_UNDERFLOW: outOfData = 1; break; case ERR_MP3_MAINDATA_UNDERFLOW: MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); //do nothing - next call to decode will provide more mainData break; case (-6): bytes_left -= 5; read_ptr += 5; //MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); break; case (-8): break; case ERR_MP3_FREE_BITRATE_SYNC: break; default: outOfData = 1; bytes_left -= 5; read_ptr += 5; break; } /* StopAudio(); rxIndex = 0; dataRxComplete = 0; bytes_left = MP3_SIZE; flipBuffers(); PlayAudioWithCallback(AudioCallback, 0);*/ } else { // no error MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); } //MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); if (mp3FrameInfo.outputSamps > 0) { ProvideAudioBuffer(samples, mp3FrameInfo.outputSamps); } else { ProvideAudioBuffer(samples, 4096); } }
static bool fill_mp3_buffer(FIL *fp, int buffer_number) { unsigned int br; unsigned int btr; static char file_read_buffer[FILE_READ_BUFFER_SIZE]; static char * file_read_ptr = file_read_buffer; static uint file_bytes = 0; // Copy of above pointers/indicators for roll back if MP3 frame decode failure. char * copy_file_read_ptr; uint copy_file_bytes; bool need_data= true; FRESULT res; int offset,err; bool out_of_data = false; int copy_samples; int i; // Turn on blue LED to indicate decoding start. GPIO_SetBits(GPIOD, GPIO_Pin_15); do { if ( need_data ) { // Reset the file read buffer memmove(file_read_buffer,file_read_ptr,file_bytes); file_read_ptr = file_read_buffer; // Fill the file read buffer btr = FILE_READ_BUFFER_SIZE - file_bytes; res = f_read(fp, file_read_buffer + file_bytes , btr, &br); file_bytes += br; if ( res != FR_OK ) { // File access failure, dump out. out_of_data = true; break; } // Flag when file is completely read complete. out_of_data = f_eof(fp); // Clear flag for needing more data. need_data = false; } // Find the next frame in the MP3 file offset = MP3FindSyncWord((unsigned char*)file_read_ptr, file_bytes); if ( offset < 0 ) { // This should never happen unless we have a badly formatted frame. // Just exit out and hope the next call gets a good frame. need_data = true; continue; } copy_file_bytes = file_bytes - offset; copy_file_read_ptr = file_read_ptr + offset; // Decode this frame. err = MP3Decode(hMP3Decoder, (unsigned char**)©_file_read_ptr, (uint*)©_file_bytes, audio_read_buffer + buffer_number * AUDIO_LOCAL_BUFFER_SIZE, 0); if (err) { /* error occurred */ switch (err) { case ERR_MP3_INDATA_UNDERFLOW: // Next loop will refill buffer. need_data = true; continue; case ERR_MP3_MAINDATA_UNDERFLOW: // Next loop will refill buffer. need_data = true; continue; case ERR_MP3_FREE_BITRATE_SYNC: default: out_of_data = true; break; } } else { file_bytes = copy_file_bytes; file_read_ptr = copy_file_read_ptr; // no error MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); // Duplicate data in case of mono to maintain playback speed if (mp3FrameInfo.nChans == 1) { for(i = mp3FrameInfo.outputSamps;i >= 0;i--) { audio_read_buffer[ buffer_read * AUDIO_LOCAL_BUFFER_SIZE + 2 * i] = audio_read_buffer[ buffer_read * AUDIO_LOCAL_BUFFER_SIZE + i]; audio_read_buffer[ buffer_read * AUDIO_LOCAL_BUFFER_SIZE + 2 * i + 1] = audio_read_buffer[ buffer_read * AUDIO_LOCAL_BUFFER_SIZE + i]; } mp3FrameInfo.outputSamps *= 2; } audio_buffer_length[ buffer_number ] = mp3FrameInfo.outputSamps; } } while( offset < 0 && res == FR_OK && !out_of_data ); // Turn off blue LED to indicate decoding finish. GPIO_ResetBits(GPIOD, GPIO_Pin_15); return(out_of_data); }
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 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(); }