• <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,個(gè)人移動(dòng)存儲(chǔ),zyzx_lsl@163.com

             

            簡(jiǎn)單音頻播放:音頻播放核心實(shí)現(xiàn)

            tag:C,音頻播放,libsndfile,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庫編譯簡(jiǎn)介:音頻播放

            ?????? 2、依賴庫libsndfile (http://www.mega-nerd.com/libsndfile/
            ???????????? 簡(jiǎn)介:是一個(gè)開源跨平臺(tái)C庫,用于解碼一系列的音頻文件格式如WAV,AIFF,SF等等。初期支持Mp3格式的,后來由于種種原因取消了對(duì)Mp3格式的支持。
            ???????????? 編譯環(huán)境:MinGW+MSYSMinGW+MSYS的C\C++編程環(huán)境安裝與升級(jí)
            ???????????? 1)從libsndfile上下載libsndfile-1.0.17.tar.gz(當(dāng)前最高版本)
            ???????????? 2)將libsndfile-1.0.17.tar.gz復(fù)制到MinGW/Msys安裝目錄Msys/home目錄下
            ???????????? 3)打開Msys模擬環(huán)境
            ?????????????????? $ cd /home
            ?????????????????? $ tar jxf libsndfile-1.0.17.tar.gz && cd libsndfile-1.0.17
            ?????????????????? $ ./configure
            ?????????????????? $ make && make install
            ???????????? 4)如果懶點(diǎn),直接使用源碼包中發(fā)布的libsndfile-1.dll和sndfile.h文件得了。

            二、編碼試驗(yàn)
            ??????? 嘿,,經(jīng)過層層碰壁后,,小弟終于初窺了點(diǎn)門道,,成功的摸索出了一條小道。。不過不要緊,萬事開頭難,,接下來嗎。。距離自己的音頻播放器又近了一步。。

            ??????? 值得注意的地方:
            ??????? 如下源碼參照 PortAudio庫中示例patest_read_write_wire.c 和 libsndfile 庫中示例sndfile-play.c 文件進(jìn)行的修改。。所以還有很多地方懶得去理會(huì),代碼難看點(diǎn)。。
            ??????? 1)其中 while(1) { ......} 語句,可以提取到一個(gè)線程中去。此線程專門負(fù)責(zé)給聲卡喂數(shù)據(jù),使用雙緩存或三緩存,當(dāng)某個(gè)緩存塊數(shù)據(jù)全部喂到聲卡后,通知數(shù)據(jù)讀取線程開工了。
            ??????? 2)為了節(jié)省空間咱不能一下申請(qǐng)WIN32_AUDIO_BUFF_LEN這大的內(nèi)存區(qū)域,使用多線程來解決。添加數(shù)據(jù)讀取線程。。
            ??????? 3)為了可以播放,暫停,... 咱得提供一個(gè)GUI界面,所以就涉及到線程通訊了哦。。
            ??????? 4)為了保證跨平臺(tái)性,還得去找個(gè)跨平臺(tái)的線程庫啊。。Boost庫中包含線程相關(guān)的,就先學(xué)習(xí)ing...


            下面是源碼:(還要在vs里設(shè)置庫環(huán)境)
            #include <stdio.h>
            #include <stdlib.h>
            #include <string.h>
            #include "portaudio.h"

            #include "windows.h"
            #include "sndfile.h"

            #define SF_DLL??? ??? "libsndfile-1.dll"

            typedef int??? ??? ?? ?????? (*P_sf_command)(SNDFILE *sndfile, int command, void *data, int datasize);
            typedef SNDFILE*??? (*P_sf_open)(const char *path, int mode, SF_INFO *sfinfo);
            typedef sf_count_t???? (*P_sf_read_short)(SNDFILE *sndfile, short *ptr, sf_count_t items);
            typedef int??? ??? ??????? ?? (*P_sf_close)(SNDFILE *sndfile);
            typedef int??? ??? ????????? (*P_sf_perror)(SNDFILE *sndfile);
            typedef const char*?? (*P_sf_strerror)(SNDFILE *sndfile);
            typedef sf_count_t??? (*P_sf_read_float)(SNDFILE *sndfile, float *ptr, sf_count_t items);
            typedef sf_count_t??? (*P_sf_read_int)(SNDFILE *sndfile, int *ptr, sf_count_t items);

            #define sf_command( hInstan, p )??? ??? P_sf_command p = (P_sf_command)GetProcAddress( hInstan, "sf_command")
            #define sf_open( hInstan, p )??? ??? ??? P_sf_open p = (P_sf_open)GetProcAddress( hInstan, "sf_open" )
            #define sf_close( hInstan, p )??? ??? ??? P_sf_close p = (P_sf_close)GetProcAddress( hInstan, "sf_close" )
            #define sf_perror( hInstan, p )??? ??? ??? P_sf_perror p = (P_sf_perror)GetProcAddress( hInstan, "sf_perror" )
            #define sf_read_short( hInstan, p )??? ??? P_sf_read_short p = (P_sf_read_short)GetProcAddress( hInstan, "sf_read_short" )
            #define sf_read_int( hInstan, p )??? ??? P_sf_read_int p = (P_sf_read_int)GetProcAddress( hInstan, "sf_read_int" )
            #define sf_read_float( hInstan, p )??? ??? P_sf_read_float p = (P_sf_read_float)GetProcAddress( hInstan, "sf_read_float" )
            #define sf_strerror( hInstan, p )??? ??? P_sf_strerror p = (P_sf_strerror)GetProcAddress( hInstan, "sf_strerror" )

            //* - 整上面這些也是沒辦法啊,在VS里只有*.dll和頭文件,咱只有動(dòng)態(tài)加載了。

            //* - 保存動(dòng)態(tài)庫句柄
            HINSTANCE?? ghIns;??

            /* #define SAMPLE_RATE (17932) // Test failure to open with this value. */
            #define SAMPLE_RATE (44100)?????????????????????????????????????? //* - 采樣率
            #define FRAMES_PER_BUFFER ( 64 * 1024 )???????????????? //* - 緩存大小 - 向聲卡驅(qū)動(dòng)寫數(shù)據(jù)時(shí)候的
            #define NUM_CHANNELS??? (2)?????????????????????????????????????????? //* - 聲道數(shù)
            /* #define DITHER_FLAG???? (paDitherOff) */
            #define DITHER_FLAG???? (0) /**/

            /* Select sample format. */

            #define PA_SAMPLE_TYPE paFloat32???????????????????????????? //* - 采樣點(diǎn)占用大小32位的float型
            #define SAMPLE_SIZE (4)?????????????????????????????????????????????????? //* - 采樣點(diǎn)占用4字節(jié)
            #define SAMPLE_SILENCE (0.0f)
            #define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
            #define PRINTF_S_FORMAT "%.8f"

            #define WIN32_AUDIO_BUFF_LEN??? 32 * 1024 * 1024 //* - 音頻數(shù)據(jù)(解碼后)緩沖區(qū)域大小

            typedef struct
            {
            ??? float*??? ??? buffer;????????????????????? //* - 音頻數(shù)據(jù)(解碼后)緩沖區(qū)域

            ??? long??? ??? current, bufferlen ;??? //* - 當(dāng)前播放到達(dá)的數(shù)據(jù)點(diǎn),實(shí)際全部音頻數(shù)據(jù)長(zhǎng)度

            ??? SNDFILE ??? *sndfile ;???????????? //* - libsndfile 庫 基本 結(jié)構(gòu) -- 類似句柄或結(jié)構(gòu)體指針
            ??? SF_INFO ??? sfinfo ;??????????????? //* - libsndfile 庫 讀取的音頻基本信息(如采樣率,聲道,等等)

            ??? sf_count_t??? remaining ;???????? //* - 好像沒用到
            } Win32_Audio_Data ;


            /*******************************************************************/
            int main(int argc, char *argv [] );
            int main(int argc, char *argv [] )
            {
            ??? HINSTANCE?? hIns;
            ??? hIns = LoadLibrary( SF_DLL );????????? //* 加載 libsndfile-1.dll

            ??? Win32_Audio_Data audio_data;

            ??? audio_data.buffer = new float[ WIN32_AUDIO_BUFF_LEN ] ;
            ??? audio_data.current = 0;

            ??? ghIns = hIns;

            ??? PaStreamParameters inputParameters, outputParameters;
            ??? PaStream *stream = NULL;
            ??? PaError err;
            ??? int i;
            ??? int numBytes;


            ??? printf("patest_read_write_wire.c\n"); fflush(stdout);

            ??? err = Pa_Initialize();
            ??? if( err != paNoError ) goto error;

            ??? //* - 打開****.***音頻文件
            ??? sf_open( ghIns, Open );
            ??? if (! (audio_data.sndfile = Open (argv[1], SFM_READ, &(audio_data.sfinfo))))
            ??? {???
            ??? ??? sf_strerror( ghIns, Strerror );
            ??? ??? puts ( Strerror(NULL) ) ;

            ??? ??? goto error;
            ??? }

            ??? //* 以float格式讀取并解析音頻格式 長(zhǎng)度標(biāo)為WIN32_AUDIO_BUFF_LEN,基本上能全部讀取文件
            ??? sf_read_float( ghIns, ReadFloat );
            ??? audio_data.bufferlen += (long) ReadFloat (audio_data.sndfile, (float*)(audio_data.buffer ), WIN32_AUDIO_BUFF_LEN/*audio_data.sfinfo.frames */) ;


            ??? 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.sfinfo.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,???????????????????????????????????????? //* - 麥克風(fēng)
            ??? ??? &outputParameters,?????????????????????????????????????????????????? //* - 揚(yáng)聲器
            ??? ??? audio_data.sfinfo.samplerate,//SAMPLE_RATE,?? //* - 采樣率
            ??? ??? FRAMES_PER_BUFFER,??????????????????????????????????????? //* - 緩沖區(qū)
            ??? ??? 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 )
            ??? {
            ??????? //* - 此函數(shù)為同步函數(shù),它一直等待到buffer中的數(shù)據(jù)全部寫入聲卡驅(qū)動(dòng)才返回
            ??????? //* - 緩沖去長(zhǎng)度為FRAMES_PER_BUFFER,指的是一個(gè)聲道上的數(shù)據(jù)大小
            ??? ??? 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 ;

            ??? ??? //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;
            ??? FreeLibrary( ghIns );
            ??? return -2;

            error:
            ??? if( stream ) {
            ??? ??? Pa_AbortStream( stream );
            ??? ??? Pa_CloseStream( stream );
            ??? ??? FreeLibrary( ghIns );
            ??? }
            ??? 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;
            ??? FreeLibrary( ghIns );
            ??? return -1;
            }

            三、某次播放Wav文件 截圖 -- 紀(jì)念

            TestPortAudio.png

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

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            常用鏈接

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            久久国产精品一区| 日韩乱码人妻无码中文字幕久久| 无遮挡粉嫩小泬久久久久久久 | 狠狠精品久久久无码中文字幕| 亚洲国产婷婷香蕉久久久久久| 7777精品伊人久久久大香线蕉| 久久精品国产AV一区二区三区 | 日本精品久久久久影院日本| 中文字幕久久波多野结衣av| 久久精品视频免费| 久久精品国产亚洲AV影院| 精品久久一区二区三区| 欧美久久综合九色综合| 99久久久精品免费观看国产| 亚州日韩精品专区久久久| 久久九九青青国产精品| 国产aⅴ激情无码久久| 欧美午夜A∨大片久久| 久久91精品国产91久久小草| 国产精品久久久久蜜芽| 久久99精品久久久久久水蜜桃| 无遮挡粉嫩小泬久久久久久久| 三级韩国一区久久二区综合 | 久久精品国产亚洲av瑜伽| 色婷婷久久综合中文久久蜜桃av| 久久99精品久久久久久野外| 久久精品国产亚洲欧美| 精品无码久久久久国产| 97精品国产97久久久久久免费 | 伊人情人综合成人久久网小说 | 伊人久久精品线影院| 狠狠色丁香久久婷婷综合五月| 久久香综合精品久久伊人| 色婷婷久久久SWAG精品| 久久久久国产精品麻豆AR影院 | 久久精品无码一区二区app| 亚洲国产精品婷婷久久| 欧美久久综合性欧美| 爱做久久久久久| 国産精品久久久久久久| 久久久久久亚洲精品不卡|