diff --git a/source/mini/audio/audio.cpp b/source/mini/audio/audio.cpp index 361e729..17e5979 100644 --- a/source/mini/audio/audio.cpp +++ b/source/mini/audio/audio.cpp @@ -6,19 +6,19 @@ namespace mini { namespace audio { - JA_Music_t *current_music = NULL; - #define MAX_SOUNDS 50 - JA_Sound_t *sounds[MAX_SOUNDS]; + int current_music = -1; + //#define MAX_SOUNDS 50 + //JA_Sound_t *sounds[MAX_SOUNDS]; void init() { - JA_Init(48000, SDL_AUDIO_S16, 1); - for (int i=0;i #include +#include -#define JA_MAX_SIMULTANEOUS_CHANNELS 5 - -struct JA_Sound_t +// structs i variables +// ============================= +namespace jail { - SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 }; - Uint32 length { 0 }; - Uint8 *buffer { NULL }; -}; + namespace audio + { + static SDL_AudioSpec audioSpec { SDL_AUDIO_S16, 2, 48000 }; + SDL_AudioDeviceID sdlAudioDevice { 0 }; + SDL_TimerID timerID { 0 }; -struct JA_Channel_t -{ - JA_Sound_t *sound { nullptr }; - int pos { 0 }; - int times { 0 }; - SDL_AudioStream *stream { nullptr }; - JA_Channel_state state { JA_CHANNEL_FREE }; -}; + namespace music + { + struct music_t + { + SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 }; + Uint32 length { 0 }; + Uint8 *buffer { nullptr }; -struct JA_Music_t -{ - SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 }; - Uint32 length { 0 }; - Uint8 *buffer { nullptr }; + int pos { 0 }; + int times { 0 }; + SDL_AudioStream *stream { nullptr }; + music::state state { music::state::invalid }; + }; - int pos { 0 }; - int times { 0 }; - SDL_AudioStream *stream { nullptr }; - JA_Music_state state { JA_MUSIC_INVALID }; -}; + static int current { -1 }; + static std::vector musics; + static float volume { 1.0f }; + static bool enabled { true }; -JA_Music_t *current_music { nullptr }; -JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; - -SDL_AudioSpec JA_audioSpec { SDL_AUDIO_S16, 2, 48000 }; -float JA_musicVolume { 1.0f }; -float JA_soundVolume { 0.5f }; -bool JA_musicEnabled { true }; -bool JA_soundEnabled { true }; -SDL_AudioDeviceID sdlAudioDevice { 0 }; -SDL_TimerID JA_timerID { 0 }; - -bool fading = false; -int fade_start_time; -int fade_duration; -int fade_initial_volume; - -/* -void audioCallback(void * userdata, uint8_t * stream, int len) { - SDL_memset(stream, 0, len); - if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) { - const int size = SDL_min(len, current_music->samples*2-current_music->pos); - SDL_MixAudioFormat(stream, (Uint8*)(current_music->output+current_music->pos), AUDIO_S16, size, JA_musicVolume); - current_music->pos += size/2; - if (size < len) { - if (current_music->times != 0) { - SDL_MixAudioFormat(stream+size, (Uint8*)current_music->output, AUDIO_S16, len-size, JA_musicVolume); - current_music->pos = (len-size)/2; - if (current_music->times > 0) current_music->times--; - } else { - current_music->pos = 0; - current_music->state = JA_MUSIC_STOPPED; + namespace fade + { + static bool fading = false; + static int start_time; + static int duration; + static int initial_volume; } } - } - // Mixar els channels mi amol - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { - if (channels[i].state == JA_CHANNEL_PLAYING) { - const int size = SDL_min(len, channels[i].sound->length - channels[i].pos); - SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume); - channels[i].pos += size; - if (size < len) { - if (channels[i].times != 0) { - SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len-size, JA_soundVolume); - channels[i].pos = len-size; - if (channels[i].times > 0) channels[i].times--; - } else { - JA_StopChannel(i); - } + + namespace sound + { + struct sound_t + { + SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 }; + Uint32 length { 0 }; + Uint8 *buffer { NULL }; + }; + + static std::vector sounds; + static float volume { 0.5f }; + static bool enabled { true }; + + namespace channel + { + struct channel_t + { + int sound { -1 }; + int pos { 0 }; + int times { 0 }; + SDL_AudioStream *stream { nullptr }; + channel::state state { channel::state::free }; + }; + + static std::vector channels; + } } } } -*/ -Uint32 JA_UpdateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval) +// Funcions +// ================== +namespace jail { - if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING) + namespace audio { - if (fading) { - int time = SDL_GetTicks(); - if (time > (fade_start_time+fade_duration)) { - fading = false; - JA_StopMusic(); - return 30; - } else { - const int time_passed = time - fade_start_time; - const float percent = (float)time_passed / (float)fade_duration; - SDL_SetAudioStreamGain(current_music->stream, 1.0 - percent); - } - } - - if (current_music->times != 0) + static void updateMusic() { - if (SDL_GetAudioStreamAvailable(current_music->stream) < int(current_music->length/2)) { - SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length); - } - if (current_music->times>0) current_music->times--; - } - else - { - if (SDL_GetAudioStreamAvailable(current_music->stream) == 0) JA_StopMusic(); - } - } + if (!music::enabled) return; + if (music::current < 0 || music::current > music::musics.size()) return; + auto &m = music::musics[music::current]; + if (m.state != music::state::playing) return; - if (JA_soundEnabled) - { - for (int i=0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) - if (channels[i].state == JA_CHANNEL_PLAYING) - { - if (channels[i].times != 0) - { - if (SDL_GetAudioStreamAvailable(channels[i].stream) < int(channels[i].sound->length/2)) - SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer, channels[i].sound->length); - if (channels[i].times>0) channels[i].times--; + if (music::fade::fading) { + int time = SDL_GetTicks(); + if (time > (music::fade::start_time + music::fade::duration)) { + music::fade::fading = false; + 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); } } + + if (m.times != 0) + { + if (SDL_GetAudioStreamAvailable(m.stream) < int(m.length/2)) { + SDL_PutAudioStreamData(m.stream, m.buffer, m.length); + } + if (m.times>0) m.times--; + } else { - if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) JA_StopChannel(i); + if (SDL_GetAudioStreamAvailable(m.stream) == 0) music::stop(); } + } - } + static void updateSound() + { + if (sound::enabled) + { + for (int i=0; i < sound::channel::channels.size(); ++i) { + auto &c = sound::channel::channels[i]; + if (c.state == sound::channel::state::playing) + { + if (c.times != 0) + { + auto &s = sound::sounds[c.sound]; + if (SDL_GetAudioStreamAvailable(c.stream) < int(s.length/2)) + SDL_PutAudioStreamData(c.stream, s.buffer, s.length); + if (c.times>0) c.times--; + } + } + else + { + if (SDL_GetAudioStreamAvailable(c.stream) == 0) sound::channel::stop(i); + } + } + } + } - return 30; -} - -void JA_Init(const int freq, const SDL_AudioFormat format, const int channels) -{ - #ifdef DEBUG - SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); - #endif + Uint32 updateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval) + { + updateMusic(); + updateSound(); + return 30; + } - JA_audioSpec = {format, channels, freq }; - if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); - sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec); - if (!sdlAudioDevice) { - log_msg(LOG_FAIL, "Failed to initialize SDL audio: %s\n", SDL_GetError()); - } else { - log_msg(LOG_OK, "Audio subsytem initialized\n"); - } - //SDL_PauseAudioDevice(sdlAudioDevice); - JA_timerID = SDL_AddTimer(30, JA_UpdateCallback, nullptr); -} - -void JA_Quit() -{ - if (JA_timerID) SDL_RemoveTimer(JA_timerID); - - if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); - sdlAudioDevice = 0; -} - -JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length) -{ - JA_Music_t *music = new JA_Music_t(); - - int chan, samplerate; - short *output; - music->length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2; - - music->spec.channels = chan; - music->spec.freq = samplerate; - music->spec.format = SDL_AUDIO_S16; - music->buffer = (Uint8*)SDL_malloc(music->length); - SDL_memcpy(music->buffer, output, music->length); - free(output); - music->pos = 0; - music->state = JA_MUSIC_STOPPED; - - return music; -} - -JA_Music_t *JA_LoadMusic(const char* filename) -{ - // [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid. - FILE *f = fopen(filename, "rb"); - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - fseek(f, 0, SEEK_SET); - Uint8 *buffer = (Uint8*)malloc(fsize + 1); - if (fread(buffer, fsize, 1, f)!=1) return NULL; - fclose(f); - - JA_Music_t *music = JA_LoadMusic(buffer, fsize); - - free(buffer); - - return music; -} - -void JA_PlayMusic(JA_Music_t *music, const int loop) -{ - if (!JA_musicEnabled) return; - - JA_StopMusic(); - - current_music = music; - current_music->pos = 0; - current_music->state = JA_MUSIC_PLAYING; - current_music->times = loop; - - current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &JA_audioSpec); - if (!SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length)) log_msg(LOG_FAIL, "SDL_PutAudioStreamData failed!\n"); - SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); - if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) log_msg(LOG_FAIL, "SDL_BindAudioStream failed!\n"); - //SDL_ResumeAudioStreamDevice(current_music->stream); -} - -void JA_PauseMusic() -{ - if (!JA_musicEnabled) return; - if (!current_music || current_music->state == JA_MUSIC_INVALID) return; - - current_music->state = JA_MUSIC_PAUSED; - //SDL_PauseAudioStreamDevice(current_music->stream); - SDL_UnbindAudioStream(current_music->stream); -} - -void JA_ResumeMusic() -{ - if (!JA_musicEnabled) return; - if (!current_music || current_music->state == JA_MUSIC_INVALID) return; - - current_music->state = JA_MUSIC_PLAYING; - //SDL_ResumeAudioStreamDevice(current_music->stream); - SDL_BindAudioStream(sdlAudioDevice, current_music->stream); -} - -void JA_StopMusic() -{ - if (!JA_musicEnabled) return; - if (!current_music || current_music->state == JA_MUSIC_INVALID) return; - - current_music->pos = 0; - current_music->state = JA_MUSIC_STOPPED; - //SDL_PauseAudioStreamDevice(current_music->stream); - SDL_DestroyAudioStream(current_music->stream); - current_music->stream = nullptr; -} - -void JA_FadeOutMusic(const int milliseconds) -{ - if (!JA_musicEnabled) return; - if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return; - - fading = true; - fade_start_time = SDL_GetTicks(); - fade_duration = milliseconds; - fade_initial_volume = JA_musicVolume; -} - -JA_Music_state JA_GetMusicState() -{ - if (!JA_musicEnabled) return JA_MUSIC_DISABLED; - if (!current_music) return JA_MUSIC_INVALID; - - return current_music->state; -} - -void JA_DeleteMusic(JA_Music_t *music) -{ - if (current_music == music) current_music = nullptr; - SDL_free(music->buffer); - if (music->stream) SDL_DestroyAudioStream(music->stream); - delete music; -} - -float JA_SetMusicVolume(float volume) -{ - JA_musicVolume = SDL_clamp( volume, 0.0f, 1.0f ); - if (current_music) SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); - return JA_musicVolume; -} - -void JA_SetMusicPosition(float value) -{ - if (!current_music) return; - current_music->pos = value * current_music->spec.freq; -} - -float JA_GetMusicPosition() -{ - if (!current_music) return 0; - return float(current_music->pos)/float(current_music->spec.freq); -} - -void JA_EnableMusic(const bool value) -{ - if ( !value && current_music && (current_music->state==JA_MUSIC_PLAYING) ) JA_StopMusic(); - - JA_musicEnabled = value; -} - -const bool JA_IsMusicEnabled() -{ - return JA_musicEnabled; -} - - - - -JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length) -{ - JA_Sound_t *sound = new JA_Sound_t(); - sound->buffer = buffer; - sound->length = length; - return sound; -} - -JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size) -{ - JA_Sound_t *sound = new JA_Sound_t(); - SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size),1, &sound->spec, &sound->buffer, &sound->length); - - return sound; -} - -JA_Sound_t *JA_LoadSound(const char* filename) -{ - JA_Sound_t *sound = new JA_Sound_t(); - SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length); - - return sound; -} - -int JA_PlaySound(JA_Sound_t *sound, const int loop) -{ - if (!JA_soundEnabled) return -1; - - int channel = 0; - while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; } - if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channel = 0; - JA_StopChannel(channel); - - channels[channel].sound = sound; - channels[channel].times = loop; - channels[channel].pos = 0; - channels[channel].state = JA_CHANNEL_PLAYING; - channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec); - SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer, channels[channel].sound->length); - SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume); - SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); - - return channel; -} - -int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop) -{ - if (!JA_soundEnabled) return -1; - - if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1; - JA_StopChannel(channel); - - channels[channel].sound = sound; - channels[channel].times = loop; - channels[channel].pos = 0; - channels[channel].state = JA_CHANNEL_PLAYING; - channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec); - SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer, channels[channel].sound->length); - SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume); - SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); - - return channel; -} - -void JA_DeleteSound(JA_Sound_t *sound) -{ - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { - if (channels[i].sound == sound) JA_StopChannel(i); - } - SDL_free(sound->buffer); - delete sound; -} - -void JA_PauseChannel(const int channel) -{ - if (!JA_soundEnabled) return; - - if (channel == -1) - { - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) - if (channels[i].state == JA_CHANNEL_PLAYING) - { - channels[i].state = JA_CHANNEL_PAUSED; - //SDL_PauseAudioStreamDevice(channels[i].stream); - SDL_UnbindAudioStream(channels[i].stream); - } - } - else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) - { - if (channels[channel].state == JA_CHANNEL_PLAYING) + void init() { - channels[channel].state = JA_CHANNEL_PAUSED; - //SDL_PauseAudioStreamDevice(channels[channel].stream); - SDL_UnbindAudioStream(channels[channel].stream); - } - } -} + #ifdef DEBUG + SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); + #endif -void JA_ResumeChannel(const int channel) -{ - if (!JA_soundEnabled) return; - - if (channel == -1) - { - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) - if (channels[i].state == JA_CHANNEL_PAUSED) - { - channels[i].state = JA_CHANNEL_PLAYING; - //SDL_ResumeAudioStreamDevice(channels[i].stream); - SDL_BindAudioStream(sdlAudioDevice, channels[i].stream); + audioSpec = {SDL_AUDIO_S16, 1, 48000 }; + if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); + sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audioSpec); + if (!sdlAudioDevice) { + log_msg(LOG_FAIL, "Failed to initialize SDL audio: %s\n", SDL_GetError()); + } else { + log_msg(LOG_OK, "Audio subsytem initialized\n"); } - } - else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) - { - if (channels[channel].state == JA_CHANNEL_PAUSED) + //SDL_PauseAudioDevice(sdlAudioDevice); + timerID = SDL_AddTimer(30, updateCallback, nullptr); + } + + void quit() { - channels[channel].state = JA_CHANNEL_PLAYING; - //SDL_ResumeAudioStreamDevice(channels[channel].stream); - SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); + if (timerID) SDL_RemoveTimer(timerID); + + for (int i=0; i= 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; + m.times = loop; + 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); + } + + void pause() + { + if (!music::enabled) return; + if (current<0 || current>musics.size()) { + log_msg(LOG_FAIL, "music::pause: Illegal music handle: %i\n", current); + return; + } + auto &m = musics[current]; + if (m.state == state::invalid) { + log_msg(LOG_FAIL, "music::pause: Invalidated music handle: %i\n", current); + return; + } + + m.state = state::paused; + //SDL_PauseAudioStreamDevice(current->stream); + SDL_UnbindAudioStream(m.stream); + } + + void resume() + { + if (!music::enabled) return; + if (current<0 || current>musics.size()) { + log_msg(LOG_FAIL, "music::resume: Illegal music handle: %i\n", current); + return; + } + auto &m = musics[current]; + if (m.state == state::invalid) { + log_msg(LOG_FAIL, "music::resume: Invalidated music handle: %i\n", current); + return; + } + + m.state = state::playing; + //SDL_ResumeAudioStreamDevice(current->stream); + SDL_BindAudioStream(sdlAudioDevice, m.stream); + } + + void stop() + { + if (!music::enabled) return; + if (current<0 || current>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; + } + + m.pos = 0; + m.state = state::stopped; + //SDL_PauseAudioStreamDevice(current->stream); + SDL_DestroyAudioStream(m.stream); + m.stream = nullptr; + } + + void fadeOut(int milliseconds) + { + if (!music::enabled) return; + if (current<0 || current>musics.size()) { + log_msg(LOG_FAIL, "music::fadeOut: Illegal music handle: %i\n", current); + return; + } + auto &m = musics[current]; + if (m.state == state::invalid) { + log_msg(LOG_FAIL, "music::fadeOut: Invalidated music handle: %i\n", current); + return; + } + + fade::fading = true; + fade::start_time = SDL_GetTicks(); + fade::duration = milliseconds; + fade::initial_volume = volume; + } + + music::state getState() + { + if (!music::enabled) return music::state::disabled; + if (current<0 || current>musics.size()) return state::invalid; + return musics[current].state; + } + + void destroy(int mus) + { + if (current == mus) current = -1; + if (mus<0 || mus>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 (m.stream) SDL_DestroyAudioStream(m.stream); + m.stream = nullptr; + m.state = state::invalid; + } + + float setVolume(float vol) + { + volume = SDL_clamp( vol, 0.0f, 1.0f ); + + if (current<0 || current>musics.size()) return vol; + auto &m = musics[current]; + if (m.state == state::invalid) return vol; + + SDL_SetAudioStreamGain(m.stream, volume); + return volume; + } + + void setPosition(float value) + { + if (!music::enabled) return; + if (current<0 || current>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; + } + + m.pos = value * m.spec.freq; + } + + float getPosition() + { + if (!music::enabled) return 0; + if (current<0 || current>musics.size()) { + log_msg(LOG_FAIL, "music::getPosition: Illegal music handle: %i\n", current); + return 0; + } + auto &m = musics[current]; + if (m.state == state::invalid) { + log_msg(LOG_FAIL, "music::getPosition: Invalidated music handle: %i\n", current); + return 0; + } + + return float(m.pos)/float(m.spec.freq); + } + + void enable(bool value) + { + if (!value && music::enabled && current>=0 && currentsounds.size()) { + log_msg(LOG_FAIL, "sound::play: Illegal sound handle: %i\n", snd); + return -1; + } + auto &s = sounds[snd]; + if (!s.buffer) { + log_msg(LOG_FAIL, "sound::play: Invalid sound: %i\n", snd); + return -1; + } + + int chan = 0; + while (chan < channel::channels.size() && channel::channels[chan].state != channel::state::free) { chan++; } + if (chan == channel::channels.size()) channel::channels.emplace_back(); + channel::stop(chan); + auto &c = channel::channels[chan]; + c.sound = snd; + c.times = loop; + c.pos = 0; + c.state = channel::state::playing; + c.stream = SDL_CreateAudioStream(&s.spec, &audioSpec); + SDL_PutAudioStreamData(c.stream, s.buffer, s.length); + SDL_SetAudioStreamGain(c.stream, volume); + SDL_BindAudioStream(sdlAudioDevice, c.stream); + + return chan; + } + + int playOnChannel(int snd, int chan, int loop) + { + if (!sound::enabled) return -1; + + if (snd<0 || snd>sounds.size()) { + log_msg(LOG_FAIL, "sound::playOnChannel: Illegal sound handle: %i\n", snd); + return -1; + } + auto &s = sounds[snd]; + if (!s.buffer) { + log_msg(LOG_FAIL, "sound::playOnChannel: Invalid sound: %i\n", snd); + return -1; + } + + if (chan<0 || chan>channel::channels.size()) { + log_msg(LOG_FAIL, "sound::playOnChannel: Illegal channel handle: %i\n", chan); + return -1; + } + + channel::stop(chan); + + auto &c = channel::channels[chan]; + c.sound = snd; + c.times = loop; + c.pos = 0; + c.state = channel::state::playing; + c.stream = SDL_CreateAudioStream(&s.spec, &audioSpec); + SDL_PutAudioStreamData(c.stream, s.buffer, s.length); + SDL_SetAudioStreamGain(c.stream, volume); + SDL_BindAudioStream(sdlAudioDevice, c.stream); + + return chan; + } + + void destroy(int snd) + { + for (int i = 0; i < channel::channels.size(); i++) { + if (channel::channels[i].sound == snd) channel::stop(i); + } + + if (snd<0 || snd>sounds.size()) { + log_msg(LOG_FAIL, "sound::destroy: Illegal sound handle: %i\n", snd); + return; + } + auto &s = sounds[snd]; + SDL_free(s.buffer); + } + + float setVolume(float vol) + { + volume = SDL_clamp( vol, 0.0f, 1.0f ); + + for (int i = 0; i < channel::channels.size(); i++) { + auto &c = channel::channels[i]; + if ( (c.state == channel::state::playing) || (c.state == channel::state::paused) ) + SDL_SetAudioStreamGain(c.stream, volume); + } + return volume; + } + + void enable(bool value) + { + if (!value && sound::enabled) { + for (int i = 0; i < channel::channels.size(); i++) { + if (channel::channels[i].state == channel::state::playing) channel::stop(i); + } + } + enabled = value; + } + + bool isEnabled() + { + return enabled; + } + + namespace channel + { + void pause(const int chan) + { + if (!sound::enabled) return; + + if (chan == -1) + { + for (int i = 0; i < channels.size(); i++) + if (channels[i].state == state::playing) + { + channels[i].state = state::paused; + //SDL_PauseAudioStreamDevice(channels[i].stream); + SDL_UnbindAudioStream(channels[i].stream); + } + } + else if (chan >= 0 && chan < channels.size()) + { + if (channels[chan].state == state::playing) + { + channels[chan].state = state::paused; + //SDL_PauseAudioStreamDevice(channels[channel].stream); + SDL_UnbindAudioStream(channels[chan].stream); + } + } + } + + void resume(int chan) + { + if (!sound::enabled) return; + + if (chan == -1) + { + for (int i = 0; i < channels.size(); i++) + if (channels[i].state == state::paused) + { + channels[i].state = state::playing; + //SDL_ResumeAudioStreamDevice(channels[i].stream); + SDL_BindAudioStream(sdlAudioDevice, channels[i].stream); + } + } + else if (chan >= 0 && chan < channels.size()) + { + if (channels[chan].state == state::paused) + { + channels[chan].state = state::playing; + //SDL_ResumeAudioStreamDevice(channels[channel].stream); + SDL_BindAudioStream(sdlAudioDevice, channels[chan].stream); + } + } + } + + void stop(int chan) + { + if (!sound::enabled) return; + + if (chan == -1) + { + for (int i = 0; i < channels.size(); i++) { + if (channels[i].state != state::free) SDL_DestroyAudioStream(channels[i].stream); + channels[i].stream = nullptr; + channels[i].state = state::free; + channels[i].pos = 0; + channels[i].sound = -1; + } + } + else if (chan >= 0 && chan < channels.size()) + { + if (channels[chan].state != state::free) SDL_DestroyAudioStream(channels[chan].stream); + channels[chan].stream = nullptr; + channels[chan].state = state::free; + channels[chan].pos = 0; + channels[chan].sound = -1; + } + } + + channel::state getState(int chan) + { + if (!sound::enabled) return state::disabled; + if (chan < 0 || chan >= channels.size()) return state::invalid; + return channels[chan].state; + } + } } } } -void JA_StopChannel(const int channel) -{ - if (!JA_soundEnabled) return; - - if (channel == -1) - { - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { - if (channels[i].state != JA_CHANNEL_FREE) SDL_DestroyAudioStream(channels[i].stream); - channels[i].stream = nullptr; - channels[i].state = JA_CHANNEL_FREE; - channels[i].pos = 0; - channels[i].sound = NULL; - } - } - else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) - { - if (channels[channel].state != JA_CHANNEL_FREE) SDL_DestroyAudioStream(channels[channel].stream); - channels[channel].stream = nullptr; - channels[channel].state = JA_CHANNEL_FREE; - channels[channel].pos = 0; - channels[channel].sound = NULL; - } -} - -JA_Channel_state JA_GetChannelState(const int channel) -{ - if (!JA_soundEnabled) return JA_SOUND_DISABLED; - - if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID; - - return channels[channel].state; -} - -float JA_SetSoundVolume(float volume) -{ - JA_soundVolume = SDL_clamp( volume, 0.0f, 1.0f ); - - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) - if ( (channels[i].state == JA_CHANNEL_PLAYING) || (channels[i].state == JA_CHANNEL_PAUSED) ) - SDL_SetAudioStreamGain(channels[i].stream, JA_soundVolume); - - return JA_soundVolume; -} - -void JA_EnableSound(const bool value) -{ - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) - { - if (channels[i].state == JA_CHANNEL_PLAYING) JA_StopChannel(i); - } - JA_soundEnabled = value; -} - -const bool JA_IsSoundEnabled() -{ - return JA_soundEnabled; -} - -float JA_SetVolume(float volume) -{ - JA_SetSoundVolume(JA_SetMusicVolume(volume) / 2.0f); - - return JA_musicVolume; -} - #endif \ No newline at end of file diff --git a/source/mini/audio/jail_audio.h b/source/mini/audio/jail_audio.h index e145161..382cb95 100644 --- a/source/mini/audio/jail_audio.h +++ b/source/mini/audio/jail_audio.h @@ -1,42 +1,57 @@ #pragma once -#include +#include -enum JA_Channel_state { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED }; -enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED }; +namespace jail +{ + namespace audio + { + void init(/*const int freq, const SDL_AudioFormat format, const int channels*/); + void quit(); -struct JA_Sound_t; -struct JA_Music_t; + namespace music + { + //struct JA_Music_t; + enum state { invalid, playing, paused, stopped, disabled }; -void JA_Init(const int freq, const SDL_AudioFormat format, const int channels); -void JA_Quit(); + int load(const char* filename); + int load(const uint8_t* buffer, uint32_t length); + void play(int mus, int loop = -1); + void pause(); + void resume(); + void stop(); + void fadeOut(int milliseconds); + state getState(); + void destroy(int mus); + float setVolume(float vol); + void setPosition(float value); + float getPosition(); + void enable(bool value); + bool isEnabled(); + } -JA_Music_t *JA_LoadMusic(const char* filename); -JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length); -void JA_PlayMusic(JA_Music_t *music, const int loop = -1); -void JA_PauseMusic(); -void JA_ResumeMusic(); -void JA_StopMusic(); -void JA_FadeOutMusic(const int milliseconds); -JA_Music_state JA_GetMusicState(); -void JA_DeleteMusic(JA_Music_t *music); -float JA_SetMusicVolume(float volume); -void JA_SetMusicPosition(float value); -float JA_GetMusicPosition(); -void JA_EnableMusic(const bool value); -const bool JA_IsMusicEnabled(); + namespace sound + { + //struct JA_Sound_t; + int create(uint8_t* buffer, uint32_t length); + int load(uint8_t* buffer, uint32_t length); + int load(const char* filename); + int play(int snd, int loop = 0); + int playOnChannel(int snd, int chan, int loop = 0); + void destroy(int snd); + float setVolume(float vol); + void enable(bool value); + bool isEnabled(); + + namespace channel + { + enum state { invalid, free, playing, paused, disabled }; + void pause(int chan); + void resume(int chan); + void stop(int chan); + state getState(int chan); + } + } + } +} -JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length); -JA_Sound_t *JA_LoadSound(Uint8* buffer, Uint32 length); -JA_Sound_t *JA_LoadSound(const char* filename); -int JA_PlaySound(JA_Sound_t *sound, const int loop = 0); -int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop = 0); -void JA_PauseChannel(const int channel); -void JA_ResumeChannel(const int channel); -void JA_StopChannel(const int channel); -JA_Channel_state JA_GetChannelState(const int channel); -void JA_DeleteSound(JA_Sound_t *sound); -float JA_SetSoundVolume(float volume); -void JA_EnableSound(const bool value); -const bool JA_IsSoundEnabled(); -float JA_SetVolume(float volume);