VERSIÓ 1.5.8:
- [NEW] Implementat streaming de OGGs
This commit is contained in:
@@ -24,12 +24,15 @@ namespace jail
|
|||||||
struct music_t
|
struct music_t
|
||||||
{
|
{
|
||||||
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
|
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
|
||||||
Uint32 length { 0 };
|
|
||||||
Uint8 *buffer { nullptr };
|
|
||||||
|
|
||||||
int pos { 0 };
|
|
||||||
int times { 0 };
|
|
||||||
SDL_AudioStream* stream { nullptr };
|
SDL_AudioStream* stream { nullptr };
|
||||||
|
|
||||||
|
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 };
|
music::state state { music::state::invalid };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -87,10 +90,12 @@ namespace jail
|
|||||||
static void updateMusic()
|
static void updateMusic()
|
||||||
{
|
{
|
||||||
if (!music::enabled) return;
|
if (!music::enabled) return;
|
||||||
if (music::current < 0 || music::current > static_cast<int>(music::musics.size())) return;
|
if (music::current < 0) return;
|
||||||
|
|
||||||
auto& m = music::musics[music::current];
|
auto& m = music::musics[music::current];
|
||||||
if (m.state != music::state::playing) return;
|
if (m.state != music::state::playing) return;
|
||||||
|
|
||||||
|
// Fade-out
|
||||||
if (music::fade::fading) {
|
if (music::fade::fading) {
|
||||||
int time = SDL_GetTicks();
|
int time = SDL_GetTicks();
|
||||||
if (time > (music::fade::start_time + music::fade::duration)) {
|
if (time > (music::fade::start_time + music::fade::duration)) {
|
||||||
@@ -98,23 +103,37 @@ namespace jail
|
|||||||
music::stop();
|
music::stop();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
const int time_passed = time - music::fade::start_time;
|
float percent = float(time - music::fade::start_time) / float(music::fade::duration);
|
||||||
const float percent = (float)time_passed / (float)music::fade::duration;
|
SDL_SetAudioStreamGain(m.stream, 1.0f - percent);
|
||||||
SDL_SetAudioStreamGain(m.stream, 1.0 - percent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m.times != 0)
|
// ¿Hay suficiente audio en el stream?
|
||||||
{
|
if (SDL_GetAudioStreamAvailable(m.stream) > 48000) return; // 1 segundo
|
||||||
if (SDL_GetAudioStreamAvailable(m.stream) < static_cast<int>(m.length/2)) {
|
|
||||||
SDL_PutAudioStreamData(m.stream, m.buffer, m.length);
|
// 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--;
|
if (m.times > 0) m.times--;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
music::stop();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (SDL_GetAudioStreamAvailable(m.stream) == 0) music::stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_PutAudioStreamData(m.stream, temp, n * m.info.channels * sizeof(int16_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void updateSound()
|
static void updateSound()
|
||||||
@@ -194,26 +213,31 @@ namespace jail
|
|||||||
{
|
{
|
||||||
int load(const uint8_t* buffer, uint32_t length)
|
int load(const uint8_t* buffer, uint32_t length)
|
||||||
{
|
{
|
||||||
int music = 0;
|
int idx = 0;
|
||||||
while (music < static_cast<int>(musics.size()) && musics[music].state != state::invalid) { music++; }
|
while (idx < (int)musics.size() && musics[idx].state != state::invalid) idx++;
|
||||||
if (music == static_cast<int>(musics.size())) musics.emplace_back();
|
if (idx == (int)musics.size()) musics.emplace_back();
|
||||||
|
|
||||||
auto &m = musics[music];
|
auto& m = musics[idx];
|
||||||
|
|
||||||
int chan, samplerate;
|
m.ogg_data = buffer;
|
||||||
short *output;
|
m.ogg_length = length;
|
||||||
m.length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2;
|
|
||||||
|
|
||||||
m.spec.channels = chan;
|
int error;
|
||||||
m.spec.freq = samplerate;
|
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.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;
|
m.state = state::stopped;
|
||||||
|
|
||||||
return music;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load(const char* filename)
|
int load(const char* filename)
|
||||||
@@ -236,23 +260,19 @@ namespace jail
|
|||||||
|
|
||||||
void play(int mus, int loop)
|
void play(int mus, int loop)
|
||||||
{
|
{
|
||||||
if (!music::enabled) return;
|
|
||||||
stop();
|
stop();
|
||||||
if (mus < 0 || mus >= static_cast<int>(musics.size())) {
|
|
||||||
log_msg(LOG_FAIL, "music::play: Illegal music handle: %i\n", mus);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
current = mus;
|
current = mus;
|
||||||
auto &m = musics[current];
|
auto& m = musics[mus];
|
||||||
m.pos = 0;
|
|
||||||
m.state = state::playing;
|
|
||||||
m.times = loop;
|
m.times = loop;
|
||||||
|
m.state = state::playing;
|
||||||
|
|
||||||
|
stb_vorbis_seek_start(m.vorbis);
|
||||||
|
|
||||||
m.stream = SDL_CreateAudioStream(&m.spec, &audioSpec);
|
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);
|
SDL_SetAudioStreamGain(m.stream, volume);
|
||||||
if (!SDL_BindAudioStream(sdlAudioDevice, m.stream)) log_msg(LOG_FAIL, "SDL_BindAudioStream failed!\n");
|
SDL_BindAudioStream(sdlAudioDevice, m.stream);
|
||||||
//SDL_ResumeAudioStreamDevice(current->stream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pause()
|
void pause()
|
||||||
@@ -293,21 +313,13 @@ namespace jail
|
|||||||
|
|
||||||
void stop()
|
void stop()
|
||||||
{
|
{
|
||||||
if (!music::enabled || (current<0)) return;
|
if (current < 0) return;
|
||||||
if (current>static_cast<int>(musics.size())) {
|
|
||||||
log_msg(LOG_FAIL, "music::stop: Illegal music handle: %i\n", current);
|
auto& m = musics[current];
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto &m = musics[current];
|
|
||||||
if (m.state == state::invalid) {
|
|
||||||
log_msg(LOG_FAIL, "music::stop: Invalidated music handle: %i\n", current);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m.pos = 0;
|
|
||||||
m.state = state::stopped;
|
m.state = state::stopped;
|
||||||
//SDL_PauseAudioStreamDevice(current->stream);
|
|
||||||
SDL_DestroyAudioStream(m.stream);
|
if (m.stream) SDL_DestroyAudioStream(m.stream);
|
||||||
m.stream = nullptr;
|
m.stream = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,16 +351,16 @@ namespace jail
|
|||||||
|
|
||||||
void destroy(int mus)
|
void destroy(int mus)
|
||||||
{
|
{
|
||||||
if (current == mus) current = -1;
|
if (mus < 0 || mus >= (int)musics.size()) return;
|
||||||
if (mus<0 || mus>static_cast<int>(musics.size())) {
|
|
||||||
log_msg(LOG_FAIL, "music::destroy: Illegal music handle: %i\n", mus);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto& m = musics[mus];
|
auto& m = musics[mus];
|
||||||
SDL_free(m.buffer);
|
|
||||||
m.buffer = nullptr;
|
|
||||||
if (m.stream) SDL_DestroyAudioStream(m.stream);
|
if (m.stream) SDL_DestroyAudioStream(m.stream);
|
||||||
|
if (m.vorbis) stb_vorbis_close(m.vorbis);
|
||||||
|
|
||||||
m.stream = nullptr;
|
m.stream = nullptr;
|
||||||
|
m.vorbis = nullptr;
|
||||||
|
|
||||||
m.state = state::invalid;
|
m.state = state::invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,18 +378,13 @@ namespace jail
|
|||||||
|
|
||||||
void setPosition(float value)
|
void setPosition(float value)
|
||||||
{
|
{
|
||||||
if (!music::enabled) return;
|
|
||||||
if (current<0 || current>static_cast<int>(musics.size())) {
|
|
||||||
log_msg(LOG_FAIL, "music::setPosition: Illegal music handle: %i\n", current);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto& m = musics[current];
|
auto& m = musics[current];
|
||||||
if (m.state == state::invalid) {
|
|
||||||
log_msg(LOG_FAIL, "music::setPosition: Invalidated music handle: %i\n", current);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
float getPosition()
|
||||||
@@ -392,8 +399,8 @@ namespace jail
|
|||||||
log_msg(LOG_FAIL, "music::getPosition: Invalidated music handle: %i\n", current);
|
log_msg(LOG_FAIL, "music::getPosition: Invalidated music handle: %i\n", current);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int sample = stb_vorbis_get_sample_offset(m.vorbis);
|
||||||
return float(m.pos)/float(m.spec.freq);
|
return float(sample) / float(m.info.sample_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void enable(bool value)
|
void enable(bool value)
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MINI_VERSION "1.5.7"
|
#define MINI_VERSION "1.5.8"
|
||||||
|
|||||||
Reference in New Issue
Block a user