Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions MarathonRecomp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ set(MARATHON_RECOMP_APU_CXX_SOURCES
"apu/audio.cpp"
"apu/xma_decoder.cpp"
"apu/embedded_player.cpp"
"apu/driver/sdl2_driver.cpp"
"apu/driver/sdl3_driver.cpp"
)

set(MARATHON_RECOMP_HID_CXX_SOURCES
Expand Down Expand Up @@ -200,7 +200,7 @@ set(MARATHON_RECOMP_UTILS_CXX_SOURCES
)

set(MARATHON_RECOMP_THIRDPARTY_SOURCES
"${MARATHON_RECOMP_THIRDPARTY_ROOT}/imgui/backends/imgui_impl_sdl2.cpp"
"${MARATHON_RECOMP_THIRDPARTY_ROOT}/imgui/backends/imgui_impl_sdl3.cpp"
"${MARATHON_RECOMP_THIRDPARTY_ROOT}/imgui/imgui.cpp"
"${MARATHON_RECOMP_THIRDPARTY_ROOT}/imgui/imgui_demo.cpp"
"${MARATHON_RECOMP_THIRDPARTY_ROOT}/imgui/imgui_draw.cpp"
Expand Down Expand Up @@ -410,8 +410,8 @@ target_link_libraries(MarathonRecomp PRIVATE
nfd::nfd
o1heap
XenonUtils
SDL2::SDL2-static
SDL2_mixer
SDL3::SDL3-static
SDL3_mixer::SDL3_mixer
tomlplusplus::tomlplusplus
MarathonRecompLib
xxHash::xxhash
Expand Down
2 changes: 1 addition & 1 deletion MarathonRecomp/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ PPC_FUNC(sub_825EA610)
if (std::this_thread::get_id() == g_mainThreadId)
{
SDL_PumpEvents();
SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
SDL_FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST);
GameWindow::Update();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,46 @@

static PPCFunc* g_clientCallback{};
static uint32_t g_clientCallbackParam{}; // pointer in guest memory
static SDL_AudioDeviceID g_audioDevice{};
static SDL_AudioStream* g_audioStream{};
static bool g_downMixToStereo;

static void CreateAudioDevice()
{
if (g_audioDevice != NULL)
SDL_CloseAudioDevice(g_audioDevice);
if (g_audioStream != nullptr)
{
SDL_DestroyAudioStream(g_audioStream);
g_audioStream = nullptr;
}

bool surround = Config::ChannelConfiguration == EChannelConfiguration::Surround;
int allowedChanges = surround ? SDL_AUDIO_ALLOW_CHANNELS_CHANGE : 0;

SDL_AudioSpec desired{}, obtained{};
SDL_AudioSpec deviceSpec{};
if (surround && SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &deviceSpec, nullptr))
surround = deviceSpec.channels >= XAUDIO_NUM_CHANNELS;

SDL_AudioSpec desired{};
desired.freq = XAUDIO_SAMPLES_HZ;
desired.format = AUDIO_F32SYS;
desired.format = SDL_AUDIO_F32;
desired.channels = surround ? XAUDIO_NUM_CHANNELS : 2;
desired.samples = XAUDIO_NUM_SAMPLES;
g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, allowedChanges);

if (obtained.channels != 2 && obtained.channels != XAUDIO_NUM_CHANNELS) // This check may fail only when surround sound is enabled.
{
SDL_CloseAudioDevice(g_audioDevice);
g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0);
}
g_audioStream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &desired, nullptr, nullptr);

if (!g_audioDevice)
if (!g_audioStream)
LOGFN_ERROR("Failed to open audio device: {}", SDL_GetError());

g_downMixToStereo = (obtained.channels == 2);
g_downMixToStereo = (desired.channels == 2);
}

void XAudioInitializeSystem()
{
#ifdef _WIN32
// Force wasapi on Windows.
SDL_setenv("SDL_AUDIODRIVER", "wasapi", true);
SDL_SetHint(SDL_HINT_AUDIO_DRIVER, "wasapi");
#endif

SDL_SetHint(SDL_HINT_AUDIO_CATEGORY, "playback");
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "Marathon Recompiled");
SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING, "Marathon Recompiled");

if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
if (!SDL_InitSubSystem(SDL_INIT_AUDIO))
{
LOGFN_ERROR("Failed to init audio subsystem: {}", SDL_GetError());
return;
Expand All @@ -69,11 +68,11 @@ static void AudioThread()

while (!g_audioThreadShouldExit)
{
uint32_t queuedAudioSize = SDL_GetQueuedAudioSize(g_audioDevice);
int queuedAudioSize = SDL_GetAudioStreamQueued(g_audioStream);
constexpr size_t MAX_LATENCY = 10;
const size_t callbackAudioSize = channels * XAUDIO_NUM_SAMPLES * sizeof(float);

if ((queuedAudioSize / callbackAudioSize) <= MAX_LATENCY)
if (queuedAudioSize >= 0 && (queuedAudioSize / callbackAudioSize) <= MAX_LATENCY)
{
ctx.ppcContext.r3.u32 = g_clientCallbackParam;
g_clientCallback(ctx.ppcContext, g_memory.base);
Expand All @@ -92,7 +91,7 @@ static void AudioThread()

static void CreateAudioThread()
{
SDL_PauseAudioDevice(g_audioDevice, 0);
SDL_ResumeAudioStreamDevice(g_audioStream);
g_audioThreadShouldExit = false;
g_audioThread = std::make_unique<std::thread>(AudioThread);
}
Expand Down Expand Up @@ -143,7 +142,7 @@ void XAudioSubmitFrame(void* samples)
audioFrames[i * 2 + 1] = isnan(samp1) ? 0.0f : samp1;
}

SDL_QueueAudio(g_audioDevice, &audioFrames, sizeof(audioFrames));
SDL_PutAudioStreamData(g_audioStream, &audioFrames, sizeof(audioFrames));
}
else
{
Expand All @@ -158,7 +157,7 @@ void XAudioSubmitFrame(void* samples)
}
}

SDL_QueueAudio(g_audioDevice, &audioFrames, sizeof(audioFrames));
SDL_PutAudioStreamData(g_audioStream, &audioFrames, sizeof(audioFrames));
}
}

Expand Down
76 changes: 51 additions & 25 deletions MarathonRecomp/apu/embedded_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@ enum class EmbeddedSound

struct EmbeddedSoundData
{
Mix_Chunk* chunk{};
MIX_Audio* audio{};
};

static constexpr size_t EMBEDDED_TRACK_COUNT = 8;

static MIX_Mixer* g_mixer;
static std::array<MIX_Track*, EMBEDDED_TRACK_COUNT> g_tracks = {};

static std::array<EmbeddedSoundData, size_t(EmbeddedSound::Count)> g_embeddedSoundData = {};
static const std::unordered_map<std::string_view, EmbeddedSound> g_embeddedSoundMap =
{
Expand All @@ -40,12 +45,12 @@ static const std::unordered_map<std::string_view, EmbeddedSound> g_embeddedSound
{ "cannot_deside", EmbeddedSound::CannotDeside },
};

static size_t g_channelIndex;
static size_t g_trackIndex;

static void PlayEmbeddedSound(EmbeddedSound s)
{
EmbeddedSoundData &data = g_embeddedSoundData[size_t(s)];
if (data.chunk == nullptr)
if (data.audio == nullptr)
{
// The sound hasn't been created yet, create it and pick it.
const void *soundData = nullptr;
Expand Down Expand Up @@ -85,25 +90,41 @@ static void PlayEmbeddedSound(EmbeddedSound s)
return;
}

data.chunk = Mix_LoadWAV_RW(SDL_RWFromConstMem(soundData, soundDataSize), 1);
data.audio = MIX_LoadAudio_IO(g_mixer, SDL_IOFromConstMem(soundData, soundDataSize), true, true);
}

Mix_VolumeChunk(data.chunk, (Config::MasterVolume * Config::EffectsVolume * EmbeddedPlayer::EFFECTS_VOLUME) * MIX_MAX_VOLUME);
Mix_PlayChannel(g_channelIndex % MIX_CHANNELS, data.chunk, 0);
++g_channelIndex;

MIX_Track *track = g_tracks[g_trackIndex % EMBEDDED_TRACK_COUNT];
++g_trackIndex;

MIX_SetTrackGain(track, Config::MasterVolume * Config::EffectsVolume * EmbeddedPlayer::EFFECTS_VOLUME);
MIX_SetTrackAudio(track, data.audio);
MIX_PlayTrack(track, 0);
}

static Mix_Music* g_installerMusic;
static MIX_Audio* g_installerMusic;
static MIX_Track* g_musicTrack;

void EmbeddedPlayer::Init()
void EmbeddedPlayer::Init()
{
Mix_OpenAudio(XAUDIO_SAMPLES_HZ, AUDIO_F32SYS, 2, 4096);
g_installerMusic = Mix_LoadMUS_RW(SDL_RWFromConstMem(g_installer_music, sizeof(g_installer_music)), 1);
MIX_Init();

SDL_AudioSpec spec{};
spec.freq = XAUDIO_SAMPLES_HZ;
spec.format = SDL_AUDIO_F32;
spec.channels = 2;
g_mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec);

for (MIX_Track *&track : g_tracks)
track = MIX_CreateTrack(g_mixer);

g_installerMusic = MIX_LoadAudio_IO(g_mixer, SDL_IOFromConstMem(g_installer_music, sizeof(g_installer_music)), false, true);
g_musicTrack = MIX_CreateTrack(g_mixer);
MIX_SetTrackAudio(g_musicTrack, g_installerMusic);

s_isActive = true;
}

void EmbeddedPlayer::Play(const char *name)
void EmbeddedPlayer::Play(const char *name)
{
assert(s_isActive && "Playback shouldn't be requested if the Embedded Player isn't active.");

Expand All @@ -118,32 +139,37 @@ void EmbeddedPlayer::Play(const char *name)

void EmbeddedPlayer::PlayMusic()
{
if (!Mix_PlayingMusic())
if (!MIX_TrackPlaying(g_musicTrack))
{
Mix_PlayMusic(g_installerMusic, INT_MAX);
Mix_VolumeMusic(Config::MasterVolume * Config::MusicVolume * MUSIC_VOLUME * MIX_MAX_VOLUME);
SDL_PropertiesID options = SDL_CreateProperties();
SDL_SetNumberProperty(options, MIX_PROP_PLAY_LOOPS_NUMBER, -1);

MIX_SetTrackGain(g_musicTrack, Config::MasterVolume * Config::MusicVolume * MUSIC_VOLUME);
MIX_PlayTrack(g_musicTrack, options);

SDL_DestroyProperties(options);
}
}

void EmbeddedPlayer::FadeOutMusic()
{
if (Mix_PlayingMusic())
Mix_FadeOutMusic(1000);
if (MIX_TrackPlaying(g_musicTrack))
MIX_StopTrack(g_musicTrack, MIX_TrackMSToFrames(g_musicTrack, 1000));
}

void EmbeddedPlayer::Shutdown()
void EmbeddedPlayer::Shutdown()
{
MIX_DestroyMixer(g_mixer);

for (EmbeddedSoundData &data : g_embeddedSoundData)
{
if (data.chunk != nullptr)
Mix_FreeChunk(data.chunk);
if (data.audio != nullptr)
MIX_DestroyAudio(data.audio);
}

Mix_HaltMusic();
Mix_FreeMusic(g_installerMusic);
MIX_DestroyAudio(g_installerMusic);

Mix_CloseAudio();
Mix_Quit();
MIX_Quit();

s_isActive = false;
}
4 changes: 2 additions & 2 deletions MarathonRecomp/gpu/video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1590,7 +1590,7 @@ static void CreateImGuiBackend()
OptionsMenu::Init();
InstallerWizard::Init();

ImGui_ImplSDL2_InitForOther(GameWindow::s_pWindow);
ImGui_ImplSDL3_InitForOther(GameWindow::s_pWindow);

#ifdef ENABLE_IM_FONT_ATLAS_SNAPSHOT
g_imFontTexture = LoadTexture(
Expand Down Expand Up @@ -2872,7 +2872,7 @@ static void DrawFPS()

static void DrawImGui()
{
ImGui_ImplSDL2_NewFrame();
ImGui_ImplSDL3_NewFrame();

auto& io = ImGui::GetIO();
io.DisplaySize = { float(Video::s_viewportWidth), float(Video::s_viewportHeight) };
Expand Down
Loading
Loading