#include #include #include #include #include "main.h" #include "config.h" int g_midi_main_control = -1; int g_midi_main_channel = 0; int g_midi_two_octave_split = 50; int g_midi_three_octave_split_1 = 33; int g_midi_three_octave_split_2 = 66; int g_midi_three_octave_split_inverse = 0; int g_settled_timedelta = 10; int g_settled_dist = 5; int g_timetosilence = 30; int g_pitch_factor = 256*128; int g_pitchbend_delay = 500; int g_min_y = 0, g_max_y; int g_normalize_factor = 0; static int g_current_string; StringConfig g_string_conf[MAX_LINECOUNT]; int g_string_count; ConfigSource g_config_source = source_none; int g_importing_config; int g_calibration_running = 0; void config_reset() { //Reinitialise string config array memset(g_string_conf, 0, sizeof(g_string_conf)); g_min_y = 0; g_max_y = 1024; g_current_string = 0; g_midi_main_control = -1; g_midi_main_channel = 0; g_midi_two_octave_split = 50; g_midi_three_octave_split_1 = 33; g_midi_three_octave_split_2 = 66; g_midi_three_octave_split_inverse = 0; g_settled_dist = 5; g_timetosilence = 30; g_pitch_factor = 256*128; g_pitchbend_delay = 500; g_config_source = source_none; } static char *midi_note[] = { "C-1", "C#-1", "D-1", "D#-1", "E-1", "F-1", "F#-1", "G-1", "G#-1", "A-1", "A#-1", "B-1", "C0", "C#0", "D0", "D#0", "E0", "F0", "F#0", "G0", "G#0", "A0", "A#0", "B0", "C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", "G#1", "A1", "A#1", "B1", "C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2", "C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3", "C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4", "C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5", "C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6", "C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", "G#7", "A7", "A#7", "B7", "C8", "C#8", "D8", "D#8", "E8", "F8", "F#8", "G8", "G#8", "A8", "A#8", "B8", "C9", "C#9", "D9", "D#9", "E9", "F9", "F#9", "G9", "G#9", "A9", "A#9", "B9" }; static char *modifier_names[] = { "none", "pitch_bend_up", "pitch_bend_down", "midi_control", "midi_control_inverse" }; static char *mode_names[] = { "midi_one_octave", "midi_two_octaves", "midi_three_octaves", "midi_control", "midi_control_inverse" }; enum { KEYWORD_STRINGS, KEYWORD_STRING, KEYWORD_LINE, KEYWORD_LINEARIZE, KEYWORD_PITCHBEND_DELAY, KEYWORD_MODE, KEYWORD_MODE_ONE_OCTAVE, KEYWORD_MODE_TWO_OCTAVES, KEYWORD_MODE_THREE_OCTAVES, KEYWORD_MODE_CONTROL, KEYWORD_MODE_CONTROL_INVERSE, KEYWORD_CHANNEL, KEYWORD_NOTE, KEYWORD_AFTERTOUCH, KEYWORD_NONE, KEYWORD_PITCH_BEND_UP, KEYWORD_PITCH_BEND_DOWN, KEYWORD_MIDI_CONTROL, KEYWORD_MIDI_CONTROL_INVERSE, KEYWORD_CONTROLLER, KEYWORD_TIMETOSILENCE, KEYWORD_PITCHFACTOR, KEYWORD_TWOOCTAVESPLIT, KEYWORD_THREEOCTAVESPLIT_1, KEYWORD_THREEOCTAVESPLIT_2, KEYWORD_MIDI_MAIN_CONTROL, KEYWORD_MIDI_MAIN_CHANNEL, KEYWORD_SETTLED_DIST }; typedef struct { int id; char *name; } keyword; static keyword keywords[] = { {KEYWORD_STRINGS, "Strings"}, {KEYWORD_STRING, "String"}, {KEYWORD_LINE, "Line"}, {KEYWORD_LINEARIZE, "LineSquareFactor"}, {KEYWORD_PITCHBEND_DELAY, "PitchBendDelay"}, {KEYWORD_MODE, "Mode"}, {KEYWORD_MODE_ONE_OCTAVE, "midi_one_octave"}, {KEYWORD_MODE_TWO_OCTAVES, "midi_two_octaves"}, {KEYWORD_MODE_THREE_OCTAVES, "midi_three_octaves"}, {KEYWORD_MODE_CONTROL, "midi_control"}, {KEYWORD_MODE_CONTROL_INVERSE, "midi_control_inverse"}, {KEYWORD_CHANNEL, "Channel"}, {KEYWORD_NOTE, "Note"}, {KEYWORD_AFTERTOUCH, "AfterTouch"}, {KEYWORD_NONE, "none"}, {KEYWORD_PITCH_BEND_UP, "pitch_bend_up"}, {KEYWORD_PITCH_BEND_DOWN, "pitch_bend_down"}, {KEYWORD_MIDI_CONTROL, "midi_control"}, {KEYWORD_MIDI_CONTROL_INVERSE, "midi_control_inverse"}, {KEYWORD_CONTROLLER, "Controller"}, {KEYWORD_TIMETOSILENCE, "TimeToSilence"}, {KEYWORD_PITCHFACTOR, "PitchFactor"}, {KEYWORD_TWOOCTAVESPLIT, "midi_two_octave_split"}, {KEYWORD_THREEOCTAVESPLIT_1, "midi_three_octave_split_1"}, {KEYWORD_THREEOCTAVESPLIT_2, "midi_three_octave_split_2"}, {KEYWORD_MIDI_MAIN_CONTROL, "midi_main_control"}, {KEYWORD_MIDI_MAIN_CHANNEL, "midi_main_channel"}, {-1, 0} }; static int config_findkeyword(char **line) { char *_l = *line; int i; while (isspace(*_l)) ++_l; for (i = 0; keywords[i].name; ++i) { size_t kl = strlen(keywords[i].name); if (!strncasecmp(_l, keywords[i].name, kl)) { if (!isspace(_l[kl]) && _l[kl]) continue; _l += strlen(keywords[i].name); /* Skip rest of white spaces */ while (isspace(*_l)) ++_l; *line = _l; return keywords[i].id; } } return -1; } static uint8_t config_midi_note_from_string(char *string) { int i; for (i = 0; i < sizeof(midi_note) / sizeof(*midi_note); ++i) if (!strncasecmp(string, midi_note[i], strlen(midi_note[i]))) return i; return 0xff; } char * config_midi_note_to_string(int string) { return midi_note[string]; } int config_handle_line(char *line) { StringConfig *sc = g_string_conf + g_current_string; int split_done = 0; char *_line = line; /* Skip leading spaces */ while (isspace(*line)) ++line; if (*line == 0 || *line == '#' || *line == '\n') return 0; switch (config_findkeyword(&line)) { case KEYWORD_STRINGS: g_string_count = atol(line); if (!g_string_count || g_string_count > MAX_LINECOUNT) { harfe_error(stderr, "Incorrect number of strings: %s\n", _line); return -1; } harfe_debug("GLOBAL: Configuring expected lines %d\n", g_string_count); break; case KEYWORD_STRING: g_current_string = atol(line) - 1; harfe_debug("Switching to string: %d\n", g_current_string + 1); if (g_current_string < 0 || g_current_string > g_string_count) { harfe_error(stderr, "Incorrect string selected: %s\n", _line); return -1; } break; case KEYWORD_LINEARIZE: g_normalize_factor = atol(line); break; case KEYWORD_PITCHBEND_DELAY: g_pitchbend_delay = atol(line); break; case KEYWORD_LINE: { LLine *l = &sc->line; if (sscanf(line, "%d %d %d %d", &l->p0.x, &l->p0.y, &l->p1.x, &l->p1.y) != 4) { harfe_error(stderr, "Incorrect Line statement for string\n"); return -1; } if (l->p0.y > l->p1.y) { LPoint tmp = l->p0; l->p0 = l->p1; l->p1 = tmp; } if (l->p0.y > g_min_y) g_min_y = l->p0.y; if (l->p0.y < g_max_y) g_max_y = l->p1.y; break; } case KEYWORD_MODE: switch (config_findkeyword(&line)) { case KEYWORD_MODE_ONE_OCTAVE: sc->mode = midi_one_octave; harfe_debug("String %d is midi_one_octave\n", 1 + g_current_string); break; case KEYWORD_MODE_TWO_OCTAVES: sc->mode = midi_two_octaves; harfe_debug("String %d is midi_two_octaves\n", 1 + g_current_string); break; case KEYWORD_MODE_THREE_OCTAVES: sc->mode = midi_three_octaves; harfe_debug("String %d is midi_three_octaves\n", 1 + g_current_string); break; case KEYWORD_MODE_CONTROL: sc->mode = midi_control; harfe_debug("String %d is midi_control\n", 1 + g_current_string); break; case KEYWORD_MODE_CONTROL_INVERSE: sc->mode = midi_control_inv; harfe_debug("String %d is midi_control_inverse\n", 1 + g_current_string); break; default: harfe_error(stderr, "Illegal Mode for string: %s\n", _line); return -1; } break; case KEYWORD_CHANNEL: sc->channel = atol(line); if (sc->channel > 16) { harfe_error(stderr, "Incorrect channel specified: %s.\n", _line); return -1; } harfe_debug("String %d is on channel %d\n", 1 + g_current_string, sc->channel); break; case KEYWORD_NOTE: sc->note = config_midi_note_from_string(line); if (sc->note == 0xff) { harfe_error(stderr, "Unknown midi note specified: %s.\n", _line); return -1; } harfe_debug("String %d is midi note %d\n", 1 + g_current_string, sc->note); break; case KEYWORD_AFTERTOUCH: switch (config_findkeyword(&line)) { case KEYWORD_NONE: sc->modifier = none; harfe_debug("String %d does not act aftertouch\n", 1 + g_current_string); break; case KEYWORD_PITCH_BEND_UP: sc->modifier = pitch_bend_up; harfe_debug("String %d acts aftertouch as pitch_bend_up\n", 1 + g_current_string); break; case KEYWORD_PITCH_BEND_DOWN: sc->modifier = pitch_bend_down; harfe_debug("String %d acts aftertouch as pitch_bend_down\n", 1 + g_current_string); break; case KEYWORD_MIDI_CONTROL: sc->modifier = midi_controller; harfe_debug("String %d acts aftertouch as midi_controller\n", 1 + g_current_string); break; case KEYWORD_MIDI_CONTROL_INVERSE: sc->modifier = midi_controller_inv; harfe_debug("String %d acts aftertouch as midi_controller_inverse\n", 1 + g_current_string); break; default: harfe_error(stderr, "Illegal Modifier for string: %s\n", _line); return -1; } break; case KEYWORD_PITCHFACTOR: sc->pitch_factor = atol(line); harfe_debug("String %d is given a custom pitch factor of %d\n", 1 + g_current_string, sc->pitch_factor); break; case KEYWORD_CONTROLLER: sc->controller = atol(line); harfe_debug("String %d is on midi_controller line %d\n", 1 + g_current_string, sc->controller); break; case KEYWORD_TIMETOSILENCE: sc->timetosilence = atol(line); harfe_debug("String %d has a timetosilence of %d\n", 1 + g_current_string, sc->timetosilence); break; case KEYWORD_TWOOCTAVESPLIT: g_midi_two_octave_split = atol(line); harfe_debug("Splitting TWO octaves at %d%%\n", g_midi_two_octave_split); if (g_midi_two_octave_split < 0 || g_midi_two_octave_split > 100) { harfe_error(stderr, "Invalid percentage in line: %s\n", _line); exit(1); } break; case KEYWORD_THREEOCTAVESPLIT_1: g_midi_three_octave_split_1 = atol(line); harfe_debug("Splitting THREE octaves top above %d%%\n", g_midi_three_octave_split_1); if (g_midi_three_octave_split_1 < 0 || g_midi_three_octave_split_1 > 100) { harfe_error(stderr, "Invalid percentage in line: %s\n", _line); exit(1); } split_done = 1; break; case KEYWORD_THREEOCTAVESPLIT_2: g_midi_three_octave_split_2 = atol(line); harfe_debug("Splitting THREE octaves bottom below %d%%\n", g_midi_three_octave_split_2); if (g_midi_three_octave_split_2 < 0 || g_midi_three_octave_split_2 > 100) { harfe_error(stderr, "Invalid percentage in line: %s\n", _line); return -1; } split_done = 1; break; case KEYWORD_MIDI_MAIN_CONTROL: g_midi_main_control = atol(line); harfe_debug("All Strings modify controller %d\n", g_midi_main_control); if (g_midi_main_control > 127) { harfe_error(stderr, "Invalid controller number %d in line: %s\n", g_midi_main_control, _line); return -1; } break; case KEYWORD_MIDI_MAIN_CHANNEL: g_midi_main_channel = atol(line); harfe_debug("All Strings modify controller %d on channel %d\n", g_midi_main_control, g_midi_main_channel); if (g_midi_main_channel < 1 || g_midi_main_channel > 16) { harfe_error(stderr, "Invalid channel number %d in line: %s\n", g_midi_main_channel, _line); return -1; } break; case KEYWORD_SETTLED_DIST: g_settled_dist = atol(line); harfe_debug("All AfterTouch events take place only after movement has slown down to %d points\n", g_settled_dist); break; default: harfe_error(stderr, "Unhandled config line: %s\n", _line); return -1; } if (!split_done) return 0; /* split also true for two octaves */ if (g_midi_three_octave_split_2 < g_midi_three_octave_split_1) { g_midi_three_octave_split_inverse = g_midi_three_octave_split_1; g_midi_three_octave_split_1 = g_midi_three_octave_split_2; g_midi_three_octave_split_2 = g_midi_three_octave_split_inverse; g_midi_three_octave_split_inverse = 1; } else g_midi_three_octave_split_inverse = 0; return 0; } size_t config_dumpglobals(char *out, size_t outsize) { int tos1 = g_midi_three_octave_split_inverse ? g_midi_three_octave_split_2 : g_midi_three_octave_split_1; int tos2 = g_midi_three_octave_split_inverse ? g_midi_three_octave_split_1 : g_midi_three_octave_split_2; size_t off = snprintf(out, outsize, "Strings %d\n\nmidi_two_octave_split %d\nmidi_three_octave_split_1 %d\nmidi_three_octave_split_2 %d\n", g_string_count, g_midi_two_octave_split, tos1, tos2 ); if (g_midi_main_control >= 0) off += snprintf(out + off, outsize - off, "midi_main_control %d\n\n", g_midi_main_control); if (g_midi_main_channel > 0) off += snprintf(out + off, outsize - off, "midi_main_channel %d\n\n", g_midi_main_channel); off += snprintf(out + off, outsize - off, "LineSquareFactor %d\n\n", g_normalize_factor); off += snprintf(out + off, outsize - off, "PitchBendDelay %d\n\n", g_pitchbend_delay); if (g_settled_dist != 5) off += snprintf(out + off, outsize - off, "SettledDist %d\n\n", g_settled_dist); off += snprintf(out + off, outsize - off, "\n" ); return off; } size_t config_dumpstring(int string, char *out, size_t outsize) { StringConfig *s = g_string_conf + string; if (string < 0 || string > g_string_count || !out) { if (out && outsize) *out = 0; return 0; } size_t off = snprintf(out, outsize, "String %d\n Line %d %d %d %d\n Mode %s\n Channel %d\n Note %s\n AfterTouch %s\n Controller %d\n", string + 1, s->line.p0.x, s->line.p0.y, s->line.p1.x, s->line.p1.y, mode_names[s->mode], s->channel, midi_note[s->note], modifier_names[s->modifier], s->controller ); if (s->timetosilence) off += snprintf(out + off, outsize - off, " TimeToSilence %d\n", s->timetosilence); if (s->pitch_factor) off += snprintf(out + off, outsize - off, " PitchFactor %d\n", s->pitch_factor); off += snprintf(out + off, outsize - off, "\n" ); return off; } void config_reverse_strings() { int i; for (i=0; i