From 3a0d14ce12597341085621d88be610677f513e28 Mon Sep 17 00:00:00 2001 From: Len Shustek Date: Sat, 24 Apr 2021 12:27:13 -0700 Subject: [PATCH] add minor new features --- LICENSE.txt | 2 +- README.txt | 19 +++++++++++++-- miditones.c | 54 +++++++++++++++++++++++++++++-------------- miditones.exe | Bin 30720 -> 31232 bytes miditones_scroll.c | 25 +++++++++++++++----- miditones_scroll.exe | Bin 53760 -> 20992 bytes 6 files changed, 74 insertions(+), 26 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index e6f88c6..34a2d76 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016, Len Shustek +Copyright (c) 2016,2021 Len Shustek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.txt b/README.txt index 48ffd8c..7ae092d 100644 --- a/README.txt +++ b/README.txt @@ -44,6 +44,15 @@ (from MIDI channel 10) are generated from longer sampled waveforms of a complete instrument strike. Each generator's volume is independently adjusted according to the MIDI velocity of the note being played before all channels are mixed. + + www.github.com/LenShustek/Playtune_Teensy + The fifth version is for the Teensy 3.1/3.2, and uses the four Periodic Interval + Timers in the Cortex M4 processor to support up to 4 simultaneous notes. + It uses less CPU time than the polling version, but is limited to 4 notes at a time. + (This was written to experiment with multi-channel multi-Tesla Coil music playing, + where I use Flexible Timer Module FTM0 for generating precise one-shot pulses. + But I ultimately switched to the polling version to play more simultaneous notes.) + www.github.com/LenShustek/Playtune_Teensy www.github.com/LenShustek/ATtiny-playtune This is a much simplified version that fits, with a small song, into an ATtiny @@ -93,6 +102,9 @@ The is the base name, without an extension, for the input and output files. It can contain directory path information, or not. + If the user specifies the full .mid filename, the .mid or .MID extension + will be dropped and the remaining name will be used as . + The input file is .mid, and the output filename(s) are the base file name with .c, .h, .bin, and/or .log extensions. @@ -152,6 +164,9 @@ -h Give command-line help. + -showskipped Display information to the console each note that had to be skipped + because there weren't enough tone generators. + -delaymin=x Don't generate delays less than x milliseconds long, to reduce the number of "delay" commands and thus make the bytestream smaller, at the expense of moving notes slightly. The deficits are accumulated and eventually used, @@ -208,7 +223,7 @@ F0 End of score; stop playing. - E0 End of score, but start playing again from the beginning. This is + E0 End of score, but start playing again from the beginning. This is generated by the -r option. If the high-order bit of the byte is 0, it is a command to delay for a while until @@ -238,4 +253,4 @@ Any subsequent header bytes covered by the count, if present, are currently undefined and should be ignored by players. - Len Shustek, 2011 to 2019; see the change log. + Len Shustek, 2011 to 2021; see the change log. \ No newline at end of file diff --git a/miditones.c b/miditones.c index d2d99dc..2dc4c22 100644 --- a/miditones.c +++ b/miditones.c @@ -46,6 +46,15 @@ (from MIDI channel 10) are generated from longer sampled waveforms of a complete instrument strike. Each generator's volume is independently adjusted according to the MIDI velocity of the note being played before all channels are mixed. + + www.github.com/LenShustek/Playtune_Teensy + The fifth version is for the Teensy 3.1/3.2, and uses the four Periodic Interval + Timers in the Cortex M4 processor to support up to 4 simultaneous notes. + It uses less CPU time than the polling version, but is limited to 4 notes at a time. + (This was written to experiment with multi-channel multi-Tesla Coil music playing, + where I use Flexible Timer Module FTM0 for generating precise one-shot pulses. + But I ultimately switched to the polling version to play more simultaneous notes.) + www.github.com/LenShustek/Playtune_Teensy www.github.com/LenShustek/ATtiny-playtune This is a much simplified version that fits, with a small song, into an ATtiny @@ -157,6 +166,9 @@ -h Give command-line help. + -showskipped Display information to the console each note that had to be skipped + because there weren't enough tone generators. + -delaymin=x Don't generate delays less than x milliseconds long, to reduce the number of "delay" commands and thus make the bytestream smaller, at the expense of moving notes slightly. The deficits are accumulated and eventually used, @@ -213,7 +225,7 @@ F0 End of score; stop playing. - E0 End of score, but start playing again from the beginning. This is + E0 End of score, but start playing again from the beginning. This is generated by the -r option. If the high-order bit of the byte is 0, it is a command to delay for a while until @@ -243,11 +255,11 @@ Any subsequent header bytes covered by the count, if present, are currently undefined and should be ignored by players. - Len Shustek, 2011 to 2019; see the change log. + Len Shustek, 2011 to 2021; see the change log. *---------------------------------------------------------------------------------------- * The MIT License (MIT) -* Copyright (c) 2011,2013,2015,2016,2019 Len Shustek +* Copyright (c) 2011,2013,2015,2016,2019,2021 Len Shustek * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -367,14 +379,17 @@ -Let user supply full filename to MIDI file on command line to be friendlier to users using shell autocompletion. If a .mid or .MID file is provided, the extension will be dropped to generate the base filename. + 22 April 2021, Len Shustek, V2.2 + -Add -showskipped to log the places where notes had to be discarded because + there aren't enough tone generators. future version ideas -Perhaps elide "note off/note on" event sequences for the same note that become adjacent because of -delaymin. Does that happen much, or at all? - -Allow the flexibility to specify note timing on a track-by-track or - channel-by-channel basis, by using a .cfg file which has + -Allow the flexibility to specify note timing on a track-by-track or + channel-by-channel basis, by using a .cfg file which has commands like these: options track 1 // melody @@ -382,7 +397,7 @@ future version ideas channel 8 // organ options -attacktime=1000 -sustainlevel=80% -releasetime=100 -notemin=200 */ -#define VERSION "2.1" +#define VERSION "2.2" /*-------------------------------------------------------------------------------------------- @@ -465,7 +480,7 @@ See https://stackoverflow.com/questions/1080297/how-does-midi-tempo-message-appl /*--------------- processing outline ----------------------------------- Lots of details are omitted. Note that MIDI track parsing is based -on counting "ticks", but our queueing is based on real-time seconds. +on counting "ticks", but our queueing is based on real-time seconds. The number of ticks per second changes with the tempo. noteinfo @@ -518,7 +533,7 @@ queue command output queue entries at the oldest time static output time, time deficit if time has advanced - output DELAY + output DELAY for all entries at the same oldest time if STOP find tgen matching channel and note @@ -571,7 +586,7 @@ struct track_header { bool loggen, logparse, parseonly, strategy1, strategy2, binaryoutput, define_progmem, volume_output, instrumentoutput, percussion_ignore, percussion_translate, do_header, - gen_restart, scorename; + gen_restart, scorename, showskipped; FILE *infile, *outfile, *logfile; uint8_t *buffer, *hdrptr; unsigned long buflen; @@ -703,6 +718,7 @@ void SayUsage(char *programName) { " -r terminate output file with \"restart\" instead of \"stop\" command", " -s1 strategy 1: favor track 1", " -s2 strategy 2: try to assign tracks to specific tone generators", + " -showskipped display information about each note that had to be skipped", " -delaymin=x minimum delay is x msec, to save bytestream space", " -attacktime=x the high volume attack phase lasts x msec", " -attacknotemax=x notes over x msec don't use the attack/sustain profile", @@ -752,6 +768,7 @@ int HandleOptions (int argc, char *argv[]) { else if (opt_key(arg, "s1")) strategy1 = true; else if (opt_key(arg, "s2")) strategy2 = true; else if (opt_key(arg, "scorename")) scorename = true; + else if (opt_key(arg, "showskipped")) showskipped = true; else if (opt_int(arg, "t", &num_tonegens, 1, MAX_TONEGENS)) printf("Using %d tone generators\n", num_tonegens); else if (opt_key(arg, "v")) volume_output = true; @@ -898,8 +915,11 @@ struct channel_status { // current status of a channel char *describe(struct noteinfo *np) { // create a description of a note // WARNING: returns a pointer to a static string, so only call once per line, in a printf! static char notedescription[100]; - sprintf(notedescription, "at %lu.%03lu msec, note %d (0x%02X) track %d channel %d volume %d instrument %d", - np->time_usec / 1000, np->time_usec % 1000, np->note, np->note, + int secs = np->time_usec / 1000000; + sprintf(notedescription, "at %3lu.%06lu sec (%d:%02d), note %d (0x%02X) track %d channel %d volume %d instrument %d", + secs, np->time_usec % 1000000, + secs/60, secs % 60, + np->note, np->note, np->track, np->channel, np->volume, np->instrument); return notedescription; } @@ -1001,7 +1021,7 @@ void remove_queue_entry(int ndx) { // remove the oldest queue entry for (tgnum = 0; tgnum < num_tonegens; ++tgnum) { struct tonegen_status *tg = &tonegen[tgnum]; if (tg->playing - && tg->note.note == q->note.note + && tg->note.note == q->note.note && tg->note.channel == q->note.channel) { // found the note tg->stopnote_pending = true; // "stop note needed unless another start note follows" tg->playing = false; // free the tg to be reallocated, but note the stop time in case @@ -1056,7 +1076,8 @@ void remove_queue_entry(int ndx) { // remove the oldest queue entry else { if (loggen) fprintf(logfile, " *** at %lu.%03lu msec no free generator; skipping %s\n", output_usec / 1000, output_usec % 1000, describe(&q->note)); - ++notes_skipped; } } } + if (showskipped) printf(" *** no free generator %s\n", + describe(&q->note)); ++notes_skipped; } } } void generate_delay(unsigned long delta_msec) { // output a delay command if (delta_msec > 0) { @@ -1557,10 +1578,9 @@ int main (int argc, char *argv[]) { // strip off trailing .mid or .MID extension if provided by user basenamelen = strlength(filebasename); if (basenamelen > 4 && - (charcmp (filebasename + basenamelen - 4, ".mid") || - charcmp (filebasename + basenamelen - 4, ".MID"))) { - filebasename[basenamelen - 4] = 0; - } + (charcmp (filebasename + basenamelen - 4, ".mid") || + charcmp (filebasename + basenamelen - 4, ".MID"))) { + filebasename[basenamelen - 4] = 0; } if (logparse || loggen) { // open the log file miditones_strlcpy (filename, filebasename, MAXPATH); diff --git a/miditones.exe b/miditones.exe index c082d38d74b795b545fd76e7e0198fc3236165a3..ba15dfc19444ff9c297fc8f0adfd3fbe36754ec1 100644 GIT binary patch delta 11037 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 Q;+6Pjyaun`;}@a$AI3Dj+W-In delta 10217 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 X_`(SHq6jF$$p~^BNs^T{N>=f|KpS%f diff --git a/miditones_scroll.c b/miditones_scroll.c index 1931238..e92f06e 100644 --- a/miditones_scroll.c +++ b/miditones_scroll.c @@ -53,7 +53,7 @@ * *---------------------------------------------------------------------------------------- * The MIT License (MIT) -* Copyright (c) 2011,2013,2015,2016,2019, Len Shustek +* Copyright (c) 2011,2013,2015,2016,2019,2021 Len Shustek * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -109,9 +109,12 @@ * - Write the output to .txt, if not -c * - Decode the header flags * - Reformat to condense the code +* 23 April 2021, L. Shustek, V1.9 +* - show a summary at the end of what instruments were used and how many times +* - show the lowest and highest volume used */ -#define VERSION "1.8" +#define VERSION "1.9" #include #include @@ -150,6 +153,7 @@ bool codeoutput = false; bool expect_volume = false; bool ignore_volume = false; bool showhex = false; +unsigned max_vol = 0, min_vol = 255; struct file_hdr_t { /* what the optional file header looks like */ char id1; // 'P' @@ -216,6 +220,7 @@ static char *instrumentname[128] = { /* maximum 6 characters */ "Sitar ", "Banjo ", "Shamis", "Koto ", "Kalimb", "Bagpip", "Fiddle", "Shanai", "TnkBel", "Agogo ", "StDrum", "WdBlok", "TaiDrm", "MelTom", "SynDrm", "RevCym", "GuitFr", "Breath", "Seashr", "BirdTw", "Phone ", "Copter", "Claps ", "Guns " }; +int instrument_count[128] = { 0 }; /************** command-line processing *******************/ @@ -450,8 +455,7 @@ int main (int argc, char *argv[]) { for (int i = 0; i < argc; i++) fprintf(outfile, "%s ", argv[i]); fprintf(outfile, "\n"); fprintf(outfile, "reading %s.bin with %ld bytes\n", filebasename, buflen); - if (num_tonegens < MAX_TONEGENS) fprintf(outfile, "displaying only %d tone generators.\n", num_tonegens); - } + if (num_tonegens < MAX_TONEGENS) fprintf(outfile, "displaying only %d tone generators.\n", num_tonegens); } else { fprintf (outfile, "// Playtune bytestream for file \"%s.bin\"", filebasename); fprintf (outfile, " created by MIDITONES_SCROLL V%s on %s\n", VERSION, @@ -513,11 +517,14 @@ int main (int argc, char *argv[]) { if (cmd == 0x90) { /* note on */ gen_note[gen] = *++bufptr; // note number tonegens_used |= 1 << gen; // record that we used this generator at least once + ++instrument_count[gen_instrument[gen]]; // count a use of this instrument if (gen_did_stopnote[gen]) { // unnecesary stop note ++stopnotes_before_startnote; warning = true; } - if (expect_volume) - gen_volume[gen] = *++bufptr; // volume + if (expect_volume) { + unsigned volume = gen_volume[gen] = *++bufptr; // volume + if (volume > max_vol) max_vol = volume; + if (volume < min_vol) min_vol = volume; } if (gen >= num_tonegens) ++notes_skipped; // won't be displaying this note } else if (cmd == 0x80) { /* note off */ @@ -555,4 +562,10 @@ int main (int argc, char *argv[]) { fprintf (infofile, "%u stopnote commands were unnecessary.\n", stopnotes_before_startnote); fprintf (infofile, "%u consecutive delays could have been merged.\n", consecutive_delays); if (stopnotes_before_startnote + consecutive_delays > 0) fprintf (infofile, "(Those locations are marked with \"!\")\n"); + fprintf(infofile, "instruments used:\n"); + for (int i = 0; i < 128; ++i) + if (instrument_count[i]) { + fprintf(infofile, " %s (%3d, 0x%02X) %7d\n", instrumentname[i], i, i, instrument_count[i]); } + if (expect_volume) + fprintf(infofile, "volume ranged from %d to %d\n", min_vol, max_vol); printf ("Done.\n"); } diff --git a/miditones_scroll.exe b/miditones_scroll.exe index ab64fa824160e8938c5d82a64da8bc42b5f10433..8235666ac0120ea54ae2bbc9f94b268d326f4dea 100644 GIT binary patch literal 20992 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 BDmefE literal 53760 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

nN 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