From cd694d06b76bcbcf88d209877bfcc1e05ac7a866 Mon Sep 17 00:00:00 2001
From: Nanako <469449812@qq.com>
Date: Tue, 4 Jun 2024 13:52:39 +0800
Subject: [PATCH] =?UTF-8?q?mixer=5Ftrack=E6=95=88=E6=9E=9C=E5=99=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 Arona/src/widget/main_window.cpp             |  1 +
 Arona/src/widget/main_window.h               |  3 +-
 Arona/src/widget/misc/w_audio_buffer_bar.cpp |  3 +-
 Arona/src/widget/misc/w_volume_bar.h         |  7 ++-
 Arona/src/widget/mixer/w_effect_item.cpp     | 53 +++++++++++++++++
 Arona/src/widget/mixer/w_effect_item.h       | 54 +++++++++++++++++
 Arona/src/widget/mixer/w_effect_list.cpp     | 62 ++++++++++++++++++++
 Arona/src/widget/mixer/w_effect_list.h       | 43 ++++++++++++++
 Arona/src/widget/mixer/w_mixer_list.cpp      | 31 +++++-----
 Arona/src/widget/mixer/w_mixer_list.h        | 14 +++--
 AronaCore                                    |  2 +-
 11 files changed, 247 insertions(+), 26 deletions(-)
 create mode 100644 Arona/src/widget/mixer/w_effect_item.cpp
 create mode 100644 Arona/src/widget/mixer/w_effect_item.h
 create mode 100644 Arona/src/widget/mixer/w_effect_list.cpp
 create mode 100644 Arona/src/widget/mixer/w_effect_list.h

diff --git a/Arona/src/widget/main_window.cpp b/Arona/src/widget/main_window.cpp
index ed8a30d..adaf59c 100644
--- a/Arona/src/widget/main_window.cpp
+++ b/Arona/src/widget/main_window.cpp
@@ -12,5 +12,6 @@ void main_window::on_click() {
 
 bool main_window::on_close_request() {
     get_arona_application()->shutdown();
+    connection_.empty();
     return Window::on_close_request();
 }
diff --git a/Arona/src/widget/main_window.h b/Arona/src/widget/main_window.h
index 07e8b49..f3d85b1 100644
--- a/Arona/src/widget/main_window.h
+++ b/Arona/src/widget/main_window.h
@@ -7,7 +7,7 @@ public:
     main_window() {
         box_ = Gtk::Box(Gtk::Orientation::VERTICAL);
         button_ = Gtk::Button("Hello, World!");
-        button_.signal_clicked().connect(mem_fun(*this, &main_window::on_click));
+        connection_ = button_.signal_clicked().connect(mem_fun(*this, &main_window::on_click));
 
         box_.append(button_);
         box_.append(mixer_list_);
@@ -23,4 +23,5 @@ private:
     Gtk::Box box_;
     Gtk::Button button_;
     w_mixer_list mixer_list_;
+    sigc::connection connection_;
 };
diff --git a/Arona/src/widget/misc/w_audio_buffer_bar.cpp b/Arona/src/widget/misc/w_audio_buffer_bar.cpp
index d0e43e8..c233c37 100644
--- a/Arona/src/widget/misc/w_audio_buffer_bar.cpp
+++ b/Arona/src/widget/misc/w_audio_buffer_bar.cpp
@@ -7,7 +7,8 @@
 #include "tool/delta_timer.h"
 
 w_audio_buffer_bar::w_audio_buffer_bar() {
-    timer_ = std::make_shared<delta_timer>(mem_fun(*this, &w_audio_buffer_bar::on_timer), 1000.f / get_arona_application()->get_screen_refresh_rate());
+    float Interval = 1000.f / get_arona_application()->get_screen_refresh_rate();
+    timer_ = std::make_shared<delta_timer>(mem_fun(*this, &w_audio_buffer_bar::on_timer), Interval);
 }
 
 void w_audio_buffer_bar::set_buffers(weak_buffer in_buffers) {
diff --git a/Arona/src/widget/misc/w_volume_bar.h b/Arona/src/widget/misc/w_volume_bar.h
index 253bc45..15d84f2 100644
--- a/Arona/src/widget/misc/w_volume_bar.h
+++ b/Arona/src/widget/misc/w_volume_bar.h
@@ -1,15 +1,18 @@
 #pragma once
 #include "gtkmm/drawingarea.h"
+#include "extern.h"
 
 class w_volume_bar : public Gtk::DrawingArea {
 public:
     explicit w_volume_bar(bool vertical = false);
-    void set_value(double value) {
+    void set_value(sample_t value) {
+        if (value_ == value)
+            return;
         value_ = value;
         queue_draw();
     }
     const bool is_vertical;
 private:
     void on_draw(const Cairo::RefPtr<Cairo::Context>& cr, int width, int height);
-    double value_ = 0.;
+    sample_t value_ = 0.;
 };
diff --git a/Arona/src/widget/mixer/w_effect_item.cpp b/Arona/src/widget/mixer/w_effect_item.cpp
new file mode 100644
index 0000000..f855125
--- /dev/null
+++ b/Arona/src/widget/mixer/w_effect_item.cpp
@@ -0,0 +1,53 @@
+#include "w_effect_item.h"
+#include "audio/plugin_host/plugin_host.h"
+
+void w_effect_item::set_effect(plugin_host* in_effect) {
+    effect_ = in_effect;
+    effect_name_.set_label(effect_->name);
+    data_model_->remove_all();
+    uint32_t param_count = in_effect->get_param_count();
+    for (int i = 0; i < param_count; ++i) {
+        auto model_data = effect_value_model::create(in_effect, i);
+        if (model_data->is_valid())
+            data_model_->append(model_data);
+    }
+}
+
+w_effect_item::w_effect_item() : Gtk::Box(Gtk::Orientation::VERTICAL) {
+    data_model_ = Gio::ListStore<effect_value_model>::create();
+    selection_model_ = Gtk::SingleSelection::create(data_model_);
+    selection_model_->set_autoselect(true);
+
+    factory_ = Gtk::SignalListItemFactory::create();
+    factory_->signal_setup().connect(mem_fun(*this, &w_effect_item::on_setup_value_widget));
+    factory_->signal_bind().connect(mem_fun(*this, &w_effect_item::on_bind_value_widget));
+
+    list_view_.set_model(selection_model_);
+    list_view_.set_factory(factory_);
+    list_view_.set_orientation(Gtk::Orientation::VERTICAL);
+
+    append(effect_name_);
+    append(list_view_);
+}
+
+void w_effect_item::on_setup_value_widget(const Glib::RefPtr<Gtk::ListItem>& item) {
+    const auto widget = Gtk::make_managed<w_effect_value>();
+    item->set_child(*widget);
+}
+
+void w_effect_item::on_bind_value_widget(const Glib::RefPtr<Gtk::ListItem>& item) {
+    const auto index = item->get_position();
+    if (auto* widget = dynamic_cast<w_effect_value*>(item->get_child())) {
+        auto data = data_model_->get_item(index);
+        widget->set_value(data);
+    }
+}
+
+void w_effect_value::set_value(const Glib::RefPtr<effect_value_model>& in_param) {
+    param_ = in_param;
+    param_name_.set_label(in_param->get_name());
+}
+
+w_effect_value::w_effect_value() : Gtk::Box(Gtk::Orientation::HORIZONTAL) {
+    append(param_name_);
+}
diff --git a/Arona/src/widget/mixer/w_effect_item.h b/Arona/src/widget/mixer/w_effect_item.h
new file mode 100644
index 0000000..f304453
--- /dev/null
+++ b/Arona/src/widget/mixer/w_effect_item.h
@@ -0,0 +1,54 @@
+#pragma once
+#include <gtkmm/box.h>
+#include <gtkmm/listview.h>
+#include <giomm/liststore.h>
+#include <gtkmm/singleselection.h>
+#include <gtkmm/signallistitemfactory.h>
+#include <gtkmm/label.h>
+#include "audio/plugin_host/host_param.h"
+
+class plugin_host;
+
+class effect_value_model : public Glib::Object {
+public:
+    host_param param;
+    bool is_valid() const {
+        return param.is_valid();
+    }
+    const std::string& get_name() const {
+        return param.get_name();
+    }
+    static Glib::RefPtr<effect_value_model> create(plugin_host* in_effect, int32_t index) {
+        return Glib::make_refptr_for_instance(new effect_value_model(in_effect, index));
+    }
+private:
+    explicit effect_value_model(plugin_host* in_effect, int32_t index) : param(in_effect, index) {}
+};
+
+class w_effect_value : public Gtk::Box {
+public:
+    w_effect_value();
+    void set_value(const Glib::RefPtr<effect_value_model>& in_param);
+private:
+    Glib::RefPtr<effect_value_model> param_;
+
+    Gtk::Label param_name_;
+};
+
+class w_effect_item : public Gtk::Box {
+public:
+    w_effect_item();
+    void set_effect(plugin_host* in_effect);
+protected:
+    void on_setup_value_widget(const Glib::RefPtr<Gtk::ListItem>& item);
+    void on_bind_value_widget(const Glib::RefPtr<Gtk::ListItem>& item);
+private:
+    plugin_host* effect_;
+
+    Glib::RefPtr<Gio::ListStore<effect_value_model>> data_model_;
+    Glib::RefPtr<Gtk::SingleSelection> selection_model_;
+    Glib::RefPtr<Gtk::SignalListItemFactory> factory_;
+
+    Gtk::Label effect_name_;
+    Gtk::ListView list_view_;
+};
diff --git a/Arona/src/widget/mixer/w_effect_list.cpp b/Arona/src/widget/mixer/w_effect_list.cpp
new file mode 100644
index 0000000..ac245f5
--- /dev/null
+++ b/Arona/src/widget/mixer/w_effect_list.cpp
@@ -0,0 +1,62 @@
+#include "w_effect_list.h"
+#include "audio/mixer/mixer_track.h"
+#include "w_effect_item.h"
+#include "audio/plugin_host/plugin_host_manager.h"
+
+w_effect_list::w_effect_list() : Gtk::Box(Gtk::Orientation::HORIZONTAL), mixer_track_(nullptr) {
+    {
+        add_effect_.set_label("add_new_effect");
+        add_effect_.signal_clicked().connect(mem_fun(*this, &w_effect_list::add_new_effect));
+    }
+
+    data_model_ = Gio::ListStore<mixer_effect_model>::create();
+    selection_model_ = Gtk::SingleSelection::create(data_model_);
+    selection_model_->set_autoselect(true);
+
+    factory_ = Gtk::SignalListItemFactory::create();
+    factory_->signal_setup().connect(mem_fun(*this, &w_effect_list::on_setup_effect_widget));
+    factory_->signal_bind().connect(mem_fun(*this, &w_effect_list::on_bind_effect_widget));
+
+    list_view_.set_model(selection_model_);
+    list_view_.set_factory(factory_);
+    list_view_.set_orientation(Gtk::Orientation::HORIZONTAL);
+
+    append(list_view_);
+    append(add_effect_);
+}
+
+void w_effect_list::set_track(mixer_track* in_mixer_track) {
+    if (mixer_track_) {
+        mixer_track_->on_add_effect.remove_object(this);
+    }
+    mixer_track_ = in_mixer_track;
+    mixer_track_->on_add_effect.add_raw(this, &w_effect_list::on_add_effect);
+    data_model_->remove_all();
+    for (auto effect : mixer_track_->effects) {
+        on_add_effect(effect);
+    }
+}
+
+void w_effect_list::on_setup_effect_widget(const Glib::RefPtr<Gtk::ListItem>& item) {
+    const auto widget = Gtk::make_managed<w_effect_item>();
+    item->set_child(*widget);
+}
+
+void w_effect_list::on_bind_effect_widget(const Glib::RefPtr<Gtk::ListItem>& item) {
+    const auto index = item->get_position();
+    if (auto* widget = dynamic_cast<w_effect_item*>(item->get_child())) {
+        auto data = data_model_->get_item(index);
+        widget->set_effect(data->effect);
+    }
+}
+
+void w_effect_list::add_new_effect() {
+    if (!mixer_track_)
+        return;
+    auto* host = get_plugin_host_manager()->create_effect_plugin_host(R"(F:\VST\VST64\OTT_x64.dll)");
+    mixer_track_->add_effect(host);
+}
+
+void w_effect_list::on_add_effect(plugin_host* in_effect) {
+    data_model_->append(mixer_effect_model::create(in_effect));
+}
diff --git a/Arona/src/widget/mixer/w_effect_list.h b/Arona/src/widget/mixer/w_effect_list.h
new file mode 100644
index 0000000..5ed2a9c
--- /dev/null
+++ b/Arona/src/widget/mixer/w_effect_list.h
@@ -0,0 +1,43 @@
+#pragma once
+#include <gtkmm/box.h>
+#include <gtkmm/listview.h>
+#include <giomm/liststore.h>
+#include <gtkmm/singleselection.h>
+#include <gtkmm/signallistitemfactory.h>
+#include <gtkmm/button.h>
+
+class mixer_track;
+class plugin_host;
+
+class mixer_effect_model : public Glib::Object {
+public:
+    plugin_host* effect;
+    static Glib::RefPtr<mixer_effect_model> create(plugin_host* in_effect) {
+        return Glib::make_refptr_for_instance(new mixer_effect_model(in_effect));
+    }
+protected:
+    explicit mixer_effect_model(plugin_host* in_effect) : effect(in_effect) {
+
+    }
+};
+
+class w_effect_list : public Gtk::Box {
+public:
+    w_effect_list();
+
+    void set_track(mixer_track* in_mixer_track);
+    mixer_track* get_track() const { return mixer_track_; }
+private:
+    void add_new_effect();
+    void on_setup_effect_widget(const Glib::RefPtr<Gtk::ListItem>& item);
+    void on_bind_effect_widget(const Glib::RefPtr<Gtk::ListItem>& item);
+    void on_add_effect(plugin_host* in_effect);
+    Gtk::ListView list_view_;
+
+    Glib::RefPtr<Gio::ListStore<mixer_effect_model>> data_model_;
+    Glib::RefPtr<Gtk::SingleSelection> selection_model_;
+    Glib::RefPtr<Gtk::SignalListItemFactory> factory_;
+
+    mixer_track* mixer_track_;
+    Gtk::Button add_effect_;
+};
diff --git a/Arona/src/widget/mixer/w_mixer_list.cpp b/Arona/src/widget/mixer/w_mixer_list.cpp
index 706b708..c2b4a5c 100644
--- a/Arona/src/widget/mixer/w_mixer_list.cpp
+++ b/Arona/src/widget/mixer/w_mixer_list.cpp
@@ -4,7 +4,7 @@
 #include "audio/mixer/mixer.h"
 #include "thread_message/thread_message_hubs.h"
 
-w_mixer_list::w_mixer_list() {
+w_mixer_list::w_mixer_list() : Gtk::Box(Gtk::Orientation::VERTICAL) {
     mixer* mixer = get_mixer();
 
     {
@@ -20,6 +20,7 @@ w_mixer_list::w_mixer_list() {
     data_model_ = Gio::ListStore<mixer_list_model>::create();
     selection_model_ = Gtk::SingleSelection::create(data_model_);
     selection_model_->set_autoselect(true);
+    selection_model_->signal_selection_changed().connect(mem_fun(*this, &w_mixer_list::on_selection_changed));
 
     factory_ = Gtk::SignalListItemFactory::create();
     factory_->signal_setup().connect(mem_fun(*this, &w_mixer_list::on_setup_track_widget));
@@ -30,6 +31,7 @@ w_mixer_list::w_mixer_list() {
     list_view_.set_orientation(Gtk::Orientation::HORIZONTAL);
 
     append(list_view_);
+    append(effect_list_);
 }
 
 w_mixer_list::~w_mixer_list() {
@@ -38,13 +40,15 @@ w_mixer_list::~w_mixer_list() {
     mixer->on_remove_track.remove_object(this);
 }
 
-void w_mixer_list::on_add_track(mixer_track* mixer_track) {
-    data_model_->append(mixer_list_model::create(mixer_track));
+void w_mixer_list::on_add_track(mixer_track* track) {
+    data_model_->append(mixer_list_model::create(track));
+    if (!effect_list_.get_track())
+        effect_list_.set_track(track);
 }
 
-void w_mixer_list::on_remove_track(mixer_track* mixer_track) {
+void w_mixer_list::on_remove_track(mixer_track* track) {
     for (int i = 0; i < data_model_->get_n_items(); ++i) {
-        if (data_model_->get_item(i)->mixer == mixer_track) {
+        if (data_model_->get_item(i)->mixer == track) {
             data_model_->remove(i);
             return;
         }
@@ -57,22 +61,19 @@ void w_mixer_list::on_setup_track_widget(const Glib::RefPtr<Gtk::ListItem>& item
 }
 
 void w_mixer_list::on_bind_track_widget(const Glib::RefPtr<Gtk::ListItem>& item) {
-    const auto index = item->get_position() + 1; // 0 is master track
+    const auto index = item->get_position();
     if (auto* widget = dynamic_cast<w_mixer_track*>(item->get_child())) {
-        const std::vector<mixer_track*>& tracks = get_mixer()->get_tracks();
-        if (index >= tracks.size()) {
-            return;
-        }
-        widget->set_mixer_track(tracks[index]);
+        auto data = data_model_->get_item(index);
+        widget->set_mixer_track(data->mixer);
     }
 }
 
-void w_mixer_list::on_selection_changed() {
-    const guint selected = selection_model_->get_selected();
-    const Glib::RefPtr<mixer_list_model>& selected_model = data_model_->get_item(selected);
+void w_mixer_list::on_selection_changed(uint32_t position, uint32_t count) {
+    const Glib::RefPtr<mixer_list_model>& selected_model = data_model_->get_item(selection_model_->get_selected());
     if (!selection_model_) {
         return;
     }
-    const mixer_track* track = selected_model->mixer;
+    mixer_track* track = selected_model->mixer;
     spdlog::info("Selected track: {}", track->get_name());
+    effect_list_.set_track(track);
 }
diff --git a/Arona/src/widget/mixer/w_mixer_list.h b/Arona/src/widget/mixer/w_mixer_list.h
index 926090a..aba0a43 100644
--- a/Arona/src/widget/mixer/w_mixer_list.h
+++ b/Arona/src/widget/mixer/w_mixer_list.h
@@ -7,15 +7,16 @@
 
 #include "w_mixer_track.h"
 #include "audio/mixer/mixer_track.h"
+#include "w_effect_list.h"
 
 class mixer_list_model : public Glib::Object {
 public:
     mixer_track* mixer;
-    static Glib::RefPtr<mixer_list_model> create(mixer_track* mixer) {
-        return Glib::make_refptr_for_instance(new mixer_list_model(mixer));
+    static Glib::RefPtr<mixer_list_model> create(mixer_track* in_mixer) {
+        return Glib::make_refptr_for_instance(new mixer_list_model(in_mixer));
     }
 protected:
-    explicit mixer_list_model(mixer_track* mixer) : mixer(mixer) {}
+    explicit mixer_list_model(mixer_track* in_mixer) : mixer(in_mixer) {}
 };
 
 class w_mixer_list : public Gtk::Box {
@@ -23,12 +24,12 @@ public:
     w_mixer_list();
     ~w_mixer_list() override;
 private:
-    void on_add_track(mixer_track* mixer_track);
-    void on_remove_track(mixer_track* mixer_track);
+    void on_add_track(mixer_track* track);
+    void on_remove_track(mixer_track* track);
 
     void on_setup_track_widget(const Glib::RefPtr<Gtk::ListItem>& item);
     void on_bind_track_widget(const Glib::RefPtr<Gtk::ListItem>& item);
-    void on_selection_changed();
+    void on_selection_changed(uint32_t position, uint32_t count);
     Glib::RefPtr<Gio::ListStore<mixer_list_model>> data_model_;
     Glib::RefPtr<Gtk::SingleSelection> selection_model_;
     Glib::RefPtr<Gtk::SignalListItemFactory> factory_;
@@ -36,4 +37,5 @@ private:
     Gtk::ListView list_view_;
 
     w_mixer_track* master_track_;
+    w_effect_list effect_list_;
 };
diff --git a/AronaCore b/AronaCore
index 03353ac..1b4ee22 160000
--- a/AronaCore
+++ b/AronaCore
@@ -1 +1 @@
-Subproject commit 03353ac2c928069792734091f78ef5e32732ac8b
+Subproject commit 1b4ee22c9502b55cd063d96fa1c9f82a03cd33fd