FreeCalypso > hg > freecalypso-tools
diff ringtools/imy/convert.c @ 882:fd4c9bc7835d
fc-imy2pwt program written, compiles
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 03 Apr 2022 03:30:27 +0000 |
parents | |
children | 3e398f9c31a0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ringtools/imy/convert.c Sun Apr 03 03:30:27 2022 +0000 @@ -0,0 +1,276 @@ +/* + * This module implements the second pass of fc-imy2pwt processing: + * stepping through the captured melody and converting it to PWT. + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +extern char melody_str_buf[]; +extern unsigned tdma_durations[6][4]; +extern FILE *outF; + +static int cur_octave = 4; + +static char *pwt_note_names[12] = {"c", "cs", "d", "ds", "e", "f", "fs", + "g", "gs", "a", "as", "b"}; + +static void +process_octave_cmd(octchar) +{ + if (!isdigit(octchar)) { + fprintf(stderr, + "melody error: '*' octave prefix not followed by digit\n"); + exit(1); + } + cur_octave = octchar - '0'; +} + +static int +process_note(str, type) + char *str; +{ + int note, dur_basic, dur_mod; + + switch (*str) { + case 'c': + note = 0; + break; + case 'd': + note = 2; + break; + case 'e': + note = 4; + break; + case 'f': + note = 5; + break; + case 'g': + note = 7; + break; + case 'a': + note = 9; + break; + case 'b': + note = 11; + break; + default: + fprintf(stderr, + "melody error: note letter expected after '&' or '#'\n"); + exit(1); + } + switch (type) { + case 1: + if (note == 0 || note == 5) { + fprintf(stderr, "melody error: invalid flat note\n"); + exit(1); + } + note--; + break; + case 2: + if (note == 4 || note == 11) { + fprintf(stderr, "melody error: invalid sharp note\n"); + exit(1); + } + note++; + break; + } + if (str[1] < '0' || str[1] > '5') { + fprintf(stderr, + "melody error: missing expected note duration digit\n"); + exit(1); + } + dur_basic = str[1] - '0'; + switch (str[2]) { + case '.': + dur_mod = 1; + break; + case ':': + dur_mod = 2; + break; + case ';': + dur_mod = 3; + break; + default: + dur_mod = 0; + break; + } + fprintf(outF, "%s%d\t64\t%u\n", pwt_note_names[note], cur_octave + 1, + tdma_durations[dur_basic][dur_mod]); + if (dur_mod) + return 3; + else + return 2; +} + +static int +process_rest(str) + char *str; +{ + int dur_basic, dur_mod; + + if (str[1] < '0' || str[1] > '5') { + fprintf(stderr, + "melody error: missing expected rest duration digit\n"); + exit(1); + } + dur_basic = str[1] - '0'; + switch (str[2]) { + case '.': + dur_mod = 1; + break; + case ':': + dur_mod = 2; + break; + case ';': + dur_mod = 3; + break; + default: + dur_mod = 0; + break; + } + fprintf(outF, "rest\t\t%u\n", tdma_durations[dur_basic][dur_mod]); + if (dur_mod) + return 3; + else + return 2; +} + +melody_convert_pass() +{ + char *cp, *repeat_start_ptr; + int repeat_start_octave, repeat_count, rpt_set; + + repeat_start_ptr = 0; + for (cp = melody_str_buf; *cp; ) { + /* skip junk first */ + if (!strncmp(cp, "vibeon", 6)) { + cp += 6; + continue; + } + if (!strncmp(cp, "vibeoff", 7)) { + cp += 7; + continue; + } + if (!strncmp(cp, "ledon", 5)) { + cp += 5; + continue; + } + if (!strncmp(cp, "ledoff", 6)) { + cp += 6; + continue; + } + if (!strncmp(cp, "backon", 6)) { + cp += 6; + continue; + } + if (!strncmp(cp, "backoff", 7)) { + cp += 7; + continue; + } + /* real stuff */ + switch (*cp) { + case '*': + process_octave_cmd(cp[1]); + cp += 2; + continue; + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'a': + case 'b': + cp += process_note(cp, 0); + continue; + case '&': + cp++; + cp += process_note(cp, 1); + continue; + case '#': + cp++; + cp += process_note(cp, 2); + continue; + case 'r': + cp += process_rest(cp); + continue; + case 'V': + /* skip unimplemented volume control */ + cp++; + if (*cp == '+' || *cp == '-') { + cp++; + continue; + } + if (!isdigit(*cp)) { + fprintf(stderr, + "melody error: invalid character after 'V'\n"); + exit(1); + } + if (*cp == '1' && cp[1] >= '0' && cp[1] <= '5') + cp += 2; + else + cp++; + continue; + case '(': + if (repeat_start_ptr) { + fprintf(stderr, + "melody error: nested repeat\n"); + exit(1); + } + cp++; + repeat_start_ptr = cp; + repeat_start_octave = cur_octave; + repeat_count = 0; + continue; + case '@': + if (!repeat_start_ptr) { + fprintf(stderr, + "melody error: '@' not in repeat block\n"); + exit(1); + } + cp++; + if (!isdigit(*cp)) { + fprintf(stderr, + "melody error: '@' not followed by digit\n"); + exit(1); + } + rpt_set = *cp - '0'; + if (!rpt_set) { + fprintf(stderr, + "melody error: infinite repeat not supported\n"); + exit(1); + } + cp++; + if (!repeat_count) + repeat_count = rpt_set; + continue; + case ')': + if (!repeat_start_ptr) { + fprintf(stderr, + "melody error: ')' without opening '('\n"); + exit(1); + } + if (!repeat_count) { + fprintf(stderr, + "melody error: repeat block without count\n"); + exit(1); + } + repeat_count--; + if (repeat_count) { + cp = repeat_start_ptr; + cur_octave = repeat_start_octave; + } else { + cp++; + repeat_start_ptr = 0; + } + continue; + default: + fprintf(stderr, + "melody error: non-understood character\n"); + exit(1); + } + } +}