Back to site
Since 2004, our University project has become the Internet's most widespread web hosting directory. Here we like to talk a lot about web servers, web development, networking and security services. It is, after all, our expertise. To make things better we've launched this science section with the free access to educational resources and important scientific material translated to different languages.

ПортАудио Туториjали



Ови туторјиали вас воде кроз примере коришћења ПортАудио да би направили звук. Ако не желите да почнете са врха надоле прегледом ПортАудио АПИ, погледајте ПортАудио АПИ Преглед.

Преузимање

Прва ствар коју морате да урадите је да преузмете ПортАудио изворни код било да је као тарбалл са веб сајта, или из Субверзионог Спремишта.

Компајлирање

Када сте преузели ПортАудио мораћете да га компајлирате, што наравно, зависи од вашег окружења:

  • Виндовс

  • Мац ОС Кс

  • ПОСИКС


    Многе платформе са ГЦЦ/учинити могу користити једноставан ./configure && да направе комбинације и једноставно користе настале библиотеке у свом коду.

    Програмирање са ПортАудио



    Испод су кораци за писање ПортАудио апликације:

    • Напишите функцију за повратни позив која ће бити позвана од ПортАудиа када је потребна обрада аудио сигнала.
    • Покрените ПА библиотеку и отворите проток за И/О аудио.
    • Покрените проток. Ваша повратни позив функција ће сада бити позвана у више наврата у позадини од стране ПА.
    • У вашем повратном позиву можете прочитати аудио податке из инпутБуффер и/или написати податке у оутпутБуффер.
    • Зауставите проток повраћајем 1 из вашег повратног позива, или позивањем стоп функције.
    • Затворите проток и избришите библиотеку.


    Поред ове "Повратни Позив" Архитектуре, В19 такође подржава "Блокирање И/О" модел који користи читање и писање позива који могу бити познати не-аудио програмерима. Имајте на уму да у овом тренутку, не сви АПИ подржавају ову функцију.

    У овом туторијалу ћемо показати како да користите Повратни Позив архитектуру да пустите једнакомерни талас. Већи део туторијала је преузет из датотеке paex_saw.c, која је део ПортАудио дистрибуције. Када завршите са овим упутством, бићете наоружани са основним знањем које је потребно да напишете аудио програм. Ако вам је потребно више узорака кода, погледајте у "примери" и "тестови" директоријуму ПортАудио дистрибуције. Други велики извор информација је portaudio.h Doxygen страна, која документује цео В19 АПИ. Такође погледајте страницу за савете о програмском ПортАудиу на ПортАудио Викију.

    Ако надограђујете В18, можда ћете желети да погледате Предлог Побољшања ПортАудиа, који описује разлике између В18 и В19 .



    Писање повратне функције



    Једном када стекнете основно разумевање о томе како да користите ПортАудио, можда ћете бити заинтересовани за Истраживање ПортАудиа.



    Да напишете програм користећи ПортАудио, морате укључити "портаудио.х" укључујући датотеку. Можда ћете желети да прочитате "портаудио.х", јер садржи комплетан опис ПортАудио функција и константи. Алтернативно, можете да претражујете [http://www.portaudio.com/docs/v19-doxydocs/portaudio_8h.html Доксиген страницу]



    #include "portaudio.h"



    Следећи задатак је да напишете свој "повратни позив" функцију. "Повратни позив" је функција која се зове по ПортАудио мотор кад год је заробљен аудио податак или када је потребно више података за аудио излаз.

    Пре него што почнете, важно је схватити да је повратни позив деликатно место. То је зато што неки системи изврше повратни позив у посебном току, или прекид управљача и то се ређе третира исто као и остатак кода. Поред тога, ако желите да ваш звук стигне до звучника на време, мораћете да се уверите да на који год код наиђете у повратном позиву ради брзо. Шта је безбедно или није сигурно ће се разликовати од платформе до платформе, али као по правилу, не радити ништа као што је додељивање или ослобађање меморије, читање или писање датотека, принтф (), или било шта друго што би могло да заузме неку неограничену количину времена или се ослањају на ОС или захтевају контекст прекидач. Ед: ово је и даље истина? : Такође не зову ПортАудио никакве функције у повратни позив, осим за Па_СтримТиме () и Па_ГетЦПУЛоад ().

    Ваша фунција повратни позив мора да врати инт и прихвати тачне параметре наведене у овом типдеф:


    typedef int PaStreamCallback( const void *input,
                                          void *output,
                                          unsigned long frameCount,
                                          const PaStreamCallbackTimeInfo* timeInfo,
                                          PaStreamCallbackFlags statusFlags,
                                          void *userData ) ;
    
    



    Овде је пример за фунцију повратни позив из тест фајла "патестс/патест.цав.ц". Он израчунава једноставан леви и десни једнакомерни сигнал и пише да га на излазни бафер. Приметити да у овом примеру, сигнали су од података типа плуте. Сигнали морају бити између -1.0 и +1.0. Такође можете да користите 16 битне целе бројеве или друге формате које су утврђени током инсталације, али плута су најлакши за рад. Можете донети показивач за вашу струтуру података преко ПортАудио који ће се појавити као корисникПодатка.


    typedef struct
    {
        float left_phase;
        float right_phase;
    }   
    paTestData;
    
    /* This routine will be called by the PortAudio engine when audio is needed.
    
     It may called at interrupt level on some machines so don't do anything
     that could mess up the system like calling malloc() or free().
    */ 
    static int patestCallback( const void *inputBuffer, void *outputBuffer,
                               unsigned long framesPerBuffer,
                               const PaStreamCallbackTimeInfo* timeInfo,
                               PaStreamCallbackFlags statusFlags,
                               void *userData )
    {
        /* Cast data passed through stream to our structure. */
    
        paTestData *data = (paTestData*)userData; 
        float *out = (float*)outputBuffer;
        unsigned int i;
        (void) inputBuffer; /* Prevent unused variable warning. */
    
        
        for( i=0; i<framesPerBuffer; i++ )
        {
            *out++ = data->left_phase;  /* left */
            *out++ = data->right_phase;  /* right */
            /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
            data->left_phase += 0.01f;
            /* When signal reaches top, drop back down. */
    
            if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
            /* higher pitch so we can distinguish left and right. */
            data->right_phase += 0.03f;
            if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
        }
        return 0;
    }
    
    



    Иницијализација ПортАудиa



    Пре доношења било каквих других позива на ПортАудиу, Ви 'морате' позватиПа_Иницијализират() .Ово ће покренути скенирање доступних уређаја који могу бити касније питани. Као и већина ПА функција, вратиће резултат типа паЕрор. Ако резултат није паНоуЕрор, онда је дошло до грешке.


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



    Можете добити текстуалну поруку која објашњава поруку о грешци доносећи га на Па_ГетЕрорТекст ( ерр ). На пример:


    printf(  "PortAudio error: %s\n", Pa_GetErrorText( err ) );
    



    Такође је важно, када сте завршили са ПортАудиом, окончати га: ерр = Па_Терминате();


    err = Pa_Terminate();
    
    if( err != paNoError )
       printf(  "PortAudio error: %s\n", Pa_GetErrorText( err ) );
    



    Отварање коришћењем подразумеваног тока



    Следећи корак је да отворите ток, који је сличан отварању датотеке. Можете да одредите да ли желите и аудио улаз и / или излаз, колико канала, формат података, основни рејт, итд. Отварањем '' дефаулт'' тока значи отварање подразумеваног улазног и излазног уређаја, који вас штеди од невоља добијања списка уређаја и бирајући једну из списка. (Видећемо како то урадити касније.)


    #define SAMPLE_RATE (44100)
    static paTestData data;
    
    .....
    
        PaStream *stream;
        PaError err;
    
        /* Open an audio I/O stream. */
    
        err = Pa_OpenDefaultStream( &stream,
                                    0,          /* no input channels */
                                    2,          /* stereo output */
                                    paFloat32,  /* 32 bit floating point output */
                                    SAMPLE_RATE,
                                    256,        /* frames per buffer, i.e. the number
    
                                                       of sample frames that PortAudio will
                                                       request from the callback. Many apps
                                                       may want to use
                                                       paFramesPerBufferUnspecified, which
                                                       tells PortAudio to pick the best,
                                                       possibly changing, buffer size.*/
    
                                    patestCallback, /* this is your callback function */
                                    &data ); /*This is a pointer that will be passed to
                                                       your callback*/
        if( err != paNoError ) goto error;
    
    



    Структура података и повратни позив су описани уПисање функције повратног позива

    Горњи пример отвара ток за писање, што је довољно за репродукцију. Такође је могуће да отворите ток за читање, да уради снимање, или оба читање и писање, за симултано снимање и репродукцију или чак реал-тиме обраде аудио сигнала. Ако планирате да урадите репродукцију и снимање у исто време, отворите само један ток са важећим улазним и излазним параметрима.

    Постоје нека упозорења која треба напоменути у вези са истовременим читањем / писањем:

    •Неке платформе могу само отворити читање / писање тока користећи исти уређај.

    •Иако могу да се отворе више токова, тешко их је синхронизовати

    •Неке платформе не подржавају отварање више токова на истом уређају

    •Коришћење вишеструких токова не могу бити добро тестирани, као и остале карактеристике.

    •У ПортАудиу библиотеци позиви морају бити направљени из истог тока или синхронизацијом од стране корисника.

    Покретање, заустављање и прекидање тока



    ПортАудио неће почети репродукцију звука док не започнете ток. После позивањаПа_СтартСтреам() ,ПортАудио ће започети позивање ваше функције повратног позива да обави аудио обраду.


        err = Pa_StartStream( stream );
        if( err != paNoError ) goto error;
    
    



    Можете да комуницирате са вашим рутинским повратним позивом кроз структуру података коју сте прошли на конкурсу, или преко глобалних променљивих, или користећи друге међупроцесе комуникационе технике, али имајте на уму да ваша функција повратног позива може бити позван за време прекида када се ваш процес у првом плану најмање очекује. Зато избегавајте дељења сложене структуре података који се лако оштете попут двоструких повезаних листи, и избегавајте коришћење брава, као што су мутекс јер то може изазвати блокирање ваше функције повратног позива и због тога спустите тон. Такве технике могу чак изазвати застој на неким платформама.

    ПортАудио ће наставити да позива ваш повратни позив и аудио процес све док не прекинете ток. Ово се може урадити на један од неколико начина, али, пре него што то урадимо, видећемо да неки од наших звукова бивају обрађени спавањем за неколико секунди. Ово је лако урадити са Па_Слеп (), која се користи од стране многих примера у патестс / директоријум за управо ову сврху. Имајте на уму да, из различитих разлога, не можете се ослонити на ову функцију за прецизно планирање, тако да се ток не може кандидовати за тачно исти временски период како сте очекивали, али је довољно добар за наш пример.


        /* Sleep for several seconds. */
        Pa_Sleep(NUM_SECONDS*1000);
    



    Сада морамо да зауставимо репродукцију. Постоји неколико начина да то урадите, од којих је најједноставнији да позоветеПа_СтопСтрим() :


        err = Pa_StopStream( stream );
        if( err != paNoError ) goto error;
    
    



    Па_СтопСтрим () је осмишљен тако да се уверите да су бафери које сте обрадили у вашем повратном позиву сви извршени, што може изазвати нека кашњења. Алтернативно, можете да позоветеПа_АбортСтри() . На неким платформама, уништавање тока је много брже и може да проузрокује неке податке обрађених од стране вашег повратног позива да не буду извршени.

    Други начин да се заустави ток је да се врати или паКомплит, или паАборт са вашег повратног позива. паКомплит осигурава да се изврши последњи бафер док паАборт зауставља ток што пре. Ако прекинете ток користећи ову технику, мораћете да позовете Па_СтопСтрим () пре почетка тока поново.

    Затварање тока и завршавање ПортАудиа



    Када сте завршили са током, требало би да га затворите да бисте ослободили ресурсе:


        err = Pa_CloseStream( stream );
        if( err != paNoError ) goto error;
    
    



    Већ смо поменули ово Иницијализацији ПортАудиа, али у случају да сте заборавили, будите сигурни да прекинете ПортАудио када завршите:


        err = Pa_Terminate( );
        if( err != paNoError ) goto error;
    



    Корисност функција



    Поред описаних функција на другом месту у овом упутству, ПортАудио пружа бројне комуналне функције које су корисне у разним околностима. Пожелећете да прочитате портаудио.х референцу, која документује цео В19 АПИ за више детаља, али ћемо покушати да покријемо основе овде.

    Верзија информације



    ПортАудио нуди две функције које одређују ПортАудио Верзију. Ово је најкорисније када користите ПортАудио као динамичка библиотека, али такође може бити корисно у неким другим приликама.


    int             Pa_GetVersion (void)
    const char *    Pa_GetVersionText (void)
    
    

    <

    Грешка текста


    ,br>ПортАудио вам дозвољава да добијете текст грешку из броја грешке .


    const char *    Pa_GetErrorText (PaError errorCode)
    



    Стање тока

    ПортАудиоТокови постоје у 3 стања: активан, заустављен , и заустављен повратни позив. Ако је ток у стању заустављеног повратног позива, мораћете да га заустави пре него што можете да га покренете поново. Ако је потребан упит стања на ПортАудио току, постоје две функције за то:


    PaError     Pa_IsStreamStopped (PaStream *stream)
    PaError     Pa_IsStreamActive (PaStream *stream)
    
    



    Ток информација



    Ако је потребно да преузмете информације о датом току, као што су кашњења, и информација основног рејта, постоје функције за то такође:


    const PaStreamInfo *    Pa_GetStreamInfo (PaStream *stream)
    

    <

    Ток време



    Ако је потребно да синхронизујете друге активности као што су приказ исправке или МИДИ излаз са ПортАудио повратни позив, морате да знате тренутно време у складу са истом временском базом коју користи ток повратног позива временских маркера.


    double  Pa_GetStreamCpuLoad (PaStream *stream)
    



    Употребa



    Да бисте утврдили колико се ЦПУ користи за повратни позив, користите следеће:


    double  Pa_GetStreamCpuLoad (PaStream *stream)
    



    Остале комуналне услуге



    Ове функције вам омогућавају да одреди величину узорка из његовог формата и спавање за дати временски период. Функцију спавање не треба користити за прецизно мерења времена или синхронизацију јер чини неколико гаранција о тачној дужини времена чекања. То је најкорисније за испитивање.


    PaError Pa_GetSampleSize (PaSampleFormat format)
    
    void    Pa_Sleep (long msec)
    



    Набрајање и претраживање ПортАудио уређаја



    Претраживање уређаја



    Често је у реду да користите подразумевани уређај као што смо претходно урадили у овом упутству, али постоје ситуације када ћете желети да експлицитно изаберете уређај са листе расположивих уређаја на систему. Да бисте видели радни пример овога, погледајте па_девс.ц у тестовима / директоријум на ПортАудио изворног кода. Да бисте то урадили, мораћете прво да покренете ПортАудио и упит за број уређаја:


    int     structVersion
    const char *    name
    
    PaHostApiIndex  hostApi
    int     maxInputChannels
    int     maxOutputChannels
    PaTime  defaultLowInputLatency
    PaTime  defaultLowOutputLatency
    PaTime  defaultHighInputLatency
    
    PaTime  defaultHighOutputLatency
    double  defaultSampleRate
    



    Ако желите да добијете информације о сваком уређају, једноставно петља пролази као што следи:


        const   PaDeviceInfo *deviceInfo;
    
        for( i=0; i<numDevices; i++ )
        {
            deviceInfo = Pa_GetDeviceInfo( i );
            ...
        }
    



  • Па_ДевицеИнфо структура садржи обиље информација као што је име уређаја, стандардна кашњења повезана са уређајима и још много тога. Структура има следећа поља:


    int     structVersion
    const char *    name
    
    PaHostApiIndex  hostApi
    int     maxInputChannels
    int     maxOutputChannels
    PaTime  defaultLowInputLatency
    PaTime  defaultLowOutputLatency
    PaTime  defaultHighInputLatency
    
    PaTime  defaultHighOutputLatency
    double  defaultSampleRate
    



    Можда ћете приметити да не можете одредити, само из ове информације, да ли је или није партикуларан основни рејт подржан. То је зато што неки уређаји подржавају опсеге основног рејта, други подржавају, списак основних рејтова, и још увек подржавају неке основне рејтове и број канала комбинација али не и друго. Да бисте дошли до овога, ПортАудио нуди функцију за тестирање одређеног уређаја са датим форматом:


        const PaStreamParameters *inputParameters;
        const PaStreamParameters *outputParameters;
        double desiredSampleRate;
        ...
        PaError err;
    
        err = Pa_IsFormatSupported( inputParameters, outputParameters, desiredSampleRate );
        if( err == paFormatIsSupported )
        {
           printf( "Hooray!\n");
        }
        else
    
        {
           printf("Too Bad.\n");
        }
    



    Попуњавање инпутПараметера и аутпутПараметера поља су приказана у тренутку. Када једном пронађете конфигурацију која вам се допада, или неку са којом желите да напредујете и покушате, да отворите ток попуњавањем у ПаСтримПараметарс структури, и позвати Па_ОпенСтрим:


        double srate = ... ;
        PaStream *stream;
        unsigned long framesPerBuffer = ... ; //could be paFramesPerBufferUnspecified, in which case PortAudio will do its best to manage it for you, but, on some platforms, the framesPerBuffer will change in each call to the callback
    
        PaStreamParameters outputParameters;
        PaStreamParameters inputParameters;
    
        bzero( &inputParameters, sizeof( inputParameters ) ); //not necessary if you are filling in all the fields
        inputParameters.channelCount = inChan;
        inputParameters.device = inDevNum;
        inputParameters.hostApiSpecificStreamInfo = NULL;
        inputParameters.sampleFormat = paFloat32;
        inputParameters.suggestedLatency = Pa_GetDeviceInfo(inDevNum)->defaultLowInputLatency ;
        inputParameters.hostApiSpecificStreamInfo = NULL; //See you specific host's API docs for info on using this field
    
    
        bzero( &outputParameters, sizeof( outputParameters ) ); //not necessary if you are filling in all the fields
        outputParameters.channelCount = outChan;
        outputParameters.device = outDevNum;
        outputParameters.hostApiSpecificStreamInfo = NULL;
        outputParameters.sampleFormat = paFloat32;
        outputParameters.suggestedLatency = Pa_GetDeviceInfo(outDevNum)->defaultLowOutputLatency ;
        outputParameters.hostApiSpecificStreamInfo = NULL; //See you specific host's API docs for info on using this field
    
        err = Pa_OpenStream(
                        &stream,
                        &inputParameters,
                        &outputParameters,
                        srate,
                        framesPerBuffer,
                        paNoFlag, //flags that can be used to define dither, clip settings and more
                        portAudioCallback, //your callback function
                        (void *)this ); //data to be passed to callback. In C++, it is frequently (void *)this
    
    



    Блокирање функције читања / писања



    ПортАудио В19 придодаје огроман напредак у односу на претходне верзије са функцијом званом Блокирање И / О. Иако то може имати мањи учинак да је метод повратни позив описан раније у овом упутству, блокирајући И / О је лакше разумети и, у неким случајевима, више компатибилан са системима трећих лица него за метод повратног позива. Већина људи који започињу аудио програмирање такође проналазе Блокирање И / О да лакше уче.

    Блокирање И / О ради на исти начин као и метод повратног позива, осим да се уместо пружања функције обезбеди (или троши) аудио податке, морате снадбевати податке за (или конзумирати податке) ПортАудио у редовним интервалима, обично унутар петље. Пример доле, изузети од патест_реад_врите_вире.ц, показује како да отворите подразумевани уређај, и доноси податке из свог улаза на свом излазу за одређени временски период. Имајте на уму да користимо подразумевану високу вредност кашњења да бисмо избегли вађење мреже од обичног читања и писања аудио податка са релативно ниским приоритетом тока, и где обично додатна тампонажа захтева да блокира И / О рад.

    Имајте на уму да нису све АПИ спроведене Блокирањем И / О у овом тренутку, тако да за максималну преносивост и перформансу, и даље ћете желите да користите повратни позив.


        /* -- initialize PortAudio -- */
    
        err = Pa_Initialize();
        if( err != paNoError ) goto error;
    
        /* -- setup input and output -- */
        inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
    
        inputParameters.channelCount = NUM_CHANNELS;
        inputParameters.sampleFormat = PA_SAMPLE_TYPE;
        inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ;
        inputParameters.hostApiSpecificStreamInfo = NULL;
    
        outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
        outputParameters.channelCount = NUM_CHANNELS;
        outputParameters.sampleFormat = PA_SAMPLE_TYPE;
        outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
        outputParameters.hostApiSpecificStreamInfo = NULL;
    
        /* -- setup stream -- */
    
        err = Pa_OpenStream(
                  &stream,
                  &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;
    
        /* -- start stream -- */
        err = Pa_StartStream( stream );
        if( err != paNoError ) goto error;
        printf("Wire on. Will run one minute.\n"); fflush(stdout);
    
        /* -- Here's the loop where we pass data from input to output -- */
    
        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;
        }
        /* -- Now we stop the stream -- */
    
        err = Pa_StopStream( stream );
        if( err != paNoError ) goto error;
    
        /* -- don't forget to cleanup! -- */
        err = Pa_CloseStream( stream );
        if( err != paNoError ) goto error;
    
        Pa_Terminate();
        return 0;
    
    



    Истраживање ПортАудиа

    Сада када имате добру представу о томе како функционише ПортАудио, можете да испробате примере програма. Пронаћи ћете их у примери / директоријум ПортАудио дистрибуције.

    На пример игра синусни талас, примери/паекс_сине.ц.

    На пример снимање и репродукцију звука, види примери/паекс_рекорд.ц .

    Такође Вам саветујемо да се испита извор за ПортАудио библиотекама. Уколико имате предлоге о начинима да их побољшамо, молимо Вас да нас обавестите. Ако желите да спроведете ПортАудио на новој платформи, молимо Вас да нас обавестите као и како можемо да координирамо људским напорима.



    Published (Last edited): 24-06-2012 , source: http://portaudio.com/docs/v19-doxydocs/tutorial_start.html