157157* If the high-order bit of the byte is 1, then it is one of the following commands:
158158*
159159* 9t nn [vv]
160- * Start playing note nn on tone generator t. Generators are numbered
161- * starting with 0. The note numbers are the MIDI numbers for the chromatic
162- * scale, with decimal 60 being Middle C, and decimal 69 being Middle A (440 Hz).
160+ * Start playing note nn on tone generator t, replacing any previous note.
161+ * Generators are numbered starting with 0. The note numbers are the MIDI
162+ * numbers for the chromatic scale, with decimal 69 being Middle A (440 Hz).
163163* If the -v option was given, a second byte is added to indicate note volume.
164164*
165165* 8t Stop playing the note on tone generator t.
322322* -Add alternate frequency/duration pair output format and options to support it
323323* -Add -r option to terminate output with "restart" instead of "stop"
324324* -Allow hex and octal entry, in addition to decimal, for -cn option
325+ * -Prevent unnecessary "note off" commands from being generated by delaying
326+ * them until we see if a "note on" is generated before the next wait.
327+ * Ported from MIDITONES V1.14
325328*/
326329#define VERSION "1.0.0"
327330
@@ -434,7 +437,7 @@ struct track_header {
434437
435438bool loggen , logparse , parseonly , strategy1 , strategy2 , binaryoutput , define_progmem ,
436439 velocityoutput , instrumentoutput , percussion_ignore , percussion_translate , do_header ,
437- alt_out , restart , freq_style_a , freq_style_b , option_n ;
440+ alt_out , gen_restart , freq_style_a , freq_style_b , option_n ;
438441FILE * infile , * outfile , * logfile ;
439442uint8_t * buffer , * hdrptr ;
440443unsigned long buflen ;
@@ -459,6 +462,7 @@ int alt_out_channel; /* alt out format: MIDI channel used */
459462
460463struct tonegen_status { /* current status of a tone generator */
461464 bool playing ; /* is it playing? */
465+ bool stopnote_pending ; /* do we need to stop this generator before the next wait? */
462466 int track ; /* if so, which track is the note from? */
463467 int note ; /* what note is playing? */
464468 int instrument ; /* what instrument? */
@@ -472,11 +476,11 @@ struct track_status { /* current processing point of a MIDI track */
472476 uint8_t * trkend ; /* ptr past the end of the track */
473477 unsigned long time ; /* what time we're at in the score */
474478 unsigned long tempo ; /* the tempo last set, in usec per qnote */
475- unsigned int preferred_tonegen ; /* for strategy2, try to use this generator */
476- unsigned char cmd ; /* CMD_xxxx next to do */
479+ unsigned int preferred_tonegen ; /* for strategy2, try to use this generator */
480+ unsigned char cmd ; /* CMD_xxxx next to do */
477481 unsigned char note ; /* for which note */
478482 unsigned char chan ; /* from which channel it was */
479- unsigned char velocity ;
483+ unsigned char velocity ; /* the current volume */
480484 unsigned char last_event ; /* the last event, for MIDI's "running status" */
481485 bool tonegens [MAX_TONEGENS ]; /* which tone generators our notes are playing on */
482486} track [MAX_TRACKS ] = {
@@ -719,7 +723,7 @@ does not start with a dash or a slash*/
719723 goto opterror ;
720724 break ;
721725 case 'R' :
722- restart = true;
726+ gen_restart = true;
723727 if (argv [i ][2 ] != '\0' )
724728 goto opterror ;
725729 break ;
@@ -1145,6 +1149,26 @@ void find_note (int tracknum) {
11451149}
11461150
11471151
1152+ /* generate "stop note" commands for any channels that have them pending */
1153+
1154+ void gen_stopnotes (void ) {
1155+ struct tonegen_status * tg ;
1156+ for (int tgnum = 0 ; tgnum < num_tonegens ; ++ tgnum ) {
1157+ tg = & tonegen [tgnum ];
1158+ if (tg -> stopnote_pending ) {
1159+ if (binaryoutput ) {
1160+ putc (CMD_STOPNOTE | tgnum , outfile );
1161+ outfile_bytecount += 1 ;
1162+ } else {
1163+ fprintf (outfile , " 0x%02X," , CMD_STOPNOTE | tgnum );
1164+ outfile_items (1 );
1165+ }
1166+ tg -> stopnote_pending = false;
1167+ }
1168+ }
1169+ }
1170+
1171+
11481172/********************* main ****************************/
11491173
11501174int main (int argc , char * argv []) {
@@ -1291,7 +1315,7 @@ int main (int argc, char *argv[]) {
12911315 }
12921316 } else if (do_header ) { // write the binary file header
12931317 for (int i = 0 ; i < sizeof (file_header ); ++ i )
1294- fputc (((unsigned char * ) & file_header )[i ], outfile );
1318+ putc (((unsigned char * ) & file_header )[i ], outfile );
12951319 file_header_num_tgens_position = (char * ) & file_header .num_tgens - (char * ) & file_header ;
12961320 outfile_bytecount += sizeof (file_header );
12971321 }
@@ -1371,6 +1395,8 @@ This is not unlike multiway merging used for tape sorting algoritms in the 50's!
13711395
13721396 delta_time = earliest_time - timenow ;
13731397 if (delta_time ) {
1398+ if (!alt_out )
1399+ gen_stopnotes (); /* first check if any tone generators have "stop note" commands pending */
13741400 /* Convert ticks to milliseconds based on the current tempo */
13751401 unsigned long long temp ;
13761402 temp = ((unsigned long long ) delta_time * tempo ) / ticks_per_beat ;
@@ -1449,19 +1475,11 @@ This is not unlike multiway merging used for tape sorting algoritms in the 50's!
14491475 fprintf (logfile ,
14501476 "->Stop note %d, generator %d, track %d\n" ,
14511477 tg -> note , tgnum , tracknum );
1452- if (!alt_out ) {
1453- if (binaryoutput ) {
1454- putc (CMD_STOPNOTE | tgnum , outfile );
1455- outfile_bytecount += 1 ;
1456- } else {
1457- fprintf (outfile , " 0x%02X," , CMD_STOPNOTE | tgnum );
1458- outfile_items (1 );
1459- }
1460- } else {
1461- pending_note = pending_velocity = 0 ;
1462- }
1478+ tg -> stopnote_pending = true; /* must stop the current note if another doesn't start first */
14631479 tg -> playing = false;
14641480 trk -> tonegens [tgnum ] = false;
1481+ if (alt_out )
1482+ pending_note = pending_velocity = 0 ;
14651483 }
14661484 }
14671485 find_note (tracknum ); // use up the note
@@ -1507,6 +1525,7 @@ This is not unlike multiway merging used for tape sorting algoritms in the 50's!
15071525 tg -> playing = true;
15081526 tg -> track = tracknum ;
15091527 tg -> note = trk -> note ;
1528+ tg -> stopnote_pending = false;
15101529 trk -> tonegens [tgnum ] = true;
15111530 trk -> preferred_tonegen = tgnum ;
15121531 ++ note_on_commands ;
@@ -1580,25 +1599,28 @@ This is not unlike multiway merging used for tape sorting algoritms in the 50's!
15801599 } /* !parseonly do */
15811600 while (tracks_done < num_tracks );
15821601
1602+ if (!alt_out )
1603+ gen_stopnotes (); /* flush out any pending "stop note" commands */
1604+
15831605 // generate the end-of-score command and some commentary
15841606 if (binaryoutput ) {
15851607 if (!alt_out ) {
1586- putc (restart ? CMD_RESTART : CMD_STOP , outfile );
1608+ putc (gen_restart ? CMD_RESTART : CMD_STOP , outfile );
15871609 outfile_bytecount ++ ;
15881610 } else {
1589- output_word (restart ? TONES_REPEAT : TONES_END );
1611+ output_word (gen_restart ? TONES_REPEAT : TONES_END );
15901612 }
15911613 } else {
15921614 if (outfile_itemcount != 0 )
15931615 putc ('\n' , outfile );
15941616 if (!alt_out ) {
1595- fprintf (outfile , " 0x%02x" , restart ? CMD_RESTART : CMD_STOP );
1617+ fprintf (outfile , " 0x%02x" , gen_restart ? CMD_RESTART : CMD_STOP );
15961618 outfile_bytecount ++ ;
15971619 } else {
15981620 if (freq_style_b )
1599- fprintf (outfile , " 0x%04x" , restart ? TONES_REPEAT : TONES_END );
1621+ fprintf (outfile , " 0x%04x" , gen_restart ? TONES_REPEAT : TONES_END );
16001622 else
1601- fprintf (outfile , " %s" , restart ? "TONES_REPEAT" : "TONES_END" );
1623+ fprintf (outfile , " %s" , gen_restart ? "TONES_REPEAT" : "TONES_END" );
16021624 outfile_bytecount += 2 ;
16031625 }
16041626 fprintf (outfile , "\n};\n// This score contains %ld bytes" , outfile_bytecount );
0 commit comments