diff --git a/miditones.c b/miditones.c index 952a307..c805129 100644 --- a/miditones.c +++ b/miditones.c @@ -253,8 +253,13 @@ * 30 September 2016, Scott Allen, V1.13 * - Allow -c channel numbers to be specified as hex or octal * - Add -r to end the file with "repeat" instead of "score end" +* 30 September 2016, Len Shustek, V1.14 +* - Prevent unnecessary "note off" commands from being generated by delaying +* them until we see if a "note on" is generated before the next wait. +* Thanks to Scott Allen for inspiring me to do this. In the best case we've +* seen, this makes the bytestream 21% smaller! */ -#define VERSION "1.13" +#define VERSION "1.14" /*-------------------------------------------------------------------------------------------- @@ -381,6 +386,7 @@ unsigned long tempo; /* current tempo in usec/qnote */ struct tonegen_status { /* current status of a tone generator */ bool playing; /* is it playing? */ + bool stopnote_pending; /* do we need to stop this generator before the next wait? */ int track; /* if so, which track is the note from? */ int note; /* what note is playing? */ int instrument; /* what instrument? */ @@ -394,11 +400,11 @@ struct track_status { /* current processing point of a MIDI track */ uint8_t *trkend; /* ptr past the end of the track */ unsigned long time; /* what time we're at in the score */ unsigned long tempo; /* the tempo last set, in usec per qnote */ - unsigned int preferred_tonegen; /* for strategy2, try to use this generator */ - unsigned char cmd; /* CMD_xxxx next to do */ + 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 chan; /* from which channel it was */ - unsigned char velocity; + unsigned char velocity; /* the current volume */ 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] = { @@ -1003,6 +1009,25 @@ void find_note (int tracknum) { } +/* generate "stop note" commands for any channels that have them pending */ + +void gen_stopnotes(void) { + struct tonegen_status *tg; + for (int tgnum = 0; tgnum < num_tonegens; ++tgnum) { + tg = &tonegen[tgnum]; + if (tg->stopnote_pending) { + if (binaryoutput) { + putc (CMD_STOPNOTE | tgnum, outfile); + outfile_bytecount += 1; + } else { + fprintf (outfile, "0x%02X, ", CMD_STOPNOTE | tgnum); + outfile_items (1); + } + tg->stopnote_pending = false; + } + } +} + /********************* main ****************************/ int main (int argc, char *argv[]) { @@ -1196,6 +1221,7 @@ This is not unlike multiway merging used for tape sorting algoritms in the 50's! delta_time = earliest_time - timenow; if (delta_time) { + gen_stopnotes(); /* first check if any tone generators have "stop note" commands pending */ /* Convert ticks to milliseconds based on the current tempo */ unsigned long long temp; temp = ((unsigned long long) delta_time * tempo) / ticks_per_beat; @@ -1240,13 +1266,7 @@ This is not unlike multiway merging used for tape sorting algoritms in the 50's! fprintf (logfile, "->Stop note %d, generator %d, track %d\n", tg->note, tgnum, tracknum); - if (binaryoutput) { - putc (CMD_STOPNOTE | tgnum, outfile); - outfile_bytecount += 1; - } else { - fprintf (outfile, "0x%02X, ", CMD_STOPNOTE | tgnum); - outfile_items (1); - } + tg->stopnote_pending = true; /* must stop the current note if another doesn't start first */ tg->playing = false; trk->tonegens[tgnum] = false; } @@ -1294,6 +1314,7 @@ This is not unlike multiway merging used for tape sorting algoritms in the 50's! tg->playing = true; tg->track = tracknum; tg->note = trk->note; + tg->stopnote_pending = false; trk->tonegens[tgnum] = true; trk->preferred_tonegen = tgnum; ++note_on_commands; @@ -1359,6 +1380,7 @@ This is not unlike multiway merging used for tape sorting algoritms in the 50's! while (tracks_done < num_tracks); // generate the end-of-score command and some commentary + gen_stopnotes(); /* flush out any pending "stop note" commands */ outfile_bytecount++; if (binaryoutput) putc (gen_restart ? CMD_RESTART : CMD_STOP, outfile); diff --git a/miditones.exe b/miditones.exe index 51c0fc8..b5902de 100644 Binary files a/miditones.exe and b/miditones.exe differ