Functies

Zodra u veel code begint te schrijven, kan je als je wil, een manier vinden om dingen te gaan organiseren en structureren, om deze netter te maken en gemakkelijker te begrijpen. Functies zijn een zeer krachtige manier om dit te doen. Ze brengen ons de mogelijkheid om een naam te geven aan een bundel code. Laten we een kijkje nemen.

Functies definiëren

define :foo do
  play 50
  sleep 1
  play 55
  sleep 2
end

Hier hebben we een nieuwe functie genaamd foo gedefinieerd. We doen dit met onze oude vriend het do/end blok en het magische woord define gevolgd door de naam die wij willen geven aan onze functie. We hoefde deze niet foo te noemen, we konden deze om het even wat noemen zoals fiets, bal of een ideale beschrijving zoals refrein_stuk of lead_riff.

Vergeet niet van een dubbele punt : bij de naam van je functie te voegen wanneer je deze definieert.

Functies aanroepen

Eens we een functie hebben gedefinieerd kunnen we deze oproepen door gewoon zijn naam te schrijven:

define :foo do
  play 50
  sleep 1
  play 55
  sleep 0.5
end
foo
sleep 1
2.times do
  foo
end

We kunnen zelfs gebruik maken van ‘foo’ binnen iteratie blokken of overal waar we spelen of samplen hebben geschreven. Dit schenkt ons een geweldige manier om onszelf te uiten en nieuwe zinvolle woorden te gebruiken in onze composities.

Functies worden onthouden langsheen het uitvoer commando

Tot nu toe was het zo, dat telkens als u de Afspeel-knop ingedrukte, Sonic Pi met een schone lei startte. Het weet weet van niets tenzij van wat er in de buffer zit. Je kan niet verwijzen naar code die in een andere buffer of een andere thread zit. Met functies veranderd dat. Wanneer je een functie definieert zal Sonic Pi zich deze herinneren. Laten we dit eens proberen. Verwijder alle code uit uw buffer en vervang het met:

foo

Druk op de Afspeel-knop - en hoor je functie nu spelen. Zo zonder code? Hoe wist Sonic Pi wat het moest spelen? Sonic Pi herinnerde zich jouw functie - dus zelfs nadat je deze hebt gewist uit de buffer, het herinnerde zich wat jij had getypt. Dit gedrag werkt alleen met functies die zijn gemaakt met define (en defonce).

geparametreerde functies

Interessant om weten ook is dat je net zoals je min als max waarden kan geven aan rrand, kan je ook jouw functies argumenten laten accepteren. Laat ons dat even bekijken:

define :my_player do |n|
  play n
end
my_player 80
sleep 0.5
my_player 90

Dit is niet erg spannend, maar het illustreert wel de zaak. We hebben onze eigen versie van play genaamd ‘my_player’ die is geparametriseerd.

De parameters moeten na de do van het define do/end blok komen te staan, omringd door een sluisteken |en gescheiden door komma’s ,. Om deze parameters te benoemen mag je elk woord gebruiken dat je maar wil.

Het zit ‘h allemaal in de define do/end blok. Je kan de parameternamen gebruiken zoals echte waarden. In dit voorbeeld speel ik de noot n. Je kan deze beschouwen als een soort toezegging, dat wanneer de code loopt, deze door de werkelijke waarden vervangen wordt wanneer je deze benoemd. Ik doe dit met my_player 80. om noot 80 te spelen. Binnen de definitie van deze functie, is nnu vervangen door 80, dus play n verandert in play 80. Wanneer ik deze vernoem met my_player 90´, is n nu vervangen met 90, play nis veranderd in play 90.

Laten we eens kijken naar een interessanter voorbeeld:

define :chord_player do |root, repeats| 
  repeats.times do
    play chord(root, :minor), release: 0.3
    sleep 0.5
  end
end
chord_player :e3, 2
sleep 0.5
chord_player :a3, 3
chord_player :g3, 4
sleep 0.5
chord_player :e3, 3

Hier gebruikte ik repeats als een cijfer in de regel repeats.times do.Ik gebruikte root ook als naam van een noot in mijn play oproep.

Hierbij zien we dat we in staat zijn om iets zeer expressief, maar makkelijk leesbaar te schrijven door onze logica in een functie te steken!