Przygotowanie krótkiego utworu (~30s) w środowisku Sonic Pi, spełniającego następujące wymagania:
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
Dodatkowe informacje: porównanie Pythona i Rubiego
Encyklopedia ciągów liczbowych
Odpowiednik tablic z dodatkowymi metodami.
Tworzone funkcją vector
Pierścień p to n-elementowy wektor, gdzie p[i] == p[i%n].
Tworzone funkcją ring
Wektor ograniczony v to n-elementowy wektor, gdzie:
i < 0, ,p[i] ≡ p[0],i ≥ n, ,p[i] ≡ p[n-1].Tworzony funkcją ramp
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
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ą.
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)
Ź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
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