Sisällysluettelo

Ohjelmallista musiikkia

Yritys saada tietokoneohjelma tuottmaan amatöörin korviin siedettävää musiikkia


2016-2-25

/ Heikin pohteita/ Ohjelmointia, matematiikkaa, fysiikkaa … Ohjelmallista musiikkia /Polyrytmistä rummutusta Sonic Pi:llä

 

Polyrytmistä rummutusta Sonic Pi:llä

Miten tuottaa ohjelmallisesti jotain soiton tapaista muutamalla yksinkertaisella säännöllä ja ripauksella satunnaisuutta?

Helmikuu 2016

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ä.