#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 current_music{NULL}; 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}; Uint8 JA_channels {2}; 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_memcpy(stream, current_music->output+current_music->pos, size); current_music->pos += size/2; if (size < len) { if (current_music->loop) { SDL_memcpy(stream+size, current_music->output, len-size); current_music->pos = (len-size)/2; } else { current_music->pos = 0; current_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); } JA_Music JA_LoadMusic(const char* filename) { int chan, samplerate; JA_Music music = (JA_Music)SDL_malloc(sizeof(JA_Music_t)); 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_STOPPED; return music; } void JA_PlayMusic(JA_Music music, const bool loop) { int chan, samplerate; if (current_music != NULL) { current_music->pos = 0; current_music->state = JA_MUSIC_STOPPED; } current_music = music; current_music->pos = 0; current_music->state = JA_MUSIC_PLAYING; current_music->loop = loop; } void JA_PauseMusic() { if (current_music->state == JA_MUSIC_INVALID) return; current_music->state = JA_MUSIC_PAUSED; } void JA_ResumeMusic() { if (current_music->state == JA_MUSIC_INVALID) return; current_music->state = JA_MUSIC_PLAYING; } void JA_StopMusic() { if (current_music->state == JA_MUSIC_INVALID) return; current_music->pos = 0; current_music->state = JA_MUSIC_STOPPED; } bool JA_IsMusicPlaying() { return current_music->state == JA_MUSIC_PLAYING; } void JA_DeleteMusic(JA_Music music) { if (current_music == music) current_music = NULL; free(music->output); free(music); } 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; }