Yritys saada tietokoneohjelma tuottmaan amatöörin korviin siedettävää musiikkia
Heikin pohteita > Ohjelmointia, matematiikkaa, fysiikkaa … > Ohjelmallista musiikkia > Polyrytmistä rummutusta Sonic Pi:llä (2016-2-25)
Miten tuottaa ohjelmallisesti jotain soiton tapaista muutamalla yksinkertaisella säännöllä ja ripauksella satunnaisuutta?
Helmikuu 2016
Tällaista
Musiikin teoriaa en paljoa tunne, mutta afrikkalaiseen rummutukseen perehtyessäni opin, että polyrytmisyys voi tuoda eloa muuten yksitoikkoiseen jumputukseen. Laitoin siis ohjelmani soittamaan useampaa perusjumputusta kutakin omaan tahtiinsa.
Perusjumpukseni tahdit jaan kolmeen, neljään tai viiteen tasaväliseen iskuun. Jotenkin tuohon tyylin olen ymmärtänyt nuottejakin ripoteltavan tahdin sisään. Käytän sääntöä, että tahdin alussa on hyvä olla muita lujempi isku ja tahdin "keskivaiheilla" voi olla vähän vaimeampi isku ja vielä voi lyödä kevyesti pari kertaa tahdin muissa kohdissa.
Ylätason rytmi on kiinteä. Tempoa ohjelmani vaihtelee – luullakseni. Tahtien jakoa iskuihin ja iskujen voimakkuuksia ohjelma vaihtaa satunnaisesti ylätason syklin vaihtuessa.
Musiikista enemmän ymmärtävä keksisi varmaan helposti sääntöjä, jotka tekisivät soitosta mielenkiintoisempaa. Saattaa olla, että teen jotain hölmösti ja pienellä musiikin lisäopiskelulla saisin aikaiseksi jotain jännempää.
Afrikkalaisessa musiikissa on kuulemma oma rytminsä käsille, lanteille ja jaloille. Innostuin laittamaan soittooni vielä neljännenkin rytmin, joten tämän tahdissa voisi afrikkalaisenkin olla vaikea tanssia.
Ohjelmanpätkääni tuli lopulta rivejä melkein 300, mutta ei se silti kovin monimutkainen ole. Ohjelma toimii, mutta saattaa siinä silti olla virheitä. Jos et siis ymmärrä jotain kohtaa, joko 1) et ymmärrä, 2) minä en ole ymmärtänyt.
# Ohjelma luo polyrytmistä rummutusta, joka ainakin minun epämusikaalisiini korviini
# kuulostaa aika ajoin musiikilta.
# Ohjelmassa neljä "rumpalia" paukuttaa kukin eri tahtiin yksinkertaista
# rytmikuviota. Polyrytmisyyden idea on se, että eri tahtisten paukutusten
# yhdistäminen, interferenssi, saattaa tuottaa mielenkiintoisia rytmejä.
# En tunne musiikkia enkä musiikin termistöä, joten siltä osin tästä ei
# kannata ottaa oppia
# Käytössä olevan lyömäsoittimet
allDrums = [:sn_dub,
:sn_dolf,
:sn_zome,
:bd_ada,
:bd_pure,
:bd_808,
:bd_zum,
:bd_gas,
:bd_sone,
:bd_haus,
:bd_zome,
:bd_boom,
:bd_klub,
:bd_fat,
:bd_tek,
:drum_heavy_kick,
:drum_tom_mid_soft,
:drum_tom_mid_hard,
:drum_tom_lo_soft,
:drum_tom_lo_hard,
:drum_tom_hi_soft,
:drum_tom_hi_hard,
:drum_splash_soft,
:drum_splash_hard,
:drum_snare_soft,
:drum_snare_hard,
:drum_cymbal_soft,
:drum_cymbal_hard,
:drum_cymbal_open,
:drum_cymbal_closed,
:drum_cymbal_pedal,
:drum_bass_soft,
:drum_bass_hard,
:perc_bell,
:perc_snap,
:perc_snap2,
:sn_dub,
:sn_dolf,
:sn_zome]
# Jollain näistä lyödaan tahdin pääisku. Esim 3 tarkoittaa ylläolevan listan
# neljättä soitinta (Indeksointi alkaa 0:sta, vähennä 10 rivinumerosta)
drum_hard = [3,8,9,10,14,17,19,21,32]
# Jollain näistä lyödään tahdin keskivaiheilla "puoli-isku"
drum_mid = [6,15,16,20,31]
# Jollain näistä lyödään toisinaan edellisten lisäksi vaimea isku
drum_low = [4,7,11,12,13,18]
tempo = 180
use_bpm tempo
# polyrytmisyyttä on selitetty seuraavassa
# http://music.tutsplus.com/articles/introduction-to-polyrhythms--audio-2573
# Perusidea on, että tietyssä ajassa eri soittajat soittavat eri määrän tahteja.
# Esimerkiksi 4/3 polyrytmissä toinen soittaa 12 tahdin jaksossa 4 tahtia, toinen 3.
# Rytmikuvio siis toistuu 12 tahdin mittaisissa jaksoissa
# Seuraavassa dt0 on tuo jakson pituus. 4/3 polyrytmissä sen siis pitäisi olla 12 ja
# tempoa säädettäisiin muuttujalla tempo.
# Osoittautui kuitenkin helpommaksi olla välittämättä tahdin pituuden ja tempon
#välisestä yhteydestä (tempo 60 bpm -> tahti on sekunnin mittainen) ja valita
# dt0:ksi joku luku ja virittää tempo sen jälkeen sopivaksi
dt0 = 18.0
# Ohjelmassa käytetään näennäissatunnaislukuja.
# Ne ovat tilastollisesti ottaen satunnaisia, eli näyttävät satunnaisilta,
# mutta ne toistuvat joka ajolla samoina.
# Muuttamalla random_seediä, saadaan erilainen sarja satunnaislukuja ja 'kappale'
# tavallaan alkaa eri kohdasta
use_random_seed 200
# Valittavana on jakaa tahti kolmeen, neljään tai viiteen iskuun
# Tämä selviää myöhemmin
sels = [3,4,5]
# # # # # # # # # # # # # # # #
# Funktio params tuo satunnaisuutta soittoon.
# Tämän funktion antamilla parametreillä soitetaan yksi jakso.
# Kommentoin pois osan eri iskujen voimakkuuksien satunnaisuudesta
define :params do
# amps = [0.2, 0.4, 0.6, 0.8, 1.0]
# pans = [-1.0, -0.8, -0.6, 0.6, 0.8, 1.0]
# clhs = [0.5,0.75,1.0,1.0]
# cls1 = [0.25,0.5,0.75,1.0]
# cls2 = [0.0,0.25,0.5,0.75]
amps = [0.25, 0.5, 0.75, 1.0]
pans = [-1.0, -0.75, 0.75, 1.0]
# clhs = [0.5, 0.75, 1.0]
# cls1 = [0.25, 0.5, 1.0]
# cls2 = [0.25, 0.5, 1.0]
# Valitaan instrumentit
# choose valitsee listalta satunnaisesti yhden alkion
ih = choose(drum_hard)
im = choose(drum_mid)
il = choose(drum_low)
dr_h = allDrums[ih]
dr_lh = allDrums[im]
dr_l = allDrums[il]
# Valitaan iskujen voimakkuudet
# Kommentoin pois osan satunnaisuudesta
amph = choose(amps)
# clh = choose(clhs)
# cl1 = choose(cls1)
# cl2 = choose(cls2)
clh = 1.0
cl1 = 1.0
cl2 = 1.0
amplh = clh*amph
ampl1 = cl1*amplh
ampl2 = cl2*amplh
pan = choose(pans)
return dr_h, dr_lh, dr_l, amph, amplh, ampl1, ampl2, pan
end
# # # # # # # # # # # # # # # # # # # # # #
# Tahdin sisällä lyödään 3, 4 tai 5 iskua seuraavien rytmikuvioiden
# mukaisesti
# Parametri n kertoo, montako tahtia per rytmijakso lyödään
# lista nn kertoo, mitkä ylätason syklin tahdeista soitetaan,
# minkä aikana pidetään taukoa
# Kolme iskua per tahti: Tasavälein pääisku - puoli-isku - kevyt isku
define :iskut3 do |nn|
n = nn.length
dt = dt0/n/3.0
dtb = dt0/n
drumh, drumlh, druml, amph, amplh, ampl1, ampl2, pan = params
for b in nn
if b == 1 then
sample drumh, amp: amph, pan: pan
sleep dt
sample drumlh, amp: amplh, pan: -pan
sleep dt
sample druml, amp: ampl1, pan: -pan
sleep dt
else
sleep dtb
end
end
end
# Neljä iskua per tahti: Tasavälein
# pääisku - kevyt isku - puoli-isku - kevyt isku
define :iskut4 do |nn|
n = nn.length
dt = dt0/n/4.0
dtb = dt0/n
drumh, drumlh, druml, amph, amplh, ampl1, ampl2, pan = params
for b in nn
if b == 1 then
sample drumh, amp: amph, pan: pan
sleep dt
sample druml, amp: ampl1, pan: -pan
sleep dt
sample drumlh, amp: amplh, pan: -pan
sleep dt
sample druml, amp: ampl2, pan: pan
sleep dt
else
sleep dtb
end
end
end
# Viisi iskua per tahti: Tasavälein
# pääisku - kevyt isku - puoli-isku - kevyt isku - kevyt isku
define :iskut5 do |nn|
n = nn.length
dt = dt0/n/5.0
dtb = dt0/n
drumh, drumlh, druml, amph, amplh, ampl1, ampl2, pan = params
for b in nn
if b == 1 then
sample drumh, amp: amph, pan: pan
sleep dt
sample druml, amp: ampl1, pan: -pan
sleep dt
sample drumlh, amp: amplh, pan: -pan
sleep dt
sample druml, amp: ampl2, pan: pan
sleep dt
sample druml, amp: ampl2, pan: pan
sleep dt
else
sleep dtb
end
end
end
# # # # # # # # # # # # # # # # # # # # # #
# Tehosteella gverb saadaan rummutus kaikumaan
with_fx :gverb, room: 20.0, spread: 1.0, release: 3, mix: 0.5, damp: 0.5 do
# Kullekin rummulle käynnistetään oma säie - thread.
# Kutakin säiettä suoritetaan rinnakkain samanaikaisesti
# # # # # # # # # # # # # # # # # # # # # #
in_thread do
sync :start3 # Tämä säie odottaa synkronointikäskyä :start3
nn = [1,1,1] # kolme tahtia ylätason syklissä, soitetaan kaikki
# seuraavan silmukan kierros vastaa yhtä polyrytmin sykliä
loop do
# Valitaan, montako iskua per tahti lyödään tässä syklissä
sel = choose(sels)
if sel = 3 then
iskut3(nn)
else
if sel = 4 then
iskut4(nn)
else
iskut5(nn)
end
end
end
end
in_thread do
sync :start4 # säie odottaa synkronointikäskyä :start4
n_tahti = 4
nn = [1,1,1,1]
loop do
sel = choose(sels)
if sel = 3 then
iskut3(nn)
else
if sel = 4 then
iskut4(nn)
else
iskut5(nn)
end
end
end
end
in_thread do
sync :start5 # säie odottaa synkronointikäskyä :start5
n_tahti = 5
nn = [1,1,1,1,1]
loop do
sel = choose(sels)
if sel = 3 then
iskut3(nn)
else
if sel = 4 then
iskut4(nn)
else
iskut5(nn)
end
end
end
end
in_thread do
sync :start7
n_tahti = 7
nn = [1,1,1,1,1,1,1]
loop do
sel = choose(sels)
if sel = 3 then
iskut3(nn)
else
if sel = 4 then
iskut4(nn)
else
iskut5(nn)
end
end
end
end
# # # # # # # # # # # # # # # # # # #
## Pääohjelma alkaa
dt0 = 8
# Aloitetaan rumpu kerrallaan.
cue :start3
sleep(3*dt0)
cue :start4
sleep(3*dt0)
cue :start5
sleep(3*dt0)
cue :start7
sleep(3*dt0)
# Vaihdellaan syklin kestoa eli tempoa satunnaisin aikavälein.
loop do
dt0 = choose([8,10,12,14])
print("dt0: ", dt0)
sleep rrand(3*dt0, 6*dt0)
end
end
Tein ohjelmani Sonic Pi:llä , jonka voi installoida Linuxiin, Windowsiin tai Maciin. Mukana tulee hyvä tutoriaali, jolla pääsee helposti ohjelmoinnin alkuun. Mukana tulee myös mielenkiintoisia oikean muusikon tekemiä esimerkkejä.