diff options
Diffstat (limited to 'engine.c')
| -rw-r--r-- | engine.c | 172 |
1 files changed, 104 insertions, 68 deletions
| @@ -2,6 +2,7 @@ | |||
| 2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
| 3 | 3 | ||
| 4 | #include "config.h" | 4 | #include "config.h" |
| 5 | #include "geometry.h" | ||
| 5 | #include "engine.h" | 6 | #include "engine.h" |
| 6 | #include "main.h" | 7 | #include "main.h" |
| 7 | #include "midi.h" | 8 | #include "midi.h" |
| @@ -13,91 +14,131 @@ static int g_selected_string = -1; | |||
| 13 | 14 | ||
| 14 | static LPoint g_render_points[1024]; | 15 | static LPoint g_render_points[1024]; |
| 15 | static int g_render_point_count; | 16 | static int g_render_point_count; |
| 16 | static const int g_harfe_width = 1024; | 17 | static ConfigSelect g_selected_config; |
| 17 | static const int g_harfe_height = 768; | 18 | static void highlight_line(int value, int y, int max_x, uint32_t color); |
| 18 | static int g_factor = 1<<16; | ||
| 19 | 19 | ||
| 20 | static inline int scale(int coord) { | 20 | #define scale(X) display_scale_harfe_to_screen(X) |
| 21 | return (int)(((((int64_t)coord) << 32) / g_factor ) >> 16); | ||
| 22 | } | ||
| 23 | 21 | ||
| 24 | void | 22 | void |
| 25 | engine_redraw() | 23 | engine_redraw() |
| 26 | { | 24 | { |
| 27 | int i; | 25 | char text[32]; |
| 26 | char *config_hints[] = { "No", "Harfe", "File", "Edit" }; | ||
| 27 | int i, MAX_X, MAX_Y, FONT_HEIGHT; | ||
| 28 | int height = g_max_y - g_min_y; | ||
| 28 | 29 | ||
| 29 | display_redraw(); | 30 | display_redraw(); |
| 30 | display_clear(); | 31 | display_clear(); |
| 31 | display_text(g_harfe_connected ? "online" : "offline", 4, 4, 0xffffffff); | 32 | display_getdimensions(&MAX_X, &MAX_Y, &FONT_HEIGHT); |
| 32 | 33 | ||
| 33 | for (i = 0; i < g_string_count; ++i) { | 34 | snprintf( text, sizeof(text), g_harfe_connected ? "online (%s)" : "offline (%s)", config_hints[(int)g_config_source]); |
| 34 | LLine *l = &g_string_conf[i].line; | 35 | display_text(text, 8, MAX_Y - 4, g_harfe_connected ? 0x00ff3fff : 0xff003fff ); |
| 35 | uint32_t color = i == g_selected_string ? 0xff00ffff : 0x00ffffffff; | ||
| 36 | 36 | ||
| 37 | display_line_color(scale(l->x0), scale(l->y0), scale(l->x1), scale(l->y1), color); | 37 | if (height) { |
| 38 | display_circle(scale(l->x0), scale(l->y0), 4); | 38 | int b = g_midi_three_octave_split_inverse; |
| 39 | display_circle(scale(l->x1), scale(l->y1), 4); | 39 | int tos1 = g_midi_three_octave_split_1, tos2 = g_midi_three_octave_split_2; |
| 40 | display_text( b ? "+1" : "-1", 4, scale(g_min_y + tos1 * height / 200) + FONT_HEIGHT / 2, 0x007f7f7fff); | ||
| 41 | display_text( " 0", 4, scale(g_min_y + (tos1 + tos2) * height / 200) + FONT_HEIGHT / 2, 0x007f7f7fff); | ||
| 42 | display_text( b ? "-1" : "+1", 4, scale(g_min_y + (tos2 / 2 + 50 ) * height / 100) + FONT_HEIGHT / 2, 0x007f7f7fff); | ||
| 40 | 43 | ||
| 41 | if (g_string_conf[i].playing) | 44 | display_line_color(0, scale(g_min_y), MAX_X, scale(g_min_y), 0xff00ffff); |
| 42 | 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 ); | 45 | display_line_color(0, scale(g_max_y), MAX_X, scale(g_max_y), 0xff00ffff); |
| 43 | else | 46 | |
| 44 | display_text(config_midi_note_to_string(g_string_conf[i].note), scale(l->x1) - 20, g_height - 40, color ); | 47 | 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); |
| 48 | |||
| 49 | display_line_color(0, scale(g_min_y + tos1 * height / 100), MAX_X, scale(g_min_y + tos1 * height / 100), 0x00ff00ff); | ||
| 50 | display_line_color(0, scale(g_min_y + tos2 * height / 100), MAX_X, scale(g_min_y + tos2 * height / 100), 0x00ff00ff); | ||
| 51 | |||
| 52 | |||
| 53 | switch (g_selected_config) { | ||
| 54 | case sel_min_y: highlight_line(g_min_y, g_min_y, MAX_X, 0xff00ffff); break; | ||
| 55 | case sel_max_y: highlight_line(g_max_y, g_max_y, MAX_X, 0xff00ffff); break; | ||
| 56 | 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; | ||
| 57 | case sel_3_oct_top: highlight_line(tos2, g_min_y + tos2 * height / 100, MAX_X, 0x00ff00ff); break; | ||
| 58 | case sel_3_oct_bottom: highlight_line(tos1, g_min_y + tos1 * height / 100, MAX_X, 0x00ff00ff); break; | ||
| 59 | case sel_none: break; | ||
| 60 | } | ||
| 61 | |||
| 62 | for (i = 0; i < g_string_count; ++i) { | ||
| 63 | LLine *l = &g_string_conf[i].line; | ||
| 64 | uint32_t color = ( ( i == g_selected_string ) ? 0xff00ffff : 0x00ffffffff ); | ||
| 65 | uint32_t text_color = ( ( i == g_selected_string ) ? 0xff00ffff : 0x007f7f7fff ); | ||
| 66 | |||
| 67 | int center_y = g_min_y+height/2; | ||
| 68 | int x2 = l->p1.x; | ||
| 69 | |||
| 70 | if (l->p1.x!=l->p0.x) { | ||
| 71 | double m = (double)(l->p1.y-l->p0.y) / (double)(l->p1.x-l->p0.x); | ||
| 72 | double _x2 = ((double)center_y) - (double)l->p0.y + m * (double)l->p0.x; | ||
| 73 | x2 = (int)(_x2/m); | ||
| 74 | } | ||
| 75 | |||
| 76 | if (g_string_conf[i].playing) | ||
| 77 | 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 ); | ||
| 78 | else | ||
| 79 | display_text(config_midi_note_to_string(g_string_conf[i].note), scale(x2-20), scale(center_y) + FONT_HEIGHT, text_color ); | ||
| 80 | |||
| 81 | display_line_color(scale(l->p0.x), scale(l->p0.y), scale(l->p1.x), scale(l->p1.y), color); | ||
| 82 | display_circle(scale(l->p0.x), scale(l->p0.y), 4); | ||
| 83 | display_circle(scale(l->p1.x), scale(l->p1.y), 4); | ||
| 84 | |||
| 85 | } | ||
| 45 | } | 86 | } |
| 46 | g_selected_string = -1; | 87 | g_selected_string = -1; |
| 47 | 88 | ||
| 48 | for (i = 0; i < g_render_point_count; ++i) | 89 | for (i = 0; i < g_render_point_count; ++i) |
| 49 | display_circle_color(scale(g_render_points[i].x), scale(g_render_points[i].y), 4, 0xff0000ff); | 90 | display_circle_color(scale(g_render_points[i].x), scale(g_render_points[i].y), 4, 0xff0000ff); |
| 50 | g_render_point_count = 0; | 91 | g_render_point_count = 0; |
| 92 | } | ||
| 51 | 93 | ||
| 52 | display_line_color(0, scale(g_min_y), g_width, scale(g_min_y), 0xff00ffff); | 94 | static void |
| 53 | display_line_color(0, scale(g_max_y), g_width, scale(g_max_y), 0xff00ffff); | 95 | highlight_line(int value, int y, int max_x, uint32_t color) { |
| 54 | 96 | char text[32]; | |
| 55 | if (g_min_y != g_max_y) { | 97 | display_line_color(0, scale(y-10), 10, scale(y), color); |
| 56 | int height = scale(g_max_y - g_min_y); | 98 | display_line_color(0, scale(y+10), 10, scale(y), color); |
| 57 | 99 | display_line_color(max_x, scale(y-10), max_x-10, scale(y), color); | |
| 58 | 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); | 100 | display_line_color(max_x, scale(y+10), max_x-10, scale(y), color); |
| 59 | 101 | ||
| 60 | 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); | 102 | display_rect_color(max_x/2-40, scale(y+20), 80, 40, 0xffffffff); |
| 61 | 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); | 103 | display_text(text, max_x/2-20, scale(y+20), 0); |
| 62 | } | ||
| 63 | } | 104 | } |
| 64 | 105 | ||
| 65 | #endif | ||
| 66 | |||
| 67 | void | 106 | void |
| 68 | engine_init() { | 107 | engine_select_config(ConfigSelect sel) { |
| 69 | #ifndef NO_DISPLAY | 108 | g_selected_config = sel; |
| 70 | g_factor = (g_harfe_width << 16) / g_width; | ||
| 71 | if ((g_harfe_height << 16) / g_height < g_factor) | ||
| 72 | g_factor = (g_harfe_height << 16) / g_height; | ||
| 73 | #endif | ||
| 74 | } | 109 | } |
| 75 | 110 | ||
| 76 | static int | 111 | ConfigSelect |
| 77 | dist_pp(int x0, int y0, int x1, int y1) | 112 | engine_change_selected(int off) |
| 78 | { | 113 | { |
| 79 | return (y0 - y1) * (y0 - y1) + (x0 - x1) * (x0 - x1); | 114 | switch(g_selected_config) { |
| 115 | case sel_3_oct_top: | ||
| 116 | g_midi_three_octave_split_2 += off; | ||
| 117 | if (g_midi_three_octave_split_2<0) g_midi_three_octave_split_2 = 0; | ||
| 118 | if (g_midi_three_octave_split_2>100) g_midi_three_octave_split_2 = 100; | ||
| 119 | break; | ||
| 120 | case sel_3_oct_bottom: | ||
| 121 | g_midi_three_octave_split_1 += off; | ||
| 122 | if (g_midi_three_octave_split_1<0) g_midi_three_octave_split_1 = 0; | ||
| 123 | if (g_midi_three_octave_split_1>100) g_midi_three_octave_split_1 = 100; | ||
| 124 | break; | ||
| 125 | case sel_2_oct: | ||
| 126 | g_midi_two_octave_split += off; | ||
| 127 | if (g_midi_two_octave_split<0) g_midi_two_octave_split = 0; | ||
| 128 | if (g_midi_two_octave_split>100) g_midi_two_octave_split = 100; | ||
| 129 | break; | ||
| 130 | default: | ||
| 131 | break; | ||
| 132 | } | ||
| 133 | return g_selected_config; | ||
| 80 | } | 134 | } |
| 81 | 135 | ||
| 82 | // dist is a fixed point with precission of 8 bits | 136 | #endif |
| 83 | // offs is where on the line segment xy0-xy1 the point's normale hits, | ||
| 84 | // range 0..65536 (but can extend, if normale hits line outside line segment) | ||
| 85 | static int | ||
| 86 | dist_lp(int x0, int y0, int x1, int y1, int xp, int yp, int *offs) | ||
| 87 | { | ||
| 88 | int64_t r = (y1 - y0) * (y1 - y0) + (x1 - x0) * (x1 - x0); | ||
| 89 | int64_t q1 = (xp - x0) * (y1 - y0) - (yp - y0) * (x1 - x0); | ||
| 90 | int64_t q2 = (x1 - x0) * (xp - x0) + (y1 - y0) * (yp - y0); | ||
| 91 | 137 | ||
| 92 | *offs = (int)((q2 << 16) / r); | 138 | void |
| 93 | return (int)( q1 * q1 * ((y0 - y1) * (y0 - y1) + (x1 - x0) * (x1 - x0)) * 256 / (r * r)); | 139 | engine_init() { |
| 94 | } | 140 | } |
| 95 | 141 | ||
| 96 | static int | ||
| 97 | dist_pl(LPoint * p, LLine * l, int *offs) | ||
| 98 | { | ||
| 99 | return dist_lp(l->x0, l->y0, l->x1, l->y1, p->x, p->y, offs); | ||
| 100 | } | ||
| 101 | 142 | ||
| 102 | void | 143 | void |
| 103 | engine_handle_point(LPoint * p, uint32_t monotime) | 144 | engine_handle_point(LPoint * p, uint32_t monotime) |
| @@ -108,9 +149,6 @@ engine_handle_point(LPoint * p, uint32_t monotime) | |||
| 108 | int y_viewfield, pitch_factor = 12; | 149 | int y_viewfield, pitch_factor = 12; |
| 109 | int dv, dt, speed, new_pitch; | 150 | int dv, dt, speed, new_pitch; |
| 110 | 151 | ||
| 111 | // XXX should not be inverted here | ||
| 112 | p->x = 1024 - p->x; | ||
| 113 | |||
| 114 | #ifndef NO_DISPLAY | 152 | #ifndef NO_DISPLAY |
| 115 | /* Pass to "render thread" */ | 153 | /* Pass to "render thread" */ |
| 116 | g_render_points[g_render_point_count] = *p; | 154 | g_render_points[g_render_point_count] = *p; |
| @@ -120,27 +158,25 @@ engine_handle_point(LPoint * p, uint32_t monotime) | |||
| 120 | /* See which line is closest */ | 158 | /* See which line is closest */ |
| 121 | for (i = 0; i < g_string_count; ++i) { | 159 | for (i = 0; i < g_string_count; ++i) { |
| 122 | int dist = dist_pl(p, &g_string_conf[i].line, &offs); | 160 | int dist = dist_pl(p, &g_string_conf[i].line, &offs); |
| 123 | if ((dist < 256 * 10 * 10 ) && (dist < dist_max)) { | 161 | |
| 162 | /* Avoid miss-fires, check if offset is in range -5% - +105% */ | ||
| 163 | if ((dist < 512 * 10 * 10 ) && (dist < dist_max) && (offs<68812) && (offs>-3276)) { | ||
| 124 | dist_max = dist; | 164 | dist_max = dist; |
| 125 | saite = i; | 165 | saite = i; |
| 126 | } | 166 | } |
| 127 | } | 167 | } |
| 128 | 168 | ||
| 129 | /* Avoid miss-fires, check if offset is in range -5% - +105% */ | ||
| 130 | if (offs>68812 || offs<-3276) | ||
| 131 | return; | ||
| 132 | |||
| 133 | if (saite == -1) | 169 | if (saite == -1) |
| 134 | return; | 170 | return; |
| 135 | 171 | ||
| 136 | s = g_string_conf + saite; | 172 | s = g_string_conf + saite; |
| 137 | g_selected_string = saite; | 173 | g_selected_string = saite; |
| 138 | 174 | ||
| 139 | y_viewfield = 256 * (g_max_y - p->y) / (g_max_y - g_min_y); | 175 | y_viewfield = (100 * (p->y - g_min_y)) / (g_max_y - g_min_y); |
| 140 | if (y_viewfield < 0) | 176 | if (y_viewfield < 0) |
| 141 | y_viewfield = 0; | 177 | y_viewfield = 0; |
| 142 | if (y_viewfield >= 256) | 178 | if (y_viewfield >= 100) |
| 143 | y_viewfield = 255; | 179 | y_viewfield = 100; |
| 144 | 180 | ||
| 145 | // Determine octave, if configured | 181 | // Determine octave, if configured |
| 146 | switch (s->mode) { | 182 | switch (s->mode) { |
| @@ -183,7 +219,7 @@ engine_handle_point(LPoint * p, uint32_t monotime) | |||
| 183 | dv = abs(s->start_off - offs); | 219 | dv = abs(s->start_off - offs); |
| 184 | dt = monotime - s->first_time_seen; | 220 | dt = monotime - s->first_time_seen; |
| 185 | if (!dt) ++dt; | 221 | if (!dt) ++dt; |
| 186 | speed = 1000 * dv / dt; // in offs_prec per second | 222 | speed = 1000 * dv / dt; // in offs_prec per second |
| 187 | } | 223 | } |
| 188 | s->last_off = offs; | 224 | s->last_off = offs; |
| 189 | break; | 225 | break; |
| @@ -193,7 +229,7 @@ engine_handle_point(LPoint * p, uint32_t monotime) | |||
| 193 | if (s->modifier == pitch_bend_up) | 229 | if (s->modifier == pitch_bend_up) |
| 194 | new_pitch = (pitch_factor * (s->start_off - offs)) >> 16; | 230 | new_pitch = (pitch_factor * (s->start_off - offs)) >> 16; |
| 195 | else if (s->modifier == pitch_bend_down) | 231 | else if (s->modifier == pitch_bend_down) |
| 196 | new_pitch = (pitch_factor * (s->start_off - offs)) >> 16; | 232 | new_pitch = (pitch_factor * (offs - s->start_off)) >> 16; |
| 197 | else | 233 | else |
| 198 | break; | 234 | break; |
| 199 | // avoid reporting same pitch bend over and over | 235 | // avoid reporting same pitch bend over and over |
