Muzyka algorytmiczna

Zajęcia 9 (2026-04-22)

Zadanie (na 2026-04-29)

Dwa warianty (do wyboru 1):

  1. Muzyka konkretna / soundscape
  2. Udźwiękowienie do przesłanego Państwu mailem filmu
    Nie dodajemy filmu na GITa. Przekazujemy go osobie prowadzącej zajęcia w trakcie zajęć (puszczony zostanie pendrive).

Zadania na zajęciach

  1. Zapoznaj się z dokumentacją funkcji sample i spróbuj wykonać następujące akcje wykorzystujące Twoje nagrania:
    1. Odtworzenie pojedyńczego sample'a
    2. Odtworzenie pojedyńczego sample'a dwa razy wolniej
    3. Odtworzenie pojedyńczego sample'a dwa razy wolniej przy zachowaniu wysokości dźwięków w nagraniu
    4. Odtwarzanie dźwięku od końca
    5. Odtwarzanie [1/3,2/3] części dźwięku
    6. Odtwarzanie dźwięku z banku dźwięków (katalogu, dokumentacja poniżej)
  2. Wykorzystując sample: dostępne na stronie ZTM Poznań oraz Kmart October 1989 oraz własne, stwórz utwór o następującej strukturze:
    1. Przez całą długość utworu wykonywany jest sample Kmart October (pierwsze 2 minuty. Przed załadowaniem do Sonic Pi należy skrócić oryginalny plik by ułatwić załadowanie w Sonic Pi. Rekomendowanym programem do skrócenia jest Audacity).
    2. Sample poddawane są obróbce np. efektami, przesunięciem wysokości dźwięków, itp.
    3. Z losowymi odstępami wykonywane są losowe sample od ZTM Poznań, z efektami takimi jak reverb, slicer, echo.

    Ciekawostka: ZTM Poznań udostępnia też trasy tramwajów, z odstępami między przystankami, pozwalając na stworzenie rekreacji przejazdu tramwajem.

Sample w Sonic Pi

Sonic Pi posiada wbudowany bank sampli - wcześniej przygotowanych fragmentów dźwiękowych. Odpowiednikiem funkcji play jest funkcja sample :nazwa_sampla np:

sample :ambi_drone
sleep 1
sample :ambi_drone

Zauważ, że funkcja sample podobnie jak play nie oczekuje na zakończenie odtwarzania sampla! Ponadto każdy odtwarzany sampel może mieć różną długość - aby zdobyć dlugość sampla używamy funkcji sample_duration:

sample :ambi_drone
sleep sample_duration(:ambi_drone)
sample :ambi_drone

Jeśli zmienimy parametry odtwarzania musimy te same parametry przekazać do funkcji sleep_duration!

Modyfikacja parametrów odtwarzania

Funkcja sample posiada (podobnie jak play) ADSR kontrolujący poziom głośności. Ponadto dostępne jest:

Więcej parametrów opisanych jest w dokumentacji funkcji sample

Sample odtworzony od końca, dwa razy szybciej, z pominiętym 30% utworu od końca. Następinie ten sam sample, pierwsze 30%, dwa razy wolniej do przodu:

sample :loop_amen, finish: 0.7, rate: -2
sleep sample_duration(:loop_amen, finish: 0.7, rate: -2)
sample :loop_amen, finish: 0.3, rate: 0.5

Sample spoza Sonic Pi

Sonic Pi nie wspiera niektórych powszechnie używanych formatów plików! Rekomendowanym jest używanie plików wav lub ogg.

tomatoes.wav

Poniższy przykład zakłada, że plik znajduje się w tej samej ścieżce co Sonic Pi. Rekomendowanym jest używanie pełnych ścieżek (absolute path).

Windows: \ należy zamienić na \\: ścieżka "C:\Users\test\test.wav" na "C:\\Users\\test\\test.wav"

use_bpm 60

tomatoes = "tomatoes.wav"

sample tomatoes, pitch: 12
sleep sample_duration(tomatoes)

12.times do |n|
  rate = 1 + 0.25 * n

  s = 0.4
  f = 0.67
  sample tomatoes, start: s, finish: f, rate: rate, lpf: :c7
  sleep sample_duration(tomatoes, rate: rate, start: s, finish: f)
end

sample tomatoes, rate: 0.8, attack: 0, decay: 0, sustain: 0, release: sample_duration(tomatoes)

Katalog jako bank sampli

Zakładając, że w katalogu "/foo" znajdują się pliki wav/ogg, mamy możliwość wykorzystania katalogu jako bazy sampli - sample "/foo", 1 odtworzy drugą próbkę dźwiękową wewnątrz katalogu.

Zapoznaj się z dokumentacją funkcji sample by poznać dokładny algorytm działania.

Efekty

# W przypadku fxów pomaga wcześniej załadować:
load_sample "tomatoes.wav"

with_fx :panslicer, smooth: 0.25 do
  with_fx :reverb do
    with_fx :flanger do
      with_fx :ring_mod do
        sample "tomatoes.wav"
      end
    end
  end
end

Dzielenie sample'a na fragmenty o równej długości

Przykład z dokumentacji Sonic Pi

Wykorzystujemy fakt, że :loop_amen dzieli się na 8 równych fragmentów:

Równomierny podział :loop_amen na 8 fragmentów

Każda iteracja pętli :beat_slicer losuje indeks od 0 do 8, wedle którego odtworzymy jeden z 8 fragmentow :loop_amen. Każdy fragment ma dlugość 1/8 utworu (slice_size). Wyliczamy start (zmienna s) - jest to pominięcie poprzednich do wylosowanego fragmentów oraz koniec (zmiemma f) - jest to start przesunięty o dlugośc fragmentu. Następnie możemy odtworzyć fragment z użyciem funkcji sample.

live_loop :beat_slicer do
  slice_idx = rand_i(8)
  slice_size = 1 / 8.0
  
  s = slice_idx * slice_size
  f = s + slice_size
  sample :loop_amen, start: s, finish: f
  sleep sample_duration :loop_amen, start: s, finish: f
end

Dzielenie sample'a na fragmenty o różnej długości przy pomocy tablicy

Powyższy przykład można rozszerzyć poprzez nierównomierny podział sampla - każda sekcja może mieć inną długość. Aby osiągnąć ten efekt będziemy losować z tablicy, w której każdy element oznacza długość danego fragmentu. Pętla rozpoczyna się podobnie - od losowania indeksu, tym razem indeksu tablicy.

Następnie wyciągamy długość pojedyńczego fragmentu (slice_size = durations[slice_idx]) oraz liczymy sumę długości fragmentów pominiętych (s = durations[...slice_idx].sum) - zapis durations[...slice_idx]wyciąga elementy tablicy od 0 do slice_idx (bez slice_idx), natomiast .sum sumuje elementy tablicy.

Pozostała część kodu jest identyczna.

durations = [0.4, 0.1, 0.2, 0.1, 0.2]

live_loop :beat_slicer do
  slice_idx = rand_i(durations.length)
  slice_size = durations[slice_idx]
  s = durations[...slice_idx].sum
  f = s + slice_size
  sample :loop_amen, start: s, finish: f
  sleep sample_duration :loop_amen, start: s, finish: f
end