Music Code
Contents
current default music backends don't support this[edit]
--- When the OHR made the transition from BAM music to MIDI, it lost a feature that was important, even if little used (because there was no way to use it): Proper music looping (E.g. looping to the middle of a song, as in a victory fanfare)
To remedy this, a new standard for looping Midi files by means of special Midi events was implemented.
Note: To do any of this, you must have a Midi sequencer. Although this is beyond the scope of the OHR, you may want to give Anvil Studio a try (on Windows).
Easy Way: Controller 111[edit]
The OHRRPGCE keeps a special eye out for controller #111 (0x6F). In RPG Maker, this event is used to designate a loop point in the music. In other words, when the song reaches the end, it jumps back to the loop point and continues playing. This enables an author to create seamless looping.
How to add Controller 111 in Anvil Studio[edit]
- In any mode dealing with the notes (Compose, Piano Roll or Event List), navigate the cursor to where you want to insert the loop point
- Go to the Edit menu, and choose Insert MIDI Controller Event...
- Ensure that Show all controller events is checked off
- Scroll to "Event: b06f" in the Kind of event box
- Press Ok
To test it, you can import it into Custom, and play it from the Import Music menu.
Hard Way: Sysex Commands[edit]
What are SysEx events?[edit]
MIDI was designed to control devices (primarily instruments) digitally. It contains note on and off events, volume events, and a number of various controller events, for things like sustain, etc.
However, sometimes these are not enough. Some devices contain settings outside of the MIDI specs. To support these, MIDI contains a catchall "SysEx" event, which is an arbitrary length data event, whose contents are opaque to an actual midi parser, but can be interpreted by the device or program.
For more information as to how SysEx events are stored in a MIDI file, look at MIDI File Format.
The Format[edit]
Similar to how the BAM Format uses a single "code" byte to designate a type of event, Music Code does the same. However, for maximum flexibility (and because not all of the BAM codes are needed), Music Code redefines the meaning of the codes. (Note: all the codes are written in Hexidecimal)
Any Music Code sysex should begin with the following 4 bytes to indicate that it is intended for the OHR:
0x4F, 0x48, 0x52, 0x6D
This spells out "OHRm" in ASCII code. It is in Big-Endian format, so the bytes must come in the order shown.
Screenshots (of adding sysex events) needed
When the specs below refer to an INT, this is a 16-bit signed integer in Big-Endian format.
- 00 - Stop: causes the song to stop playing. Useful at the end of a song, to prevent it from automatically looping.
- 01 - Label: Followed by one (1) additional byte which designates the number of the label. In the standard implementation, the label can be #s 0 through 15 (0-F), but an extended implementation can support up to 256 labels (0-FF)
- 02 - Infinite Jump: Causes playback to jump to the designated label. Followed by one (1) additional byte which designates the label to jump to.
- 03 - Limited Jump: Causes playback to jump to the designated label a set number of times. Followed by two (2) bytes, which designate the label and the number of jumps respectively. The jump counter for that label should be decremented each time playback hits this command, until it reaches zero, at which point it should be ignored.
- 04 - Chorus Jump: Causes playback to jump to a label. Followed by one (1) additional byte which designates the label to jump to. Unlike the infinite jump, this command remembers the playback position before the jump/
- 05 - Return: If the song is in Chorus mode (command 04), this command causes playback to jump back to where it was before the chorus was entered. If it isn't in playback mode, nothing happens.
- 06 - Unset Tag: Sets a tag to off. Followed by an INT which designates the tag.
- 07 - Set Tag: Opposite of command 06.
- 08 - Set Variable: Sets a global variable to a specific value. Followed by two INTs: The global, and its new value.
- 09 - Increment: Adds a number to a global. Followed by two INTs: the global and the value to be
added.
- 0A - Decrement: Subtracts a number from a global. Followed by two INTs: the global and the value to be subtracted.
- 0B-0F - Reserved
NOTE: Due to portability concerns, commands 06 - 0A are not active in Serendipity. Hopefully, they will return in Tirgoviste.
The following commands are conditional commands. All are followed by a second command which is executed if the condition is true. Several conditionals can be "stacked" to create very specific conditions.
- 10 - If tag: If a tag is set, execute the next command. Followed by an INT specifying the tag.
- 11 - If variable equals: If a variable equals a value, execute the next command. Followed by two INTs, specifying the global and the value.
- 12 - If variable greater than: If a variable is greater than a value, execute the next command. Followed by two INTs, specifying the global and the value.
- 13 - If variable less than: Same as 12, but less than.
- 14 - If sound effect playing: If a sound effect slot is playing, execute the next command.
- 15-1F - Reserved
- 20-2F are the "NOT" versions of #s 10-1F. Note that 22 (Not greater than) would be the same as a "less than or equal" command, and vice versa.
The following commands deal with sound effects, both the loading and the playing of.
- 30 - Load sound: Loads a song into a slot. Followed by an INT specifying the song, and a BYTE specifying the slot (generally, you should stick to slots 0 - 7)
- 31 - Play sound: Plays an already-loaded sound effect. Followed by an BYTE specifying the slot, and another BYTE specifying whether or not to loop it (0 = no, anything else = yes)
- 32 - Stop sound: Stops a playing sound effect slot. Followed by a BYTE specifying the slot.
- 33 - Unload sound: Unloads a sound from a slot. Followed by a BYTE specifying the slot.
- 34-3F Reserved