Suppress unnecessary "stop note" commands so the byestream file is smaller

pull/10/head
Len Shustek 8 years ago
parent 5a50a01498
commit 8a4b9c8fc3
  1. 44
      miditones.c
  2. BIN
      miditones.exe

@ -253,8 +253,13 @@
* 30 September 2016, Scott Allen, V1.13 * 30 September 2016, Scott Allen, V1.13
* - Allow -c channel numbers to be specified as hex or octal * - Allow -c channel numbers to be specified as hex or octal
* - Add -r to end the file with "repeat" instead of "score end" * - 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 */ struct tonegen_status { /* current status of a tone generator */
bool playing; /* is it playing? */ 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 track; /* if so, which track is the note from? */
int note; /* what note is playing? */ int note; /* what note is playing? */
int instrument; /* what instrument? */ 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 */ uint8_t *trkend; /* ptr past the end of the track */
unsigned long time; /* what time we're at in the score */ unsigned long time; /* what time we're at in the score */
unsigned long tempo; /* the tempo last set, in usec per qnote */ unsigned long tempo; /* the tempo last set, in usec per qnote */
unsigned int preferred_tonegen; /* for strategy2, try to use this generator */ unsigned int preferred_tonegen; /* for strategy2, try to use this generator */
unsigned char cmd; /* CMD_xxxx next to do */ unsigned char cmd; /* CMD_xxxx next to do */
unsigned char note; /* for which note */ unsigned char note; /* for which note */
unsigned char chan; /* from which channel it was */ 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" */ unsigned char last_event; /* the last event, for MIDI's "running status" */
bool tonegens[MAX_TONEGENS]; /* which tone generators our notes are playing on */ bool tonegens[MAX_TONEGENS]; /* which tone generators our notes are playing on */
} track[MAX_TRACKS] = { } 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 ****************************/ /********************* main ****************************/
int main (int argc, char *argv[]) { 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; delta_time = earliest_time - timenow;
if (delta_time) { 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 */ /* Convert ticks to milliseconds based on the current tempo */
unsigned long long temp; unsigned long long temp;
temp = ((unsigned long long) delta_time * tempo) / ticks_per_beat; 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, fprintf (logfile,
"->Stop note %d, generator %d, track %d\n", "->Stop note %d, generator %d, track %d\n",
tg->note, tgnum, tracknum); tg->note, tgnum, tracknum);
if (binaryoutput) { tg->stopnote_pending = true; /* must stop the current note if another doesn't start first */
putc (CMD_STOPNOTE | tgnum, outfile);
outfile_bytecount += 1;
} else {
fprintf (outfile, "0x%02X, ", CMD_STOPNOTE | tgnum);
outfile_items (1);
}
tg->playing = false; tg->playing = false;
trk->tonegens[tgnum] = 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->playing = true;
tg->track = tracknum; tg->track = tracknum;
tg->note = trk->note; tg->note = trk->note;
tg->stopnote_pending = false;
trk->tonegens[tgnum] = true; trk->tonegens[tgnum] = true;
trk->preferred_tonegen = tgnum; trk->preferred_tonegen = tgnum;
++note_on_commands; ++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); while (tracks_done < num_tracks);
// generate the end-of-score command and some commentary // generate the end-of-score command and some commentary
gen_stopnotes(); /* flush out any pending "stop note" commands */
outfile_bytecount++; outfile_bytecount++;
if (binaryoutput) if (binaryoutput)
putc (gen_restart ? CMD_RESTART : CMD_STOP, outfile); putc (gen_restart ? CMD_RESTART : CMD_STOP, outfile);

Binary file not shown.
Loading…
Cancel
Save