MOD Player

Když jsem se v roce 1992 prvně setkal s Amigou 500+, byl jsem unesený ze všeho, co Amiga nabízela. Kdo zažil uvěří. Hry byly super, ale demoscéna, to je pojem. Demoscénu sleduji a kroužím kolem již několik let. Dema vnímám jako prostředek, jak ostatním ukázat, co s daným počítačem dokážu. Dema jsou pasivní aplikace, které nevyžadují uživatelovu interakci. Vizuální a audio část je spolu spojena a navzájem se doprovází. Vhodné načasování pak vytváří dokonalý dojem. Dema vytváří často tvůrčí skupinky, kde je práce rozdělena. Často se pak stává, že grafickou podobu dělá jeden člověk a my pak můžeme ohodnotit, jak pěkně umí grafiku. Jiný programuje 3D engine a my se můžeme kochat pohybem oživlé grafiky a samozřejmě muzikant, který skládá hudbu pro dané demo. Přiznám se, že mým oblýbeným hudebním autorem ve spojení s fenoménem Amiga jsou: Travolta Spaceballs, Laxity, Jogeir Liljedahl.

Jak jsem naznačil, vizuální a audio spojení pak může přinášet hluboké dojmy a je to ideální způsob, jak dovednosti prezentovat.
Navíc, pokud demo sleduje někdo z oboru, dokáže si přestavit náročnost, která za zrovna sledovanou scénou probíhá.
Hudební formát MOD byl dlouhá léta oblíbeným formátem všech borců, kteří dema tvořili a stále tvoří. Nějaký pátek jsem strávil za obrazovkou ProTrackeru na Amize 1200 a později u FastTrackeru a Scale na PC. Já nemám dar skládat libou muziku, ale muziku rád poslouchám a jako technicky orientovanému člověku mi formát MOD očaroval. S oblibou jsem remixoval mé oblíbené skladby a tešil se z toho, jak se dá snadno na počítači tvořit hudba.
Ukázka sama za sebe, jedno z nejznámějších dem pro Amigu A500, informace o harware si můžete zjistit na internetu. Demo je z roku 1993

(Videa nejsou má, přijde mi zbyterčné grabovat to, co na youtubu již je)

Desert Dream Část 1.

Desert Dream Část 2.


Obdivoval sem a stále obdivuji tu nadčasovost, kterou tento hudební formát od svých autorů získal. Tímto bych rád smeknul a složil poklonu pánům Karsten Obarskimu, který formát stvořil a Mahonymu a Kaktusovi, kteří se významně podepsali na rozvoji tohoto formátu. A také všem, kdo zvládli vlastní implementaci, protože to není zrovna triviální záležitost, i když formát souboru je elegatně přehledný.
Na amigách bylo postavení přehrávače o něco jednodušší, protože například samply, digitální vzorky hudebních nástrojů, jsou v modulech ukládány ve formátu 8-bit PCM, což je identický formát, s jakým pracuje DAC chip Amigy. Takže tamní programátoři nemuseli řešit trasformace a konverze. To je také důvod, proč přehrávátka na Amigách braly zlomky výkonu CPU.

Vetšinou mi nestačí pouze vědět, jak věci fungují, ale mám často potřebu to umět i naprogramovat. Někdy v roce 2001 jsem se rozhodl, že si naprogramuji vlastní přehrávátko na "moduly" pod Windows.
Věděl jsem o problematice hodně věcí, měl jsem k dispozici popisky jak formátu souboru, tak i některé implementační teorie pro Amigy.
Dalším důvodem, proč jsem se rozhodl napsat si vlastní přehrávátko, byla i ona demoscéna, do které jak pevně doufám ještě přispěji. Prostě jsem nechtěl použít "cizí" kód, ale jen vlastní. Časem napíši povídání o tom, jak jsem zkoušel jednoduchou 3D grafiku pomocí GDI :)

Pro vývoj jsem zvolil Delphi, protože jsem je v té době aktivně používal. I dnes v nich sem tam něco ještě napíšu. Většinou po nich sáhnu, když potřebuji nějakou utilitu a honem rychle. Delphi ovládám dobře a tak většinou nemusím zkoumat technologické temné kouty, jak říkává jeden můj kolega.

Vybral jsem z archivu modulů ty pro mě nejzajímavější, ty které se mi nejvíc líbily a prohlásil jsem je za takový "unit test". Prostě když tyhle moduly dokážu přehrát pokud možno identicky jako Amiga, budu spokojený.
Vybral jsem tyto moduly:

  • Test last
  • 9 fingers
  • Condom coruption
  • Desert dream 1,2,3 a hiden part
  • Boesendorfer
  • Love theme

(ke stažení zde)

Později, abych nemusel používat emulátor na Amigu pro přehrávání modulů, začal jsem používat stařičký WinAMP 2.9, který umí moduly také přehrávat a to celkem slušně. Tato stará verze se dá stále stáhnout. Je to maličkýá přehrávač a hraje dobře, dDodnes ho používám pro přehrávání MP3.

Přehrávátko je nyní ve třetí generaci. Dvě předchozí generace jsem zahodil, protože jsem se vydal špatnou a slepou cestou. Zprvu jsem neuměl mixovat zvuky dohromady a tak jsem hledal způsoby, jak přehrát paralelně dva a více zvuků najednou.
Zkoušel jsem to přes DirectSound, zkoušel jsem to přes vlákna. Ani jedna varianta nefungovala tak, jak jsem si představoval. Spouštění samplů v jednom momentě mi nefungovalo přesně a také jsem měl potíže s opakováním samplů. Pokud byl sample opakovaný, nedařilo se mi včas nastavovat jeho novou pozici na začátek offsetu opakování. Dojem z takové muziky byl dle mého názoru mizerný.
Třetí generace již mixuje jednotlivé samply dohromady v jeden výstupní a výsledný zvuk. K přehrávání jsem použil nekonečný audio stream. Toto je velice elegantní způsob, jak pořešit všechny potíže, které jsem v předchozích generacích projektu měl anebo vytvořil.
Princip je velice jednoduchý. Otevře se pomoci Win32 API waveOutOpen audio výstup ve specifikovaném formátu a také se definuje callback funkce, kterou bude systém volat, aby fukce obsloužila zprávy, které při přehrávání nastanou. Pomocí API waveOutWrite zapíši do audio streamu připravená hudební data. A v tom je ta krása. Callback funkce je volána v případě, že se blíží konec přehrávaného bufferu a je tedy potřeba namixovat další kus výstupního zvuku.
Celý přehrávač tedy funguje v režimu, kdy chviličku pracuje naplno a mixuje samply a pak je v klidu a nic nedělá. V tu dobu, kdy nic nedělá, přehrává systém data, která program namixoval. Ve chvíli, kdy namixovaná data dochází, zavolá systém callback a tím se opět spustí další cyklus přehrávátka. Opět namixuje další kus muziky a čeká až se data přehrají. Délka zvukového záznamu, který se vytváří, mixuje a následně přehrává se definuje při otevírání audio kanálu. Čím menší je buffer pro přehrávaná data, tím častěji je callback volaný, ale také lze spíše reagovat na podněty zvenčí. Například změna hlasitosti uživatelem. Nebo když bych chtěl vyvolávat nějakou událost pokaždé, když přehrávátko přehraje vybraný nástroj, bylo by dobré aby buffer byl co nejkratší. Kdyby byl buffer naopak dlouhý, nebyly by reakce formou event dobře načasované a to právě díky tomu, že se dopředu vytvoří například 10 vteřin muziky a pak se 10 vteřin z pohledu aplikace nic neděje.

Jak je vidět, celý mechanizmus je celkem jednoduchý, pokud si srovnáme v hlavě, jak to pracuje po kusech. Implementace mechanizmu je v podstatě také jednoduchá. Co je ale složitější, je právě ono mixování všech těch nástrojů dohromady. Aplikace v současné verzi nastavuje kvalitu výstupního zvuku pomocí kompilačních direktiv. To znamená, že za běhu programu nelze měnit kvalitu výstupu. Je to kvůli rozdílným datovým typům. Pokud bude výstup 8bitový, pracuje i mixovaci mechanizmus 8bitově a proměnné, které k tomu používá jsou také 8bitové. Analogicky je to u 16bitové kvality zvuku. Musel bych mít dva mechanizmy, abych obsloužil tak rozdílné typy proměnných. Je otázka co je menší zlo. Jestli dvě podobné metody anebo jednu metodu prošpikovanou kompilačními direktivami. Pro potřeby doprovodné muziky pro nějakou grafickou scénu jsou ale kompilační direktivy správné řešení, protože za běhu aplikace nebudu mít potřebu volit si kvalitu výstupu, ale ještě použiji tu, kterou nastavím já v době vývoje. Celé se to ale stává složitějším ještě samplovací frekvencí, která může být libovolná z těch, které systém podporuje. Běžně se používají frekvence 11025Hz, 22050Hz a 44100Hz. Zde je největší problém v tom, že většina samplů, které jsou v modulech uložené jsou 8bitové a vzorkované na 22KHz. Dále výstup může být mono, stereo nebo pseudo surround.
Mixovací metoda s tímto vším musí pracovat a data samplů upravovat. Tomu se říká resamplování a děje se to za běhu. Vytvořím rozdílový koeficient výstupní frekvence a vstupní frekvence každého samplu. Tento koeficient pak používám k vyčítání dat samplu tak, že data samplu přeskakuji v případě, že je sample kvalitnější než audio výstup a nebo data opakuji v opačném případě. Pokud je frekvence shodná, dochází k přímému kopírování. Až nahlédnete do zdrojového kódu, uvidíte, že je to ještě malinko zamotanější, ale naštěstí pochopitelné. Do série zpracování výstupního zvuku jsem ještě začlenil úpravu výstupu pomocí jednoduchého tří-pásmového ekvalizéru. Je tak možné řídit basy, středy a výšky. Pomocí tohoto ekvalizéru lze získat celkem pěkné výsledky.

Teď, když je popsán mixovací mechanizmus, je na řadě popsat lehce formát modulu a vysvětlit, jak mixování samplů ve výslednou muziku vlastně probíhá. Popisuji to proto, že z implementačního hlediska se jedná o celkem slušnou výzvu.

O formátu modulu se lze na internetu v současnosti dočíst snad úplně vše.
Mohu doporučit stručný, ale výstižný popis na WiKi zde.

Existují různé variace, avšak ta nejrozšířenější variace s označením M.K. (Mahoney and Kaktus) říká, že:

  • předpokládá se audio výstup se dvěma stereo kanály. Tedy 4 samostatné mono stopy.
  • počet samplů (hudebních nástrojů) může být 31
  • samply jsou samplovány jako 8bit mono 22KHz
  • matice s předpisem not má 64 řádků
  • na každém řádku se může nechat přehrát konkrétní sample na konkrétní frekvenci
  • na každém řádku se může definovat efekt (typicky hlasitost, tempo)
  • je podporováno až 127 matic s předpisem not pro každá kanál zvlášť (4 kanály)
  • obsahuje seznam, určující pořadí jednotlivých matic jak se budou hrát za sebou


Dále specifikace říká, že rychlost, jakou se přehrávátko pohybuje z jedné řádky matice na druhou, je definována pomocí BPM (beats per minute). Standardní hodnota je 125 BPM. Další významná informace je, že mezi přechodem z jednoho řádku na druhý se může několikrát aktualizovat efekt. Počet je definován jako Speed a standardní hodnota je 6. Další pojem je Tick, který představuje pohyb v rámci jedné řádky a to v rozsahu 1 až Speed.
Efekty se rozdělují na 2 základní skupiny a to:

  • notové efekty, vykonávají se při přechodu na nový řádek matice
  • tick efekty, vykonávají se při přechodu ticku mezi 1 až Speed

Pomocí tickových efektů se dosahuje například vibráta, zkrácení hrací doby samplu. Přechod z jedné noty na druhou (frekvenční přechod po tónech nebo půltónech, a další).

Zde je výpis efektů, které přehrávátko v současnosti implementuje a jen stručně popis (samotná implementace některých efektů je náročná stejně jako složitost jejich detailniho popisu, který ale neuvádím):

Krátké vysvětlení označení efektů pro lepší přestavení:
1. písmeno je označení efektu
x a y jsou volitelné parametry ovlivňující algoritmy efektů, x a y jsou 4-bitová čísla, někdy se použivají jako jedno 8-bitové číslo a někdy se dělí po 2 bitech.

  • 0xy - Arpeggio - každý 1 z 3 ticků se resetuje perioda tónu na default, každý 2 z 3 ticků se perioda zvýší o x, a každým 3 ze 3 ticků se zvýší prioda tónu o y.
  • 1xx - Porta up - každý tick sníží periodu o xx.
  • 2xx - Porta Down - každý tick zvýší periodu o xx.
  • 3xx - Slide to note - přechod z přehrávané periody na novou v rámci ticků. Pokud je xx nula, pak se opakuje s předešlým nastavením, jinak xx určuje rychlost přechodu. Přechází se na notu, kterou určuje nota v rámci přehrávaného řádku a kanálu.
  • 4xy - Vibrato - osciluje frekvenci samplu podle sinusoidy, kterou před aplikací výpočtu nové frekvence upravím podle nastavení vibrata, to zajišťuje efekt E4. Parametr x = rychlost efektu a y = intenzita. Efekt E4 nastavuje tvar sinusoidy (vlna, pilový zub s kolmou náběžnou hranou a čtvercový tvar - hradbičky)
  • 5xy - Volume slide + slide to note: toto je efekt, který pokračuje ve vykonávání efektu 3xx (portamento) a zároveň upravuje hlasitost podle pravidla volume = volume + x-y, přičemž celková upravená hlasitost nesmí opustit hranice 0 až 64.
  • 6xy - Volume slide + vibrato: toto je efekt, který pokračuje ve vykonávání efektu 4xx (vibrato) a zároveň upravuje hlasitost podle pravidla volume = volume + x-y, přičemž celková upravená hlasitost nesmí opustit hranice 0 až 64.
  • 7xy - Tremolo - osciluje hlasitost přehrávaného samplu. x je rychlost a y je intenzita. Podobně jako vibrato, oscilace kopíruje sinusoidu. Výsledná hlasitost nesmí opustit hranice 0 až 64.
  • 8xx - Panning - neimplementováno, pouze příprava. Klasická Amiga tento efekt nepoužívá. Parametr xx má význam: 0=vlevo, 255=vpravo.
  • 9xx - Set sample offset to xx * $100. Nastavuje offset, odkud se má sample začít přehrávat. Parametr xx se musí vynásobit 256 a je to počet bajtů od začátku samplu. Odtud se začně přehrávat.
  • Axy - Volume slide - mění hlasitost kanálu, v kterém je efekt použitý, každý tick kromě prvního o hodnotu x-y.
  • Bxx - Jump to offset - ukazuje na pozici v seznamu matic. Matice uvedená na této pozici se začne přehrávat.
  • Cxx - Set volume - nastavuje hlasitost kanálu, v kterém je efekt použitý. Hodnota je 0 až 64.
  • Dxy - Pattern break - Skočí na řádek x*10+y aktuální matice (pattern).
  • E0x - Amiga filter - neimplementováno. Tento efekt je určený pro Amigy, které mají hardwarový audio filtr. Do budoucna ho zkusím emulovat ekvalizérem.
  • E1x - Fine slide up - stejné jako efekt 1xx, ale funguje jen na prvním ticku. Po přehrání noty se hodnota zapomene.
  • E2x - Fine slide down. stejné jako efekt 2xx, ale funguje jen na prvním ticku. Po přehrání noty se hodnota zapomene.
  • E3x - Set glissando on/off - neimplementováno. Význam je, že pokud x=0, pak je glisando vypnuté. x=1, glisando je zapnuté. Pokud je glisando zapnuté, pak přechod na jinou notu efektem 3xx jde po půltónech, v opačném případě jde plynule.
  • E4x - Set vibrato waveform. Spodní 2 bity z x nastavují typ tvaru sinusoidy, třetí bit určuje, dali se resetuje sinusoida při každém přehrání nové noty. Pokud se neresetuje, znamená to, že vibrato efekt plynule přechází na další noty. Typ tvaru může být: 0-sinusoida, 1-pilový zub s kolmou náběžnou hranou, 2=čtvercový tvar, 3=náhodný tvar - jeden z výše uvedených. Tento efekt nastavuje vlastnosti efektu 4xy.
  • E5x - Set finetune - jmené doladění hlasitosti (4 bity) -7 až 8.
  • E6x - Loop pattern - používá se dvojím způsobem. Pokud je x = 0, pak definuje značku na kterou se bude skákat. Pokud obsahuje x > 0, pak se jedná o počet skoku z tohoto místa na značku (E60). Efekt používá počítadlo, které se každým skokem sníží. Jakmile je počítadlo = 0, pokračuje přehrávání dál a již se dál neskáče. Nelze používat zanořené smyčky. Pokud není definována značka, skáče se na začátek matice (paternu). Skákat lze pouze v rámci současné matice (paternu). Každá kanál má své vlastní počítadlo.
  • E7x - Set tremolo waveform - jako E4x, ale pracuje s efektem 7xy.
  • E8x - stereo pan extension - neimplementováno, pouze příprava. $0 je úplně vlevo, $F je úplně vpravo.
  • E9x - Retrigger sample - Každý x tick se spustí přehrávání aktuálního samplu znovu od začátku. Pokud je x = 0, pak se nic nestane.
  • EAx - Fine volume slide up - jednorázově zvedne hlasitost o x, hlasitost nesmí překročit hodnotu 64. Tento efekt se stane jen při tick = 0, podobně jako E1x.
  • EBx - Fine volume slide down - jednorázově sníží hlasitost o x, hlasitost nesmí klesnout pod 0. Tento efekt se stane jen při tick = 0, podobně jako E2x.
  • ECx - Note cut - znamená, že na se nastaví hlasitost kanálu na nulu jakmile tisk = x.
  • EDx - Note delay - Spustí přehrávání samplu až když tick = x. Sampl se spustí od začátku v hlasitosti kanálu.
  • EEx - Row delay - x-krát opakuje řádek, například, pokud je x = 3, pak se řádka s tímto efektem vykoná celkem 4x a až pak přehrávání pokračuje dalším řádkem matice (paternu).
  • Fxx - Set speed - pokud je hodnota menší jak 32, pak se nastavuje Speed, pokud je vetší nebo rovna 32, pak se nastavuje BPM.


Tak, jak to říci jednoduše. Skoro bych zápis modulu přirovnal k jazyku, definujícímu přehrávání muziky. Něco jako hudební programovací jazyk. Nicméně každý si dokáže přestavit, že skladatel musel znát mnoho technických detailů jak o hudbě, tak především o způsobu interpretace efektů. Ticks, Speed a BPM spolu s parametry x a y jako parametry do algoritmů. Nic snadného.
Je řada modulů, kde se používají jen ty nejzákladnější efekty, ale pak je řada těch hodně vypilovaných, kde je vidět a hlavně slyšet, že autor je prostě a jednoduše borec.
Například jeden takový borec je Laxity, programuje a zároveň skládá muziku, tím že si sám programuje hudební interpreter přesně ví, jak efekty dobře využít. Mrkněte na následující video, ukazující přehrávání modulu Desert Dream #2 v ProTrackeru na Amize. Je vidět komplexnost a složitost modulu.

Nebo zde jiný příklad objemu dat, od 2:24


Když jsem ladil frekvenční tabulky a některé efekty, moje žena si se mnou vyloženě užila. Jí se éra Amig nedotkla a většina skladeb jí připadá příliš syntetických. Když jsem ladil efekty, stavěl jsem si ukázkové moduly, kde jsem mohl sledovat jak je implementace přesná v porovnání například se zmíněným ProTrackerem nebo WinAMPem. To bylo falešných zvuků a chrčení, když mi ukazatelé v mixéru ujely do jiné paměti. Od té doby tomu žena neříká přehrávátko, ale pípátko. Ladění trvalo poměrně dlouho. Jednak se k tomuto projektu vracím průběžně a druhak zde bylo spousty pro mě nových mechanizmů a také ladění tohoto typu aplikace je časově náročné.
Pro mně to ale byl fajn strávený čas a získání dalších skillů navíc. Na linkedIn si tohle do profesního životopisu dát nemůžu, ale ruku na srdce. Pro mě je zajímavější psát taková pípátka, než kdo ví kolika vrstvé systémy které přehazují data z jené strany na druhou. Občas je ta profesní práce také zábavná, zejména pokud mohu prokopnout nové věci, nové směry nebo nové technologie, ale tohle, tohle je zajímavější.

Naprogramoval jsem přehrávátko, které má následující rysy:

  • přehrává MOD a UNIC hudební soubory
  • zvládne výše popsané efekty
  • má neomezený počet hudebních kanálů
  • má neomezený počet samplů (instrumentů)
  • přehrává mono
  • přehrává stereo
  • přehrává panned stereo
  • přehrává simulated surround
  • přehrává v CD kvalitě 16bit 44KHz, umí ale i 8bit a nižší frekvence
  • notofikuje pomocí event o různých událostech z přehrávání
  • disponuje možností úpravy hlasitosti (master volume)
  • disponuje jednoduchým tří-pásmovým ekvalizérem


Ještě krátký příběh k formátu UNIC. Kdo zná demo Desert Dream z Amigy ví, že v demu byla skrytá část, Tam byla taková jemná muzika od Laxity. Nedařilo se mi tento modul vůbec vygooglit. Jen na jednom místě v tom obrovském houští internetu jsem ho našel, ale ve formátu UNIC. Do té doby jsem o tomto formátu vůbec nevěděl. Ve své podstatě je to téměř stejný format jako typycký MOD, jen jsou některé informace jinak interpretovány. Obocně se takto autoři chránili proto, aby nějaký šikula s ripperem nevykuchal muziku jen tak jedním kliknutím.

Zdrojové kódy jsou přeložitelné pod Turbo Delphi, Delphi 2005 (nepodstatné rozdíly v DFM), Delphi 2006. Protože nepoužívám žádné featury, které jsou jen v některých verzích, půjde to přeložit od Delphi3 až po poslední verze Delphi, nejspíš. Možná některé vlastnosti vizuálních komponent nejsou ve všech verzích Delphi.

Zdrojové kódy jsou zde.
(Používejte dle libosti. Pokud použijete, dejte mi jen vědět a případně mě uveďte do credits vašeho projektu).
Komentáře unity "UModProcess.pas" jsou poměrně masivní a lze je číst jako další článek, tentokáte ale plný technických detailů.

Pár slov a demo aplikaci kterou si můžet stáhnout z odkazu výše a je vidět na screen shotu výše:
Demo aplikace má za úkol demonstrovat jak se přehrávátko používá. Vytvoří se instance přehrávače, zavolá se metoda pro nahrátí hudebního modulu a pomocí zavolání metody Play to začne hrát. Demo aplikace také zobrazuje průběh přehrávání. Posun ale není přesný, protože to jde proti principu mixování audio výstupu dopředu. Proto na otázku, jak to fuguje, odpovím, že: V unitě UModProcess.pas na řádku 2261 je tento kód "XNumSamples := XSamplesPerBeat * FSpeed div 2;" a řáká, kolik dat se o výstupního bufferu mixuje. Stačí buffer zvtšit a sníží se frekvence callbacků.

Demo aplikace má tlačítko "Load Module", které nahrává moduly z disku PC. Tlačítka "RES MOD" a "RES UNIC" nahrávají moduly z resource aplikace. Jeen ve formátu MOD a druhý v UNIC. Tlačítka "Play" a "Stop" jsou jasná.

Posuvníkem Volume, lze měnit hlasitost. A Ekvalizér má funkci také jasnou. Račte ozkoušet.

Jako obvykle, žádný software není dokonalý a tak mi prosím odpusťte chyby, které najdete.

 

No a proč zveřejňuji tyto zdroje? Jenoduše proto, že se to třeba může někomu hodit a nebo proto, že jsem chtěl ostatním říci čím se také dále zabývám a čím si vyplňuji volný čas, kterého je čím dál méně. Třeba v mých zdrojácích najdete inspiraci, zkušenosti a nejspíš také chyby.

Zde bych chtěl také poděkovat Neilu C., jehož zdoje pro ekvalizér jsem použil, přeložil do Delphi a lehce modifikoval.
Dále děkuji všem, kdo píší na web specifikace a zveřejňují zdroje, páč tak ostatní mají možnost něco okoukat, vylepšit.


FUVI0111ADANAUL
FREE Joomla! template "Adana"
joomla 1.6 templates by funky-visions.de