/* * maestropond.c * * Convert Acorn Maestro files to LilyPond files * * (c) 2011 Thomas White * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include struct music { unsigned int n_staves; unsigned int n_perc; unsigned int n_gates; unsigned int lengths[8]; unsigned char *gates; unsigned char *notes[8]; }; static const int bpm[] = { 40, 50, 60, 65, 70, 80, 90, 100, 115, 130, 145, 160, 175, 190, 210 }; static void show_syntax(const char *s) { printf("Syntax: %s [options]\n", s); } static void show_help(const char *s) { show_syntax(s); printf( "\nConvert Acorn Maestro files to LilyPond files.\n" "\n" " -h, --help Display this help message.\n" "\n" ); } static unsigned int get_basic_int(unsigned char *f, size_t *pptr) { unsigned int v; size_t ptr = *pptr; int sig; v = 0; sig = f[ptr++]; if ( sig != 0x40 ) { fprintf(stderr, "Not a BASIC integer (sig %i, val %i)\n", sig, v); goto out; } v += f[ptr++] << 24; v += f[ptr++] << 16; v += f[ptr++] << 8; v += f[ptr++]; out: *pptr = ptr; return v; } static void music_attribute(unsigned char ma, int save, FILE *ofh) { if ( (ma & 0x7f) == 0x40 ) { printf("Warning: reserved gate type.\n"); } else if ( (ma & 0x3f) == 0x20 ) { fprintf(ofh, "|\n ");; } else if ( (ma & 0x1f) == 0x10 ) { printf("Octave shift\n"); } else if ( (ma & 0xf) == 0x8 ) { int st; st = 1 + ((ma & 0xc0) >> 6); if ( ma & 0x10 ) { printf("Slur on (stave %i)\n", st); } else { printf("Slur off (stave %i)\n", st); } } else if ( (ma & 0x7) == 0x4 ) { int ct, st; ct = (ma & 0x18) >> 3; switch ( ct ) { case 0 : fprintf(ofh, "\\clef \"treble\"\n"); break; case 1 : fprintf(ofh, "\\clef \"treble\"\n"); break; case 2 : fprintf(ofh, "\\clef \"treble\"\n"); break; case 3 : fprintf(ofh, "\\clef \"treble\"\n"); break; } st = (ma & 0x60) >> 5; printf(" stave %i\n", st); } else if ( (ma & 0x3) == 0x2 ) { } else if ( (ma & 0x1) == 0x1 ) { int tn, td; tn = 1 + ((ma & 0x1e) >> 1); td = 1 + ((ma & 0xe0) >> 5); fprintf(ofh, "\\time %i/%i\n", tn, td); } } static const char *note_letter(int pos, int acc) { switch ( pos ) { case 0 : return "a"; case 1 : return "b"; case 2 : return "c"; case 4 : return "d"; case 5 : return "e"; case 6 : return "f"; case 7 : return "g"; case 8 : return "a'"; case 9 : return "b'"; case 10 : return "c'"; case 11 : return "d'"; case 12 : return "e'"; case 13 : return "f'"; case 14 : return "g'"; case 15 : return "a''"; case 16 : return "b''"; case 17 : return "c''"; case 18 : return "d''"; case 19 : return "e''"; case 20 : return "f''"; case 21 : return "g''"; case 22 : return "a'''"; case 23 : return "b'''"; case 24 : return "c'''"; case 25 : return "d'''"; case 26 : return "e'''"; case 27 : return "f'''"; case 28 : return "g'''"; case 29 : return "a''''"; case 30 : return "b''''"; case 31 : return "c''''"; } return "?"; } static void get_note(unsigned char **notes, int *nptrs, int ch, FILE *ofh) { unsigned char n1, n2; int rest = 0; n1 = notes[ch][nptrs[ch]++]; if ( n1 & 0xf8 ) { n2 = notes[ch][nptrs[ch]++]; } else { rest = 1; } if ( rest ) { printf(" %i", n1); } else { int pos, acc, len; pos = (n1 & 0xf8) >> 3; acc = n2 & 0x07; len = (n2 & 0xe0) >> 5; fprintf(ofh, "%s%i ", note_letter(pos, acc), (int)pow(2, len)); } } static void interpret_gates(struct music *mus, int stave, int ch, FILE *ofh) { unsigned int i; int ma = 0; int nptrs[8]; for ( i=0; i<8; i++ ) nptrs[i] = 0; fprintf(ofh, "{\n "); printf("%i gates\n", mus->n_gates); for ( i=0; in_gates; i++ ) { if ( ma ) { music_attribute(mus->gates[i], stave, ofh); ma = 0; continue; } if ( mus->gates[i] == 0 ) { ma = 1; continue; } else { if ( mus->gates[i] & 1<notes, nptrs, ch, ofh); } } } fprintf(ofh, "\n}\n"); } static size_t read_music_data(unsigned char *f, size_t ptr, size_t len, struct music *mus) { unsigned int i; mus->n_gates = get_basic_int(f, &ptr); for ( i=0; i<8; i++ ) { mus->lengths[i] = get_basic_int(f, &ptr); printf("Channel %i, length %i\n", i+1, mus->lengths[i]); } mus->gates = malloc(mus->n_gates); if ( mus->gates == NULL ) { fprintf(stderr, "Failed to allocate gates\n"); } for ( i=0; in_gates; i++ ) { mus->gates[i] = f[ptr++]; } for ( i=0; i<8; i++ ) { unsigned int j; mus->notes[i] = malloc(mus->lengths[i]); if ( mus->notes[i] == NULL ) { fprintf(stderr, "Failed to allocate notes\n"); } for ( j=0; jlengths[i]; j++ ) { mus->notes[i][j] = f[ptr++]; } } return ptr; } static size_t process_stave_data(unsigned char *f, size_t ptr, size_t len, struct music *mus) { mus->n_staves = 1 + f[ptr++]; mus->n_perc = f[ptr++]; printf("%i staves, %i percussion\n", mus->n_staves, mus->n_perc); return ptr; } static size_t process_instrument_data(unsigned char *f, size_t ptr, size_t len, struct music *mus) { int i; for ( i=0; i<8; i++ ) { int ch, v; ch = f[ptr++]; v = f[ptr++]; //printf("Channel %i, voice %i\n", ch+1, v); } return ptr; } static size_t process_volume_data(unsigned char *f, size_t ptr, size_t len, struct music *mus) { int i; for ( i=0; i<8; i++ ) { int v; v = f[ptr++]; //printf("Channel %i, volume %i\n", i+1, v); } return ptr; } static size_t process_stereo_data(unsigned char *f, size_t ptr, size_t len, struct music *mus) { int i; for ( i=0; i<8; i++ ) { int st; st = f[ptr++]; //printf("Channel %i, stereo %i\n", i+1, st); } return ptr; } static size_t process_tempo_data(unsigned char *f, size_t ptr, size_t len, struct music *mus) { int tempo; tempo = f[ptr++]; printf("Tempo = %i bpm\n", bpm[tempo]); return ptr; } static void convert_file(const char *filename) { struct stat statbuf; FILE *fh; FILE *ofh; unsigned char *f; size_t r, ptr; unsigned int i; struct music mus; if ( stat(filename, &statbuf) == -1 ) { fprintf(stderr, "Couldn't file file '%s'\n", filename); return; } f = malloc(statbuf.st_size); if ( f == NULL ) { fprintf(stderr, "Couldn't allocate memory.\n"); return; } /* Load data */ fh = fopen(filename, "rb"); if ( fh == NULL ) { fprintf(stderr, "Failed to open file '%s'\n", filename); return; } r = fread(f, 1, statbuf.st_size, fh); if ( r != (size_t)statbuf.st_size ) { fprintf(stderr, "Failed to read file" " (got %lli out of %lli bytes).\n", (long long int)r, (long long int)statbuf.st_size); fclose(fh); free(f); return; } fclose(fh); ofh = fopen("maestropond.ly", "w"); if ( ofh == NULL ) { fprintf(stderr, "Failed to open output file.\n"); return; } fprintf(ofh, "\\version \"2.14.2\"\n"); fprintf(ofh, "\\header {\n"); fprintf(ofh, " title = \"%s\"\n", filename); fprintf(ofh, " composer = \"Unknown\"\n"); fprintf(ofh, "}\n"); if ( memcmp(f, "Maestro\n", 8) != 0 ) { fprintf(stderr, "Not a Maestro file.\n"); free(f); return; } if ( f[8] != 2 ) { fprintf(stderr, "Unrecognised Maestro file type (%i)\n", f[8]); free(f); return; } ptr = 9; while ( ptr < r ) { switch ( f[ptr++] ) { case 1 : ptr = read_music_data(f, ptr, r, &mus); break; case 2 : ptr = process_stave_data(f, ptr, r, &mus); break; case 3 : ptr = process_instrument_data(f, ptr, r, &mus); break; case 4 : ptr = process_volume_data(f, ptr, r, &mus); break; case 5 : ptr = process_stereo_data(f, ptr, r, &mus); break; case 6 : ptr = process_tempo_data(f, ptr, r, &mus); break; } } fprintf(ofh, "\score {\n"); for ( i=0; i>\n>>\n"); } fprintf(ofh, "}\n"); } int main(int argc, char *argv[]) { int c; char *infile; /* Long options */ const struct option longopts[] = { {"help", 0, NULL, 'h'}, {0, 0, NULL, 0} }; /* Short options */ while ((c = getopt_long(argc, argv, "h", longopts, NULL)) != -1) { switch (c) { case 'h' : show_help(argv[0]); return 0; case 0 : break; default : return 1; } } if ( optind >= argc ) { show_syntax(argv[0]); return 1; } infile = argv[optind++]; printf("Input: '%s'\n", infile); convert_file(infile); return 0; }