Dr.Godfried-Willem RAES

Kursus Experimentele Muziek: Boekdeel 1: Algoritmische Kompositie

Hogeschool Gent: School of Arts


Naar inhoudstafel kursus

1172: Stochastiek

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%

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