diff --git a/.gitmodules b/.gitmodules index 6186f20..7fb3998 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "third_party/rtaudio"] path = third_party/rtaudio url = https://github.com/thestk/rtaudio.git +[submodule "third_party/glfw"] + path = third_party/glfw + url = https://github.com/glfw/glfw.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 5176cf2..aa660d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,4 +36,5 @@ add_subdirectory(third_party/rtaudio) add_subdirectory(third_party/spdlog) add_subdirectory(third_party/mempool) add_subdirectory(third_party/taskflow) +add_subdirectory(third_party/glfw) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 7af254c..598d3f2 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -8,10 +8,10 @@ retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} ALL_FILES) add_library(${PROJECT_NAME} SHARED ${ALL_FILES}) -target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} rtaudio spdlog mempool Taskflow) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} rtaudio spdlog mempool Taskflow) -target_link_libraries(${PROJECT_NAME} PUBLIC rtaudio spdlog mempool Taskflow) +target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(${PROJECT_NAME} PUBLIC rtaudio spdlog mempool Taskflow glfw) add_definitions(-Dcore_EXPORTS) @@ -26,9 +26,9 @@ endif () # platform micros if (WIN32) - target_compile_definitions(${PROJECT_NAME} PUBLIC PLATFORM_WINDOWS=1 PLATFORM_MACOS=0 PLATFORM_LINUX=0) + target_compile_definitions(${PROJECT_NAME} PUBLIC PLATFORM_WINDOWS=1 PLATFORM_MACOS=0 PLATFORM_LINUX=0 GLFW_EXPOSE_NATIVE_WIN32) elseif(APPLE) - target_compile_definitions(${PROJECT_NAME} PUBLIC PLATFORM_WINDOWS=0 PLATFORM_MACOS=1 PLATFORM_LINUX=0) + target_compile_definitions(${PROJECT_NAME} PUBLIC PLATFORM_WINDOWS=0 PLATFORM_MACOS=1 PLATFORM_LINUX=0 GLFW_EXPOSE_NATIVE_COCOA) elseif(UNIX AND NOT APPLE) - target_compile_definitions(${PROJECT_NAME} PUBLIC PLATFORM_WINDOWS=0 PLATFORM_MACOS=0 PLATFORM_LINUX=1) + target_compile_definitions(${PROJECT_NAME} PUBLIC PLATFORM_WINDOWS=0 PLATFORM_MACOS=0 PLATFORM_LINUX=1 GLFW_EXPOSE_NATIVE_X11) endif() diff --git a/core/audio/device/audio_device_manager.cpp b/core/audio/device/audio_device_manager.cpp index 9979a95..893dc52 100644 --- a/core/audio/device/audio_device_manager.cpp +++ b/core/audio/device/audio_device_manager.cpp @@ -23,6 +23,7 @@ void audio_device_manager::init(singleton_initliazer& initliazer) { audio_ = new RtAudio(); log_all_devices(); output_params_.deviceId = audio_->getDefaultOutputDevice(); + output_params_.deviceId = 131; output_params_.nChannels = get_output_channel_count(); spdlog::info("using output device id: {}", output_params_.deviceId); } diff --git a/core/audio/mixer/mixer.h b/core/audio/mixer/mixer.h index 63a1de2..8d4de91 100644 --- a/core/audio/mixer/mixer.h +++ b/core/audio/mixer/mixer.h @@ -22,6 +22,7 @@ public: dummy_track* create_dummy_track(const std::string& in_name); instrument_track* create_instrument_track(plugin_host* in_instrument); void remove_track(mixer_track* track); + const std::vector& get_tracks() const { return tracks_; } void process(uint32_t in_frames); void reset(); diff --git a/core/audio/mixer/mixer_track.cpp b/core/audio/mixer/mixer_track.cpp index 320d8a6..73c2d2c 100644 --- a/core/audio/mixer/mixer_track.cpp +++ b/core/audio/mixer/mixer_track.cpp @@ -13,7 +13,7 @@ void mixer_track::init() { const uint32_t channel_count = g_audio_device_manager.get_output_channel_count(); buffer.resize(channel_count, g_audio_device_manager.get_buffer_size()); for (int i = 0; i < buffer.get_num_channels(); ++i) { - ui_buffers.emplace_back(g_audio_device_manager.get_buffer_size() * 2); + ui_buffers->emplace_back(g_audio_device_manager.get_buffer_size() * 2); } channel_interface_ = new mixer_channel_interface(this); @@ -52,7 +52,7 @@ void mixer_track::process(uint32_t in_frames) { buffer.multiple(volume); on_processed.broadcast(this); for (int i = 0; i < buffer.get_num_channels(); ++i) { - ui_buffers[i].Push(buffer.get_headers()[i], in_frames); + (*ui_buffers)[i].Push(buffer.get_headers()[i], in_frames); } } diff --git a/core/audio/mixer/mixer_track.h b/core/audio/mixer/mixer_track.h index f683645..3fe8553 100644 --- a/core/audio/mixer/mixer_track.h +++ b/core/audio/mixer/mixer_track.h @@ -20,7 +20,9 @@ struct mixer_track_link { class mixer_track { public: - explicit mixer_track(mixer_track_type in_type) : type_(in_type) {} + explicit mixer_track(mixer_track_type in_type) : type_(in_type) { + ui_buffers = std::make_shared>>(); + } virtual ~mixer_track(); void init(); @@ -41,7 +43,7 @@ public: [[nodiscard]] channel_interface* get_channel_interface() const { return channel_interface_; } audio_buffer buffer; - std::vector> ui_buffers; + std::shared_ptr>> ui_buffers; std::atomic volume = 1.0f; std::vector effects{}; std::vector children{}; diff --git a/core/audio/plugin_host/plugin_host.cpp b/core/audio/plugin_host/plugin_host.cpp index 9c1194a..58d3d00 100644 --- a/core/audio/plugin_host/plugin_host.cpp +++ b/core/audio/plugin_host/plugin_host.cpp @@ -1,6 +1,7 @@ #include "plugin_host.h" #include "audio/mixer/channel_interface.h" +#include "window/window_manager.h" plugin_host::~plugin_host() { delete channel; @@ -11,8 +12,7 @@ void plugin_host::try_open_editor() { return; if (editor_opened) return; - // editor_window = g_window_manager.create_plugin_host_window(this); - // open_editor(editor_window); + create_and_open_editor(); editor_opened = true; } @@ -21,9 +21,8 @@ void plugin_host::try_close_editor() { return; if (editor_opened == false) return; - close_editor(); + destroy_editor(); editor_opened = false; - // g_window_manager.destroy_plugin_host_window(this); } void plugin_host::toggle_editor() { @@ -38,3 +37,12 @@ void plugin_host::toggle_editor() { void plugin_host::init_channel_interface() { channel = new channel_interface(get_input_channels(), get_output_channels()); } + +void plugin_host::create_and_open_editor() { + void* handle = get_window_manager()->create_plugin_window(this); + open_editor(handle); +} + +void plugin_host::destroy_editor() { + get_window_manager()->destroy_plugin_window(this); +} diff --git a/core/audio/plugin_host/plugin_host.h b/core/audio/plugin_host/plugin_host.h index 309299c..398b834 100644 --- a/core/audio/plugin_host/plugin_host.h +++ b/core/audio/plugin_host/plugin_host.h @@ -3,18 +3,20 @@ #include #include #include "extern.h" +#include "misc/delegates.h" class mixer_track; class channel_interface; class CORE_API plugin_host { + friend class window_manager; public: virtual ~plugin_host(); virtual bool load_plugin(const char* path) = 0; virtual void set_enabled(bool enabled) = 0; - virtual bool is_enabled() const = 0; + [[nodiscard]] virtual bool is_enabled() const = 0; virtual void on_update_sample_rate(double sample_rate) = 0; virtual void on_update_buffer_size(int buffer_size) = 0; @@ -30,7 +32,7 @@ public: virtual void idle_editor() {} [[nodiscard]] virtual bool has_editor() const { return false; } - // [[nodiscard]] virtual ImVec2 get_editor_size() const { return ImVec2(0, 0); } + virtual void get_editor_size(uint32_t& width, uint32_t& height) const = 0; [[nodiscard]] virtual std::string load_name() const { return ""; } [[nodiscard]] virtual std::string load_vendor() const { return ""; } @@ -43,6 +45,8 @@ public: std::vector owner_tracks; bool editor_opened = false; protected: - virtual void open_editor() = 0; + void create_and_open_editor(); + void destroy_editor(); + virtual void open_editor(void* window_handle) = 0; virtual void close_editor() = 0; }; diff --git a/core/audio/plugin_host/plugin_host_manager.cpp b/core/audio/plugin_host/plugin_host_manager.cpp index 0a75878..55ed9b2 100644 --- a/core/audio/plugin_host/plugin_host_manager.cpp +++ b/core/audio/plugin_host/plugin_host_manager.cpp @@ -10,6 +10,7 @@ #include "misc/singleton/singleton_manager.h" #include "thread_message/thread_message_hubs.h" #include "vst2/vst2_plugin_host.h" +#include "window/window_manager.h" void plugin_host_manager::init(singleton_initliazer& initliazer) { singleton_t::init(initliazer); diff --git a/core/audio/plugin_host/vst2/vst2_plugin_host.cpp b/core/audio/plugin_host/vst2/vst2_plugin_host.cpp index c2c9884..99055f7 100644 --- a/core/audio/plugin_host/vst2/vst2_plugin_host.cpp +++ b/core/audio/plugin_host/vst2/vst2_plugin_host.cpp @@ -224,13 +224,16 @@ bool vst2_plugin_host::has_editor() const { return effect_->flags & effFlagsHasEditor; } -// ImVec2 vst2_plugin_host::get_editor_size() const { -// ERect* EditorRect = nullptr; -// dispatch(effEditGetRect, 0, 0, &EditorRect); -// if (EditorRect) -// return ImVec2(EditorRect->right - EditorRect->left, EditorRect->bottom - EditorRect->top); -// return ImVec2(0, 0); -// } +void vst2_plugin_host::get_editor_size(uint32_t& width, uint32_t& height) const { + ERect* EditorRect = nullptr; + dispatch(effEditGetRect, 0, 0, &EditorRect); + if (!EditorRect) { + width = height = 0; + return; + } + width = EditorRect->right - EditorRect->left; + height = EditorRect->bottom - EditorRect->top; +} std::string vst2_plugin_host::load_name() const { char buffer[256]; @@ -244,12 +247,10 @@ std::string vst2_plugin_host::load_vendor() const { return buffer; } -void vst2_plugin_host::open_editor() { +void vst2_plugin_host::open_editor(void* window_handle) { if (!has_editor()) return; - // void* window_handle = glfwGetWindowHandle(window); - - // dispatch(effEditOpen, 0, 0, window_handle); + dispatch(effEditOpen, 0, 0, window_handle); } void vst2_plugin_host::close_editor() { diff --git a/core/audio/plugin_host/vst2/vst2_plugin_host.h b/core/audio/plugin_host/vst2/vst2_plugin_host.h index 7434173..7b4b5b4 100644 --- a/core/audio/plugin_host/vst2/vst2_plugin_host.h +++ b/core/audio/plugin_host/vst2/vst2_plugin_host.h @@ -24,12 +24,13 @@ public: void idle_editor() override; [[nodiscard]] bool has_editor() const override; + void get_editor_size(uint32_t& width, uint32_t& height) const override; // [[nodiscard]] ImVec2 get_editor_size() const override; [[nodiscard]] std::string load_name() const override; [[nodiscard]] std::string load_vendor() const override; protected: - void open_editor() override; + void open_editor(void* window_handle) override; void close_editor() override; private: VstIntPtr dispatch(VstInt32 opcode, VstInt32 index = 0, VstIntPtr value = 0, void* ptr = nullptr, float opt = 0) const; diff --git a/core/window/window_manager.cpp b/core/window/window_manager.cpp new file mode 100644 index 0000000..475ec6f --- /dev/null +++ b/core/window/window_manager.cpp @@ -0,0 +1,96 @@ +#include "window_manager.h" + +#include "audio/plugin_host/plugin_host.h" +#include "audio/plugin_host/plugin_host_manager.h" +#include "GLFW/glfw3.h" +#include "GLFW/glfw3native.h" + +void window_manager::init(singleton_initliazer& initliazer) { + singleton_t::init(initliazer); + auto plugin_host = initliazer.require(); + plugin_host->on_instrument_removed.add_raw(this, &window_manager::destroy_plugin_window); + if (!glfwInit()) + return; + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); +} + +void window_manager::release(singleton_release_guard& release_guard) { + singleton_t::release(release_guard); + release_guard.require_release(); + + windows_.clear(); + host_infos_.clear(); + glfwTerminate(); +} + +std::shared_ptr window_manager::create_window(int width, int height, const char* title) { + auto* window = glfwCreateWindow(width, height, title, nullptr, nullptr); + std::shared_ptr w = std::shared_ptr(window, [](GLFWwindow* w) { + glfwDestroyWindow(w); + }); + windows_.push_back(w); + return w; +} + +void* window_manager::create_plugin_window(plugin_host* host) { + uint32_t width, height; + host->get_editor_size(width, height); + if (width == 0 || height == 0) + return nullptr; + auto w = create_window(width, height, host->name.c_str()); + host_info info; + host_info& window_info = host_infos_[host]; + window_info.window = w; + glfwSetWindowCloseCallback(w.get(), [](GLFWwindow* window) { + get_window_manager()->on_host_window_close(window); + }); +#if PLATFORM_WINDOWS + HWND hwnd = glfwGetWin32Window(w.get()); + return hwnd; +#elif PLATFORM_LINUX + return glfwGetX11Window(w.get()); +#elif PLATFORM_MACOS + return glfwGetCocoaWindow(w.get()); +#endif + return nullptr; +} + +void window_manager::destroy_plugin_window(plugin_host* host) { + const auto& find = host_infos_.find(host); + if (find == host_infos_.end()) { + return; + } + auto window = find->second.window; + if (!window) + return; + + auto f = std::ranges::find_if(windows_, [window](const std::weak_ptr& w) { + return w.lock() == window; + }); + windows_.erase(f); + on_host_window_close(window.get()); +} + +void window_manager::update() { + glfwPollEvents(); + for (auto& info : host_infos_) { + if (!info.second.window) { + continue; + } + info.first->idle_editor(); + } +} + +void window_manager::on_host_window_close(GLFWwindow* window) { + auto f = std::ranges::find_if(host_infos_, [window](const std::pair& info) { + return info.second.window.get() == window; + }); + if (f != host_infos_.end()) { + f->first->close_editor(); + int x, y; + glfwGetWindowPos(window, &x, &y); + f->second.x = x; + f->second.y = y; + f->second.window.reset(); + } +} diff --git a/core/window/window_manager.h b/core/window/window_manager.h new file mode 100644 index 0000000..07b1d73 --- /dev/null +++ b/core/window/window_manager.h @@ -0,0 +1,32 @@ +#pragma once +#include "GLFW/glfw3.h" +#include "misc/singleton/singleton.h" +#include +#include +#include + +class plugin_host; + +class CORE_API window_manager : public singleton_t { +public: + void init(singleton_initliazer& initliazer) override; + void release(singleton_release_guard& release_guard) override; + + std::shared_ptr create_window(int width, int height, const char* title); + void* create_plugin_window(plugin_host* host); + void destroy_plugin_window(plugin_host* host); + const char* get_name() override { return "window_manager"; } + void update(); +private: + std::vector> windows_; + + struct host_info { + int32_t x; + int32_t y; + std::shared_ptr window; + }; + void on_host_window_close(GLFWwindow* window); + std::map host_infos_; +}; + +DEFINE_SINGLETON_INSTANCE(window_manager) \ No newline at end of file diff --git a/third_party/glfw b/third_party/glfw new file mode 160000 index 0000000..64b4f0f --- /dev/null +++ b/third_party/glfw @@ -0,0 +1 @@ +Subproject commit 64b4f0f30c60f11aee715214a9d8faef4372d946 diff --git a/update.bat b/update.bat index 3ff1fc7..4519fd4 100644 --- a/update.bat +++ b/update.bat @@ -15,4 +15,9 @@ git checkout master git pull cd .. +cd glfw +git checkout master +git pull +cd .. + pause \ No newline at end of file