From a8be0d3d20f07d4561826b01f566ca307eb23526 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Fri, 12 Aug 2016 14:46:51 +0200 Subject: commit as a backup --- engine.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 engine.c (limited to 'engine.c') diff --git a/engine.c b/engine.c new file mode 100644 index 0000000..ae62cb5 --- /dev/null +++ b/engine.c @@ -0,0 +1,220 @@ +#include +#include + +#include "config.h" +#include "engine.h" +#include "display.h" +#include "main.h" +#include "midi.h" + +static int g_selected_string = -1; + +#ifndef NO_DISPLAY +static LPoint g_render_points[1024]; +static int g_render_point_count; +static const int g_harfe_width = 1024; +static const int g_harfe_height = 768; +static int g_factor = 1<<16; + +static inline int scale(int coord) { + return (int)(((((int64_t)coord) << 32) / g_factor ) >> 16); +} + +void +engine_redraw() +{ + int i; + + display_redraw(); + display_clear(); + display_text(g_harfe_connected ? "online" : "offline", 4, 4, 0xffffffff); + + for (i = 0; i < g_string_count; ++i) { + LLine *l = &g_string_conf[i].line; + uint32_t color = i == g_selected_string ? 0xff00ffff : 0x00ffffffff; + + display_line_color(scale(l->x0), scale(l->y0), scale(l->x1), scale(l->y1), color); + display_circle(scale(l->x0), scale(l->y0), 4); + display_circle(scale(l->x1), scale(l->y1), 4); + + if (g_string_conf[i].playing) + display_text(config_midi_note_to_string(g_string_conf[i].note+12*g_string_conf[i].octave), scale(l->x1) - 20, g_height - 40, color ); + else + display_text(config_midi_note_to_string(g_string_conf[i].note), scale(l->x1) - 20, g_height - 40, color ); + } + g_selected_string = -1; + + for (i = 0; i < g_render_point_count; ++i) + display_circle_color(scale(g_render_points[i].x), scale(g_render_points[i].y), 4, 0xff0000ff); + g_render_point_count = 0; + + display_line_color(0, scale(g_min_y), g_width, scale(g_min_y), 0xff00ffff); + display_line_color(0, scale(g_max_y), g_width, scale(g_max_y), 0xff00ffff); + + if (g_min_y != g_max_y) { + int height = scale(g_max_y - g_min_y); + + display_line_color(0, scale(g_max_y) - g_midi_two_octave_split * height / 256, g_width, scale(g_max_y) - g_midi_two_octave_split * height / 256, 0xffff00ff); + + display_line_color(0, scale(g_max_y) - g_midi_three_octave_split_1 * height / 256, g_width, scale(g_max_y) - g_midi_three_octave_split_1 * height / 256, 0x00ff00ff); + display_line_color(0, scale(g_max_y) - g_midi_three_octave_split_2 * height / 256, g_width, scale(g_max_y) - g_midi_three_octave_split_2 * height / 256, 0x00ff00ff); + } +} + +#endif + +void +engine_init() { +#ifndef NO_DISPLAY + g_factor = (g_harfe_width << 16) / g_width; + if ((g_harfe_height << 16) / g_height < g_factor) + g_factor = (g_harfe_height << 16) / g_height; +#endif +} + +static int +dist_pp(int x0, int y0, int x1, int y1) +{ + return (y0 - y1) * (y0 - y1) + (x0 - x1) * (x0 - x1); +} + +// dist is a fixed point with precission of 8 bits +// offs is where on the line segment xy0-xy1 the point's normale hits, +// range 0..65536 (but can extend, if normale hits line outside line segment) +static int +dist_lp(int x0, int y0, int x1, int y1, int xp, int yp, int *offs) +{ + int64_t r = (y1 - y0) * (y1 - y0) + (x1 - x0) * (x1 - x0); + int64_t q1 = (xp - x0) * (y1 - y0) - (yp - y0) * (x1 - x0); + int64_t q2 = (x1 - x0) * (xp - x0) + (y1 - y0) * (yp - y0); + + *offs = (int)((q2 << 16) / r); + return (int)( q1 * q1 * ((y0 - y1) * (y0 - y1) + (x1 - x0) * (x1 - x0)) * 256 / (r * r)); +} + +static int +dist_pl(LPoint * p, LLine * l, int *offs) +{ + return dist_lp(l->x0, l->y0, l->x1, l->y1, p->x, p->y, offs); +} + +void +engine_handle_point(LPoint * p, uint32_t monotime) +{ + StringConfig *s;; + int dist_max = 1024 * 1024 * 8; + int offs, saite = -1, i, oct = 0; + int y_viewfield, pitch_factor = 12; + int dv, dt, speed, new_pitch; + + // XXX should not be inverted here + p->x = 1024 - p->x; + +#ifndef NO_DISPLAY + /* Pass to "render thread" */ + g_render_points[g_render_point_count] = *p; + ++g_render_point_count; +#endif + + /* See which line is closest */ + for (i = 0; i < g_string_count; ++i) { + int dist = dist_pl(p, &g_string_conf[i].line, &offs); + if ((dist < 256 * 10 * 10 ) && (dist < dist_max)) { + dist_max = dist; + saite = i; + } + } + + if (saite == -1) + return; + + s = g_string_conf + saite; + g_selected_string = saite; + + y_viewfield = 256 * (g_max_y - p->y) / (g_max_y - g_min_y); + if (y_viewfield < 0) + y_viewfield = 0; + if (y_viewfield >= 256) + y_viewfield = 255; + + // Determine octave, if configured + switch (s->mode) { + case midi_controller: + case midi_controller_inv: + return; // not implemented + case midi_one_octave: + break; + case midi_two_octaves: + if (y_viewfield < g_midi_two_octave_split) + oct = -1; + break; + case midi_three_octaves: + if (y_viewfield < g_midi_three_octave_split_1) + oct = -1; + if (y_viewfield > g_midi_three_octave_split_2) + oct = 1; + break; + } + // handle inverted octave configuration + if (g_midi_three_octave_split_inverse) + oct = -oct; + + switch (s->playing) { + case silent: + midi_playnote(s->channel, s->note, oct); + s->playing = in_attack; + s->octave = oct; + s->start_off = s->last_off = offs; + s->first_time_seen = monotime; + break; + case in_attack: + // test if difference is less than g_settled_dist percent of + // line segment length + if (100 * abs(s->last_off - offs) < g_settled_dist << 16) { + s->playing = playing; + s->current_pitch = 0; + + // estimated energy of hand is dv/dt from first seen to settled + dv = abs(s->start_off - offs); + dt = monotime - s->first_time_seen; + if (!dt) ++dt; + speed = 1000 * dv / dt; // in offs_prec per second + } + s->last_off = offs; + break; + case playing: + if (s->pitch_factor) + pitch_factor = s->pitch_factor; + if (s->modifier == pitch_bend_up) + new_pitch = (pitch_factor * (s->start_off - offs)) >> 16; + else if (s->modifier == pitch_bend_down) + new_pitch = (pitch_factor * (s->start_off - offs)) >> 16; + else + break; + // avoid reporting same pitch bend over and over + if (s->current_pitch == new_pitch) + break; + midi_pitchbend(s->channel, new_pitch); + s->current_pitch = new_pitch; + break; + } + s->last_time_seen = monotime; +} + +void +engine_checksilence(uint32_t monotime) +{ + int i; + + for (i = 0; i < g_string_count; ++i) { + StringConfig *s = g_string_conf + i; + int tts = s->timetosilence ? s->timetosilence : g_timetosilence; + + if (s->mode == midi_controller) + continue; + if (s->playing && (monotime - s->last_time_seen > tts)) { + midi_silencenote(s->channel, s->note, s->octave); + s->playing = 0; + } + } +} -- cgit v1.2.3