Dus je hebt je fatale baslijn en een vette beat. Hoe speel je ze op hetzelfde moment? Een oplossing is deze handmatig verweven- een beetje bas , dan wat drums, wat meer bas… Lang gaat het niet duren eer je je de timing moeilijk kan voorstellen, zeker als je nog meer elementen hierin wil verweven.
Wat als Sonic Pi deze automatisch kan verweven voor jou? Nou, het kan, en je het doet dat met wat heet een thread.
Om het voorbeeld eenvoudig te houden, moet je je voorstellen dat dit een waanzinnige baslijn is en een vette beat:
loop do
sample :drum_heavy_kick
sleep 1
end
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
Zoals we reeds eerder bespraken, zijn loops zoals zwarte gaten voor het programma. Zodra je in loop bent geraakt, kan je deze niet verlaten totdat u op stop hebt gedrukt. Hoe spelen we dan deze beide loops op hetzelfde moment? We moeten Sonic Pi vertellen dat we iets op hetzelfde moment als de rest van de code willen beginnen. Dit is waar de threads ons redding brengen.
in_thread do
loop do
sample :drum_heavy_kick
sleep 1
end
end
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
Door de eerste loop in een in_thread
do/end block te plaatsen, vertellen we Sonic Pi de inhoud van de do/end block uit te voeren op exact hetzelfde moment als de volgende instructie na de do/end block (toevallig ook onze tweede lus). Probeer het en je zal de baslijn en de drums samen horen spelen!
Wat als we hieraan nog een synth willen toevoegen? Zoiets als:
in_thread do
loop do
sample :drum_heavy_kick
sleep 1
end
end
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
loop do
use_synth :zawa
play 52, release: 2.5, phase: 2, amp: 0.5
sleep 2
end
Nu hebben we hetzelfde probleem als hiervoor. De eerste loop wordt gespeeld op hetzelfde moment als de tweede loop, door onze ‘in_thread’. De derde loop wordt weer nooit bereikt. Daarom hebben we een andere thread nodig:
in_thread do
loop do
sample :drum_heavy_kick
sleep 1
end
end
in_thread do
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
end
loop do
use_synth :zawa
play 52, release: 2.5, phase: 2, amp: 0.5
sleep 2
end
Wat je mischien zal verbazen is dat iedere keer je op de afspeel-knop drukt je eigenlijk een nieuwe thread aanmaakt voor de uitvoerende code. Vandaar dat, wanneer je meerdere keren op afspelen drukt, de klanken op elkaar hoort opstapelen. Vermits deze een thread op zich is, verweeft hij deze code voor jou automatisch.
Als je Sonic Pi leert beheersen, ga je zien dat threads de belangrijkste bouwstenen voor jouw muziek zullen zijn. Eén van de belangrijkste taak die zij hebben is het isoleren van de huidige staat van andere threads. Wat betekend dit? Wel, wanneer je van synth overschakeld door het gebruik van use_synth
schakel je van synth in de huidige thread - geen enkele andere thread zal van synth veranderen. Laten we dit in actie zien:
play 50
sleep 1
in_thread do
use_synth :tb303
play 50
end
sleep 1
play 50
Merk je op dat de middelste klank anders is dan de andere? De use_synth
declaratie zal enkel invloed hebben op de thread waarin deze zich bevind en niet op de threads daarbuiten.
Wanneer je een nieuwe thread met in_thread
creëert, zal de nieuwe thread de instellingen van de huidige thread overnemen. Laten we dit even bekijken :
use_synth :tb303
play 50
sleep 1
in_thread do
play 55
end
Merk je op hoe de tweede noot met de ‘: tb303’ synth wordt gespeeld, hoewel het door een aparte thread werd aangestuurd? Elk van de met verschillende use_*
functies gewijzigde instellingen, zullen zich op dezelfde manier gaan gedragen.
Wannneer threads worden gecreëerd, erven zij alle instellingen over van bovenliggende (parent) maar zij delen geen veranderingen aan hen terug.
Ook nog kunnen wij namen geven aan threads:
in_thread(name: :bass) do
loop do
use_synth :prophet
play chord(:e2, :m7).choose, release: 0.6
sleep 0.5
end
end
in_thread(name: :drums) do
loop do
sample :elec_snare
sleep 1
end
end
Kijk naar het log venster wanneer u deze code uitvoert. Zie je hoe het logboek de naam rapporteert van de thread met een bericht?
[Run 36, Time 4.0, Thread :bass]
|- synth :prophet, {release: 0.6, note: 47}
Wat je nog moet weten over benoemde threads is dat slechts één thread met een bepaalde naam tegelijkertijd kan worden uitgevoerd. Laten we dit onderzoeken met de volgende code:
in_thread do
loop do
sample :loop_amen
sleep sample_duration :loop_amen
end
end
Ga je gang en plak deze in een buffer en druk op de knop afspelen. Druk er opnieuw een paar keer. Luister naar de kakofonie van meerdere amen breaks in loop, uit de maat afspelen . OK, je mag nu op Stop drukken.
Dit soort gedrag hebben we al keer op keer gezien - dat als je de afspeelknop aanklikt, geluidslagen op bestaande klanken gaan stapelen. Dus als je een loop hebt en je klikt drie keer op afspelen zal je drie lagen loops tegelijkertijd horen afspelen.
Met benoemde threads is dat echter anders:
in_thread(name: :amen) do
loop do
sample :loop_amen
sleep sample_duration :loop_amen
end
end
Probeer de afspeel-knop meerdere malen met deze code. Je zal nu één enkele amen break loop horen. Ook zie je dit in het logboek:
==> Skipping thread creation: thread with name :amen already exists.
Sonic Pi vertelt je hier dat een thread met de naam :amen
al aan het spelen is , en gaat geen andere creëren.
Dit gedrag lijkt misschien niet onmiddellijk bruikbaar voor je nu - maar het zal erg handig worden wanneer we beginnen met het spelen van code live…