Article History
 
 
 
Discussion
 
544 views
 
100% damifortune
Tinymod Optimization Strategies
 

::|CONTENTS

  1. What's the most efficient module type?
  2. Basic tips and tools
  3. Space-saving tips: Samples & Instruments
  4. Space-saving tips: Pattern Structure
  5. Space-saving tips: Pattern Data, Notes & Effects
  6. Space-saving tips: Other Data
  7. See also
So, you're trying to tackle the tinymod/modXk formats, eh? It may seem like they're pretty limiting, but there are a lot of cool and interesting ways to optimize your module and cram a lot of information into a small amount of space - and plenty of best practices to ensure you're not wasting space along the way.

The smaller the format, the more critical it will be to optimize your pattern data, which is a major focus of this article. Mod04k, mod08k and mod12k will be especially reliant on careful tracking to get much of a full song written. This is simply due to the size of pattern data being generally a few bytes per item, and that's proportionally more of, say, 4KB, than it is of 64KB.

For the larger tinymods like mod32k, mod48k and mod64k, the most relevant factor in your filesize will wind up being the samples you use. You can still save space by optimizing your pattern data, of course, but it may be easier to manipulate the samples you're using to cut your module's size down.


What's the most efficient module type?



Generally it's .it, which handles empty space the best of the bunch.

.xm is viable too if you prefer, but .xm is best used if the song data is quite dense; otherwise your song may take up more space than if it were .it.

The least viable option is .mod. Tread carefully; there's no fancy compression here. It's a unique sound though, so if you want to try it, go ahead!


Basic tips and tools



* In OpenMPT's Edit menu, you will find options for "Cleanup" and "Automatic Sample Trimmer". Both of these tools can save you space and are best run near the end of your work (choose cleanup options carefully).

* If you're using .it, Munch.py is a tool that will optimize your module data even further; results may vary, but you can expect to save 0.5-1.5KB overall in the smallest formats, and potentially way more in the larger ones thanks to its sample compression*. Run your module through here at the very end! (*Note that IT sample compression is enabled by default in OpenMPT v1.31 or later, which means Munch will not make as big a difference, though it will still help in other ways.)

* Similarly, if you're using .xm, BoobieSqueezer (yes, really) is a tool that will optimize your module data even further while remaining completely playable and format-accurate.

* In OpenMPT, using "Compatibility Export" from the File menu may save a small amount of space; it's shaving away a few newer features to be better compatible with the original DOS trackers.


Space-saving tips: Samples & Instruments




Sample Size
Samples take up a lot of space. Use small, mono, 8-bit sample data. Ensure there is no extra data after the loop; it is useless space. Likewise for any silence at the start of your sample. Note that Munch.py (for .it) applies valuable space-saving compression here*, which may turn out to be a huge amount in the larger mod*k variants. But that doesn't mean you shouldn't be efficient, and you may need to do some trimming to make space without editing your patterns.

*As mentioned above, OpenMPT v1.31+ has IT lossless sample compression turned on by default, which saves a lot of space in your module without you having to do a thing! It does mean that Munch.py will ultimately do less for your module though.

If using mono 8-bit samples, their uncompressed size should equate to the number of bytes they are consuming (e.g. 7000 length sample = 7000 bytes). Compression via Munch or OpenMPT will reduce this, though. Complete silence in the middle of samples also gets compressed nicely!


Downsampling
You may be able to comfortably downsample your sounds, though they will sound flatter and flatter (losing high frequency content) each time. This reduces the sample rate of the sound, lowering its quality by reducing the number of data points per second in the audio.

In OpenMPT, use "Resample" on the sample screen--the sixth icon from the left in the big row of buttons, also mapped to Ctrl+R by default. This can also be done in Audacity by changing the "project rate" in the lower left corner.

Try it and see how small you can get them before the resulting sound becomes unacceptable to you. The default "downsample" option halves the size, but you can also input your own value to downsize in whatever proportion you desire. Compare with the "Freq. (Hz)" value listed on the lower left of the sample screen. If the value is 22000, choosing "21000" for your resample value will make it only slightly smaller, for example, whereas 11000 would halve it.

Downsampling in OpenMPT also offers different interpolation options. Generally, "r8brain (High Quality)" preserves the sample best, but you may get more interesting results with other options like "None", particularly if dealing with simpler waveforms.


Sample Trimming
Particularly if your sample loops a few periods of a waveform, consider trimming this down by either selecting a new loop point or by adjusting the position of the loop. If hunting for new loop points, the arrow buttons next to the Loop Start and Loop End values will try to seek to the nearest closely matching value to pair with the other value. You may also be able to simply subtract the same amount from both values to "nudge" the loop around while keeping it the same size.

OpenMPT does offer a "Crossfade" tool in the Samples tab - it may be also helpful when searching for a viable loop point to shore up a slight clicking sound or unwanted overtones. A couple of sliders are available to tweak its result.


Instruments
Instruments in .it take up almost 400 bytes apiece, so avoid using Instrument mode unless you plan to take advantage of the features like New Note Actions (NNAs), random volume/panning sliders, sample maps and/or the various envelopes. However they can be used very effectively with those features to achieve sounds otherwise not possible in the tinymod restrictions. If you want to learn more about designing complex .it Instruments and utilizing their more intricate features, check out the Using .it Instruments article!

If you are just using ADSR volume envelopes, they are probably best represented with Dx/Cx/Bx/Ax (vol column) or Dxy (effect column) commands - the volume column ones will be most efficient, as detailed below.

You may be able to get away with this in the larger mod*k variants but be aware of the space they consume.

Also, for maximum efficiency, make sure the order of your samples and instruments matches! Occasionally Munch.py has issues if they are out of order, too. You can reorder them in OpenMPT's "Tree" view sidebar.


Space-saving tips: Pattern Structure




The "Unmute Trick"
It is possible to save pattern space in .it by using the Mxx (Channel Volume) command to mute and unmute channels of your choice.

For example, if you wrote a pattern that you wanted to copy and add something to, you could have the Channel Volume at 0 for the first pass, then set it to a new nonzero value with Mxx for the second pass - all contained within one pattern.

Depending on the construction of your song this can be an extremely useful, invaluable trick to fitting more material into less space.

M40 is the maximum (which is 64 in hex).

A channel can start out muted by setting its volume to 0 in the General tab.

A common use of the Unmute Trick is to have an additional pattern, one row in length, containing only the necessary Mxx commands. Try using a Speed Change command of speed 1 in this tiny pattern alongside another Speed Change on the final row of the previous pattern that's 1 less than your overall speed. That way, they add up and it's as smooth as possible!

Another useful variant is to use the Nxy Channel Volume Slide command to gradually fade in (or out) the material in a new channel.


Speed
Using slower speed settings (i.e. high number of ticks per row) will help you save space overall because there will be less empty space inbetween your notes. Consider using the slowest speed you can while still being able to contain the notes you want, so as to have few (or no) blank rows. Blank rows cost you 1 byte each in .it and substantially more in .xm because each row on each channel costs space.

The speed can be briefly raised for a flourish of fast notes and then lowered again (with Axx (.it)/Fxx (.xm)).

Also, the SDx (Note Delay) command can be used for intermittent offsetting from the slow-speed grid, so give this a try if there's just a few notes keeping you away from slow speed settings working for you.


Pattern Delays
Blank rows can be trimmed by using the Pattern Delay command, SEx (.it) or EEx (.xm) in the row before the blank rows would happen. This extends the length of the row by holding in place x times, where x is the length of one row.

For example, SE1 at speed 6 would cause that row to be held for 12 ticks instead.

If there's nothing in between a bunch of rows, consider using this command and moving everything else up to fill the space!

Another way to do this is by changing the speed - for instance, setting the speed to 16 in the middle of music that's speed 4 in order to hold for four rows' worth of time, then switching back to 4. Doing it this way may consume marginally more space in comparison to the Pattern Delay, though (since it will take at minimum two effect commands).

Notably, there is a strange interaction between Pattern Delays and the Note Delay command (SDx (.it)/EDx (.xm)); if used on a row containing a Pattern Delay, the delayed note will repeat with each iteration of the Pattern Delay. At times this may be unwanted, but it can also potentially be used to your advantage (e.g. with Instrument NNAs in .it).


Pattern Loops
If there are smaller repeating chunks of pattern data (for example, you wrote a 16-row pattern where the stuff in 1-4, 5-8, and 9-12 is identical), you can save space by using the Pattern Loop command (SBx in .it, E6x in .xm).

Placing an SB0 command at row 1 and an SB2 command at row 4 will cause 1-4 to loop twice before proceeding. This is potentially a huge space-saver. In this example your pattern's length would be halved, from 16 to 8 rows.

They are also another way to potentially take advantage of the "unmute trick" in .it for adding new sounds on a second loop through something. Try placing an Mxx command alongside the second SBx, or even after it for additional unique loop passthroughs!

Pattern loops can also be nested! Try experimenting with loops inside of loops. Place the new loops on a different channel (the loop end command will always search for the most recent SBx in its own channel).

Notably for .it, the end of a Pattern Loop may behave strangely if placed on a row that contains a Pattern Delay SEx command. (This works fine in .xm however.) The loop may be ignored entirely if the value for SEx is greater than the value for the adjacent SBx. In other situations, the loop count may differ from what's written or simply loop infinitely. The rules for this appear complex, with low-value SEx (1 or 2) being more likely to cause infinite loops, especially if both effect values are odd or even.


Merging Patterns, De-Duping Patterns
You can merge/combine patterns that are only used once (or only ever used adjacently), as they may take up a few bytes more of space when separated. A new pattern will take up, at minimum, 14 bytes (one blank row).

Also, pattern separators +++ in .it take up a byte apiece (as well as any other addition to the pattern order), making them technically trimmable chaff.

However, splitting patterns out can also be beneficial to "de-duplicate" data in your module: if there are chunks of pattern data utilized in multiple places within your song, it will be beneficial to split the patterns so that the reused chunk is only stored in one place. For example: You have 16 rows of data - let's call each group of 4 rows A B C D. The "A" chunk also appears in a later pattern like A E F G; that pattern starts the same way, but the rest is different. If you split both patterns so that the "A" part is on its own, you can save space by using that pattern in both places. Since pattern data takes up so much space, this will almost certainly be worth the byte cost of a new pattern.


Space-saving tips: Pattern Data, Notes & Effects




"Continue" Commands
Do not use "continue" commands (e.g. H00, D00, etc) in .it. It is more efficient to write H44 H44 H44 than H44 H00 H00. Continue commands take up an additional byte.

Munch.py should change this for you automatically, but it is good practice to get used to it.

There can be niche use cases for "continue" commands - for example, a pattern containing only continues can be made to sound different if played after some other pattern assigning a different value. T00, the Set Tempo continue command, could be either a speed-up or a slow-down depending on whether it's preceded by T01 (-1 bpm) or T11 (+1 bpm). If doing this, you may not be able to use Munch (or at least you will have to modify the code yourself to make it not remove continues).


Repeated Commands Are Compressed
This one is a very important concept! Reuse of previous commands in .it saves space if they are used in succession--for all columns.

For example, v56 v56 v56 v56 will take up less space than v56 v12 v56 v12. But also, C-4 C-4 C-4 C-4 will take up less space than C-4 C-5 C-4 C-5.

This means that it's best to stick with constant volumes where possible, and if you are alternating between volumes or effects, separating them into their own channels is a better use of space.

Other effects will also be compressed if used without something different separating them, as detailed in the next tip, which elaborates upon this idea. How much will depend on a few details!


Volume Column vs. Effect Column
In general, for .it, volume column commands take up 3 bytes of space apiece, while effect column commands take up 4 bytes of space. Thus it is likely more efficient to put volume slide commands in the volume column (Dx/Cx/Bx/Ax).

For .xm, instead it's 1 byte and 2 bytes, respectively!

As mentioned above, compression of consecutive effects occurs in .it format - even if there are blank rows inbetween their uses.
For compression in the volume column, the first repeated effect is reduced from 3 bytes to 2, and all subsequent repeated effects get reduced to 1 byte!

For the effects column, reuse of the same type of effect (e.g. two H commands) consumes 1 fewer byte, and likewise for reuse of the same effect value (e.g. A4), regardless of the effect itself.

This means that with subsequent uses of the same effect, for example E02 E02 E02, all effects after the first consume 2 bytes instead of 4. Different values for E would change this to 3 bytes, as would different effects all using value 02.

Note that if using Hx for vibrato in the volume colum, it must be "initialized" with an Hxy effect command prior, to set the desired speed.

(An interesting niche .it case: If every successive row in a channel is identical, i.e. same note, instrument, volume and effect, the additional effects [or notes or volumes] take up no space whatsoever!)


Note Cuts
For .it users, Note Cuts ^^ may take up a little more space than using a v00 command, although this may depend somewhat on what effects you might be using in the volume column, and may be undesirable if using a New Note Action in Instrument mode other than the default Cut. If you need to do some trimming though, try swapping Note Cuts out for v00 commands.

A Note Cut (or Off or Fade) in .it will cost you 3 bytes generally, but has the potential to be compressed down to 2 if no new data is placed in the instrument, volume, or effect columns.

Meanwhile, it just costs 1 byte in .xm, the same as the cost of a volume column command, so either one works.


Instrument Column
In .it, instrument column values don't take up space either, so trimming them is not typically important. In fact, it should be discouraged if using Munch.py and Instrument mode both. This is because one of the thing Munch cuts space through is the Sample Map within the Instrument settings - all notes that the script deems "unused" get assigned a garbage value pointing to a nonexistent sample. How does it check for something "unused"? It looks for each value next to the note in the instrument column. This will probably cause some notes to make no sound at all.

This has a notable interaction if you're using Gx in the volume column and removing the value in the instrument column to keep its volume consistent (this is just a quirky .it behavior - if the previous note was at a non-default volume, the new portamento note will play at default volume unless you do this). If that new note doesn't appear anywhere else in your module, Munch will still interpret this as an "unused" note and it won't make sound in your munched module.

One of the only reasons you could bother to trim instrument column values in .it is if you're repeatedly alternating between notes and Note Cuts. The Note Cuts specifically will be compressed by 1 byte each if there's no additional data outside of the note column inbetween them.

In .xm, instrument column values do actually take up space. You can trim all but the first value that sets the instrument and shave a byte of space each.


Auto-Vibrato
Rather than using vibrato commands, the "Auto-Vibrato" setting on the sample screen can be used to automatically apply vibrato at a chosen rate, depth and "sweep" (which sets the length of time until vibrato starts happening).

This can be set for each sample individually, without even needing Instrument mode!

In .it format, rate can be 0-63 with 63 being the fastest; depth can be 0-31 with 31 being the widest; and sweep can be 0-255 with 255 making it occur immediately.

For .xm it's slightly different: rate is still 0-63 with 63 being the fastest; depth can only be 0-15 with 15 being the widest; and sweep can be 0-255 but instead the value is exactly the number of ticks until vibrato triggers, so 0 is immediately.


Space-saving tips: Other Data




Extra Channels
Extra channels do not actually take up space in .it - unless they're full, of course. A 24-channel .it file will be the same size as 1-channel if blank. (For .xm though this is definitely not true! It does not handle blank space efficiently!)


Text Fields
The song Name field in the General tab takes up no space, so feel free to indicate preferred interpolation settings here.

The Artist field, however, does take up additional space, so Munch.py will trim it away.

The name fields for samples and instruments do not take up additional space.

However, the name fields for Channels (set in the General tab) do take up space, so avoid using those.


See also



The tinymod formats:
* mod04k (format)
* mod08k (format)
* mod12k (format)
* mod16k (format)
* mod24k (format)
* mod32k (format)
* mod48k (format)
* mod64k (format)

Related formats:
* S3XMODIT (*.s3m, *.xm, *.mod, *.it)
* Amigamod (*.mod)
* ModPlugTracker Module (*.mptm)

Related articles:
* IT Module Optimisation (some more technical stuff than what's written here)

 
C A T E G O R I E S
 
 
Helper Tools