Yritys saada tietokoneohjelma tuottmaan amatöörin korviin siedettävää musiikkia
Heikin pohteita > Ohjelmointia, matematiikkaa, fysiikkaa … > Ohjelmallista musiikkia > Polyrytmistä rummutusta Sonic Pi:llä (edit: 2016-2-25)
Miten tuottaa ohjelmallisesti jotain soiton tapaista muutamalla yksinkertaisella säännöllä ja ripauksella satunnaisuutta?
Helmikuu 2016
Tällaista sain aikaiseksi pienellä ohjelmanpätkällä. Ohjelma pysyy väsymättä tyylilleen uskollisena, mutta ihan yhtä ja samaa se ei soita. Pieniä yllätyksiä voi kuulla vielä tunninkin kuuntelun jälkeen. Tuollaiset yllätykset jäävät tietysti kuulijalta kokematta, ellei hän pidä tyylistä. Tämän jutun tarkoitus onkin innostaa lukijaa ohjelmoimaan oman tyylistä musiikkia.
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ä.