2024-10-09 02:01:23 +02:00
/*
*
* VISEQ - Visual Sequencer
*
*
*/
2024-10-13 04:22:09 +02:00
/*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>
2024-10-13 04:22:09 +02:00
# 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>
2024-10-19 04:08:46 +02:00
# include "midi.h"
2024-10-09 02:01:23 +02:00
# include "node.h"
# include "signal.h"
2024-10-15 02:59:26 +02:00
# include "connection-manager.h"
2024-10-09 02:01:23 +02:00
std : : vector < Node > nodes ;
std : : vector < Signal > signals ;
2024-10-15 02:59:26 +02:00
ConnectionManager cm ;
2024-10-13 04:22:09 +02:00
2024-10-19 04:08:46 +02:00
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 ;
2024-10-13 04:22:09 +02:00
bool mouse_dragging = false ;
2024-10-09 02:01:23 +02:00
2024-10-13 04:22:09 +02:00
enum States { IDLE , CONFIG } ;
struct AppState {
int width ;
int height ;
2024-10-19 17:41:31 +02:00
int gui_selected_midi_out ;
2024-10-13 04:22:09 +02:00
States state ;
} app ;
2024-10-09 02:01:23 +02:00
int main ( ) {
srand ( time ( NULL ) ) ;
2024-10-13 04:22:09 +02:00
InitWindow ( 2560 , 1440 , " VISEQ " ) ;
GuiLoadStyleDark ( ) ;
int monitor = 0 ; //GetCurrentMonitor();
SetWindowMonitor ( monitor ) ;
app . width = GetMonitorWidth ( monitor ) ;
app . height = GetMonitorHeight ( monitor ) ;
2024-10-19 04:08:46 +02:00
Camera2D camera = { { 0 } } ;
2024-10-13 04:22:09 +02:00
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 ( ) ;
2024-10-13 04:22:09 +02:00
while ( ! WindowShouldClose ( ) ) {
2024-10-09 02:01:23 +02:00
2024-10-13 04:22:09 +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
2024-10-13 04:22:09 +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
2024-10-13 04:22:09 +02:00
if ( mouse_clicked ) {
2024-10-10 02:59:27 +02:00
drag_start = mouse_pos ;
}
2024-10-13 04:22:09 +02:00
BeginDrawing ( ) ;
2024-10-09 02:01:23 +02:00
2024-10-13 04:22:09 +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 04:22:09 +02:00
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 ) ;
2024-10-13 04:22:09 +02:00
float dist_connector = ( connector_position - mouse_pos ) . length ( ) ;
float dist = ( n . position - mouse_pos ) . length ( ) ;
2024-10-13 15:07:19 +02:00
2024-10-13 04:22:09 +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 ) {
2024-10-13 04:22:09 +02:00
connecting_from = & n ;
n . connecting = true ;
2024-10-16 02:26:02 +02:00
connecting = true ;
2024-10-13 04:22:09 +02:00
}
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 04:22:09 +02:00
}
2024-10-13 15:07:19 +02:00
if ( mouse_released & & ( n . hover_connect | | n . hover_move ) ) {
2024-10-15 02:59:26 +02:00
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-13 04:22:09 +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-13 04:22:09 +02:00
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 ;
}
2024-10-13 04:22:09 +02:00
}
n . draw ( & mouse_pos ) ;
}
2024-10-15 02:59:26 +02:00
cm . draw ( ) ;
2024-10-13 04:22:09 +02:00
2024-10-15 02:59:26 +02:00
for ( auto & s : signals ) {
2024-10-16 02:26:02 +02:00
s . direction = ( s . next - > position - s . position ) . norm ( ) ;
2024-10-13 04:22:09 +02:00
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 ) ;
2024-10-19 04:08:46 +02:00
2024-10-15 02:59:26 +02:00
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 ;
2024-10-15 02:59:26 +02:00
s . next = n ;
2024-10-13 04:22:09 +02:00
}
}
s . draw ( & mouse_pos ) ;
}
2024-10-19 17:41:31 +02:00
midi . update ( ) ;
2024-10-13 04:22:09 +02:00
EndMode2D ( ) ;
2024-10-19 17:41:31 +02:00
// 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-19 17:41:31 +02:00
2024-10-16 02:26:02 +02:00
for ( auto & n : nodes ) {
if ( n . config ) {
2024-10-20 02:01:30 +02:00
n . config = ! GuiWindowBox ( ( Rectangle ) { n . position . x + 10 , n . position . y + 10 , 240 , 400 } , " config " ) ;
2024-10-16 02:26:02 +02:00
int option = n . mode ;
2024-10-19 04:08:46 +02:00
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 " ) ;
2024-10-19 04:08:46 +02:00
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-19 17:41:31 +02:00
}
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-19 04:08:46 +02:00
}
2024-10-20 01:17:18 +02:00
int y_channel = y_midi + 20 + i * 20 ;
2024-10-20 02:01:30 +02:00
GuiLabel ( ( Rectangle ) { n . position . x + 20 , n . position . y + y_channel , 220 , 20 } , " CHANNEL " ) ;
GuiToggleGroup ( ( Rectangle ) { n . position . x + 20 , n . position . y + y_channel + 30 , 25 , 20 } , " 1;2;3;4;5;6;7;8 \n 9;10;11;12;13;14;15;16 " , & n . midi_channel ) ;
GuiLabel ( ( Rectangle ) { n . position . x + 20 , n . position . y + y_channel + 90 , 100 , 20 } , " NOTE " ) ;
float v = n . midi_note ;
GuiLabel ( ( Rectangle ) { n . position . x + 210 , n . position . y + y_channel + 90 , 20 , 20 } , midi . midiNotes [ ( int ) round ( v ) ] . c_str ( ) ) ;
GuiLabel ( ( Rectangle ) { n . position . x + 160 , n . position . y + y_channel + 90 , 40 , 20 } , std : : format ( " {} " , n . midi_note ) . c_str ( ) ) ;
GuiSlider ( ( Rectangle ) { n . position . x + 20 , n . position . y + y_channel + 120 , 220 , 20 } , " " , " " , & v , 0 , 127 ) ;
n . midi_note = round ( v ) ;
GuiLabel ( ( Rectangle ) { n . position . x + 20 , n . position . y + y_channel + 150 , 100 , 20 } , " VELOCITY " ) ;
v = n . midi_velocity ;
GuiLabel ( ( Rectangle ) { n . position . x + 210 , n . position . y + y_channel + 150 , 20 , 20 } , std : : format ( " {} " , n . midi_velocity ) . c_str ( ) ) ;
GuiSlider ( ( Rectangle ) { n . position . x + 20 , n . position . y + y_channel + 180 , 220 , 20 } , " " , " " , & v , 0 , 127 ) ;
n . midi_velocity = round ( v ) ;
2024-10-20 01:17:18 +02:00
2024-10-20 02:01:30 +02:00
GuiLabel ( ( Rectangle ) { n . position . x + 20 , n . position . y + y_channel + 210 , 100 , 20 } , " GATE " ) ;
v = n . midi_gate ;
GuiLabel ( ( Rectangle ) { n . position . x + 210 , n . position . y + y_channel + 210 , 20 , 20 } , std : : format ( " {} " , ( float ) n . midi_gate / 1000.0f ) . c_str ( ) ) ;
GuiSlider ( ( Rectangle ) { n . position . x + 20 , n . position . y + y_channel + 240 , 220 , 20 } , " " , " " , & v , 0 , 5000 ) ;
n . midi_gate = round ( v ) ;
2024-10-20 01:17:18 +02:00
2024-10-20 02:01:30 +02:00
//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-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
}
}
2024-10-13 04:22:09 +02:00
EndDrawing ( ) ;
2024-10-09 02:01:23 +02:00
}
2024-10-13 04:22:09 +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