• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            zyzx的小窩

            C/C++,GUI,個人移動存儲,zyzx_lsl@163.com

             

            簡單mp3播放器:音頻播放核心

            tag:C,mp3解碼,libMAD,PortAudio

            /* Create by zyzx
            * Created 2008-08-09
            * Modified 2008-08-09
            */

            一、準備
            ?????? 1、依賴庫PortAudio(http://www.portaudio.com/
            ???????????? Win32平臺編譯見《Win32環境PortAudio庫編譯簡介:音頻播放

            ?????? 2、依賴庫libMAD (http://www.underbit.com/products/mad/)
            ???????????? 簡介:開源跨平臺的mpeg-1,mpeg-2,mpeg-2.5,MP3解碼C庫。
            ???????????? 編譯環境 Win32 + VS
            ???????????? 下載libMAD 打開 ..\msvc++\LibMad.sln 可以用VS直接編譯。

            二、編碼試驗
            ??????? 如上一篇《簡單音頻播放:音頻播放核心實現》的代碼實現,不同的是LibMad 提供給我們的解碼方式稍微有些區別。

            ??????? 如下源碼參照 PortAudio庫中示例patest_read_write_wire.c 和 LibMad庫中示例minimad.c文件進行的修改,還有Audacity中的部分實現。。所以還有很多地方懶得去理會,代碼難看點。。

            ??????? 需要注意的地方:
            ??????? 基本上同上一篇。
            ??????? 1)PCM格式,分左右聲道2個緩存區域
            ??????? 2)PortAudio接受一個緩存區域,左右聲道并列方式組織。

            ??????? 3)當然如果要讓你的音頻播放模塊能夠支持更多種格式,可要做一番設計了。。要做到可以替換編解碼模塊,驅動聲卡模塊,跨平臺,移植ARM那些系統,還是不容易的。。


            如下是全部的源碼:

            #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;?????????????????????????????? //* - 解碼后的數據存儲區域
            ??? long??? ??? current, bufferlen ;

            ??? unsigned char*??? bufferMad;?????????? //* - 由于LibMad是一段一段讀寫,這里是緩沖區域
            ??? 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編碼方式,可能某次讀取的數據并不是完整的,我們只取完整的 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庫內置的采樣點格式轉換為 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格式 的數據是分布在2個緩存區域中分左右聲道,而PortAudio庫是只接受一個區域
            ??????? //* - 左右聲道數據相鄰,所以轉換下。
            ??? ??? 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 */

            ??? //* - 此函數是同步函數,在“input”函數返回MAD_FLOW_STOP后才完成。
            ??? //* - 出錯在error函數中定義行為。
            ??? 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文件 截圖 -- 留念

            TestMadMp3.png

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

            導航

            統計

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            常用鏈接

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            欧美综合天天夜夜久久| 香港aa三级久久三级| 国产A级毛片久久久精品毛片| 99久久免费国产精品特黄| 久久综合给合久久狠狠狠97色| 久久久精品午夜免费不卡| 欧美一级久久久久久久大| 国产婷婷成人久久Av免费高清| 青草久久久国产线免观| 97久久久精品综合88久久| 亚洲人成无码久久电影网站| 久久婷婷综合中文字幕| 精品国产日韩久久亚洲| 国产精品亚洲美女久久久| 婷婷伊人久久大香线蕉AV | 精品精品国产自在久久高清| 久久精品国产精品亚洲艾草网美妙| 日产精品久久久久久久| 伊人色综合九久久天天蜜桃 | 久久综合亚洲鲁鲁五月天| 久久青青草原国产精品免费 | 亚洲人成电影网站久久| 99久久精品国产一区二区| 久久久久久夜精品精品免费啦| 伊色综合久久之综合久久| 久久久久亚洲AV无码专区桃色| 久久97精品久久久久久久不卡| 亚洲中文字幕无码久久2017| 亚洲欧美一级久久精品| 欧洲性大片xxxxx久久久| 欧美国产成人久久精品| 久久久精品视频免费观看| 99久久99久久精品国产| 99久久精品无码一区二区毛片| 国产精品9999久久久久| 国产一区二区三区久久精品| 国产精品无码久久综合| 久久国产精品久久| 国产国产成人久久精品| 久久成人18免费网站| 日韩久久无码免费毛片软件|