diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..089e9e3 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +miditones: miditones.c + gcc -O2 -Wall -o miditones miditones.c + +clean: + rm -f miditones diff --git a/miditones.c b/miditones.c index 2ac0fdd..deed642 100644 --- a/miditones.c +++ b/miditones.c @@ -5,7 +5,7 @@ * Convert a MIDI file into a bytestream of notes * * -* (C) Copyright 2011,2013,2015, Len Shustek +* (C) Copyright 2011,2013,2015,2016 Len Shustek * * This program is free software: you can redistribute it and/or modify * it under the terms of version 3 of the GNU General Public License as @@ -52,9 +52,11 @@ * Generate "const" for data initialization for compatibility with Arduino IDE v1.6.x. * 23 January 2016, D. Blackketter, V1.8 * -Fix warnings and errors building on Mac OS X via "gcc miditones.c" +* 25 January 2016, D. Blackketter, Paul Stoffregen, V1.9 + -Merge in velocity output option from Arduino/Teensy Audio Library */ -#define VERSION "1.8" +#define VERSION "1.9" /*-------------------------------------------------------------------------------- @@ -146,6 +148,8 @@ * -kn Change the musical key of the output by n chromatic notes. * -k-12 goes one octave down, -k12 goes one octave up, etc. * +* -v Add velocity information to output +* * * ***** The score bytestream ***** * @@ -155,9 +159,10 @@ * * If the high-order bit of the byte is 1, then it is one of the following commands: * -* 9t nn Start playing note nn on tone generator t. Generators are numbered +* 9t nn [vv] Start playing note nn on tone generator t. Generators are numbered * starting with 0. The notes numbers are the MIDI numbers for the chromatic * scale, with decimal 60 being Middle C, and decimal 69 being Middle A (440 Hz). +* if the -v option is enabled, a second byte is added to indicate velocity * * 8t Stop playing the note on tone generator t. * @@ -213,7 +218,7 @@ struct track_header { #define DEFAULT_TONEGENS 6 /* default number of tone generators */ #define MAX_TRACKS 24 /* max number of MIDI tracks we will process */ -bool loggen, logparse, parseonly, strategy1, strategy2, binaryoutput; +bool loggen, logparse, parseonly, strategy1, strategy2, binaryoutput, velocityoutput; FILE *infile, *outfile, *logfile; uint8_t *buffer, *hdrptr; unsigned long buflen; @@ -235,7 +240,7 @@ struct tonegen_status { /* current status of a tone generator */ int note; /* what note is playing? */ } tonegen [MAX_TONEGENS] = { - 0}; + {0}}; struct track_status { /* current processing point of a MIDI track */ uint8_t *trkptr; /* ptr to the next note change */ @@ -245,11 +250,12 @@ struct track_status { /* current processing point of a MIDI track */ unsigned int preferred_tonegen; /* for strategy2: try to use this generator */ unsigned char cmd; /* CMD_xxxx next to do */ unsigned char note; /* for which note */ + unsigned char velocity; unsigned char last_event; /* the last event, for MIDI's "running status" */ bool tonegens[MAX_TONEGENS];/* which tone generators our notes are playing on */ } track[MAX_TRACKS] = { - 0}; + {0}}; /* output bytestream commands, which are also stored in track_status.cmd */ @@ -271,7 +277,7 @@ track[MAX_TRACKS] = { void SayUsage(char *programName){ static char *usage[] = { "Convert MIDI files to an Arduino PLAYTUNE bytestream", - "miditones [-p] [-lg] [-lp] [-s1] [-tn] ", + "miditones [-p] [-lg] [-lp] [-s1] [-tn] [-v] ", " -p parse only, don't generate bytestream", " -lp log input parsing", " -lg log output generation", @@ -281,6 +287,7 @@ void SayUsage(char *programName){ " -b binary file output instead of C source text", " -cn mask for which tracks to process, e.g. -c3 for only 0 and 1", " -kn key shift in chromatic notes, positive or negative", + " -v include velocity data in play note commands", "input file: .mid", "output file: .bin or .c", "log file: .log", @@ -314,6 +321,9 @@ int HandleOptions(int argc,char *argv[]) { case 'B': binaryoutput = true; break; + case 'V': + velocityoutput = true; + break; case 'S': if (argv[i][2] == '1') strategy1 = true; else if (argv[i][2] == '2') strategy2 = true; @@ -413,7 +423,7 @@ size_t miditones_strlcat(char *dst, const char *src, size_t siz) { /* match a constant character sequence */ -int charcmp (char *buf, char *match) { +int charcmp (const char *buf, const char *match) { int len, i; len = strlen (match); for (i=0; iMTrk,"MTrk")) midi_error("Missing 'MTrk'", hdrptr); + if (!charcmp((char *)(hdr->MTrk),"MTrk")) midi_error("Missing 'MTrk'", hdrptr); tracklen = rev_long(hdr->track_size); if (logparse) fprintf (logfile, "\nTrack %d length %ld\n", tracknum, tracklen); @@ -640,6 +650,7 @@ note_off: t->note = *t->trkptr++; velocity = *t->trkptr++; if (velocity == 0) /* some scores use note-on with zero velocity for off! */ goto note_off; + t->velocity = velocity; if (logparse) fprintf (logfile, "note %02X on, chan %d, velocity %d\n", t->note, chan, velocity); if ((1<cmd = CMD_PLAYNOTE; @@ -697,7 +708,7 @@ int main(int argc,char *argv[]) { unsigned long earliest_time; int notes_skipped = 0; - printf("MIDITONES V%s, (C) 2011,2015 Len Shustek\n", VERSION); + printf("MIDITONES V%s, (C) 2011,2015,2016 Len Shustek\n", VERSION); printf("See the source code for license information.\n\n"); if (argc == 1) { /* no arguments */ SayUsage(argv[0]); @@ -773,7 +784,12 @@ int main(int argc,char *argv[]) { fprintf(outfile, "// Only the masked channels were processed: %04X\n", channel_mask); if (keyshift != 0) fprintf(outfile, "// Keyshift was %d chromatic notes\n", keyshift); - fprintf(outfile, "const byte PROGMEM score [] = {\n"); + fprintf(outfile, "#ifdef __AVR__\n"); + fprintf(outfile, "#include \n"); + fprintf(outfile, "#else\n"); + fprintf(outfile, "#define PROGMEM\n"); + fprintf(outfile, "#endif\n"); + fprintf(outfile, "const unsigned char PROGMEM score [] = {\n"); } } @@ -932,10 +948,19 @@ int main(int argc,char *argv[]) { putc (CMD_PLAYNOTE | tgnum, outfile); putc (shifted_note, outfile); outfile_bytecount += 2; + if (velocityoutput) { + putc (trk->velocity, outfile); + outfile_bytecount++; + } } else { - fprintf (outfile, "0x%02X,%d, ", CMD_PLAYNOTE | tgnum, shifted_note); - outfile_items(2); + if (velocityoutput == 0) { + fprintf (outfile, "0x%02X,%d, ", CMD_PLAYNOTE | tgnum, shifted_note); + outfile_items(2); + } else { + fprintf (outfile, "0x%02X,%d,%d, ", CMD_PLAYNOTE | tgnum, shifted_note, trk->velocity); + outfile_items(3); + } } } else {