1. 程式人生 > >SDL2.0學習筆記6--用SDL播放音訊wave檔案

SDL2.0學習筆記6--用SDL播放音訊wave檔案

#include "SDL.h"

struct {
    Uint8   *sound;     // pointer to wave data
    Uint32  soundlen;   // length of wave data
    int     soundpos;   // current play position
}wave;

int done;

static void quit(int rc)
{
    SDL_Quit();
    exit(rc);
}

void SDLCALL fill_audio(void *unused, Uint8 *stream, int len)
{
    Uint8   *waveptr;
    int     waveleft;
    int     copylen;

    SDL_memset(stream, 0, len);

    if (wave.soundpos == wave.soundlen)
    {
        done = 1;
        return;
    }

    waveptr  = wave.sound + wave.soundpos;
    waveleft = wave.soundlen - wave.soundpos;

    waveleft <= len ? (copylen = waveleft) : (copylen = len);

    SDL_memcpy(stream, waveptr, copylen);
    wave.soundpos += copylen;

    SDL_Log("len: %d, copylen:%d\n", len, copylen);
}

/*
    SDL播放音訊wave檔案測試
*/
int audio_test()
{
    SDL_AudioSpec spec;
    const char * audio_file = "sample.wav";

    done = 0;

    // 1. init
    SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);

    if (SDL_Init(SDL_INIT_AUDIO) < 0)
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL:%s\n", SDL_GetError());
        return (1);
    }

    // 2. open audio wave file
    if (SDL_LoadWAV(audio_file, &spec, &wave.sound, &wave.soundlen) == NULL)
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", audio_file, SDL_GetError());
        quit(1);
    }
    spec.callback = fill_audio;

    // 3. open audio
    if (SDL_OpenAudio(&spec, NULL) < 0)
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open audio: %s\n", SDL_GetError());
        SDL_FreeWAV(wave.sound);
        quit(2);
    }

    SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());

    // 4. play
    SDL_PauseAudio(0);

    /*
        5. fill audio data, it's be done by fill_audio
    */

    // 6. waiting for play end
    while (0 == done)
    {
        SDL_Delay(1);
    }

    // 7. close
    SDL_CloseAudio();
    SDL_FreeWAV(wave.sound);
    SDL_Quit();

    return 0;
}

以上程式碼參考自SDL的test資料夾下的loopwave.c函式。

由上,用SDL播放音訊wave檔案包含如下流程:

1、 呼叫SDL_Init(SDL_INIT_AUDIO)初始化音訊子系統;

2、 呼叫SDL_LoadWAW()開啟音訊wave檔案,獲取對應的spec、波形資料及波形資料長度等資訊;

3、 呼叫SDL_OpenAudio()開啟音訊裝置(在這之前還需要設定spec的callback成員),這函式實際上是啟動了SDL_RunAudio執行緒,用於實際的音訊播放;

4、 呼叫SDL_PauseAudio(0)播放音訊;

5、 呼叫spec.callback()函式,填充音訊資料(這一步由SDL_RunAudio執行緒完成);

6、 待播放完成後,關閉音訊音訊裝置(SDL_CloseAudio()),釋放波形資料buffer(SDL_FreeWAV()),然後退出。