midi_sequencer
This commit is contained in:
parent
1b4ee22c95
commit
580ad03623
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class command_line {
|
||||
public:
|
||||
@ -20,6 +20,6 @@ public:
|
||||
void get_arg(const std::string& key, bool& out) const;
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> args_; // key-value pairs
|
||||
std::unordered_map<std::string, std::string> args_; // key-value pairs
|
||||
command_line() = default;
|
||||
};
|
||||
|
@ -38,7 +38,8 @@ void audio_device_manager::release(singleton_release_guard& release_guard) {
|
||||
singleton_t<audio_device_manager>::release(release_guard);
|
||||
stop_render_thread();
|
||||
release_guard.require_release<mixer>();
|
||||
audio_->stopStream();
|
||||
if (audio_)
|
||||
audio_->stopStream();
|
||||
delete audio_;
|
||||
}
|
||||
|
||||
@ -76,6 +77,7 @@ uint32_t audio_device_manager::get_sample_rate() const {
|
||||
|
||||
void audio_device_manager::set_sample_rate(uint32_t sample_rate) {
|
||||
sample_rate_ = sample_rate;
|
||||
on_sample_rate_changed.broadcast(sample_rate_);
|
||||
}
|
||||
|
||||
uint32_t audio_device_manager::get_buffer_size() const {
|
||||
@ -164,7 +166,7 @@ void audio_device_manager::render_thread() {
|
||||
// std::this_thread::yield();
|
||||
continue;
|
||||
}
|
||||
g_midi_sequencer.process(rate, frames);
|
||||
g_midi_sequencer.process(get_sample_rate(), frames);
|
||||
g_mixer.reset();
|
||||
g_plugin_host_manager.process(frames);
|
||||
g_mixer.process(frames);
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "audio/misc/circular_audio_buffer.h"
|
||||
#include "RtAudio.h"
|
||||
#include "misc/delegates.h"
|
||||
|
||||
class audio_device_manager : public singleton_t<audio_device_manager> {
|
||||
public:
|
||||
@ -23,6 +24,8 @@ public:
|
||||
int stream_callback(sample_t* output, sample_t* input, unsigned long frame_count, double stream_time, RtAudioStreamStatus status);
|
||||
void log_all_devices();
|
||||
void log_current_device_info();
|
||||
|
||||
multicast_delegate<uint32_t> on_sample_rate_changed;
|
||||
protected:
|
||||
#pragma region render_thread
|
||||
void start_render_thread();
|
||||
|
@ -92,22 +92,22 @@ void channel_interface::set_output_channel_node_name(uint32_t node_index, uint32
|
||||
output_channel_names_[node_index][channel_index] = name;
|
||||
}
|
||||
|
||||
std::map<uint32_t, std::string> channel_interface::get_input_channel_node_name(uint32_t node_index) {
|
||||
std::unordered_map<uint32_t, std::string> channel_interface::get_input_channel_node_name(uint32_t node_index) {
|
||||
return input_channel_names_[node_index];
|
||||
}
|
||||
|
||||
std::map<uint32_t, std::string> channel_interface::get_input_channel_node_name(channel_node* node) {
|
||||
std::unordered_map<uint32_t, std::string> channel_interface::get_input_channel_node_name(channel_node* node) {
|
||||
uint32_t index = get_input_node_index(node);
|
||||
if (index == -1)
|
||||
return {};
|
||||
return get_input_channel_node_name(index);
|
||||
}
|
||||
|
||||
std::map<uint32_t, std::string> channel_interface::get_output_channel_node_name(uint32_t node_index) {
|
||||
std::unordered_map<uint32_t, std::string> channel_interface::get_output_channel_node_name(uint32_t node_index) {
|
||||
return output_channel_names_[node_index];
|
||||
}
|
||||
|
||||
std::map<uint32_t, std::string> channel_interface::get_output_channel_node_name(channel_node* node) {
|
||||
std::unordered_map<uint32_t, std::string> channel_interface::get_output_channel_node_name(channel_node* node) {
|
||||
uint32_t index = get_output_node_index(node);
|
||||
if (index == -1)
|
||||
return {};
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -27,18 +27,18 @@ public:
|
||||
|
||||
void set_input_channel_node_name(uint32_t node_index, uint32_t channel_index, const std::string& name);
|
||||
void set_output_channel_node_name(uint32_t node_index, uint32_t channel_index, const std::string& name);
|
||||
std::map<uint32_t, std::string> get_input_channel_node_name(uint32_t node_index);
|
||||
std::map<uint32_t, std::string> get_input_channel_node_name(channel_node* node);
|
||||
std::map<uint32_t, std::string> get_output_channel_node_name(uint32_t node_index);
|
||||
std::map<uint32_t, std::string> get_output_channel_node_name(channel_node* node);
|
||||
std::unordered_map<uint32_t, std::string> get_input_channel_node_name(uint32_t node_index);
|
||||
std::unordered_map<uint32_t, std::string> get_input_channel_node_name(channel_node* node);
|
||||
std::unordered_map<uint32_t, std::string> get_output_channel_node_name(uint32_t node_index);
|
||||
std::unordered_map<uint32_t, std::string> get_output_channel_node_name(channel_node* node);
|
||||
|
||||
void remove_track(mixer_track* track);
|
||||
|
||||
std::vector<channel_node*> input_channel_nodes;
|
||||
std::vector<channel_node*> output_channel_nodes;
|
||||
private:
|
||||
std::map<uint32_t, std::map<uint32_t, std::string>> input_channel_names_;
|
||||
std::map<uint32_t, std::map<uint32_t, std::string>> output_channel_names_;
|
||||
std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> input_channel_names_;
|
||||
std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> output_channel_names_;
|
||||
std::vector<sample_t*> input_headers_;
|
||||
std::vector<sample_t*> output_headers_;
|
||||
};
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
IMPL_SINGLETON_INSTANCE(mixer)
|
||||
|
||||
void build_effect_channel_interface(mixer_track* track, const channel_interface* in_interface, std::map<mixer_track*, int32_t>& processed_tracks) {
|
||||
void build_effect_channel_interface(mixer_track* track, const channel_interface* in_interface, std::unordered_map<mixer_track*, int32_t>& processed_tracks) {
|
||||
int32_t& track_current_layer = processed_tracks[track];
|
||||
auto& input_channel_nodes = in_interface->input_channel_nodes;
|
||||
auto& output_channel_nodes = in_interface->output_channel_nodes;
|
||||
@ -38,7 +38,7 @@ void build_effect_channel_interface(mixer_track* track, const channel_interface*
|
||||
}
|
||||
}
|
||||
|
||||
int32_t build_process_node_internal(mixer_track* track, std::map<mixer_track*, int32_t>& processed_tracks, int32_t layer) {
|
||||
int32_t build_process_node_internal(mixer_track* track, std::unordered_map<mixer_track*, int32_t>& processed_tracks, int32_t layer) {
|
||||
int32_t& track_current_layer = processed_tracks[track];
|
||||
track_current_layer = std::max(track_current_layer, layer);
|
||||
for (const mixer_track_link& child_link: track->children) {
|
||||
@ -51,7 +51,7 @@ int32_t build_process_node_internal(mixer_track* track, std::map<mixer_track*, i
|
||||
return ++layer;
|
||||
}
|
||||
|
||||
void build_instrument_process_node(const plugin_host* host, std::map<mixer_track*, int32_t>& processed_tracks) {
|
||||
void build_instrument_process_node(const plugin_host* host, std::unordered_map<mixer_track*, int32_t>& processed_tracks) {
|
||||
for (mixer_track* Track : host->owner_tracks) {
|
||||
build_effect_channel_interface(Track, host->channel, processed_tracks);
|
||||
}
|
||||
@ -140,7 +140,7 @@ void mixer::reset() {
|
||||
void mixer::build_process_node() {
|
||||
if (tracks_.empty())
|
||||
return;
|
||||
std::map<mixer_track*, int32_t> processed_tracks;
|
||||
std::unordered_map<mixer_track*, int32_t> processed_tracks;
|
||||
auto* master = get_master();
|
||||
build_process_node_internal(master, processed_tracks, 0);
|
||||
const auto& instruments = g_plugin_host_manager.get_plugin_hosts();
|
||||
@ -235,6 +235,7 @@ void mixer::update_taskflow(uint32_t in_frames) {
|
||||
void mixer::begin_release(singleton_release_guard &release_guard) {
|
||||
singleton::begin_release(release_guard);
|
||||
auto e = executor_.exchange(nullptr);
|
||||
e->wait_for_all();
|
||||
if (e)
|
||||
e->wait_for_all();
|
||||
delete e;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ private:
|
||||
void update_taskflow(uint32_t in_frames);
|
||||
|
||||
std::vector<mixer_track*> tracks_;
|
||||
std::map<int32_t, std::vector<mixer_track*>> layer_tracks_;
|
||||
std::unordered_map<int32_t, std::vector<mixer_track*>> layer_tracks_;
|
||||
std::vector<int32_t> layer_order_;
|
||||
std::atomic<tf::Executor*> executor_;
|
||||
tf::Taskflow taskflow_;
|
||||
|
@ -1,15 +1,44 @@
|
||||
#include "midi_sequencer.h"
|
||||
|
||||
#include "audio/device/audio_device_manager.h"
|
||||
#include "misc/tick.h"
|
||||
#include "vst2/vst2_plugin_host.h"
|
||||
|
||||
IMPL_SINGLETON_INSTANCE(midi_sequencer)
|
||||
|
||||
|
||||
void midi_sequencer::init(singleton_initliazer& initliazer) {
|
||||
singleton_t<midi_sequencer>::init(initliazer);
|
||||
|
||||
vst2_plugin_host::vst_time_info.tempo = 128.0;
|
||||
|
||||
auto adm = initliazer.require<audio_device_manager>();
|
||||
adm->on_sample_rate_changed.add_raw(this, &midi_sequencer::on_sample_rate_changed);
|
||||
set_bpm(140.0);
|
||||
set_tpq(960);
|
||||
}
|
||||
|
||||
void midi_sequencer::process(double sample_rate, uint32_t in_frames) {
|
||||
void midi_sequencer::process(double sample_rate, uint32_t delta_frames) {
|
||||
update_time(sample_rate, delta_frames);
|
||||
update_vst2_time_info();
|
||||
}
|
||||
|
||||
void midi_sequencer::set_bpm(double in_bpm) {
|
||||
bpm_ = std::max(in_bpm, 1.0);
|
||||
vst2_time.tempo = bpm_;
|
||||
}
|
||||
|
||||
void midi_sequencer::set_tpq(int32_t in_tpq) {
|
||||
tpq_ = in_tpq;
|
||||
}
|
||||
|
||||
void midi_sequencer::on_sample_rate_changed(uint32_t sample_rate) {
|
||||
vst2_time.sampleRate = sample_rate;
|
||||
}
|
||||
|
||||
void midi_sequencer::update_time(double sample_rate, uint32_t delta_frames) {
|
||||
audio_frame frame(delta_frames);
|
||||
}
|
||||
|
||||
void midi_sequencer::update_vst2_time_info() {
|
||||
vst2_time.nanoSeconds = 0;
|
||||
vst2_time.ppqPos = tpq_pos_;
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,35 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
#include "misc/tick.h"
|
||||
#include "misc/singleton/singleton.h"
|
||||
|
||||
class midi_sequencer : public singleton_t<midi_sequencer> {
|
||||
public:
|
||||
|
||||
void init(singleton_initliazer& initliazer) override;
|
||||
void process(double sample_rate, uint32_t in_frames);
|
||||
void process(double sample_rate, uint32_t delta_frames);
|
||||
|
||||
const char* get_name() override { return "midi_sequencer"; }
|
||||
void set_bpm(double in_bpm);
|
||||
void set_tpq(int32_t in_tpq);
|
||||
[[nodiscard]] double get_bpm() const {
|
||||
return bpm_;
|
||||
}
|
||||
[[nodiscard]] int32_t get_tpq() const {
|
||||
return tpq_;
|
||||
}
|
||||
protected:
|
||||
void on_sample_rate_changed(uint32_t sample_rate);
|
||||
void update_time(double sample_rate, uint32_t delta_frames);
|
||||
private:
|
||||
void update_vst2_time_info();
|
||||
|
||||
double bpm_ = 0;
|
||||
int32_t tpq_ = 0;
|
||||
audio_frame sample_pos_ = 0;
|
||||
int32_t tpq_pos_ = 0;
|
||||
double nano_seconds_ = 0;
|
||||
};
|
||||
|
||||
DEFINE_SINGLETON_INSTANCE(midi_sequencer)
|
||||
|
@ -116,6 +116,7 @@ void plugin_host_manager::update_taskflow(uint32_t in_frames) {
|
||||
|
||||
void plugin_host_manager::begin_release(singleton_release_guard& release_guard) {
|
||||
auto executor = executor_.exchange(nullptr);
|
||||
executor->wait_for_all();
|
||||
if (executor)
|
||||
executor->wait_for_all();
|
||||
delete executor;
|
||||
}
|
||||
|
@ -4,10 +4,10 @@
|
||||
#include "audio/mixer/channel_interface.h"
|
||||
#include "window/window_manager.h"
|
||||
|
||||
std::map<std::string, std::weak_ptr<dynamic_library>> vst2_library_map;
|
||||
std::unordered_map<std::string, std::weak_ptr<dynamic_library>> vst2_library_map;
|
||||
VstTimeInfo vst2_plugin_host::vst_time_info{};
|
||||
|
||||
std::map<std::string, bool> can_do_map =
|
||||
std::unordered_map<std::string, bool> can_do_map =
|
||||
{
|
||||
{"sendVstEvents", true},
|
||||
{"sendVstMidiEvent", true},
|
||||
@ -73,7 +73,7 @@ VstIntPtr vst_master_callback(AEffect* effect, VstInt32 opcode, VstInt32 index,
|
||||
return 1;
|
||||
}
|
||||
case audioMasterGetTime:
|
||||
return (VstIntPtr)&vst2_plugin_host::vst_time_info;
|
||||
return (VstIntPtr)&vst2_time;
|
||||
case audioMasterIdle:
|
||||
// UE_LOG(LogTemp, Log, TEXT("Plugin Idle"));
|
||||
return 1;
|
||||
|
@ -43,3 +43,5 @@ private:
|
||||
std::shared_ptr<dynamic_library> library_;
|
||||
bool enabled_ = false;
|
||||
};
|
||||
|
||||
#define vst2_time vst2_plugin_host::vst_time_info
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
#define DEFINE_SINGLETON_INSTANCE(T) \
|
||||
inline T g_##T; \
|
||||
extern "C" CORE_API T* get_##T();
|
||||
#else
|
||||
#else
|
||||
#define DEFINE_SINGLETON_INSTANCE(T) \
|
||||
extern "C" CORE_API T* get_##T();
|
||||
#endif
|
||||
|
29
core/misc/tick.cpp
Normal file
29
core/misc/tick.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
#include "tick.h"
|
||||
#include "audio/device/audio_device_manager.h"
|
||||
#include "audio/plugin_host/midi_sequencer.h"
|
||||
|
||||
midi_tick::midi_tick(const audio_frame& in_frame) {
|
||||
auto bpm = g_midi_sequencer.get_bpm();
|
||||
auto tpq = g_midi_sequencer.get_tpq();
|
||||
auto sample_rate = g_audio_device_manager.get_sample_rate();
|
||||
|
||||
double time_in_seconds = (double)in_frame.get_frames() / sample_rate;
|
||||
ticks = time_in_seconds * bpm * tpq / 60.0;
|
||||
}
|
||||
|
||||
audio_frame midi_tick::to_audio_frame() const {
|
||||
return audio_frame(*this);
|
||||
}
|
||||
|
||||
audio_frame::audio_frame(const midi_tick& in_tick) {
|
||||
auto bpm = g_midi_sequencer.get_bpm();
|
||||
auto tpq = g_midi_sequencer.get_tpq();
|
||||
auto sample_rate = g_audio_device_manager.get_sample_rate();
|
||||
double tick_duration = 60.0 / (bpm * tpq);
|
||||
double tick_in_seconds = in_tick.get_ticks() * tick_duration;
|
||||
frames = tick_in_seconds * sample_rate;
|
||||
}
|
||||
|
||||
midi_tick audio_frame::to_midi_tick() const {
|
||||
return midi_tick(*this);
|
||||
}
|
42
core/misc/tick.h
Normal file
42
core/misc/tick.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class audio_frame;
|
||||
|
||||
class midi_tick {
|
||||
public:
|
||||
midi_tick(int64_t in_ticks) : ticks(in_ticks) {
|
||||
|
||||
}
|
||||
explicit midi_tick(const audio_frame& in_frame);
|
||||
|
||||
[[nodiscard]] audio_frame to_audio_frame() const;
|
||||
[[nodiscard]] int64_t get_ticks() const {
|
||||
return ticks;
|
||||
}
|
||||
operator int64_t() const {
|
||||
return ticks;
|
||||
}
|
||||
private:
|
||||
int64_t ticks;
|
||||
};
|
||||
|
||||
class audio_frame {
|
||||
public:
|
||||
audio_frame(int64_t in_frames) : frames(in_frames) {
|
||||
|
||||
}
|
||||
explicit audio_frame(const midi_tick& in_tick);
|
||||
|
||||
[[nodiscard]] midi_tick to_midi_tick() const;
|
||||
[[nodiscard]] int64_t get_frames() const {
|
||||
return frames;
|
||||
}
|
||||
operator int64_t() const {
|
||||
return frames;
|
||||
}
|
||||
auto operator<=>(const audio_frame&) const = default;
|
||||
private:
|
||||
int64_t frames;
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "misc/singleton/singleton.h"
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
@ -27,7 +27,7 @@ private:
|
||||
std::shared_ptr<GLFWwindow> window;
|
||||
};
|
||||
void on_host_window_close(GLFWwindow* window);
|
||||
std::map<plugin_host*, host_info> host_infos_;
|
||||
std::unordered_map<plugin_host*, host_info> host_infos_;
|
||||
};
|
||||
|
||||
DEFINE_SINGLETON_INSTANCE(window_manager)
|
Loading…
x
Reference in New Issue
Block a user