2024-10-22 01:55:31 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "datatypes.h"
|
2024-10-30 14:55:24 +01:00
|
|
|
#include "graph-manager.h"
|
2024-11-01 02:38:47 +01:00
|
|
|
#include "midi-node.h"
|
2024-11-21 02:03:32 +01:00
|
|
|
#include "node.h"
|
2024-10-22 01:55:31 +02:00
|
|
|
#include "signal.h"
|
|
|
|
|
#include "midi.h"
|
|
|
|
|
|
|
|
|
|
#include <chrono>
|
2024-11-01 02:38:47 +01:00
|
|
|
#include <memory>
|
2024-10-22 01:55:31 +02:00
|
|
|
#include <thread>
|
|
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
using namespace VISEQ::GRAPH;
|
2024-10-22 01:55:31 +02:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
namespace VISEQ::SIGNAL {
|
|
|
|
|
|
|
|
|
|
typedef std::shared_ptr<Signal> SPTR_Signal;
|
|
|
|
|
typedef std::vector<SPTR_Signal> VEC_SPTR_Signal;
|
|
|
|
|
|
2024-11-30 02:54:40 +01:00
|
|
|
class SignalManager : public std::enable_shared_from_this<SignalManager>{
|
2024-11-03 03:48:49 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
SignalManager() {}
|
|
|
|
|
SignalManager(GraphManager *gm, std::mutex *mutex) : mutex(mutex), gm(gm) {}
|
|
|
|
|
|
2024-11-30 02:54:40 +01:00
|
|
|
std::shared_ptr<SignalManager> getPtr(){
|
|
|
|
|
return shared_from_this();
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
VISEQ::MIDI::Midi midi;
|
|
|
|
|
|
|
|
|
|
std::mutex *mutex;
|
|
|
|
|
GraphManager *gm;
|
|
|
|
|
|
|
|
|
|
VEC_SPTR_Signal signals;
|
2024-10-22 01:55:31 +02:00
|
|
|
|
2024-11-04 01:00:59 +01:00
|
|
|
VEC_SPTR_Signal erase_signals;
|
|
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
bool loop = true;
|
|
|
|
|
bool play = false;
|
2024-10-22 01:55:31 +02:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void pause(){
|
|
|
|
|
play = false;
|
|
|
|
|
}
|
2024-11-01 02:38:47 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void stop(){
|
|
|
|
|
play = false;
|
|
|
|
|
reset();
|
|
|
|
|
}
|
2024-10-25 02:43:41 +02:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void start(){
|
|
|
|
|
play = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void reset(){
|
|
|
|
|
for(auto &s : signals){
|
|
|
|
|
s->position = s->start->position + Vec2Df{0.1, 0.1};
|
|
|
|
|
s->next = s->start;
|
|
|
|
|
s->last = s->start;
|
|
|
|
|
}
|
|
|
|
|
gm->reset();
|
|
|
|
|
}
|
2024-10-25 02:43:41 +02:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void startSignalThread(){
|
|
|
|
|
std::thread t1(&SignalManager::updateSignals, this);
|
|
|
|
|
t1.detach();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stopSignalThread(){
|
|
|
|
|
loop = false;
|
|
|
|
|
}
|
2024-10-25 02:43:41 +02:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void addSignalAtNode(SPTR_Node node){
|
|
|
|
|
Color c = {(unsigned char)(20 + (rand() % 200)), 100, (unsigned char)(20 + (int)(rand() % 200)), 200};
|
|
|
|
|
signals.emplace_back(std::make_shared<Signal>(node->position + Vec2Df{0.5f, 0.5f}, 8.0f, 0, c)); // position + 1 or else it does not render. why? no idea!
|
|
|
|
|
signals.back()->next = node;
|
|
|
|
|
signals.back()->last = node;
|
|
|
|
|
signals.back()->start = node;
|
2024-10-25 02:43:41 +02:00
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
|
2024-11-21 02:03:32 +01:00
|
|
|
void rerouteSignal(VEC_SPTR_Node nodes, VEC_SPTR_Node adjacent_nodes){
|
|
|
|
|
auto reroute_signals = signals | RANGE_FILTER([nodes](SIGNAL::SPTR_Signal s){return std::ranges::contains(nodes, s->next);});
|
|
|
|
|
|
|
|
|
|
for(auto s : reroute_signals){
|
|
|
|
|
float dist = 10000000;
|
|
|
|
|
SPTR_Node next_node;
|
|
|
|
|
for(auto n : adjacent_nodes){
|
|
|
|
|
if(n->position.dist(s->position) < dist) {
|
|
|
|
|
dist = n->position.dist(s->position);
|
|
|
|
|
next_node = n;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s->next = next_node;
|
|
|
|
|
s->last = next_node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rebaseSignal(VEC_SPTR_Node nodes){
|
|
|
|
|
auto rebase_signals = signals | RANGE_FILTER([nodes](SIGNAL::SPTR_Signal s){return std::ranges::contains(nodes, s->start);});
|
|
|
|
|
|
|
|
|
|
for(auto s : rebase_signals){
|
|
|
|
|
s->start = s->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-04 01:00:59 +01:00
|
|
|
void removeSignal(std::shared_ptr<Signal> s){
|
|
|
|
|
erase_signals.push_back(s);
|
2024-11-03 03:48:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void updateSignals(){
|
|
|
|
|
auto last = std::chrono::high_resolution_clock::now();
|
|
|
|
|
while(loop){
|
|
|
|
|
std::chrono::duration<double, std::micro> diff = std::chrono::high_resolution_clock::now() - last;
|
|
|
|
|
if((int)diff.count() >= 250){
|
|
|
|
|
mutex->lock();
|
|
|
|
|
if(play){
|
|
|
|
|
for(auto& s : signals){
|
|
|
|
|
s->direction = (s->next->position - s->position).norm();
|
|
|
|
|
s->update(diff.count());
|
|
|
|
|
if(s->position.dist(s->next->position) < 0.6f) {
|
|
|
|
|
SPTR_Node next_node = gm->next(s->next, s->last);
|
|
|
|
|
s->next->trigger();
|
|
|
|
|
|
|
|
|
|
if(next_node != s->next && next_node != SPTR_Node(nullptr) && s->next->getNodeType() == NodeType::MIDINODE) {
|
|
|
|
|
auto midinode = std::dynamic_pointer_cast<MidiNode>(s->next);
|
|
|
|
|
for(auto &m : midinode->midi_outs){
|
|
|
|
|
if(m.second.enabled) {
|
2024-11-04 01:00:59 +01:00
|
|
|
if(midinode->send_note) midi.note(m.second.i, midinode->midi_note_channel, (int)Clamp(midinode->midi_note + s->midi_note_offset, 0, 127), midinode->midi_velocity, midinode->midi_gate);
|
|
|
|
|
if(midinode->send_cc) midi.cc(m.second.i, midinode->midi_cc_channel, midinode->midi_cc, (int)Clamp(midinode->midi_cc_value + s->midi_cc_offset, 0, 127));
|
2024-11-03 03:48:49 +01:00
|
|
|
if(midinode->send_pitch_bend) midi.pitch_bend(m.second.i, midinode->midi_pitch_bend_channel, midinode->midi_pitch_bend);
|
|
|
|
|
}
|
2024-10-28 02:07:47 +01:00
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
s->last = s->next;
|
|
|
|
|
s->next = next_node;
|
2024-10-25 02:43:41 +02:00
|
|
|
}
|
2024-10-22 01:55:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
midi.update();
|
|
|
|
|
mutex->unlock();
|
|
|
|
|
last = std::chrono::high_resolution_clock::now();
|
2024-10-22 01:55:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void drawSignals(Vec2Df mouse_pos, Camera2D camera){
|
2024-11-04 01:00:59 +01:00
|
|
|
mutex->lock();
|
|
|
|
|
if(!erase_signals.empty()){
|
|
|
|
|
for(auto s: erase_signals){
|
|
|
|
|
std::erase(signals, s);
|
|
|
|
|
}
|
|
|
|
|
erase_signals.clear();
|
|
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
for(auto s : signals){
|
|
|
|
|
s->draw(mouse_pos, camera);
|
|
|
|
|
}
|
2024-11-04 01:00:59 +01:00
|
|
|
mutex->unlock();
|
2024-10-22 01:55:31 +02:00
|
|
|
}
|
2024-11-07 00:56:33 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline void to_json(json& j, const SignalManager& G){
|
|
|
|
|
j = json{{"signals", G.signals}};
|
|
|
|
|
}
|
|
|
|
|
}
|