mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-09-30 10:48:21 +03:00
SDL: Add SDL3 BGM backend
Add an owner-aware music track shared by the SDL3 BGM, CD, and MIDI backends. Use it to preserve exclusive music playback while moving BGM loading, looping, fades, and volume control to SDL3_mixer.
This commit is contained in:
+1
-1
@@ -109,7 +109,7 @@ elseif (XSYSTEM35_SDL_VERSION STREQUAL "3")
|
||||
target_sources(xsystem35 PRIVATE
|
||||
pcm.sdl3mixer.c
|
||||
sdl3_mixer_backend.c
|
||||
bgm.sdlmixer.c)
|
||||
bgm.sdl3mixer.c)
|
||||
target_compile_definitions(xsystem35 PRIVATE HAVE_SDL3_MIXER_BACKEND)
|
||||
else()
|
||||
target_sources(xsystem35 PRIVATE pcm.sdlmixer.c bgm.sdlmixer.c)
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* bgm.sdl3mixer.c: BGM (*BA.ALD) playback using SDL3_mixer
|
||||
*
|
||||
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
|
||||
* 1998- <masaki-c@is.aist-nara.ac.jp>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ald_manager.h"
|
||||
#include "audio_meta.h"
|
||||
#include "bgm.h"
|
||||
#include "music_private.h"
|
||||
#include "nact.h"
|
||||
#include "sdl3_mixer_backend.h"
|
||||
#include "system.h"
|
||||
|
||||
static DRIFILETYPE dri_type;
|
||||
static int base_no;
|
||||
static int current_no;
|
||||
static int current_vol = 100;
|
||||
static uint32_t start_time;
|
||||
|
||||
static int clamp_volume(int volume)
|
||||
{
|
||||
if (volume < 0)
|
||||
return 0;
|
||||
if (volume > 100)
|
||||
return 100;
|
||||
return volume;
|
||||
}
|
||||
|
||||
static float music_gain(int volume)
|
||||
{
|
||||
float gain = clamp_volume(volume) / 100.0f;
|
||||
return gain * clamp_volume(prv.volval[BGM_VOLVAL_CH]) / 100.0f;
|
||||
}
|
||||
|
||||
static void apply_music_volume(int volume)
|
||||
{
|
||||
current_vol = volume;
|
||||
sdl3_mixer_set_music_gain(SDL3_MIXER_MUSIC_BGM,
|
||||
music_gain(current_vol));
|
||||
}
|
||||
|
||||
void musbgm_reapply_valance(void)
|
||||
{
|
||||
apply_music_volume(current_vol);
|
||||
}
|
||||
|
||||
static void free_music(void)
|
||||
{
|
||||
current_no = 0;
|
||||
sdl3_mixer_stop_music(SDL3_MIXER_MUSIC_BGM, 0);
|
||||
}
|
||||
|
||||
static MIX_Audio *load_music(int no)
|
||||
{
|
||||
free_music();
|
||||
int ald_no = no + base_no - 1;
|
||||
dridata *dfile = ald_getdata(dri_type, ald_no);
|
||||
if (!dfile) {
|
||||
WARNING("Failed to open BGM %d", ald_no);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MIX_Audio *audio = sdl3_mixer_load_music_memory(
|
||||
dfile->data, dfile->size);
|
||||
ald_freedata(dfile);
|
||||
if (!audio)
|
||||
WARNING("Failed to load BGM %d: %s", ald_no, SDL_GetError());
|
||||
return audio;
|
||||
}
|
||||
|
||||
bool musbgm_init(DRIFILETYPE type, int base)
|
||||
{
|
||||
dri_type = type;
|
||||
base_no = base;
|
||||
if (type == DRIFILE_BGM)
|
||||
return bgi_read(nact->files.bgi);
|
||||
return true;
|
||||
}
|
||||
|
||||
void musbgm_exit(void)
|
||||
{
|
||||
free_music();
|
||||
}
|
||||
|
||||
void musbgm_reset(void)
|
||||
{
|
||||
free_music();
|
||||
}
|
||||
|
||||
bool musbgm_play(int no, int time, int volume, int loop_count)
|
||||
{
|
||||
MIX_Audio *audio = load_music(no);
|
||||
if (!audio)
|
||||
return false;
|
||||
|
||||
int loops = loop_count == 0 ? -1 : loop_count - 1;
|
||||
current_vol = volume;
|
||||
if (!sdl3_mixer_play_music(SDL3_MIXER_MUSIC_BGM, audio,
|
||||
loops, time * 10, music_gain(current_vol)))
|
||||
return false;
|
||||
current_no = no;
|
||||
start_time = sys_get_ticks();
|
||||
return true;
|
||||
}
|
||||
|
||||
void musbgm_stop(int no, int time)
|
||||
{
|
||||
if (no == current_no)
|
||||
sdl3_mixer_stop_music(SDL3_MIXER_MUSIC_BGM, time * 10);
|
||||
}
|
||||
|
||||
void musbgm_fade(int no, int time, int volume)
|
||||
{
|
||||
(void)time;
|
||||
if (no == current_no)
|
||||
apply_music_volume(volume);
|
||||
}
|
||||
|
||||
int musbgm_getpos(int no)
|
||||
{
|
||||
if (!musbgm_isplaying(no))
|
||||
return 0;
|
||||
return (sys_get_ticks() - start_time) / 10;
|
||||
}
|
||||
|
||||
int musbgm_getlen(int no)
|
||||
{
|
||||
bgi_t *bgi = bgi_find(no);
|
||||
return bgi ? bgi->len / 441 : 0;
|
||||
}
|
||||
|
||||
bool musbgm_isplaying(int no)
|
||||
{
|
||||
return no == current_no &&
|
||||
sdl3_mixer_music_active(SDL3_MIXER_MUSIC_BGM);
|
||||
}
|
||||
|
||||
void musbgm_stopall(int time)
|
||||
{
|
||||
musbgm_stop(current_no, time);
|
||||
}
|
||||
|
||||
void musbgm_wait(int no, int timeout)
|
||||
{
|
||||
while (timeout-- > 0 && musbgm_isplaying(no))
|
||||
SDL_Delay(10);
|
||||
}
|
||||
@@ -5,6 +5,27 @@
|
||||
#define SAMPLE_RATE 44100
|
||||
|
||||
static MIX_Mixer *mixer;
|
||||
static MIX_Track *music_track;
|
||||
static MIX_Audio *music_audio;
|
||||
static enum sdl3_mixer_music_owner music_owner;
|
||||
|
||||
static void clear_music(void)
|
||||
{
|
||||
if (!music_audio)
|
||||
return;
|
||||
MIX_StopTrack(music_track, 0);
|
||||
MIX_SetTrackAudio(music_track, NULL);
|
||||
MIX_DestroyAudio(music_audio);
|
||||
music_audio = NULL;
|
||||
music_owner = SDL3_MIXER_MUSIC_NONE;
|
||||
}
|
||||
|
||||
static void reap_finished_music(void)
|
||||
{
|
||||
if (music_audio && !MIX_TrackPlaying(music_track) &&
|
||||
!MIX_TrackPaused(music_track))
|
||||
clear_music();
|
||||
}
|
||||
|
||||
bool sdl3_mixer_backend_init(int audio_buffer_size)
|
||||
{
|
||||
@@ -33,6 +54,14 @@ bool sdl3_mixer_backend_init(int audio_buffer_size)
|
||||
MIX_Quit();
|
||||
return false;
|
||||
}
|
||||
music_track = MIX_CreateTrack(mixer);
|
||||
if (!music_track) {
|
||||
WARNING("Cannot create music track: %s", SDL_GetError());
|
||||
MIX_DestroyMixer(mixer);
|
||||
mixer = NULL;
|
||||
MIX_Quit();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -40,6 +69,9 @@ void sdl3_mixer_backend_exit(void)
|
||||
{
|
||||
if (!mixer)
|
||||
return;
|
||||
clear_music();
|
||||
MIX_DestroyTrack(music_track);
|
||||
music_track = NULL;
|
||||
MIX_DestroyMixer(mixer);
|
||||
mixer = NULL;
|
||||
MIX_Quit();
|
||||
@@ -49,3 +81,90 @@ MIX_Mixer *sdl3_mixer_backend_get(void)
|
||||
{
|
||||
return mixer;
|
||||
}
|
||||
|
||||
MIX_Audio *sdl3_mixer_load_music_memory(const void *data, size_t size)
|
||||
{
|
||||
if (!mixer)
|
||||
return NULL;
|
||||
SDL_IOStream *io = SDL_IOFromConstMem(data, size);
|
||||
if (!io)
|
||||
return NULL;
|
||||
return MIX_LoadAudio_IO(mixer, io, false, true);
|
||||
}
|
||||
|
||||
MIX_Audio *sdl3_mixer_load_music_file(const char *path)
|
||||
{
|
||||
return mixer ? MIX_LoadAudio(mixer, path, false) : NULL;
|
||||
}
|
||||
|
||||
bool sdl3_mixer_play_music(enum sdl3_mixer_music_owner owner,
|
||||
MIX_Audio *audio, int loops, int fade_in_ms, float gain)
|
||||
{
|
||||
if (!music_track || !audio || owner == SDL3_MIXER_MUSIC_NONE) {
|
||||
MIX_DestroyAudio(audio);
|
||||
return false;
|
||||
}
|
||||
|
||||
clear_music();
|
||||
if (!MIX_SetTrackAudio(music_track, audio)) {
|
||||
MIX_DestroyAudio(audio);
|
||||
return false;
|
||||
}
|
||||
music_audio = audio;
|
||||
music_owner = owner;
|
||||
|
||||
SDL_PropertiesID props = SDL_CreateProperties();
|
||||
bool success = props &&
|
||||
MIX_SetTrackGain(music_track, gain) &&
|
||||
SDL_SetNumberProperty(props, MIX_PROP_PLAY_LOOPS_NUMBER, loops) &&
|
||||
SDL_SetNumberProperty(props,
|
||||
MIX_PROP_PLAY_FADE_IN_MILLISECONDS_NUMBER, fade_in_ms) &&
|
||||
MIX_PlayTrack(music_track, props);
|
||||
if (props)
|
||||
SDL_DestroyProperties(props);
|
||||
if (!success)
|
||||
clear_music();
|
||||
return success;
|
||||
}
|
||||
|
||||
void sdl3_mixer_stop_music(enum sdl3_mixer_music_owner owner, int fade_out_ms)
|
||||
{
|
||||
reap_finished_music();
|
||||
if (music_owner != owner)
|
||||
return;
|
||||
if (fade_out_ms <= 0) {
|
||||
clear_music();
|
||||
return;
|
||||
}
|
||||
Sint64 frames = MIX_TrackMSToFrames(music_track, fade_out_ms);
|
||||
if (frames <= 0 || !MIX_StopTrack(music_track, frames))
|
||||
clear_music();
|
||||
}
|
||||
|
||||
void sdl3_mixer_pause_music(enum sdl3_mixer_music_owner owner)
|
||||
{
|
||||
reap_finished_music();
|
||||
if (music_owner == owner)
|
||||
MIX_PauseTrack(music_track);
|
||||
}
|
||||
|
||||
void sdl3_mixer_resume_music(enum sdl3_mixer_music_owner owner)
|
||||
{
|
||||
reap_finished_music();
|
||||
if (music_owner == owner)
|
||||
MIX_ResumeTrack(music_track);
|
||||
}
|
||||
|
||||
bool sdl3_mixer_music_active(enum sdl3_mixer_music_owner owner)
|
||||
{
|
||||
reap_finished_music();
|
||||
return music_owner == owner &&
|
||||
(MIX_TrackPlaying(music_track) || MIX_TrackPaused(music_track));
|
||||
}
|
||||
|
||||
void sdl3_mixer_set_music_gain(enum sdl3_mixer_music_owner owner, float gain)
|
||||
{
|
||||
reap_finished_music();
|
||||
if (music_owner == owner)
|
||||
MIX_SetTrackGain(music_track, gain);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,27 @@
|
||||
#include "portab.h"
|
||||
#include "sdl_mixer_compat.h"
|
||||
|
||||
enum sdl3_mixer_music_owner {
|
||||
SDL3_MIXER_MUSIC_NONE,
|
||||
SDL3_MIXER_MUSIC_BGM,
|
||||
SDL3_MIXER_MUSIC_CD,
|
||||
SDL3_MIXER_MUSIC_MIDI,
|
||||
};
|
||||
|
||||
bool sdl3_mixer_backend_init(int audio_buffer_size);
|
||||
void sdl3_mixer_backend_exit(void);
|
||||
MIX_Mixer *sdl3_mixer_backend_get(void);
|
||||
|
||||
MIX_Audio *sdl3_mixer_load_music_memory(const void *data, size_t size);
|
||||
MIX_Audio *sdl3_mixer_load_music_file(const char *path);
|
||||
|
||||
/* play_music takes ownership of audio, including when playback fails. */
|
||||
bool sdl3_mixer_play_music(enum sdl3_mixer_music_owner owner,
|
||||
MIX_Audio *audio, int loops, int fade_in_ms, float gain);
|
||||
void sdl3_mixer_stop_music(enum sdl3_mixer_music_owner owner, int fade_out_ms);
|
||||
void sdl3_mixer_pause_music(enum sdl3_mixer_music_owner owner);
|
||||
void sdl3_mixer_resume_music(enum sdl3_mixer_music_owner owner);
|
||||
bool sdl3_mixer_music_active(enum sdl3_mixer_music_owner owner);
|
||||
void sdl3_mixer_set_music_gain(enum sdl3_mixer_music_owner owner, float gain);
|
||||
|
||||
#endif /* XSYSTEM35_SDL3_MIXER_BACKEND_H */
|
||||
|
||||
Reference in New Issue
Block a user