diff --git a/source/mini/audio/jail_audio.cpp b/source/mini/audio/jail_audio.cpp index 961511a..36f7da6 100644 --- a/source/mini/audio/jail_audio.cpp +++ b/source/mini/audio/jail_audio.cpp @@ -23,14 +23,17 @@ namespace jail { struct music_t { - SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 }; - Uint32 length { 0 }; - Uint8 *buffer { nullptr }; + SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 }; + SDL_AudioStream* stream { nullptr }; - int pos { 0 }; - int times { 0 }; - SDL_AudioStream *stream { nullptr }; - music::state state { music::state::invalid }; + const uint8_t* ogg_data { nullptr }; + uint32_t ogg_length { 0 }; + + stb_vorbis* vorbis { nullptr }; + stb_vorbis_info info {}; + + int times { 0 }; + music::state state { music::state::invalid }; }; static int current { -1 }; @@ -87,10 +90,12 @@ namespace jail static void updateMusic() { if (!music::enabled) return; - if (music::current < 0 || music::current > static_cast(music::musics.size())) return; - auto &m = music::musics[music::current]; + if (music::current < 0) return; + + auto& m = music::musics[music::current]; if (m.state != music::state::playing) return; + // Fade-out if (music::fade::fading) { int time = SDL_GetTicks(); if (time > (music::fade::start_time + music::fade::duration)) { @@ -98,23 +103,37 @@ namespace jail music::stop(); return; } else { - const int time_passed = time - music::fade::start_time; - const float percent = (float)time_passed / (float)music::fade::duration; - SDL_SetAudioStreamGain(m.stream, 1.0 - percent); + float percent = float(time - music::fade::start_time) / float(music::fade::duration); + SDL_SetAudioStreamGain(m.stream, 1.0f - percent); } } - if (m.times != 0) - { - if (SDL_GetAudioStreamAvailable(m.stream) < static_cast(m.length/2)) { - SDL_PutAudioStreamData(m.stream, m.buffer, m.length); + // ¿Hay suficiente audio en el stream? + if (SDL_GetAudioStreamAvailable(m.stream) > 48000) return; // 1 segundo + + // Decodificar un bloque + const int SAMPLES = 4096; + static int16_t temp[SAMPLES * 2]; + + int n = stb_vorbis_get_samples_short_interleaved( + m.vorbis, + m.info.channels, + temp, + SAMPLES + ); + + if (n == 0) { + if (m.times != 0) { + stb_vorbis_seek_start(m.vorbis); + if (m.times > 0) m.times--; + return; + } else { + music::stop(); + return; } - if (m.times>0) m.times--; - } - else - { - if (SDL_GetAudioStreamAvailable(m.stream) == 0) music::stop(); } + + SDL_PutAudioStreamData(m.stream, temp, n * m.info.channels * sizeof(int16_t)); } static void updateSound() @@ -194,26 +213,31 @@ namespace jail { int load(const uint8_t* buffer, uint32_t length) { - int music = 0; - while (music < static_cast(musics.size()) && musics[music].state != state::invalid) { music++; } - if (music == static_cast(musics.size())) musics.emplace_back(); + int idx = 0; + while (idx < (int)musics.size() && musics[idx].state != state::invalid) idx++; + if (idx == (int)musics.size()) musics.emplace_back(); - auto &m = musics[music]; + auto& m = musics[idx]; - int chan, samplerate; - short *output; - m.length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2; + m.ogg_data = buffer; + m.ogg_length = length; - m.spec.channels = chan; - m.spec.freq = samplerate; + int error; + m.vorbis = stb_vorbis_open_memory(buffer, length, &error, nullptr); + if (!m.vorbis) { + log_msg(LOG_FAIL, "stb_vorbis_open_memory failed: %d\n", error); + return -1; + } + + m.info = stb_vorbis_get_info(m.vorbis); + + m.spec.channels = m.info.channels; + m.spec.freq = m.info.sample_rate; m.spec.format = SDL_AUDIO_S16; - m.buffer = (uint8_t*)SDL_malloc(m.length); - SDL_memcpy(m.buffer, output, m.length); - free(output); - m.pos = 0; + m.state = state::stopped; - return music; + return idx; } int load(const char* filename) @@ -236,23 +260,19 @@ namespace jail void play(int mus, int loop) { - if (!music::enabled) return; stop(); - if (mus < 0 || mus >= static_cast(musics.size())) { - log_msg(LOG_FAIL, "music::play: Illegal music handle: %i\n", mus); - return; - } current = mus; - auto &m = musics[current]; - m.pos = 0; - m.state = state::playing; + auto& m = musics[mus]; + m.times = loop; + m.state = state::playing; + + stb_vorbis_seek_start(m.vorbis); + m.stream = SDL_CreateAudioStream(&m.spec, &audioSpec); - if (!SDL_PutAudioStreamData(m.stream, m.buffer, m.length)) log_msg(LOG_FAIL, "SDL_PutAudioStreamData failed!\n"); SDL_SetAudioStreamGain(m.stream, volume); - if (!SDL_BindAudioStream(sdlAudioDevice, m.stream)) log_msg(LOG_FAIL, "SDL_BindAudioStream failed!\n"); - //SDL_ResumeAudioStreamDevice(current->stream); + SDL_BindAudioStream(sdlAudioDevice, m.stream); } void pause() @@ -293,21 +313,13 @@ namespace jail void stop() { - if (!music::enabled || (current<0)) return; - if (current>static_cast(musics.size())) { - log_msg(LOG_FAIL, "music::stop: Illegal music handle: %i\n", current); - return; - } - auto &m = musics[current]; - if (m.state == state::invalid) { - log_msg(LOG_FAIL, "music::stop: Invalidated music handle: %i\n", current); - return; - } + if (current < 0) return; + + auto& m = musics[current]; - m.pos = 0; m.state = state::stopped; - //SDL_PauseAudioStreamDevice(current->stream); - SDL_DestroyAudioStream(m.stream); + + if (m.stream) SDL_DestroyAudioStream(m.stream); m.stream = nullptr; } @@ -339,16 +351,16 @@ namespace jail void destroy(int mus) { - if (current == mus) current = -1; - if (mus<0 || mus>static_cast(musics.size())) { - log_msg(LOG_FAIL, "music::destroy: Illegal music handle: %i\n", mus); - return; - } - auto &m = musics[mus]; - SDL_free(m.buffer); - m.buffer = nullptr; + if (mus < 0 || mus >= (int)musics.size()) return; + + auto& m = musics[mus]; + if (m.stream) SDL_DestroyAudioStream(m.stream); + if (m.vorbis) stb_vorbis_close(m.vorbis); + m.stream = nullptr; + m.vorbis = nullptr; + m.state = state::invalid; } @@ -366,18 +378,13 @@ namespace jail void setPosition(float value) { - if (!music::enabled) return; - if (current<0 || current>static_cast(musics.size())) { - log_msg(LOG_FAIL, "music::setPosition: Illegal music handle: %i\n", current); - return; - } - auto &m = musics[current]; - if (m.state == state::invalid) { - log_msg(LOG_FAIL, "music::setPosition: Invalidated music handle: %i\n", current); - return; - } + auto& m = musics[current]; - m.pos = value * m.spec.freq; + int sample = int(value * m.info.sample_rate); + + if (stb_vorbis_seek(m.vorbis, sample)) { + SDL_ClearAudioStream(m.stream); // importante + } } float getPosition() @@ -392,8 +399,8 @@ namespace jail log_msg(LOG_FAIL, "music::getPosition: Invalidated music handle: %i\n", current); return 0; } - - return float(m.pos)/float(m.spec.freq); + int sample = stb_vorbis_get_sample_offset(m.vorbis); + return float(sample) / float(m.info.sample_rate); } void enable(bool value) diff --git a/source/mini/version.h b/source/mini/version.h index 5997ee4..efebd08 100644 --- a/source/mini/version.h +++ b/source/mini/version.h @@ -1,3 +1,3 @@ #pragma once -#define MINI_VERSION "1.5.7" +#define MINI_VERSION "1.5.8"