#include #include #include "config.h" #include "geometry.h" #include "engine.h" #include "main.h" #include "midi.h" static int g_selected_string = -1; #ifndef NO_DISPLAY #include "display.h" static LPoint g_render_points[1024]; static int g_render_point_count; static ConfigSelect g_selected_config; static void highlight_line(int value, int y, int max_x, uint32_t color); #define scale(X) display_scale_harfe_to_screen(X) void engine_redraw() { const char *config_hints[] = { "No", "Harfe", "File", "Edit" }; char text[32]; const int tos1 = g_midi_three_octave_split_1, tos2 = g_midi_three_octave_split_2; const int height = g_max_y - g_min_y; int i, x2, MAX_X, MAX_Y, FONT_HEIGHT; display_redraw(); display_clear(); display_getdimensions(&MAX_X, &MAX_Y, &FONT_HEIGHT); snprintf( text, sizeof(text), g_harfe_connected ? "online (%s)" : "offline (%s)", config_hints[(int)g_config_source]); display_text(text, 8, MAX_Y - 4, g_harfe_connected ? 0x00ff3fff : 0xff003fff ); if (height) { int b = g_midi_three_octave_split_inverse; display_text( b ? "+1" : "-1", 4, scale(g_min_y + tos1 * height / 200) + FONT_HEIGHT / 2, 0x007f7f7fff); display_text( " 0", 4, scale(g_min_y + (tos1 + tos2) * height / 200) + FONT_HEIGHT / 2, 0x007f7f7fff); display_text( b ? "-1" : "+1", 4, scale(g_min_y + (tos2 / 2 + 50 ) * height / 100) + FONT_HEIGHT / 2, 0x007f7f7fff); display_line_color(0, scale(g_min_y), MAX_X, scale(g_min_y), 0xff00ffff); display_line_color(0, scale(g_max_y), MAX_X, scale(g_max_y), 0xff00ffff); display_line_color(0, scale(g_min_y + g_midi_two_octave_split * height / 100), MAX_X, scale(g_min_y + g_midi_two_octave_split * height / 100), 0xffff00ff); display_line_color(0, scale(g_min_y + tos1 * height / 100), MAX_X, scale(g_min_y + tos1 * height / 100), 0x00ff00ff); display_line_color(0, scale(g_min_y + tos2 * height / 100), MAX_X, scale(g_min_y + tos2 * height / 100), 0x00ff00ff); switch (g_selected_config) { case sel_min_y: highlight_line(g_min_y, g_min_y, MAX_X, 0xff00ffff); break; case sel_max_y: highlight_line(g_max_y, g_max_y, MAX_X, 0xff00ffff); break; case sel_2_oct: highlight_line(g_midi_two_octave_split, g_min_y + g_midi_two_octave_split * height / 100, MAX_X, 0xffff00ff); break; case sel_3_oct_top: highlight_line(tos2, g_min_y + tos2 * height / 100, MAX_X, 0x00ff00ff); break; case sel_3_oct_bottom: highlight_line(tos1, g_min_y + tos1 * height / 100, MAX_X, 0x00ff00ff); break; case sel_none: break; } for (i = 0; i < g_string_count; ++i) { LLine *l = &g_string_conf[i].line; LLine _l = g_string_conf[i].line; // Copy for extension uint32_t color = ( ( i == g_selected_string ) ? 0xff00ffff : 0x00ffffffff ); uint32_t text_color = ( ( i == g_selected_string ) ? 0xff00ffff : 0x007f7f7fff ); int extended = 0, center_y = g_min_y+height/2; if (_l.p0.y > g_min_y) { _l.p0.x = get_x_for_y(&_l.p0, &_l.p1, g_min_y); _l.p0.y = g_min_y; extended = 1; } if (_l.p1.y < g_max_y) { _l.p1.x = get_x_for_y(&l->p0 /* Using unmodified original! */, &_l.p1, g_max_y); _l.p1.y = g_max_y; extended = 1; } if (extended) { display_line_color(scale(_l.p0.x), scale(_l.p0.y), scale(_l.p1.x), scale(_l.p1.y), 0x007f3f00); display_circle_color(scale(_l.p0.x), scale(_l.p0.y), 4, 0x007f3f00); display_circle_color(scale(_l.p1.x), scale(_l.p1.y), 4, 0x007f3f00); } x2 = get_x_for_y(&l->p0,&l->p1,center_y); 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(x2-20), scale(center_y) + FONT_HEIGHT, text_color ); else display_text(config_midi_note_to_string(g_string_conf[i].note), scale(x2-20), scale(center_y) + FONT_HEIGHT, text_color ); display_line_color(scale(l->p0.x), scale(l->p0.y), scale(l->p1.x), scale(l->p1.y), color); display_circle(scale(l->p0.x), scale(l->p0.y), 4); display_circle(scale(l->p1.x), scale(l->p1.y), 4); } } 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; } static void highlight_line(int value, int y, int max_x, uint32_t color) { char text[32]; display_line_color(0, scale(y-10), 10, scale(y), color); display_line_color(0, scale(y+10), 10, scale(y), color); display_line_color(max_x, scale(y-10), max_x-10, scale(y), color); display_line_color(max_x, scale(y+10), max_x-10, scale(y), color); display_rect_color(max_x/2-40, scale(y+20), 80, 40, 0xffffffff); snprintf(text, sizeof(text), "%d", value); display_text(text, max_x/2-20, scale(y+20), 0); } void engine_select_config(ConfigSelect sel) { // test if we have moved g_min_y or g_max_y and resize lines accordingly if (sel == sel_none) { int i; for (i=0; ip0.y > g_min_y) { l->p0.x = get_x_for_y(&l->p0, &l->p1, g_min_y); l->p0.y = g_min_y; } if (l->p1.y < g_max_y) { l->p1.x = get_x_for_y(&_l.p0 /* Using unmodified original! */, &l->p1, g_max_y); l->p1.y = g_max_y; } } } g_selected_config = sel; } ConfigSelect engine_change_selected(int off) { switch(g_selected_config) { case sel_min_y: g_min_y += off; break; case sel_max_y: g_max_y += off; break; case sel_3_oct_top: g_midi_three_octave_split_2 += off; if (g_midi_three_octave_split_2<0) g_midi_three_octave_split_2 = 0; if (g_midi_three_octave_split_2>100) g_midi_three_octave_split_2 = 100; break; case sel_3_oct_bottom: g_midi_three_octave_split_1 += off; if (g_midi_three_octave_split_1<0) g_midi_three_octave_split_1 = 0; if (g_midi_three_octave_split_1>100) g_midi_three_octave_split_1 = 100; break; case sel_2_oct: g_midi_two_octave_split += off; if (g_midi_two_octave_split<0) g_midi_two_octave_split = 0; if (g_midi_two_octave_split>100) g_midi_two_octave_split = 100; break; default: break; } return g_selected_config; } #endif void engine_init() { } 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; #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); /* Avoid miss-fires, check if offset is in range -5% - +105% */ if ((dist < 512 * 10 * 10 ) && (dist < dist_max) && (offs<68812) && (offs>-3276)) { dist_max = dist; saite = i; } } if (saite == -1) return; s = g_string_conf + saite; g_selected_string = saite; y_viewfield = (100 * (p->y - g_min_y)) / (g_max_y - g_min_y); if (y_viewfield < 0) y_viewfield = 0; if (y_viewfield >= 100) y_viewfield = 100; // 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 * (offs - s->start_off)) >> 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 = silent; } } }