📄 player_lib.c
字号:
/***********************************************************************
* *
* 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 + -