Files
viseq/src/main.cpp
T

284 lines
8.8 KiB
C++
Raw Normal View History

2024-10-09 02:01:23 +02:00
/*
*
* VISEQ - Visual Sequencer
*
*
*/
/*Background: (46, 46, 46); #2e2e2e*/
/*Comments: (121, 121, 121); #797979*/
/*White: (214, 214, 214); #d6d6d6*/
/*Yellow: (229, 181, 103); #e5b567*/
/*Green: (180, 210, 115); #b4d273*/
/*Orange: (232, 125, 62); #e87d3e*/
/*Purple: (158, 134, 200); #9e86c8*/
/*Pink: (176, 82, 121); #b05279*/
/*Blue: (108, 153, 187); #6c99bb*/
2024-10-16 02:26:02 +02:00
#include "datatypes.h"
2024-10-20 01:17:18 +02:00
#include <format>
2024-10-16 02:26:02 +02:00
#include <iostream>
#include <raylib.h>
#include <raymath.h>
#define RAYGUI_IMPLEMENTATION
#include "raygui/raygui.h"
#include "raygui/dark/style_dark.h"
2024-10-09 02:01:23 +02:00
#include <cstdlib>
#include <stdio.h>
#include <cmath>
#include "midi.h"
2024-10-09 02:01:23 +02:00
#include "node.h"
#include "signal.h"
#include "connection-manager.h"
2024-10-09 02:01:23 +02:00
std::vector<Node> nodes;
std::vector<Signal> signals;
ConnectionManager cm;
Midi midi;
2024-10-09 02:01:23 +02:00
Vec2D<float> mouse_pos;
Vec2D<float> drag_start;
bool mouse_clicked = false;
bool mouse_touched = false;
bool mouse_dragging = false;
2024-10-09 02:01:23 +02:00
enum States {IDLE, CONFIG};
struct AppState{
int width;
int height;
int gui_selected_midi_out;
States state;
} app;
2024-10-09 02:01:23 +02:00
int main(){
srand(time(NULL));
InitWindow(2560, 1440, "VISEQ");
GuiLoadStyleDark();
int monitor = 0; //GetCurrentMonitor();
SetWindowMonitor(monitor);
app.width = GetMonitorWidth(monitor);
app.height = GetMonitorHeight(monitor);
Camera2D camera = { {0} };
camera.target = (Vector2){ app.width/2.0f, app.height/2.0f };
camera.offset = (Vector2){ app.width/2.0f, app.height/2.0f };
camera.rotation = 0.0f;
camera.zoom = 1.0f;
SetTargetFPS(120);
ToggleFullscreen();
2024-10-09 02:01:23 +02:00
for(int i = 0; i < 10; i++){
2024-10-16 02:26:02 +02:00
nodes.emplace(nodes.end(), Node((float)(rand() % app.width*0.5 + app.width*0.25), (float)(rand() % app.height*0.5 + app.height*0.25), 15.0f));
std::cout << nodes.back().position.x << " " << nodes.back().position.y << std::endl;
2024-10-09 02:01:23 +02:00
}
2024-10-16 02:26:02 +02:00
for(int i = 0; i < 1; i++){
signals.emplace(signals.end(), Signal(nodes.front().position.x+1, nodes.front().position.y+1, 5.0f, 2.0f)); // position + 1 or else it does not render. why? no idea!
signals[i].next = &nodes.front();
signals[i].last = &nodes.front();
2024-10-09 02:01:23 +02:00
}
2024-10-18 01:27:14 +02:00
2024-10-13 15:07:19 +02:00
Vec2D<float> drag_offset;
2024-10-09 02:01:23 +02:00
2024-10-16 02:26:02 +02:00
Node* connecting_from = nullptr;
double drag_timer = GetTime();
while(!WindowShouldClose()){
2024-10-09 02:01:23 +02:00
Vector2 mp = GetScreenToWorld2D(GetMousePosition(), camera);
2024-10-10 02:59:27 +02:00
Vec2D<float> mouse_pos = {(float)mp.x, (float)mp.y};
2024-10-09 02:01:23 +02:00
bool mouse_down = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
bool mouse_clicked = IsMouseButtonPressed(MOUSE_BUTTON_LEFT);
bool mouse_released = IsMouseButtonReleased(MOUSE_BUTTON_LEFT);
2024-10-10 02:59:27 +02:00
if(mouse_clicked){
2024-10-10 02:59:27 +02:00
drag_start = mouse_pos;
}
BeginDrawing();
2024-10-09 02:01:23 +02:00
ClearBackground((Color){46,46,46});
BeginMode2D(camera);
2024-10-16 02:26:02 +02:00
bool connecting = false;
bool dragging = false;
2024-10-13 15:07:19 +02:00
for(auto& n : nodes){
2024-10-18 01:27:14 +02:00
Vec2D<float> connector_position = n.position - ((n.position - mouse_pos)).norm() * (n.radius + 14.0f);
float dist_connector = (connector_position - mouse_pos).length();
float dist = (n.position - mouse_pos).length();
2024-10-13 15:07:19 +02:00
// connect nodes
if( (dist <= n.radius + 25.0f && dist > n.radius) || n.connecting){
n.hover_connect = true;
} else {
n.hover_connect = false;
}
2024-10-18 01:27:14 +02:00
if(dist_connector <= 8.0f && mouse_clicked && !connecting) {
connecting_from = &n;
n.connecting = true;
2024-10-16 02:26:02 +02:00
connecting = true;
}
if(n.connecting && mouse_down){
DrawLine(connector_position.x, connector_position.y, mouse_pos.x, mouse_pos.y, (Color){229, 181, 103, 255});
}
if(mouse_released && n.connecting) {
n.connecting = false;
2024-10-16 02:26:02 +02:00
//connecting_from = nullptr;
}
2024-10-13 15:07:19 +02:00
if(mouse_released && (n.hover_connect || n.hover_move)) {
if(&n != connecting_from && connecting_from != nullptr){
cm.connections.emplace(cm.connections.end(), connecting_from, &n);
connecting_from = nullptr;
2024-10-13 15:07:19 +02:00
}
}
2024-10-16 02:26:02 +02:00
if(!connecting){
// move node
if((n.position - mouse_pos).length() <= n.radius || n.picked_up){
n.hover_move = true;
} else {
n.hover_move = false;
}
2024-10-13 15:07:19 +02:00
2024-10-16 02:26:02 +02:00
if(mouse_clicked && n.hover_move && !dragging){
n.picked_up = true;
drag_offset = n.position - mouse_pos;
dragging = true;
drag_timer = GetTime();
}
if(mouse_down && n.picked_up){
if(GetTime() - drag_timer > 0.1) n.position = mouse_pos + drag_offset;
}
2024-10-16 02:26:02 +02:00
if(mouse_released && n.picked_up){
if(GetTime() - drag_timer < 0.1) n.config = true;
}
if(mouse_released) {
n.picked_up = false;
}
}
n.draw(&mouse_pos);
}
cm.draw();
for(auto& s : signals){
2024-10-16 02:26:02 +02:00
s.direction = (s.next->position - s.position).norm();
if(s.position.dist(&s.next->position) < s.speed * 1.5) {
2024-10-16 02:26:02 +02:00
Node* n = cm.next(s.next, s.last);
if(n != s.next && n != nullptr) {
2024-10-20 01:17:18 +02:00
for(auto &m : s.next->midi_outs){
if(m.second.enabled) midi.note(m.second.i, s.next->midi_channel, s.next->midi_note, s.next->midi_velocity, s.next->midi_gate);
}
2024-10-16 02:26:02 +02:00
s.last = s.next;
s.next = n;
}
}
s.draw(&mouse_pos);
}
midi.update();
EndMode2D();
// Main Config Window
GuiWindowBox((Rectangle){0,0,280,(float)app.height}, "config");
{
GuiLabel((Rectangle){20, 60, 240, 20}, "MIDI OUT");
int i = 0;
for(auto& mo : midi.midi_out_ports){
GuiCheckBox((Rectangle){20, 80 + i*20.0f, 20, 20}, mo.port.port_name.c_str(), &mo.enabled);
i++;
}
if(GuiButton((Rectangle){20, 60, 240, 20}, "ADD SIGNAL")){
signals.emplace_back(Signal(nodes.front().position.x + 1, nodes.front().position.y + 1, 5.0f, 2.0f)); // position + 1 or else it does not render. why? no idea!
signals.back().next = &nodes[0];
signals.back().last = &nodes[0];
}
2024-10-16 02:26:02 +02:00
}
2024-10-16 02:26:02 +02:00
for(auto& n : nodes){
if(n.config){
n.config = !GuiWindowBox((Rectangle){n.position.x + 10, n.position.y + 10,240,300}, "config");
2024-10-16 02:26:02 +02:00
int option = n.mode;
GuiComboBox((Rectangle){ n.position.x + 20, n.position.y + 40, 220, 20 }, "Round Robin;Random", &option);
2024-10-16 02:26:02 +02:00
n.mode = (Distribution)option;
2024-10-20 01:17:18 +02:00
int y_midi = 60;
GuiLabel((Rectangle){n.position.x + 20, n.position.y + y_midi, 220, 20}, "MIDI OUT");
for(auto& mo : midi.midi_out_ports){
2024-10-20 01:17:18 +02:00
if(!n.midi_outs.contains(mo.number) && mo.enabled){
n.midi_outs[mo.number] = {mo.number, mo.port.port_name, false};
}
}
2024-10-20 01:17:18 +02:00
int i = 0;
for(auto& mo : n.midi_outs){
GuiCheckBox((Rectangle){n.position.x + 20, n.position.y + y_midi + 20 + i*20.0f, 20, 20}, mo.second.name.c_str(), &mo.second.enabled);
i++;
}
2024-10-20 01:17:18 +02:00
int y_channel = y_midi + 20 + i*20;
if(GuiValueBox((Rectangle){n.position.x + 100, n.position.y + y_channel, 140, 20}, "CHANNEL", &n.midi_channel, 0, 15, n.gui_midi_channel_edit)) n.gui_midi_channel_edit = !n.gui_midi_channel_edit;
if(GuiValueBox((Rectangle){n.position.x + 100, n.position.y + y_channel + 20, 140, 20}, "NOTE", &n.midi_note, 0, 127, n.gui_midi_note_edit)) n.gui_midi_note_edit = !n.gui_midi_note_edit;
if(GuiValueBox((Rectangle){n.position.x + 100, n.position.y + y_channel + 40, 140, 20}, "VELOCITY", &n.midi_velocity, 0, 127, n.gui_midi_velocity_edit)) n.gui_midi_velocity_edit = !n.gui_midi_velocity_edit;
if(GuiValueBox((Rectangle){n.position.x + 100, n.position.y + y_channel + 60, 140, 20}, "GATE", &n.midi_gate, 0, 5000, n.gui_midi_gate_edit)) n.gui_midi_gate_edit = !n.gui_midi_gate_edit;
2024-10-20 01:17:18 +02:00
float v = n.midi_channel;
GuiSlider((Rectangle){n.position.x + 100, n.position.y + y_channel + 80, 120, 20}, "CHANNEL", std::format("{}",(int)v).c_str(), &v, 0.0f, 15.0f);
n.midi_channel = (int)round(v);
GuiToggleGroup((Rectangle){n.position.x + 20, n.position.y + y_channel + 100, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &n.midi_channel);
GuiToggleGroup((Rectangle){n.position.x + 20, n.position.y + y_channel + 140, 25, 20}, "C-1;C#-1;D-1;D#-1;E-1;F-1;F#-1;G-1\nG#-1;A-1;A#-1;B-1;C0;C#0;D0;D#0\nE0;F0;F#0;G0;G#0;A0;A#0;B0\nC1;C#1;D1;D#1;E1;F1;F#1;G1\nG#1;A1;A#1;B1;C2;C#2;D2;D#2\nE2;F2;F#2;G2;G#2;A2;A#2;B2\nC3;C#3;D3;D#3;E3;F3;F#3;G3\nG#3;A3;A#3;B3;C4;C#4;D4;D#4\nE4;F4;F#4;G4;G#4;A4;A#4;B4\nC5;C#5;D5;D#5;E5;F5;F#5;G5\nG#5;A5;A#5;B5;C6;C#6;D6;D#6\nE6;F6;F#6;G6;G#6;A6;A#6;B6\nC7;C#7;D7;D#7;E7;F7;F#7;G7\nG#7;A7;A#7;B7;C8;C#8;D8;D#8\nE8;F8;F#8;G8;G#8;A8;A#8;B8\nC9;C#9;D9;D#9;E9;F9;F#9;G9\nG#9;A9;A#9;B9;C10", &n.midi_note);
2024-10-18 01:27:14 +02:00
}
}
for(auto& c : cm.connections){
if(c.config){
Vec2D<float> config_handle = c.v2->position - ((c.v2->position - c.v1->position))*0.75f;
c.config = !GuiWindowBox((Rectangle){config_handle.x + 10, config_handle.y + 10, 200, 300}, "connection");
GuiToggle((Rectangle){config_handle.x + 10, config_handle.y + 50, 80, 20}, "v1v2", &c.v1_v2);
GuiToggle((Rectangle){config_handle.x + 100, config_handle.y + 50, 80, 20}, "v2v1", &c.v2_v1);
2024-10-16 02:26:02 +02:00
}
}
EndDrawing();
2024-10-09 02:01:23 +02:00
}
CloseWindow();
return 0;
2024-10-09 02:01:23 +02:00
}
2024-10-10 02:59:27 +02:00
2024-10-09 02:01:23 +02:00