AnsweredAssumed Answered

Playing MP3 with Libmad (Urgent Help Needed)

Question asked by wei_peng.kwan on Dec 3, 2014
Latest reply on Dec 4, 2014 by wei_peng.kwan
Hello Everyone, 
Currently, I have downloaded the "Audio Playback and Record" sample code for my STM32F4-Discovery board. As you all know, this sample is only applicable to play the WAV file. So, I implement the Libmad inside for the MP3 decoding purpose. I used back the algorithm from the sample code to feed the mp3 data to the libmad process and use back the same algorithm from the sample code to play the decoded MP3 data (16 bits PCM format). Anyway, there is no sound coming out. And, I realized the Audio Playback and Record sample is getting the data in PDM format and converted it back to PCM before playing the audio. May I know anyone know where might be the problem is for me to output the sound? Is it because the data missing or anything? Below are the part of "waveplayer.c" which I altered to decode the MP3 data:

001./**
002.  ******************************************************************************
003.  * @file    Audio_playback_and_record/Src/waveplayer.c
004.  * @author  MCD Application Team
005.  * @version V1.1.0
006.  * @date    26-June-2014
007.  * @brief   I2S Audio player program.
008.  ******************************************************************************
009.  * @attention
010.  *
011.  * <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
012.  *
013.  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
014.  * You may not use this file except in compliance with the License.
015.  * You may obtain a copy of the License at:
016.  *
018.  *
019.  * Unless required by applicable law or agreed to in writing, software
020.  * distributed under the License is distributed on an "AS IS" BASIS,
021.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
022.  * See the License for the specific language governing permissions and
023.  * limitations under the License.
024.  *
025.  ******************************************************************************
026.  */
027. 
028. 
029. 
030. 
031./* Includes ------------------------------------------------------------------*/
032.#include "main.h"
033.#include "Libmad/mad.h"
034./** @addtogroup STM32F4-Discovery_Audio_Player_Recorder
035.* @{
036.*/
037. 
038. 
039. 
040. 
041./* Private typedef -----------------------------------------------------------*/
042./* Private define ------------------------------------------------------------*/
043. 
044. 
045. 
046. 
047.#define AUDIO_BUFFER_SIZE             4096
048. 
049. 
050. 
051. 
052./* Private macro -------------------------------------------------------------*/
053./* Private variables ---------------------------------------------------------*/
054. 
055. 
056. 
057. 
058./* LED State (Toggle or OFF)*/
059.__IO uint32_t LEDsState;
060. 
061. 
062. 
063. 
064.extern __IO uint32_t RepeatState, PauseResumeStatus, PressCount;
065. 
066. 
067. 
068. 
069./* Audio Play Start variable.
070.   Defined as external in main.c*/
071.__IO uint32_t AudioPlayStart = 0;
072. 
073. 
074. 
075. 
076./* Audio wave data length to be played */
077.static uint32_t WaveDataLength = 0;
078. 
079. 
080. 
081. 
082./* Audio wave remaining data length to be played */
083.static __IO uint32_t AudioRemSize = 0;
084. 
085. 
086. 
087. 
088./* Ping-Pong buffer used for audio play */
089.uint8_t Audio_Buffer[AUDIO_BUFFER_SIZE];
090. 
091. 
092. 
093. 
094./* Position in the audio play buffer */
095.__IO BUFFER_StateTypeDef BufferOffset = BUFFER_OFFSET_NONE;
096. 
097. 
098. 
099. 
100./* Initial Volume level (from 0 (Mute) to 100 (Max)) */
101.static uint8_t Volume = 90;
102. 
103. 
104. 
105. 
106./* Variable used to indicate audio mode (play, record or stop). */
107./* Defined in main.c */
108.extern __IO uint32_t CmdIndex;
109. 
110. 
111. 
112. 
113./* Variable used by FatFs*/
114.FIL FileRead;
115.DIR Directory;
116. 
117. 
118. 
119. 
120./* Libmad Variables */
121.struct mad_stream Stream;
122.struct mad_frame Frame;
123.struct mad_synth Synth;
124. 
125. 
126. 
127. 
128.uint8_t MP3_data[AUDIO_BUFFER_SIZE];
129. 
130. 
131. 
132. 
133./* Variable used to switch play from audio sample available on USB to recorded file. */
134./* Defined in waverecorder.c */
135.//extern uint32_t WaveRecStatus;
136. 
137. 
138. 
139. 
140./* Variable to indicate USB state (start/idle) */
141./* Defined in main.c */
142.extern MSC_ApplicationTypeDef AppliState;
143. 
144. 
145. 
146. 
147.void MP3_Decoder(uint8_t* Buffer, int size);
148./* Private function prototypes -----------------------------------------------*/
149.static signed short MadFixedToShort(mad_fixed_t sample)
150.{
151.  /* round */
152.  sample += (1L << (MAD_F_FRACBITS - 16));
153. 
154. 
155. 
156. 
157.  /* clip */
158.  if (sample >= MAD_F_ONE)
159.    sample = MAD_F_ONE - 1;
160.  else if (sample < -MAD_F_ONE)
161.    sample = -MAD_F_ONE;
162. 
163. 
164. 
165. 
166.  /* quantize */
167.  return sample >> (MAD_F_FRACBITS + 1 - 16);
168.}
169. 
170. 
171. 
172. 
173.void MP3_Decoder(uint8_t* Buffer, int size)
174.{
175.    uint8_t *mp3_decoded_data = Audio_Buffer;
176. 
177. 
178. 
179. 
180.    mad_stream_buffer(&Stream, Buffer, size);
181.     
182.    if(mad_frame_decode(&Frame, &Stream))
183.    {
184.        if(MAD_RECOVERABLE(Stream.error))
185.        {
186.            if(Stream.error!=MAD_ERROR_LOSTSYNC ||Stream.this_frame!=NULL)
187.            {
188.            //continue;
189.            }
190.        }
191.        else
192.        {
193.            if(Stream.error==MAD_ERROR_BUFLEN)
194.                        {
195.                         
196.                        }
197.                        //continue;
198.        }
199.    }
200.     
201.    mad_synth_frame(&Synth, &Frame);
202. 
203. 
204. 
205. 
206.    for(int i = 0; i < Synth.pcm.length; i++)
207.    {
208.        signed short Sample;
209.        Sample = MadFixedToShort(Synth.pcm.samples[0][i]);
210.        *(mp3_decoded_data++) = Sample;
211.        LEDsState = LED6_TOGGLE;
212.        if(MAD_NCHANNELS(&Frame.header)==2)
213.        {
214.            Sample = MadFixedToShort(Synth.pcm.samples[1][i]);
215.            *(mp3_decoded_data++) = Sample;
216.             
217.        }  
218.    }
219.    //mp3_decoded_data = Audio_Buffer;
220.    //return &mp3_decoded_data;
221.}
222. 
223. 
224. 
225. 
226./* Private functions ---------------------------------------------------------*/
227. 
228. 
229. 
230. 
231./**
232.  * @brief  Plays Wave from a mass storage.
233.  * @param  AudioFreq: Audio Sampling Frequency
234.  * @retval None
235.*/
236.void WavePlayBack(uint32_t AudioFreq)
237.{
238.  UINT bytesread = 0;
239.   
240.  /* Libmad Initialization */
241.  mad_stream_init(&Stream);
242.  mad_frame_init(&Frame);
243.  mad_synth_init(&Synth);
244.   
245.  /* Start playing */
246.  AudioPlayStart = 1;
247.  RepeatState = REPEAT_ON;
248.   
249.  /* Initialize Wave player (Codec, DMA, I2C) */
250.  if(WavePlayerInit(AudioFreq) != 0)
251.  {
252.    Error_Handler();
253.  }
254.   
255.  /* Get Data from USB Flash Disk */
256.  f_lseek(&FileRead, 0);
257.  //f_read (&FileRead, &Audio_Buffer[0], AUDIO_BUFFER_SIZE, &bytesread);
258.  f_read (&FileRead, &MP3_data[0], AUDIO_BUFFER_SIZE, &bytesread);
259.  
260.   
261.  //AudioRemSize = WaveDataLength - bytesread;
262.  MP3_Decoder(&MP3_data[0], AUDIO_BUFFER_SIZE);
263.  /* Start playing Wave */
264.  BSP_AUDIO_OUT_Play((uint16_t*)&Audio_Buffer[0], AUDIO_BUFFER_SIZE);
265.  //LEDsState = LED6_TOGGLE;
266.  PauseResumeStatus = RESUME_STATUS;
267.  PressCount = 0;
268.   
269.  /* Check if the device is connected.*/
270.  while((bytesread != 0) && (AppliState != APPLICATION_IDLE))
271.  {
272.    /* Test on the command: Playing */
273.    if(CmdIndex == CMD_PLAY)
274.    {
275.      if(PauseResumeStatus == PAUSE_STATUS)
276.      {
277.        /* Stop Toggling LED2 to signal Pause */
278.        LEDsState = STOP_TOGGLE;
279.        /* Pause playing Wave */
280.        WavePlayerPauseResume(PauseResumeStatus);
281.        PauseResumeStatus = IDLE_STATUS;
282.      }
283.      else if(PauseResumeStatus == RESUME_STATUS)
284.      {
285.        /* Toggling LED6 to signal Play */
286.        //LEDsState = LED6_TOGGLE;
287.        /* Resume playing Wave */
288.        WavePlayerPauseResume(PauseResumeStatus);
289.        PauseResumeStatus = IDLE_STATUS;
290.      
291.       
292.      bytesread = 0;
293.       
294.      if(BufferOffset == BUFFER_OFFSET_HALF)
295.      {
296.        f_read(&FileRead,
297.               &MP3_data[0],
298.               AUDIO_BUFFER_SIZE/2,
299.               (void *)&bytesread);
300.        MP3_Decoder(&MP3_data[0], AUDIO_BUFFER_SIZE/2);
301.        BufferOffset = BUFFER_OFFSET_NONE;
302.      }
303.       
304.      if(BufferOffset == BUFFER_OFFSET_FULL)
305.      {
306.        f_read(&FileRead,
307.               &MP3_data[AUDIO_BUFFER_SIZE/2],
308.               AUDIO_BUFFER_SIZE/2,
309.               (void *)&bytesread);
310.        MP3_Decoder(&MP3_data[AUDIO_BUFFER_SIZE/2], AUDIO_BUFFER_SIZE/2);
311.        BufferOffset = BUFFER_OFFSET_NONE;
312.      }
313. 
314. 
315. 
316. 
317.    }
318.    else
319.    {
320.      /* Stop playing Wave */
321.      WavePlayerStop();
322.      f_close(&FileRead);
323.      AudioRemSize = 0;
324.      RepeatState = REPEAT_ON;
325.      break;
326.    }
327.  }
328.#ifdef PLAY_REPEAT_DISABLED
329.  RepeatState = REPEAT_OFF;
330.  /* Stop playing Wave */
331.  WavePlayerStop();
332.  f_close(&FileRead);
333.  /* Test on the command: Playing */
334.  if(CmdIndex == CMD_PLAY)
335.  {
336.    LEDsState = LED4_TOGGLE;
337.  }
338.#else
339.  LEDsState = LEDS_OFF;
340.  RepeatState = REPEAT_ON;
341.  AudioPlayStart = 0;
342.  /* Stop playing Wave */
343.  WavePlayerStop();
344.  f_close(&FileRead);
345.#endif /* PLAY_REPEAT_DISABLED */
346.}
347. 
348. 
349. 
350. 
351./**
352.  * @brief  Pauses or Resumes a played Wave.
353.  * @param  state: Player state: Pause, Resume or Idle
354.  * @retval None
355.  */
356.void WavePlayerPauseResume(uint32_t wState)
357.{
358.  if(wState == PAUSE_STATUS)
359.  {
360.    BSP_AUDIO_OUT_Pause();  
361.  }
362.  else
363.  {
364.    BSP_AUDIO_OUT_Resume();  
365.  }
366.}
367. 
368. 
369. 
370. 
371./**
372.  * @brief  Stops playing Wave.
373.  * @param  None
374.  * @retval None
375.  */
376.void WavePlayerStop(void)
377.{
378.  BSP_AUDIO_OUT_Stop(CODEC_PDWN_HW);
379.}
380.  
381./**
382.  * @brief  Initializes the Wave player.
383.  * @param  AudioFreq: Audio sampling frequency
384.  * @retval None
385.  */
386.int WavePlayerInit(uint32_t AudioFreq)
387.{
388.  /* MEMS Accelerometer configure to manage PAUSE, RESUME operations */
389.  BSP_ACCELERO_Click_ITConfig();
390. 
391. 
392. 
393. 
394.  /* Initialize the Audio codec and all related peripherals (I2S, I2C, IOExpander, IOs...) */ 
395.  return(BSP_AUDIO_OUT_Init(OUTPUT_DEVICE_AUTO, Volume, AudioFreq)); 
396.}
397. 
398. 
399. 
400. 
401./*--------------------------------
402.Callbacks implementation:
403.The callbacks prototypes are defined in the stm32f4_discovery_audio_codec.h file
404.and their implementation should be done in the user code if they are needed.
405.Below some examples of callback implementations.
406.--------------------------------------------------------*/
407. 
408. 
409. 
410. 
411./**
412.  * @brief  Manages the DMA Half Transfer complete interrupt.
413.  * @param  None
414.  * @retval None
415.  */
416.void BSP_AUDIO_OUT_HalfTransfer_CallBack(void)
417.{
418.  BufferOffset = BUFFER_OFFSET_HALF;
419.}
420. 
421. 
422. 
423. 
424./**
425.* @brief  Calculates the remaining file size and new position of the pointer.
426.* @param  None
427.* @retval None
428.*/
429.void BSP_AUDIO_OUT_TransferComplete_CallBack(void)
430.{
431.  BufferOffset = BUFFER_OFFSET_FULL;
432.  BSP_AUDIO_OUT_ChangeBuffer((uint16_t*)&Audio_Buffer[0], AUDIO_BUFFER_SIZE /2);
433.}
434. 
435. 
436. 
437. 
438./**
439.* @brief  Manages the DMA FIFO error interrupt.
440.* @param  None
441.* @retval None
442.*/
443.void BSP_AUDIO_OUT_Error_CallBack(void)
444.{
445.  /* Stop the program with an infinite loop */
446.  while (1)
447.  {}
448.   
449.  /* Could also generate a system reset to recover from the error */
450.  /* .... */
451.}
452. 
453. 
454. 
455. 
456./**
457.  * @brief  Starts Wave player.
458.  * @param  None
459.  * @retval None
460.  */
461.void WavePlayerStart(void)
462.{
463.  UINT bytesread = 0;
464.  char path[] = "0:/";
465.  char* wavefilename = NULL;
466.  WAVE_FormatTypeDef waveformat;
467.   
468.  /* Get the read out protection status */
469.   
470.  if(f_opendir(&Directory, path) == FR_OK)
471.  {
472.    /*
473.    if(WaveRecStatus == 1)
474.    {
475.      wavefilename = REC_WAVE_NAME;
476.    }
477.    else
478.    {
479.      wavefilename = WAVE_NAME;
480.    }
481.    */
482.     
483.    wavefilename = WAVE_NAME;
484.     
485.    /* Open the Wave file to be played */
486.    if(f_open(&FileRead, wavefilename , FA_READ) != FR_OK)
487.    {
488.      BSP_LED_On(LED5);
489.      CmdIndex = CMD_RECORD;
490.    }
491.    else
492.    {   
493.      /* Read sizeof(WaveFormat) from the selected file */
494.      //f_read (&FileRead, &waveformat, sizeof(waveformat), &bytesread);
495.       
496.      /* Set WaveDataLenght to the Speech Wave length */
497.      //WaveDataLength = waveformat.FileSize;
498.     
499.      /* Play the Wave */
500.      WavePlayBack(44100);
501.    }   
502.  }
503.}
504. 
505. 
506. 
507. 
508./**
509.  * @brief  Resets the Wave player.
510.  * @param  None
511.  * @retval None
512.  */
513.void WavePlayer_CallBack(void)
514.{
515.  if(AppliState != APPLICATION_IDLE)
516.  {
517.    /* Reset the Wave player variables */
518.    RepeatState  = REPEAT_ON;
519.    AudioPlayStart = 0;
520.    LEDsState = LEDS_OFF;
521.    PauseResumeStatus = RESUME_STATUS;
522.    WaveDataLength =0;
523.    PressCount = 0;
524.     
525.    /* Stop the Codec */
526.    if(BSP_AUDIO_OUT_Stop(CODEC_PDWN_HW) != AUDIO_OK)
527.    {
528.      while(1){};
529.    }
530.     
531.    /* Turn OFF LED3, LED4 and LED6 */
532.    BSP_LED_Off(LED3);
533.    BSP_LED_Off(LED4);
534.    BSP_LED_Off(LED6);
535.  }
536.}
537. 
538. 
539. 
540. 
541./**
542.* @}
543.*/
544. 
545. 
546. 
547. 
548./************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


Thanks for the help. I will share out the full project as soon as it's done.

Outcomes