distance to closest node displayed, timing problems with midi notes being sent 1 to 3ms too early, or too late

This commit is contained in:
Sebastian
2024-10-28 02:07:47 +01:00
parent 58766cc373
commit 06cb6d8319
11 changed files with 68 additions and 70 deletions
-27
View File
@@ -1,27 +0,0 @@
## style: dark
Classical dark style with an extra high-def colour touch! Elegant and professional, perfect for the expensive tools!
![dark style table](style_dark.png)
## style: provided files
Several options are provided to add the style to a `raygui` application, choose the one that better fits the project.
| file name | description |
| :-------- | :---------- |
| `style_dark.rgs` | Binary style file (raygui 4.0), font data compressed (recs, glyphs) |
| `style_dark.txt.rgs` | Text style file, no font data, requires external font provided |
| `style_dark.old.rgs` | Binary style file (raygui 3.x), font data uncompressed (recs, glyphs) |
| `style_dark.h` | Embeddable style as code file, self-contained, includes font data |
| `style_dark.png` | Style table image, contains `rGSf` chunk with binary `rgs` file data |
## screenshot
![dark style screen](screenshot.png)
## about font
"Pixel Operator" font by de Jayvee Enaguas.
CC0 1.0 Universal, downloaded from dafont.com: [pixel-operator](https://www.dafont.com/pixel-operator.font)
+24 -24
View File
@@ -7,7 +7,7 @@
// more info and bugs-report: github.com/raysan5/raygui //
// feedback and support: ray[at]raylibtech.com //
// //
// Copyright (c) 2020-2023 raylib technologies (@raylibtech) //
// Copyright (c) 2020-2024 raylib technologies (@raylibtech) //
// //
//////////////////////////////////////////////////////////////////////////////////
@@ -15,29 +15,29 @@
// Custom style name: Dark
static const GuiStyleProp darkStyleProps[DARK_STYLE_PROPS_COUNT] = {
{ 0, 0, (long)0x878787ff }, // DEFAULT_BORDER_COLOR_NORMAL
{ 0, 1, (long)0x2c2c2cff }, // DEFAULT_BASE_COLOR_NORMAL
{ 0, 2, (long)0xc3c3c3ff }, // DEFAULT_TEXT_COLOR_NORMAL
{ 0, 3, (long)0xe1e1e1ff }, // DEFAULT_BORDER_COLOR_FOCUSED
{ 0, 4, (long)0x848484ff }, // DEFAULT_BASE_COLOR_FOCUSED
{ 0, 5, (long)0x181818ff }, // DEFAULT_TEXT_COLOR_FOCUSED
{ 0, 6, (long)0x000000ff }, // DEFAULT_BORDER_COLOR_PRESSED
{ 0, 7, (long)0xefefefff }, // DEFAULT_BASE_COLOR_PRESSED
{ 0, 8, (long)0x202020ff }, // DEFAULT_TEXT_COLOR_PRESSED
{ 0, 9, (long)0x6a6a6aff }, // DEFAULT_BORDER_COLOR_DISABLED
{ 0, 10, (long)0x818181ff }, // DEFAULT_BASE_COLOR_DISABLED
{ 0, 11, (long)0x606060ff }, // DEFAULT_TEXT_COLOR_DISABLED
{ 0, 16, (long)0x00000010 }, // DEFAULT_TEXT_SIZE
{ 0, 17, (long)0x00000000 }, // DEFAULT_TEXT_SPACING
{ 0, 18, (long)0x9d9d9dff }, // DEFAULT_LINE_COLOR
{ 0, 19, (long)0x3c3c3cff }, // DEFAULT_BACKGROUND_COLOR
{ 0, 20, (long)0x00000018 }, // DEFAULT_TEXT_LINE_SPACING
{ 1, 5, (long)0xf7f7f7ff }, // LABEL_TEXT_COLOR_FOCUSED
{ 1, 8, (long)0x898989ff }, // LABEL_TEXT_COLOR_PRESSED
{ 4, 5, (long)0xb0b0b0ff }, // SLIDER_TEXT_COLOR_FOCUSED
{ 5, 5, (long)0x848484ff }, // PROGRESSBAR_TEXT_COLOR_FOCUSED
{ 9, 5, (long)0xf5f5f5ff }, // TEXTBOX_TEXT_COLOR_FOCUSED
{ 10, 5, (long)0xf6f6f6ff }, // VALUEBOX_TEXT_COLOR_FOCUSED
{ 0, 0, 0x878787ff }, // DEFAULT_BORDER_COLOR_NORMAL
{ 0, 1, 0x2c2c2cff }, // DEFAULT_BASE_COLOR_NORMAL
{ 0, 2, 0xc3c3c3ff }, // DEFAULT_TEXT_COLOR_NORMAL
{ 0, 3, 0xe1e1e1ff }, // DEFAULT_BORDER_COLOR_FOCUSED
{ 0, 4, 0x848484ff }, // DEFAULT_BASE_COLOR_FOCUSED
{ 0, 5, 0x181818ff }, // DEFAULT_TEXT_COLOR_FOCUSED
{ 0, 6, 0x000000ff }, // DEFAULT_BORDER_COLOR_PRESSED
{ 0, 7, 0xefefefff }, // DEFAULT_BASE_COLOR_PRESSED
{ 0, 8, 0x202020ff }, // DEFAULT_TEXT_COLOR_PRESSED
{ 0, 9, 0x6a6a6aff }, // DEFAULT_BORDER_COLOR_DISABLED
{ 0, 10, 0x818181ff }, // DEFAULT_BASE_COLOR_DISABLED
{ 0, 11, 0x606060ff }, // DEFAULT_TEXT_COLOR_DISABLED
{ 0, 16, 0x00000010 }, // DEFAULT_TEXT_SIZE
{ 0, 17, 0x00000000 }, // DEFAULT_TEXT_SPACING
{ 0, 18, 0x9d9d9dff }, // DEFAULT_LINE_COLOR
{ 0, 19, 0x3c3c3cff }, // DEFAULT_BACKGROUND_COLOR
{ 0, 20, 0x00000018 }, // DEFAULT_TEXT_LINE_SPACING
{ 1, 5, 0xf7f7f7ff }, // LABEL_TEXT_COLOR_FOCUSED
{ 1, 8, 0x898989ff }, // LABEL_TEXT_COLOR_PRESSED
{ 4, 5, 0xb0b0b0ff }, // SLIDER_TEXT_COLOR_FOCUSED
{ 5, 5, 0x848484ff }, // PROGRESSBAR_TEXT_COLOR_FOCUSED
{ 9, 5, 0xf5f5f5ff }, // TEXTBOX_TEXT_COLOR_FOCUSED
{ 10, 5, 0xf6f6f6ff }, // VALUEBOX_TEXT_COLOR_FOCUSED
};
// WARNING: This style uses a custom font: "PixelOperator.ttf" (size: 16, spacing: 0)
+1
View File
@@ -38,6 +38,7 @@ class Vec2D{
T x = 0;
T y = 0;
T dist(Vec2D* v) { return sqrt(pow((v->x - x), 2) + pow((v->y - y), 2));};
T dist(Vec2D v) { return sqrt(pow((v.x - x), 2) + pow((v.y - y), 2));};
T length() { return (T)sqrt(pow(x, 2) + pow(y, 2));};
+2 -2
View File
@@ -66,8 +66,8 @@ int main(){
app.settings.speed = (app.settings.grid * 8.0f) * (app.settings.bpm / 120.f);
app.settings.width = monitor_width;
app.settings.height = monitor_height;
app.settings.width = monitor_width - 300;
app.settings.height = monitor_height - 300;
SetTargetFPS(app.settings.fps);
+2 -2
View File
@@ -76,7 +76,7 @@ class Midi {
}
void note(int midi_out, int channel, int note, int velocity, int gate){
if(!midi_outs.empty()){
if(midi_outs.contains(midi_out)){
if(midi_outs[midi_out]->is_port_open()){
midi_outs[midi_out]->send_message(libremidi::channel_events::note_on(channel, note, velocity));
notes.emplace_back(midi_out, channel, note, velocity, GetTime(), gate);
@@ -88,7 +88,7 @@ class Midi {
float time = GetTime();
for(auto &n : notes){
if(time - n.start >= (float)n.gate / 1000.0f){
midi_outs[n.midi_out]->send_message(libremidi::channel_events::note_off(n.channel, n.note, n.velocity));
if(midi_outs.contains(n.midi_out) && midi_outs[n.midi_out]->is_port_open()) midi_outs[n.midi_out]->send_message(libremidi::channel_events::note_off(n.channel, n.note, n.velocity));
n.erase = true;
}
}
+1
View File
@@ -18,6 +18,7 @@ class Movable{
Vec2D<float> direction;
virtual void update(int fps) {};
virtual void update(double frametime) {};
virtual void update() {};
virtual void draw(Vec2D<float> *mouse, Camera2D *cam) {};
+16
View File
@@ -1,6 +1,9 @@
#pragma once
#include "datatypes.h"
#include "node.h"
#include "raylib.h"
#include "raymath.h"
#include <algorithm>
#include <iterator>
#include <random>
@@ -57,7 +60,20 @@ class NodeManager{
}
void drawNodes(Vec2D<float> *mouse_pos, Camera2D *camera){
auto flat_nodes = nodes | std::ranges::views::values | std::ranges::to<std::vector<Node>>();
for(auto& n : nodes | std::ranges::views::values ){
if(n.dragging){
std::sort(flat_nodes.begin(), flat_nodes.end(), [n](Node na, Node nb){ return na.position.dist(n.position) < nb.position.dist(n.position);});
float d = flat_nodes.at(1).position.dist(n.position);
if(d > 0 && d < 240) {
Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",d).c_str(), 10.0f, 2.0f);
Vec2D<float> middle_handle = flat_nodes.at(1).position + (n.position - flat_nodes.at(1).position) * ((d - text_length.x)*0.5f)/d;
Vec2D<float> text_position = middle_handle + (flat_nodes.at(1).position - n.position).norm().orth() * 12.0f;
float rotation = Vector2Angle((Vector2){1,0}, (n.position - flat_nodes.at(1).position)) * RAD2DEG;
DrawTextPro(GetFontDefault(), std::format("{:.1f}",d).c_str(), text_position, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK);
DrawLineV(n.position, flat_nodes.at(1).position, VS_COLOR_PINK);
}
}
n.draw(mouse_pos, camera);
}
}
+10 -6
View File
@@ -71,22 +71,24 @@ class SignalManager{
}
void updateSignals(){
auto last = std::chrono::steady_clock::now();
auto last = std::chrono::high_resolution_clock::now();
while(loop){
std::chrono::duration<double, std::micro> diff = std::chrono::steady_clock::now() - last;
if(diff.count() > 500){
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 = (nm->nodes[s.next].position - s.position).norm();
s.update(diff.count());
if(s.position.dist(&nm->nodes[s.next].position) < 1.0f) {
if(s.position.dist(&nm->nodes[s.next].position) < 0.6f) {
int n = cm->next(s.next, s.last);
nm->nodes[s.next].trigger();
if(n != s.next && n != -1) {
for(auto &m : nm->nodes[s.next].midi_outs){
if(m.second.enabled) midi.note(m.second.i, nm->nodes[s.next].midi_channel, nm->nodes[s.next].midi_note, nm->nodes[s.next].midi_velocity, nm->nodes[s.next].midi_gate);
if(m.second.enabled) {
midi.note(m.second.i, nm->nodes[s.next].midi_channel, nm->nodes[s.next].midi_note, nm->nodes[s.next].midi_velocity, nm->nodes[s.next].midi_gate);
}
}
s.last = s.next;
s.next = n;
@@ -96,14 +98,16 @@ class SignalManager{
}
midi.update();
mutex->unlock();
last = std::chrono::steady_clock::now();
last = std::chrono::high_resolution_clock::now();
}
}
}
void drawSignals(Vec2D<float> *mouse_pos, Camera2D *camera){
for(auto& s : signals){
mutex->lock();
s.draw(mouse_pos, camera);
mutex->unlock();
}
}
+1 -1
View File
@@ -28,7 +28,7 @@ class Signal : public Movable{
Color color;
void update(int t_delta){
void update(double t_delta){
// 120px / 16th = 1920px / whole note
// whole note = 2s at 120bpm
// 960px / s
+3 -1
View File
@@ -53,6 +53,8 @@ class AppState{
for(auto &n : copy_nodes_ids){
int old_id = n;
int new_id = nm.copyNode(n, position + nm.nodes[n].drag_offset);
nm.nodes[new_id].copied = false;
nm.nodes[new_id].selected = true;
for(auto &c : copy_connections){
if(c.v1 == old_id) c.v1 = new_id;
@@ -121,10 +123,10 @@ class AppState{
void draw(Vec2D<float> *mouse_pos, Camera2D *camera){
mutex.lock();
updateMidiPorts();
mutex.unlock();
nm.drawNodes(mouse_pos, camera);
cm.drawConnections(mouse_pos, camera);
sm.drawSignals(mouse_pos, camera);
mutex.unlock();
}
void drawUI(Vec2D<float> *mouse_pos, Camera2D *camera){
+7 -6
View File
@@ -27,12 +27,13 @@ class AppUI{
void drawSideBar(){
GuiWindowBox((Rectangle){0,0,280,(float)settings->height}, "config");
GuiPanel((Rectangle){-1,-30,280,(float)settings->height + 31}, "");
{
const int s_controls = 55;
if(GuiButton((Rectangle){20, (float)s_controls, 60, 30}, "PLAY")) sm->play ? sm->pause() : sm->start();
if(GuiButton((Rectangle){100, (float)s_controls, 60, 30}, "STOP")) sm->stop();
if(GuiButton((Rectangle){180, (float)s_controls, 60, 30}, "RESET")) sm->reset();
const int s_controls = 20;
//GuiSetStyle(BUTTON, STATE_FOCUSED, 0xFF0000FF);
if(GuiButton((Rectangle){20, (float)s_controls, 80, 30}, "PLAY")) sm->play ? sm->pause() : sm->start();
if(GuiButton((Rectangle){120, (float)s_controls, 60, 30}, "STOP")) sm->stop();
if(GuiButton((Rectangle){200, (float)s_controls, 60, 30}, "RESET")) sm->reset();
const int s_bpm = s_controls + 35;
GuiLabel((Rectangle){20, (float)s_bpm, 120, 20}, "TIMING");
@@ -83,7 +84,7 @@ class AppUI{
if(GuiButton((Rectangle){20, (float)s_nodes + 60, 240, 20}, "ADD RANDOM NODE")){
nm->addNode(200.0f, 200.0f);
}
DrawText(std::format("{}", nm->nodes.size()).c_str(), 20, settings->height - 70, 15, VS_COLOR_WHITE);
DrawFPS(20, settings->height - 30);
}
}