簡單mp3播放器:音頻播放核心
tag:C,mp3解碼,libMAD,PortAudio
/* Create by zyzx
* Created 2008-08-09
* Modified 2008-08-09
*/
一、準(zhǔn)備
?????? 1、依賴庫PortAudio(http://www.portaudio.com/)
???????????? Win32平臺(tái)編譯見《Win32環(huán)境PortAudio庫編譯簡介:音頻播放》
?????? 2、依賴庫libMAD (http://www.underbit.com/products/mad/)
???????????? 簡介:開源跨平臺(tái)的mpeg-1,mpeg-2,mpeg-2.5,MP3解碼C庫。
???????????? 編譯環(huán)境 Win32 + VS
???????????? 下載libMAD 打開 ..\msvc++\LibMad.sln 可以用VS直接編譯。
二、編碼試驗(yàn)
??????? 如上一篇《簡單音頻播放:音頻播放核心實(shí)現(xiàn)》的代碼實(shí)現(xiàn),不同的是LibMad 提供給我們的解碼方式稍微有些區(qū)別。
??????? 如下源碼參照 PortAudio庫中示例patest_read_write_wire.c 和 LibMad庫中示例minimad.c文件進(jìn)行的修改,還有Audacity中的部分實(shí)現(xiàn)。。所以還有很多地方懶得去理會(huì),代碼難看點(diǎn)。。
??????? 需要注意的地方:
??????? 基本上同上一篇。
??????? 1)PCM格式,分左右聲道2個(gè)緩存區(qū)域
??????? 2)PortAudio接受一個(gè)緩存區(qū)域,左右聲道并列方式組織。
??????? 3)當(dāng)然如果要讓你的音頻播放模塊能夠支持更多種格式,可要做一番設(shè)計(jì)了。。要做到可以替換編解碼模塊,驅(qū)動(dòng)聲卡模塊,跨平臺(tái),移植ARM那些系統(tǒng),還是不容易的。。
如下是全部的源碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "portaudio.h"
#include <sys/types.h>
#include "mad.h"
#include "windows.h"
/* #define SAMPLE_RATE (17932) // Test failure to open with this value. */
#define SAMPLE_RATE (44100)
#define FRAMES_PER_BUFFER ( 64 * 1024 )
#define NUM_CHANNELS??? (2)
/* #define DITHER_FLAG???? (paDitherOff) */
#define DITHER_FLAG???? (0) /**/
/* Select sample format. */
#if 1
#define PA_SAMPLE_TYPE paFloat32
#define SAMPLE_SIZE (4)
#define SAMPLE_SILENCE (0.0f)
#define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
#define PRINTF_S_FORMAT "%.8f"
#elif 0
#define PA_SAMPLE_TYPE paInt16
#define SAMPLE_SIZE (2)
#define SAMPLE_SILENCE (0)
#define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
#define PRINTF_S_FORMAT "%d"
#elif 0
#define PA_SAMPLE_TYPE paInt24
#define SAMPLE_SIZE (3)
#define SAMPLE_SILENCE (0)
#define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
#define PRINTF_S_FORMAT "%d"
#elif 0
#define PA_SAMPLE_TYPE paInt8
#define SAMPLE_SIZE (1)
#define SAMPLE_SILENCE (0)
#define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
#define PRINTF_S_FORMAT "%d"
#else
#define PA_SAMPLE_TYPE paFloat32//paUInt8
#define SAMPLE_SIZE ( sizeof(float) )
#define SAMPLE_SILENCE (128)
#define CLEAR( a ) { \
??? int i; \
??? for( i=0; i<FRAMES_PER_BUFFER*NUM_CHANNELS; i++ ) \
??? ((unsigned char *)a)[i] = (SAMPLE_SILENCE); \
}
#define PRINTF_S_FORMAT "%d"
#endif
#define WIN32_AUDIO_BUFF_LEN??? 32 * 1024 * 1024
#define WIN32_BUFF_MAD_LEN??? ??? FRAMES_PER_BUFFER
typedef struct
{
??? float*??? ??? buffer;?????????????????????????????? //* - 解碼后的數(shù)據(jù)存儲(chǔ)區(qū)域
??? long??? ??? current, bufferlen ;
??? unsigned char*??? bufferMad;?????????? //* - 由于LibMad是一段一段讀寫,這里是緩沖區(qū)域
??? long??? bfMadLen;
??? unsigned int samplerate;??? ??? /* sampling frequency (Hz) */
??? unsigned short channels;??? ??? /* number of channels */
??? FILE* file;
} Win32_Data ;
struct MadBuffer {
??? unsigned char const *start;
??? unsigned long length;
};
static
enum mad_flow input(void *data,
struct mad_stream *stream)
{
??? Win32_Data *buffer = (Win32_Data*)data;
??? //if (!buffer->length)
??? //??? return MAD_FLOW_STOP;
??? //mad_stream_buffer(stream, buffer->start, buffer->length);
??? //buffer->length = 0;
??? if( feof( buffer->file ) ) {
??? ??? return MAD_FLOW_STOP;
??? }
??? //* - 這段摘自Audacity(http://audacity.sourceforge.net/)
??? //* - 由于mp3編碼方式,可能某次讀取的數(shù)據(jù)并不是完整的,我們只取完整的 frame段,
??? //* - 將剩余的部分留給下段。
??? unsigned int unconsumedBytes;
??? if(stream->next_frame) {
??? ??? unconsumedBytes = buffer->bufferMad + WIN32_BUFF_MAD_LEN - stream->next_frame;
??? ??? memmove(buffer->bufferMad, stream->next_frame, unconsumedBytes);
??? }
??? else
??? ??? unconsumedBytes = 0;
??? off_t read = fread(buffer->bufferMad + unconsumedBytes, sizeof( unsigned char ), WIN32_BUFF_MAD_LEN - unconsumedBytes, buffer->file);
??? mad_stream_buffer(stream, buffer->bufferMad, read + unconsumedBytes);
??? return MAD_FLOW_CONTINUE;
}
/*
* The following utility routine performs simple rounding, clipping, and
* scaling of MAD's high-resolution samples down to 16 bits. It does not
* perform any dithering or noise shaping, which would be recommended to
* obtain any exceptional audio quality. It is therefore not recommended to
* use this routine if high-quality output is desired.
*/
static inline
float scale(mad_fixed_t sample)
{
??? /* round */
??? //sample += (1L << (MAD_F_FRACBITS - 16));
??? ///* clip */
??? //if (sample >= MAD_F_ONE)
??? //??? sample = MAD_F_ONE - 1;
??? //else if (sample < -MAD_F_ONE)
??? //??? sample = -MAD_F_ONE;
??? ///* quantize */
??? //return sample >> (MAD_F_FRACBITS + 1 - 16);
??? //* 將libMad庫內(nèi)置的采樣點(diǎn)格式轉(zhuǎn)換為 32位float類型
??? return (float) (sample / (float) (1L << MAD_F_FRACBITS));
}
/*
* This is the output callback function. It is called after each frame of
* MPEG audio data has been completely decoded. The purpose of this callback
* is to output (or play) the decoded PCM audio.
*/
static
enum mad_flow output(void *data,
struct mad_header const *header,
struct mad_pcm *pcm)
{
??? unsigned int nsamples;
??? mad_fixed_t const *left_ch, *right_ch;
??? Win32_Data* buffer = ( Win32_Data* ) data;
??? ///* pcm->samplerate contains the sampling frequency */
??? buffer->channels = pcm->channels;
??? buffer->samplerate = pcm->samplerate;
??? nsamples = pcm->length;
??? left_ch?? = pcm->samples[0];
??? right_ch = pcm->samples[1];
??? while (nsamples--) {
??? ??? float sample;
??? ??? /* output sample(s) in 16-bit signed little-endian PCM */
??????? //* - PCM格式 的數(shù)據(jù)是分布在2個(gè)緩存區(qū)域中分左右聲道,而PortAudio庫是只接受一個(gè)區(qū)域
??????? //* - 左右聲道數(shù)據(jù)相鄰,所以轉(zhuǎn)換下。
??? ??? if ( buffer->channels == 2) {
??? ??? ??? sample = scale(*left_ch++);
??? ??? ??? buffer->buffer[ buffer->current++ ] = sample;
??? ??? ??? sample = scale(*right_ch++);
??? ??? ??? buffer->buffer[ buffer->current++ ] = sample;
??? ??? }
??? }
??? return MAD_FLOW_CONTINUE;
}
/*
* This is the error callback function. It is called whenever a decoding
* error occurs. The error is indicated by stream->error; the list of
* possible MAD_ERROR_* errors can be found in the mad.h (or stream.h)
* header file.
*/
static
enum mad_flow error(void *data,
struct mad_stream *stream,
struct mad_frame *frame)
{
??? //struct buffer *buffer = data;
??? //fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n",
??? //??? stream->error, mad_stream_errorstr(stream),
??? //??? stream->this_frame - buffer->start);
??? ///* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */
??? return MAD_FLOW_CONTINUE;
}
/*
* This is the function called by main() above to perform all the decoding.
* It instantiates a decoder object and configures it with the input,
* output, and error callback functions above. A single call to
* mad_decoder_run() continues until a callback function returns
* MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and
* signal an error).
*/
static
int decode( Win32_Data * data )
{
??? //struct buffer buffer;
??? struct mad_decoder decoder;
??? int result;
??? ///* initialize our private message structure */
??? //buffer.start = start;
??? //buffer.length = length;
??? ///* configure input, output, and error functions */
??? mad_decoder_init(&decoder, data,
??? ??? ??? ??? ??? input, 0 /* header */, 0 /* filter */, output,
??? ??? ??? ??? ??? error, 0 /* message */);
??? ///* start decoding */
??? //* - 此函數(shù)是同步函數(shù),在“input”函數(shù)返回MAD_FLOW_STOP后才完成。
??? //* - 出錯(cuò)在error函數(shù)中定義行為。
??? result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
??? ///* release the decoder */
??? mad_decoder_finish(&decoder);
??? return result;
}
/*******************************************************************/
int main(int argc, char *argv [] );
int main(int argc, char *argv [] )
{
??? Win32_Data audio_data;
??? audio_data.buffer = new float[ WIN32_AUDIO_BUFF_LEN ] ;
??? audio_data.bufferMad = new unsigned char[ WIN32_BUFF_MAD_LEN ];
??? audio_data.current = 0;
??? PaStreamParameters inputParameters, outputParameters;
??? PaStream *stream = NULL;
??? PaError err;
??? char *sampleBlock;
??? int i;
??? int numBytes;
??? printf("patest_read_write_wire.c\n"); fflush(stdout);
??? //numBytes = FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ;
??? //sampleBlock = (char *) malloc( numBytes );
??? //if( sampleBlock == NULL )
??? //{
??? //??? printf("Could not allocate record array.\n");
??? //??? exit(1);
??? //}
??? audio_data.file = fopen ( argv[1] , "rb" );
??? if (audio_data.file == NULL)
??? {
??? ??? fputs ("File error",stderr);
??? ??? exit (1);
??? }
??? printf( "-- Start Decode %s\n" , argv[1] );
??? decode( &audio_data );
??? audio_data.bufferlen = audio_data.current;
??? audio_data.current = 0;
??? fclose( audio_data.file );
??? printf( "-- End Decode\n" );
??? printf( "-------------------------------\n" );
??? printf( "Output samplerate %d\n", audio_data.samplerate );
??? printf( "Output channels %d\n", audio_data.channels );
??? err = Pa_Initialize();
??? if( err != paNoError ) goto error;
??? //printf( "-------------------------------\n" );
??? //printf( "Output samplerate %d\n", audio_data.sfinfo.samplerate );
??? //printf( "Output frames %d\n", audio_data.sfinfo.frames );
??? //printf( "Output channels %d\n", audio_data.sfinfo.channels );
??? //printf( "seekable %d\n ", audio_data.sfinfo.seekable );
??? //printf( "format is %d\n ", audio_data.sfinfo.format );
??? //printf( "Sections is %d\n ", audio_data.sfinfo.sections );
??? //printf( "Read buffer len %d\n" , audio_data.bufferlen );
??? //printf( "-------------------------------\n" );
??? //inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
??? //printf( "Input device # %d.\n", inputParameters.device );
??? //printf( "Input LL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency );
??? //printf( "Input HL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency );
??? //inputParameters.channelCount = audio_data.sfinfo.channels;//NUM_CHANNELS;
??? //inputParameters.sampleFormat = PA_SAMPLE_TYPE;
??? //inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ;
??? //inputParameters.hostApiSpecificStreamInfo = NULL;
??? outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
??? printf( "Output device # %d.\n", outputParameters.device );
??? printf( "Output LL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency );
??? printf( "Output HL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency );
??? outputParameters.channelCount = audio_data.channels;//NUM_CHANNELS;
??? outputParameters.sampleFormat = PA_SAMPLE_TYPE;
??? outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
??? outputParameters.hostApiSpecificStreamInfo = NULL;
??? /* -- setup -- */
??? err = Pa_OpenStream(
??? ??? &stream,
??? ??? NULL,//&inputParameters,
??? ??? &outputParameters,
??? ??? SAMPLE_RATE,
??? ??? FRAMES_PER_BUFFER,
??? ??? paClipOff,????? /* we won't output out of range samples so don't bother clipping them */
??? ??? NULL, /* no callback, use blocking API */
??? ??? NULL ); /* no callback, so no callback userData */
??? if( err != paNoError ) goto error;
??? //err = Pa_StartStream( stream );
??? //if( err != paNoError ) goto error;
??? //printf("Wire on. Will run one minute.\n"); fflush(stdout);
??? //for( i=0; i<(60*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i )
??? //{
??? //??? err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER );
??? //??? if( err ) goto xrun;
??? //??? err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER );
??? //??? if( err ) goto xrun;
??? //}
??? //err = Pa_StopStream( stream );
??? //if( err != paNoError ) goto error;
??? //CLEAR( sampleBlock );
??? err = Pa_StartStream( stream );
??? if( err != paNoError ) goto error;
??? printf("Wire on. Interrupt to stop.\n"); fflush(stdout);
??? while( 1 )
??? {
??? ??? err = Pa_WriteStream( stream, audio_data.buffer + audio_data.current/*sampleBlock*/, FRAMES_PER_BUFFER );
??? ??? audio_data.current = audio_data.current + FRAMES_PER_BUFFER * NUM_CHANNELS /* SAMPLE_SIZE */;
??? ??? //if( audio_data.current + FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE > audio_data.bufferlen ) break;
??? ??? printf( "%d\n", audio_data.current);
??? ??? if( err ) goto xrun;
??? ??? //err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER );
??? ??? //if( err ) goto xrun;
??? }
??? err = Pa_StopStream( stream );
??? if( err != paNoError ) goto error;
??? Pa_CloseStream( stream );
??? free( sampleBlock );
??? Pa_Terminate();
??? return 0;
xrun:
??? if( stream ) {
??? ??? Pa_AbortStream( stream );
??? ??? Pa_CloseStream( stream );
??? }
??? free( sampleBlock );
??? Pa_Terminate();
??? if( err & paInputOverflow )
??? ??? fprintf( stderr, "Input Overflow.\n" );
??? if( err & paOutputUnderflow )
??? ??? fprintf( stderr, "Output Underflow.\n" );
??? delete [] audio_data.buffer;
??? delete [] audio_data.bufferMad;
??? return -2;
error:
??? if( stream ) {
??? ??? Pa_AbortStream( stream );
??? ??? Pa_CloseStream( stream );
??? }
??? free( sampleBlock );
??? Pa_Terminate();
??? fprintf( stderr, "An error occured while using the portaudio stream\n" );
??? fprintf( stderr, "Error number: %d\n", err );
??? fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
??? delete [] audio_data.buffer;
??? delete [] audio_data.bufferMad;
??? return -1;
}
三、某此播放mp3文件 截圖 -- 留念


/* Create by zyzx
* Created 2008-08-09
* Modified 2008-08-09
*/
一、準(zhǔn)備
?????? 1、依賴庫PortAudio(http://www.portaudio.com/)
???????????? Win32平臺(tái)編譯見《Win32環(huán)境PortAudio庫編譯簡介:音頻播放》
?????? 2、依賴庫libMAD (http://www.underbit.com/products/mad/)
???????????? 簡介:開源跨平臺(tái)的mpeg-1,mpeg-2,mpeg-2.5,MP3解碼C庫。
???????????? 編譯環(huán)境 Win32 + VS
???????????? 下載libMAD 打開 ..\msvc++\LibMad.sln 可以用VS直接編譯。
二、編碼試驗(yàn)
??????? 如上一篇《簡單音頻播放:音頻播放核心實(shí)現(xiàn)》的代碼實(shí)現(xiàn),不同的是LibMad 提供給我們的解碼方式稍微有些區(qū)別。
??????? 如下源碼參照 PortAudio庫中示例patest_read_write_wire.c 和 LibMad庫中示例minimad.c文件進(jìn)行的修改,還有Audacity中的部分實(shí)現(xiàn)。。所以還有很多地方懶得去理會(huì),代碼難看點(diǎn)。。
??????? 需要注意的地方:
??????? 基本上同上一篇。
??????? 1)PCM格式,分左右聲道2個(gè)緩存區(qū)域
??????? 2)PortAudio接受一個(gè)緩存區(qū)域,左右聲道并列方式組織。
??????? 3)當(dāng)然如果要讓你的音頻播放模塊能夠支持更多種格式,可要做一番設(shè)計(jì)了。。要做到可以替換編解碼模塊,驅(qū)動(dòng)聲卡模塊,跨平臺(tái),移植ARM那些系統(tǒng),還是不容易的。。
如下是全部的源碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "portaudio.h"
#include <sys/types.h>
#include "mad.h"
#include "windows.h"
/* #define SAMPLE_RATE (17932) // Test failure to open with this value. */
#define SAMPLE_RATE (44100)
#define FRAMES_PER_BUFFER ( 64 * 1024 )
#define NUM_CHANNELS??? (2)
/* #define DITHER_FLAG???? (paDitherOff) */
#define DITHER_FLAG???? (0) /**/
/* Select sample format. */
#if 1
#define PA_SAMPLE_TYPE paFloat32
#define SAMPLE_SIZE (4)
#define SAMPLE_SILENCE (0.0f)
#define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
#define PRINTF_S_FORMAT "%.8f"
#elif 0
#define PA_SAMPLE_TYPE paInt16
#define SAMPLE_SIZE (2)
#define SAMPLE_SILENCE (0)
#define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
#define PRINTF_S_FORMAT "%d"
#elif 0
#define PA_SAMPLE_TYPE paInt24
#define SAMPLE_SIZE (3)
#define SAMPLE_SILENCE (0)
#define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
#define PRINTF_S_FORMAT "%d"
#elif 0
#define PA_SAMPLE_TYPE paInt8
#define SAMPLE_SIZE (1)
#define SAMPLE_SILENCE (0)
#define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
#define PRINTF_S_FORMAT "%d"
#else
#define PA_SAMPLE_TYPE paFloat32//paUInt8
#define SAMPLE_SIZE ( sizeof(float) )
#define SAMPLE_SILENCE (128)
#define CLEAR( a ) { \
??? int i; \
??? for( i=0; i<FRAMES_PER_BUFFER*NUM_CHANNELS; i++ ) \
??? ((unsigned char *)a)[i] = (SAMPLE_SILENCE); \
}
#define PRINTF_S_FORMAT "%d"
#endif
#define WIN32_AUDIO_BUFF_LEN??? 32 * 1024 * 1024
#define WIN32_BUFF_MAD_LEN??? ??? FRAMES_PER_BUFFER
typedef struct
{
??? float*??? ??? buffer;?????????????????????????????? //* - 解碼后的數(shù)據(jù)存儲(chǔ)區(qū)域
??? long??? ??? current, bufferlen ;
??? unsigned char*??? bufferMad;?????????? //* - 由于LibMad是一段一段讀寫,這里是緩沖區(qū)域
??? long??? bfMadLen;
??? unsigned int samplerate;??? ??? /* sampling frequency (Hz) */
??? unsigned short channels;??? ??? /* number of channels */
??? FILE* file;
} Win32_Data ;
struct MadBuffer {
??? unsigned char const *start;
??? unsigned long length;
};
static
enum mad_flow input(void *data,
struct mad_stream *stream)
{
??? Win32_Data *buffer = (Win32_Data*)data;
??? //if (!buffer->length)
??? //??? return MAD_FLOW_STOP;
??? //mad_stream_buffer(stream, buffer->start, buffer->length);
??? //buffer->length = 0;
??? if( feof( buffer->file ) ) {
??? ??? return MAD_FLOW_STOP;
??? }
??? //* - 這段摘自Audacity(http://audacity.sourceforge.net/)
??? //* - 由于mp3編碼方式,可能某次讀取的數(shù)據(jù)并不是完整的,我們只取完整的 frame段,
??? //* - 將剩余的部分留給下段。
??? unsigned int unconsumedBytes;
??? if(stream->next_frame) {
??? ??? unconsumedBytes = buffer->bufferMad + WIN32_BUFF_MAD_LEN - stream->next_frame;
??? ??? memmove(buffer->bufferMad, stream->next_frame, unconsumedBytes);
??? }
??? else
??? ??? unconsumedBytes = 0;
??? off_t read = fread(buffer->bufferMad + unconsumedBytes, sizeof( unsigned char ), WIN32_BUFF_MAD_LEN - unconsumedBytes, buffer->file);
??? mad_stream_buffer(stream, buffer->bufferMad, read + unconsumedBytes);
??? return MAD_FLOW_CONTINUE;
}
/*
* The following utility routine performs simple rounding, clipping, and
* scaling of MAD's high-resolution samples down to 16 bits. It does not
* perform any dithering or noise shaping, which would be recommended to
* obtain any exceptional audio quality. It is therefore not recommended to
* use this routine if high-quality output is desired.
*/
static inline
float scale(mad_fixed_t sample)
{
??? /* round */
??? //sample += (1L << (MAD_F_FRACBITS - 16));
??? ///* clip */
??? //if (sample >= MAD_F_ONE)
??? //??? sample = MAD_F_ONE - 1;
??? //else if (sample < -MAD_F_ONE)
??? //??? sample = -MAD_F_ONE;
??? ///* quantize */
??? //return sample >> (MAD_F_FRACBITS + 1 - 16);
??? //* 將libMad庫內(nèi)置的采樣點(diǎn)格式轉(zhuǎn)換為 32位float類型
??? return (float) (sample / (float) (1L << MAD_F_FRACBITS));
}
/*
* This is the output callback function. It is called after each frame of
* MPEG audio data has been completely decoded. The purpose of this callback
* is to output (or play) the decoded PCM audio.
*/
static
enum mad_flow output(void *data,
struct mad_header const *header,
struct mad_pcm *pcm)
{
??? unsigned int nsamples;
??? mad_fixed_t const *left_ch, *right_ch;
??? Win32_Data* buffer = ( Win32_Data* ) data;
??? ///* pcm->samplerate contains the sampling frequency */
??? buffer->channels = pcm->channels;
??? buffer->samplerate = pcm->samplerate;
??? nsamples = pcm->length;
??? left_ch?? = pcm->samples[0];
??? right_ch = pcm->samples[1];
??? while (nsamples--) {
??? ??? float sample;
??? ??? /* output sample(s) in 16-bit signed little-endian PCM */
??????? //* - PCM格式 的數(shù)據(jù)是分布在2個(gè)緩存區(qū)域中分左右聲道,而PortAudio庫是只接受一個(gè)區(qū)域
??????? //* - 左右聲道數(shù)據(jù)相鄰,所以轉(zhuǎn)換下。
??? ??? if ( buffer->channels == 2) {
??? ??? ??? sample = scale(*left_ch++);
??? ??? ??? buffer->buffer[ buffer->current++ ] = sample;
??? ??? ??? sample = scale(*right_ch++);
??? ??? ??? buffer->buffer[ buffer->current++ ] = sample;
??? ??? }
??? }
??? return MAD_FLOW_CONTINUE;
}
/*
* This is the error callback function. It is called whenever a decoding
* error occurs. The error is indicated by stream->error; the list of
* possible MAD_ERROR_* errors can be found in the mad.h (or stream.h)
* header file.
*/
static
enum mad_flow error(void *data,
struct mad_stream *stream,
struct mad_frame *frame)
{
??? //struct buffer *buffer = data;
??? //fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n",
??? //??? stream->error, mad_stream_errorstr(stream),
??? //??? stream->this_frame - buffer->start);
??? ///* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */
??? return MAD_FLOW_CONTINUE;
}
/*
* This is the function called by main() above to perform all the decoding.
* It instantiates a decoder object and configures it with the input,
* output, and error callback functions above. A single call to
* mad_decoder_run() continues until a callback function returns
* MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and
* signal an error).
*/
static
int decode( Win32_Data * data )
{
??? //struct buffer buffer;
??? struct mad_decoder decoder;
??? int result;
??? ///* initialize our private message structure */
??? //buffer.start = start;
??? //buffer.length = length;
??? ///* configure input, output, and error functions */
??? mad_decoder_init(&decoder, data,
??? ??? ??? ??? ??? input, 0 /* header */, 0 /* filter */, output,
??? ??? ??? ??? ??? error, 0 /* message */);
??? ///* start decoding */
??? //* - 此函數(shù)是同步函數(shù),在“input”函數(shù)返回MAD_FLOW_STOP后才完成。
??? //* - 出錯(cuò)在error函數(shù)中定義行為。
??? result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
??? ///* release the decoder */
??? mad_decoder_finish(&decoder);
??? return result;
}
/*******************************************************************/
int main(int argc, char *argv [] );
int main(int argc, char *argv [] )
{
??? Win32_Data audio_data;
??? audio_data.buffer = new float[ WIN32_AUDIO_BUFF_LEN ] ;
??? audio_data.bufferMad = new unsigned char[ WIN32_BUFF_MAD_LEN ];
??? audio_data.current = 0;
??? PaStreamParameters inputParameters, outputParameters;
??? PaStream *stream = NULL;
??? PaError err;
??? char *sampleBlock;
??? int i;
??? int numBytes;
??? printf("patest_read_write_wire.c\n"); fflush(stdout);
??? //numBytes = FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ;
??? //sampleBlock = (char *) malloc( numBytes );
??? //if( sampleBlock == NULL )
??? //{
??? //??? printf("Could not allocate record array.\n");
??? //??? exit(1);
??? //}
??? audio_data.file = fopen ( argv[1] , "rb" );
??? if (audio_data.file == NULL)
??? {
??? ??? fputs ("File error",stderr);
??? ??? exit (1);
??? }
??? printf( "-- Start Decode %s\n" , argv[1] );
??? decode( &audio_data );
??? audio_data.bufferlen = audio_data.current;
??? audio_data.current = 0;
??? fclose( audio_data.file );
??? printf( "-- End Decode\n" );
??? printf( "-------------------------------\n" );
??? printf( "Output samplerate %d\n", audio_data.samplerate );
??? printf( "Output channels %d\n", audio_data.channels );
??? err = Pa_Initialize();
??? if( err != paNoError ) goto error;
??? //printf( "-------------------------------\n" );
??? //printf( "Output samplerate %d\n", audio_data.sfinfo.samplerate );
??? //printf( "Output frames %d\n", audio_data.sfinfo.frames );
??? //printf( "Output channels %d\n", audio_data.sfinfo.channels );
??? //printf( "seekable %d\n ", audio_data.sfinfo.seekable );
??? //printf( "format is %d\n ", audio_data.sfinfo.format );
??? //printf( "Sections is %d\n ", audio_data.sfinfo.sections );
??? //printf( "Read buffer len %d\n" , audio_data.bufferlen );
??? //printf( "-------------------------------\n" );
??? //inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
??? //printf( "Input device # %d.\n", inputParameters.device );
??? //printf( "Input LL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency );
??? //printf( "Input HL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency );
??? //inputParameters.channelCount = audio_data.sfinfo.channels;//NUM_CHANNELS;
??? //inputParameters.sampleFormat = PA_SAMPLE_TYPE;
??? //inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ;
??? //inputParameters.hostApiSpecificStreamInfo = NULL;
??? outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
??? printf( "Output device # %d.\n", outputParameters.device );
??? printf( "Output LL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency );
??? printf( "Output HL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency );
??? outputParameters.channelCount = audio_data.channels;//NUM_CHANNELS;
??? outputParameters.sampleFormat = PA_SAMPLE_TYPE;
??? outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
??? outputParameters.hostApiSpecificStreamInfo = NULL;
??? /* -- setup -- */
??? err = Pa_OpenStream(
??? ??? &stream,
??? ??? NULL,//&inputParameters,
??? ??? &outputParameters,
??? ??? SAMPLE_RATE,
??? ??? FRAMES_PER_BUFFER,
??? ??? paClipOff,????? /* we won't output out of range samples so don't bother clipping them */
??? ??? NULL, /* no callback, use blocking API */
??? ??? NULL ); /* no callback, so no callback userData */
??? if( err != paNoError ) goto error;
??? //err = Pa_StartStream( stream );
??? //if( err != paNoError ) goto error;
??? //printf("Wire on. Will run one minute.\n"); fflush(stdout);
??? //for( i=0; i<(60*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i )
??? //{
??? //??? err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER );
??? //??? if( err ) goto xrun;
??? //??? err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER );
??? //??? if( err ) goto xrun;
??? //}
??? //err = Pa_StopStream( stream );
??? //if( err != paNoError ) goto error;
??? //CLEAR( sampleBlock );
??? err = Pa_StartStream( stream );
??? if( err != paNoError ) goto error;
??? printf("Wire on. Interrupt to stop.\n"); fflush(stdout);
??? while( 1 )
??? {
??? ??? err = Pa_WriteStream( stream, audio_data.buffer + audio_data.current/*sampleBlock*/, FRAMES_PER_BUFFER );
??? ??? audio_data.current = audio_data.current + FRAMES_PER_BUFFER * NUM_CHANNELS /* SAMPLE_SIZE */;
??? ??? //if( audio_data.current + FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE > audio_data.bufferlen ) break;
??? ??? printf( "%d\n", audio_data.current);
??? ??? if( err ) goto xrun;
??? ??? //err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER );
??? ??? //if( err ) goto xrun;
??? }
??? err = Pa_StopStream( stream );
??? if( err != paNoError ) goto error;
??? Pa_CloseStream( stream );
??? free( sampleBlock );
??? Pa_Terminate();
??? return 0;
xrun:
??? if( stream ) {
??? ??? Pa_AbortStream( stream );
??? ??? Pa_CloseStream( stream );
??? }
??? free( sampleBlock );
??? Pa_Terminate();
??? if( err & paInputOverflow )
??? ??? fprintf( stderr, "Input Overflow.\n" );
??? if( err & paOutputUnderflow )
??? ??? fprintf( stderr, "Output Underflow.\n" );
??? delete [] audio_data.buffer;
??? delete [] audio_data.bufferMad;
??? return -2;
error:
??? if( stream ) {
??? ??? Pa_AbortStream( stream );
??? ??? Pa_CloseStream( stream );
??? }
??? free( sampleBlock );
??? Pa_Terminate();
??? fprintf( stderr, "An error occured while using the portaudio stream\n" );
??? fprintf( stderr, "Error number: %d\n", err );
??? fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
??? delete [] audio_data.buffer;
??? delete [] audio_data.bufferMad;
??? return -1;
}
三、某此播放mp3文件 截圖 -- 留念

posted on 2009-04-27 17:19 zyzx 閱讀(1912) 評論(0) 編輯 收藏 引用 所屬分類: OpenSource開源