使用stb_vorbis和SDL2播放音频会切断

时间:2016-06-28 22:07:26

标签: c++ audio sdl-2 oggvorbis

无论我使用什么音频文件,它总是会切断大约四分之一。我有一种感觉,因为我正在将解码后的音频转换为Uint8*,但如果我不这样做,音频播放速度非常快,而且它仍然只播放大约一半的文件。此外,使用SDL_MixAudio代替SDL_memcpy会导致声音的一堆副本因某种原因相互影响。

Uint8* audio_pos;
Uint32 audio_len;

void audioCallback(void* userdata, Uint8* stream, int len) {
    if (audio_len == 0) return;
    len = (len > audio_len ? audio_len : len);
    SDL_memcpy(stream, audio_pos, len);
    audio_pos += len;
    audio_len -= len;
}

int main(int argc, char *argv[]) {
    ...
    short* decoded;
    int channels, rate, len;
    len = stb_vorbis_decode_filename(RealPath("music.ogg").c_str(), &channels, &rate, &decoded);

    SDL_AudioSpec spec;
    spec.freq = rate;
    spec.format = AUDIO_S16;
    spec.channels = channels;
    spec.samples = 2048;
    spec.callback = audioCallback;
    spec.userdata = NULL;

    audio_pos = (Uint8*)decoded;
    audio_len = len;

    if (SDL_OpenAudio(&spec, NULL) < 0) {
        std::cout << "failed to open audio device: " << SDL_GetError() << '\n';
        SDL_GL_DeleteContext(context);
        SDL_Quit();
        return -1;
    }

    SDL_PauseAudio(0);

    SDL_Event windowEvt;
    while (true) {
        if (audio_len == 0) break;
        if (SDL_PollEvent(&windowEvt)) {
            if (windowEvt.type == SDL_QUIT) break;
            if (windowEvt.type == SDL_KEYUP && windowEvt.key.keysym.sym == SDLK_ESCAPE) break;
        }
        SDL_GL_SwapWindow(window);
    }
    ...
}

1 个答案:

答案 0 :(得分:0)

stb_vorbis_decode_filename返回&#34;已解码的样本数,&#34;这与int16有关,并不包括渠道因素。 您正在寻找:

int32 length = stb_vorbis_decode_filename("thing.ogg", &channels, &rate, &decoded);
int32 audio_length = length * channels * (sizeof(int16) / sizeof(uint8));

对于声音重叠的SDL_MixAudio vs SDL_memcpy,您需要使用静音值明确清除流。例如,当您输入SDL音频回调时SDL_memset

void audioCallback(void* userdata, Uint8* stream, int len) 
{
    SDL_memset(stream, 0, len);// silence the stream
    if (audio_len == 0) return;
    len = (len > audio_len ? audio_len : len);
    SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);// this takes a volume argument
    audio_pos += len;
    audio_len -= len;
}

传递给SDL_memset的零应与您在调用SDL_AudioSpec时在SDL_OpenAudioDevice中创建的静音值相同。