|
Pagina 12 van 15 Flow control functiesProgramma's zullen afhankelijk van de waarden van variabelen vaak een andere bewerking moeten uitvoeren. Om dit te bereiken gebruiken we relationele functies in ‘flow control’ functies. De al eerder aangehaalde “ forEachEvent” functie, “do” functie en “if” functie zijn zulke ‘flow control’ functies. Allereerst wil ik dieper op de “forEachEvent” functie ingaan. Deze functie is een heel belangrijke functie binnen CAL. In een CAL-programma zal je in de meeste gevallen werken op geselecteerde Events. Door de “forEachEvent” functie te gebruiken leg je de focus van je programma op de geselecteerde Events. Dat wil dus zeggen dat de niet geselecteerde Events niet worden gezien. De functie ziet er als volgt uit: (forEachEvent <functie>) In het algemeen zal je niet één functie binnen een “forEachEvent” functie uitvoeren. Wil je meer functies uitvoeren dan moet je ze combineren binnen de “do” functie. Voordat ik dit in een voorbeeld laat zien, behandel ik eerst de “if” functie: (if <conditie> < TRUE expressie> [<FALSE expressie>]) De conditie zal een relationele functie zijn eventueel gecombineerd met een logische functie. Voor de duidelijkheid kan ik de functie ook - met toelichtend commentaar - schrijven als: | (if <conditie> | | ; als de conditie waar is | | | ; dan | | | | <TRUE expressie> | ; de uit te voeren functies als de ; conditie TRUE is | | | ; anders | | | | [<FALSE expressie>] | ; de uit te voeren functie als de ; conditie FALSE is | | ) ; einde van if | | | In de eerder gegeven voorbeelden hadden we het optionele anders-deel weggelaten. Je ziet ook hier dat er dus maar één functie kan worden uitgevoerd bij TRUE en één bij FALSE. Wil je dus meer functies uitvoeren, dan zal je weer de “do” functie moeten gebruiken. In het volgende voorbeeld laat ik zien hoe één en ander werkt. In dit voorbeeld tellen we het aantal geselecteerde noten. Noten die op hetzelfde moment vallen worden als één noot gezien. In de variabele teller houden we het aantal noten bij en in de variabele vorige de tijd van de daarvoor gevonden noot. | (do | (word teller 0) ; definieer de teller en zet op 0 (dword vorige 0) ; definieer vorige tijd en zet op 0 (forEachEvent ; we testen op alle geselecteerde Events | | (if (== Event.Kind NOTE) ; test of het een NOTE is | (do ; hier gebruiken we een do om een ; een aantal functies te combineren ; dan is het een note ; test de gevonden NOTE ; als de tijd==0 (vorige==0) en de teller==0, is het altijd de eerste NOTE (if (&& (== teller 0) (== Event.Time 0))
| ; dan (= teller 1) ; anders ; als de tijd van de vorige NOTE ongelijk is aan de huidige tijd (if (!= Event.Time vorige) ; first event on time zero ; zet de teller op 1 | ; dan verhogen we de teller en maken ‘vorige’ gelijk aan de huidige tijd (do ; hier gebruiken we een do om een ; aantal functies te combineren | | (++ teller) ; verhoog de teller | | (= vorige Event.Time) ; zet vorige op de huidige tijd | | ) ; einde van do | | ) ; einde van if | | ) ; einde van if | | ) ; einde van do | | ) ; einde van if | | ) ; einde van forEachEvent | | ) ; einde van do en het programma | Bekijk dit voorbeeld goed; hierin zie je belangrijke constructies zoals ze in CAL voorkomen.
Naast de do, if en forEachEvent functies zijn er ook nog andere functies: switch, while en include. (switch <index> <case1> <case1result> <case2> <case2result> ….) Met deze functie kan aan de hand van een specifieke waarde van de variabele index een bewerking worden uitgevoerd. Een praktisch voorbeeld helpt dit duidelijk te maken. Ik laat nu een stukje programma zien waarmee je de GM drumset in een andere drumset om kan zetten. | (switch nNote | | 40 (= nNewNote 50) ; zet Electric snare om in Snare low | | 41 (= nNewNote 55) ; zet Low floor tom om in Tom bass | | ) ; einde van switch | Op deze manier kan je dus een hele reeks noten omzetten in een andere reeks. (while <conditie> <actie>) Zolang de conditie waar is, wordt het programma binnen deze functie doorlopen. Laten we een praktisch voorbeeld bekijken. In een sequence op de plaats rPositie willen we het aantal kloktikken weten dat een tel bevat. | ; eerst bepalen we het begin van de maat | (= rTemp (makeTime (meas rPositie) 1 0)) ; rTemp bevat het begin van de ; maat | | ; Bepaal aantal kloktikken in een tel | | (while (< (beat rTemp) 2) ; zolang de tel kleiner is dan 2 | | (++ rTemp) ; verhoog rTemp | | ) ; einde van while | | ; nu berekenen we het aantal kloktikken van een tel | | (-= (rTemp (makeTime (meas rPositie) 1 0)) ; trek het einde van de eerste tel af | | &nbs; van het begin van de maat | | ; rTemp bevat het aantal kloktikken van een tel op de plaats rPositie | We verhogen rTemp net zolang tot we in de volgende tel komen. Dan vallen we uit de while functie. Nu trekken we het ‘einde van de eerste tel’ af van het ‘begin van de maat’ en bergen het resultaat op in rTemp. (include <file naam>) Deze functie geeft de mogelijkheid om een ander CAL-programma op te roepen binnen een CAL-programma. Een goed voorbeeld van deze functie is het oproepen van een programma om het versienummer te testen. Hierbij als voorbeeld een programma om MIDI-controllers in een sequence in te voegen, waarbij eerst een versietest wordt gedaan: | (do | | | (int nCALVersion 20) | ; vereiste CAL version
| | (include "+need version.cal") | ; test versienummer van CAL | (int nControlNum 7)
| ; Controller nummer default | | (getInt nControlNum "Controller number: " 1 127) | ; haal controller nummer | | (include "+Controller.cal") | ; proces het invoegen | | ) ; einde van do | | | ; einde van het programma | | Het aangeroepen programma.
| (if (< VERSION nCALVersion) | | (do | (pause "MK003: This program requires CAL version " (/ nCALVersion 10) "." (% nCALVersion 10) “ or higher”)) | | (exit) | | ); einde van do | | ); einde van if | | ; einde van programma | Het programma ‘+controller.cal’ is een vrij uitgebreid programma dat te ver gaat voor deze CAL introductie.
|