mixer: support looping bgms with a separate intro

This commit is contained in:
Andrei Alexeyev 2017-10-02 03:37:29 +03:00
parent 8965ad4cb2
commit 05954b2764
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
4 changed files with 98 additions and 25 deletions

View file

@ -19,7 +19,7 @@
static bool mixer_loaded = false;
const char *mixer_audio_exts[] = { ".wav", ".ogg", ".mp3", ".mod", ".xm", ".s3m",
const char *mixer_audio_exts[] = { ".bgm", ".wav", ".ogg", ".mp3", ".mod", ".xm", ".s3m",
".669", ".it", ".med", ".mid", ".flac", ".aiff", ".voc",
NULL };
@ -109,8 +109,8 @@ void audio_backend_set_bgm_volume(float gain) {
Mix_VolumeMusic(gain * MIX_MAX_VOLUME);
}
char* audio_mixer_sound_path(const char *prefix, const char *name) {
for(const char **ext = mixer_audio_exts; *ext; ++ext) {
char* audio_mixer_sound_path(const char *prefix, const char *name, bool isbgm) {
for(const char **ext = mixer_audio_exts + !isbgm; *ext; ++ext) {
char *p = strjoin(prefix, name, *ext, NULL);
if(vfs_query(p).exists) {
@ -124,16 +124,31 @@ char* audio_mixer_sound_path(const char *prefix, const char *name) {
}
bool audio_mixer_check_sound_path(const char *path, bool isbgm) {
if(strstartswith(resource_util_filename(path), "bgm_") == isbgm) {
return strendswith_any(path, mixer_audio_exts);
}
return strendswith_any(path, mixer_audio_exts + !isbgm);
}
return false;
static Mix_Music *next_loop;
static void mixer_music_finished(void) {
// XXX: there may be a race condition in here
// probably should protect next_loop with a mutex
log_debug("Intro stopped playing");
if(next_loop) {
if(Mix_PlayMusic(next_loop, -1) == -1) {
log_warn("Mix_PlayMusic() failed: %s", Mix_GetError());
} else {
next_loop = NULL;
}
}
}
void audio_backend_music_stop(void) {
if(mixer_loaded)
if(mixer_loaded) {
Mix_HookMusicFinished(NULL);
Mix_HaltMusic();
}
}
bool audio_backend_music_is_paused(void) {
@ -145,20 +160,40 @@ bool audio_backend_music_is_playing(void) {
}
void audio_backend_music_resume(void) {
if(mixer_loaded)
if(mixer_loaded) {
Mix_HookMusicFinished(mixer_music_finished);
Mix_ResumeMusic();
}
}
void audio_backend_music_pause(void) {
if(mixer_loaded)
if(mixer_loaded) {
Mix_HookMusicFinished(NULL);
Mix_PauseMusic();
}
}
bool audio_backend_music_play(void *impl) {
if(!mixer_loaded)
return false;
bool result = (Mix_PlayMusic((Mix_Music*)impl, -1) != -1);
MixerInternalMusic *imus = impl;
Mix_Music *mmus;
int loops;
if(imus->intro) {
next_loop = imus->loop;
mmus = imus->intro;
loops = 0;
assert(next_loop != NULL);
Mix_HookMusicFinished(mixer_music_finished);
} else {
mmus = imus->loop;
loops = -1;
Mix_HookMusicFinished(NULL);
}
bool result = (Mix_PlayMusic(mmus, loops) != -1);
if(!result) {
log_warn("Mix_PlayMusic() failed: %s", Mix_GetError());
@ -193,7 +228,6 @@ bool audio_backend_sound_loop(void *impl) {
}
return true;
}
bool audio_backend_sound_stop_loop(void *impl) {

View file

@ -8,6 +8,9 @@
#pragma once
#include <SDL_mixer.h>
#include <stdbool.h>
// I needed to add this for supporting loop sounds since Mixer doesnt remember
// what channel a sound is playing on.
@ -16,3 +19,10 @@ typedef struct {
int loopchan; // channel the sound may be looping on. -1 if not looping
} MixerInternalSound;
typedef struct MixerInternalMusic {
Mix_Music *intro;
Mix_Music *loop;
} MixerInternalMusic;
char* audio_mixer_sound_path(const char *prefix, const char *name, bool isbgm);
bool audio_mixer_check_sound_path(const char *path, bool isbgm);

View file

@ -10,20 +10,22 @@
#include <SDL_mixer.h>
#include "resource.h"
#include "sfx.h"
char* audio_mixer_sound_path(const char *prefix, const char *name);
bool audio_mixer_check_sound_path(const char *path, bool isbgm);
#include "bgm.h"
#include "audio_mixer.h"
char* music_path(const char *name) {
return audio_mixer_sound_path(BGM_PATH_PREFIX, name);
return audio_mixer_sound_path(BGM_PATH_PREFIX, name, true);
}
bool check_music_path(const char *path) {
return strstartswith(path, BGM_PATH_PREFIX) && audio_mixer_check_sound_path(path, true);
}
void* load_music_begin(const char *path, unsigned int flags) {
static Mix_Music* load_mix_music(const char *path) {
if(!path) {
return NULL;
}
SDL_RWops *rwops = vfs_open(path, VFS_MODE_READ | VFS_MODE_SEEKABLE);
if(!rwops) {
@ -38,8 +40,35 @@ void* load_music_begin(const char *path, unsigned int flags) {
return NULL;
}
return music;
}
void* load_music_begin(const char *path, unsigned int flags) {
Music *mus = calloc(1, sizeof(Music));
mus->impl = music;
MixerInternalMusic *imus = calloc(1, sizeof(MixerInternalMusic));
mus->impl = imus;
if(strendswith(path, ".bgm")) {
Hashtable *bgm = parse_keyvalue_file(path, 8);
if(!bgm) {
log_warn("Failed to parse bgm config '%s'", path);
} else {
imus->intro = load_mix_music(hashtable_get_string(bgm, "intro"));
imus->loop = load_mix_music(hashtable_get_string(bgm, "loop"));
hashtable_foreach(bgm, hashtable_iter_free_data, NULL);
hashtable_free(bgm);
}
} else {
imus->loop = load_mix_music(path);
}
if(!imus->loop) {
assert(imus->intro == NULL);
free(imus);
mus = NULL;
log_warn("Failed to load bgm '%s'", path);
}
return mus;
}
@ -50,6 +79,9 @@ void* load_music_end(void *opaque, const char *path, unsigned int flags) {
void unload_music(void *vmus) {
Music *mus = vmus;
Mix_FreeMusic((Mix_Music*)mus->impl);
MixerInternalMusic *imus = mus->impl;
Mix_FreeMusic(imus->intro);
Mix_FreeMusic(imus->loop);
free(mus->impl);
free(mus);
}

View file

@ -13,11 +13,8 @@
#include "sfx.h"
#include "audio_mixer.h"
char* audio_mixer_sound_path(const char *prefix, const char *name);
bool audio_mixer_check_sound_path(const char *path, bool isbgm);
char* sound_path(const char *name) {
return audio_mixer_sound_path(SFX_PATH_PREFIX, name);
return audio_mixer_sound_path(SFX_PATH_PREFIX, name, true);
}
bool check_sound_path(const char *path) {
@ -35,7 +32,7 @@ void* load_sound_begin(const char *path, unsigned int flags) {
Mix_Chunk *sound = Mix_LoadWAV_RW(rwops, true);
if(!sound) {
log_warn("Mix_LoadWAV() failed: %s", Mix_GetError());
log_warn("Mix_LoadWAV_RW() failed: %s", Mix_GetError());
return NULL;
}