TODO, PLEASE UNDERSTAND THIS IS NOT FINALIZED-------
mconvert is a utility designed specifically to accommodate data preparation for use with the streaming music player. It does not perform direct conversions of raw .MID files, as this is already accomplished well by midiconv. In general the goal is to let what midiconv does well in general, and focus on the specifics of streaming music that would be messy and a bad fit to place inside midiconv.
mconvert will take the direct C array output provided by midiconv, and outputs data that is ready to be used in the streaming music player. This includes raw C arrays for direct inclusion in your game(costs flash but no buffer is required, not yet implemented), and abilities to create an SD file which contains all the music and an index to the start of individual song(the more common method). It is recommended to take a look at SPIRamMusicDemo to help understand this. There are several options available that will affect the format of the output data to your individual program needs.
mconvert takes only one argument, and that is the name of a configuration file from which it shall operate. This configuration file is of a simple format which is easy to process, that allows the tool's source code to be small and simple to understand. The options should be enough for anyone's requirements. It is important to remember that, though the tool does cope with some deviance on spaces, etc. it is recommended to exactly follow the format described to avoid possible errors. The tool can be triggered from the command line like so:
It is likely better to call it directly from your makefile, so that you do not need to manually intervene when things change. This is similar to what you will find in the tutorial for gconvert, in the makefile integration section: Generating Tiles and Maps with gconvert
... ## Objects explicitly added by the user LINKONLYOBJECTS = ## Include Directories INCLUDES = -I"$(KERNEL_DIR)" ## Build all: SDMUSIC.DAT $(TARGET) $(GAME).hex $(GAME).eep $(GAME).lss $(GAME).uze size ## Regenerate the music SD image SDMUSIC.DAT: ../data/song1.inc ../data/song2.inc mconvert ../data/SDMusicImage.cfg ## Compile Kernel files uzeboxVideoEngineCore.o: $(KERNEL_DIR)/uzeboxVideoEngineCore.s $(CC) $(INCLUDES) $(ASMFLAGS) -c $< ..
The format of this file is not nearly as fancy or flexible as the xml found in gconvert. The source code is smaller, and uses nothing but the standard C library(and therefore easier to understand quickly) while doing everything that is required to get the job done: that is the reasoning behind this perhaps questionable design decision versus a full blown big xml setup. Lets look at an example of a configuration file:
1,512,1,MUSIC.DAT, ../tools/mconvert/song1.inc,0, ../tools/mconvert/song2.inc,3, ../tools/mconvert/song3.inc,0,
That is it. It should handle some minor changes from the ideal format, but it is wise to simple use this format to avoid potential issues. Do no put a newline after the last 0, in this example, to avoid what will appear like the start of a new entry to the simple parser. Let's think about what these arguments mean.
The first line is the setup line which will dictate some things about how the entries will be processed. The first byte, '1' in this case, specifies to use the binary format as opposed to the C array hex format. This is expected to be the most common choice, and if you are doing SD/SPI Ram streaming you need this. 0 is for the flash version(not yet implemented). The second number "512" represents where the first output byte of the first converted song will start at. 512 is a good location for most things. The next song will start immediately after the data for the first song. It is important to remember that for each converted song, mconvert will automatically fill in directory values starting from 0 and moving up 4 bytes for each entry towards your music data. This allows songs to be anywhere in an image, and your code to easily be able to find them. 512 is an arbitrary choice that leaves lots of room, and has potential performance benefits in the case of SD streaming. The next item after this, '1' in this case, specifies whether the tool should apply padding to the end of songs. The padding, if enabled, will ensure that the total number of bytes output for each song is an even multiple of 512. These padding bytes will all be 0xFF(they should never be reached in a proper song, but if they were, this value would stop the song). The reason for padding out the data is primarily intended to help with SD streaming. SD cards have a penalty for crossing a 512 byte sector, and you also cannot start reading except directly on a sector boundary. By having all the music start on sector boundaries, the amount of wasted byte reads can be minimized which increases performance.
Each line after that is just 2 arguments. The first argument is the path to the song file which you wish to convert. The order the song will be written in the directory is implied by the order you specify them in the configuration file. The second value, if a bit cryptic, is mainly aimed at advanced users...advanced MIDI users that are too lazy to delete spurious MIDI events from their source material ;) This is a decimal representation of a byte which is used as binary flags. These individual bits can be used to eliminate specific controller events from the stream, which can help improve performance and will likely not be missed. The flags can be OR'ed together in any configuration. The values are as so:
#define FILTER_CHANNEL_VOLUME 1//filter out channel volume events #define FILTER_EXPRESSION 2//filter out expression events #define FILTER_TREMOLO_VOLUME 4//filter out tremolo volume events #define FILTER_TREMOLO_RATE 8//filter out tremolo rate events #define FILTER_NOTE_OFF 16//filter out all NOTE_ONs which have a volume of 0(that is how Uzebox does "NOTE_OFFs")
For those not familiar with bit flags I highly recommend taking the time to understand them, it's simple, but basically you can just add these flags together. If for instance you want to eliminate all channel volume events and also all tremolo volume events, you would specify 5 for the value here(1+4). If you want to eliminate spurious expression events(common with the NSF->MIDI method shown in Music Step By Step) as well as all tremolo rate events and note off events, specify the number 26 which is 2+8+16
This tool should be rather easy to use, and hopefully will do everything that is required to generate data which is usable in your game. If you need an extra feature, notice a bug, or just have a question, please feel free to address this in the streaming music thread on the forums. Thanks for reading, and I hope you enjoy the possibilities of limitless music in your game!
You may also be interested in the possibility of streaming PCM simultaneously as you stream music. If you can afford the ram in your game to include the vsync mixer, you can enjoy some massive resource offloading bliss! If that sounds interesting, check out Streaming PCM.