From 2a6683db82b79ad0066a96e1d82bfa3d6ae51e1c Mon Sep 17 00:00:00 2001 From: scawful Date: Tue, 11 Mar 2025 21:03:38 -0400 Subject: [PATCH] Refactor audio handling in Controller; replace LoadAudioDevice with backend audio initialization and shutdown methods --- src/app/core/controller.cc | 37 ++-------- src/app/core/controller.h | 8 +- src/app/core/platform/backend.h | 125 ++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 35 deletions(-) create mode 100644 src/app/core/platform/backend.h diff --git a/src/app/core/controller.cc b/src/app/core/controller.cc index b459102b..475f769f 100644 --- a/src/app/core/controller.cc +++ b/src/app/core/controller.cc @@ -22,7 +22,12 @@ absl::Status Controller::OnEntry(std::string filename) { RETURN_IF_ERROR(CreateWindow()) RETURN_IF_ERROR(CreateRenderer()) RETURN_IF_ERROR(CreateGuiContext()) - RETURN_IF_ERROR(LoadAudioDevice()) + backend_.init_audio(); + // cast to Sdl2backend to access audio buffer and device + auto &sdl2_backend = static_cast(backend_); + editor_manager_.emulator().set_audio_buffer( + sdl2_backend.audio_buffer().get()); + editor_manager_.emulator().set_audio_device_id(sdl2_backend.audio_device()); Initialize(filename); return absl::OkStatus(); } @@ -108,10 +113,6 @@ absl::Status Controller::OnLoad() { return absl::OkStatus(); } - - - - void Controller::DoRender() const { ImGui::Render(); SDL_RenderClear(Renderer::GetInstance().renderer()); @@ -121,8 +122,7 @@ void Controller::DoRender() const { } void Controller::OnExit() { - SDL_PauseAudioDevice(audio_device_, 1); - SDL_CloseAudioDevice(audio_device_); + backend_.shutdown_audio(); ImGui_ImplSDLRenderer2_Shutdown(); ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); @@ -180,32 +180,11 @@ absl::Status Controller::CreateGuiContext() { gui::ColorsYaze(); // Build a new ImGui frame - ImGui_ImplSDLRenderer2_NewFrame(); - ImGui_ImplSDL2_NewFrame(); + backend_.new_frame(); return absl::OkStatus(); } -absl::Status Controller::LoadAudioDevice() { - SDL_AudioSpec want, have; - SDL_memset(&want, 0, sizeof(want)); - want.freq = audio_frequency_; - want.format = AUDIO_S16; - want.channels = 2; - want.samples = 2048; - want.callback = NULL; // Uses the queue - audio_device_ = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0); - if (audio_device_ == 0) { - return absl::InternalError( - absl::StrFormat("Failed to open audio: %s\n", SDL_GetError())); - } - audio_buffer_ = std::make_shared(audio_frequency_ / 50 * 4); - SDL_PauseAudioDevice(audio_device_, 0); - editor_manager_.emulator().set_audio_buffer(audio_buffer_.get()); - editor_manager_.emulator().set_audio_device_id(audio_device_); - return absl::OkStatus(); -} - absl::Status Controller::LoadConfigFiles() { // Create and load a dotfile for the application // This will store the user's preferences and settings diff --git a/src/app/core/controller.h b/src/app/core/controller.h index 79d26e1b..a9213f1e 100644 --- a/src/app/core/controller.h +++ b/src/app/core/controller.h @@ -6,9 +6,9 @@ #include #include "absl/status/status.h" +#include "app/core/platform/backend.h" #include "app/core/platform/file_dialog.h" #include "app/core/platform/renderer.h" -#include "app/editor/editor.h" #include "app/editor/editor_manager.h" #include "imgui/backends/imgui_impl_sdl2.h" #include "imgui/backends/imgui_impl_sdlrenderer2.h" @@ -39,7 +39,6 @@ class Controller { absl::Status CreateWindow(); absl::Status CreateRenderer(); absl::Status CreateGuiContext(); - absl::Status LoadAudioDevice(); absl::Status LoadConfigFiles(); auto window() -> SDL_Window * { return window_.get(); } @@ -51,11 +50,8 @@ class Controller { bool active_ = false; editor::EditorManager editor_manager_; - - int audio_frequency_ = 48000; - SDL_AudioDeviceID audio_device_; - std::shared_ptr audio_buffer_; std::shared_ptr window_; + core::PlatformBackend backend_; }; } // namespace core diff --git a/src/app/core/platform/backend.h b/src/app/core/platform/backend.h new file mode 100644 index 00000000..1159b426 --- /dev/null +++ b/src/app/core/platform/backend.h @@ -0,0 +1,125 @@ +#ifndef YAZE_APP_CORE_PLATFORM_BACKEND_H +#define YAZE_APP_CORE_PLATFORM_BACKEND_H + +#include + +#include +#include + +#include "app/core/platform/renderer.h" +#include "app/core/platform/sdl_deleter.h" +#include "imgui/backends/imgui_impl_sdl2.h" +#include "imgui/backends/imgui_impl_sdlrenderer2.h" + +namespace yaze { +namespace core { + +template +class PlatformBackend { + public: + PlatformBackend() = default; + ~PlatformBackend() = default; + + void init() { static_cast(this)->init(); } + void init_audio() { static_cast(this)->init_audio(); } + void shutdown_audio() { static_cast(this)->shutdown_audio(); } + void shutdown() { static_cast(this)->shutdown(); } + void new_frame() { static_cast(this)->new_frame(); } + void render() { static_cast(this)->render(); } +}; + +class Sdl2Backend : public PlatformBackend { + public: + Sdl2Backend() = default; + ~Sdl2Backend() = default; + + void init() { + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != + 0) { + throw std::runtime_error("Failed to initialize SDL2"); + } + + SDL_DisplayMode display_mode; + SDL_GetCurrentDisplayMode(0, &display_mode); + int screen_width = display_mode.w * 0.8; + int screen_height = display_mode.h * 0.8; + + window = std::unique_ptr( + SDL_CreateWindow("Yet Another Zelda3 Editor", // window title + SDL_WINDOWPOS_UNDEFINED, // initial x position + SDL_WINDOWPOS_UNDEFINED, // initial y position + screen_width, // width, in pixels + screen_height, // height, in pixels + SDL_WINDOW_RESIZABLE), + core::SDL_Deleter()); + if (!window) { + throw std::runtime_error("Failed to create window"); + } + + if (!Renderer::GetInstance().CreateRenderer(window.get()).ok()) { + throw std::runtime_error("Failed to create renderer"); + } + + ImGui_ImplSDL2_InitForSDLRenderer(window.get(), + Renderer::GetInstance().renderer()); + ImGui_ImplSDLRenderer2_Init(Renderer::GetInstance().renderer()); + } + + void init_audio() { + const int audio_frequency = 48000; + SDL_AudioSpec want, have; + SDL_memset(&want, 0, sizeof(want)); + want.freq = audio_frequency; + want.format = AUDIO_S16; + want.channels = 2; + want.samples = 2048; + want.callback = NULL; // Uses the queue + audio_device_ = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0); + if (audio_device_ == 0) { + throw std::runtime_error( + absl::StrFormat("Failed to open audio: %s\n", SDL_GetError())); + } + audio_buffer_ = std::make_shared(audio_frequency / 50 * 4); + SDL_PauseAudioDevice(audio_device_, 0); + } + + void shutdown_audio() { + SDL_PauseAudioDevice(audio_device_, 1); + SDL_CloseAudioDevice(audio_device_); + } + + void shutdown() { + ImGui_ImplSDL2_Shutdown(); + ImGui_ImplSDLRenderer2_Shutdown(); + SDL_DestroyRenderer(Renderer::GetInstance().renderer()); + SDL_DestroyWindow(window.get()); + SDL_Quit(); + } + + void new_frame() { + ImGui_ImplSDLRenderer2_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + } + + void render() { + ImGui::Render(); + SDL_RenderClear(Renderer::GetInstance().renderer()); + ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), + Renderer::GetInstance().renderer()); + SDL_RenderPresent(Renderer::GetInstance().renderer()); + } + + auto window_ptr() -> SDL_Window * { return window.get(); } + auto audio_device() -> SDL_AudioDeviceID { return audio_device_; } + auto audio_buffer() -> std::shared_ptr { return audio_buffer_; } + + private: + SDL_AudioDeviceID audio_device_; + std::shared_ptr audio_buffer_; + std::unique_ptr window; +}; + +} // namespace core +} // namespace yaze + +#endif // YAZE_APP_CORE_PLATFORM_BACKEND_H