summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--arduino/Laserharfe/Laserharfe.ino105
-rw-r--r--config.c69
-rw-r--r--config.h27
-rw-r--r--display.c88
-rw-r--r--display.h9
-rw-r--r--engine.c172
-rw-r--r--engine.h6
-rw-r--r--geometry.c31
-rw-r--r--geometry.h18
-rw-r--r--main-sdl.c245
-rw-r--r--main.h8
12 files changed, 604 insertions, 178 deletions
diff --git a/Makefile b/Makefile
index b41215a..622150b 100644
--- a/Makefile
+++ b/Makefile
@@ -3,8 +3,8 @@ all: main
3GenBkBasB.c: GenBkBasB.ttf 3GenBkBasB.c: GenBkBasB.ttf
4 xxd -i $< $@ 4 xxd -i $< $@
5 5
6main: main-sdl.c display.c config.c display.h config.h engine.c engine.h midi-sdl.c midi.h GenBkBasB.c GenBkBasB.h 6main: 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
10clean: 10clean:
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
17int led = 13; 9int led = 13;
10int g_reading_config = 0;
11int g_writing_config = 0;
12ConfigSource g_config_source = source_none;
13//Sd2Card card;
18 14
19enum { 15enum {
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
25uint32_t now() { 21uint32_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
87static void setup_cam() { 83static 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
130void 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
149void 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
132void setup() { 158void 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
229void midi_playnote(int channel, int note, int octave_offset ) { 255void 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
249void handle_configure(char *command) { 275void 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
253void 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
281void handle_serial() { 336void 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
diff --git a/config.c b/config.c
index fb8a6fa..e373727 100644
--- a/config.c
+++ b/config.c
@@ -8,9 +8,9 @@
8 8
9int g_midi_main_control = -1; 9int g_midi_main_control = -1;
10int g_midi_main_channel = 0; 10int g_midi_main_channel = 0;
11int g_midi_two_octave_split = 256 / 2; 11int g_midi_two_octave_split = 50;
12int g_midi_three_octave_split_1 = 256 / 3; 12int g_midi_three_octave_split_1 = 33;
13int g_midi_three_octave_split_2 = 512 / 3; 13int g_midi_three_octave_split_2 = 66;
14int g_midi_three_octave_split_inverse = 0; 14int g_midi_three_octave_split_inverse = 0;
15int g_settled_dist = 5; 15int g_settled_dist = 5;
16int g_timetosilence = 30; 16int 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
380void 375size_t
381config_dumpglobals(char *out, size_t outsize) 376config_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
396void 400size_t
397config_dumpstring(int string, char *out, size_t outsize) 401config_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}
diff --git a/config.h b/config.h
index d7399fa..64f7689 100644
--- a/config.h
+++ b/config.h
@@ -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
7extern int g_min_y, g_max_y; 9extern 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
40typedef struct { 42typedef 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
45typedef struct { 51typedef 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
49typedef struct { 58typedef struct {
50 StringMode mode; 59 StringMode mode;
@@ -70,6 +79,6 @@ extern StringConfig g_string_conf[MAX_LINECOUNT];
70extern int g_string_count; 79extern int g_string_count;
71void config_reset(); 80void config_reset();
72int config_handle_line( char *line); 81int config_handle_line( char *line);
73void config_dumpglobals(char *out, size_t outsize); 82size_t config_dumpglobals(char *out, size_t outsize);
74void config_dumpstring(int string, char *out, size_t outsize); 83size_t config_dumpstring(int string, char *out, size_t outsize);
75char *config_midi_note_to_string(int string); 84char *config_midi_note_to_string(int string);
diff --git a/display.c b/display.c
index 42235a2..4263e52 100644
--- a/display.c
+++ b/display.c
@@ -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))
9enum { FONT_SIZE = 28 };
9 10
10static SDL_Window *screen; 11static SDL_Window *screen;
11static SDL_Renderer *renderer; 12static SDL_Renderer *renderer;
12static int g_width, g_height; 13static int g_screen_width, g_screen_height;
14static int g_harfe_width, g_harfe_height;
15double g_scale_factor;
13static TTF_Font *font = NULL; 16static TTF_Font *font = NULL;
14 17
15void 18void
16display_init(int width, int height) 19display_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
51void
52display_getdimensions(int *width, int *height, int *fontsize)
53{
54 *width = g_screen_width;
55 *height = g_screen_height;
56 *fontsize = FONT_SIZE;
57}
58
59int
60display_scale_harfe_to_screen(int coord)
61{
62 return (int)((double)coord / g_scale_factor);
63}
64
65int
66display_scale_screen_to_harfe(int coord)
67{
68 return (int)((double)coord * g_scale_factor);
39} 69}
40 70
41void 71void
@@ -48,19 +78,23 @@ display_clear()
48void 78void
49display_circle(int x, int y, int w) 79display_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
55void 86void
56display_circle_color(int x, int y, int w, int color) 87display_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
61void 93void
62display_line(int x0, int y0, int x1, int y1) 94display_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)
68void 102void
69display_line_color(int x0, int y0, int x1, int y1, int color) 103display_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
75void 111void
112display_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
123void
76display_redraw() 124display_redraw()
77{ 125{
78 SDL_RenderPresent(renderer); 126 SDL_RenderPresent(renderer);
@@ -81,6 +129,7 @@ display_redraw()
81void 129void
82display_text(char *text, int x, int y, int color) 130display_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
158void
159display_messagebox(char *title, char *info) {
160 SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_INFORMATION, title, info, screen);
161}
162
163int
164display_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
109int 177int
110display_test_menu_click(int y, int max_pos) 178display_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;
diff --git a/display.h b/display.h
index adc08b7..c7003fd 100644
--- a/display.h
+++ b/display.h
@@ -1,6 +1,9 @@
1#pragma once 1#pragma once
2 2
3void display_init(int width, int height); 3void display_init(int screen_width, int screen_height, int harfe_width, int harfe_height);
4void display_getdimensions(int *width, int *height, int *fontsize);
5int display_scale_harfe_to_screen(int coord);
6int display_scale_screen_to_harfe(int coord);
4void display_redraw(); 7void display_redraw();
5 8
6void display_clear(); 9void display_clear();
@@ -8,10 +11,12 @@ void display_line(int x0, int y0, int x1, int y1);
8void display_line_color(int x0, int y0, int x1, int y1, int color); 11void display_line_color(int x0, int y0, int x1, int y1, int color);
9void display_circle(int x, int y, int w); 12void display_circle(int x, int y, int w);
10void display_circle_color(int x, int y, int w, int color); 13void display_circle_color(int x, int y, int w, int color);
11void display_rectangle(int x, int y, int w, int h); 14void display_rect_color(int x, int y, int width, int height, int color);
12 15
13void display_text(char *text, int x, int y, int color); 16void display_text(char *text, int x, int y, int color);
14void display_textbox(int min_x, int pos, int max_x, int max_pos, char *text, int color); 17void display_textbox(int min_x, int pos, int max_x, int max_pos, char *text, int color);
15int display_test_menu_click(int y, int max_pos); 18int display_test_menu_click(int y, int max_pos);
19void display_messagebox(char *title, char *info);
20int display_messagebox_yesno(char *title, char *info);
16 21
17void display_report(char *message, int line); 22void display_report(char *message, int line);
diff --git a/engine.c b/engine.c
index 0d92b50..43892fb 100644
--- a/engine.c
+++ b/engine.c
@@ -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
14static LPoint g_render_points[1024]; 15static LPoint g_render_points[1024];
15static int g_render_point_count; 16static int g_render_point_count;
16static const int g_harfe_width = 1024; 17static ConfigSelect g_selected_config;
17static const int g_harfe_height = 768; 18static void highlight_line(int value, int y, int max_x, uint32_t color);
18static int g_factor = 1<<16;
19 19
20static 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
24void 22void
25engine_redraw() 23engine_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); 94static void
53 display_line_color(0, scale(g_max_y), g_width, scale(g_max_y), 0xff00ffff); 95highlight_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
67void 106void
68engine_init() { 107engine_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
76static int 111ConfigSelect
77dist_pp(int x0, int y0, int x1, int y1) 112engine_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)
85static int
86dist_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); 138void
93 return (int)( q1 * q1 * ((y0 - y1) * (y0 - y1) + (x1 - x0) * (x1 - x0)) * 256 / (r * r)); 139engine_init() {
94} 140}
95 141
96static int
97dist_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
102void 143void
103engine_handle_point(LPoint * p, uint32_t monotime) 144engine_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
diff --git a/engine.h b/engine.h
index 3b59e86..2d47dc7 100644
--- a/engine.h
+++ b/engine.h
@@ -1,6 +1,12 @@
1#pragma once 1#pragma once
2 2
3#include "config.h"
4
3void engine_init(); 5void engine_init();
4void engine_redraw(); 6void engine_redraw();
5void engine_handle_point(LPoint * p, uint32_t monotime); 7void engine_handle_point(LPoint * p, uint32_t monotime);
6void engine_checksilence(uint32_t monotime); 8void engine_checksilence(uint32_t monotime);
9void engine_select_config(ConfigSelect sel);
10ConfigSelect engine_change_selected(int off);
11
12extern 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)
6static inline int
7impl_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
17int
18dist_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
23static inline int
24impl_dist_pp(int x0, int y0, int x1, int y1 ) {
25 return (y0-y1)*(y0-y1)+(x0-x1)*(x0-x1);
26}
27
28int
29dist_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
3typedef struct {
4 int x;
5 int y;
6} LPoint;
7
8typedef 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)
16int dist_pl(LPoint const * p, LLine const * l, int * offs);
17int dist_pp(LPoint const * p0, LPoint const * p1);
18
diff --git a/main-sdl.c b/main-sdl.c
index 687e5c7..6bc3970 100644
--- a/main-sdl.c
+++ b/main-sdl.c
@@ -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; 26enum {
25const 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
27int g_harfe_connected = 0; 33int g_harfe_connected = 0;
28int g_harfe_fd = -1; 34int g_harfe_fd = -1;
35int g_importing_config = 0;
36ConfigSource g_config_source = source_none;
37int g_calibration_running = 0;
29 38
30static char * 39static char *
31find_harfe() 40find_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;
180printf( "%s\n", text ); 196printf( "%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
262static void
263calib_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
231int 291int
@@ -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);
diff --git a/main.h b/main.h
index 7d87f99..38fe4ff 100644
--- a/main.h
+++ b/main.h
@@ -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;
11extern int g_height; 12extern int g_height;
12extern int g_harfe_connected; 13extern int g_harfe_connected;
13 14
15/* 0 unconfigured
16 1 import from Harfe
17 2 import from File
18 3 modified locally
19*/
20extern ConfigSource g_config_source;
21
14extern int g_harfe_fd; 22extern int g_harfe_fd;