MMK is a language designed by nobody1089 to make it easier to move note data, both within a channel and between channels. Instead of placing notes into channels, they are placed into segments which can be placed anywhere.
Tracks are single instrumental tracks made up of multiple segments. Tracks can be shuffled between channels at segment boundaries; segments are printed entirely in one channel. Tracks usually consist of a single instrument. If there is a temporal gap, the settings are carried over, but I’m not sure if it should be considered part of the same track or not. Tracks can be printed as-is in a single channel, or a segment can be printed in a different channel, and the MMK parser will automatically initialize the instrument, volume, and pan settings.
Additionally, the MMK parser supports scaled volumes and panning. Scaled volumes are multiplied by a configurable multiplier. Scaled pan values are processed by first subtracting a configurable "center" value to normalize around zero, then multiplying by a configurable scale factor, then adding 10 to center the panning. If the panning value is increasing-right (like normal), you must use a negative scale factor to convert to increasing-left.
The MMK parser only saves the state when a new segment is defined. State is only used for determining %vs and %ys and reinitializing segments when moving to a different channel. All commands (including %vs and %ps) are evaluated at define-time, not print-time. If you print a segment after changing the volume scale factor, the volumes within the segment will not be rescaled.
In the future, I will add more easily readable pitch and volume bend commands. Really, this should be a feature natively in AddMusicK. I think one possible reason it's missing is because AddMusicK apparently doesn't support multi-letter keywords, and Kipernal ran out of letters. It's about time to add native multi-letter commands to AMK.
At the current moment, the actual program includes all functionality included in this readme, but is almost entirely untested and not publicly available (yet). Both the spec and the program will evolve as I receive feedback.
Outputs to “infile.out.txt”
Outputs to “infile.first.second.out.txt
mmk_parser.py infile.txt infile2.txt
Outputs to “infile.out.txt”.
When you supply multiple input arguments, they are concatenated.
You can use this to hide boilerplate headers and instrument declarations, so you won’t have to scroll through them when looking for part of the song.
You can also do that to divide the song into multiple files, each containing several related tracks, and open each in a tab in Notepad++.
mmk_parser.py infile.txt –o outfile.txt
Outputs to “outfile.txt”
Each MMK file has a header:
In future versions, the header may increase when new features are added.
Next, you add all headers that appear before note data, not including tempo or channel definition.
"whatever.brr" $00 $00 $00 $00 $00
In a normal AMK file, you then proceed with a list of channels followed by note data.
In a MMK file, you follow with a series of segments. Each segment is a single unit of data which can be inserted into one or more places in the timeline. If you want a single line of music split into multiple tracks, all you need to do is to put a %segment command wherever you want to split and then redefine the octave afterwards. The recommended naming convention is the name of the instrument/part, disambiguation if necessary (low or high, etc.), followed by the starting measure (zero-indexed). I’m not sure if there’s a good way to indicate the length of a segment.
Use “%v 128” to set the volume. (See footnote ) This inserts “v128” into the segment and also memorizes the volume. The memorized information is only ever used when you split a track into a new channel. Note that using %v is only strictly necessary in segments not followed by a %reset, only for the last volume change. I still recommend using the %v/s commands at all times, except when you have a track with only one segment, then it’s just a waste of typing.
Scaled volumes use command "%vs 64" are multiplied by a configurable multiplier. The multiplier is immediately evaluated and the corresponding “vxx” keyword added. This initializes the %vs command so you can adjust the entire channel's volume at once. (See footnote ) Note that the scaled volume command is %vs instead of %v. Depending on user feedback, I may merge both into %s command and default to a scale factor of 1.0, which is identical to unscaled.
Similarly, there is both a standard pan command (%y 10) and a scaled pan command (%ys 64).
%p 10 %ps 64
Before you use scaled volumes, you must first define the scale factor for the volume. You can use either a decimal or a fraction (no spaces allowed):
%setvolscale 3.14159/2.71828 (yes this is pi/e) (pun not intended)
Pan scale factors are slightly different. It has two values. The first number is the center value of the original pan (64 for MIDI pan values), and the second number is the scale factor. Both can be integers, decimals, or fractions (no spaces allowed), though the first one will most likely be an integer. The exact formula for scaled panning is (%ps - center) * scale + 10 . SMW panning increases from right to left, MIDI panning increases from left to right, so use a negative scale factor.
%setpanscale 64 -5/64
This formula converts from MIDI panning into half-scale SMW panning (Full-scale panning would result in the quieter channel becoming entirely silent, not good). If you do not provide a scale factor, it will assume these factors. (I don’t like the idea of silently ignoring missing commands and may add an “initialize default panscale” command instead.
Use the %instr command to define the instrument used in the channel. Note that this must either be a @xx or a previously defined macro. This example uses a macro defined in the header. Treat it exactly like the “%instr” header doesn’t exist.
Then you add music data like normal. The data is placed into a segment, which can be printed at any position within the channel declarations.
When you start a new segment, it retains the settings of the previous one (pan, volume, and their respective scale factors).
A single track is broken into a new segment whenever it must be moved into a new channel. The octave must be redeclared, the volume, pan, and instrument are memorized and do not need to be redeclared.
“piano0” and “piano2” are two segments in a single track.
c4 < b4 a4 g4
f4 e4 d4 c4
The %reset command resets the vol (%v %vs), pan (%y %ys), volscale, panscale, and instr to default. It is designed to be paired with %segment. In future versions, I may provide individual reset functions, but I’m too lazy to do a 5-minute change and somewhat reluctant of making the source code even messier.
%instr @0 %y 10
The %passthrough command ends the previous segment and redirects subsequent text directly to the output. This is used to assemble the segments.
When reassembling the music into a final file, use the %miniprint command to print a segment. It should be used for the first segment of a track, and all following segments if you are in the same channel as the previous one. When you %miniprint the first segment of a track, you don’t need to print the memorized default information, because the %v xx command inserts a “vxx” directly into the beginning of the segment.
%miniprint piano0 ; Starts at measure 0 (2 measures long)
[r1]2 ; 2 measures of padding
miniprint flute4 ; Starts at measure 4 (2 measures long)
When you print a mid-track segment without the one before it, you must use %print instead of %miniprint. It prepends the correct volume and pan and instrument, but not the octave. Instead of adding an “o” command before the %print command, the correct thing to do is to go to the segment declaration and add the proper “o” command at the beginning.
[r1]2 ; 2 measures of padding
%print piano2 ; Starts at measure 2 (2 measures long)
[r1]2 ; Pad #1 to 6 measures total
Philosophy: In general, let AMK handle abstractions.
For example, it is your responsibility to redefine the octave every time you define a new segment.
I may consider adding an automatic instrument numbering system for convenience, depending on user feedback.
Parametric macros... Well, I have no choice but to do it myself.
In other words, be as lazy as possible while still creating a marginally functional end product.
If anyone volunteers to write a complete AMK parser for me, I can remove the need for a custom volume command, instead hooking the default volume command. Maybe at some point, I’ll look into the source and write a similar parser in Python. Or maybe I’ll just mod/fork AMK to include an extra preprocessing stage with functionality similar to this program. Anyone know how difficult it is to parse AddmusicML?
The %vs command is also useful for copying volumes directly from the MIDI without spending 10 seconds per note calculating the scaled volumes, 30 seconds and serious stress every time you make a mistake, and hours of head-bashing every single time you change the scale factor or realize you calculated everything wrong. Cue accusations of overcomplicating the porting procedure, when in fact skimping will result in a port of decreased quality.
MMK stands for MetaMusicK. I never refer to it as such because it looks far too much like “Metaknight”.