⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 player_lib.c

📁 MP3 Cyclone的source code 利用FPGGA實現MP3的功能
💻 C
📖 第 1 页 / 共 3 页
字号:
/***********************************************************************
 *                                                                     *
 * File:     player_lib.c                                              *
 *                                                                     *
 * Purpose:  Contains all our custom MP3 player functions.             *
 *                                                                     *
 * Author:   N. Knight                                                 *
 *           Altera Corporation                                        *
 *           Aug 2005                                                  *
 **********************************************************************/

#include "player_lib.h"
#include "mad/mad.h"
#include "altera_avalon_pio_regs.h"
#include "system.h"
#include "sys/alt_alarm.h"
#include "pwm/pwm.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/***********************************************************************
 * Function: NiosIIMP3_Decode                                          *
 *                                                                     *
 * Purpose: Initializes the MP3 decoder structure and starts the       *
 *          decoder using the MAD API                                  *
 *                                                                     *
 * Input:   Pointer to the MP3 file structure.                         *
 * Output:  None, API uses callback functions for output               * 
 * Returns: Error Code, 0 = Success                                    *
 **********************************************************************/

int NiosIIMP3_Decode( nios_mp3_file_struct *mp3_files )
{
  int ret_code;
  mad_decoder_type* decoder;
  
  decoder = ( mad_decoder_type* ) 
                  malloc( sizeof ( mad_decoder_type ) );
  /* 
   * Setup our callback functions with a MAD API call. 
   *  -Input function =  NiosIIMP3_Input
   *  -Output function = NiosIIMP3_Output
   *  -Error function =  NiosIIMP3_Error
   * Header, filter, and message functions aren't used
   * 
   * We also pass in a pointer to the mp3 file structure.  This in turn
   * will get passed to our callback functions, giving them access 
   * to the mp3 files.
   */
  mad_decoder_init( decoder, mp3_files,
       NiosIIMP3_Input, 0 /* header */, 0 /* filter */, NiosIIMP3_Output,
       NiosIIMP3_Error, 0 /* message */);
       
  /* Start the decoder with an API call */
  ret_code = mad_decoder_run( decoder, MAD_DECODER_MODE_SYNC );

  /* Give back what we've taken */
  free( decoder );
  
  return( ret_code );
}       
        
/***********************************************************************
 * Function: NiosIIMP3_Input                                           *
 *                                                                     *
 * Purpose: This is the callback function the MAD API calls when it's  *
 *          buffer has run out of frames to decode (or hasnt gotten    *
 *          any yet).  We simply refill the file buffer from the file  *
 *          and pass the buffer pointer back to the decoder.           *
 *                                                                     *
 * Input:   Pointer to the MP3 file structure. (passed in as a void*)  *
 *          Pointer to the decoder's input stream buffer structure     *
 * Output:  A refilled input stream buffer                             * 
 * Returns: Error Code, MAD_FLOW_CONTINUE = Success                    *
 **********************************************************************/

enum mad_flow NiosIIMP3_Input(void *data, struct mad_stream *stream)
{
  int file_pos_needed;
  nios_mp3_file_struct *mp3_files;
  int ret_code;
  
  /* Our file info gets past in as "data" */
  mp3_files = ( nios_mp3_file_struct * )data;
    
  if( mp3_files->file_position < mp3_files->file_length )
  {
    file_pos_needed = ( mp3_files->file_position - ( stream->bufend - stream->next_frame ) );
    NiosIIMP3_FillFileBuffer( mp3_files, file_pos_needed );
  
    /* Hand off the buffer to the MP3 input stream */
    mad_stream_buffer( stream, mp3_files->file_buffer, mp3_files->file_buffer_size );
  
    ret_code = MAD_FLOW_CONTINUE;
  }
  else
  {
    /* End of song.  Exit and let the caller decide what to do */
    ret_code = MAD_FLOW_STOP;
  }
  
  return( ret_code );

}

/***********************************************************************
 * Function: NiosIIMP3_Output                                          *
 *                                                                     *
 * Purpose: This is the callback function the MAD API calls after it's *
 *          synthesized a frame's worth of output samples and they're  *
 *          ready for playback.  We have two choices, we can measure   *
 *          the decode performance or play the samples. If we play the *
 *          samples, our performance measurement wont be accurate      *
 *          because the audio player throttles the decoder to prevent  *
 *          overflow.  When PLAY_AUDIO is 1, the highest the decode    *
 *          performance will ever be is the output sample rate         *
 *                                                                     *
 *          Second, we take this opportunity to check the buttons and  *
 *          see if they've been pressed.                               *
 *                                                                     *
 *          Lastly, we throw in a flashy LED spinner every time a      *
 *          frame is decoded                                           *
 *                                                                     *
 * Input:   Pointer to the MP3 file structure. (passed in as a void*)  *
 *          Pointer to the decoder's header structure (not used)       *
 *          Pointer to the decoder's PCM output sample buffers         *
 * Output:  Samples are sent to the play audio routine                 * 
 * Returns: Return code whether to restart playback                    *
 **********************************************************************/

enum mad_flow NiosIIMP3_Output(void *data,
         struct mad_header const *header,
         struct mad_pcm *pcm)         
{
  nios_mp3_file_struct *mp3_files;
  alt_u32 ret_code, buttons;
  
  /* Our file info gets past in as void* "data" */
  mp3_files = (nios_mp3_file_struct*)data;
  
  if( MEASURE_DECODE_PERFORMANCE )
  {
    NiosIIMP3_MeasurePerformance( pcm );
  }
  if( PLAY_AUDIO & mp3_files->playing )
  {
    NiosIIMP3_PlayAudio( pcm );
    
    /* Start the PWM if it's not already running */
    PWM_Start( AUDIO_PWM_BASE );
  }
  /* Spin the 7-seg every time we finish a frame's worth of samples */ 
  NiosIIMP3_ShowSpinner( 1 );

  /* 
   * This is as good a place as any to check the buttons.
   * If the buttons say we're starting a new file, we need
   * to exit and start over with decoding
   */
  buttons = NiosIIMP3_CheckButtons( mp3_files );
  if( buttons == NEW_FILE )
  {
    ret_code = MAD_FLOW_STOP;
  }
  else if( buttons == PAUSE )
  {
     while( mp3_files->playing == 0 )
       NiosIIMP3_CheckButtons( mp3_files );
     ret_code = MAD_FLOW_CONTINUE;
  }
  else 
  {
    ret_code = MAD_FLOW_CONTINUE;
  }
  
  return ret_code;
}

/***********************************************************************
 * Function: NiosIIMP3_Error                                           *
 *                                                                     *
 * Purpose: This is the callback function the MAD API calls when it    *
 *          encounters a decode error.  The only error we really know  *
 *          how to deal with is when the decoder runs into an ID3 tag. *
 *          All we do is read the length of the tag, then refill the   *
 *          file buffer starting where the ID3 tag ends.  That should  *
 *          be the beginning of a valid frame.                         *
 *                                                                     *
 * Input:   Pointer to the MP3 file structure. (passed in as a void*)  *
 *          Pointer to the decoder's input stream buffer structure     *
 *          Pointer to the decoder's frame buffer structure (not used) *
 * Output:  A refilled file buffer that starts with a valid frame OR   *
 *          an error message if the error wasnt ID3 tag related        * 
 * Returns: MAD_FLOW_CONTINUE = success, MAD_FLOW_BREAK = error        *
 **********************************************************************/

enum mad_flow NiosIIMP3_Error( void *data, 
                               struct mad_stream *stream, 
                               struct mad_frame *frame )
{
  int ret_code;
  alt_u32 tag_length;
  nios_mp3_file_struct *mp3_files;
  
  /* Our file info gets past in as "data" */
  mp3_files = ( nios_mp3_file_struct * )data;
   
  /*
   * The error could be caused by an ID3 tag if this is the beginning of 
   * a file.  Lets check, and if there's a tag, read it's length and point 
   * past it to the first actual data frame.
   */
  if (mad_bit_read( &stream->ptr, 8 ) == 0x49 &&     //"I"
      mad_bit_read( &stream->ptr, 8 ) == 0x44 &&     //"D"
      mad_bit_read( &stream->ptr, 8 ) == 0x33 )      //"3"
  {
    /* Skip over the version and flags */
    mad_bit_skip( &stream->ptr,24 );
    /* Read the tag length. It's in a weird "syncproof" format, so we 
     * need to process it a bit */
    tag_length =  (mad_bit_read(&stream->ptr,8) & 0x7f) << 21;
    tag_length |= (mad_bit_read(&stream->ptr,8) & 0x7f) << 14;
    tag_length |= (mad_bit_read(&stream->ptr,8) & 0x7f) << 7;
    tag_length |= (mad_bit_read(&stream->ptr,8) & 0x7f);
    /* tag_length excludes the tag header, so add 10 to it */
    tag_length += 10;
    
    /* Now we know where the first frame is, refill the buffer starting there */
    NiosIIMP3_FillFileBuffer( mp3_files, tag_length );
    /* Hand off the buffer to the MP3 input stream */
    mad_stream_buffer( stream, mp3_files->file_buffer, mp3_files->file_buffer_size );
     
    ret_code = MAD_FLOW_CONTINUE;
  }
  /* EOF, exit and let caller decide what to do */
  else if( mp3_files->file_position >= mp3_files->file_length )
  {
    ret_code = MAD_FLOW_STOP;
  }
  else
  {
    printf( "ERROR ERROR!! \n" );
    ret_code = MAD_FLOW_BREAK;
  }
  
  return( ret_code );
}

/***********************************************************************
 * Function: NiosIIMP3_FileInit                                        *
 *                                                                     *
 * Purpose: Initializes the structure that keeps track of important    *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -