Introductie
Syntax van CAL
Datatypen
Events
Constanten
Declaraties
Interactie met de gebruiker
Rekenkundige bewerkingen
Relationele functies
Logische operatoren
Muziek tijdfuncties
Flow control functies
Het aanmaken van een CAL-programma
Het uitvoeren van een CAL-programma
In de loop der jaren zijn MIDI-sequencers
uitgebreid met allerlei digitale audio-functies.
Ook hadden ze eerst vooral als doel een externe
synthesizer aan te sturen. Later werden softwarematige
synthesizerfuncties toegevoegd. Functioneel
zijn de programma’s van de diverse
leveranciers steeds meer naar elkaar gegroeid,
maar hebben hun eigen specifieke gebruikersgroepen
gekregen. Cakewalk Professional heeft zich
vanaf versie 2 onderscheiden omdat het de
gebruiker de mogelijkheid biedt om eigen
functies toe te voegen. De Cakewalk
Application Language (CAL) maakt het mogelijk
kleine programma's te schrijven waarmee Cakewalk
aangepast kan worden aan je eigen specifieke
wensen. Met latere versies van Cakewalk is CAL verder uitgebreid, maar de laatste jaren is het wat onderbelicht gebleven.
Nog steeds vergt het veel tijd en inspanning om een goede MIDI-sequence te maken. CAL biedt interessante mogelijkheden om je productiviteit
te vergroten. Veel muziekliefhebbers zijn
echter geen programmeur en CAL is geen eenvoudige
taal die je zo maar toepast. Op internet
zijn echter tal van CAL-programma's te vinden
die zo in Cakewalk gebruikt kunnen worden.
Ikzelf maak meestal een CAL-programma zodra
ik ontdek dat een bepaalde bewerking vaak
terugkomt en ik door een programma veel sneller
tot een goed resultaat kom.
Hier wil ik ingaan op deze programmeertaal en hoe je deze kan toepassen. Ik zal CAL bespreken zoals het bij Cakewalk SONAR kan worden gebruikt. CAL leent zich bij uitstek voor het modificeren van een MIDI-sequence. Je kan hierbij denken aan een triller maken, de sterkte (velocity of Expression) van de noten aanpassen om een natuurlijke aanslag te krijgen, maar ook om de synthesizer instellingen te veranderen. Als een bepaalde standaard edit-functie net niet is wat je nodig hebt, kan je met CAL er één maken die precies doet wat je wilt.
Cakewalk programma's zijn in het algemeen niet zo groot, en naarmate je er handiger in wordt, zal blijken dat je steeds sneller complexere programma's maakt.Allereerst wil ik ingaan op de structuur en opbouw van een CAL-programma. De syntaxis van Cakewalk lijkt sterk op de programmeertaal LISP en dat is even wennen als je hiermee geen ervaring hebt.
Laten we er van uitgaan dat we twee getallen van elkaar willen aftrekken. We zijn gewend dit als volgt te schrijven:2-1In CAL ziet dit er uit als: (- 2 1)
Het min-teken is een functie en de twee getallen zijn de variabelen die bij de aftrekking worden gebruikt. We geven in het volgende voorbeeld de functie (operator) aan met op en de variabelen met var. Een CAL-programma ziet er gestileerd weergegeven als volgt uit:
(do (op var var) (op var var))
Deze geneste structuur is kenmerkend voor
CAL. Om de leesbaarheid van een programma
te bevorderen, wordt het echter meestal niet
op één lijn geschreven:
| (do | ; ieder programma begint met een do opdracht | ||
| (op var var) | ; commentaar wordt achter een ; geschreven | ||
| (op var var) | |||
| ) ; einde van do |
; een goede gewoonte is om het einde van
een ; do opdracht aan tegeven met een ; einde van do |
||
Binnen de do opdracht staat het programma. De do opdracht geeft een rij van opdrachten (statements) aan die bij elkaar horen en dus als het ware één functie vormen.
Variabelen moeten echter alvorens te worden gebruikt, worden gedefinieerd (gedeclareerd); anders worden ze niet door CAL herkend en gezien als een onbekende functie.
Alvorens dieper op de taal in te gaan, wil ik bespreken hoe CAL programma’s gebeurtenissen (Events) in een MIDI-sequence behandelt. Events kunnen zijn: Chords, ‘Channel aftertouch’, Controllers, Expressions, Hair pins, ‘Key aftertouch’, Lyrics, ‘Non-registered Parameter Numbers’, Notes, Patches, ‘Registered Parameter Numbers’, ‘System Exclusive Data Messages’, Text, Wave, Windows ‘Media Control Interface commands’ en Wheel. Het is een mengeling van MIDI, Audio en bladmuziek zaken.
Een MIDI-sequence is georganiseerd per track met Events die op een bepaalde tijd plaatsvinden. Ook is het goed om te realiseren dat als je een MIDI-Channel associeert met een track, alle Events in deze track over het betreffende channel van deze track worden uitgezonden. Een CAL-programma werkt op (een deel van) geselecteerde tracks en loopt één voor één langs deze tracks en bewerkt eventueel de Events in de betreffende track.
Om een beter gevoel te krijgen hoe dit gaat nemen we een klein programma als voorbeeld. In het voorbeeld worden alle noten die zijn geselecteerd op een velocity 100 gezet. De geselecteerde range wordt in het Cakewalk ‘user window’ aangegeven met de waarden in de vensters From en Thru.
| 1 | (forEachEvent |
; proces iedere geselecteerde Event ; binnen de range |
||
| 2 | (if (== Event.Kind NOTE) | ; als het een note is, | ||
| 3 | (= Note.Vel 100) | ; dan zet je de note velocity op 100 | ||
| 4 | ) | ; einde van if | ||
| 5 | ) | ; einde van forEachEvent | ||
Ik heb regelnummers ingevoerd die er normaal niet zijn, maar nu helpen bij de uitleg. Het inspringen maakt het programma leesbaarder, maar is niet strikt noodzakelijk.
Omdat er geen eigen variabelen worden gebruikt, heeft het programma geen declaraties nodig.
In dit programma zie je verder, dat een statement meer dan één regel mag bevatten:
Ik wil nu verder ingaan op de belangrijkste data typen, Events, variabelen en constanten.
CAL kent als variabelen: integers en strings. Een integer in de grootte van 16- of 32-bits - kan zowel met als zonder teken zijn. Integers met teken zijn:
| int | 16-bits, van – 32676 tot +32767; |
| long | 32-bits, van ruim min 2 miljard tot ruim plus 2 miljard. |
Integers zonder teken zijn:
| word | 16-bits, van 0 tot 65536; |
| dword | 32-bits, van 0 tot over de 4 miljard |
Verder kennen we nog de string: een stuk tekst
De programmeur kan variabelen definiëren van bovengenoemde typen en er een naam aan toekennen. Daar komen we later nog op terug.
In CAL kennen we Events (gebeurtenissen). Een Event is van een bepaald type (Event.Kind), gebeurt op een bepaalde tijd (Event.Time) en is gekoppeld aan een Channel (Event.Chan).
We kennen de volgende belangrijke typen Events:
| Event.Kind | Variabelen | Type | Betekenis | Toegestane waarden |
| CHANAFT | ChanAft.Val | int | Sterkte van de druk | 0..127 |
| CONTROL | Control.Num | Int | Control nummer | 0..127 |
| Control.Val | Int | Control waarde | 0..127 | |
| KEYAFT | KeyAft.Key | Int | Hoogte van de noot | 0..127 |
| KeyAft.Val | Int | Sterkte van de druk | 0..127 | |
| PATCH | Patch.Bank | Int | Instrument bank | -1..16383[2] |
| Patch.Num | Int | Instrument nummer | 0..127 | |
| Note.Dur | word | Lengte van de noot | 0..65535 | |
| Note.Key | Int | Hoogte van de noot | 0..127 | |
| Note.Vel | Int | Sterkte van de noot | 0..127 | |
| WHEEL | Wheel.Val | Int> | Wheel waarde | -8192..8191 |
Een Event.Chan kan de waarde 0 tot 15 hebben. In het Cakewalk ‘user window’ zullen deze waarden worden getoond van 1 tot 16.
Event.Time is een variabele van het type dword. Het wordt uitgedrukt in‘raw time’(clock ticks). Deze tijd kan worden omgerekend in maatnummer, tel en aantal tikken (Measure:Beat:Tick).
Er zijn nog meer Events, maar die zijn voor het begrip nu niet van belang. Later komen deze wel aan de orde.
Verder zijn er nog variabelen, die ook in het Cakewalk ‘user window’ zijn te vinden:
| From | Begin marker. Het begin van het geselecteerde gebied. |
| Now | De positie van de ‘bar’ cursor. |
| Thru | Eind marker. Het eind van het geslecteerde gebied. |
| End | Het eind van de sequence. |
Deze variabelen zijn alle van het type dword.
ConstantenCakewalk kent ook een aantal vooraf gedefinieerde constanten:
| TRUE | Een boolean constante die aangeeft dat iets waar is. De waarde is ‘1’. |
| FALSE | Een boolean constante die aangeeft dat iets niet waar is. De waarde is ‘0’. |
| TIMEBASE | Deze constante geeft het aantal tikken per kwartnoot aan. |
| VERSION | Versienummer van CAL. |
Nu we de belangrijkste datatypen hebben leren kennen, kunnen we de functies van CAL bekijken. De functies zijn onder te verdelen in: declaraties, toewijzingen (assignments) , invoer, uitvoer, buffer, rekenkundig, relationeel, boolean, ‘control flow’, ‘musical time’, menu, etc. We zullen een programma laten zien, dat goed aangeeft hoe CAL je productiviteit kan verhogen. Het programma maakt van iedere geselecteerde noot een staccato noot en verhoogt de velocity met 25%.
| 1 | (do | |||||
| 2 | (forEachEvent | ; voor iedere geselecteerde ; event |
||||
| 3 | (if (== Event.Kind NOTE) | ; als het event een noot is | ||||
| 4 | (do | ; dan | ||||
| 5 | (= Note.Dur (/ Note.Dur 2)) | ; halveer je de nootlengten en | ||||
| 6 | (= Note.Vel (/ (* Note.Vel 125) 100)) | ; verhoog de velocity met 25% | ||||
| 7 | (if (> Note.Vel 127) (= Note.Vel 127)) | ; zorg dat de velocity nooit ; groter wordt dan127 |
||||
| 8 | ) | ; einde van do | ||||
| 9 | ) | ; einde van if | ||||
| 10 | ) | ; einde van forEachEvent | ||||
| 11 | ) | ; end of do | ||||
We gaan nu na wat er gebeurt op iedere regel van dit programma.
Wat je ziet is dat bij een geneste structuur,
zoals (= Note.Dur (/
Note.Dur 2)), CAL dit verwerkt van binnen naar buiten.
Dus eerste
wordt (/Note.Dur 2) berekend en daarna dit resultaat gebruikt
in (= Note.Dur …..).
Voordat we variabelen in een CAL-programma
kunnen gebruiken, moeten ze eerst zijn gedefinieerd
(gedeclareerd). Variabelen declareren we
als volgt:
| (int <naam> [<waarde>]) | ; [3]declareert een integer en kent ; eventueel een waarde toe |
| (dword <naam> [<waarde>]) | ; declareert een dubbel word en kent
; eventueel een waarde toe |
| (long <naam> [<waarde>]) | ; declareert een long en kent ; eventueel een waarde toe |
| (string <naam> ["Dit is tekst"]) | ; declareert een string en kent ; eventueel tekst toe |
| (word <naam> [<waarde>]) | ; declareert een word en kent ; eventueel een waarde toe |
| (undef <naam>) | ; wist de naam van een variabele ; uit het geheugen |
Als we geen waarde aan de variabele hebben gegeven, dan is het onvoorspelbaar wat de waarde is.
Later zal ik laten zien hoe de declaratie in een programma wordt gebruikt.
We hebben invoer- en uitvoerfuncties. De invoerfuncties zijn:
(getInt <naam> <prompt> <minimum> <maximum>)
(getWord <naam> <prompt> <minimum> <maximum>)
(getTime <naam> <prompt>)
Hierin is:
| <naam> | de naam van de variabele; |
| <prompt> | het bericht dat in een ‘window’ op het scherm verschijnt; |
| <minimum> | de minimum waarde die de invoer mag hebben; |
| <maximum> | de maximale waarde die de invoer mag hebben. |
Je ziet dat met getInt invoer voor een integer variabele kan worden gevraagd. Bij getWord geldt hetzelfde voor een word variabele. Bij getTime wordt de invoer van de gebruiker die in
‘Measure:Beat:Tick’ wordt ingevoerd, omgezet in ‘raw time’ en opgeslagen in een dword variabele. Bij getTime kunnen geen limieten worden opgegeven.
We breiden het eerste voorbeeld uit 'De syntax
van CAL' nu uit met het vragen aan de gebruiker
om de gewenste Note Velocity waarde op te geven.
|
1 |
(do |
; open het programma |
|
2 |
(int nVelocity 100) |
; declareer de variabele nVelocity |
|
3 |
(getInt nVelocity “Velocity: “ 0 127) |
; vraag om invoer |
|
4 |
(forEachEvent |
; proces iedere geselecteerde |
|
5 |
(if (== Event.Kind NOTE) |
; Als het een note is, |
|
6 |
(= Note.Vel nVelocity) |
; dan zet je de note velocity |
|
7 |
) |
; einde van if |
|
8 |
) |
; einde van forEachEvent |
|
9 |
) |
; einde van do |
In de toegevoegde programmaregels gebeurt het volgende:
De uitvoerfuncties zijn:
(message <waarde> [[<waarde>] …...])
(pause <waarde> [[<waarde>] …...])
(format <waarde> [[<waarde>] …...])
Deze functies geven een bericht in de ‘status bar’ van Cakewalk. Bij de pause functie stopt Cakewalk. Via een ‘dialoog window’ krijgt de gebruiker de mogelijkheid door te gaan (OK) of het proces af te breken (CANCEL). Het bericht van message en pause in de ‘status bar’ kan opgebouwd zijn uit een willekeurige combinatie van variabelen van het type: string, integer, long, word en dword.
De format functie is niet echt een uitvoerfunctie, maar converteert een combinatie van variabelen tot één string.
De functie message wordt vooral gebruikt om bijvoorbeeld extra informatie aan de gebruiker te verschaffen of voortgangsberichten naar de gebruiker te sturen. De pause functie is handig bij het testen van programma's.
We breiden ons voorbeeld programma nu uit met een extra informatie bij het vragen van invoer door de gebruiker.
|
1 |
(do |
; open het programma |
||
|
2 |
(int nVelocity 100) |
; declareer de variabele nVelocity |
||
|
2a |
(message "Toegestane waarden voor velocity zijn: 0 tot en met 127") |
|||
|
3 |
(getInt nVelocity “Velocity: “ 0 127) |
; vraag om invoer |
||
|
4 |
(forEachEvent |
; proces iedere geselecteerde |
||
|
5 |
(if (== Event.Kind NOTE) |
; Als het een note is, |
||
|
6 |
(= Note.Vel nVelocity) |
; dan zet je de note velocity |
||
|
7 |
) |
; einde van if |
||
|
8 |
) |
; einde van forEachEvent |
||
|
9 |
) |
; einde van do |
||
We verklaren hieronder alleen de toegevoegde programmaregel:
2a. Alvorens de gebruiker om invoer te vragen wordt met de functie message een bericht op de status bar’ gegeven, waarin de toegestane waarde van de invoer wordt aangegeven.
In een programma zal je vaak rekenkundige
bewerkingen moeten uitvoeren op je gegevens
in de MIDI-sequence. CAL kent de volgende
rekenkundige functies:
| (+ <operand1> <operand2>) | ; telt operand2 bij operand1 |
| (- <operand1> <operand2>) | ; trekt operand2 van operand1 af |
| (* <operand1> <operand2>) | ; vermenigvuldigt operand2 met operand1 |
| (/ <operand1> <operand2>) | ; deelt operand1 door operand2 |
| (% <operand1> <operand2>) | ; rest van de deling van operand1 door
; operand2 |
| (++ < variabele>) | ; verhoogt de waarde van variabele met één |
| (-- <variabele>) | ; verlaagt de waarde van de variabele
met
; één |
| (random <minimum> <maximum>) | ; geeft een willekeurig getal tussen
minimum
; en maximum |
De meeste functies spreken voor zich, maar de “%” (modulo) functie kan wel een nadere toelichting gebruiken. In CAL bestaan alleen hele getallen. Als er door een deling een rest overblijft, kan deze met de “%” functie worden gevonden. Ik zal dit toelichten met een voorbeeld. In dit voorbeeld willen we weten wat het versienummer is van CAL en dat aan de gebruiker laten zien.
Versienummers zien er bijvoorbeeld uit als: 4.5. CAL bewaart zijn versienummer in de constante VERSION. Daar CAL alleen hele getallen kent is dit versienummer vermenigvuldigd met 10. Dus in VERSION staat volgens ons voorbeeld: 45.
Een bericht naar de gebruiker kunnen we als volgt programmeren:
(pause "De versie van CAL is: " (/ VERSION 10) "." (% VERSION 10))
Het getal voor de punt volgt uit: (/ VERSION 10) en het getal na de punt berekenen we met (% VERSION 10). Analyseer zelf hoe het bericht is samengesteld met een aantal strings en deze berekeningen. De gebruiker krijgt te zien: De versie van CAL is: 4.5.
De “random” functie is een beetje vreemde eend in de bijt. Hiermee kan een zogenaamd willekeurig getal worden gegenereerd, dat ligt tussen het minimum en maximum.
Met deze functies vergelijken we twee getallen. Met de uitkomst van dergelijke vergelijkingen (TRUE of FALSE) kan het verloop van een programma worden beïnvloed. CAL kent de volgende relationele functies:
(== <operand1> <operand2>) ; test of operand1 gelijk is aan operand2
(!= <operand1> <operand2>) ; test of operand1 ongelijk is aan operand2
(< <operand1> <operand2>) ; test of operand1 kleiner is dan operand2
(<= <operand1> <operand2>)
; test of operand1 kleiner is dan of gelijk
is
; aan
operand2
(> <operand1> <operand2>) ; test of operand1 groter is dan operand2
(>= <operand1> <operand2>)
; test of operand1 groter is dan of gelijk
is
; aan
operand2
De uitkomst van dergelijke functies is altijd
een waarde 1 (TRUE) of 0 (FALSE). Een voorbeeld van het gebruik hebben we
al gezien bij de introductie:
| (if (== Event.Kind NOTE) | |
| ; hier staat de functie die wordt uitgevoerd bij een uitkomst gelijk aan TRUE | |
| ) ; einde van if | |
Logische operatoren worden gebruikt om testen te combineren. Dit wordt het duidelijkst met een voorbeeld. CAL kent twee logische operatoren:
(&& <operand1> <operand2>) ; TRUE als beide operanden TRUE zijn
(|| <operand1><operand2>) ; TRUE als minstens één operand TRUE is
Als voorbeeld gebruiken we een test of het
Event een NOTE is en de Velocity gelijk is aan 60:
| (if (&& (== Event.Kind NOTE) (== Note.Vel 60)) | |
| ; hier staat de functie die wordt uitgevoerd bij een uitkomst gelijk aan TRUE | |
| ) ; einde van if | |
CAL kent enkele functies voor het omzetten van muziek tijd in de SONAR tijd.
SONAR kent de ‘measure’, ‘beat’ en ‘tick’ (M:B:T). In de muziek kennen we de maat (measure) en tel (beat). Voor MIDI is een grotere nauwkeurigheid nodig, daarom kent SONAR ook de kloktik (tick). Deze maat, tel en kloktikken kunnen worden omgezet in de ruwe tijd (raw time) van SONAR. Deze ‘raw time’ is het aantal kloktikken vanaf het begin van een muziekstuk. Uit de ‘raw time’ kunnen we de maat, tel en overblijvende kloktikken bepalen.
(meas <rawtime>)> ; bepaalt de maat uit de ruwe tijd
(beat <rawtime>) ; bepaalt de tel uit de ruwe tijd
(tick <rawtime>)> ; bepaalt de kloktikken uit de ruwe tijd
Het is goed om te onthouden dat een maat altijd groter of gelijk is aan 1. Dit geldt ook voor de tel. Het aantal kloktikken loopt van nul tot één tik minder dan de lengte van een tel uitgedrukt in kloktikken.
Omgekeerd kunnen we ook de ‘raw time’ uit de maat, tel en kloktikken bepalen:
(makeTime <maat> <tel> <kloktikken>)
Zo kan je het begin van de vijftiende maat in kloktikken bepalen met:
(makeTime 15 1 0)
Mede met de constante TIMEBASE die het aantal kloktikken per kwartnoot geeft, kunnen we bijvoorbeeld nootwaarden omrekenen in kloktikken en omgekeerd.
Programma'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 |
| ; 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 artikelenreeks. Geïnteresseerden kunnen het echter vinden in de CAL bibliotheek op deze WEB-site.
In eerdere versies van Cakewalk was een speciale CAL-editor ingebouwd. Met de introductie van Cakewalk SONAR is deze verdwenen. We zullen daarom van standaard editors gebruik moeten maken. [4]
CAL-programma's zijn tekstbestanden die we bijvoorbeeld kunnen maken met ‘Microsoft Word’. Het eerder getoonde voorbeelden kunnen zonder de regelnummers worden ingetikt met ‘Word. Daarna slaan we ze op met de opdracht ‘Opslaan als..’, waarbij we aangeven dat het een tekstbestand is. We geven het de extensie ‘CAL’ [5] . De bestandsnaam zetten we tussen dubbele aanhalingstekens [6] . Het programma zou Note velocity.cal” kunnen heten.
Van de MIDI-sequence selecteer je in Cakewalk de track of range waarop je het programma wilt laten werken. Daarna roep je een lijst van CAL-programma's op doormiddel van het pull-down’menu ‘'Process/Run CAL... Ctrl+F1'’[7] of direct door de toetsencombinatie ‘Ctrl+F1. Uit deze lijst kun je kiezen welk programma moet worden uitgevoerd. Selecteer het programma en kies ‘Openen.
[1] Tussen de beide gelijktekens zit geen spatie.
[2] ‘-1’ betekent: niet gedefinieerd.
[3] <naam> geeft een verplichte variabele
naam aan. Variabelen tussen [ ] zijn optioneel.
[4] Een CAL-editor in embryonaal stadium is te
vinden op: http://www.collusioninc.org.uk
[5] De te gebruiken naam van de map, waarin we
het bestand moeten opbergen, kan gevonden
worden onder Cakewalks ‘Options/Global…/Folders.
[6] De dubbele aanhalingstekens zorgen er voor
dat ‘Word’ geen extensie TXT
toevoegt aan de bestandsnaam.
[7] Dit geldt voor Cakewalk SONAR. In vroegere
versies van Cakewalk worden andere menu's
gebruikt.