parent
fd994d37cb
commit
ee76ad2d1f
@ -1,171 +1,241 @@ |
|||||||
/********************************************************************************************* |
|
||||||
* |
MIDITONES: Convert a MIDI file into a simple bytestream of notes |
||||||
* MIDITONES: Convert a MIDI file into a simple bytestream of notes |
|
||||||
* |
|
||||||
* |
MIDITONES compiles a MIDI music file into a much simplified compact time-ordered stream of |
||||||
* MIDITONES converts a MIDI music file into a much simplified stream of commands, so that |
commands, so that the music can easily be played on a small microcontroller-based synthesizer |
||||||
* the music can easily be played on a small microcontroller-based synthesizer that has |
that has only simple tone generators. This is on github at www.github.com/LenShustek/miditones. |
||||||
* only simple tone generators. This is on github at www.github.com/LenShustek/miditones. |
|
||||||
* |
Volume ("velocity") and instrument information in the MIDI file can either be |
||||||
* Volume ("velocity") and instrument information in the MIDI file can either be |
discarded or kept. All the tracks are processed and merged into a single time-ordered |
||||||
* discarded or kept. All the tracks are processed and merged into a single time-ordered |
stream of "note on", "note off", "change instrument" and "delay" commands. |
||||||
* stream of "note on", "note off", "change instrument" and "delay" commands. |
|
||||||
* |
MIDITONES was written for the "Playtune" series of Arduino and Teensy |
||||||
* This was written for the "Playtune" series of Arduino and Teensy microcontroller |
microcontroller software synthesizers: |
||||||
* synthesizers. See the separate documentation for the various Playtune.players at |
|
||||||
* www.github.com/LenShustek/arduino-playtune |
www.github.com/LenShustek/arduino-playtune |
||||||
* www.github.com/LenShustek/ATtiny-playtune |
This original version of Playtune, first released in 2011, uses a separate hardware timer |
||||||
* www.github.com/LenShustek/Playtune_poll |
for each note to generate a square wave on an output pin. All the pins are then combined |
||||||
* www.github.com/LenShustek/Playtune_samp |
with a simple resistor network connected to a speaker and/or amplifier. It can only play |
||||||
* www.github.com/LenShustek/Playtune_synth |
as many simutaneous notes as there are timers. There is no volume modulation. |
||||||
* MIDITONES may also prove useful for other simple music synthesizers.. |
|
||||||
* |
www.github.com/LenShustek/Playtune_poll |
||||||
* The output can be either a C-language source code fragment that initializes an |
This second vesion uses only one hardware timer that interrupts periodically at a fast |
||||||
* array with the command bytestream, or a binary file with the bytestream itself. |
rate, and toggles square waves onto any number of digital output pins. It also implements |
||||||
* |
primitive volume modulation by changing the duty cycle of the square wave. The number of |
||||||
* MIDITONES is written in standard ANSI C and is meant to be executed from the |
simultaneous notes is limited only by the number of output pins and the speed of the processor. |
||||||
* command line. There is no GUI interface. |
|
||||||
* |
www.github.com/LenShustek/Playtune_samp |
||||||
* The MIDI file format is complicated, and this has not been tested on all of its |
The third version also uses only one hardware timer interrupting frequently, but |
||||||
* variations. In particular we have tested only format type "1", which seems |
uses the hardware digital-to-analog converter on high-performance microntrollers like |
||||||
* to be what most of them are. Let me know if you find MIDI files that it |
the Teensy to generate an analog wave that is the sum of stored samples of sounds for |
||||||
* won't digest and I'll see if I can fix it. |
many different instruments. The samples are scaled to the right frequency and volume, |
||||||
* |
and any number of instrument samples can be used and mapped to MIDI patches. The sound |
||||||
* There is a companion program in the same repository called Miditones_scroll |
quality is much better, although not in league with real synthesizers. It currently |
||||||
* that can convert the bytestream generated by MIDITONES into a piano-player |
only supports Teensy boards. |
||||||
* like listing for debugging or annotation. See the documentation in the |
|
||||||
* beginning of its source code. |
www.github.com/LenShustek/Playtune_synth |
||||||
* |
The fourth version is an audio object for the PJRC Audio Library. |
||||||
* |
https://www.pjrc.com/teensy/td_libs_Audio.html |
||||||
* ***** The MIDITONES command line ***** |
It allows up to 16 simultaneous sound generators that are internally mixed, at |
||||||
* |
the appropriate volume, to produce one monophonic audio stream. |
||||||
* To convert a MIDI file called "chopin.mid" into a command bytestream, execute |
Sounds are created from sampled one-cycle waveforms for any number of instruments, |
||||||
* |
each with its own attack-hold-decay-sustain-release envelope. Percussion sounds |
||||||
* miditones chopin |
(from MIDI channel 10) are generated from longer sampled waveforms of a complete |
||||||
* |
instrument strike. Each generator's volume is independently adjusted according to |
||||||
* It will create a file in the same directory called "chopin.c" which contains |
the MIDI velocity of the note being played before all channels are mixed. |
||||||
* the C-language statement to intiialize an array called "score" with the bytestream. |
|
||||||
* |
www.github.com/LenShustek/ATtiny-playtune |
||||||
* |
This is a much simplified version that fits, with a small song, into an ATtiny |
||||||
* The general form for command line execution is this: |
processor with only 4K of flash memory. It also using polling with only one timer, |
||||||
* |
and avoids multiplication or division at runtime for speed. It was written |
||||||
* miditones <options> <basefilename> |
for the Evil Mad Scientist menorah kit: |
||||||
* |
https://www.evilmadscientist.com/2009/new-led-hanukkah-menorah-kit/ |
||||||
* The <basefilename> is the base name, without an extension, for the input and |
https://forum.evilmadscientist.com/discussion/263/making-the-menorah-play-music |
||||||
* output files. It can contain directory path information, or not. |
(Imagine what you can do with the $1 8-pin ATtiny85 with a whopping 8K!) |
||||||
* |
|
||||||
* The input file is <basefilename>.mid The output filename(s) |
MIDITONES may also prove useful for other simple music synthesizers. There are |
||||||
* are the base file name with .c, .bin, and/or .log extensions. |
various forks of the code, and the Playtune players, on Githib. |
||||||
* |
|
||||||
* |
*** THE PROGRAM |
||||||
* The following commonly-used command-line options can be specified: |
|
||||||
* |
MIDITONES is written in standard ANSI C and is meant to be executed from the |
||||||
* -v Add velocity (volume) information to the output bytestream |
command line. There is no GUI interface. |
||||||
* |
|
||||||
* -i Add instrument change commands to the output bytestream |
The output can be either a C-language source code fragment that initializes an |
||||||
* |
array with the command bytestream, or a binary file with the bytestream itself. |
||||||
* -pt Translate notes in the MIDI percussion track to note numbers 128..255 |
|
||||||
* and assign them to a tone generator as usual. |
The MIDI file format is complicated, and this has not been tested on all of its |
||||||
* |
variations. In particular we have tested only format type "1", which seems |
||||||
* -d Generate a self-describing file header that says which optional bytestream |
to be what most of them are. Let me know if you find MIDI files that it |
||||||
* fields are present. This is highly recommended if you are using later |
won't digest and I'll see if I can fix it. |
||||||
* Playtune players that can check the header to know what data to expect. |
|
||||||
* |
There is a companion program in the same repository called Miditones_scroll |
||||||
* -b Generate a binary file with the name <basefilename>.bin, instead of a |
that can convert the bytestream generated by MIDITONES into a piano-player |
||||||
* C-language source file with the name <basefilename>.c. |
like listing for debugging or annotation. See the documentation near the |
||||||
* |
top of its source code. |
||||||
* -tn Generate the bytestream so that at most "n" tone generators are used. |
|
||||||
* The default is 6 tone generators, and the maximum is 16. The program |
|
||||||
* will report how many notes had to be discarded because there weren't |
*** THE COMMAND LINE |
||||||
* enough tone generators. |
|
||||||
* |
To convert a MIDI file called "chopin.mid" into a command bytestream, execute |
||||||
* |
|
||||||
* The best combination of options to use with the later Playtune music players is: |
miditones chopin |
||||||
* -v -i -pt -d |
|
||||||
* |
It will create a file in the same directory called "chopin.c" which contains |
||||||
* |
the C-language statement to intiialize an array called "score" with the bytestream. |
||||||
* The following are lesser-used command-line options: |
|
||||||
* |
|
||||||
* -p Only parse the MIDI file, and don't generate an output file. |
The general form for command line execution is this: |
||||||
* Tracks are processed sequentially instead of being merged into chronological order. |
|
||||||
* This is mostly useful for debugging MIDI file parsing problems. |
miditones <options> <basefilename> |
||||||
* |
|
||||||
* -lp Log input file parsing information to the <basefilename>.log file |
The <basefilename> is the base name, without an extension, for the input and |
||||||
* |
output files. It can contain directory path information, or not. |
||||||
* -lg Log output bytestream generation information to the <basefilename>.log file |
|
||||||
* |
The input file is <basefilename>.mid, and the output filename(s) |
||||||
* -nx Put about "x" items on each line of the C file output |
are the base file name with .c, .h, .bin, and/or .log extensions. |
||||||
* |
|
||||||
* -sn Use bytestream generation strategy "n". |
|
||||||
* Two strategies are currently implemented: |
The following commonly-used command-line options can be specified: |
||||||
* 1:favor track 1 notes instead of all tracks equally |
|
||||||
* 2:try to keep each track to its own tone generator |
-v Add velocity (volume) information to the output bytestream |
||||||
* |
|
||||||
* -cn Only process the channel numbers whose bits are on in the number "n". |
-i Add instrument change commands to the output bytestream |
||||||
* For example, -c3 means "only process channels 0 and 1". In addition to decimal, |
|
||||||
* "n" can be also specified in hex using a 0x prefix or octal with a 0 prefix. |
-pt Translate notes in the MIDI percussion track to note numbers 128..255 |
||||||
* |
and assign them to a tone generator as usual. |
||||||
* -kn Change the musical key of the output by n chromatic notes. |
|
||||||
* -k-12 goes one octave down, -k12 goes one octave up, etc. |
-d Generate a self-describing file header that says which optional bytestream |
||||||
* |
fields are present. This is highly recommended if you are using later |
||||||
* -pi Ignore notes in the MIDI percussion track 9 (also called 10 by some) |
Playtune players that can check the header to know what data to expect. |
||||||
* |
|
||||||
* -dp Generate IDE-dependent C code to define PROGMEM |
-b Generate a binary file with the name <basefilename>.bin, instead of a |
||||||
* |
C-language source file with the name <basefilename>.c. |
||||||
* -r Terminate the output file with a "restart" command instead of a "stop" command. |
|
||||||
* |
-t=n Generate the bytestream so that at most "n" tone generators are used. |
||||||
* -h Give command-line help. |
The default is 6 tone generators, and the maximum is 16. The program |
||||||
* |
will report how many notes had to be discarded because there weren't |
||||||
* |
enough tone generators. |
||||||
* ***** The score bytestream ***** |
|
||||||
* |
The best combination of options to use with the later Playtune music players is: |
||||||
* The generated bytestream is a series of commands that turn notes on and off, |
-v -i -pt -d |
||||||
* maybe change instruments, and begin delays until the next note change. |
|
||||||
* Here are the details, with numbers shown in hexadecimal. |
The following are lesser-used command-line options: |
||||||
* |
|
||||||
* If the high-order bit of the byte is 1, then it is one of the following commands: |
-c=n Only process the channel numbers whose bits are on in the number "n". |
||||||
* |
For example, -c3 means "only process channels 0 and 1". In addition to decimal, |
||||||
* 9t nn [vv] |
"n" can be also specified in hex using a 0x prefix. |
||||||
* Start playing note nn on tone generator t, replacing any previous note. |
|
||||||
* Generators are numbered starting with 0. The note numbers are the MIDI |
-dp Generate Arduino IDE-dependent C code that uses PROGMEM for the bytestream. |
||||||
* numbers for the chromatic scale, with decimal 69 being Middle A (440 Hz). |
|
||||||
* If the -v option was given, a second byte is added to indicate note volume. |
-k=n Change the musical key of the output by n chromatic notes. |
||||||
* |
-k=-12 goes one octave down, -k=12 goes one octave up, etc. |
||||||
* 8t Stop playing the note on tone generator t. |
|
||||||
* |
-lp Log input file parsing information to the <basefilename>.log file |
||||||
* Ct ii Change tone generator t to play instrument ii from now on. This will only |
|
||||||
* be generated if the -i option was given. |
-lg Log output bytestream generation information to the <basefilename>.log file |
||||||
* |
|
||||||
* F0 End of score; stop playing. |
-n=x Put about "x" items on each line of the C file output |
||||||
* |
|
||||||
* E0 End of score; start playing again from the beginning. |
-p Only parse the MIDI file, and don't generate an output file. |
||||||
* |
Tracks are processed sequentially instead of being merged into chronological order. |
||||||
* If the high-order bit of the byte is 0, it is a command to delay for a while until |
This is mostly useful for debugging MIDI file parsing problems. |
||||||
* the next note change. The other 7 bits and the 8 bits of the following byte are |
|
||||||
* interpreted as a 15-bit big-endian integer that is the number of milliseconds to |
-pi Ignore notes in the MIDI percussion track 9 (also called 10 by some) |
||||||
* wait before processing the next command. For example, |
|
||||||
* |
-r Terminate the output file with a "restart" command instead of a "stop" command. |
||||||
* 07 D0 |
|
||||||
* |
-sn Use bytestream generation strategy "n". Two are currently implemented: |
||||||
* would cause a delay of 0x07d0 = 2000 decimal millisconds, or 2 seconds. Any tones |
1:favor track 1 notes instead of all tracks equally |
||||||
* that were playing before the delay command will continue to play. |
2:try to keep each track to its own tone generator |
||||||
* |
|
||||||
* If the -d option is specified, the bytestream begins with a little header that tells |
-h Give command-line help. |
||||||
* what optional information will be in the data. This makes the file more self-describing, |
|
||||||
* and allows music players to adapt to different kinds of files. The later Playtune |
-delaymin=x Don't generate delays less than x milliseconds long, to reduce the number |
||||||
* players do that. The header looks like this: |
of "delay" commands and thus make the bytestream smaller, at the expense of |
||||||
* |
moving notes slightly. The deficits are accumulated and eventually used, |
||||||
* 'Pt' Two ascii characters that signal the presence of the header |
so that there is no loss of synchronization in the long term. |
||||||
* nn The length (in one byte) of the entire header, 6..255 |
The default is 0, which means timing is exact to the millisecond. |
||||||
* ff1 A byte of flag bits, three of which are currently defined: |
|
||||||
* 80 velocity information is present |
-releasetime=x Stop each note x milliseconds before it is supposed to end. This results |
||||||
* 40 instrument change information is present |
in better sound separation between notes. It might also allow more notes to |
||||||
* 20 translated percussion notes are present |
be played with fewer tone generators, since there could be fewer |
||||||
* ff2 Another byte of flags, currently undefined |
simultaneous notes playing. |
||||||
* tt The number (in one byte) of tone generators actually used in this music. |
|
||||||
* |
-notemin=x The releasetime notwithstanding, don't let the resulting note be reduced |
||||||
* Any subsequent header bytes covered by the count, if present, are currently undefined |
to smaller than x milliseconds. Making releasetime very large and notemin |
||||||
* and should be ignored by players. |
small results in staccato sounds. |
||||||
* |
|
||||||
* Len Shustek, 4 Feb 2011 and later |
-attacktime=x The high-volume attack phase of a note lasts x milliseconds, after which |
||||||
* |
the lower-volume sustain phase begins, unless the release time makes it |
||||||
|
too short. (Only valid with -v.) |
||||||
|
|
||||||
|
-attacknotemax=x Notes larger than x milliseconds won't have the attack/sustain profile |
||||||
|
applied. That allows sustained organ-like pedaling. |
||||||
|
|
||||||
|
-sustainlevel=p The volume level during the sustain phase is p percent of the starting |
||||||
|
note volume. (Only valid with -v.) |
||||||
|
|
||||||
|
-scorename Use <basefilename> as the name of the score in the generated C code |
||||||
|
instead of "score", and name the file <basefilename>.h instead of |
||||||
|
<basefilenam>.c. That allows multiple scores to be directly #included |
||||||
|
into an Arduino .ino file without modification. |
||||||
|
|
||||||
|
Note that for backwards compatibility and easier batch-file processing, the equal sign |
||||||
|
for specifying an option's numeric value may be omitted. Also, numeric values may be |
||||||
|
specified in hex as 0xhhhh. |
||||||
|
|
||||||
|
*** THE SCORE BYTESTREAM |
||||||
|
|
||||||
|
The generated bytestream is a series of commands to turn notes on and off, |
||||||
|
change instruments, and request a delay until the next event time. |
||||||
|
Here are the details, with numbers shown in hexadecimal. |
||||||
|
|
||||||
|
If the high-order bit of the byte is 1, then it is one of the following commands, |
||||||
|
where the two characters are a hex representation of one byte: |
||||||
|
|
||||||
|
9t nn [vv] |
||||||
|
Start playing note nn on tone generator t, replacing any previous note. |
||||||
|
Generators are numbered starting with 0. The note numbers are the MIDI |
||||||
|
numbers for the chromatic scale, with decimal 69 being Middle A (440 Hz). |
||||||
|
If the -v option was given, the third byte specifies the note volume. |
||||||
|
|
||||||
|
8t Stop playing the note on tone generator t. |
||||||
|
|
||||||
|
Ct ii Change tone generator t to play instrument ii from now on. This will only |
||||||
|
be generated if the -i option was given. |
||||||
|
|
||||||
|
F0 End of score; stop playing. |
||||||
|
|
||||||
|
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 |
||||||
|
the next note change. The other 7 bits and the 8 bits of the following byte are |
||||||
|
interpreted as a 15-bit big-endian integer that is the number of milliseconds to |
||||||
|
wait before processing the next command. For example, |
||||||
|
|
||||||
|
07 D0 |
||||||
|
|
||||||
|
would cause a delay of 0x07d0 = 2000 decimal millisconds, or 2 seconds. Any tones |
||||||
|
that were playing before the delay command will continue to play. |
||||||
|
|
||||||
|
If the -d option is specified, the bytestream begins with a little header that tells |
||||||
|
what optional information will be in the data. This makes the file more self-describing, |
||||||
|
and allows music players to adapt to different kinds of files. The later Playtune |
||||||
|
players do that. The header looks like this: |
||||||
|
|
||||||
|
'Pt' Two ascii characters that signal the presence of the header |
||||||
|
nn The length (in one byte) of the entire header, 6..255 |
||||||
|
ff1 A byte of flag bits, three of which are currently defined: |
||||||
|
80 volume information is present |
||||||
|
40 instrument change information is present |
||||||
|
20 translated percussion notes are present |
||||||
|
ff2 Another byte of flags, currently undefined |
||||||
|
tt The number (in one byte) of tone generators actually used in this music. |
||||||
|
|
||||||
|
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. |
||||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Loading…
Reference in new issue