- [FIX] La música ja sona be en un auricularet

- [CHG] El joc ja no usa SDL_Mixer, sinó JailAudio
- [FIX] La música de game over ja no fa bucle
- [FIX] Tanquem les coses abans d'eixir pa que Valgrind no s'enfade
This commit is contained in:
2024-10-06 15:03:46 +02:00
parent da3cb5ff8e
commit 394773003a
11 changed files with 6009 additions and 35 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,4 +1,4 @@
libs = -lSDL2 -lSDL2_mixer
libs = -lSDL2
cppflags = -D DEBUG -g
executable = thepool_debug
sourcepath = source

345
source/jail_audio.cpp Normal file
View File

@@ -0,0 +1,345 @@
#ifndef JA_USESDLMIXER
#include "jail_audio.h"
#include "stb_vorbis.c"
#include <SDL2/SDL.h>
#include <stdio.h>
#define JA_MAX_SIMULTANEOUS_CHANNELS 5
struct JA_Sound_t {
Uint32 length {0};
Uint8* buffer {NULL};
};
struct JA_Channel_t {
JA_Sound_t *sound;
int pos {0};
int times {0};
JA_Channel_state state { JA_CHANNEL_FREE };
};
struct JA_Music_t {
int samples {0};
int pos {0};
int times {0};
short* output {NULL};
JA_Music_state state {JA_MUSIC_INVALID};
};
JA_Music_t *current_music{NULL};
JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS];
int JA_freq {48000};
SDL_AudioFormat JA_format {AUDIO_S16};
Uint8 JA_channels {2};
int JA_musicVolume = 128;
int JA_soundVolume = 64;
bool JA_musicEnabled = true;
bool JA_soundEnabled = true;
SDL_AudioDeviceID sdlAudioDevice = 0;
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;
}
}
}
// 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);
}
}
}
}
}
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};
if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0);
SDL_PauseAudioDevice(sdlAudioDevice, 0);
}
void JA_Quit() {
SDL_PauseAudioDevice(sdlAudioDevice, 1);
if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = 0;
}
JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length)
{
int chan, samplerate;
JA_Music_t *music = new JA_Music_t();
music->samples = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &music->output);
// [RZC 28/08/22] Abans el descomprimiem mentre el teniem obert
// 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);
if (cvt.needed) {
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;
}
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;
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->times = loop;
}
void JA_PauseMusic()
{
if (!JA_musicEnabled) return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
current_music->state = JA_MUSIC_PAUSED;
}
void JA_ResumeMusic()
{
if (!JA_musicEnabled) return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
current_music->state = JA_MUSIC_PLAYING;
}
void JA_StopMusic()
{
if (!JA_musicEnabled) return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED;
}
JA_Music_state JA_GetMusicState() {
if (!JA_musicEnabled) return JA_MUSIC_DISABLED;
if (current_music == NULL) return JA_MUSIC_INVALID;
return current_music->state;
}
void JA_DeleteMusic(JA_Music_t *music) {
if (current_music == music) current_music = NULL;
free(music->output);
delete music;
}
int JA_SetMusicVolume(int volume)
{
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume;
return JA_musicVolume;
}
void JA_EnableMusic(const bool value)
{
if (!value && current_music != NULL && current_music->state==JA_MUSIC_PLAYING) JA_StopMusic();
JA_musicEnabled = value;
}
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_AudioSpec wavSpec;
SDL_LoadWAV_RW(SDL_RWFromMem(buffer, size),1, &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);
SDL_FreeWAV(sound->buffer);
sound->buffer = cvt.buf;
sound->length = cvt.len_cvt;
return sound;
}
JA_Sound_t *JA_LoadSound(const char* filename) {
JA_Sound_t *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);
SDL_FreeWAV(sound->buffer);
sound->buffer = cvt.buf;
sound->length = cvt.len_cvt;
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;
channels[channel].sound = sound;
channels[channel].times = loop;
channels[channel].pos = 0;
channels[channel].state = JA_CHANNEL_PLAYING;
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;
}
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
if (channels[channel].state == JA_CHANNEL_PLAYING) channels[channel].state = JA_CHANNEL_PAUSED;
}
}
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;
}
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
if (channels[channel].state == JA_CHANNEL_PAUSED) channels[channel].state = JA_CHANNEL_PLAYING;
}
}
void JA_StopChannel(const int channel)
{
if (!JA_soundEnabled) return;
if (channel == -1) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
channels[i].state = JA_CHANNEL_FREE;
channels[i].pos = 0;
channels[i].sound = NULL;
}
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
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;
}
int JA_SetSoundVolume(int volume)
{
JA_soundVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume;
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;
}
int JA_SetVolume(int volume)
{
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume;
JA_soundVolume = JA_musicVolume/2;
return JA_musicVolume;
}
#endif

36
source/jail_audio.h Normal file
View File

@@ -0,0 +1,36 @@
#pragma once
#include <SDL2/SDL.h>
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 };
struct JA_Sound_t;
struct JA_Music_t;
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels);
void JA_Quit();
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();
JA_Music_state JA_GetMusicState();
void JA_DeleteMusic(JA_Music_t *music);
int JA_SetMusicVolume(int volume);
void JA_EnableMusic(const bool value);
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);
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);
int JA_SetSoundVolume(int volume);
void JA_EnableSound(const bool value);
int JA_SetVolume(int volume);

View File

@@ -1,6 +1,6 @@
#include "jaudio.h"
#include "jail_audio.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
#include <stdio.h>
#include "jfile.h"
#include <vector>
@@ -11,30 +11,29 @@ namespace audio
struct sound_cache_t
{
std::string name;
Mix_Chunk *chunk;
JA_Sound_t *chunk;
};
char *music_buffer = nullptr;
Mix_Music *music = nullptr;
//char *music_buffer = nullptr;
JA_Music_t *music = nullptr;
std::vector<sound_cache_t> sounds;
std::string musica_actual = "";
// Inicialitza el sistema de só
void init()
{
//int result =
Mix_Init(MIX_INIT_OGG);// | MIX_INIT_WAVPACK);
// Al final he ficat la configuració automàtica i au. Si en el futur necesitem canviar-ho pos se canvia
//result =
Mix_OpenAudio(48000, AUDIO_S16, 2, 512);
JA_Init(48000, AUDIO_S16, 2);
//Mix_Init(MIX_INIT_OGG);// | MIX_INIT_WAVPACK);
//Mix_OpenAudio(48000, AUDIO_S16, 2, 512);
}
// Tanca el sistema de só (no shit, sherlock)
void quit()
{
for (auto sound : sounds) Mix_FreeChunk(sound.chunk);
if (music) JA_DeleteMusic(music);
for (auto sound : sounds) JA_DeleteSound(sound.chunk); // Mix_FreeChunk(sound.chunk);
sounds.clear();
Mix_CloseAudio();
JA_Quit(); // Mix_CloseAudio();
}
// Comença a reproduïr la música en questió
@@ -42,46 +41,49 @@ namespace audio
{
if (!config::isMusicEnabled()) return;
// Si hi havia musica carregada, alliberem memòria
if (music_buffer) free(music_buffer);
if (music) Mix_FreeMusic(music);
//if (music_buffer) free(music_buffer);
if (music) JA_DeleteMusic(music); //Mix_FreeMusic(music);
int size;
music_buffer = file::getFileBuffer(filename, size);
auto rwops = SDL_RWFromMem(music_buffer, size);
auto mus = Mix_LoadMUS_RW(rwops, 1);
char *buffer = file::getFileBuffer(filename, size);
music = JA_LoadMusic((uint8_t*)buffer, size);
free(buffer);
//auto rwops = SDL_RWFromMem(music_buffer, size);
//auto mus = Mix_LoadMUS_RW(rwops, 1);
//free(music_buffer); // [RZC 03/10/2024] Si allibere el buffer, no funciona la música. Porca miseria! Per aixó l'allibere abans de carregar si ja estava usat.
Mix_PlayMusic((Mix_Music *)mus, loop);
//Mix_PlayMusic((Mix_Music *)mus, loop);
JA_PlayMusic(music, loop);
musica_actual = filename;
}
// Pausa la música que està sonant ara
void pauseMusic()
{
Mix_PauseMusic();
JA_PauseMusic(); //Mix_PauseMusic();
}
// Continua la música pausada
void resumeMusic()
{
if (!config::isMusicEnabled()) return;
Mix_ResumeMusic();
JA_ResumeMusic(); //Mix_ResumeMusic();
}
// Para la música que estava sonant
void stopMusic()
{
Mix_HaltMusic();
JA_StopMusic(); //Mix_HaltMusic();
musica_actual = "";
}
// Obté el estat actual de la música
const music_state getMusicState()
{
if (Mix_PausedMusic())
if (JA_GetMusicState() == JA_MUSIC_PAUSED)
{
return MUSIC_PAUSED;
}
else if (Mix_PlayingMusic())
else if (JA_GetMusicState() == JA_MUSIC_PLAYING)
{
return MUSIC_PLAYING;
}
@@ -104,8 +106,11 @@ namespace audio
{
int size;
char *buffer = file::getFileBuffer(filename, size);
auto chunk = Mix_LoadWAV_RW(SDL_RWFromMem(buffer, size), 1);
if (!chunk) printf("ERROR: %s\n", SDL_GetError());
auto chunk = JA_LoadSound((uint8_t *)buffer, size);
free(buffer);
//auto chunk = Mix_LoadWAV_RW(SDL_RWFromMem(buffer, size), 1);
//if (!chunk) printf("ERROR: %s\n", SDL_GetError());
sound_cache_t sound = { filename, chunk };
sounds.push_back(sound);
}
@@ -116,7 +121,7 @@ namespace audio
if (priority < config::getSoundMode()) return -1;
for (auto sound : sounds)
{
if (sound.name == name) return Mix_PlayChannel(-1, sound.chunk, loop);
if (sound.name == name) return JA_PlaySound(sound.chunk, loop); // Mix_PlayChannel(-1, sound.chunk, loop);
}
return -1;
}
@@ -125,37 +130,37 @@ namespace audio
void pauseChannel(const int channel)
{
if (channel == -1) return;
Mix_Pause(channel);
JA_PauseChannel(channel); // Mix_Pause(channel);
}
// Continua un canal pausat
void resumeChannel(const int channel)
{
if (channel == -1) return;
Mix_Resume(channel);
JA_ResumeChannel(channel); // Mix_Resume(channel);
}
// Para un canal que estava reproduïnt un só
void stopChannel(const int channel)
{
if (channel == -1) return;
Mix_HaltChannel(channel);
JA_StopChannel(channel); // Mix_HaltChannel(channel);
}
// Para tots els canals
void stopAllChannel()
{
Mix_HaltChannel(-1);
JA_StopChannel(-1); // Mix_HaltChannel(-1);
}
// Obté l'estat d'un canal
const channel_state getChannelState(const int channel)
{
if (Mix_Paused(channel))
if (JA_GetChannelState(channel) == JA_CHANNEL_PAUSED)
{
return CHANNEL_PAUSED;
}
else if (Mix_Playing(channel))
else if (JA_GetChannelState(channel) == JA_CHANNEL_PLAYING)
{
return CHANNEL_PLAYING;
}
@@ -168,6 +173,6 @@ namespace audio
// Estableix el volum general
const int setVolume(int volume)
{
return Mix_Volume(-1, volume);
return JA_SetVolume(volume); // Mix_Volume(-1, volume);
}
}

View File

@@ -82,5 +82,9 @@ int main(int argc, char *argv[])
current_ticks = SDL_GetTicks();
}
}
audio::quit();
draw::quit();
return 0;
}

View File

@@ -16,7 +16,7 @@ namespace modules
void init()
{
audio::playMusic("mus_gameover.ogg");
audio::playMusic("mus_gameover.ogg", 0);
if (gat == nullptr) gat = actor::createFromTemplate("GAT-NEGRE");
}

View File

@@ -17,7 +17,7 @@ namespace modules
void init()
{
if (audio::getCurrentMusic() != "mus_gameover.ogg") audio::playMusic("mus_gameover.ogg");
if (audio::getCurrentMusic() != "mus_gameover.ogg") audio::playMusic("mus_gameover.ogg", 0);
if (heroi == nullptr) heroi = actor::create("HERO", {16,32,8}, {6,6,12}, "test.gif", {0,32,20,32}, {-6,38});
heroi->flags = FLAG_ANIMATED;

5584
source/stb_vorbis.c Normal file

File diff suppressed because it is too large Load Diff