Sisällysluettelo

Oh­jel­mal­lis­ta mu­siik­kia

Yri­tys saada tieto­kone­oh­jel­ma tuottmaan ama­töö­rin kor­viin sie­det­tä­vää mu­siik­kia


Heikin pohteita > Ohjelmointia, matematiikkaa, fysiikkaa … > Ohjelmallista musiikkia > Polyrytmistä rummutusta Sonic Pi:llä (edit: 2016-2-25)

Poly­ryt­mis­tä rum­mu­tus­ta Sonic Pi:llä

Miten tuot­taa oh­jel­mal­li­ses­ti jo­tain soi­ton ta­pais­ta muu­ta­mal­la yksin­ker­tai­sel­la sään­nöl­lä ja ri­pauk­sel­la sa­tun­nai­suut­ta?

Helmi­kuu 2016

Täl­lais­ta 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.

Mu­sii­kin teo­riaa en pal­joa tunne, mutta af­rik­ka­lai­seen rum­mu­tuk­seen pe­reh­tyes­sä­ni opin, että poly­ryt­mi­syys voi tuoda eloa muuten yksitoikkoiseen jumputukseen. Laitoin siis ohjelmani soittamaan useampaa perusjumputusta kutakin omaan tahtiinsa.

Perusjumpukseni tah­dit jaan kol­meen, nel­jään tai vii­teen tasa­vä­li­seen is­kuun. Jo­ten­kin tuo­hon tyy­lin olen ym­mär­tä­nyt nuot­te­ja­kin ri­po­tel­ta­van tah­din si­sään. Käy­tän sään­töä, että tah­din alus­sa on hyvä olla muita lu­jem­pi isku ja tah­din "keski­vai­heil­la" voi olla vähän vai­meam­pi isku ja vielä voi lyödä ke­vyes­ti pari ker­taa tah­din muis­sa koh­dis­sa.

Ylä­tason rytmi on kiin­teä. Tem­poa oh­jel­ma­ni vaih­te­lee – luul­lak­se­ni. Tah­tien jakoa is­kui­hin ja is­ku­jen voi­mak­kuuk­sia oh­jel­ma vaih­taa sa­tun­nai­ses­ti ylä­tason syk­lin vaih­tues­sa.

Mu­sii­kis­ta enem­män ym­mär­tä­vä kek­si­si var­maan hel­pos­ti sään­tö­jä, jotka te­ki­si­vät soi­tos­ta mie­len­kiin­toi­sem­paa. Saat­taa olla, että teen jo­tain höl­mös­ti ja pie­nel­lä mu­sii­kin lisä­opis­ke­lul­la sai­sin ai­kai­sek­si jo­tain jän­nem­pää.

Af­rik­ka­lai­ses­sa mu­sii­kis­sa on kuu­lem­ma oma ryt­min­sä kä­sil­le, lan­teil­le ja ja­loil­le. In­nos­tuin lait­ta­maan soit­too­ni vielä nel­jän­nen­kin ryt­min, joten tämän tah­dis­sa voisi af­rik­ka­lai­sen­kin olla vai­kea tans­sia.

Oh­jel­man­pät­kää­ni tuli lo­pul­ta ri­ve­jä mel­kein 300, mutta ei se silti kovin moni­mut­kai­nen ole. Oh­jel­ma toi­mii, mutta saat­taa siinä silti olla vir­hei­tä. Jos et siis ym­mär­rä jo­tain koh­taa, joko 1) et ym­mär­rä, 2) minä en ole ym­mär­tä­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 oh­jel­ma­ni 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ä.