Muzyka algorytmiczna

Zajęcia 5 (2026-03-25)

Zadanie (na 2026-04-01)

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

  1. Utwór oparty o własną skalę
  2. Wykorzystuje tablicowe struktury w Sonic Pi
  3. Używa algorytmu do definiowania struktury utworu, przykłady: Algorytm nie powinien determinować ostatecznej formy utworu! Powinien raczej być bazą, na której rozbudowujemy faktyczne doświadczenie muzyczne.

Zadania na zajęciach

  1. Stwórz program odtwarzający kolejne liczby Fibonacciego w wybranych przez Ciebie skalach poprzez zdefiniowanie zmiennej skala zawierającej dźwięki z skali. Przykład:
    skala = [:c4, :d4, :e4]
    
    a, b = [1, 0]
    30.times do |n|
      print "fib(#{n}) = #{a}"
      play skala[a % skala.length]
      sleep 1
      a, b = [a+b, a]
    end
  2. Stwórz program, który będzie odtwarzał zawsze ten sam zbiór dźwięków z użyciem play_pattern_timed, natomiast zmieniana jest jej postać za wykorzystaniem metod tablicowych opisanych poniżej (np. map, reflect). To samo zadanie wykonaj dla rytmu.

Tablicowe struktury danych w Sonic Pi

Dodatkowe informacje: porównanie Pythona i Rubiego

Encyklopedia ciągów liczbowych

Sonic Pi: wektory

Odpowiednik tablic z dodatkowymi metodami.

Tworzone funkcją vector

Wspierane operacje
+
dodaje liczbę do elementów / łączy wektory
-
odejmuje liczbę od elementów / róznica zbiorów
*
powtarza elementy n razy
all?
czy predykat jest prawdziwy dla każdego z elementów
any?
czy predykat jest prawdziwy dla któregokolwiek z elementów
butlast
elementy poza ostatnim
choose
wybierz losowy element
drop
pomiń n elementów
drop_last
pomiń n ostatnich elementów
each
iteruj po elementach
each_with_index
iteruj po elementach z indeksem
empty?
czy wektor jest pusty
filter
filtruj elementy według predykatu
first
pierwsze n elementów
flat_map
złącz wyniki iteracji w wektor
flatten
złącz elementy w jedną listę
last
zwróć n ostatnich elementów
length
długość wektora
map
iteruj elementy, tworząc wektor z wyników iteracji
max
maksimum
min
minimum
mirror
złącz wektor z jego lustrzanym odbiciem
ramp
Zwróć wektor ograniczony z elementów wektora
reflect
złącz wektor z jego lustrzanym odbiciem, nie powtarzaj środkowego elementu
repeat
złącz wektor n razy
reverse
odwróć kolejność elementów w wektorze
ring
zwróć pierśćień z elementów wektora
rotate
przesuń elementy wektora
scale
skaluj elementy (mnóż po elementach)
shuffle
losowa permutacja elementów
size
rozmiar wektora
sort
zwróć elementy posortowane
stretch
powtórz elementy obok siebie
take
weź n elementów
take_last
weź n elementów od końca
uniq
zwróć elementy bez powtórzeń

Sonic Pi: pierścienie

Pierścień p to n-elementowy wektor, gdzie p[i] == p[i%n].

Tworzone funkcją ring

Sonic Pi: wektor ograniczony

Wektor ograniczony v to n-elementowy wektor, gdzie:

Tworzony funkcją ramp

Przykładowe wykorzystanie wektorów

use_synth :piano

times = (1..8).map do |x|
  1r / x
end.ring.mirror

play_pattern_timed (ring :f4, :g4).repeat(times.length/2), times

Skale

Kompozycję (w kontekście harmonii) rozpoczynamy od wyboru skali - podzbioru dostępnych nam dźwięków, na którym będziemy potem operować. Pierwszy dźwięk skali nazywany jest toniką (teoretycznie wyłącznie w skalach diatonicznych - dur i moll; Sonic Pi używa częściej). Skala zawiera dźwięki od pierwszego jej dźwięku do oktawy (dźwięku 12 półtonów wyżej).

Sonic Pi posiada duży zbiór wbudowanych skal. Lista skal dostępna jest poprzez funkcję scale_names.

Przykładowy program prezentujący skalę C-dur:

play_pattern_timed scale(:c4, :major), 1

Przykładowy program prezentujący losowanie skali, a następnie odtworzenie jej dźwięków:

scale_name = scale_names.choose
sc = scale(:c4, scale_name)
play_pattern_timed sc, 1

Skala to wyłącznie predefiniowane interwały kończące się na oktawie. Gama to „wdrożenie” skali od początkowego dźwięku. Mówimy np. o skali durowej, a gdy zaczyna się od konkretnego dźwięku (np. C) jest to gama C-dur.

Muzyka opisana z użyciem opisanych powyżej narzędzi jest tzw. muzyką tonalną - odchodząc od tych zasad i traktując dźwięki równoważnie, a ich połączenia dowolnie tworzymy muzykę atonalną.

Skale wbudowane w Sonic Pi

scale zwraca skalę w postaci pierścienia. scale_names zwraca listę skal w postaci pierścienia.

scale :C4, :major # ≡ (ring 60, 62, 64, 65, 67, 69, 71, 72)
scale :C4, :minor # ≡ (ring 60, 62, 63, 65, 67, 68, 70, 72)
scale :C4, :egyptian # ≡ (ring 60, 62, 65, 67, 70, 72)

Skala pitagorejska

Źródło odległości między dźwiękami

pit = [0, 203.91, 294.13, 498.04, 701.96, 905.87, 996.09].map do |x| note(:d4) + x/100 end
D1, E1, F1, G1, A1, B1, C1 = pit
tet = [:d4, :e4, :f4, :g4, :a4, :b4, :c5]

pit.zip(tet).each do |a, b|
  print a, b
  play_pattern_timed (ring a, b), 1
end

# Można krócej:
# play_pattern_timed (ring pit.zip(tet)).flatten, 1

Generowanie skal równomiernie temperowanych

def równomiernie_temperowany(start, n)
  sounds = []
  n.times do |i|
    sounds << hz_to_midi(midi_to_hz(start) * (2 ** (1r/n)) ** i)
  end
  sounds.ring
end

S, K, A, L, A = równomiernie_temperowany(:a4, 5)
play S
play A
sleep 1

tet19 = równomiernie_temperowany(:a4, 19)
play_pattern_timed tet19, 1/8r, release: 0.1
sleep 1