Dr.Godfried-Willem RAES

Kursus Experimentele Muziek: Boekdeel 1: Algoritmische Kompositie

Hogeschool Gent : Departement Muziek & Drama


<Terug naar inhoudstafel kursus>

 ../gmt/manual.html

 1134: Multitasking

 1135:

Ritmiek in kompositorische multitaskers

In <GMT> voorzagen we deze strukturen ('Types') voor de beschrijving van een muzikaal proces -een 'organisme' bij wijze van metafoor- (cfr. GMT-manual en source code):

TYPE MTtask

InitRSI AS INTEGER ' initiele oproepfrekwentie

rsi AS INTEGER ' momentele oproepfrekwentie

starttime AS INTEGER ' tijd waarop de taak werd gestart of moet starten

stoptime AS INTEGER ' tijd waarop de taak moet eindigen

name AS STRING * 8 ' string beschrijving van de taak

level AS INTEGER ' meestal gebruikt als volumeregelaar voor de output van die taak

kanaal AS INTEGER ' meestal gebruikt voor het te gebruiken midi-kanaal

chord AS INTEGER ' kan ook H() AS Harmtype... zijn. Bijhouden harmonische situatie

patch AS INTEGER ' meestal gebruikt voor midi-instrumentatie van de taal

duur AS INTEGER ' duur van de taak

END TYPE

In deze struktuur, die een aantal muzikale eigenschap van een proces beschrijven op een bepaald ogenblik, liggen nog geen mogelijkheden vervat om met ritmische patronen om te gaan. Een dinamische beschrijving van de parametrische veranderingen van deze eigenschappen vergt de integratie van de tijdsdimensie in de struktuur. Uiteraard kunnen we, wanneer we het eenvoudig willen houden, elke klank-genererende taak een ritmisch verloop geven door binnen de taak zelf het rsi interval te moduleren:

Bvb. een accellerando voor een bepaald muzikaal proces gekodeerd als taak binnen GMT kan alsvolgt:

DECLARE SUB Muz1

STATIC cnt%

...

... kode waarin bvb. een nieuwe te spelen noot wordt berekend en naar de midi I/O taak verzonden.

...

Task(15).rsi = Task(15).rsi - (Task(15).rsi / 20) :' de taak Muz1 versnelt 5% na elke oproep

IF Task(15).rsi <= Task(15).InitRsi / 2 THEN Task(15).rsi = Task(15).InitRsi/ 2 :' we begrenzen tot het dubbele tempo is bereikt.

' we zouden ook van cnt% gebruik kunnen maken om bvb. slechts 5 stapjes te versnellen:

Task(15).rsi = Task(15).rsi - 1

cnt% = cnt% + 1

IF cnt% = 5 THEN cnt% =0

END SUB

Het is met een beetje fantasie best mogelijk op deze wijze allerlei ritmische patronen binnen de taak zelf te genereren. In werkelijkheid echter -en hier sluiten we nauwer aan bij de gebruikelijke kompositorische terminologie - doen we hier niets anders dan tempomodulatie van de muzikale generatoren of taken.

In een meer flexibele en algemene benadering kunnen we beter de muzikale taak zien als een 'maat-eenheid', een beetje zoals in traditionele kompositie. Die maat kan dan op de meest diverse wijzen worden onderverdeeld, waardoor uiteraard een ritmisch patroon kan ontstaan.

Wanneer het patroon vast ligt, kan het uiteraard opgeslagen worden in een op voorhand bepaald array:

MTritm!(0 TO Size%)

Willen we ons beperken tot de antieke ritmische verdelingen in 'notenwaarden', dan kunnen we ook patroonarrays bouwen die nauw bij de oude muziekteorie aansluiten (bvb. op DARMS geinspireerde kodering):

W

Hele noot

H

Halve noot

Q

Vierde noot

E

Achtste noot

S

Zestiende noot

T

Tweeendertigste noot

G

Versieringsnoot, voorslag ('grace'-note)

Voor gepunte waarden, voegen we gewoon punten toe. Voor groeperingen in triolen etc. kunnen we haakjes gebruiken... Wanneer we rusten willen invoegen gebruiken we dezelfde lettersymbolen, maar laten ze voorafgaan door een 'R'. Alle ritmische figuren uit de gehele westeuropese geschiedenis van de bladmuziekkompositie kunnen op deze wijze worden voorgesteld en uigedrukt.

Omdat het in onze bedoeling ligt het kompositorische denken te verruimen tot ver buiten de traditionele (en populaire) koncepten en mogelijkheden, hebben we deze aanpak in onze <GMT> projekten niet verder geimplementeerd. Dit traditionele koncept laat inderdaad geen volkomen vrije patroonvorming binnen maten toe: alles is binair of ternair.

In onze aanpak binnen <GMT> bestaat elke 'maat' -haar tempo of periodiciteit is bepaald in Taks().InitRsi- uit een variabel en moduleerbaar aantal 'tiks' of onderverdelingen. De onderverdelingen of het ritmisch patroon wordt gegeven door een reeks getallen waarbij positieve waarden 'output' of klankgeneratie aanduiden, terwijl negatieve waarden worden gebruikt voor 'rusten' of klankpauses. Een nul in de getallenreeks wordt gebruikt als signaalteken voor het aanduiden van het einde van het patroon.

Een voorbeeld: stel het patroon [Q Q E E Q]. Dit wordt dan in onze konceptie:

MTritm!(0) = 2

MTritm!(1) = 2

Mtritm!(2) = 1

Mtritm!(3) = 1

Mtritm!(4) = 2

Mtritm!(5) = 0

De hier gebruikte numerieke waarden zijn arbitrair! Wat het patroon bepaald is de onderlinge verhouding van deze numerieke waarden. Volgende invulling van hetzelfde array, levert dan ook een identisch resultaat:

MTritm!(0) = 8

MTritm!(1) = 8

Mtritm!(2) = 4

Mtritm!(3) = 4

Mtritm!(4) = 8

Mtritm!(5) = 0

Het voordeel van deze voorstelling, is dat te 'tik-eenheid' nu duidelijk de 'tweeendertigste' is geworden, waardoor een wijziging van het ritmisch patroon naar Q Q EE E RS S wordt:

MTritm!(0) = 8

MTritm!(1) = 8

Mtritm!(2) = 4

Mtritm!(3) = 4

Mtritm!(4) = 4

Mtritm!(5) = -2

Mtritm!(6) = 2

Mtritm!(7) = 0

Maar, dit formaat laat ook volkomen irrationale ritmische patronen toe, zoals bvb.:

MTritm!(0) = 0.2345

MTritm!(1) = 0.111

Mtritm!(2) = ATN(1)

Mtritm!(3) = EXP(1)

Mtritm!(4) = -SQR(2)

Mtritm!(5) = SIN(2.3)

<GMT> werd voorzien van enkele intrinsieke funkties die het werken met ritmische patronen kunnen vergemakkelijken.

De funktie GetRitmTiks%(taaknummer%, ritmearray()) bvb. retourneert het aantal tiks in de taak overeenkomstig het patroon in het ritmearray. Taken die van de ritmiek funkties gebruik maken moeten in hun procedure kode een ritmeteller bijhouden.

De kode voor deze funktie as alsvolgt:

FUNCTION GetRitmTiks% (taaknummer%)

' wanneer in het array een nul staat is het ritmisch patroon gedaan.' Positieve waarden = klank, Negatieve waarde = rust. Nul = einde patroon

i% = 0

tiks% = 0

DO

tiks% = tiks% + ABS(MTritm!(taaknummer%, i%))

i% = i% + 1

LOOP UNTIL i% > UBOUND(MTritm!, 2)

GetRitmTiks% = tiks%

END FUNCTION

De funktie die ons de afmetingen (het aantal tijd-events binnen een cyclus) van een ritmisch patroon retourneert ziet er zo uit:

FUNCTION GetRitmSize% (taaknummer%)

i% = -1

DO

i% = i% + 1

IF MTritm!(taaknummer%, i%) = 0 THEN i% = i% - 1: EXIT DO

LOOP UNTIL (i% = UBOUND(MTritm!, 2))

' wanneer in het array een nul staat is het ritmisch patroon gedaan.' Positieve waarden = klank, Negatieve waarde = rust' Nul = einde patroon' de nul zelf mag niet worden geteld!' (-> divide 0 error in MT!)

IF i% < 0 THEN BEEP: STOP: ' is illegal!

GetRitmSize% = i%

END FUNCTION

Een voorbeeld voor de mogelijke kodering van een muzikaal proces met ritmiek kan eruit zien als:

SUB MuziekTaak

' stel dat dit taak 15 is...

STATIC Ritmeteller

Aantaltikken% = GetRitmTiks%(15, ritmerarray())

IF Ritmeteller% > UBOUND(ritmearray,2) THEN Ritmeteller%= 0

' kode voor de bepaling van de klanken zelf...

' ...

Task(15).rsi = Task(15).Initrsi * ritmearray(Ritmeteller) / Aantaltikken%

Ritmeteller% = Ritmeteller% + 1

END SUB


Voorbeeldkompositie:

Godfried-Willem Raes <Counting down from 747> Een beschrijvende tekst over deze kompositie is beschikbaar op de logos homepage. <CDF747.html> Real-time elektroakoestische muziek, voor komputer (Pentium PC) en EMU procussion sample player.De kode voor de globale en gedetaileerde ritmiek - hier een afzonderlijke taak- verloopt zo:

SUB Ritmiek

STATIC Toggle0%, Lt%, Ht%, oldsize%, patroonmaximum%

' in deze taak (nr.29) worden de ritmische patronen voor' de generatoren in tasks 15-23 bepaald en berekend.' De patronen staan in de arrays MTritm!(15-24)' Positieve waarden zijn event-tijdsduren' Negatieve waarden zijn rusten.

IF Toggle0% = False THEN

Lt% = 15

Ht% = 23

REDIM PRESERVE MTritm!(Lt% TO Ht%, 0 TO 0): ' 9 tasks

FOR i% = Lt% TO Ht%

MTritm!(i%, 0) = 1: ' hele noten on init.

NEXT i%

Toggle0% = True

oldsize% = 0

patroonmaximum% = 48: ' risiko op /0 errors want ' indien te groot, kan de Task().rsi deling' in de tasks nul opleveren!!!' Dit is het geval voor 74...' De waarde is afhankelijk van de komputer en' van de belasting van GMT.

END IF

' halve kwadraat-sinus voor verloop van de patroonlengte:

halfsin! = (SIN(Tang!(29) / 2)) ^ 2: ' hoek van 0 tot Pi

size% = halfsin! * patroonmaximum%

IF size% <> oldsize% THEN

REDIM PRESERVE MTritm!(Lt% TO Ht%, 0 TO size%)

oldsize% = size%

END IF: ' was at end of procedure!

FOR i% = Lt% TO Ht%

' patterncode...

a% = RND(1) * 10!

SELECT CASE a%

CASE IS < 1: MTritm!(i%, 0) = -1

CASE IS < 4: MTritm! = -a%

CASE ELSE: MTritm! = a%

END SELECT

j% = 1

DO

IF j% > size% THEN EXIT DO

a% = RND(1) * 9!

SELECT CASE a%

CASE IS <= 4: MTritm!(i%, j%) = MTritm!(i%, j%) - 1

CASE IS <= 7: ' niks

CASE ELSE: MTritm!(i%, j%) = MTritm!(i%, j%) + 1

END SELECT

IF MTritm!(i%, j%) = False THEN EXIT DO

' vermijd opeenvolgende rusten:

IF (MTritm!(i%, j% - 1) < 0) AND (MTritm!(i%, j%) < 0) THEN

MTritm!(i%, j% - 1) = MTritm!(i%, j% - 1) + MTritm!(i%, j%)

MTritm!(i%, j%) = 0

END IF

j% = j% + 1

LOOP UNTIL j% > size%

' korrektie om globale drieledigheid te verkrijgen

DO

tiksom% = GetRitmTiks%(i%)

IF tiksom% MOD 3 <> 0 THEN

IF MTritm!(i%, 0) < 0 THEN

MTritm!(i%, 0) = MTritm!(i%, 0) - 1

ELSE

MTritm!(i%, 0) = MTritm!(i%, 0) + 1

END IF

ELSE

EXIT DO

END IF

LOOP

NEXT i%

UBOUND(MTritm!, 2); " ";

Task(29).rsi = Lps%: ' => 747 ritmische refreshes (1 per sekonde)

END SUB


Filedate: 971109/971201/2003-11-25

Terug naar inhoudstafel kursus: <Index Kursus>

Naar homepage dr.Godfried-Willem RAES

 <GMT>-Manual