diff options
| author | erdgeist <erdgeist@bauklotz.fritz.box> | 2017-04-08 14:21:36 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@bauklotz.fritz.box> | 2017-04-08 14:21:36 +0200 |
| commit | f2683a4b707cd714b7f540ebf6482563df83d51e (patch) | |
| tree | de4941add99f0eb1642aa57c6af180b4ee70119a | |
| parent | 78d309a97b782bd6ab2716fa7595bb3f409479e3 (diff) | |
Near complete rewrite.
| -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; |
