diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | arduino/Laserharfe/Laserharfe.ino | 105 | ||||
-rw-r--r-- | config.c | 69 | ||||
-rw-r--r-- | config.h | 27 | ||||
-rw-r--r-- | display.c | 88 | ||||
-rw-r--r-- | display.h | 9 | ||||
-rw-r--r-- | engine.c | 172 | ||||
-rw-r--r-- | engine.h | 6 | ||||
-rw-r--r-- | geometry.c | 31 | ||||
-rw-r--r-- | geometry.h | 18 | ||||
-rw-r--r-- | main-sdl.c | 245 | ||||
-rw-r--r-- | main.h | 8 |
12 files changed, 604 insertions, 178 deletions
@@ -3,8 +3,8 @@ all: main | |||
3 | GenBkBasB.c: GenBkBasB.ttf | 3 | GenBkBasB.c: GenBkBasB.ttf |
4 | xxd -i $< $@ | 4 | xxd -i $< $@ |
5 | 5 | ||
6 | main: main-sdl.c display.c config.c display.h config.h engine.c engine.h midi-sdl.c midi.h GenBkBasB.c GenBkBasB.h | 6 | main: main-sdl.c calib.c calib.h config.c config.h display.c display.h engine.c engine.h geometry.c geometry.h midi-noop.c midi.h GenBkBasB.c GenBkBasB.h |
7 | cc -O2 -o Laserharfe main-sdl.c config.c display.c engine.c midi-sdl.c GenBkBasB.c -I /usr/local/include -lm -L/usr/local/lib -lSDL2 -framework Cocoa -lSDL2main -lSDL2_ttf -lSDL2_gfx | 7 | cc -g -o Laserharfe main-sdl.c calib.c config.c display.c engine.c geometry.c midi-noop.c GenBkBasB.c -I /usr/local/include -lm -L/usr/local/lib -lSDL2 -framework Cocoa -lSDL2main -lSDL2_ttf -lSDL2_gfx |
8 | 8 | ||
9 | .PHONY: clean | 9 | .PHONY: clean |
10 | clean: | 10 | clean: |
diff --git a/arduino/Laserharfe/Laserharfe.ino b/arduino/Laserharfe/Laserharfe.ino index a0e8d07..107dffb 100644 --- a/arduino/Laserharfe/Laserharfe.ino +++ b/arduino/Laserharfe/Laserharfe.ino | |||
@@ -1,11 +1,3 @@ | |||
1 | /* | ||
2 | * MIDIUSB_test.ino | ||
3 | * | ||
4 | * Created: 4/6/2015 10:47:08 AM | ||
5 | * Author: gurbrinder grewal | ||
6 | * Modified by Arduino LLC (2015) | ||
7 | */ | ||
8 | |||
9 | #include "MIDIUSB.h" | 1 | #include "MIDIUSB.h" |
10 | #include <SD.h> | 2 | #include <SD.h> |
11 | #include <Wire.h> | 3 | #include <Wire.h> |
@@ -15,12 +7,16 @@ | |||
15 | #include "engine.h" | 7 | #include "engine.h" |
16 | 8 | ||
17 | int led = 13; | 9 | int led = 13; |
10 | int g_reading_config = 0; | ||
11 | int g_writing_config = 0; | ||
12 | ConfigSource g_config_source = source_none; | ||
13 | //Sd2Card card; | ||
18 | 14 | ||
19 | enum { | 15 | enum { |
20 | MODE_STANDALONE = 0, | 16 | MODE_STANDALONE = 0, |
21 | MODE_REPORTPOINTS = 1, | 17 | MODE_REPORTPOINTS = 1, |
22 | MODE_REPORTPOINTS_PLAY = 2, | 18 | MODE_REPORTPOINTS_PLAY = 2 |
23 | } g_mode = MODE_REPORTPOINTS_PLAY; | 19 | } g_mode = MODE_STANDALONE; |
24 | 20 | ||
25 | uint32_t now() { | 21 | uint32_t now() { |
26 | return millis(); | 22 | return millis(); |
@@ -85,6 +81,7 @@ static void set_cam_register(uint8_t r, uint8_t v) { | |||
85 | } | 81 | } |
86 | 82 | ||
87 | static void setup_cam() { | 83 | static void setup_cam() { |
84 | digitalWrite(19, HIGH); // turn the LED on (HIGH is the voltage level) | ||
88 | set_cam_register(0x30, 0x01); | 85 | set_cam_register(0x30, 0x01); |
89 | set_cam_register(0x06, 0x90); | 86 | set_cam_register(0x06, 0x90); |
90 | set_cam_register(0x08, 0xc0); | 87 | set_cam_register(0x08, 0xc0); |
@@ -99,7 +96,6 @@ void read_config() { | |||
99 | Serial.println("initialization failed!"); | 96 | Serial.println("initialization failed!"); |
100 | return; | 97 | return; |
101 | } | 98 | } |
102 | |||
103 | File configfile = SD.open("laserhar.cfg", FILE_READ); | 99 | File configfile = SD.open("laserhar.cfg", FILE_READ); |
104 | if (!configfile) { | 100 | if (!configfile) { |
105 | Serial.println("opening config failed"); | 101 | Serial.println("opening config failed"); |
@@ -107,14 +103,15 @@ void read_config() { | |||
107 | } | 103 | } |
108 | 104 | ||
109 | char command[256]; | 105 | char command[256]; |
110 | int command_len; | 106 | int command_len = 0; |
111 | int skip_command; | 107 | int skip_command = 0; |
112 | 108 | ||
113 | while (configfile.available()) { | 109 | while (configfile.available()) { |
114 | char c = command[command_len++] = configfile.read(); | 110 | char c = command[command_len++] = configfile.read(); |
115 | if (c=='\n') { | 111 | if (c=='\n') { |
116 | if (!skip_command) { | 112 | if (!skip_command) { |
117 | command[command_len] = 0; | 113 | command[command_len] = 0; |
114 | // Serial.write(command); | ||
118 | config_handle_line(command); | 115 | config_handle_line(command); |
119 | } | 116 | } |
120 | skip_command = 0; | 117 | skip_command = 0; |
@@ -126,9 +123,38 @@ void read_config() { | |||
126 | command_len = 0; | 123 | command_len = 0; |
127 | } | 124 | } |
128 | } | 125 | } |
126 | |||
127 | configfile.close(); | ||
128 | } | ||
129 | |||
130 | void write_config() { | ||
131 | SD.remove("laserhar.cfg"); | ||
132 | File configfile = SD.open("laserhar.cfg", FILE_WRITE); | ||
133 | if (!configfile) { | ||
134 | Serial.println("opening config failed"); | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | char text[256]; | ||
139 | size_t len = config_dumpglobals(text, sizeof(text)); | ||
140 | configfile.write(text, len); | ||
141 | for (int i=0; i< g_string_count; ++i) { | ||
142 | len = config_dumpstring(i, text, sizeof(text)); | ||
143 | configfile.write(text, len); | ||
144 | } | ||
145 | Serial.println("-- DONE"); | ||
129 | configfile.close(); | 146 | configfile.close(); |
130 | } | 147 | } |
131 | 148 | ||
149 | void flashy_death() { | ||
150 | while(1) { | ||
151 | digitalWrite(led, LOW); // turn the LED on (HIGH is the voltage level) | ||
152 | delay(500); | ||
153 | digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) | ||
154 | delay(500); | ||
155 | } | ||
156 | } | ||
157 | |||
132 | void setup() { | 158 | void setup() { |
133 | pinMode(led, OUTPUT); | 159 | pinMode(led, OUTPUT); |
134 | 160 | ||
@@ -139,8 +165,8 @@ void setup() { | |||
139 | // Let PWM settle for a bit | 165 | // Let PWM settle for a bit |
140 | delay(100); | 166 | delay(100); |
141 | setup_cam(); | 167 | setup_cam(); |
142 | |||
143 | Serial.begin(115200); | 168 | Serial.begin(115200); |
169 | delay(5000); | ||
144 | read_config(); | 170 | read_config(); |
145 | digitalWrite(led, LOW); // turn the LED on (HIGH is the voltage level) | 171 | digitalWrite(led, LOW); // turn the LED on (HIGH is the voltage level) |
146 | } | 172 | } |
@@ -220,10 +246,10 @@ void handle_midi(char *command) { | |||
220 | return; | 246 | return; |
221 | if (command[6] != '\n') | 247 | if (command[6] != '\n') |
222 | return; | 248 | return; |
223 | |||
224 | midiEventPacket_t p = { m[0], (m[0]<<4) | m[1], (m[2]<<4) | m[3], (m[4]<<4) | m[5] }; | 249 | midiEventPacket_t p = { m[0], (m[0]<<4) | m[1], (m[2]<<4) | m[3], (m[4]<<4) | m[5] }; |
225 | MidiUSB.sendMIDI(p); | 250 | MidiUSB.sendMIDI(p); |
226 | // MidiUSB.flush(); | 251 | MidiUSB.flush(); |
252 | Serial.println("- MIDI SENT"); | ||
227 | } | 253 | } |
228 | 254 | ||
229 | void midi_playnote(int channel, int note, int octave_offset ) { | 255 | void midi_playnote(int channel, int note, int octave_offset ) { |
@@ -246,11 +272,20 @@ void midi_pitchbend( int channel, int pitch ) { | |||
246 | MidiUSB.sendMIDI(p); | 272 | MidiUSB.sendMIDI(p); |
247 | } | 273 | } |
248 | 274 | ||
249 | void handle_configure(char *command) { | 275 | void handle_command(char *command) { |
276 | char text[512]; | ||
277 | size_t len; | ||
278 | // Serial.write( text, sprintf(text, "- %s\n", command)); | ||
250 | 279 | ||
251 | } | 280 | if (g_reading_config ) { |
281 | if ( !strcmp(command, "-- DONE")) { | ||
282 | g_reading_config = 0; | ||
283 | return; | ||
284 | } | ||
285 | config_handle_line(command); | ||
286 | return; | ||
287 | } | ||
252 | 288 | ||
253 | void handle_command(char *command) { | ||
254 | switch (*command) { | 289 | switch (*command) { |
255 | case 'M': /* Getting MIDI instruction */ | 290 | case 'M': /* Getting MIDI instruction */ |
256 | handle_midi(command+1); | 291 | handle_midi(command+1); |
@@ -266,12 +301,32 @@ void handle_command(char *command) { | |||
266 | case '3': | 301 | case '3': |
267 | g_mode = MODE_REPORTPOINTS; | 302 | g_mode = MODE_REPORTPOINTS; |
268 | break; | 303 | break; |
269 | default: | ||
270 | break; | ||
271 | } | 304 | } |
272 | break; | 305 | break; |
273 | case 'C': /* Getting configure command */ | 306 | case 'C': /* Import a single config line from host */ |
274 | handle_configure(command+1); | 307 | config_handle_line(command+1); |
308 | break; | ||
309 | case 'E': /* Export config from host, import here */ | ||
310 | config_reset(); | ||
311 | g_reading_config = true; | ||
312 | break; | ||
313 | case 'I': /* Import config at host */ | ||
314 | delay(1000); | ||
315 | len = config_dumpglobals(text, sizeof(text)); | ||
316 | Serial.write(text, len); | ||
317 | for (int i=0; i< g_string_count; ++i) { | ||
318 | len = config_dumpstring(i, text, sizeof(text)); | ||
319 | delay(100); | ||
320 | Serial.write(text, len); | ||
321 | } | ||
322 | delay(100); | ||
323 | Serial.println("-- DONE"); | ||
324 | break; | ||
325 | case 'R': /* Re-read config */ | ||
326 | read_config(); | ||
327 | break; | ||
328 | case 'W': /* Write local config */ | ||
329 | write_config(); | ||
275 | break; | 330 | break; |
276 | default: | 331 | default: |
277 | break; | 332 | break; |
@@ -279,7 +334,7 @@ void handle_command(char *command) { | |||
279 | } | 334 | } |
280 | 335 | ||
281 | void handle_serial() { | 336 | void handle_serial() { |
282 | static char command[128]; | 337 | static char command[512]; |
283 | static int command_len; | 338 | static int command_len; |
284 | static int skip_command; | 339 | static int skip_command; |
285 | 340 | ||
@@ -323,6 +378,6 @@ void loop() { | |||
323 | */ | 378 | */ |
324 | 379 | ||
325 | engine_checksilence(millis()); | 380 | engine_checksilence(millis()); |
326 | digitalWrite(led, ++led_state & 1 ? HIGH : LOW); // turn the LED on (HIGH is the voltage level) | 381 | digitalWrite(led, ++led_state & 0xff < 0x7f ? HIGH : LOW); // turn the LED on (HIGH is the voltage level) |
327 | } | 382 | } |
328 | 383 | ||
@@ -8,9 +8,9 @@ | |||
8 | 8 | ||
9 | int g_midi_main_control = -1; | 9 | int g_midi_main_control = -1; |
10 | int g_midi_main_channel = 0; | 10 | int g_midi_main_channel = 0; |
11 | int g_midi_two_octave_split = 256 / 2; | 11 | int g_midi_two_octave_split = 50; |
12 | int g_midi_three_octave_split_1 = 256 / 3; | 12 | int g_midi_three_octave_split_1 = 33; |
13 | int g_midi_three_octave_split_2 = 512 / 3; | 13 | int g_midi_three_octave_split_2 = 66; |
14 | int g_midi_three_octave_split_inverse = 0; | 14 | int g_midi_three_octave_split_inverse = 0; |
15 | int g_settled_dist = 5; | 15 | int g_settled_dist = 5; |
16 | int g_timetosilence = 30; | 16 | int g_timetosilence = 30; |
@@ -33,12 +33,14 @@ config_reset() | |||
33 | 33 | ||
34 | g_midi_main_control = -1; | 34 | g_midi_main_control = -1; |
35 | g_midi_main_channel = 0; | 35 | g_midi_main_channel = 0; |
36 | g_midi_two_octave_split = 256 / 2; | 36 | g_midi_two_octave_split = 50; |
37 | g_midi_three_octave_split_1 = 256 / 3; | 37 | g_midi_three_octave_split_1 = 33; |
38 | g_midi_three_octave_split_2 = 512 / 3; | 38 | g_midi_three_octave_split_2 = 66; |
39 | g_midi_three_octave_split_inverse = 0; | 39 | g_midi_three_octave_split_inverse = 0; |
40 | g_settled_dist = 5; | 40 | g_settled_dist = 5; |
41 | g_timetosilence = 30; | 41 | g_timetosilence = 30; |
42 | |||
43 | g_config_source = source_none; | ||
42 | } | 44 | } |
43 | 45 | ||
44 | 46 | ||
@@ -206,23 +208,19 @@ config_handle_line(char *line) | |||
206 | { | 208 | { |
207 | LLine *l = &sc->line; | 209 | LLine *l = &sc->line; |
208 | 210 | ||
209 | if (sscanf(line, "%d %d %d %d", &l->x0, &l->y0, &l->x1, &l->y1) != 4) { | 211 | if (sscanf(line, "%d %d %d %d", &l->p0.x, &l->p0.y, &l->p1.x, &l->p1.y) != 4) { |
210 | fprintf(stderr, "Incorrect Line statement for string\n"); | 212 | fprintf(stderr, "Incorrect Line statement for string\n"); |
211 | return -1; | 213 | return -1; |
212 | } | 214 | } |
213 | if (l->y0 > l->y1) { | 215 | if (l->p0.y > l->p1.y) { |
214 | l->y0 ^= l->y1; | 216 | LPoint tmp = l->p0; |
215 | l->y1 ^= l->y0; | 217 | l->p0 = l->p1; |
216 | l->y0 ^= l->y1; | 218 | l->p1 = tmp; |
217 | l->x0 ^= l->x1; | ||
218 | l->x1 ^= l->x0; | ||
219 | l->x0 ^= l->x1; | ||
220 | |||
221 | } | 219 | } |
222 | if (l->y0 > g_min_y) | 220 | if (l->p0.y > g_min_y) |
223 | g_min_y = l->y0; | 221 | g_min_y = l->p0.y; |
224 | if (l->y1 < g_max_y) | 222 | if (l->p0.y < g_max_y) |
225 | g_max_y = l->y1; | 223 | g_max_y = l->p1.y; |
226 | break; | 224 | break; |
227 | } | 225 | } |
228 | case KEYWORD_MODE: | 226 | case KEYWORD_MODE: |
@@ -259,7 +257,7 @@ config_handle_line(char *line) | |||
259 | fprintf(stderr, "Incorrect channel specified: %s.\n", _line); | 257 | fprintf(stderr, "Incorrect channel specified: %s.\n", _line); |
260 | return -1; | 258 | return -1; |
261 | } | 259 | } |
262 | printf("String %d is on channel %d\n", g_current_string, sc->channel); | 260 | printf("String %d is on channel %d\n", 1 + g_current_string, sc->channel); |
263 | break; | 261 | break; |
264 | case KEYWORD_NOTE: | 262 | case KEYWORD_NOTE: |
265 | sc->note = config_midi_note_from_string(line); | 263 | sc->note = config_midi_note_from_string(line); |
@@ -267,7 +265,7 @@ config_handle_line(char *line) | |||
267 | fprintf(stderr, "Unknown midi note specified: %s.\n", _line); | 265 | fprintf(stderr, "Unknown midi note specified: %s.\n", _line); |
268 | return -1; | 266 | return -1; |
269 | } | 267 | } |
270 | printf("String %d is midi note %d\n", g_current_string, sc->note); | 268 | printf("String %d is midi note %d\n", 1 + g_current_string, sc->note); |
271 | break; | 269 | break; |
272 | case KEYWORD_AFTERTOUCH: | 270 | case KEYWORD_AFTERTOUCH: |
273 | switch (config_findkeyword(&line)) { | 271 | switch (config_findkeyword(&line)) { |
@@ -315,7 +313,6 @@ config_handle_line(char *line) | |||
315 | fprintf(stderr, "Invalid percentage in line: %s\n", _line); | 313 | fprintf(stderr, "Invalid percentage in line: %s\n", _line); |
316 | exit(1); | 314 | exit(1); |
317 | } | 315 | } |
318 | g_midi_two_octave_split = (256 * g_midi_two_octave_split) / 100; | ||
319 | break; | 316 | break; |
320 | case KEYWORD_THREEOCTAVESPLIT_1: | 317 | case KEYWORD_THREEOCTAVESPLIT_1: |
321 | g_midi_three_octave_split_1 = atol(line); | 318 | g_midi_three_octave_split_1 = atol(line); |
@@ -324,7 +321,6 @@ config_handle_line(char *line) | |||
324 | fprintf(stderr, "Invalid percentage in line: %s\n", _line); | 321 | fprintf(stderr, "Invalid percentage in line: %s\n", _line); |
325 | exit(1); | 322 | exit(1); |
326 | } | 323 | } |
327 | g_midi_three_octave_split_1 = (256 * g_midi_three_octave_split_1) / 100; | ||
328 | split_done = 1; | 324 | split_done = 1; |
329 | break; | 325 | break; |
330 | case KEYWORD_THREEOCTAVESPLIT_2: | 326 | case KEYWORD_THREEOCTAVESPLIT_2: |
@@ -334,7 +330,6 @@ config_handle_line(char *line) | |||
334 | fprintf(stderr, "Invalid percentage in line: %s\n", _line); | 330 | fprintf(stderr, "Invalid percentage in line: %s\n", _line); |
335 | return -1; | 331 | return -1; |
336 | } | 332 | } |
337 | g_midi_three_octave_split_2 = (256 * g_midi_three_octave_split_2) / 100; | ||
338 | split_done = 1; | 333 | split_done = 1; |
339 | break; | 334 | break; |
340 | case KEYWORD_MIDI_MAIN_CONTROL: | 335 | case KEYWORD_MIDI_MAIN_CONTROL: |
@@ -377,34 +372,43 @@ config_handle_line(char *line) | |||
377 | return 0; | 372 | return 0; |
378 | } | 373 | } |
379 | 374 | ||
380 | void | 375 | size_t |
381 | config_dumpglobals(char *out, size_t outsize) | 376 | config_dumpglobals(char *out, size_t outsize) |
382 | { | 377 | { |
383 | int tos1 = g_midi_three_octave_split_inverse ? g_midi_three_octave_split_2 : g_midi_three_octave_split_1; | 378 | int tos1 = g_midi_three_octave_split_inverse ? g_midi_three_octave_split_2 : g_midi_three_octave_split_1; |
384 | int tos2 = g_midi_three_octave_split_inverse ? g_midi_three_octave_split_1 : g_midi_three_octave_split_2; | 379 | int tos2 = g_midi_three_octave_split_inverse ? g_midi_three_octave_split_1 : g_midi_three_octave_split_2; |
385 | 380 | ||
386 | size_t off = snprintf(out, outsize, | 381 | size_t off = snprintf(out, outsize, |
387 | "Strings %d\n\nmidi_two_octave_split %d\nmidi_three_octave_split_1 %d\nmidi_three_octave_split_2 %d\nmidi_main_control %d\nmidi_main_channel %d\n", | 382 | "Strings %d\n\nmidi_two_octave_split %d\nmidi_three_octave_split_1 %d\nmidi_three_octave_split_2 %d\n", |
388 | g_string_count, g_midi_two_octave_split, tos1, tos2, g_midi_main_control, g_midi_main_channel ); | 383 | g_string_count, g_midi_two_octave_split, tos1, tos2 ); |
384 | |||
385 | if (g_midi_main_control >= 0) | ||
386 | off += snprintf(out + off, outsize - off, | ||
387 | "midi_main_control %d\n\n", g_midi_main_control); | ||
388 | |||
389 | if (g_midi_main_channel > 0) | ||
390 | off += snprintf(out + off, outsize - off, | ||
391 | "midi_main_channel %d\n\n", g_midi_main_channel); | ||
389 | 392 | ||
390 | if (g_settled_dist != 5) | 393 | if (g_settled_dist != 5) |
391 | off += snprintf(out + off, outsize - off, | 394 | off += snprintf(out + off, outsize - off, |
392 | "SettledDist %d\n\n", g_settled_dist); | 395 | "SettledDist %d\n\n", g_settled_dist); |
393 | snprintf(out + off, outsize - off, "\n" ); | 396 | off += snprintf(out + off, outsize - off, "\n" ); |
397 | return off; | ||
394 | } | 398 | } |
395 | 399 | ||
396 | void | 400 | size_t |
397 | config_dumpstring(int string, char *out, size_t outsize) | 401 | config_dumpstring(int string, char *out, size_t outsize) |
398 | { | 402 | { |
399 | StringConfig *s = g_string_conf + string; | 403 | StringConfig *s = g_string_conf + string; |
400 | 404 | ||
401 | if (string < 0 || string > g_string_count || !out) { | 405 | if (string < 0 || string > g_string_count || !out) { |
402 | if (out && outsize) *out = 0; | 406 | if (out && outsize) *out = 0; |
403 | return; | 407 | return 0; |
404 | } | 408 | } |
405 | size_t off = snprintf(out, outsize, | 409 | size_t off = snprintf(out, outsize, |
406 | "String %d\n Line %d %d %d %d\n Mode %s\n Channel %d\n Note %s\n AfterTouch %s\n Controller %d\n", | 410 | "String %d\n Line %d %d %d %d\n Mode %s\n Channel %d\n Note %s\n AfterTouch %s\n Controller %d\n", |
407 | string + 1, s->line.x0, s->line.y0, s->line.x1, s->line.y1, | 411 | string + 1, s->line.p0.x, s->line.p0.y, s->line.p1.x, s->line.p1.y, |
408 | mode_names[s->mode], s->channel, midi_note[s->note], modifier_names[s->modifier], s->controller ); | 412 | mode_names[s->mode], s->channel, midi_note[s->note], modifier_names[s->modifier], s->controller ); |
409 | 413 | ||
410 | if (s->timetosilence) | 414 | if (s->timetosilence) |
@@ -413,5 +417,6 @@ config_dumpstring(int string, char *out, size_t outsize) | |||
413 | if (s->pitch_factor) | 417 | if (s->pitch_factor) |
414 | off += snprintf(out + off, outsize - off, | 418 | off += snprintf(out + off, outsize - off, |
415 | " PitchFactor %d\n", s->pitch_factor); | 419 | " PitchFactor %d\n", s->pitch_factor); |
416 | snprintf(out + off, outsize - off, "\n" ); | 420 | off += snprintf(out + off, outsize - off, "\n" ); |
421 | return off; | ||
417 | } | 422 | } |
@@ -1,8 +1,10 @@ | |||
1 | #pragma once | 1 | #pragma once |
2 | 2 | ||
3 | #include <stdint.h> | 3 | #include <stdint.h> |
4 | #include "geometry.h" | ||
4 | 5 | ||
5 | #define MAX_LINECOUNT 32 | 6 | #define MAX_LINECOUNT 32 |
7 | #define CALIB_DEBUG | ||
6 | 8 | ||
7 | extern int g_min_y, g_max_y; | 9 | extern int g_min_y, g_max_y; |
8 | 10 | ||
@@ -37,14 +39,21 @@ typedef enum { | |||
37 | playing = 2 | 39 | playing = 2 |
38 | } StringPlaying; | 40 | } StringPlaying; |
39 | 41 | ||
40 | typedef struct { | 42 | typedef enum { |
41 | int x0; int y0; | 43 | sel_none = 0, |
42 | int x1; int y1; | 44 | sel_min_y = 1, |
43 | } LLine; | 45 | sel_max_y = 2, |
46 | sel_2_oct = 3, | ||
47 | sel_3_oct_top = 4, | ||
48 | sel_3_oct_bottom = 5 | ||
49 | } ConfigSelect; | ||
44 | 50 | ||
45 | typedef struct { | 51 | typedef enum { |
46 | int x; int y; | 52 | source_none = 0, |
47 | } LPoint; | 53 | source_harfe = 1, |
54 | source_file = 2, | ||
55 | source_edit = 3 | ||
56 | } ConfigSource; | ||
48 | 57 | ||
49 | typedef struct { | 58 | typedef struct { |
50 | StringMode mode; | 59 | StringMode mode; |
@@ -70,6 +79,6 @@ extern StringConfig g_string_conf[MAX_LINECOUNT]; | |||
70 | extern int g_string_count; | 79 | extern int g_string_count; |
71 | void config_reset(); | 80 | void config_reset(); |
72 | int config_handle_line( char *line); | 81 | int config_handle_line( char *line); |
73 | void config_dumpglobals(char *out, size_t outsize); | 82 | size_t config_dumpglobals(char *out, size_t outsize); |
74 | void config_dumpstring(int string, char *out, size_t outsize); | 83 | size_t config_dumpstring(int string, char *out, size_t outsize); |
75 | char *config_midi_note_to_string(int string); | 84 | char *config_midi_note_to_string(int string); |
@@ -6,25 +6,30 @@ | |||
6 | #include "display.h" | 6 | #include "display.h" |
7 | 7 | ||
8 | #define display_measure_text(text,w,h) TTF_SizeText(font,(text),(w),(h)) | 8 | #define display_measure_text(text,w,h) TTF_SizeText(font,(text),(w),(h)) |
9 | enum { FONT_SIZE = 28 }; | ||
9 | 10 | ||
10 | static SDL_Window *screen; | 11 | static SDL_Window *screen; |
11 | static SDL_Renderer *renderer; | 12 | static SDL_Renderer *renderer; |
12 | static int g_width, g_height; | 13 | static int g_screen_width, g_screen_height; |
14 | static int g_harfe_width, g_harfe_height; | ||
15 | double g_scale_factor; | ||
13 | static TTF_Font *font = NULL; | 16 | static TTF_Font *font = NULL; |
14 | 17 | ||
15 | void | 18 | void |
16 | display_init(int width, int height) | 19 | display_init(int screen_width, int screen_height, int harfe_width, int harfe_height) |
17 | { | 20 | { |
18 | SDL_RWops *font_file; | 21 | SDL_RWops *font_file; |
19 | 22 | ||
20 | g_width = width; | 23 | g_screen_width = screen_width; |
21 | g_height = height; | 24 | g_screen_height = screen_height; |
25 | g_harfe_width = harfe_width; | ||
26 | g_harfe_height = harfe_height; | ||
22 | 27 | ||
23 | if (SDL_Init(SDL_INIT_EVERYTHING) == -1) { | 28 | if (SDL_Init(SDL_INIT_EVERYTHING) == -1) { |
24 | fprintf(stderr, "Can't initialize SDL.\n"); | 29 | fprintf(stderr, "Can't initialize SDL.\n"); |
25 | exit(1); | 30 | exit(1); |
26 | } | 31 | } |
27 | screen = SDL_CreateWindow("Laserharfe", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_OPENGL); | 32 | screen = SDL_CreateWindow("Laserharfe", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_width, screen_height, SDL_WINDOW_OPENGL); |
28 | if (!screen) { | 33 | if (!screen) { |
29 | fprintf(stderr, "Can't set video mode.\n"); | 34 | fprintf(stderr, "Can't set video mode.\n"); |
30 | exit(1); | 35 | exit(1); |
@@ -35,7 +40,32 @@ display_init(int width, int height) | |||
35 | 40 | ||
36 | TTF_Init(); | 41 | TTF_Init(); |
37 | font_file = SDL_RWFromConstMem(GenBkBasB_ttf, GenBkBasB_ttf_len); | 42 | font_file = SDL_RWFromConstMem(GenBkBasB_ttf, GenBkBasB_ttf_len); |
38 | font = TTF_OpenFontRW(font_file, 1, 28); | 43 | font = TTF_OpenFontRW(font_file, 1, FONT_SIZE); |
44 | |||
45 | g_scale_factor = (double)harfe_height / (double)screen_height; | ||
46 | if( (double)harfe_width / (double)screen_width < g_scale_factor ) | ||
47 | g_scale_factor = (double)harfe_width / (double)screen_width; | ||
48 | printf( "Using scale factor of %lf\n", g_scale_factor ); | ||
49 | } | ||
50 | |||
51 | void | ||
52 | display_getdimensions(int *width, int *height, int *fontsize) | ||
53 | { | ||
54 | *width = g_screen_width; | ||
55 | *height = g_screen_height; | ||
56 | *fontsize = FONT_SIZE; | ||
57 | } | ||
58 | |||
59 | int | ||
60 | display_scale_harfe_to_screen(int coord) | ||
61 | { | ||
62 | return (int)((double)coord / g_scale_factor); | ||
63 | } | ||
64 | |||
65 | int | ||
66 | display_scale_screen_to_harfe(int coord) | ||
67 | { | ||
68 | return (int)((double)coord * g_scale_factor); | ||
39 | } | 69 | } |
40 | 70 | ||
41 | void | 71 | void |
@@ -48,19 +78,23 @@ display_clear() | |||
48 | void | 78 | void |
49 | display_circle(int x, int y, int w) | 79 | display_circle(int x, int y, int w) |
50 | { | 80 | { |
51 | if (x >= 0 && x < g_width && y >= 0 && y < g_height) | 81 | y = g_screen_height - y; |
52 | display_circle_color(x, y, w, 0xffffffff); | 82 | if (x >= 0 && x <= g_screen_width && y >= 0 && y <= g_screen_height) |
83 | filledCircleColor(renderer, x, y, w, 0xffffffff); | ||
53 | } | 84 | } |
54 | 85 | ||
55 | void | 86 | void |
56 | display_circle_color(int x, int y, int w, int color) | 87 | display_circle_color(int x, int y, int w, int color) |
57 | { | 88 | { |
89 | y = g_screen_height - y; | ||
58 | filledCircleColor(renderer, x, y, w, color); | 90 | filledCircleColor(renderer, x, y, w, color); |
59 | } | 91 | } |
60 | 92 | ||
61 | void | 93 | void |
62 | display_line(int x0, int y0, int x1, int y1) | 94 | display_line(int x0, int y0, int x1, int y1) |
63 | { | 95 | { |
96 | y1 = g_screen_height - y1; | ||
97 | y0 = g_screen_height - y0; | ||
64 | SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); | 98 | SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); |
65 | SDL_RenderDrawLine(renderer, x0, y0, x1, y1); | 99 | SDL_RenderDrawLine(renderer, x0, y0, x1, y1); |
66 | } | 100 | } |
@@ -68,11 +102,25 @@ display_line(int x0, int y0, int x1, int y1) | |||
68 | void | 102 | void |
69 | display_line_color(int x0, int y0, int x1, int y1, int color) | 103 | display_line_color(int x0, int y0, int x1, int y1, int color) |
70 | { | 104 | { |
105 | y1 = g_screen_height - y1; | ||
106 | y0 = g_screen_height - y0; | ||
71 | SDL_SetRenderDrawColor(renderer, (color >> 24) & 255, (color >> 16) & 255, (color >> 8) & 255, 255); | 107 | SDL_SetRenderDrawColor(renderer, (color >> 24) & 255, (color >> 16) & 255, (color >> 8) & 255, 255); |
72 | SDL_RenderDrawLine(renderer, x0, y0, x1, y1); | 108 | SDL_RenderDrawLine(renderer, x0, y0, x1, y1); |
73 | } | 109 | } |
74 | 110 | ||
75 | void | 111 | void |
112 | display_rect_color(int x, int y, int width, int height, int color) | ||
113 | { | ||
114 | SDL_Rect r; | ||
115 | r.x = x; | ||
116 | r.y = g_screen_height - y; | ||
117 | r.w = width; | ||
118 | r.h = height; | ||
119 | SDL_SetRenderDrawColor(renderer, (color >> 24) & 255, (color >> 16) & 255, (color >> 8) & 255, 255); | ||
120 | SDL_RenderFillRect(renderer, &r); | ||
121 | } | ||
122 | |||
123 | void | ||
76 | display_redraw() | 124 | display_redraw() |
77 | { | 125 | { |
78 | SDL_RenderPresent(renderer); | 126 | SDL_RenderPresent(renderer); |
@@ -81,6 +129,7 @@ display_redraw() | |||
81 | void | 129 | void |
82 | display_text(char *text, int x, int y, int color) | 130 | display_text(char *text, int x, int y, int color) |
83 | { | 131 | { |
132 | y = g_screen_height - y; | ||
84 | SDL_Color s_color = { 255 & (color>>24), 255 & (color>>16), 255 & (color>>8) }; | 133 | SDL_Color s_color = { 255 & (color>>24), 255 & (color>>16), 255 & (color>>8) }; |
85 | SDL_Surface *sText = TTF_RenderText_Solid(font, text, s_color); | 134 | SDL_Surface *sText = TTF_RenderText_Solid(font, text, s_color); |
86 | SDL_Rect rect = {x, y, sText->w, sText->h}; | 135 | SDL_Rect rect = {x, y, sText->w, sText->h}; |
@@ -98,7 +147,7 @@ display_textbox(int min_x, int pos, int max_x, int max_pos, char *text, int colo | |||
98 | 147 | ||
99 | display_measure_text("#", &w, &h); | 148 | display_measure_text("#", &w, &h); |
100 | item_height = 3 * h / 2; | 149 | item_height = 3 * h / 2; |
101 | min_y = (g_height - item_height * max_pos) / 2 + pos * item_height; | 150 | min_y = (g_screen_height - item_height * max_pos) / 2 + pos * item_height; |
102 | 151 | ||
103 | //boxColor(screen, min_x, min_y, max_x, min_y + item_height, color); | 152 | //boxColor(screen, min_x, min_y, max_x, min_y + item_height, color); |
104 | //rectangleColor(screen, min_x, min_y, max_x, min_y + item_height, 0xffffffff); | 153 | //rectangleColor(screen, min_x, min_y, max_x, min_y + item_height, 0xffffffff); |
@@ -106,6 +155,25 @@ display_textbox(int min_x, int pos, int max_x, int max_pos, char *text, int colo | |||
106 | display_text(text, min_x + (max_x - min_x - w) / 2, min_y + (item_height - h) / 2, 0xffffffff); | 155 | display_text(text, min_x + (max_x - min_x - w) / 2, min_y + (item_height - h) / 2, 0xffffffff); |
107 | } | 156 | } |
108 | 157 | ||
158 | void | ||
159 | display_messagebox(char *title, char *info) { | ||
160 | SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_INFORMATION, title, info, screen); | ||
161 | } | ||
162 | |||
163 | int | ||
164 | display_messagebox_yesno(char *title, char *info) { | ||
165 | const SDL_MessageBoxButtonData buttons[] = { | ||
166 | { /* .flags, .buttonid, .text */ 0, 0, "Cancel" }, | ||
167 | { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "OK" }, | ||
168 | }; | ||
169 | const SDL_MessageBoxData messageboxdata = { | ||
170 | SDL_MESSAGEBOX_INFORMATION, screen, title, info, SDL_arraysize(buttons), buttons, NULL | ||
171 | }; | ||
172 | int buttonid; | ||
173 | SDL_ShowMessageBox(&messageboxdata, &buttonid); | ||
174 | return buttonid == 1; | ||
175 | } | ||
176 | |||
109 | int | 177 | int |
110 | display_test_menu_click(int y, int max_pos) | 178 | display_test_menu_click(int y, int max_pos) |
111 | { | 179 | { |
@@ -114,7 +182,7 @@ display_test_menu_click(int y, int max_pos) | |||
114 | /* | 182 | /* |
115 | display_measure_text( "#", &w, &h ); | 183 | display_measure_text( "#", &w, &h ); |
116 | item_height = 3 * h / 2; | 184 | item_height = 3 * h / 2; |
117 | min_y = ( g_height - item_height * max_pos ) / 2; | 185 | min_y = ( g_screen_height - item_height * max_pos ) / 2; |
118 | if( y < min_y ) return -1; | 186 | if( y < min_y ) return -1; |
119 | if( y > min_y + item_height * max_pos ) return -1; | 187 | if( y > min_y + item_height * max_pos ) return -1; |
120 | return ( y - min_y ) / item_height; | 188 | return ( y - min_y ) / item_height; |
@@ -1,6 +1,9 @@ | |||
1 | #pragma once | 1 | #pragma once |
2 | 2 | ||
3 | void display_init(int width, int height); | 3 | void display_init(int screen_width, int screen_height, int harfe_width, int harfe_height); |
4 | void display_getdimensions(int *width, int *height, int *fontsize); | ||
5 | int display_scale_harfe_to_screen(int coord); | ||
6 | int display_scale_screen_to_harfe(int coord); | ||
4 | void display_redraw(); | 7 | void display_redraw(); |
5 | 8 | ||
6 | void display_clear(); | 9 | void display_clear(); |
@@ -8,10 +11,12 @@ void display_line(int x0, int y0, int x1, int y1); | |||
8 | void display_line_color(int x0, int y0, int x1, int y1, int color); | 11 | void display_line_color(int x0, int y0, int x1, int y1, int color); |
9 | void display_circle(int x, int y, int w); | 12 | void display_circle(int x, int y, int w); |
10 | void display_circle_color(int x, int y, int w, int color); | 13 | void display_circle_color(int x, int y, int w, int color); |
11 | void display_rectangle(int x, int y, int w, int h); | 14 | void display_rect_color(int x, int y, int width, int height, int color); |
12 | 15 | ||
13 | void display_text(char *text, int x, int y, int color); | 16 | void display_text(char *text, int x, int y, int color); |
14 | void display_textbox(int min_x, int pos, int max_x, int max_pos, char *text, int color); | 17 | void display_textbox(int min_x, int pos, int max_x, int max_pos, char *text, int color); |
15 | int display_test_menu_click(int y, int max_pos); | 18 | int display_test_menu_click(int y, int max_pos); |
19 | void display_messagebox(char *title, char *info); | ||
20 | int display_messagebox_yesno(char *title, char *info); | ||
16 | 21 | ||
17 | void display_report(char *message, int line); | 22 | void display_report(char *message, int line); |
@@ -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 |
@@ -1,6 +1,12 @@ | |||
1 | #pragma once | 1 | #pragma once |
2 | 2 | ||
3 | #include "config.h" | ||
4 | |||
3 | void engine_init(); | 5 | void engine_init(); |
4 | void engine_redraw(); | 6 | void engine_redraw(); |
5 | void engine_handle_point(LPoint * p, uint32_t monotime); | 7 | void engine_handle_point(LPoint * p, uint32_t monotime); |
6 | void engine_checksilence(uint32_t monotime); | 8 | void engine_checksilence(uint32_t monotime); |
9 | void engine_select_config(ConfigSelect sel); | ||
10 | ConfigSelect engine_change_selected(int off); | ||
11 | |||
12 | extern int g_harfe_width, g_harfe_height; | ||
diff --git a/geometry.c b/geometry.c new file mode 100644 index 0000000..f2961c7 --- /dev/null +++ b/geometry.c | |||
@@ -0,0 +1,31 @@ | |||
1 | #include "geometry.h" | ||
2 | |||
3 | // dist is a fixed point with precission of 8 bits | ||
4 | // offs is where on the line segment xy0-xy1 the point's normale hits, | ||
5 | // range 0..65536 (but can extend, if normale hits line outside line segment) | ||
6 | static inline int | ||
7 | impl_dist_pl(int xp, int yp, int x0, int y0, int x1, int y1, int *offs) | ||
8 | { | ||
9 | double r = (y1 - y0) * (y1 - y0) + (x1 - x0) * (x1 - x0); | ||
10 | double q1 = (xp - x0) * (y1 - y0) - (yp - y0) * (x1 - x0); | ||
11 | double q2 = (x1 - x0) * (xp - x0) + (y1 - y0) * (yp - y0); | ||
12 | |||
13 | *offs = (int)((q2 *65336.0f) / r); | ||
14 | return (int)( q1 * q1 * ((double)(y0 - y1) * (double)(y0 - y1) + (double)(x1 - x0) * (double)(x1 - x0)) * 256.0f / (r * r)); | ||
15 | } | ||
16 | |||
17 | int | ||
18 | dist_pl(LPoint const * p, LLine const * l, int *offs) | ||
19 | { | ||
20 | return impl_dist_pl(p->x, p->y, l->p0.x, l->p0.y, l->p1.x, l->p1.y, offs); | ||
21 | } | ||
22 | |||
23 | static inline int | ||
24 | impl_dist_pp(int x0, int y0, int x1, int y1 ) { | ||
25 | return (y0-y1)*(y0-y1)+(x0-x1)*(x0-x1); | ||
26 | } | ||
27 | |||
28 | int | ||
29 | dist_pp(LPoint const * p0, LPoint const * p1) { | ||
30 | return impl_dist_pp(p0->x,p0->y,p1->x,p1->y); | ||
31 | } | ||
diff --git a/geometry.h b/geometry.h new file mode 100644 index 0000000..509ec7e --- /dev/null +++ b/geometry.h | |||
@@ -0,0 +1,18 @@ | |||
1 | #pragma once | ||
2 | |||
3 | typedef struct { | ||
4 | int x; | ||
5 | int y; | ||
6 | } LPoint; | ||
7 | |||
8 | typedef struct { | ||
9 | LPoint p0; | ||
10 | LPoint p1; | ||
11 | } LLine; | ||
12 | |||
13 | // dist is a fixed point with precission of 8 bits | ||
14 | // offs is where on the line segment xy0-xy1 the point's normale hits, | ||
15 | // range 0..65536 (but can extend, if normale hits line outside line segment) | ||
16 | int dist_pl(LPoint const * p, LLine const * l, int * offs); | ||
17 | int dist_pp(LPoint const * p0, LPoint const * p1); | ||
18 | |||
@@ -10,22 +10,31 @@ | |||
10 | #include <termios.h> | 10 | #include <termios.h> |
11 | #include <unistd.h> | 11 | #include <unistd.h> |
12 | #include <dirent.h> | 12 | #include <dirent.h> |
13 | #include <pwd.h> | ||
13 | 14 | ||
14 | #include <SDL2/SDL.h> | 15 | #include <SDL2/SDL.h> |
15 | #include "display.h" | 16 | #include "display.h" |
16 | #include "config.h" | 17 | #include "config.h" |
17 | #include "engine.h" | 18 | #include "engine.h" |
19 | #include "calib.h" | ||
18 | 20 | ||
19 | /*** | 21 | /*** |
20 | Global config and status values | 22 | Global config and status values |
21 | ***/ | 23 | ***/ |
22 | 24 | ||
23 | /* Window width and height */ | 25 | /* Window width and height */ |
24 | // const int g_width = 1024, g_height = 768; | 26 | enum { |
25 | const int g_width = 800, g_height = 600; | 27 | HARFE_WIDTH = 1024, |
28 | HARFE_HEIGHT = 768, | ||
29 | SCREEN_WIDTH = 800, | ||
30 | SCREEN_HEIGHT = 600 | ||
31 | }; | ||
26 | 32 | ||
27 | int g_harfe_connected = 0; | 33 | int g_harfe_connected = 0; |
28 | int g_harfe_fd = -1; | 34 | int g_harfe_fd = -1; |
35 | int g_importing_config = 0; | ||
36 | ConfigSource g_config_source = source_none; | ||
37 | int g_calibration_running = 0; | ||
29 | 38 | ||
30 | static char * | 39 | static char * |
31 | find_harfe() | 40 | find_harfe() |
@@ -150,6 +159,13 @@ harfe_worker(void) | |||
150 | free(portname); | 159 | free(portname); |
151 | g_harfe_connected = 1; | 160 | g_harfe_connected = 1; |
152 | 161 | ||
162 | /* Get remote config (if any) */ | ||
163 | config_reset(); | ||
164 | write(g_harfe_fd, "S2\n", 3); | ||
165 | usleep(50); | ||
166 | g_importing_config = 1; | ||
167 | write(g_harfe_fd, "I\n", 2); | ||
168 | |||
153 | while (running) { | 169 | while (running) { |
154 | while (text_fill < sizeof(text) && !memchr(text, '\n', text_fill)) { | 170 | while (text_fill < sizeof(text) && !memchr(text, '\n', text_fill)) { |
155 | ssize_t b = read(g_harfe_fd, text + text_fill, sizeof(text) - text_fill); | 171 | ssize_t b = read(g_harfe_fd, text + text_fill, sizeof(text) - text_fill); |
@@ -178,15 +194,29 @@ harfe_worker(void) | |||
178 | if (text_fill && lineend[-1] == '\r') | 194 | if (text_fill && lineend[-1] == '\r') |
179 | lineend[-1] = 0; | 195 | lineend[-1] = 0; |
180 | printf( "%s\n", text ); | 196 | printf( "%s\n", text ); |
181 | int num_points = sscanf(text, "%04d:%04d %04d:%04d %04d:%04d %04d:%04d", &p[0].x, &p[0].y, &p[1].x, &p[1].y, &p[2].x, &p[2].y, &p[3].x, &p[3].y); | ||
182 | 197 | ||
183 | ptime = now(); | 198 | if (g_importing_config) { |
184 | for (i = 0; i < num_points / 2; ++i) { | 199 | if (!strcmp(text, "-- DONE")) { |
200 | g_importing_config = 0; | ||
201 | g_config_source = source_harfe; | ||
202 | } else | ||
203 | config_handle_line(text); | ||
204 | } else { | ||
205 | |||
206 | int num_points = sscanf(text, "%04d:%04d %04d:%04d %04d:%04d %04d:%04d", &p[0].x, &p[0].y, &p[1].x, &p[1].y, &p[2].x, &p[2].y, &p[3].x, &p[3].y); | ||
207 | |||
208 | ptime = now(); | ||
209 | for (i = 0; i < num_points / 2; ++i) { | ||
185 | // printf("%04d:%04d\n", p[i].x, p[i].y); | 210 | // printf("%04d:%04d\n", p[i].x, p[i].y); |
186 | engine_handle_point(p + i, ptime); | 211 | |
187 | } | 212 | if (!g_calibration_running) |
188 | if (num_points > 1 || *text == '-') | 213 | engine_handle_point(p + i, ptime); |
214 | else | ||
215 | calib_handle_point(p + i, ptime); | ||
216 | } | ||
217 | if (num_points > 1 || *text == '-') | ||
189 | ++g_events; | 218 | ++g_events; |
219 | } | ||
190 | 220 | ||
191 | consumed = lineend - text + 1; | 221 | consumed = lineend - text + 1; |
192 | memmove(text, lineend + 1, text_fill - consumed); | 222 | memmove(text, lineend + 1, text_fill - consumed); |
@@ -226,6 +256,36 @@ config_parse(char *config_file) | |||
226 | } | 256 | } |
227 | 257 | ||
228 | fclose(fh); | 258 | fclose(fh); |
259 | g_config_source = source_file; | ||
260 | } | ||
261 | |||
262 | static void | ||
263 | calib_fetch() { | ||
264 | int default_notes[] = { 60, 62, 64, 65, 67, 69, 71, 72, 74, 76, 77, 79, 81, 83 }; | ||
265 | int i, result_count; | ||
266 | LLine *result = calib_get_results(&result_count); | ||
267 | |||
268 | config_reset(); | ||
269 | g_string_count = result_count; | ||
270 | |||
271 | g_min_y = 0; g_max_y = 1024; | ||
272 | |||
273 | for (i=0; i<g_string_count; ++i) { | ||
274 | LLine *l = result + i; | ||
275 | |||
276 | if (l->p0.y > g_min_y) | ||
277 | g_min_y = l->p0.y; | ||
278 | if (l->p1.y < g_max_y) | ||
279 | g_max_y = l->p1.y; | ||
280 | |||
281 | g_string_conf[i].line = *l; | ||
282 | g_string_conf[i].mode = midi_three_octaves; | ||
283 | g_string_conf[i].channel = i; | ||
284 | g_string_conf[i].note = default_notes[i]; | ||
285 | g_string_conf[i].modifier = pitch_bend_up; | ||
286 | } | ||
287 | |||
288 | g_config_source = source_edit; | ||
229 | } | 289 | } |
230 | 290 | ||
231 | int | 291 | int |
@@ -236,48 +296,153 @@ main(int argc, char **argv) | |||
236 | pthread_t thread_id; | 296 | pthread_t thread_id; |
237 | uint32_t runtime; | 297 | uint32_t runtime; |
238 | static int last_click_x, last_click_y, last_mouse_event; | 298 | static int last_click_x, last_click_y, last_mouse_event; |
299 | static int g_up_pressed = 0, g_down_pressed = 0; | ||
239 | 300 | ||
240 | display_init(g_width, g_height); | 301 | display_init(SCREEN_WIDTH, SCREEN_HEIGHT, HARFE_WIDTH, HARFE_HEIGHT); |
241 | engine_init(); | 302 | engine_init(); |
242 | config_parse("config_midi"); | 303 | // config_parse("config_midi"); |
243 | 304 | ||
244 | pthread_create(&thread_id, NULL, worker, NULL); | 305 | pthread_create(&thread_id, NULL, worker, NULL); |
245 | 306 | ||
307 | /* | ||
308 | E - Export config to Harfe (with implicite write to SD) | ||
309 | I - Import config from Harfe | ||
310 | W - Write config on Harfe to SD (no implicite Transfer) | ||
311 | |||
312 | S - Save config to local file | ||
313 | L - Load config from local default (config_midi) | ||
314 | |||
315 | Y - Invert String order | ||
316 | |||
317 | Q - Reset local Config | ||
318 | C - Start calibration | ||
319 | M - Play MIDI C through Harfe | ||
320 | */ | ||
321 | |||
246 | /* Spin and let call back do all the work */ | 322 | /* Spin and let call back do all the work */ |
247 | while (1) { | 323 | while (1) { |
248 | SDL_WaitEventTimeout(&ev, 10); | 324 | SDL_WaitEventTimeout(&ev, 10); |
249 | switch (ev.type) { | 325 | switch (ev.type) { |
250 | case SDL_QUIT: | 326 | case SDL_QUIT: |
251 | exit(0); | 327 | exit(0); |
252 | case SDL_KEYDOWN: | 328 | case SDL_KEYUP: |
329 | if (ev.key.keysym.scancode == SDL_SCANCODE_UP) g_up_pressed = 0; | ||
330 | if (ev.key.keysym.scancode == SDL_SCANCODE_DOWN) g_down_pressed = 0; | ||
331 | break; | ||
332 | case SDL_KEYDOWN: | ||
253 | /* | 333 | /* |
254 | if( ev.key.keysym.sym >= SDLK_1 && ev.key.keysym.sym <= SDLK_9 ) | 334 | if ( ev.key.keysym.sym >= SDLK_1 && ev.key.keysym.sym <= SDLK_9 ) |
255 | engine_select_string( ev.key.keysym.sym - SDLK_1 ); | 335 | engine_select_string( ev.key.keysym.sym - SDLK_1 ); |
256 | if( ev.key.keysym.sym == SDLK_BACKSPACE || ev.key.keysym.sym == SDLK_DELETE ) | 336 | if ( ev.key.keysym.sym == SDLK_BACKSPACE || ev.key.keysym.sym == SDLK_DELETE ) |
257 | engine_delete_selected_string( ); | 337 | engine_delete_selected_string( ); |
258 | if( ev.key.keysym.sym == SDLK_d ) { | 338 | if ( ev.key.keysym.sym == SDLK_d ) { |
259 | g_stringsdescending = 1 - g_stringsdescending; | 339 | g_stringsdescending = 1 - g_stringsdescending; |
260 | printf( "String order (left to right) is now %sscending.\n", g_stringsdescending ? "de" : "a" ); | 340 | printf( "String order (left to right) is now %sscending.\n", g_stringsdescending ? "de" : "a" ); |
261 | } | 341 | } |
262 | */ | 342 | */ |
263 | if( ev.key.keysym.scancode == SDL_SCANCODE_R) { | 343 | if ( ev.key.keysym.scancode == SDL_SCANCODE_0) |
264 | fprintf( stderr, "re-read config\n" ); | 344 | engine_select_config(sel_none); |
265 | write(g_harfe_fd, "R\n", 2); | 345 | if ( ev.key.keysym.scancode == SDL_SCANCODE_1) |
346 | engine_select_config(sel_min_y); | ||
347 | if ( ev.key.keysym.scancode == SDL_SCANCODE_2) | ||
348 | engine_select_config(sel_max_y); | ||
349 | if ( ev.key.keysym.scancode == SDL_SCANCODE_3) | ||
350 | engine_select_config(sel_2_oct); | ||
351 | if ( ev.key.keysym.scancode == SDL_SCANCODE_4) | ||
352 | engine_select_config(sel_3_oct_top); | ||
353 | if ( ev.key.keysym.scancode == SDL_SCANCODE_5) | ||
354 | engine_select_config(sel_3_oct_bottom); | ||
355 | |||
356 | if ( ev.key.keysym.scancode == SDL_SCANCODE_UP && ! g_up_pressed++) | ||
357 | engine_change_selected(1); | ||
358 | if ( ev.key.keysym.scancode == SDL_SCANCODE_DOWN && ! g_down_pressed++) | ||
359 | engine_change_selected(-1); | ||
360 | |||
361 | if ( ev.key.keysym.scancode == SDL_SCANCODE_S) { /* export locally */ | ||
362 | const char *homeDir = getenv("HOME"); | ||
363 | char savefile[512], date[32], confdump[512]; | ||
364 | time_t t = time(NULL); | ||
365 | struct tm *tmp = localtime(&t); | ||
366 | int fd; | ||
367 | size_t len; | ||
368 | |||
369 | if (!homeDir) { | ||
370 | struct passwd* pwd = getpwuid(getuid()); | ||
371 | if (pwd) | ||
372 | homeDir = (const char*)pwd->pw_dir; | ||
373 | } | ||
374 | strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", tmp); | ||
375 | snprintf( savefile, sizeof(savefile), "%s/Laserharfe-%s.cfg", homeDir, date); | ||
376 | fd = open(savefile, O_WRONLY | O_CREAT | O_TRUNC, 0644); | ||
377 | |||
378 | len = config_dumpglobals( confdump, sizeof(confdump)); | ||
379 | write(fd, confdump, len ); | ||
380 | for (i=0; i<g_string_count; ++i) { | ||
381 | len = config_dumpstring(i, confdump, sizeof(confdump)); | ||
382 | write(fd, confdump, len ); | ||
383 | } | ||
384 | close(fd); | ||
385 | } | ||
386 | if (ev.key.keysym.scancode == SDL_SCANCODE_W) { | ||
387 | fprintf( stderr, "write remote config\n" ); | ||
388 | write(g_harfe_fd, "W\n", 2); | ||
389 | } | ||
390 | if (ev.key.keysym.scancode == SDL_SCANCODE_I) { | ||
391 | fprintf( stderr, "dump config\n" ); | ||
392 | config_reset(); | ||
393 | g_importing_config = 1; | ||
394 | write(g_harfe_fd, "I\n", 2); | ||
395 | } | ||
396 | if (ev.key.keysym.scancode == SDL_SCANCODE_Q) | ||
397 | config_reset(); | ||
398 | if (ev.key.keysym.scancode == SDL_SCANCODE_L) | ||
399 | config_parse("config_midi"); | ||
400 | if (ev.key.keysym.scancode == SDL_SCANCODE_Y) { | ||
401 | for (i=0; i<g_string_count/2; ++i) { | ||
402 | LLine temp = g_string_conf[i].line; | ||
403 | g_string_conf[i].line = g_string_conf[g_string_count-i-1].line; | ||
404 | g_string_conf[g_string_count-i-1].line = temp; | ||
405 | } | ||
406 | g_config_source = source_edit; | ||
407 | } | ||
408 | if (ev.key.keysym.scancode == SDL_SCANCODE_X) { | ||
409 | g_midi_three_octave_split_inverse ^= 1; | ||
410 | g_config_source = source_edit; | ||
266 | } | 411 | } |
267 | if( ev.key.keysym.scancode == SDL_SCANCODE_D) { | 412 | #ifdef CALIB_DEBUG |
268 | fprintf( stderr, "Dumping\n" ); | 413 | if ( ev.key.keysym.scancode == SDL_SCANCODE_SPACE) |
269 | write(g_harfe_fd, "D\n", 2); | 414 | if (g_calibration_running) |
415 | calib_next(10); | ||
416 | #endif | ||
417 | if ( ev.key.keysym.scancode == SDL_SCANCODE_C) { | ||
418 | if (g_calibration_running) | ||
419 | calib_fetch(); | ||
420 | else | ||
421 | calib_init(); | ||
422 | g_calibration_running = 1 - g_calibration_running; | ||
270 | } | 423 | } |
271 | if( ev.key.keysym.scancode == SDL_SCANCODE_C) { | 424 | if ( ev.key.keysym.scancode == SDL_SCANCODE_E) { |
272 | char confdump[512]; | 425 | char confdump[512]; |
273 | config_dumpglobals( confdump, sizeof(confdump)); | 426 | if (!g_harfe_connected) { |
274 | fputs( confdump, stderr); | 427 | display_messagebox( "Not connected", "Can't write config if Harfe is not connected."); |
428 | break; | ||
429 | } | ||
430 | if ((int)g_config_source < 2) { | ||
431 | display_messagebox( "No changes", "Config is unchanged. Won't write config to Harfe."); | ||
432 | break; | ||
433 | } | ||
434 | write(g_harfe_fd, "E\n", 2); | ||
435 | size_t len = config_dumpglobals( confdump, sizeof(confdump)); | ||
436 | write(g_harfe_fd, confdump, len ); | ||
275 | for (i=0; i<g_string_count; ++i) { | 437 | for (i=0; i<g_string_count; ++i) { |
276 | config_dumpstring(i, confdump, sizeof(confdump)); | 438 | len = config_dumpstring(i, confdump, sizeof(confdump)); |
277 | fputs( confdump, stderr); | 439 | write(g_harfe_fd, confdump, len ); |
278 | } | 440 | } |
441 | write(g_harfe_fd, "-- DONE\n", 8); /* End dump marker */ | ||
442 | write(g_harfe_fd, "W\n", 2); /* Remote write to SD */ | ||
443 | g_config_source = source_harfe; | ||
279 | } | 444 | } |
280 | if( ev.key.keysym.scancode == SDL_SCANCODE_M) { | 445 | if ( ev.key.keysym.scancode == SDL_SCANCODE_M) { |
281 | fprintf( stderr, "MIDIing on %d\n", g_harfe_fd ); | 446 | fprintf( stderr, "MIDIing on %d\n", g_harfe_fd ); |
282 | if (g_harfe_connected && (g_harfe_fd != -1)) | 447 | if (g_harfe_connected && (g_harfe_fd != -1)) |
283 | write(g_harfe_fd, "ME20020\nM824C00\n", 16); | 448 | write(g_harfe_fd, "ME20020\nM824C00\n", 16); |
@@ -285,20 +450,40 @@ main(int argc, char **argv) | |||
285 | break; | 450 | break; |
286 | case SDL_MOUSEBUTTONDOWN: | 451 | case SDL_MOUSEBUTTONDOWN: |
287 | /* | 452 | /* |
288 | if( ( g_last_mouse_event / 1000 ) != ( engine_now( ) / 1000 ) || ev.button.x != last_click_x || ev.button.y != last_click_y ) | 453 | if ( ( g_last_mouse_event / 1000 ) != ( engine_now( ) / 1000 ) || ev.button.x != last_click_x || ev.button.y != last_click_y ) |
289 | engine_process_mouse( ev.button.x, ev.button.y ); | 454 | engine_process_mouse( ev.button.x, ev.button.y ); |
290 | last_click_x = ev.button.x; | 455 | last_click_x = ev.button.x; |
291 | last_click_y = ev.button.y; | 456 | last_click_y = ev.button.y; |
292 | last_mouse_event = engine_now( ); | 457 | last_mouse_event = engine_now( ); |
293 | */ | 458 | */ |
459 | { | ||
460 | LPoint p = { display_scale_screen_to_harfe(ev.button.x), 768 - display_scale_screen_to_harfe(ev.button.y) }; | ||
461 | engine_handle_point(&p, now()); | ||
462 | } | ||
294 | break; | 463 | break; |
464 | case SDL_DROPFILE: { // In case if dropped file | ||
465 | char t[512]; | ||
466 | int ret; | ||
467 | snprintf( t, sizeof(t), "Do you want to import config file %s?\n", ev.drop.file); | ||
468 | if ((ret= display_messagebox_yesno("Import Laserharfe config", t))) | ||
469 | config_parse(ev.drop.file); | ||
470 | printf( "Dropped: %s (%d)\n", ev.drop.file, ret ); | ||
471 | break; | ||
472 | } | ||
473 | |||
295 | } | 474 | } |
475 | if (!g_calibration_running || !g_importing_config) | ||
476 | engine_checksilence(now()); | ||
296 | 477 | ||
297 | engine_checksilence(now()); | ||
298 | runtime = now(); | 478 | runtime = now(); |
299 | if (runtime - g_lastredraw > 30) { | 479 | if (runtime - g_lastredraw > 30 && !g_importing_config) { |
300 | g_lastredraw = runtime; | 480 | g_lastredraw = runtime; |
301 | engine_redraw(); | 481 | |
482 | if (!g_calibration_running) | ||
483 | engine_redraw(); | ||
484 | else | ||
485 | calib_redraw(); | ||
486 | |||
302 | } | 487 | } |
303 | if (runtime / 1000 - g_last_avg > 10) { | 488 | if (runtime / 1000 - g_last_avg > 10) { |
304 | printf("avg: %i\n", g_events / 10); | 489 | printf("avg: %i\n", g_events / 10); |
@@ -1,5 +1,6 @@ | |||
1 | #pragma once | 1 | #pragma once |
2 | #include <stdint.h> | 2 | #include <stdint.h> |
3 | #include "config.h" | ||
3 | 4 | ||
4 | #ifdef ARDUINO | 5 | #ifdef ARDUINO |
5 | #define NO_DISPLAY | 6 | #define NO_DISPLAY |
@@ -11,4 +12,11 @@ extern int g_width; | |||
11 | extern int g_height; | 12 | extern int g_height; |
12 | extern int g_harfe_connected; | 13 | extern int g_harfe_connected; |
13 | 14 | ||
15 | /* 0 unconfigured | ||
16 | 1 import from Harfe | ||
17 | 2 import from File | ||
18 | 3 modified locally | ||
19 | */ | ||
20 | extern ConfigSource g_config_source; | ||
21 | |||
14 | extern int g_harfe_fd; | 22 | extern int g_harfe_fd; |