/** * @brief Calculates the remaining file size and new position of the pointer. * @param None * @retval None */ void EVAL_AUDIO_TransferComplete_CallBack(uint32_t pBuffer, uint32_t Size) { /* Calculate the remaining audio data in the file and the new size for the DMA transfer. If the Audio files size is less than the DMA max data transfer size, so there is no calculation to be done, just restart from the beginning of the file ... */ /* Check if the end of file has been reached */ #ifdef AUDIO_MAL_MODE_NORMAL #if defined MEDIA_IntFLASH #if defined PLAY_REPEAT_OFF LED_Toggle = 4; RepeatState = 1; EVAL_AUDIO_Stop(CODEC_PDWN_HW); #else /* Replay from the beginning */ AudioFlashPlay((uint16_t*)(AUDIO_SAMPLE + AUIDO_START_ADDRESS),AUDIO_FILE_SZE,AUIDO_START_ADDRESS); #endif #elif defined MEDIA_USB_KEY XferCplt = 1; if (WaveDataLength) WaveDataLength -= _MAX_SS; if (WaveDataLength < _MAX_SS) WaveDataLength = 0; #endif #else /* #ifdef AUDIO_MAL_MODE_CIRCULAR */ #endif /* AUDIO_MAL_MODE_CIRCULAR */ }
/** * @brief EXTI0_IRQHandler * This function handles External line 0 interrupt request. * @param None * @retval None */ void EXTI0_IRQHandler(void) { /* Checks whether the User Button EXTI line is asserted*/ if (EXTI_GetITStatus(EXTI_Line0) != RESET) { if (Command_index == 1) { RepeatState = 0; /* Switch to play command */ Command_index = 0; } else if (Command_index == 0) { /* Switch to record command */ Command_index = 1; XferCplt = 1; EVAL_AUDIO_Stop(CODEC_PDWN_SW); } else { RepeatState = 0; /* Switch to play command */ Command_index = 0; } } /* Clears the EXTI's line pending bit.*/ EXTI_ClearITPendingBit(EXTI_Line0); }
/** * @brief Reset the wave player * @param None * @retval None */ void WavePlayer_CallBack(void) { /* Reset the wave player variables */ RepeatState = 0; AudioPlayStart =0; LED_Toggle = 7; PauseResumeStatus = 1; WaveDataLength =0; Count = 0; /* Stops the codec */ EVAL_AUDIO_Stop(CODEC_PDWN_HW); /* LED off */ STM_EVAL_LEDOff(LED3); STM_EVAL_LEDOff(LED4); STM_EVAL_LEDOff(LED6); /* TIM Interrupts disable */ TIM_ITConfig(TIM4, TIM_IT_CC1, DISABLE); f_mount(0, NULL); }
/** * @brief AudioCmd * Play, Stop, Pause or Resume current file. * @param pbuf: address from which file shoud be played. * @param size: size of the current buffer/file. * @param cmd: command to be executed, can be AUDIO_CMD_PLAY , AUDIO_CMD_PAUSE, * AUDIO_CMD_RESUME or AUDIO_CMD_STOP. * @retval AUDIO_OK if all operations succeed, AUDIO_FAIL else. */ static uint8_t AudioCmd(uint8_t* pbuf, uint32_t size, uint8_t cmd) { /* Check the current state */ if ((AudioState == AUDIO_STATE_INACTIVE) || (AudioState == AUDIO_STATE_ERROR)) { AudioState = AUDIO_STATE_ERROR; return AUDIO_FAIL; } switch (cmd) { /* Process the PLAY command ----------------------------*/ case AUDIO_CMD_PLAY: /* If current state is Active or Stopped */ if ((AudioState == AUDIO_STATE_ACTIVE) || \ (AudioState == AUDIO_STATE_STOPPED) || \ (AudioState == AUDIO_STATE_PLAYING)) { Audio_MAL_Play((uint32_t)pbuf, (size/2)); AudioState = AUDIO_STATE_PLAYING; return AUDIO_OK; } /* If current state is Paused */ else if (AudioState == AUDIO_STATE_PAUSED) { if (EVAL_AUDIO_PauseResume(AUDIO_RESUME /*, (uint32_t)pbuf, (size/2)*/) != 0) { AudioState = AUDIO_STATE_ERROR; return AUDIO_FAIL; } else { AudioState = AUDIO_STATE_PLAYING; return AUDIO_OK; } } else /* Not allowed command */ { return AUDIO_FAIL; } /* Process the STOP command ----------------------------*/ case AUDIO_CMD_STOP: if (AudioState != AUDIO_STATE_PLAYING) { /* Unsupported command */ return AUDIO_FAIL; } else if (EVAL_AUDIO_Stop(CODEC_PDWN_SW) != 0) { AudioState = AUDIO_STATE_ERROR; return AUDIO_FAIL; } else { AudioState = AUDIO_STATE_STOPPED; return AUDIO_OK; } /* Process the PAUSE command ---------------------------*/ case AUDIO_CMD_PAUSE: if (AudioState != AUDIO_STATE_PLAYING) { /* Unsupported command */ return AUDIO_FAIL; } else if (EVAL_AUDIO_PauseResume(AUDIO_PAUSE /*, (uint32_t)pbuf, (size/2)*/) != 0) { AudioState = AUDIO_STATE_ERROR; return AUDIO_FAIL; } else { AudioState = AUDIO_STATE_PAUSED; return AUDIO_OK; } /* Unsupported command ---------------------------------*/ default: return AUDIO_FAIL; } }
void AudioTask ( void * pvParameters ) { struct AAudioCommandMessage CmdMsg; uint8_t rc = 0; FRESULT res; uint8_t pausing = 0; xAudioQueue = xQueueCreate ( 8, sizeof ( char ) ); res = f_mount ( &FatFs, "", 1 ); // mount the drive if ( res ) { led_state[0] = LED_STATE_BLINK_FAST; while ( 1 ); } while ( 1 ) { if ( xQueueReceive ( xAudioQueue, &CmdMsg, portMAX_DELAY ) ) { switch ( CmdMsg.Command ) { case 'h': // half transfer complete break; case 't': // transfer complete if ( audioContext.lastFrame ) { EVAL_AUDIO_Stop ( CODEC_PDWN_SW ); } else { AudioProvideSamplesFromFile ( ); } break; case 'p': // play file rc = AudioStartPlayFile ( CmdMsg.sFilename ); switch ( rc ) { case 0: led_state[1] = LED_STATE_OFF; led_state[2] = LED_STATE_OFF; break; case 1: led_state[1] = LED_STATE_BLINK_FAST; break; case 2: led_state[2] = LED_STATE_BLINK_FAST; break; } break; case 'r': // pause/resume EVAL_AUDIO_PauseResume ( pausing ? AUDIO_RESUME : AUDIO_PAUSE ); pausing ^= pausing; break; case 's': // stop playback EVAL_AUDIO_Stop ( CODEC_PDWN_SW ); break; case 'v': // set volume break; case '+': // volume up break; case '-': // volume down break; case 'n': // next file break; case 'l': // last file break; }; }; }; };
/** * @brief Stop playing wave * @param None * @retval None */ void WavePlayerStop(void) { EVAL_AUDIO_Stop(CODEC_PDWN_SW); }
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; }
/** * @brief Main program. * @param None * @retval None */ int main(void) { /* Initialize LEDS */ /* Red Led On: buffer overflow */ STM_EVAL_LEDInit(LED3); /* Green Led On: fdmdv+codec2 enabled */ STM_EVAL_LEDInit(LED4); STM_EVAL_LEDInit(LED5); /* Blue Led On: start of application */ STM_EVAL_LEDInit(LED6); STM_EVAL_LEDOn(LED6); /* transparent mode switcher */ STM_EVAL_PBInit(BUTTON_USER, BUTTON_MODE_EXTI); if(Transparent_mode) STM_EVAL_LEDOff(LED4); else STM_EVAL_LEDOn(LED4); /* SysTick end of count event each 10ms */ RCC_GetClocksFreq(&RCC_Clocks); SysTick_Config(RCC_Clocks.HCLK_Frequency / 100); USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; STM_EVAL_USART2Init(&USART_InitStructure); // turn off buffers, so IO occurs immediately setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); /* Output a message on Hyperterminal using printf function */ printf("\r\nFloating-Point Based Codec2 encoder for Cortex-M4F\r\n"); /* Configure TIM4 Peripheral to manage LEDs lighting */ unsigned int idx = 0; Time_Rec_Base=0; int i, buffId; codec2_initialize_all(SPEAKER_FREQ == 48000 ? 1 : 0); /* fill output fifo */ fifoBufferFullness=0; fifoBufferCurrent=0; Switch = 0; /* modulate silence once for padding if happens */ memset(padBuffer, 0x00, (320*(SPEAKER_FREQ/MIC_FREQ)*2)*sizeof(short)); memset(fifoBuffer, 0x00, MODULATOR_QUEUE_SIZE * (SPEAKER_FREQ/MIC_FREQ)*320*2*sizeof(short)); //codec2_modulate((short *) padBuffer, (short *) padBuffer, Transparent_mode); /* Initialize I2S interface */ EVAL_AUDIO_SetAudioInterface(AUDIO_INTERFACE_I2S); /* Initialize the Audio codec and all related peripherals (I2S, I2C, IOExpander, IOs...) */ //EVAL_AUDIO_Init(OUTPUT_DEVICE_AUTO, 0, SPEAKER_FREQ); EVAL_AUDIO_Init(OUTPUT_DEVICE_AUTO, 0, SPEAKER_FREQ); EVAL_AUDIO_PauseResume(AUDIO_PAUSE); Audio_MAL_Play((uint32_t) padBuffer, (320*(SPEAKER_FREQ/MIC_FREQ))*2*sizeof(short)); EVAL_AUDIO_PauseResume(AUDIO_RESUME); /* Start the record */ MicListenerInit(32000,16, 1); MicListenerStart(RecBuf_8Khz, PCM_OUT_SIZE); /* GLOBAL SCHEDULER * DO NOT USE LOOPS INSIDE IT! * */ while(1) { /* we have frame from mike */ if(Data_Status == 0) continue; /* Switch the buffers*/ if (Switch ==1) { pAudioRecBuf_8Khz = RecBuf_8Khz; writebuffer = RecBuf1_8Khz; Switch = 0; } else { pAudioRecBuf_8Khz = RecBuf1_8Khz; writebuffer = RecBuf_8Khz; Switch = 1; } #ifdef USE_ST_FILTER //Downsampling 16Khz => 8Khz (this is input for codec, it sampled with 8KHz) for(i=0; i<320; i++) writebuffer[i] = writebuffer[2*i]; #endif //TODO: modulate, even if no data from mike! if(fifoBufferFullness < MODULATOR_QUEUE_SIZE-1) { /* get the next free buffer */ buffId = fifoBufferCurrent + fifoBufferFullness; if(buffId >= MODULATOR_QUEUE_SIZE) buffId -= MODULATOR_QUEUE_SIZE; assert(buffId >= 0 && buffId < MODULATOR_QUEUE_SIZE); codec2_modulate((short *) writebuffer, (short *) fifoBuffer[buffId], Transparent_mode); fifoBufferFullness++; if(idx % 32 == 0) printf("."); if(idx % (32*32) == 0) printf("\r\n"); /* this is hack to remove loud noise at startup */ if(volume_set==1) { STM_EVAL_LEDOff(LED3); EVAL_AUDIO_VolumeCtl(90); volume_set=2; } } else { STM_EVAL_LEDToggle(LED3); printf("x"); if(idx % (32) == 0) printf("\r\n"); } idx++; Data_Status = 0; } EVAL_AUDIO_Mute(AUDIO_MUTE_ON); EVAL_AUDIO_Stop(CODEC_PDWN_HW); MicListenerStop(); //float samples_time = idx*samplesPerFrame/((float) WAVE_Format.NumChannels*WAVE_Format.SampleRate); #if 0 float samples_time = idx*mod->samplesPerFrame/((float) 1*MIC_FREQ); float cpu_time = Time_Rec_Base/((float ) 100); printf("\r\n%8.3f s audio file encoded in %8.3f s\r\n", (double) samples_time, (double) cpu_time); #endif while(1) { STM_EVAL_LEDToggle(LED5); Delay(10); } }