#include "jail_audio.h" #include "stb_vorbis.c" #include #define JA_MAX_SIMULTANEOUS_SOUNDS 5 struct JA_Sound_t { Uint32 length {0}; Uint8 *buffer {NULL}; }; struct JA_Sound_Playing_t { Uint32 length {0}; int pos {0}; Uint8 *buffer {NULL}; JA_Sound_Playing_t* prev {NULL}; JA_Sound_Playing_t* next {NULL}; }; enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED }; struct JA_Music_t { int samples {0}; int pos {0}; short *output {NULL}; JA_Music_state state {JA_MUSIC_INVALID}; bool loop {false}; }; JA_Music_t music; JA_Sound_Playing_t sounds[JA_MAX_SIMULTANEOUS_SOUNDS]; JA_Sound_Playing_t *first_sound {NULL}; JA_Sound_Playing_t *last_sound {NULL}; JA_Sound_Playing_t *free_sounds_list {NULL}; int JA_freq {48000}; SDL_AudioFormat JA_format {AUDIO_S16}; int JA_channels {2}; void audioCallback(void * userdata, uint8_t * stream, int len) { SDL_memset(stream, 0, len); if (music.state == JA_MUSIC_PLAYING) { const int size = SDL_min(len, music.samples*2-music.pos); SDL_memcpy(stream, music.output+music.pos, size); music.pos += size/2; if (size < len) { if (music.loop) { SDL_memcpy(stream+size, music.output, len-size); music.pos = (len-size)/2; } else { music.pos = 0; music.state = JA_MUSIC_STOPPED; } } } // Mixar els sounds mi amol JA_Sound_Playing_t *sound = first_sound; while (sound != NULL) { const int size = SDL_min(len, sound->length-sound->pos); SDL_MixAudioFormat(stream, sound->buffer+sound->pos, AUDIO_S16, size, 64); sound->pos += size; if (size < len) { if (sound == last_sound) last_sound = sound->prev; if (sound == first_sound) first_sound = sound->next; if (sound->prev != NULL) sound->prev->next = sound->next; if (sound->next != NULL) sound->next->prev = sound->prev; if (free_sounds_list == NULL) { free_sounds_list = sound; sound = sound->next; free_sounds_list->prev = free_sounds_list->next = NULL; } else { free_sounds_list->prev = sound; sound = sound->next; free_sounds_list->prev->next = free_sounds_list; free_sounds_list = free_sounds_list->prev; free_sounds_list->prev = NULL; } } else { sound = sound->next; } } } void JA_Init(const int freq, const SDL_AudioFormat format, const int channels) { JA_freq = freq; JA_format = format; JA_channels = channels; SDL_AudioSpec audioSpec{JA_freq, JA_format, JA_channels, 0, 1024, 0, 0, audioCallback, NULL}; SDL_AudioDeviceID sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0); free_sounds_list = &sounds[0]; for (int i = 0; i < JA_MAX_SIMULTANEOUS_SOUNDS-2;i++) { sounds[i].next = &sounds[i+1]; sounds[i+1].prev = &sounds[i]; } SDL_PauseAudioDevice(sdlAudioDevice, 0); } void JA_PlayMusic(const char* filename, const bool loop) { int chan, samplerate; if (music.output != NULL) { free(music.output); music.output = NULL; } music.samples = stb_vorbis_decode_filename(filename, &chan, &samplerate, &music.output); SDL_AudioCVT cvt; SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq); cvt.len = music.samples * chan * 2; cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult); SDL_memcpy(cvt.buf, music.output, cvt.len); SDL_ConvertAudio(&cvt); free(music.output); music.output = (short*)cvt.buf; music.pos = 0; music.state = JA_MUSIC_PLAYING; music.loop = loop; } void JA_PauseMusic() { if (music.state == JA_MUSIC_INVALID) return; music.state = JA_MUSIC_PAUSED; } void JA_RestartMusic() { if (music.state == JA_MUSIC_INVALID) return; music.state = JA_MUSIC_PLAYING; } void JA_StopMusic() { if (music.state == JA_MUSIC_INVALID) return; music.pos = 0; music.state = JA_MUSIC_STOPPED; } JA_Sound JA_LoadSound(const char* filename) { JA_Sound sound = new JA_Sound_t(); SDL_AudioSpec wavSpec; SDL_LoadWAV(filename, &wavSpec, &sound->buffer, &sound->length); SDL_AudioCVT cvt; SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq); cvt.len = sound->length; cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult); SDL_memcpy(cvt.buf, sound->buffer, sound->length); SDL_ConvertAudio(&cvt); free(sound->buffer); sound->buffer = cvt.buf; sound->length = cvt.len_cvt; return sound; } void JA_PlaySound(JA_Sound sound) { if (free_sounds_list == NULL) { first_sound->prev = last_sound; last_sound->next = first_sound; last_sound = first_sound; first_sound = last_sound->next; first_sound->prev = last_sound->next = NULL; } else { if (last_sound != NULL) last_sound->next = free_sounds_list; last_sound = free_sounds_list; if (free_sounds_list->next != NULL) free_sounds_list->next->prev = NULL; free_sounds_list = last_sound->next; last_sound->next = NULL; if (first_sound == NULL) first_sound = last_sound; } last_sound->buffer = sound->buffer; last_sound->length = sound->length; last_sound->pos = 0; } void JA_DeleteSound(JA_Sound sound) { SDL_FreeWAV(sound->buffer); delete sound; }