Song initialisation and looping
What it is#
Making a module start and loop correctly in any player — the "finishing touch" most often forgotten, according to catspaw: default speed, tempo and pan positions in the song header apply only once, so a song whose last pattern slows to AFF for a pause, or fades the global volume to 0, comes back around at speed 255 or in silence (source: s-tw058-the-finishing-touches).
How to do it#
ST3 / Impulse Tracker#
Put a silent dummy pattern first in the order list:
1 | ^^^ .. .. X3C | ^^^ .. .. X40 | ^^^ .. .. T7D | ^^^ .. .. A06 |
2 | ... .. .. C00 | ... .. .. .00 | ... .. .. X44 | ... .. .. X40 |
^^^ cuts anything still ringing from the previous loop, Xxx sets each channel's pan (works in S3M too), T7D/A06 set tempo 125 and speed 6, C00 breaks to the real first pattern after a fraction of a second. If you fade the global volume out at the end, reset it here too (volume-slides). At the end, put C00 on the same row as the final AFF so the pause lasts one slow row and the song restarts; give the Cubic player a row or two of AFF before the break because it stops on C00 immediately.
Jumps and breaks by format (sources: s-protracker-23d-help, s-ft2-manual, s-st3-manual, s-openmpt-manual-effect-reference, s-openmpt-manual-compatible-playback): ProTracker Bxx jumps to a hex position and "also perform[s] a pattern-break" — "you can use this command instead of restart as on Noisetracker"; Dxx breaks to a decimal line; F00 stops the song. FT2 Dxx takes a hex row (D16), and its E60 loop start has a bug: the next pattern begins on the loop row unless the pattern ends with D00. ST3 Bxx is hex, Cxx decimal, SB0/SBx loops never cross patterns. IT/OpenMPT: Bxx + Cxx on one row jump into the named pattern at the named row; a Bxx right of a terminating SBx cancels the loop. Song length in MOD is "one more than the last position" and NoiseTracker's restart byte is unused by ProTracker.
Transitions#
Don't jump the speed (A06 → A07) in the middle of a melody; slide the tempo down over the last beats (T7A … T64) and restore it with the new speed on the next pattern — tempo changes leave frame-based effects (volume slides, retrigs) intact.
Chip trackers: the loop is in the orderlist, and it does not reset state#
On the C64 there is no song header to fall back on — the tune is code with an init entry point that runs once (init at the load address with the subtune number in A, then play every frame) and an orderlist that jumps back on itself (source: s-sid-wizard-manual; sid-player-routine). Everything the init call does not set is whatever the last pass through the song left behind. Three documented cases, and they agree:
- goattracker: the orderlist ends with an
RSTendmark carrying a restart position, and its TRANSPOSE entries are "reset only at song start" — so a transpose written near the end of the list is still in force on the next lap unless the list re-states it. Two editor rules go with it: TRANSPOSE must precede REPEAT, and the entry beforeRSTmust be a pattern or the editor halts playback (source: s-goattracker-readme). - sid-wizard: orderlist values are
$01–$7Fpattern,$80–$8F/$90–$9Ftranspose down/up ($90= original),$A0–$AFmain volume,$B0–$EFtrack tempo,$FEend (the track halts) and$FF xxjump to position xx — and each track has its own list and advances independently, so each has its own loop point and they need not be the same length (sources: s-sid-wizard-manual, s-duet-research-sidwizard). Transpose, volume and tempo are orderlist entries, which is the cure: re-state them at the jump target rather than trying to undo them at the end. - The drivers do it the same way, bugs included. In Charles Deenen's Maniacs of Noise player
$ffrestarts the sequence without resetting the transpose (source: s-realdmx-deenen-test-tunes); in Johannes Bjerregaard's,$FFrestarts all three voices at once, so one voice's loop point is the song's (source: s-realdmx-bjerregaard-player). The Dominator player separates the two endings outright:$FFrepeats the track,$FEends the music — and$FEtriggers an automatic fade, storing$5FinFADEand decrementing$D418every$5Fframes until the tune-number flag clears (source: s-sidin14-dominator-player).
The rule that follows is the same one catspaw gives for modules, stated in registers: anything sticky — transpose, main volume, tempo, filter state — must be re-stated at the loop target, not merely avoided at the end.
LSDj#
Playback only stays in sync if every channel has something to play from the top: Infu keeps silent chains — chain 7F holding the empty phrase FE, used as 7E (a short bridge) and 7D (a full-length chain) — in every gap of the song screen, with the same number of phrases as the neighbouring chains, so START works from any row (source: s-infu-getting-started-with-lsdj). Grooves added at the end of a phrase must be taken back (H00, or a G back to the default) so the next phrase starts on beat 1 (source: s-intense-tech-07-groove-and-tick-tricks-part-2).
H is both the loop and the ending: in a phrase H00–H0F hop to the next phrase at the given step (H00 on step C is how you compose in 3/4), H10–HFE hop back within the phrase — first digit how many times, second digit the destination step — and HFF stops the song, or just that channel in live mode (source: s-lsdj-manual). Without an HFF the song screen simply plays its chain lists top-down and comes round again, so the sticky-state rule above applies to LSDj too: a T, M or G set late in the song is still set on the next lap.
Tips & pitfalls#
- Test the loop, not the song. The failure is invisible on a first play-through by construction: every one of the cases above sounds right until the second lap.
- A fade-out and a loop are different endings. A module that fades the global volume must reset it in the dummy pattern (source: s-tw058-the-finishing-touches); a driver that fades on its end-marker will not come back at all (source: s-sidin14-dominator-player).
- Players disagree about the last row. Give the Cubic player a row or two of
AFFbefore the break, because it stops onC00immediately (source: s-tw058-the-finishing-touches); FT2'sE60needs aD00at the end of the pattern (source: s-openmpt-manual-compatible-playback).
Related#
volume-slides · arrangement · orderlist · tracking-workflow · sid-player-routine · multispeed
Sources#
s-tw058-the-finishing-touches · s-infu-getting-started-with-lsdj · s-intense-tech-07-groove-and-tick-tricks-part-2 · s-protracker-23d-help · s-ft2-manual · s-st3-manual · s-openmpt-manual-effect-reference · s-openmpt-manual-compatible-playback · s-goattracker-readme · s-sid-wizard-manual · s-duet-research-sidwizard · s-realdmx-deenen-test-tunes · s-realdmx-bjerregaard-player · s-sidin14-dominator-player · s-lsdj-manual