MXTracker – hudební tracker pro ZX Spectrum Next
23. 8. 2026

MXTracker je AY tracker pro ZX Spectrum Next. Ukládá skladby do vlastního formátu s hlavičkou MXM8 a tenhle text popisuje, jak přesně v něm hudební data leží: co je jedna buňka patternu, proč má pattern zrovna 96 řádků, jak vypadá nástroj a jak je poskládaný celý soubor. Je to spíš technický popis než návod, takže se v něm počítá s tím, že víte, co je tracker a co je pattern.

Jedna věc se hodí říct předem, protože se bude vracet skoro v každé kapitole. Formát MXM nevznikl na papíře. Vznikl z importu PT3, tedy z toho, že jsem chtěl, aby se do MXTrackeru daly načíst existující moduly z ProTrackeru 3 a hlavně aby zněly stejně jako v originálním přehrávači. ProTracker 3 je zdaleka nejrozšířenější AY tracker na Spectru a jeho chování je de facto standard, takže pokaždé, když jsem se od něj chtěl odchýlit, jsem si tím rozbil nějaký reálný modul.

MXTracker / formát MXM

Jak MXTracker ukládá hudbu

MXTracker je AY tracker pro ZX Spectrum Next. Ukládá skladby do vlastního formátu s hlavičkou MXM8 a tenhle text popisuje, jak přesně v něm hudební data leží: co je jedna buňka patternu, proč má pattern zrovna 96 řádků, jak vypadá nástroj a jak je poskládaný celý soubor. Je to spíš technický popis než návod, takže se v něm počítá s tím, že víte, co je tracker a co je pattern.

Jedna věc se hodí říct předem, protože se bude vracet skoro v každé kapitole. Formát MXM nevznikl na papíře. Vznikl z importu PT3, tedy z toho, že jsem chtěl, aby se do MXTrackeru daly načíst existující moduly z ProTrackeru 3 a hlavně aby zněly stejně jako v originálním přehrávači. ProTracker 3 je zdaleka nejrozšířenější AY tracker na Spectru a jeho chování je de facto standard, takže pokaždé, když jsem se od něj chtěl odchýlit, jsem si tím rozbil nějaký reálný modul.

Buňka patternu

Základní jednotka je buňka, tedy jedno políčko v mřížce, které patří jednomu kanálu na jednom řádku. Má osm bajtů a ukládá se v ní jenom to, co jde v trackeru skutečně editovat. Žádná pomocná pole, žádné mezivýsledky přehrávače.

OffsetVýznam
0nota: 0 prázdná, 1 note off (===), 2 release (R--), $10+n nota n v rozsahu 0 až 95, tedy $10 = C-1 až $6F = B-8
1nástroj: 0 beze změny, jinak 1 až 32
2obálka: 0 beze změny, $80 | tvar pro tvary 0 až 14, $9F tvar 15, $8F obálka vypnuta
3ornament: 0 beze změny, jinak $80 | číslo
4hlasitost: 0 beze změny, jinak $80 | 0 až 15
5spodní nibble příkaz: 0 žádný, jinak 1 až 15; horní nibble jeho prodleva 0 až 15
6parametr příkazu, vyšší bajt
7parametr příkazu, nižší bajt

Nula všude znamená beze změny, ne nulovou hodnotu. Pro tracker je to přirozené, protože prázdná buňka nemá měnit stav, jenom pokračovat v tom, co bylo nastavené dřív. Proto je hlasitost i ornament posunutý o $80, aby šlo odlišit skutečnou nulu od prázdna. Nota má vlastní schéma, kde jedničku a dvojku zabírají note off a release a skutečné noty začínají až na $10, což je C-1. Oktávy se číslují od jedničky, takže osm oktáv končí na B-8.

Bajty 6 a 7 drží parametr příkazu jako šestnáctibitovou hodnotu, což je potřeba u periody obálky a u kroků posunů. Ve vyšším nibblu bajtu 5, tedy vedle samotného čísla příkazu, sedí ještě prodleva. To je jediné místo v buňce, které je opravdu natěsnané, a je to přímý dluh vůči PT3. Speciální příkazy tam totiž nesou navíc bajt prodlevy, který určuje, jak často se posun provede, a na prodlevu i šestnáctibitový krok zároveň už mi místo nezbylo. Než jsem to takhle zúžil, prošel jsem si testovací knihovnu 12401 příkazů z modulů, které mám k dispozici (no dobře, ručně to nebylo, napsal jsem si na to skript :) ) a žádná prodleva v ní nepřekročila 15, takže se nibble ukázal jako dostatečný.

Prodleva je na první pohled kosmetika, ale není. Nula neznamená „bez zdržení", nýbrž „efekt neběží": přehrávač má v tikacích rutinách rovnou návrat, když je čítač prodlevy nulový, takže glissando, portamento ani posun obálky s nulou nedělají vůbec nic. Výjimku dělá jen glissando ve skladbách s verzí ProTrackeru 7 a vyšší, kde se nula chová jako jednička. Kvůli tomu má prodleva v editoru vlastní kurzorový sloupec vlevo od čísla příkazu a příkaz se v mřížce vykresluje jako dvě hexa číslice. Dokud ho neměla, šla vyplnit jedině importem a ručně napsané glissando v nové skladbě mlčelo.

Seznam příkazů vychází z PT3 a Vortexu, jenom očíslovaný po svém (příkazy ale můžete zadávat i z kontextového menu, tak se nemusíte nic učit...):

KódVýznamParametr
1glissando, plynulý posun tónurychlost se znaménkem
2portamento k notěkrok
3offset nástroječíslo řádku
4offset ornamentučíslo řádku
5vibratovyšší bajt délka zapnutí, nižší délka vypnutí
8posun obálky dolůkrok
9posun obálky nahorukrok
Bzměna rychlostipočet ticků na řádek
Cperioda hardwarové obálky16bitová perioda
Dperioda šumu0 až 31
Ebreak, přechod na další pozicinepoužit
Fskok na pozici order listučíslo pozice

Pattern jako jedna stránka paměti

Buňky se skládají do stop. Jedna stopa je jeden kanál v jednom patternu, tedy 96 řádků po osmi bajtech, dohromady 768 bajtů. Kanálů je devět, protože Next má TurboSound a v něm tři nezávislé čipy AY po třech kanálech, takže kanálová data jednoho patternu zabírají 6912 bajtů. Za nimi ještě leží tři globální stopy, o kterých je řeč níž.

Celý pattern je uložený v jedné osmikilové stránce paměti, která se za běhu mapuje na adresu $C000. To je nejdůležitější rozhodnutí celého formátu, protože z něj plyne skoro všechna jeho aritmetika. Adresa buňky se počítá jako začátek okna plus číslo kanálu krát délka stopy plus číslo řádku krát osm, a protože se ta první část dělá násobením horním bajtem, musí být délka stopy násobek 256 bajtů. To vyjde jenom u počtu řádků dělitelného 32.

Zároveň platí strop shora. Na jeden řádek padne devětkrát osm bajtů kanálových buněk a třikrát čtyři bajty globálních, dohromady 84 bajtů. Do osmi kilobajtů se jich vejde 8192 děleno 84, tedy 97. Dohromady s podmínkou násobku 32 vychází maximum na 96 řádků. Pattern pak zabere 8064 bajtů a ve stránce mu zbude 128 volných, což je přesně ta rezerva, ve které se už nedá nic užitečného schovat.

Dlouho měl pattern jenom 64 řádků, protože to byla nejmenší varianta, která se vešla. Zvednutí na 96 nebyla změna jedné konstanty, ale zásah do celé paměťové mapy. Za daty patternu přestal být prostor na pomocný buffer, který tam do té doby bydlel, a musel se přestěhovat jinam. Odkládací plocha pro převod PT3 vyrostla o polovinu a přestala se vejít do svojí oblasti. Dělení dlouhých patternů na kusy při importu přestalo být posunem doprava, protože 96 není mocnina dvou, a muselo se přepsat na odčítání. A schránka pro kopírování bloků musela zůstat 64řádková, protože datová stránka trackeru je zaplněná do posledního bajtu a nebylo ji kam zvětšit. Formát tím dostal novou hlavičku MXM8, starší MXM7 se ale pořád načte: má stejnou hlavičku, jen jeho stopy jsou 64řádkové, takže se čtou po jedné na širší rozestup a horní řádky zůstanou prázdné.

Stránky se patternům přidělují líně, až při prvním použití. Prázdný pattern, který je v seznamu jenom číslem, tak nestojí nic. Patternů může být nejvýš 64.

Globální stopy AY

Za devíti kanálovými stopami leží tři další, jedna pro každý čip AY. Je to jediné místo, kde jsem se od PT3 vědomě odchýlil, a má to jednoduchý důvod. Frekvence šumu a tvar i perioda hardwarové obálky patří celému čipu, ne jednomu z jeho tří tónových kanálů. PT3 je ale ukládá jako události v kanálových streamech a při přehrávání se vyhodnocují v pořadí kanálů A, B, C, takže pozdější událost přepíše dřívější. Funguje to, ale v editoru je to matoucí: stejná hodnota napsaná do dvou různých kanálů neznamená dvě nezávislá nastavení, nýbrž souboj o jeden registr.

Globální buňka má čtyři bajty:

OffsetVýznam
0událost šumu: 0 beze změny, jinak $80 | perioda v rozsahu 0 až 31
1událost obálky: 0 beze změny, $40 pouze perioda, $80 | tvar znovu spustí tvar 0 až 15
2perioda obálky, nižší bajt
3perioda obálky, vyšší bajt

Jedna globální stopa má 96 krát 4 bajty, tedy 384 bajtů, a tři jich přidávají 1152 bajtů. Editor tu stopu ukazuje vedle kanálů jako NN EPPPP podle toho, na kterém AY zrovna stojí kurzor: NN je šum, E tvar obálky, = znamená událost měnící jenom periodu a tečky znamenají beze změny. Kanálové buňky přitom dál samostatně rozhodují, jestli se v daném hlasu míchá tón se šumem a jestli jeho amplitudu řídí sdílená hardwarová obálka.

Původní kanálové příkazy C a D zůstávají funkční kvůli kompatibilitě s importem, ale nové skladby by měly základní změny šumu a obálky psát do globální stopy. Při importu PT3 se pořadí A, B, C zachovává, takže výsledek zní stejně jako ve starém přehrávači, jenom se ta informace uloží tam, kam patří.

Order list a délky patternů

Skladba je seznam pozic a každá pozice je číslo patternu. Order list má 128 položek a hraje se od začátku do hodnoty sngLength, přičemž sngLoop říká, kam se skočí po dohrání. Stejný pattern může být v seznamu kolikrát chce a nestojí to nic navíc.

Vedle order listu je v souboru tabulka patLen, jeden bajt na každý ze 64 patternů, která drží skutečnou délku patternu v rozsahu 1 až 96. Přehrávač, editor i zpětný export PT3 ji respektují: pattern kratší než maximum prostě skončí dřív a mřížka v editoru se na jeho konci točí dokola. Uložená nula znamená plnou délku.

Tahle tabulka je čistě dluh vůči PT3 a stála mě nejvíc času ze všeho. Pattern v PT3 nemá pevnou délku a nikde v souboru není zapsaná. Konec se pozná až při dekódování streamu kanálu A, ve chvíli, kdy popis dalšího řádku začíná nulou. Reálné moduly používají 32, 64, 96, 128 i 256 řádků a co je horší, běžně se různé délky míchají uvnitř jedné skladby. Když jsem si proměřil čtrnáct modulů z testovací karty, jenom šest z nich mělo všechny patterny dlouhé 64 řádků. Dokud jsem měl pattern pevně 64 řádků a delší jsem ořezával, tak se skladby rozjely normálně a někde uprostřed se rozsypaly, což vypadalo jako chyba přehrávače, i když to byla chyba importu.

Pattern delší, než se vejde do jedné stránky, se proto při importu rozdělí na po sobě jdoucí kusy po nejvýše 96 řádcích a každá pozice, která takový pattern používala, se v order listu roztáhne na odpovídající počet položek. Kusy se sdílejí stejně jako patterny, takže pattern použitý na deseti pozicích pořád zabírá jenom svoje vlastní stránky.

Nástroje a ornamenty

Nástroj je v terminologii AY trackerů obálka, tedy tabulka řádků, kterými se po tikách mění hlasitost, posun tónu a šum. V MXM má čtyřbajtovou hlavičku s délkou, začátkem smyčky, příznaky a jedním rezervním bajtem, za kterou následuje nejvýše 46 řádků po pěti bajtech. Na jeden nástroj je rezervováno 234 bajtů a nástrojů je 32.

OffsetVýznam
0příznaky, viz níže
1hlasitost 0 až 15
2znaménkový posun tónu, nižší bajt
3znaménkový posun tónu, vyšší bajt
4syrový parametr šumu nebo obálky

Příznaky v bajtu 0 jsou po bitech od nejvyššího: tón zapnutý, šum zapnutý, hardwarová obálka zapnutá, akumulovat posun tónu, akumulovat posun šumu nebo obálky, zapnutý posun hlasitosti, směr posunu, kde jednička znamená nahoru, a nakonec rezervovaný bit, do kterého se zapisuje nula.

Bajt na offsetu 4 je nejošklivější místo celého formátu a je to opsané z PT3 doslova. Slouží zároveň jako posun šumu i jako posun periody obálky a přehrávač se na něj dívá dvěma různými způsoby podle příznaku šumu ve stejném řádku. Když nástroj používá šum, bere se celý bajt jako neznaménkový přírůstek periody, který se na výstupu do AY ořízne na pět bitů. Když řídí obálku, berou se z něj jenom spodních pět bitů jako znaménková hodnota v rozsahu -16 až +15. Moje první verze importu ten bajt při načtení znaménkově rozšířila, protože to vypadalo jako rozumná normalizace, a rozbilo to naráz každý šumový nástroj ve všech modulech. Formát ho proto ukládá syrově a interpretaci nechává na přehrávači. PT3 v něm mimochodem nese jenom sedm bitů, MXM zachovává všech osm.

S nástroji souvisí ještě jedna zděděná vlastnost, která v datech vidět není, ale bez které to nezní správně. Akumulátory posunu tónu i šumu se k hodnotě aktuálního řádku přičítají vždycky. Příznak akumulace nerozhoduje o tom, jestli se přičte, ale jenom o tom, jestli se výsledek uloží zpátky a přenese na další řádek. Rozdíl je slyšet okamžitě.

Ornament je proti tomu triviální: čtyřbajtová hlavička s délkou, smyčkou a dvěma rezervními bajty a za ní nejvýše 32 znaménkových posunů noty v půltónech, kterými se dělají arpeggia. Na jeden ornament je rezervováno 40 bajtů a ornamentů je 16. Delší nástroje i ornamenty z importovaných modulů se na těch 32 řádků ořežou.

Tři banky a příznak LINK

Nástroje a ornamenty nejsou v souboru jednou, ale třikrát. Každý AY má vlastní kompletní sadu 32 nástrojů a 16 ornamentů ve své vlastní osmikilové bance, kterou si přehrávač mapuje podle toho, který čip zrovna obsluhuje.

Vypadá to jako plýtvání, ale je to opět důsledek importu. Šestikanálové skladby pro TurboSound se ve Vortex Trackeru ukládají tak, že se dva kompletní moduly PT3 slepí za sebe a přidá se šestnáctibajtová patička ve tvaru PT3!, délka prvního modulu, PT3!, délka druhého modulu a identifikátor 02TS. Oba moduly mají svoje vlastní plné sady 32 nástrojů. Naivní import by je musel přečíslovat do jedné sady, jenže se to nevejde a část dat by se zahodila. Se třemi bankami se první modul načte jedna ku jedné do AY0 a druhý jedna ku jedné do AY1, bez přečíslování a bez ztrát. Přijímají se i starší TS soubory bez patičky, kde se druhý modul hledá podle jeho třicetibajtové hlavičky.

Protože se ale často stane, že stejný nástroj chcete na všech čipech, má každé číslo nástroje i ornamentu vlastní příznak LINK. Zapnutí propojení okamžitě zkopíruje aktuální položku z banky vybrané kanálem pod kurzorem do všech tří bank a každá další úprava se propíše dál. Vypnutí vazbu jenom zruší a tři existující kopie nechá být, takže se od té chvíle dají upravovat samostatně. Příznaky jsou uložené jako 48 jednobajtových hodnot na konci každého bloku AY, kde nula znamená samostatnou položku a jednička propojenou. Stejných 48 hodnot leží v každém ze tří bloků, aby se daly banky za běhu mapovat nezávisle na sobě. Nová skladba i čerstvě importovaný modul začínají se všemi propojeními vypnutými.

Ladění

V hlavičce jsou dva nenápadné bajty, číslo frekvenční tabulky a číslice verze ProTrackeru, a bez nich by uložená skladba po načtení zněla jinak. AY nemá ladění zabudované, perioda se dá spočítat jako takt děleno šestnáctinásobkem frekvence, ale PT3 noty nepočítá. Obsahuje čtyři ručně vyrobené tabulky period, mezi kterými se vybírá jedním bajtem, a přesné hodnoty v nich navíc závisí na číslici verze trackeru, protože starší a novější verze zaokrouhlují jinak. Celkem tedy existuje osm variant.

Ty tabulky si nejsou navzájem podobné a nejde o rovnoměrně temperované ladění. Proti spočítané tabulce jsou posunuté zhruba o půltón, takže modul se špatně vybranou tabulkou nezní jenom trochu jinak, ale výrazně falešně. MXTracker je generuje algoritmem z Vortex Trackeru: z 49 základních hodnot se každý z dvanácti půltónů půlením rozvede přes osm oktáv, podle varianty se přitom zaokrouhluje nebo ořezává, a nakonec krátký seznam oprav posune jednotlivé noty o jedničku. Ty čtyři tabulky jsou překrývající se okna do stejných 49 hodnot, proto jsou zdrojová data tak malá. Volbu drží sngNoteTab a sngVersion a MXM ukládá obojí.

Celý soubor

Hlavička má 269 bajtů a je pevná. Za ní jdou tři bloky nástrojů a nakonec data patternů, jeden za druhým.

OffsetDélkaObsah
$00004"MXM8"
$000432název
$002432autor
$00448rychlost, počet kanálů, délka order listu, smyčka, ladicí tabulka, výchozí hlasitost, počet patternů, příznak změny
$004C128order list
$00CC64délky patternů, každý 1 až 96 řádků
$010C1číslice verze ProTrackeru, vybírá frekvenční tabulku
$010D6064nástroje, ornamenty a příznaky LINK pro AY0
$18BD6064totéž pro AY1
$306D6064totéž pro AY2
$481Dn krát 8064data patternů 0 až n-1, vždy 6912 bajtů kanálových stop a za nimi 1152 bajtů globálních

Blok jednoho AY je 6016 bajtů nástrojů a ornamentů, tedy 32 krát 168 plus 16 krát 40, a za nimi 32 příznaků LINK nástrojů a 16 příznaků LINK ornamentů. Data patternů se ukládají a načítají po celých stránkách, což je jeden blok 8064 bajtů na pattern, takže načtení je v podstatě jenom namapování stránky a jedno čtení. U staršího MXM7 se čte po jednotlivých stopách na širší rozestup, jinak se ale nic nemění.

Zpětný export do PT3 je celá tahle cesta naruby a má jeden nečekaný nárok navíc: nestačí umět zapsat všechno, co umím načíst, protože výsledek musí přehrát i cizí přehrávač. Přenáší se všechny speciální příkazy, které PT3 zná, tedy glissando, portamento, offset nástroje i ornamentu, vibrato, posun obálky a změnu rychlosti, včetně bajtu prodlevy. Naše kódy 1 až 5 jsou shodné s PT3, oba směry posunu obálky jdou na $08, protože směr nese znaménko kroku, a změna rychlosti na $09. Break a skok se nepřenášejí, ty PT3 jako příkaz buňky nezná. Exportér dál nezapisuje popisy prázdných řádků vůbec a místo toho u každé skutečné události nastaví přeskok na vzdálenost k té následující, přičemž ho zapíše jenom tehdy, když se ta vzdálenost změní. Každý stream si navíc svoji počáteční hodnotu přeskoku nastaví výslovně, aby se stav nemohl přenést z předchozího patternu. Tříkanálová skladba se exportuje jako obyčejný modul PT3, šestikanálová jako standardní dvoumodulový TurboSound soubor včetně patičky. U devíti kanálů žádný široce podporovaný kontejner neexistuje, takže MXTracker zapíše tři moduly za sebe a zachová všechna data, ale běžné přehrávače z toho přečtou nanejvýš první dva.

Zpětně si říkám, že začít psat formát tím, že budu importovat PT3 nebyl asi nejlepší nápad. Protože to zpětně vedlo k úsporným opatřením jako schování prodlevy do nibblu bytu příkazu. Prodlevu jsem totiž v prvopočátku ignoroval (čti přehlédl) a přišel na ní až ve chvíli, kdy vše okolo bylo kolem tohoto formátu postaveno. Mohl jsem tam ten byte extra dodělat, ale nechtěl jsem snižovat počet řádků na patern - to by bylo myslím mnohem větší omezení. Jestli to někoho naštve a začně vytvářet hudbu s příkazy jejichž prodleva bude delší než 15, tak to předělám pořádně (ale pokud to udělá někdo schválně jen proto, abych se nenudil, budu se na něj mračit). Na moji obhajobu, použít k vytvoření formátu (a pochopení co AY potřebuje) import PT3 mi práci opravdu urychlilo a usnadnilo.... byť se to bez googlení a zjišťování informací neobešlo. Ale to v dnešní době není problém. Takže teď už jen program vyzkouším sám (hahaha - myslel jako, že nepadá, jdou načíst soubory atd.) a MXTracker pošlu z00Movi k připomínkování.

screenshot_2026_8_23___23_16_52

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *