#include "modifier-node.h" namespace VISEQ::GRAPH::NODES { std::shared_ptr ModNode::getPtr() { return std::static_pointer_cast(shared_from_this()); } NodeType ModNode::getNodeType() const {return nodeType;} void ModNode::trigger() {} void ModNode::setMode(int _mode) { mode = _mode; } MIDI::MidiNote ModNode::getNotes() const { MIDI::MidiNote cNote; for(auto cn : getConnectedModNodes()){ cNote += cn.lock()->getNotes(); } return midiNote + cNote; } MIDI::MidiCC ModNode::getCC() const { MIDI::MidiCC cCC; for(auto cn : getConnectedModNodes()){ cCC += cn.lock()->getCC(); } return midiCC + cCC; } MIDI::MidiPC ModNode::getPC() const { MIDI::MidiPC cPC; for(auto cn : getConnectedModNodes()){ cPC += cn.lock()->getPC(); } return midiPC + cPC; } MIDI::MidiPitchBend ModNode::getPitchBend() const { MIDI::MidiPitchBend cPitchBend; for(auto cn : getConnectedModNodes()){ cPitchBend += cn.lock()->getPitchBend(); } return midiPitchBend + cPitchBend; } MIDI::MidiAftertouch ModNode::getAftertouch() const { MIDI::MidiAftertouch cAftertouch; for(auto cn : getConnectedModNodes()){ cAftertouch += cn.lock()->getAftertouch(); } return midiAftertouch + cAftertouch; } MIDI::MidiPolyPressure ModNode::getPolyPressure() const { MIDI::MidiPolyPressure cPolyPressure; for(auto cn : getConnectedModNodes()){ cPolyPressure += cn.lock()->getPolyPressure(); } return midiPolyPressure + cPolyPressure; } std::vector> ModNode::getConnectedModNodes() const { // TODO: check for cyclic connections of config nodes (crashes) auto config_conns = connections | RANGE_FILTER([](EDGES::SPTR_Edge c){ return c->start.lock()->getNodeType() == NodeType::CONFIGNODE || c->end.lock()->getNodeType() == NodeType::CONFIGNODE;}) | std::ranges::to>>(); std::vector> config_nodes; for(auto e : config_conns){ if(e->start.lock().get() != this && e->start.lock()->getNodeType() == NodeType::CONFIGNODE) config_nodes.push_back(std::dynamic_pointer_cast(e->start.lock())); //if(e->end.lock().get() != this && e->end.lock()->getNodeType() == NodeType::CONFIGNODE) config_nodes.push_back(std::dynamic_pointer_cast(e->end.lock())); } /*std::cout << "id: " << id << " n cn: " << config_nodes.size() << std::endl;*/ return config_nodes; } std::vector> ModNode::getConnectedMidiNodes() const { auto config_conns = connections | RANGE_FILTER([](EDGES::SPTR_Edge c){ return c->start.lock()->getNodeType() == NodeType::MIDINODE || c->end.lock()->getNodeType() == NodeType::MIDINODE;}) | std::ranges::to>>(); std::vector> config_nodes; for(auto e : config_conns){ if(e->start.lock().get() != this && e->start.lock()->getNodeType() == NodeType::MIDINODE) config_nodes.push_back(std::dynamic_pointer_cast(e->start.lock())); if(e->end.lock().get() != this && e->end.lock()->getNodeType() == NodeType::MIDINODE) config_nodes.push_back(std::dynamic_pointer_cast(e->end.lock())); } /*std::cout << "id: " << id << " n cn: " << config_nodes.size() << std::endl;*/ return config_nodes; } void ModNode::update() { Node::update(); mode = state->node_mode; } void ModNode::interact(){ float wheel = GetMouseWheelMove(); if(KEYS_DOWN.ctrl && !KEYS_DOWN.alt){ switch(state->node_mode){ case 0:{ midiNote.note += KEYS_DOWN.shift ? ((wheel > 0) - (wheel < 0)) * 12 : wheel; break;} case 1:{ midiCC.value += KEYS_DOWN.shift ? ((wheel > 0) - (wheel < 0)) * 12 : wheel; break;} case 2:{ midiPitchBend.value += KEYS_DOWN.shift ? ((wheel > 0) - (wheel < 0)) * 12 : wheel; break;} }; if(midiNote.note < -127 ) midiNote.note = -127; if(midiNote.note > 127 ) midiNote.note = 127; if(midiCC.value < -127 ) midiCC.value = -127; if(midiCC.value > 127 ) midiCC.value = 127; if(midiPitchBend.value < -16383 ) midiPitchBend.value = -16383; if(midiPitchBend.value > 16383 ) midiPitchBend.value = 16383; } else if(KEYS_DOWN.alt) { switch(state->node_mode){ case 0:{ midiNote.channel += wheel; if(midiNote.channel < 0 ) midiNote.channel = 0; if(midiNote.channel > 15) midiNote.channel = 15; break;} case 1:{ midiCC.channel += wheel; if(midiCC.channel < 0 ) midiCC.channel = 0; if(midiCC.channel > 15 ) midiCC.channel = 15; break;} case 2:{ midiPitchBend.channel += KEYS_DOWN.shift ? ((wheel > 0) - (wheel < 0)) * 100 : wheel; if(midiPitchBend.channel < 0 ) midiPitchBend.channel = 0; if(midiPitchBend.channel > 15 ) midiPitchBend.channel = 15; break;} }; } } void ModNode::draw(Vec2Df mouse, Camera2D cam) { Node::draw(); if(hovering() || selected) interact(); DrawRing(position, radius, radius+4, 0, 360, 24, (Color){60, 60, 60, 255}); DrawCircleLinesV(position, radius + 4, (Color){100, 100, 100, 255}); Color gate_color = VS_COLOR_GREEN; switch(mode){ case 0:{ gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){180, 210, 115 + 70, (unsigned char)Clamp(255, 0, 255)}, WHITE); break;} case 1:{ gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){229, 181, 103 + 70, (unsigned char)Clamp(255, 0, 255)}, WHITE); break;} case 2:{ gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){232, 125, 62 + 70, (unsigned char)Clamp(255, 0, 255)}, WHITE); break;} } if(!picked_up && !selected && !in_selection_rect && !hovering()) DrawCircle(position.x, position.y, radius, gate_color); if(picked_up || in_selection_rect || hovering()) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255}); if(selected) DrawCircle(position.x, position.y, radius, (Color){255, 153, 187, 255}); if(distributionMode == Distribution::RANDOM) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_PINK); if(distributionMode == Distribution::ROUNDROBIN) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_YELLOW); if(selected) DrawCircleLinesV(position, radius+8, (Color){158, 255, 210, 255}); if(KEYS_DOWN.alt){ float value = 0; int offset_gate = 0; switch(mode){ case 0: value = (float)getNotes().channel; offset_gate = MeasureText(std::format("{}", value).c_str(), 12); DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, VS_COLOR_BLACK ); break; case 1: value = (float)getCC().channel; offset_gate = MeasureText(std::format("{}", value).c_str(), 12); DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, VS_COLOR_BLACK ); break; case 2: value = (float)getPC().channel; offset_gate = MeasureText(std::format("{}", value).c_str(), 12); DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, VS_COLOR_BLACK ); break; case 3: value = (float)getPitchBend().channel; offset_gate = MeasureText(std::format("{}", value).c_str(), 12); DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, VS_COLOR_BLACK ); break; case 4: value = (float)getAftertouch().channel; offset_gate = MeasureText(std::format("{}", value).c_str(), 12); DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, VS_COLOR_BLACK ); break; case 5: value = (float)getPolyPressure().channel; offset_gate = MeasureText(std::format("{}", value).c_str(), 12); DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, VS_COLOR_BLACK ); break; } } else { switch(mode){ case 0:{ int offset = MeasureText(std::format("{:+}", getNotes().note).c_str(), 12); DrawText(std::format("{:+}", getNotes().note).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); break;} case 1:{ int offset = MeasureText(std::format("{:+}", getCC().value).c_str(), 12); DrawText(std::format("{:+}", getCC().value).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); break;} case 2:{ int offset = MeasureText(std::format("{:+}", getPC().value).c_str(), 12); DrawText(std::format("{:+}", getPC().value).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); break;} case 3:{ int offset = MeasureText(std::format("{:+}", getPitchBend().value).c_str(), 12); DrawText(std::format("{:+}", getPitchBend().value).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); break;} case 4:{ int offset = MeasureText(std::format("{:+}", getAftertouch().value).c_str(), 12); DrawText(std::format("{:+}", getAftertouch().value).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); break;} case 5:{ int offset = MeasureText(std::format("{:+}", getPolyPressure().value).c_str(), 12); DrawText(std::format("{:+}", getPolyPressure().value).c_str(), position.x-offset/2.0f, position.y-5, 12, VS_COLOR_BLACK ); break;} } } if(highlighted) DrawCircleLinesV(position, radius+2, (Color){255, 0, 0, 200}); //DrawText(std::format("{}", id).c_str(), position.x + 20.0f, position.y + 20.0f, 10, WHITE); } void to_json(json& j, const ModNode& N){ std::vector conns; std::ranges::transform(N.connections.begin(), N.connections.end(), std::back_inserter(conns), [](VISEQ::GRAPH::EDGES::SPTR_Edge e){ return e->id;}); j = json{ {"id", N.id}, {"position", N.position}, {"distributionMode", N.distributionMode}, {"nodeType", N.nodeType}, {"midi_note_channel",N.midiNote.channel}, {"midi_note_note",N.midiNote.note}, {"midi_note_velocity",N.midiNote.velocity}, {"midi_note_gate",N.midiNote.gate}, {"midi_cc_channel",N.midiCC.channel}, {"midi_cc_control",N.midiCC.control}, {"midi_cc_value",N.midiCC.value}, {"midi_pc_channel",N.midiPC.channel}, {"midi_pc_program",N.midiPC.program}, {"midi_pc_value",N.midiPC.value}, {"midi_pitch_bend_channel",N.midiPitchBend.channel}, {"midi_pitch_bend_value",N.midiPitchBend.value}, {"midi_aftertouch_channel",N.midiAftertouch.channel}, {"midi_aftertouch_value",N.midiAftertouch.value}, {"midi_polypressure_channel",N.midiPolyPressure.channel}, {"midi_polypressure_value",N.midiPolyPressure.value}, {"connections",conns}}; } void from_json(const json& j, ModNode& N){ std::cout << "configNode from_json" << std::endl; j.at("id").get_to(N.id); j.at("position").get_to(N.position); j.at("distributionMode").get_to(N.distributionMode); j.at("nodeType").get_to(N.nodeType); j.at("midi_note_channel").get_to(N.midiNote.channel); j.at("midi_note_note").get_to(N.midiNote.note); j.at("midi_note_velocity").get_to(N.midiNote.velocity); j.at("midi_note_gate").get_to(N.midiNote.gate); j.at("midi_cc_channel").get_to(N.midiCC.channel); j.at("midi_cc_control").get_to(N.midiCC.control); j.at("midi_cc_value").get_to(N.midiCC.value); j.at("midi_pc_channel").get_to(N.midiPC.channel); j.at("midi_pc_program").get_to(N.midiPC.program); j.at("midi_pc_value").get_to(N.midiPC.value); j.at("midi_pitch_bend_channel").get_to(N.midiPitchBend.channel); j.at("midi_pitch_bend_value").get_to(N.midiPitchBend.value); j.at("midi_aftertouch_channel").get_to(N.midiAftertouch.channel); j.at("midi_aftertouch_value").get_to(N.midiAftertouch.value); j.at("midi_polypressure_channel").get_to(N.midiPolyPressure.channel); j.at("midi_polypressure_value").get_to(N.midiPolyPressure.value); //j.at("connections").get_to(N.connections); } }