markov-midi Automatický generátor MIDI souborů podle vzoru Vít Novotný
Obsah sekce 1 1. 1.1 Prefixové stromy 1.2 Markovovy řetězce 1.3 Komprese informace 1.4 Náhodný přesun 1.5 Vážení vstupů 2. markov-midi 2.1 Základní myšlenka 2.2 Ukázky 1/18
Prefixové stromy Uvažujme jazyk L = {Petr, Petra, Pavel, Pavla}. Tento jazyk je možné zakódovat pomocí prefixového stromu (trie): start P ε e t r a ε a v ε e l ε l a 2/18
Markovovy řetězce Pokud si během budování stromu budeme poznamenávat počet průchodů jednotlivými hranami, dostaneme Markovův řetězec: P 1/2 e t r a start 1/2 1/2 1/2 a v 1/2 e l 1/2 l a 3/18
Markovovy řetězce Pokud nyní uděláme v stromě náhodnou procházku, s pravděpodobností 1/ 4 obdržíme některé ze slov jazyka L = {Petr, Petra, Pavel, Pavla}. start P ε e t r a 1/2 a v 1/2 e l ε l a 4/18
Komprese informace Takto vybudovaný strom nám nikdy nevygeneruje jiný výstup, než jaký jsme do něj explicitně zakódovali. Pro vynucení invence využijeme kompresi informace. Každý uzel vybudovaného stromu odpovídá příslušnému prefixu, který označíme návěštími: P ε e t r a start ε P P Pe Pet Petr Petra ε a v ε e l P Pa Pav Pav Pave Pavel ε l a Pav Pavl Pavla 5/18
Komprese informace Návěští nyní ořízneme na k posledních znaků a stavy se shodnými návěštími sloučíme: P ε e t r a start ε P P e t r a ε a v ε e l P a v v e l ε l a v l a Obrázek: Komprimovaný prefixový strom odpovídající jazyku L pro k = 1 6/18
Komprese informace e P e t r a v l start ε P e t r a v l a l a Obrázek: Komprimovaný prefixový strom odpovídající jazyku L pro k = 1 Vlivem komprese jsme nyní při náhodné procházce schopni vygenerovat i slova Petravel, nebo Pela, která se v původním jazyku nevyskytovala. Vznikají nám i cykly generující slova jako P(etrav) +. 7/18
Komprese informace Slova generovaná z komprimovaného prefixového stromu z hlediska frekvence písmen odpovídají vstupnímu jazyku. Při vhodné volbě parametru k jsme schopni vygenerovat velké množství nových slov, která budou vypadat dostatečně přirozeně. Při vybudování komprimovaného prefixového stromu z 1581 křestních jmen veřejně dostupných na serveru http://rodina.cz/ dostáváme s k = 6 celkem 23 nových jmen: Jarolína, Gvendolín, Fridolína, Mstislava, Vítoslava, Budislava, Velimíra, Tichomíra, Svatomíra, Stanimíra, Něhoslava, Klementýn, Budimíra, Věslav, Šebastian, Karolím, Karolíma, Jonathanael, Erharda, Adalbertýna, Adalbertina, Stojmíra, Mojmíra. Při k = 5 dostáváme 148 jmen. 8/18
Náhodný přesun Uvažujme jazyk L = {Petr, Jan}. Veškeré prefixy tohoto jazyka končí jiným písmenem a díky tomu je výsledný strom odolný vůči kompresi: P e t r start ε P e t r J a n J a n Volbou k = 0 pak způsobíme úplnou degradaci stromu: P,e,t,r,J,a,n start ε 9/18
Náhodný přesun V takovém případě si invenci můžeme vynutit tak, že z každého uzlu stromu napneme hrany do všech zbývajících uzlů. Během procházky pak může dojít k přemístění na náhodné jiné místo ve stromu. P e t r start ε P Pe Pet Petr J a n J Ja Jan Z pohledu slov, která jsme v takto upraveném stromu schopni vygenerovat, jsme ve stejné situaci, jako při k = 0. Zde ale pravděpodobnost náhodného přesunu můžeme ovládat. 10/18
Náhodný přesun další zlepšení Uvažujme jazyk L = {týpek, prototyp}. Rádi bychom, aby nám odpovídající strom pro k = 3 generoval s vysokou pravděpodobností slovo prototýpek. Zároveň chceme, aby jiné náhodné přesuny byly málo pravděpodobné. Toho můžeme dosáhnout zavedením metriky podobnosti návěští, která pro podobná návěští (týp a typ) zvýší pravděpodobnost náhodného přesunu. p r o t o t y start ε p pr pro rot oto tot oty t p ý p e k t tý týp ýpe pek typ 11/18
Vážení vstupů Uvažujme opět jazyk L = {Petr, Petra, Pavel, Pavla}. Chtěli bychom nyní přidat váhu jménu Petr tak, aby při náhodné procházce mělo větší dopad. Toho dosáhneme jeho násobným zařazením: P 3/5 e t r a start 2/3 1/3 2/5 a v 1/2 e l 1/2 l a Nyní s pravděpodobností 1/ 5 obdržíme některé ze slov Petra, Pavel, Pavla, a s pravděpodobností 2/ 5 slovo Petr. 12/18
Obsah sekce 2 1. 1.1 Prefixové stromy 1.2 Markovovy řetězce 1.3 Komprese informace 1.4 Náhodný přesun 1.5 Vážení vstupů 2. markov-midi 2.1 Základní myšlenka 2.2 Ukázky 13/18
markov-midi 1 Základní myšlenka Namísto jazyků budeme pracovat s množinami MIDI stop. MIDI stopa pro nás bude slovem a jednotlivé MIDI příkazy písmenem. Zbytek algoritmu lze beze změny zachovat. Problémy: Jednotlivé MIDI soubory používají rozdílné jednotky délky jednotlivých tónů díky rozdílnému nastavení tempa. Vstupní MIDI soubory jsou s ohledem na parametry Tempo a Division normalizovány, aby byla délka tónů srovnatelná. Příkaz Pitch_bend může snadno zcela zahltit kontext představovaný parametrem k. Aktuální verze programu jej tedy implicitně zahazuje. 1 Viz https://github.com/witiko/markov-midi 14/18
markov-midi Náměty k řešení V MIDI jsou stisk a uvolnění klávesy samostatné příkazy. V případě náhodných přesunů nemusí dojít k uvolnění stisknutých kláves. Mohlo by být vhodné jednotlivé stopy v rámci jednoho MIDI souboru provázat tak, aby se současně generovaly všechny. Udržování stavu napříč stopami je obtížné, program proto generuje jen jednu stopu z množiny vstupních stop. Náhodné přesuny nevyužívají metriku podobnosti návěští. Je možné použít existující metriky podobnosti řetězců, jako je Hammingova vzdálenost, nebo vytvořit metriku šitou na míru struktuře MIDI příkazů. 15/18
markov-midi Náměty k řešení Skladby s vysoce proměnným tempem jsou problematické. V pomalých pasážích může být parametr k příliš vysoký, což zapříčiní nízkou kreativitu algoritmu. V rychlých pasážích může být naopak příliš nízký, což zapříčiní zahlcení kontextu a přehnanou chaotičnost výstupu. Řešením by bylo agregovat MIDI příkazy v určitém časovém úseku do jednoho, nebo hodnotu parametru k v průběhu skladby klouzavě měnit. Program je momentálně ve stádiu prototypu. Spuštění vyžaduje UNIXový systém a program má pouze textové rozhraní. 16/18
markov-midi Ukázky D_ROMERO.MID Vstupní skladba je minutu dlouhá a využívá opakující se vzory. Skladba sestává z rozkladů akordů; minimální hodnota parametru k je tedy 3. Pomocí náhodných procházek jsme schopni vygenerovat devítiminutovou skladbu s obdobnou strukturou. Ukázka kódu $./markov-chain.sh 3 - - D_ROMERO.MID 17/18
markov-midi Ukázky D_E1M1.MID Volbou nízké hodnoty parametru k jsme schopni získat zajímavé variace, které se ve stupním souboru nevyskytují. Ze vstupní skladby vybíráme dvě stopy. Ukázka kódu $./markov-chain.sh 3 - - D_E1M1.MID=2-3 GoF_Battle{1,2}.MID Volbou vysoké hodnoty parametru k a povolením náhodných přesunů s pravděpodobností 5 % dosáhneme vygenerování koláže. Ukázka kódu $./markov-chain.sh 100-0.95 GoF_Battle{1,2}.MID=4 18/18