summaryrefslogtreecommitdiff
path: root/engine.c
diff options
context:
space:
mode:
Diffstat (limited to 'engine.c')
-rw-r--r--engine.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/engine.c b/engine.c
new file mode 100644
index 0000000..ae62cb5
--- /dev/null
+++ b/engine.c
@@ -0,0 +1,220 @@
1#include <stdio.h>
2#include <stdlib.h>
3
4#include "config.h"
5#include "engine.h"
6#include "display.h"
7#include "main.h"
8#include "midi.h"
9
10static int g_selected_string = -1;
11
12#ifndef NO_DISPLAY
13static LPoint g_render_points[1024];
14static int g_render_point_count;
15static const int g_harfe_width = 1024;
16static const int g_harfe_height = 768;
17static int g_factor = 1<<16;
18
19static inline int scale(int coord) {
20 return (int)(((((int64_t)coord) << 32) / g_factor ) >> 16);
21}
22
23void
24engine_redraw()
25{
26 int i;
27
28 display_redraw();
29 display_clear();
30 display_text(g_harfe_connected ? "online" : "offline", 4, 4, 0xffffffff);
31
32 for (i = 0; i < g_string_count; ++i) {
33 LLine *l = &g_string_conf[i].line;
34 uint32_t color = i == g_selected_string ? 0xff00ffff : 0x00ffffffff;
35
36 display_line_color(scale(l->x0), scale(l->y0), scale(l->x1), scale(l->y1), color);
37 display_circle(scale(l->x0), scale(l->y0), 4);
38 display_circle(scale(l->x1), scale(l->y1), 4);
39
40 if (g_string_conf[i].playing)
41 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 );
42 else
43 display_text(config_midi_note_to_string(g_string_conf[i].note), scale(l->x1) - 20, g_height - 40, color );
44 }
45 g_selected_string = -1;
46
47 for (i = 0; i < g_render_point_count; ++i)
48 display_circle_color(scale(g_render_points[i].x), scale(g_render_points[i].y), 4, 0xff0000ff);
49 g_render_point_count = 0;
50
51 display_line_color(0, scale(g_min_y), g_width, scale(g_min_y), 0xff00ffff);
52 display_line_color(0, scale(g_max_y), g_width, scale(g_max_y), 0xff00ffff);
53
54 if (g_min_y != g_max_y) {
55 int height = scale(g_max_y - g_min_y);
56
57 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);
58
59 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);
60 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);
61 }
62}
63
64#endif
65
66void
67engine_init() {
68#ifndef NO_DISPLAY
69 g_factor = (g_harfe_width << 16) / g_width;
70 if ((g_harfe_height << 16) / g_height < g_factor)
71 g_factor = (g_harfe_height << 16) / g_height;
72#endif
73}
74
75static int
76dist_pp(int x0, int y0, int x1, int y1)
77{
78 return (y0 - y1) * (y0 - y1) + (x0 - x1) * (x0 - x1);
79}
80
81// dist is a fixed point with precission of 8 bits
82// offs is where on the line segment xy0-xy1 the point's normale hits,
83// range 0..65536 (but can extend, if normale hits line outside line segment)
84static int
85dist_lp(int x0, int y0, int x1, int y1, int xp, int yp, int *offs)
86{
87 int64_t r = (y1 - y0) * (y1 - y0) + (x1 - x0) * (x1 - x0);
88 int64_t q1 = (xp - x0) * (y1 - y0) - (yp - y0) * (x1 - x0);
89 int64_t q2 = (x1 - x0) * (xp - x0) + (y1 - y0) * (yp - y0);
90
91 *offs = (int)((q2 << 16) / r);
92 return (int)( q1 * q1 * ((y0 - y1) * (y0 - y1) + (x1 - x0) * (x1 - x0)) * 256 / (r * r));
93}
94
95static int
96dist_pl(LPoint * p, LLine * l, int *offs)
97{
98 return dist_lp(l->x0, l->y0, l->x1, l->y1, p->x, p->y, offs);
99}
100
101void
102engine_handle_point(LPoint * p, uint32_t monotime)
103{
104 StringConfig *s;;
105 int dist_max = 1024 * 1024 * 8;
106 int offs, saite = -1, i, oct = 0;
107 int y_viewfield, pitch_factor = 12;
108 int dv, dt, speed, new_pitch;
109
110 // XXX should not be inverted here
111 p->x = 1024 - p->x;
112
113#ifndef NO_DISPLAY
114 /* Pass to "render thread" */
115 g_render_points[g_render_point_count] = *p;
116 ++g_render_point_count;
117#endif
118
119 /* See which line is closest */
120 for (i = 0; i < g_string_count; ++i) {
121 int dist = dist_pl(p, &g_string_conf[i].line, &offs);
122 if ((dist < 256 * 10 * 10 ) && (dist < dist_max)) {
123 dist_max = dist;
124 saite = i;
125 }
126 }
127
128 if (saite == -1)
129 return;
130
131 s = g_string_conf + saite;
132 g_selected_string = saite;
133
134 y_viewfield = 256 * (g_max_y - p->y) / (g_max_y - g_min_y);
135 if (y_viewfield < 0)
136 y_viewfield = 0;
137 if (y_viewfield >= 256)
138 y_viewfield = 255;
139
140 // Determine octave, if configured
141 switch (s->mode) {
142 case midi_controller:
143 case midi_controller_inv:
144 return; // not implemented
145 case midi_one_octave:
146 break;
147 case midi_two_octaves:
148 if (y_viewfield < g_midi_two_octave_split)
149 oct = -1;
150 break;
151 case midi_three_octaves:
152 if (y_viewfield < g_midi_three_octave_split_1)
153 oct = -1;
154 if (y_viewfield > g_midi_three_octave_split_2)
155 oct = 1;
156 break;
157 }
158 // handle inverted octave configuration
159 if (g_midi_three_octave_split_inverse)
160 oct = -oct;
161
162 switch (s->playing) {
163 case silent:
164 midi_playnote(s->channel, s->note, oct);
165 s->playing = in_attack;
166 s->octave = oct;
167 s->start_off = s->last_off = offs;
168 s->first_time_seen = monotime;
169 break;
170 case in_attack:
171 // test if difference is less than g_settled_dist percent of
172 // line segment length
173 if (100 * abs(s->last_off - offs) < g_settled_dist << 16) {
174 s->playing = playing;
175 s->current_pitch = 0;
176
177 // estimated energy of hand is dv/dt from first seen to settled
178 dv = abs(s->start_off - offs);
179 dt = monotime - s->first_time_seen;
180 if (!dt) ++dt;
181 speed = 1000 * dv / dt; // in offs_prec per second
182 }
183 s->last_off = offs;
184 break;
185 case playing:
186 if (s->pitch_factor)
187 pitch_factor = s->pitch_factor;
188 if (s->modifier == pitch_bend_up)
189 new_pitch = (pitch_factor * (s->start_off - offs)) >> 16;
190 else if (s->modifier == pitch_bend_down)
191 new_pitch = (pitch_factor * (s->start_off - offs)) >> 16;
192 else
193 break;
194 // avoid reporting same pitch bend over and over
195 if (s->current_pitch == new_pitch)
196 break;
197 midi_pitchbend(s->channel, new_pitch);
198 s->current_pitch = new_pitch;
199 break;
200 }
201 s->last_time_seen = monotime;
202}
203
204void
205engine_checksilence(uint32_t monotime)
206{
207 int i;
208
209 for (i = 0; i < g_string_count; ++i) {
210 StringConfig *s = g_string_conf + i;
211 int tts = s->timetosilence ? s->timetosilence : g_timetosilence;
212
213 if (s->mode == midi_controller)
214 continue;
215 if (s->playing && (monotime - s->last_time_seen > tts)) {
216 midi_silencenote(s->channel, s->note, s->octave);
217 s->playing = 0;
218 }
219 }
220}