[STM32H7] 【STM32H745I-DISCO试用】11、播放MP3

[复制链接]
 楼主| sujingliang 发表于 2025-2-11 19:40 | 显示全部楼层 |阅读模式
<
本帖最后由 sujingliang 于 2025-2-11 19:41 编辑


为了实现播放MP3文件需要完成以下工作:
1、利用FATFS读取位于EMMC上的mp3文件,这些mp3文件可以将EMMC模拟成U盘方式拷贝到EMMC上。
2、利用ST官方提供的mp3解码软件包实现mp3文件解码:
从st.com上下载X-CUBE-AUDIO开发包
2.png

将其中的SpiritDSP_MP3_Dec加入自己的工程。
3.png
3、利用SAI驱动EM8994播放音乐。

一、定义一些常量
  1. /* Audio PDM FS frequency = 128KHz = 8 * 16KHz = 8 * FS_Freq */
  2. #define AUDIO_PDM_GET_FS_FREQUENCY(FS)  (FS * 8)

  3. #define AUDIO_FREQUENCY       SAI_AUDIO_FREQUENCY_16K
  4. #define AUDIO_CHANNEL_NUMBER  2U
  5. #define AUDIO_BUFFER_SIZE     256U
  6. #define AUDIO_PCM_CHUNK_SIZE  32U


  7. //static FILINFO file_information;
  8. static FIL file_object;
  9. __attribute__((aligned(4))) DWORD clmt[2400];                                                                                                                                                                                                 // Cluster link map table buffer
  10. __attribute__((aligned(4))) short audio_output_buffer[8192]  __attribute__((section(".bss.ARM.__at_0xD0400000")));
audio_output_buffer是音频缓冲,位于0xD0400000

二、WM8994初始化

  1. static int32_t WM8994_Probe(void)
  2. {
  3.   int32_t ret = BSP_ERROR_NONE;
  4.   WM8994_IO_t              IOCtx;
  5.   static WM8994_Object_t   WM8994Obj;
  6.   uint32_t id;

  7.   /* Configure the audio driver */
  8.   IOCtx.Address     = AUDIO_I2C_ADDRESS;
  9.   IOCtx.Init        = BSP_I2C4_Init;
  10.   IOCtx.DeInit      = BSP_I2C4_DeInit;
  11.   IOCtx.ReadReg     = BSP_I2C4_ReadReg16;
  12.   IOCtx.WriteReg    = BSP_I2C4_WriteReg16;
  13.   IOCtx.GetTick     = BSP_GetTick;

  14.   if(WM8994_RegisterBusIO (&WM8994Obj, &IOCtx) != WM8994_OK)
  15.   {
  16.     ret = BSP_ERROR_BUS_FAILURE;
  17.   }
  18.   else
  19.   {
  20.     /* Reset the codec */
  21.     if(WM8994_Reset(&WM8994Obj) != WM8994_OK)
  22.     {
  23.       ret = BSP_ERROR_COMPONENT_FAILURE;
  24.     }
  25.     else if(WM8994_ReadID(&WM8994Obj, &id) != WM8994_OK)
  26.     {
  27.       ret = BSP_ERROR_COMPONENT_FAILURE;
  28.     }
  29.     else if(id != WM8994_ID)
  30.     {
  31.       ret = BSP_ERROR_UNKNOWN_COMPONENT;
  32.     }
  33.     else
  34.     {
  35.       Audio_Drv = (AUDIO_Drv_t *) &WM8994_Driver;
  36.       Audio_CompObj = &WM8994Obj;
  37.     }
  38.   }
  39.   return ret;
  40. }


三、SAI初始化
  1. static void Playback_Init(void)
  2. {
  3.   RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct;

  4.   /* Configure PLLSAI1 prescalers */
  5.   /* PLLSAI_VCO: VCO_512M
  6.      SAI_CLK(first level) = PLLSAI_VCO/PLLSAIP = 512/125 = 4.096 Mhz */
  7.   RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI2;
  8.   RCC_PeriphCLKInitStruct.Sai23ClockSelection = RCC_SAI2CLKSOURCE_PLL2;
  9.   RCC_PeriphCLKInitStruct.PLL2.PLL2P = 125;
  10.   RCC_PeriphCLKInitStruct.PLL2.PLL2Q = 1;
  11.   RCC_PeriphCLKInitStruct.PLL2.PLL2R = 1;
  12.   RCC_PeriphCLKInitStruct.PLL2.PLL2N = 512;
  13.   RCC_PeriphCLKInitStruct.PLL2.PLL2FRACN = 0;
  14.   RCC_PeriphCLKInitStruct.PLL2.PLL2M = 25;

  15.   if(HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK)
  16.   {
  17.     Error_Handler();
  18.   }

  19.   /* Configure PLLSAI4A prescalers */
  20.   RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI4A;
  21.   RCC_PeriphCLKInitStruct.Sai4AClockSelection = RCC_SAI4ACLKSOURCE_PLL2;
  22.   if(HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK)
  23.   {
  24.     Error_Handler();
  25.   }

  26.   /* SAI PCM Output init */
  27.   __HAL_SAI_RESET_HANDLE_STATE(&haudio_out_sai);

  28.   haudio_out_sai.Instance            = AUDIO_OUT_SAIx;
  29.   haudio_out_sai.Init.AudioMode      = SAI_MODEMASTER_TX;
  30.   haudio_out_sai.Init.Synchro        = SAI_ASYNCHRONOUS;
  31.   haudio_out_sai.Init.OutputDrive    = SAI_OUTPUTDRIVE_ENABLE;
  32.   haudio_out_sai.Init.NoDivider      = SAI_MASTERDIVIDER_ENABLE;
  33.   haudio_out_sai.Init.FIFOThreshold  = SAI_FIFOTHRESHOLD_1QF;
  34.   haudio_out_sai.Init.AudioFrequency = AUDIO_FREQUENCY;
  35.   haudio_out_sai.Init.Protocol       = SAI_FREE_PROTOCOL;
  36.   haudio_out_sai.Init.DataSize       = SAI_DATASIZE_16;
  37.   haudio_out_sai.Init.FirstBit       = SAI_FIRSTBIT_MSB;
  38.   haudio_out_sai.Init.ClockStrobing  = SAI_CLOCKSTROBING_FALLINGEDGE;

  39.   haudio_out_sai.FrameInit.FrameLength       = 128;
  40.   haudio_out_sai.FrameInit.ActiveFrameLength = 64;
  41.   haudio_out_sai.FrameInit.FSDefinition      = SAI_FS_CHANNEL_IDENTIFICATION;
  42.   haudio_out_sai.FrameInit.FSPolarity        = SAI_FS_ACTIVE_LOW;
  43.   haudio_out_sai.FrameInit.FSOffset          = SAI_FS_BEFOREFIRSTBIT;

  44.   haudio_out_sai.SlotInit.FirstBitOffset = 0;
  45.   haudio_out_sai.SlotInit.SlotSize       = SAI_SLOTSIZE_DATASIZE;
  46.   haudio_out_sai.SlotInit.SlotNumber     = 4;
  47.   haudio_out_sai.SlotInit.SlotActive     = (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_2);

  48.   /* DeInit SAI PCM input */
  49.   HAL_SAI_DeInit(&haudio_out_sai);

  50.   /* Init SAI PCM input */
  51.   if(HAL_OK != HAL_SAI_Init(&haudio_out_sai))
  52.   {
  53.     Error_Handler();
  54.   }

  55.   /* Enable SAI to generate clock used by audio driver */
  56.   __HAL_SAI_ENABLE(&haudio_out_sai);
  57.     WM8994_Probe();

  58.   /* Init PDM Filters */
  59. //  AUDIO_IN_PDMToPCM_Init(AUDIO_FREQUENCY, AUDIO_CHANNEL_NUMBER);
  60. }
四、列出所有的mp3文件名
  1. void list_mp3_files(const char *path)
  2. {
  3.     DIR dir;
  4.     FILINFO fileInfo;


  5.     // 挂载文件系统
  6.     FRESULT res = f_mount(&MMCFatFs, (TCHAR const*)MMCPath, 0);
  7.     if (res != FR_OK) {
  8.         printf("Failed to mount filesystem: %d\n", res);
  9.         return;
  10.     }

  11.     // 打开目录
  12.     res = f_opendir(&dir, path);
  13.     if (res != FR_OK) {
  14.         printf("Failed to open directory: %d\n", res);
  15.         f_mount(NULL, "", 0);  // 卸载文件系统
  16.         return;
  17.     }

  18.     // 遍历目录
  19.     while (1) {
  20.         res = f_readdir(&dir, &fileInfo);
  21.         if (res != FR_OK || fileInfo.fname[0] == 0) {
  22.             break;  // 遍历完成或出错
  23.         }

  24.         // 检查是否为 MP3 文件
  25.         if (!(fileInfo.fattrib & AM_DIR)) {  // 排除目录
  26.             char *ext = strrchr(fileInfo.fname, '.');  // 获取文件扩展名
  27.             if (ext && strcmp(ext, ".mp3") == 0) {    // 检查扩展名是否为 .mp3
  28.                 strncpy(mp3Files[mp3Count], fileInfo.fname, 255);  // 存储文件名
  29.                 mp3Count++;
  30.                 if (mp3Count >= 100) {
  31.                     break;  // 达到最大存储数量
  32.                 }
  33.             }
  34.         }
  35.     }

  36.     // 关闭目录
  37.     f_closedir(&dir);

  38.     // 卸载文件系统
  39.     f_mount(NULL, "", 0);

  40.     // 打印所有 MP3 文件名
  41.     for (int i = 0; i < mp3Count; i++) {
  42.         printf("MP3 File: %s\n", mp3Files[i]);
  43.     }
  44. }
五、初始化MP3播放器
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]  初始化MP3播放器
  3.         * @param  mp3_file: MP3文件的名字
  4.         * @param  vol: 音量
  5.         * @param  output_device: 0--耳机  1--喇叭
  6.   * @retval 1:成功 0:失败
  7.   */
  8. unsigned char st_mp3_player_Init( char *mp3_file, unsigned char vol, unsigned char output_device )
  9. {
  10.         unsigned int read_num;
  11.         unsigned int ID3_Length, temp1;
  12.         unsigned char buf[4];
  13.         uint32_t *AudioFreq_ptr;
  14.         uwVolume = vol;
  15.         
  16.         memset( SongInfo.FileName, 0, 30 );
  17.         
  18.         /* Register the file system object to the FatFs module */
  19.   if(f_mount(&MMCFatFs, (TCHAR const*)MMCPath, 0) != FR_OK)
  20.   {
  21.                 printf("f_mount error\r\n");
  22.                 return 0;
  23.   }
  24.         
  25.         if( f_open( &file_object, mp3_file, FA_OPEN_EXISTING | FA_READ ) != FR_OK )
  26.         {
  27.                 printf("MP3 File Open Err!!!\r\n" );
  28.                 return 0;
  29.         }
  30.         
  31.         /*        使能FATFS的快速读写功能        */
  32.         if( f_lseek(&file_object, 4)!= FR_OK )
  33.         {
  34.                 f_close( &file_object );
  35.                 printf("faftfs fast seek feature err!!!\r\n" );
  36.                 return 0;
  37.         }
  38.         
  39.         file_object.cltbl = clmt;                                                               /* Enable fast seek feature (cltbl != NULL) */
  40.   clmt[0] = 2400;                                                                                                                                                                                /* Set table size */
  41.         
  42.         if( f_lseek(&file_object, CREATE_LINKMAP) != FR_OK )                                                        /* Create CLMT */
  43.         {
  44.                 f_close( &file_object );
  45.                 printf("faftfs fast seek feature err!!!\r\n" );
  46.                 return 0;
  47.         }
  48.         
  49.         if( f_lseek(&file_object, 0)!= FR_OK )
  50.         {
  51.                 f_close( &file_object );
  52.                 printf("faftfs fast seek feature err!!!\r\n" );
  53.                 return 0;
  54.         }
  55.         
  56.         //计算文件大小
  57.         SongInfo.FileSize = f_size( &file_object );
  58.         memcpy( SongInfo.FileName, mp3_file, strlen( mp3_file) );
  59.         
  60.         //判断打开的文件是否是mp3文件
  61.         if( f_read( &file_object, buf, 3, &read_num ) != FR_OK )
  62.         {
  63.                 f_close( &file_object );
  64.                 return 0;
  65.         }
  66.         
  67.         if( memcmp( buf, (unsigned char *)"ID3", 3 ) != 0 )
  68.         {
  69.                 f_close( &file_object );
  70.                 printf("It is not mp3 file!!!\r\n" );
  71.                 return 0;
  72.         }
  73.         
  74.         //开始计算ID3标签头大小
  75.         f_lseek( &file_object, 6 );
  76.         
  77.         if( f_read( &file_object, buf, 4, &read_num ) != FR_OK )
  78.         {
  79.                 f_close( &file_object );
  80. //                printf("读取文件失败。\r\n" );
  81.                 return 0;
  82.         }
  83.         
  84.         ID3_Length = (buf[0] & 0x7f) * 0x200000;                                                                                                                                                                        //计算ID3标签头的大小
  85.         ID3_Length = ID3_Length + ( (buf[1] & 0x7f) * 0x400 );
  86.         ID3_Length = ID3_Length + ( (buf[2] & 0x7f) * 0x80 );
  87.         ID3_Length = ID3_Length + (buf[3] & 0x7f) + 10;
  88.         
  89.         //跳转到ID3标签结束位置,准备获取mp3文件信息
  90.         f_lseek( &file_object, ID3_Length );
  91.         SongInfo.file_ptr = ID3_Length;
  92.         
  93.         //初始化MP3解码器
  94.         memset( &g_MP3Decoder, 0, sizeof( TSpiritMP3Decoder ) );
  95.         SpiritMP3DecoderInit(        &g_MP3Decoder, // MP3 decoder object
  96.                                                                                                 RetrieveMP3Data, // Input callback function
  97.                                                                                                 NULL, // No post-process callback
  98.                                                                                                 NULL // Callback parameter
  99.                                                                                         );
  100.         
  101.         //获取mp3文件信息
  102.         while( 1 )
  103.         {
  104.                 Audio_Delay_1ms( 3 );
  105.                
  106.                 temp1 = SpiritMP3Decode(         &g_MP3Decoder,                                                     /* Decoder structure */
  107.                                                                                                                         (short *)&audio_output_buffer[0],   /* [OUT] Output PCM buffer */
  108.                                                                                                                         1152,                                                                                                 /* Number of samples to decode (1 sample = 32 bit = 2ch*16 bit) */
  109.                                                                                                                         &MP3Info                                                    /* [OUT, opt] Optional informational structure */
  110.                                                                                                          );        
  111.                 //到达文件末尾,没有获取mp3文件信息,退出                                                                                       
  112.                 if( temp1 < 1152 )
  113.                 {
  114.                         f_close( &file_object );
  115.                         printf("Get MP3 Info Err!!!\r\n");
  116.                         return 0;
  117.                 }
  118.                
  119.                 //获取到正确的MP3信息
  120.                 if( MP3Info.IsGoodStream == 1 && MP3Info.nSampleRateHz != 0 && MP3Info.nBitrateKbps != 0 )
  121.                 {
  122.                         MPEGAudioFrameInfo.mSamplesPerFrame = MP3Info.nSamplesPerFrame;
  123.                         MPEGAudioFrameInfo.mBitrate = MP3Info.nBitrateKbps * 1000;
  124.                         SongInfo.Bitrate = MPEGAudioFrameInfo.mBitrate;
  125.                         MPEGAudioFrameInfo.mChannelMode = MP3Info.nChannels;
  126.                         MPEGAudioFrameInfo.mLayer = MP3Info.nLayer;
  127.                         MPEGAudioFrameInfo.mSamplerate = MP3Info.nSampleRateHz;
  128.                         //计算歌曲的播放时长
  129.                         SongInfo.time = (SongInfo.FileSize - ID3_Length) * 8 / SongInfo.Bitrate;
  130.                         
  131.                         printf("\r\n");
  132.                         printf( "mp3 SamplesPerFrame:%d\r\n", MPEGAudioFrameInfo.mSamplesPerFrame );
  133.                         printf( "mp3 Bitrate:%d\r\n", MPEGAudioFrameInfo.mBitrate );
  134.                         printf( "mp3 Samplerate:%d\r\n", MPEGAudioFrameInfo.mSamplerate );
  135.                         printf( "mp3 ChannelMode:%d\r\n", MPEGAudioFrameInfo.mChannelMode );
  136.                         printf( "mp3 Layer:%d\r\n", MPEGAudioFrameInfo.mLayer );
  137.                         printf( "mp3 FileSize:%d\r\n", SongInfo.FileSize );
  138.                         printf( "mp3 PlayTime:%d\r\n", SongInfo.time );
  139.                         
  140.                         Display_SongDescription();
  141.                         break;
  142.                 }
  143.         }
  144.         
  145.         
  146.         //重新初始化MP3解码器,准备开始解码
  147.         memset( &g_MP3Decoder, 0, sizeof( TSpiritMP3Decoder ) );
  148.         SpiritMP3DecoderInit(        &g_MP3Decoder, // MP3 decoder object
  149.                                                                                                 RetrieveMP3Data, // Input callback function
  150.                                                                                                 NULL, // No post-process callback
  151.                                                                                                 NULL // Callback parameter
  152.                                                                                         );
  153.         
  154.         //跳转到ID3标签头结束位置,从此位置开始解码
  155.         f_lseek( &file_object, ID3_Length );
  156.         SongInfo.file_ptr = ID3_Length;
  157.         /*
  158.         for(int i=0;i<sizeof(AudioFreq);i++)
  159.         {
  160.                 if(abs((int)(AudioFreq[i]-MPEGAudioFrameInfo.mSamplerate))<100)
  161.                 {
  162.                         AudioFreq_ptr=&AudioFreq[i];
  163.                         break;
  164.                 }
  165.         }
  166.         */
  167.         AudioFreq[0]=MPEGAudioFrameInfo.mSamplerate;
  168.         AudioFreq_ptr=&AudioFreq[0];
  169.         //AudioFreq_ptr = &AudioFreq[6]; /*96K*/
  170.         
  171.         AudioPlayInit->Device = AUDIO_OUT_DEVICE_HEADPHONE;
  172.   AudioPlayInit->ChannelsNbr = 2;
  173.   AudioPlayInit->SampleRate = *AudioFreq_ptr;
  174.   AudioPlayInit->BitsPerSample = AUDIO_RESOLUTION_16B;
  175.   AudioPlayInit->Volume = uwVolume;
  176.         
  177.         //配置WM8994的工作模式
  178.         if( BSP_AUDIO_OUT_Init( 0, AudioPlayInit ) != 0 )
  179.         {
  180.                 f_close( &file_object );
  181.                 printf("WM8994 Init Err!!!\r\n");
  182.                 return 0;
  183.         }
  184.         
  185.         //if( output_device == 0 ) BSP_AUDIO_OUT_SetAudioFrameSlot(CODEC_AUDIOFRAME_SLOT_02);
  186.         //else BSP_AUDIO_OUT_SetAudioFrameSlot(CODEC_AUDIOFRAME_SLOT_13);

  187.         return 1;
  188. }
六、播放MP3函数
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]  播放MP3
  3.         * @param  time: MP3文件开始播放的时间点(不超过MP3播放时间的最大值),单位:s
  4.   * @retval 1:成功 0:失败
  5.   */
  6. unsigned char st_mp3play( unsigned short int time )
  7. {
  8.         signed int temp = 0;
  9.         unsigned int nSamples = 0;
  10.         unsigned int addr = 0;
  11.         uint8_t index=mp3Current;
  12.         
  13.         SongInfo.state = OK;
  14.         SongInfo.time_count = time;
  15.         
  16.         if( time >= (SongInfo.time-2) )
  17.         {
  18.                 BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
  19.                 f_close( &file_object );
  20.                 return 1;
  21.         }
  22.         
  23.         //根据播放起始时间,计算文件指针起始位置
  24.         addr = (time * SongInfo.Bitrate / 8 );
  25.         if( addr == 0 )
  26.         {
  27.                 if( f_lseek(&file_object, SongInfo.file_ptr ) != FR_OK )
  28.                 {
  29.                         f_close( &file_object );               
  30.                         BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
  31.                         return 0;
  32.                 }
  33.         }
  34.         else
  35.         {
  36.                 addr += SongInfo.file_ptr;
  37.                 SongInfo.file_ptr = addr;
  38.                
  39.                 if( f_lseek(&file_object, SongInfo.file_ptr) != FR_OK )
  40.                 {
  41.                         f_close( &file_object );
  42.                         BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
  43.                         return 0;
  44.                 }
  45.         }
  46.         

  47.         /*        先解码两帧mp3音频数据,用于填充audio_output_buffer */
  48.         temp = 0;
  49.         while( temp < 2 )
  50.         {
  51.                 nSamples = SpiritMP3Decode( &g_MP3Decoder,                                                                                             /* Decoder structure */
  52.                                                                                                                                 (short *)&audio_output_buffer[temp*MPEGAudioFrameInfo.mSamplesPerFrame*2],   /* [OUT] Output PCM buffer */
  53.                                                                                                                                 MPEGAudioFrameInfo.mSamplesPerFrame,          /* Number of samples to decode (1 sample = 32 bit = 2ch*16 bit) */
  54.                                                                                                                                 &MP3Info                                                                                            /* [OUT, opt] Optional informational structure */
  55.                                                                                                                         );        
  56.                                                                                                                                        
  57.                 printf("Samples:%d\r\n", nSamples);

  58.                 if( MP3Info.IsGoodStream == 1 )
  59.                 {
  60.                         temp++;
  61.                 }
  62.                
  63.                 /*        到达文件末尾,则退出        */
  64.                 if( nSamples < MPEGAudioFrameInfo.mSamplesPerFrame||index!= mp3Current)
  65.                 {
  66.                         f_close( &file_object );
  67.                         BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
  68.                         return 0;
  69.                 }
  70.                
  71.                 Audio_Delay_1ms( 3 );
  72.         }
  73.         
  74.         TxHalfCpltFlag = 0;
  75.         TxCpltFlag = 0;
  76.         TxBufNum = 0;
  77.         AudioOutFlag = 0;
  78.         Audio_ErrorFlag = 0;
  79.         
  80.         //开始播放
  81.         BSP_AUDIO_OUT_Play( 0,(uint8_t*)audio_output_buffer, (MPEGAudioFrameInfo.mSamplesPerFrame*2*2*2) );
  82.         AudioOutFlag = 1;
  83.         while( 1 )
  84.         {
  85.                 while( AudioOutFlag == 1 )
  86.                 {
  87.                         //播放状态--暂停
  88.                         if( SongInfo.state == Pause )
  89.                         {
  90.                                 BSP_AUDIO_OUT_Pause(0);
  91.                                 
  92.                                 while( SongInfo.state == Pause )
  93.                                 {
  94.                                         Audio_Delay_1ms( 10 );
  95.                                 }
  96.                         }
  97.                         //播放状态--恢复
  98.                         else if( SongInfo.state == Resume )
  99.                         {
  100.                                 BSP_AUDIO_OUT_Resume( 0 );
  101.                                 SongInfo.state = OK;
  102.                         }
  103.                         //播放状态--停止
  104.                         else if( SongInfo.state == Stop )
  105.                         {
  106.                                 BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
  107.                                 f_close( &file_object );
  108.                
  109.                                 SongInfo.state = OK;
  110.                                 return 1;
  111.                         }
  112.                         //播放状态--错误
  113.                         else if( Audio_ErrorFlag == 1 )
  114.                         {
  115.                                 BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
  116.                                 f_close( &file_object );
  117.                                 return 0;
  118.                         }
  119.         
  120.                         Audio_Delay_1ms( 3 );
  121.                 }
  122.                
  123.                 //计算当前歌曲时间点
  124.                 SongInfo.time_count = SongInfo.file_ptr * 8 / SongInfo.Bitrate ;
  125.                 //printf("SongInfo.time_count:%d\r\n",SongInfo.time_count);
  126.                
  127.                 //audio_output_buffer已通过DMA传输一半
  128.                 if( TxHalfCpltFlag == 1 )
  129.                 {
  130.                         //解码MP3音频数据,用来填充audio_output_buffer
  131.                         while( 1 )
  132.                         {
  133.                                 nSamples = SpiritMP3Decode( &g_MP3Decoder,                                                                                             /* Decoder structure */
  134.                                                                                                                                                 (short *)&audio_output_buffer[0],                                           /* [OUT] Output PCM buffer */
  135.                                                                                                                                                 MPEGAudioFrameInfo.mSamplesPerFrame,          /* Number of samples to decode (1 sample = 32 bit = 2ch*16 bit) */
  136.                                                                                                                                                 &MP3Info                                                                                            /* [OUT, opt] Optional informational structure */
  137.                                                                                                                                         );        
  138.                                 /*到达文件末尾, 则退出*/
  139.                                 if( nSamples < MPEGAudioFrameInfo.mSamplesPerFrame ||index!= mp3Current)
  140.                                 {
  141.                                         BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
  142.                                         f_close( &file_object );
  143.                                         return 1;
  144.                                 }
  145.                                 
  146.                                 if( !( !MP3Info.IsGoodStream || (MP3Info.nBitrateKbps == 0) || (MP3Info.nSampleRateHz == 0) ) )
  147.                                 {
  148.                                         break;
  149.                                 }
  150.                         }
  151.                 }
  152.                
  153.                 //audio_output_buffer已通过DMA全部传输完成
  154.                 if( TxCpltFlag == 1 )
  155.                 {
  156.                         while( 1 )
  157.                         {
  158.                                 nSamples = SpiritMP3Decode( &g_MP3Decoder,                                                                                             /* Decoder structure */
  159.                                                                                                                                                 (short *)&audio_output_buffer[MPEGAudioFrameInfo.mSamplesPerFrame*2],                                           /* [OUT] Output PCM buffer */
  160.                                                                                                                                                 MPEGAudioFrameInfo.mSamplesPerFrame,          /* Number of samples to decode (1 sample = 32 bit = 2ch*16 bit) */
  161.                                                                                                                                                 &MP3Info                                                                                            /* [OUT, opt] Optional informational structure */
  162.                                                                                                                                         );        

  163.                                 /*到达文件末尾,则退出*/
  164.                                 if( nSamples < MPEGAudioFrameInfo.mSamplesPerFrame )
  165.                                 {
  166.                                         BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
  167.                                         f_close( &file_object );
  168.                                         return 1;
  169.                                 }
  170.                                 
  171.                                 if( !( !MP3Info.IsGoodStream || (MP3Info.nBitrateKbps == 0) || (MP3Info.nSampleRateHz == 0) ) )
  172.                                 {
  173.                                         break;
  174.                                 }
  175.                         }
  176.                 }
  177.                
  178.                 if( TxHalfCpltFlag == 1 && TxCpltFlag == 1 )
  179.                 {
  180.                         TxHalfCpltFlag = 0;
  181.                         TxCpltFlag = 0;
  182.                         
  183.                         BSP_AUDIO_OUT_Resume(0);
  184.                 }
  185.                 else if( TxHalfCpltFlag == 1 ) TxHalfCpltFlag = 0;
  186.                 else if( TxCpltFlag == 1 ) TxCpltFlag = 0;
  187.                
  188.                 AudioOutFlag = 1;
  189.         }
  190.         
  191.         return 1;
  192. }
七、中断处理

  1. void DMA2_Stream1_IRQHandler(void)
  2. {
  3.   /* USER CODE BEGIN DMA2_Stream1_IRQn 0 */

  4.         HAL_DMA_IRQHandler(haudio_out_sai.hdmatx);
  5.   /* USER CODE END DMA2_Stream1_IRQn 0 */

  6.   /* USER CODE BEGIN DMA2_Stream1_IRQn 1 */

  7.   /* USER CODE END DMA2_Stream1_IRQn 1 */
  8. }
回调
  1. void  BSP_AUDIO_OUT_TransferComplete_CallBack(uint32_t Instance)
  2. {
  3.         TxCpltFlag = 1;
  4.         AudioOutFlag = 0;
  5.         TxBufNum = 0;
  6.         //printf("BSP_AUDIO_OUT_TransferComplete_CallBack\r\n");
  7.         if( TxHalfCpltFlag == 1 )
  8.         {
  9.                 BSP_AUDIO_OUT_Pause(0);
  10.                 TxBufNum = 1;
  11.                 printf("fault1\r\n");
  12.         }
  13. }        

  14. void  BSP_AUDIO_OUT_HalfTransfer_CallBack(uint32_t Instance)
  15. {
  16.         TxHalfCpltFlag = 1;
  17.         AudioOutFlag = 0;
  18.         TxBufNum = 1;
  19.         //printf("BSP_AUDIO_OUT_HalfTransfer_CallBack\r\n");
  20.         if( TxCpltFlag == 1 )
  21.         {
  22.                 BSP_AUDIO_OUT_Pause(0);
  23.                 TxBufNum = 0;
  24.                 printf("fault2\r\n");
  25.         }
  26. }


八、播放DEMO
  1. void mp3_player_demo(void)
  2. {
  3.         if( st_mp3_player_Init( mp3Files[mp3Current%mp3Count], 80, 0) == 1 )
  4.         {
  5.                 printf("mp3 init ok\r\n");
  6.                 st_mp3play( 0 );
  7.         }
  8. }
  1. void BSP_PB_Callback(Button_TypeDef Button)
  2. {
  3.         printf("BSP_PB_Callback\r\n");
  4.         if(Button==BUTTON_USER)
  5.         {
  6.                 mp3Current++;
  7.                 if(mp3Current>=mp3Count) mp3Current=0;
  8.                
  9.         }
  10. }
按键处理

您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

146

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部