Protracker Module

From MultimediaWiki
Jump to navigation Jump to search
  • Extension: mod

Originally a 15-sample format, it was first used in Ultimate SoundTracker for the Amiga. Since then, it has been used in NoiseTracker and ProTracker, which both use the 31-sample "M.K." version, as well as many other programs on many other platforms; for example, FastTracker 2 for MS-DOS on the PC, which can handle even numbers of channels from 2 to 32.

File Format

The format is big-endian (most significant byte first). A "byte" is 8 bits, and a "word" is 16 bits. Hex values will be denoted with a $ sign.

Amiga limits for periods are 113 <= x <= 856. The lower the period, the higher the pitch.

  • 20 bytes: Module name, padded with NULs.
  • 31 samples (or 15 if we're dealing with a SoundTracker file):
    • 22 bytes: Sample name, padded with NULs.
    • Word: Length of sample in words - multiply by 2 to get length in bytes.
    • Byte: Finetune value ranging from $00 to $0F as a signed nybble. $01 is 1/8 of a semitone up, $0F is 1/8 of a semitone down, $08 is 8/8 of a semitone down (that is, a whole semitone). Periods should be clamped to within Amiga limits.
    • Byte: Default volume of sample ranging from 0 to 64 ($00 to $40).
    • Word: Loop start in words.
    • Word: Loop length in words. If set to 1, don't loop. Allegedly, a value of 0 will crash an Amiga.
  • Byte: Order list length.
  • Byte: Traditionally $78 in SoundTracker. Was used in NoiseTracker as a restart point. ProTracker uses $7F. FastTracker uses it as a restart point, whereas ScreamTracker 3 uses $7F like ProTracker. You can use this to roughly detect which tracker made a MOD, and detection gets more accurate for more obscure MOD types.
  • 128 bytes: Order list. Only the first order list length orders are actually used when playing; however, we scan the WHOLE order list to find out what the highest-indexed pattern is, and that's how many patterns we load.
  • 4 bytes (31-sample version only): Sample tag. If this contains any non-ASCII ($20 to $7E (32 to 126) inclusive) characters, then we probably loaded a 15-sample MOD. The best way to detect this is to seek to this position (it's $438 / 1080) and check before you actually load any data (may not work for streams where you can't seek). Otherwise, it's probably a 31-sample MOD. Values include:
    • M.K. - standard 4-channel, 64-pattern-max MOD.
    • M!K! - ProTracker will write this if there's more than 64 patterns,
    • 6CHN, 8CHN - 6-channel and 8-channel MODs, respectively. These are common extensions, and many trackers will write these. Basically, you read like a 4 channel mod, but with 6 or 8 channels per row.
    • CD81, OKTA, OCTA - other 8-channel MOD tags. First two are probably Oktalyzer for the Atari ST, the third is possibly OctaMED.
    • xxCH - a 10+ channel MOD, xx being a decimal number. FastTracker will deal with these as long as x is an even number no greater than 32.
    • 2CHN - a 2 channel MOD. This is handled by FastTracker.
    • xxCN - another 10+ channel MOD, xx being a decimal number. Allegedly TakeTracker writes these.
    • TDZ1, TDZ2, TDZ3 - allegedly this is a TakeTracker extension for 1, 2, and 3 channels respectively.
    • 5CHN, 7CHN, 9CHN - allegedly this is a TakeTracker extension for 5, 7, and 8 channels respectively.
    • FLT4 - StarTrekker 4-channel MOD.
    • FLT8 - StarTrekker 8-channel MOD. Load patterns in like a normal 4-channel MOD, and then play two patterns at the same time (e.g. if 8 appears on the order list, play patterns 8 and 9). You'd probably be best to merge the patterns together if you want to be consistent.
    • M&K! - only sighted on echobea3.mod so far. This is just a standard MOD, but with a weird tag. I (GreaseMonkey) cannot find the tracker it's referring to ("fleg's module train-er"), so it was probably only used once or something, and never released.
  • Pattern data:
    • Read 4 bytes for a cell. Read channel count cells for a row. Read 64 of these rows for a pattern. Read pattern count of these patterns.
    • You read cells as if they were big-endian 32-bit values.
    • Cells are in the format $ipppjfxy:
      • $ppp is the period value. No, not the note, the period.
      • $ij is the sample number.
      • $fxy is the effect, $f being the effect type, and $xy being the effect parameter.
  • Signed 8-bit mono sample data. Remember those sample lengths? Now is the time to use them.

Playback notes

Amiga base clock is roughly 70ns, yielding an audio base clock of 280ns. The actual base clock differs. PAL Amigas have a slightly slower clock than NTSC Amigas. This value of 70ns is close to the NTSC clock, but not quite right. Some modules have large samples (known as "megasamples") which require a certain type of Amiga - t_o_t.mod, for instance, requires a PAL Amiga, whereas cd_orbit.mod requires an NTSC Amiga. You can also use 8363*428 for another estimate.

To get the actual note frequency, divide the Amiga base clock by the period number.

There is a number of ticks per row, often just referred to as the speed.

There is a number of "beats per minute"; however, this is a CIA clock speed (it's an Amiga thing). Often just referred to as the tempo. To convert to actual BPM, multiply by 4 and divide by 10. For clarity, we'll refer to it as BPM, even though it's not entirely correct.

When a looped sample is played, the whole sample plays through once, and then, if it has a loop, the loop is repeated.

On a real Amiga, when a nonlooped sample is played, the whole sample plays through once, and then doesn't play any further. If you then attempt a slide-to-note (3xx / 5xy), you won't hear anything.

If a sample is supplied, then the sample is "latched", the channel volume is reset to the sample's default volume, and the starting offset is reset to 0. ProTracker 1.1 (?) will change the sample, too, but other versions do not.

(please clarify: which trackers do this?)

ImpulseTracker also changes the sample; however, if you're converting MOD to IT yourself and you don't want this, you can put a "note off" with the sample and it will just change the volume (unfortunately, this behaviour does not work correctly with libmodplug or SchismTracker at the moment).

If a period is supplied, then the note plays from the starting offset of the current latched sample, unless there is a note slide (effect 3xx or 5xy).



Arpeggio between 0,x,y semitones up, changing every tick, and retriggering every row. Basically, you select by using tick % 3 where % is the modulo operator.


Slide up. For every nonzero tick, decrement the period by $xx, clamping to 113 (amiga limits).


Slide down. For every nonzero tick, increment the period by $xx, clamping to 856 (amiga limits).


Slide to note. For every nonzero tick, move the period $xx closer to the target period.

If xx is 0, then use previous value for 3xx.


Vibrato. x is speed, y is depth. You'll need to generate 3 waveforms beforehand, and spew out random numbers for the last choice of waveform. Each waveform other than the last has a full cycle of 64 steps, and the amplitude is somewhere between -y and y after calculating. When precalculating the waveform, an amplitude of 64 should be fine.

  • Waveform 0 is a sine wave. This is the default.
  • Waveform 1 is a downwards saw wave.
  • Waveform 2 is a square wave, starting from +y.
  • Waveform 3 is random. The cycle of this is mostly irrelevant. In saying this, the speed value is irrelevant with this waveform type, too.

You have a vibrato waveform position. By default, this retriggers for every note (?) you play by being reset to 0. This loops around a cycle of 64 positions.

(please clarify: is it per note or per sample, or will either retrigger it?)

For each tick, we add y to the output period at the peak amplitude. For a waveform with peak amplitude of 64, for example, we would add (y*waveform[pos]/64). The period is clamped to Amiga limits.

If xy is 0, then use previous value for 4xy.


Volume slide + slide to note: Axy and 300 combined.


Volume slide + vibrato: Axy and 400 combined.


Tremolo. x is speed, y is depth. Like vibrato, except we modify the output volume. The volume is clamped to 0 <= vol <= 64.

(please clarify: is the maximum amplitude ~16, ~32 or ~64?)

If xy is 0, then use previous value for 7xy (?).

(please clarify: does the memory work for tremolo, or just vibrato?)


FastTracker panning extension. $00 is hard left, $FF is hard right.

(please clarify: I really don't give a toss about this FastTracker extension, so I'm putting this question out to someone who does. Does this reset after a new note or sample? And probably some other things, too.)


Set sample offset to xx * $100. This also sets the sample starting offset. On older versions of ProTracker (PT < 3.15 (?)), the starting offset is doubled.

(please clarify: what players perform this quirk?)

On most non canonical trackers (those which aren't in the SoundTracker -> ProTracker line, e.g. FastTracker, ScreamTracker 3, ImpulseTracker), this quirk does not occur, and the starting offset is always 0.

(please clarify: what happens when you go over the edge?)


Volume slide. Happens every nonzero tick. If x is 0, slide down by y. If y is 0, slide up by x. If both are nonzero, do nothing. Clamp to 0 <= vol <= 64.

Unlike most module formats, this does not have effect memory. If xy is $00, then don't go anywhere.


Jump to offset. If you go over the edge, then the module is restarted (?).

(please clarify: does it actually restart?)


Set volume. If greater than 64, then... (?)

(please clarify: does it clamp the value at 64, or does it ignore the dud volume? My guess is this: it drops the top bit, and does the former. But that's the lazy way.)


Jump to row x*10 + y. THE VALUE PROVIDED IS IN DECIMAL! This had to be yelled out as it's a common mistake when making a MOD player.


If x is 1, turn the Amiga filter off. If x is 0, turn it on. This filter is present on the A500, A2000, and A1200.

For a simple 1-pole low-pass filter, 11500Hz gives a fairly decent estimation.


Fine slide up. Like 1xx but without effect memory and only on the first tick.


Fine slide down. Like 2xx but without effect memory and only on the first tick.


Screw up 3xx.

(please clarify: how does this actually work?)


Set vibrato waveform. x & 3 (bottom 2 bits) sets the waveform type. If bit 2 is set (x & 4), then don't retrigger the waveform.


Set finetune value for the current sample.

(please clarify: when does this actually kick in?)



If x is 0, then set the loopback point to the current row. The loopback point is reset to -1 for every Bxx or Dxx or pattern transition (?). Looping back with this means that you have to play row 0 twice.

(please clarify: is MikMod right?)

Otherwise, we check if the loopback counter set. If the loopback counter is set, then decrement it by 1, otherwise set the counter to x.

After doing this, if the counter is not 0, then we jump back to the loopback point.

Unlike S3M and IT, the loopback point remains where it is, so an E60/E61/E61 sequence down a column will result in an infinite loop.

Each channel has its own set of loopback counters.


Set tremolo waveform, like E4x.


Another stereo extension. $0 is hard left, $F is hard right.

(please clarify: I don't care about this extension, either. It's far from "real Amiga" material. Please see 8xx for the clarifications required.)


Retrigger note every x ticks.

(please clarify: does this effect retrigger like IT, or is this just a matter of ticks % x ?)


Fine volume slide up. For the first tick, increment the volume by x, clamping x to <= 64.


Fine volume slide down. For the first tick, decrement the volume by x, clamping x to >= 0.


Note cut. On the xth tick, set the volume to 0.

(please clarify: what happens when x >= TPR?)

(please clarify: what happens when x == 0?)


Note delay. Don't do what's in the cell until the xth tick.

(please clarify: is there anything which escapes this check?)

(please clarify: what happens when x >= TPR?)

(please clarify: what happens when x == 0?)


Row delay. Repeat the row x times, e.g. if x is 3, then do the row 4 times in total.


Funkrepeat. This is rarely implemented because not everyone knows how to use it and those who do generally think it's "nasty" as it overwrites sample data. Some might say this is incredibly rare; however, it appears to be more common than E3x.

What this thing actually does is it, for every tick, increases a counter, and once that counter crosses over a certain point, it "inverts" a byte in the current playing(?) sample's loop (a logical NOT), resets the counter to 0, and moves along to the next byte, wrapping around if necessary. It does not affect samples which don't have loops in them.

(please clarify: when you hit a lone sample which isn't the current one, does it affect that latched sample or the playing sample?)

So, here's a list which can be added to. The bigger this list, the more pressure MOD player authors will get until they finally implement this under-implemented effect.

List of MODs which use EFx
  • emax-doz.mod
  • emax-seq.mod

In most cases, a MOD which uses EFx is a chiptune.

In most cases, a MOD which uses EFx needs it (for epicness purposes mostly).

Firstly, you'll want this table. This tells you how much to increment the internal counter by, and is in the ProTracker v1.2 source code.


This roughly correlates to this number of ticks:

  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E   F - x
  0, 5, 6, 7, 8,10,11,13,16,19,22,26,32,43,64,128 - counter
inf,26,22,19,16,13,12,10, 8, 7, 6, 5, 4, 3, 2,  1 - ticks

If x is 0, then reset that channel's funkrepeat counter and funkrepeat position to 0. Otherwise, set that channel's funkrepeat speed to funkrepeat_table[x].

If a channel is not funkrepeating, then you don't need to do what follows for that channel.

For every tick, increment the channel's funkrepeat counter by its funkrepeat speed. If the funkrepeat counter reaches 128, then reset the counter to 0, and then:

sampledata[current_sample][loop_begin_in_bytes + funkrepeat_pos] ^= 0xFF;
funkrepeat_pos = (funkrepeat_pos + 1) % loop_length_in_bytes;

^ is the XOR operator in C. There's also ~ for a binary NOT, but ~= probably isn't valid C.

Every time you reach a new sample (?) value, reset that channel's funkrepeat position to 0, and start modifying the new sample (?).

(please clarify: does the funkrepeat sample position retrigger on sample, note, either, or both?)

(please clarify: there's probably a lot of mistakes in this.)


Set TPR or BPM. If xx is less than $20 (32) or this is an old 15-sample module (?), set TPR to xx, otherwise set BPM to xx.

(please clarify: Where is the dividing line between raster timing and CIA timing - that is, when was BPM introduced?)

However, if xx is 0, then ignore this effect.

Optimisation tips

Try unrolling your sample loops. 2500 bytes of padding should be fine if you're operating within Amiga limits; otherwise, you'll want at least ((base clock * 10) / (smallest period value * 4 * 32)) bytes. To unroll a loopless sample, just pad this number of bytes. To unroll a looped sample, append the loop to the end, then unroll this number of bytes from the loop.

Once you've done that, you only need to check if you've exceeded (length + loop length) words (or bytes if you've converted it) for a looped sample, or length words for an unlooped sample. For an unlooped sample, you just refuse to mix if the offset is past this point. For a looped sample, you set the offset to this:

offset = length + (offset - length) % looplength;

where % is the modulo operator. Most forms of BASIC do not have a modulo operator, so you'll probably have to do this instead:

tmp = offset - length;
offset = length + tmp - (int(tmp / looplength) * looplength);

This makes funkrepeat trickier to implement, but it has been proven possible.