Dr.Godfried-Willem RAES
Kursus Experimentele Muziek: Boekdeel 1: Algoritmische Kompositie
Hogeschool Gent: School of Arts
Naar inhoudstafel kursus
Stochastiek is een tak van de wiskunde, voortgekomen uit de waarschijnlijkheidsrekening. In de muziek raakte dit domein uit de wiskunde erg bekend door de toepassingen die vooral Iannis Xenakis ervoor bedacht in de muziek.
Een zekere kennis van de principes ervan is nodig om zelf aan de slag te kunnen met zelfs erg minimale expertsystemen en zeker, wanneer we iets willen kunnen begrijpen van neurale netwerken, fuzzy-logic en automatische kennisverwervende systemen.
Programmavoorbeeld:
Het hier gegeven programmavoorbeeld -geschreven in Microsoft Professional Basic V7.1 maar kompatibel met QB4.5- omvat bruikbare procedures voor het genereren van getallen met gewogen waarschijnlijkheden op grond van opzoekingstabellen.
'**********************************************************************
'* STOCHAST.BAS *
'* programma-module *
'* procedures voor stochastiek *
'**********************************************************************
DECLARE SUB Normalize ()
DECLARE SUB Makedomain ()
DECLARE FUNCTION Getvalue% ()
DECLARE FUNCTION Getmostprob% ()
' omwille van de demo deklareren we ook nog:
DECLARE SUB Uit (byte%)
DECLARE FUNCTION ADC% (byte%)
'een voorbeeld van kode voor een ADC konvertor is terug te vinden in de listing van <A Book of Moves>, module Bomfunc, funktie ADC%().
COMMON SHARED Wcnt%(): 'frequency tabel on entry (input-event count array)
'This table can be updated in real-time
COMMON SHARED Wn!(): 'waarschijnlijkheidsdistributie 0-1
'moet strikt genomen niet shared zijn wanneer we Normalize en Makedomain tot 1 enkele procedure
'samenvoegen. Dit kan omdat beide toch steeds samen gebruikt zullen worden.
COMMON SHARED Dwn!(): 'vergelijkingsdomein voor stochastiek
COMMON SHARED Dp% : 'I/O adres van de midi-kaart
COMMON SHARED debug% 'boole variable true/false
CONST Dp% = &H330
debug% = 0
n% = 12
RANDOMIZE ((TIMER * 10000) MOD 10000)
DIM SHARED Wcnt%(0 TO n%)
DIM SHARED Wn!(0 TO n%)
DIM SHARED Dwn!(0 TO n%)
CLS
SCREEN 12
WIDTH 80, 30
' Demo programma:
' Stel Wcnt%() bevat de waarschijnlijkheden voor het voorkomen van een noot in een toonladder (0-11) binnen een gegeven muziekstuk.De hier opgegeven waarden zijn 'kwoteringen' zonder andere dan een relationele referentie. Zij kunnen uiteraard afgeleid worden uit bvb. een telling van het voorkomen van bepaalde waarden uit een gegeven verzameling, of vanuit een real-time signaalbron zoals bvb. een midi input poort, een ADC konverter o.i.d.
Wcnt%(0) = 10
Wcnt%(1) = 1
Wcnt%(2) = 5
Wcnt%(3) = 7
Wcnt%(4) = .1
Wcnt%(5) = 7
Wcnt%(6) = .01
Wcnt%(7) = 10
Wcnt%(8) = .1
Wcnt%(9) = 5
Wcnt%(10) = 1
Wcnt%(11) = 7
Wcnt%(12) = 9
' reken Wcnt%() om naar Wn!() met waarden tussen 0 en 1:
Normalize
' bereken een gedistribueerd probalistisch domein 0-1 vanuit Wn!():
Makedomain
DO
IF debug% THEN
LOCATE 8, 1
PRINT "Pointer", "Weight", " ", "Distribution-domain";
FOR i% = LBOUND(Wn!) TO UBOUND(Wn!)
LOCATE 10 + i%, 1
PRINT i%, Wn!(i%); " ", Dwn!(i%); " ";
NEXT i%
LOCATE 12 + i%, 1
PRINT "getal="; Getvalue%; " ";
ELSE
LOCATE 20, 10
PRINT "getal="; Getvalue%; " ";
END IF
LOCATE 22, 10
PRINT "meest waarschijnlijk getal="; Getmostprob%; " ";
Uit (144): Uit (Getvalue% + 60): Uit (127)
SOUND 20000, 5
LOOP UNTIL INKEY$ <> ""
' Voorbeeld van een mogelijke toepassing waarbij de waarden van Wcnt!() in real-time geupdate worden:
DO
dummy% = ADC%(3)
Wcnt%(dummy%) = Wcnt%(dummy%) + 1
Normalize
Makedomain
noot% = Getvalue%
Uit (144): Uit (noot% + 60): Uit (127)
Uit (145): Uit (Getmostprob% + 48): Uit (90)
SOUND 20000, Wn!(noot%) * 20
LOOP UNTIL INKEY$ <> ""
' Voorbeeld van een mogelijke toepassing waarbij de waarden in Wn!() rechtstreeks gewijzigd worden. Het gewicht van een nieuwe waarde is hier bepaalbaar via de parameter WeightofPast! Hoe groter deze parameter, hoe groter het gewicht dat een nieuwe waarde in de schaal zal werpen. Waarden groter dan 1 hebben echter nauwelijks zin. Het meest logische is deze waarde te kiezen tussen 1/UBOUND(Wn!) en 1
DO
dummy% = ADC%(3)
WeightofPast! = (1 / UBOUND(Wcnt%)) * 2
Wn!(dummy%) = Wn!(dummy%) + WeightofPast!
' bereken de nieuwe som in Wn!
checksum! = 0
FOR i% = LBOUND(Wn!) TO UBOUND(Wn!)
checksum! = checksum! + Wn!(i%)
NEXT i%
' normalizeer Wn!(n%):
FOR i% = LBOUND(Wn!) TO UBOUND(Wn!)
Wn!(i%) = Wn!(i%) / checksum!
NEXT i%
noot% = Getvalue%
Uit (144): Uit (noot% + 60): Uit (127)
Uit (145): Uit (Getmostprob% + 48): Uit (90)
SOUND 20000, Wn!(noot%) * 20
LOOP UNTIL INKEY$ <> ""
' einde van de demo-kode.
FUNCTION ADC% (byte%)
' deze funktie leest een 7-bit waarde uit een ADC-konverter.
' Voor kode cfr. BOM-kode. Als dummy schrijven we hier:
ADC% = (RND(1) * RND(1) * RND(1) * RND(1)) * 12
END FUNCTION
FUNCTION Getmostprob%
' this procedures returns the number with the highest probability in the normalized array Wn!()
dummy% = LBOUND(Wn!) - 1: ' impossible default value
max! = -1
FOR i% = LBOUND(Wn!) TO UBOUND(Wn!)
IF Wn!(i%) > max! THEN max! = Wn!(i%): dummy% = i%
NEXT i%
Getmostprob% = dummy%
END FUNCTION
FUNCTION Getvalue%
'Stap 1: genereer een random getal tussen 0-1
Gok:
gamble! = RND(1)
'Stap 2: ga na in welk gebied dit getal valt en retourneer de overeenkomstige numerieke waarde:
getal% = LBOUND(Wn!) - 1: ' ken een onmogelijke waarde toe
i% = LBOUND(Wn!): ', 1)
DO
IF gamble! <= Dwn!(i%) THEN getal% = i%: EXIT DO
i% = i% + 1
LOOP UNTIL i% = UBOUND(Wn!) + 1: ' n%
IF Wn!(getal%) = 0! THEN GOTO Gok
' for debug:
IF getal% = LBOUND(Wn!) - 1 THEN STOP
Getvalue% = getal%
END FUNCTION
SUB Makedomain
'Wanneer de Normalize procedure aangeroepen werd, moet ook het DWn!() array aangepast worden:
'Stap2: maak een waarschijnlijkheids-gebieden-array:
' het trajekt 0-1 wordt in mootjes onderverdeeld zo dat de breedte van elk mootje overeenkomt met de grootte van de waarschijnlijkheid van een numerieke waarde n
REDIM Dwn!(LBOUND(Wn!) TO UBOUND(Wn!))
Dwn!(LBOUND(Wn!)) = Wn!(LBOUND(Wn!))
FOR i% = LBOUND(Wn!) + 1 TO UBOUND(Wn!): '1-n%
Dwn!(i%) = Dwn!(i% - 1) + Wn!(i%)
NEXT i%
END SUB
SUB Normalize STATIC
' deze procedure moet aangeroepen worden telkens iets gewijzigd wordt in de waarschijnlijkhedentabel.Wcnt%()
' stap 1: bereken de som van alle getallen in Wcnt%:
Sigma& = 0
FOR i% = LBOUND(Wcnt%) TO UBOUND(Wcnt%)
Sigma& = Sigma& + Wcnt%(i%)
NEXT i%
' beveiliging tegen mogelijke integer overflows:
IF Sigma& > 32000 THEN
FOR i% = LBOUND(Wcnt%) TO UBOUND(Wcnt%)
Wcnt%(i%) = Wcnt%(i%) / 2
NEXT i%
Sigma& = Sigma& / 2
END IF
' wis de vroegere waarden in Wn!():
REDIM Wn!(LBOUND(Wcnt%) TO UBOUND(Wcnt%))
' normalizeer Wn!(n%):
FOR i% = LBOUND(Wn!) TO UBOUND(Wn!): ' 0-n%
Wn!(i%) = Wcnt%(i%) / Sigma&
NEXT i%
END SUB
SUB Uit (byte%) STATIC
IF Dp% = &H330 THEN
IF INP(&H331) AND 128 THEN
WAIT &H331, 64, 64: OUT &H330, byte%: EXIT SUB
ELSE
WHILE INP(&H331) < 128: dummy% = INP(&H330): WEND
WAIT &H331, 64, 64: OUT &H330, byte%: EXIT SUB
END IF
END IF
END SUB
[Filedate:910212]
Naar inhoudstafel kursus
Naar homepage dr.Godfried-Willem Raes