Muzyka algorytmiczna

Zajęcia 6 (2025-04-02)

Cel zajęć

  1. MIDI w Sonic Pi
  2. Łączenie Sonic Pi z zewnętrznymi syntezatorami

Zadanie

Na kolejne zajęcia (2025-04-09)

Przygotowanie krótkiego utworu (~1min) w środowisku Sonic Pi, spełniającego jeden z następujących wariantów wymagań:

  1. Utwór będący reinterpretacją serializmu
  2. Wygenerowanie utworu serialistycznego (generowanie np. dźwięków w serii, kolejności wykonania serii i ich wariantów

Funkcje

Sonic Pi zbudowany jest na podstawie języka Ruby, przez co jego mechanizm tworzenia funkcji (deklaracja def) działa w wykorzystywanej wersji. Twórca zaznaczył jednak, że nie rekomenduje wykorzystywanie mechanizmów z języka Ruby.

define :getRandomNumber do
  4 # chosen by fair dice roll
    # guaranteed to be random
end

print(getRandomNumber())
print getRandomNumber

define :add do |a, b|
  a + b
end

print(add(11, 22))


define :fib do |n|
  if n <= 1 then
    return 1
  else
    return n * fib(n-1)
  end
end

print(fib(8))

Dynamiczna zmiana definicji funkcji

define :test do |x|
  x
end

live_loop :foo do
  play test(60)
  sleep 1
end

live_loop :bar do
  f = tick
  define :test do |x|
    x + f
  end
  sleep 2
end

Serializm

  1. Wyznacz serię - interwałów, rytmów, itp.
  2. Stosuj serię oraz jej przekształcenia do kompozycji utworu

Przykład z wykładu

ns = [:fs3, :cs3, :e3, :g3, :c3, :d3, :gs3,:b3, :a3, :ds3, :as3, :f3]
rytm = [1, 1/2r, 2, 1/4r, 3/4r, 1/8r, 4, 3/8r, 3/2r, 3, 1/16r, 6]
dyna = [0.33, 0.45, 0.27, 0.55, 0.1, 0.2, 0.7, 0.91, 0.82, 0.51, 0.4, 0.37]

for i in 0..12
  play ns[i], amp: dyna[i], duration: rytm[i]
  sleep rytm[i].to_f
end

Seria interwałów

Seria składająca się z odległości pomiędzy dźwiękami (w półtonach). Transformacje zachowują relatywne odległości między kolejnymi dźwiękami. Pozwala to na wyznaczenie czterech możliwych serii na podstawie trzech przekształceń.

Podstawowe przekształcenia to:

Wyznacza to 4 serie:

Operacje P, I, R, RI wraz z złożeniem funkcji jako działaniem tworzą grupę abelową znaną jako Grupa Czwórkowa Kleina, gdzie P jest elementem neutralnym.

Implementacja

Inwersja w której możemy wyjść poza oryginalną serię:

define :inwersja do |seq|
  xs = [seq[0]]
  for i in 1...12 do
    xs[i] = xs[i-1] + (seq[i-1] - seq[i])
  end
  xs.ring
end

Inwersja w której pozostajemy w serii:

define :inwersja_mod do |seq|
  inw = inwersja(seq)
  inw.flat_map do |x|
    (x - inw.min) % 12 + inw.min
  end
end

Rak i rak inwersji:

define :rak do |seq|
  seq.reverse
end

define :rak_inwersji do |seq|
  rak(inwersja(seq))
end

Kod z zajęć

# 1. Definicja funkcji silnia
# 2. Stworzenie tablicy a 12 elementowej, takiej, że
#      a[i] = i! % 12
# 3. Stworzenie tablicy b 12 elementowej, takiej, że
#      b[i] = i! % 12 + b[i-1]
# 4. Odsłuchanie tablic a i b

define :silnia do |n|
  if n == 0 then
    return 1
  end
  n * silnia(n-1)
end

a = []
12.times do |i|
  a.push(silnia(i) % 41)
end

b = [note(:c4) + silnia(0)]
for i in 1..11
  b[i] = b[i-1] + silnia(i) % 41
end

use_synth :saw

for i in 0..11
  play b[i], duration: 41.0 / a[i]
  sleep 41.0 / b[i]
end