Muzyka algorytmiczna

Zajęcia 7 (2026-04-08)

Zadanie (na 2026-04-15)

Przygotowanie krótkiego utworu (~30s) w środowisku Sonic Pi, spełniającego następujące wymagania:

  1. Utwór serialistyczny lub reinterpetujący serializm. Propozycje reinterpretacji:
    1. Użycie innej grupy niż „grupa serialistyczna” (aka. złożenie funkcji na zbiorze pryma, inwersja, rak, rak_inwersji)
    2. Rozszerzenie grupy serialistycznej o nowe elementy (jak na ćwiczeniach)
  2. Wykorzystującym protokół MIDI

Zadania na zajęciach

  1. Zdefiniuj następujące operacje jako funkcje w Sonic Pi:

MIDI

Za tworzenie i wysyłanie komunikatów MIDI odpowiada rodzina funkcji midi*. Każda z nich akceptuje parametr port:, który pozwala na wybranie docelowego portu. Domyślną wartością jest * wysyłająca na wszystkie porty.

10.times do |i|
  midi :c4, vel: i * 10, sustain: 1
  sleep 1
end
use_real_time

in_thread do
  use_midi_defaults port: "timidity_timidity_port_0_136_0"
  midi_pc 24 # AcousticGuitarNylon

  loop do
    midi scale(:c4, :major).tick
    sleep 1
  end
end

in_thread do
  use_midi_defaults port: "timidity_timidity_port_1_136_1"
  midi_pc 19 # Church Organ
  loop do
    midi scale(:c2, :major).tick
    sleep 4
  end
end

Przykładowy program rozbijający kanały MIDI na osobne porty

midi_all_notes_off

input = "midi_through_midi_through_port-0_14_0"
out1 = "midi_through_midi_through_port-1_14_1"
out2 = "midi_through_midi_through_port-2_14_2"
out3 = "midi_through_midi_through_port-3_14_3"

live_loop :chan1 do
  use_real_time
  n, vel = sync "/midi:#{input}:1/note_on"
  midi_note_on n, vel, port: out1
end

live_loop :chan2 do
  use_real_time
  n, vel = sync "/midi:#{input}:2/note_on"
  midi_note_on n, vel, port: out2
end

live_loop :chan3 do
  use_real_time
  n, vel = sync "/midi:#{input}:3/note_on"
  midi_note_on n, vel, port: out3
end

Przykładowy program odbierający komunikaty MIDI

port = "midi_through_midi_through_port-0_14_0"

synths = Hash.new

define :release do |s|
  in_thread do
    control s, amp: 0, amp_slide: 0.1
    sleep 0.2
    s.kill
  end
end


live_loop :receive do
  use_real_time
  n, v = sync "/midi:#{port}:*/note_on"
  if v == 0 then
    if synths[n]
      release synths[n]
      synths[n] = nil
    end
  else
    if synths[n]
      release synths[n]
      synths[n] = nil
    end
    synths[n] = synth :tech_saws, note: n, sustain: 99999, amp: 0.3
  end
end

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.