ここまでの講義は、Sonic Piを用いて音楽の構造をプログラミングしてきました。今回からは、よりミクロなスケールに入っていきます。SuperColliderというコンピュータ音楽言語を使用して、音の波形そのものをプログラムで生成する方法について紹介します。
前半は、SuperColliderで実際に音を生成する前に、コンピューターで音を扱うということは一体何をしているのかを理解していきます。まずはそもそも音とは何か、どうしたら音をコンピュータで扱うことができるのかといった基本的な部分から、波形、周波数(Hz)、サンプリングと量子化、ADCとDACといった基本的な事項について学んでいきます。
後半は、いよいよSuperColliderを使用していきます。まず、アプリケーションの入手方法から、基本操作、画面構成などを説明します。その後で、SuperColliderの言語の文法の基礎について実際に音を出しながら学んでいきます。
スライド資料
次回までの課題!!
次回、ミニ発表会を行います!! 課題: Sonic PiでパフォーマンスSonic Piを使用して3分程度のパフォーマンスを行ってください ライブコーディングしながらパフォーマンス 次回の授業で教卓のマシン or ノートPCを接続して発表します
サンプルプログラム
// ---------------------------------------------------------------------
// SuperCollider Basics
// ---------------------------------------------------------------------
// Introduction
{SinOsc.ar()}.play
{SinOsc.ar(220)}.play
{SinOsc.ar(220, 0, 0.8)}.play
{SinOsc.ar([220, 220], 0, 0.8)}.play
{SinOsc.ar([220, 221], 0, 0.8)}.play
{Saw.ar([220, 221])}.play
{RLPF.ar(Saw.ar([220, 221]))}.play
{RLPF.ar(Saw.ar([220, 221]), 1200)}.play
{RLPF.ar(Saw.ar([220, 221]), MouseX.kr(80, 10000, 1))}.play
{RLPF.ar(Saw.ar([220, 221]), MouseX.kr(80, 10000, 1), MouseY.kr(0.1, 1.2))}.play
{RLPF.ar(Saw.ar([80, 80.2]), MouseX.kr(80, 10000, 1), MouseY.kr(0.1, 1.2))}.play
{GVerb.ar(RLPF.ar(Saw.ar([80, 120]), MouseX.kr(80, 10000, 1), MouseY.kr(0.1, 1.2)))}.play
// Basics
{SinOsc.ar(LFNoise0.kr([10,12], mul: 600, add: 1000), 0, 0.3)}.play
{RLPF.ar(Dust.ar([12, 15]), LFNoise1.ar(1/[3, 8], 1500, 1600), 0.01, 8.0)}.play
{
RLPF.ar(
Dust.ar(
[12, 15]
),
LFNoise1.ar(
1/[3, 8],
1500,
1600
),
0.01,
8.0
)
}.play
// Enclosures
// [...] = Array, List
[0, 11, 10, 1, 9, 8, 2, 3, 7, 4, 6, 5].reverse
12 - [0, 11, 10, 1, 9, 8, 2, 3, 7, 4, 6, 5].reverse
[0, 2, 4, 5, 6, 7, 9, 11].scramble
[60, 62, 64, 67, 69].mirror
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].rotate
[60, 62, 64, 65, 67, 69, 71].midicps.round(0.1)
[1, 0.75, 0.5, 0.25, 0.125].choose
0.125 * [1, 2, 3, 4, 5, 6, 7, 8].choose
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].permute(6)
{Blip.ar(25, LFNoise0.kr(5, 12, 14), 0.3)}.play
{Blip.ar(25, LFNoise0.kr([5, 10], 12, 14), 0.3)}.play
{Blip.ar(25, LFNoise0.kr([5, 10, 2, 25], 12, 14), 0.3)}.play
{Blip.ar(25, LFNoise0.kr([5, 4, 7, 9, 5, 1, 9, 2], 12, 14), 0.3)}.play
// {...} = Function
dup(rand(1000.0), 5)
dup({rand(1000.0)}, 5)
exprand(1.0, 1000.0)
dup({exprand(1.0, 1000.0)}, 100)
sort(dup({exprand(1.0, 1000.0)}, 100))
round(sort(dup({exprand(1.0, 1000.0)}, 100)), 0.01)
{LFNoise0.ar}.play
{LFNoise0.ar(10000)}.plot
{LFNoise0.ar(10000)}.scope
{100.rand}.dup(10)
{100.rand} ! 10
{100.rand}.dup(10).postln.plot
{100.rand}.dup(100).sort.plot
// (...) = Message and Arguments
rand(100)
exprand(1.0, 100.0)
SinOsc.ar(arglist)
Mix.fill(arglist)
dup("echo", 20)
round([3.141, 5.9265, 358.98], 0.01)
sort([23, 54, 678, 1, 21, 91, 34, 78])
round(dup({exprand(1, 10)}, 100), 0.1)
sort(round(dup({exprand(1, 10)}, 100), 0.1))
// Receiver
[45, 13, 10, 498, 78].sort
"echo".dup(20)
50.midicps
444.cpsmidi
100.rand
{100.rand}.dup(50)
[1.001, 45.827, 187.18].round(0.1)
"I've just picked up a fault in the AE35 unit".speak
// Nesting
1000.0
1000.0.rand
1000.0.rand.round(0.01)
1000.0.rand.round(0.01).post
{1000.0.rand.round(0.01).postln}.dup(100).plot
{1000.0.rand.round(0.01).postln}.dup(100).postln.sort.plot
1000.0.rand.round(0.01).postln.asString.speak
// Ugen
LFNoise1.kr(10,100)
{SinOsc.ar([440,442])}.play
//---------------------------------------------------------
//
// SC 140
// "http://supercollider.github.io/community/sc140"
//
//---------------------------------------------------------
01
Nathaniel Virgo
{LocalOut.ar(a=CombN.ar(BPF.ar(LocalIn.ar(2)*7.5+Saw.ar([32,33],0.2),2**LFNoise0.kr(4/3,4)*300,0.1).distort,2,2,40));a}.play//#supercollider
02
LFSaw
{Splay.ar(Ringz.ar(Impulse.ar([2, 1, 4], [0.1, 0.11, 0.12]), [0.1, 0.1, 0.5])) * EnvGen.kr(Env([1, 1, 0], [120, 10]), doneAction: 2)}.play
03
Tim Walters
play{({|k|({|i|y=SinOsc;y.ar(i*k*k,y.ar(i*k**i/[4,5])*Decay.kr(Dust.kr(1/4**i),y.ar(0.1)+1*k+i,k*999))}!8).product}!16).sum}//#supercollider
04
Nathaniel Virgo
b=Buffer.read(s,"sounds/a11wlk01.wav");play{t=Impulse.kr(5);PlayBuf.ar(1,b,1,t,Demand.kr(t,0,Dseq(1e3*[103,41,162,15,141,52,124,190],4)))!2}
05
Batuhan Bozkurt
play{f=LocalIn.ar(2).tanh;k=Latch.kr(f[0].abs,Impulse.kr(1/4));LocalOut.ar(f+CombC.ar(Blip.ar([4,6],100*k+50,0.9),1,k*0.3,50*f));f}//44.1kHz
06
Batuhan Bozkurt (refactored by Charles Celeste Hutchins)
f={|t|Pbind(\note,Pseq([-1,1,6,8,9,1,-1,8,6,1,9,8]+5,319),\dur,t)};Ptpar([0,f.(1/6),12,f.(0.1672)],1).play//#supercollider reich RT @earslap
07
Thor Magnusson
play{x=SinOsc;y=LFNoise0;a=y.ar(8);(x.ar(Pulse.ar(1)*24)+x.ar(90+(a*90))+MoogFF.ar(Saw.ar(y.ar(4,333,666)),a*XLine.ar(1,39,99,99,0,2)))!2/3}
08
Charlie Hoistman
Ptpar(({|i|[i*8,Pbind(\scale,[0,2,4,7,9],\degree,Pseq(32.fib.fold(0,10),4)+(2*i+i)-10,\dur,1+2**i%2/6)]}!4).flat).play // #supercollider
09
MCLD
{LocalOut.ar(a=DynKlank.ar(`[LocalIn.ar.clip2(LFPulse.kr([1,2,1/8]).sum/2)**100*100],Impulse.ar(10)));HPF.ar(a).clip2}.play//
10
Julian Rohrhuber
/*eclecticity*/ Ndef(\x, { SinOsc.ar(BrownNoise.ar(30!2, 200), Ndef(\x).ar * LFNoise1.kr(1!2,1,1)) }).play;
11
Micromoog
play{VarSaw.ar((Hasher.ar(Latch.ar(SinOsc.ar((1..4)!2),Impulse.ar([5/2,5])))*300+300).round(60),0,LFNoise2.ar(2,1/3,1/2))/5}//#supercollider
12
Jose Padovani
play{x=165;b=SinOsc;p=Trig.ar(Saw.ar(x),1);y=b.ar(p*x);z=b.ar(p);(GVerb.ar(GrainIn.ar(2,y,y/2,z,p*z,-1),9))/9}//basso gettato #SuperCollider
13
Batuhan Bozkurt
play{LeakDC.ar(BRF.ar(Saw.ar(8,Decay2.kr(x=Duty.kr(1/8,0,Drand([0,Drand((0.4,0.5..1))],inf)),0.01,0.3))**1.5,x*20+[45.1,45],0.1)).tanh}//#sc
14
Nathaniel Virgo
Ndef('x',{x=Ndef('x').ar+0.01;a=BPF.ar(x,6**Latch.ar(x,Dust.ar(x))*200,0.1).sin;9.do{a=AllpassN.ar(a,0.2,{0.2.rand}!2,9)};a+a.mean}).play;
15
Jason Dixon
{x=Array.fill(5,{[0.00001,0.03].asSpec.map(LFNoise2.kr(3))});Splay.ar(Friction.ar(LFTri.ar(50),friction:x,mass:x*30000))}.play
16
Batuhan Bozkurt
play{AllpassC.ar(SinOsc.ar(55).tanh,0.4,TExpRand.ar(2e-4, 0.4,Impulse.ar(8)).round([2e-3,4e-3]),2)};// #supercollider with bass please...
17
redFrik
{RHPF.ar(GbmanN.ar([2300,1150]),LFSaw.ar(Pulse.ar(4,[1,2]/8,1,LFPulse.ar(1/8)/5+1))+2)}.play //punk (loud!)
18
Nathaniel Virgo
play{p=PinkNoise.ar(1!2);BRF.ar(p+Blip.ar(p+2,400),150,2,0.1)+LPF.ar(FreeVerb2.ar(*LPF.ar(p+0.2*Dust.ar(0.1),60)++[1,1,0.2,1e4]).tanh,2000)}
19
MCLD
{a=[0.02,0.1,1,2,3,4]; k=LFPar.kr(a+0.5).sum; f=Latch.kr(k,Impulse.kr(a)); Splay.ar(SinOsc.ar(f*100+300)/5)}.play // #supercollider
20
Sciss
play{2.collect{RecordBuf.ar(Limiter.ar(HPF.ar(Convolution2.ar(k=Crackle.ar(l=Line.kr(1,2,90)),b=LocalBuf(2048),Dust.kr(4)),8)+k)*(2-l),b)}}
21
Andrea Valle
{13.do{|i|k="SuperCollider"[i].ascii;20.do{|u|{MoogFF.ar(Saw.ar((k/4).midicps)*EnvGen.ar(Env.perc),u+k*9,k/30)}.play;(k*0.001).wait}}}.fork
22
MCLD
play{a=Duty.kr(0.1,0,Dseq(fib(32).wrap(20,55).midicps,inf));HPF.ar(LeakDC.ar(Splay.ar(LFCub.ar([-1,a,a/3,-2])))*9).clip2/9};//#supercollider
今日の内容
引き続きSonic Piのプログラミングを進めていきます。今回はより高度なSonic Piのプログラミングを行います。
まずプログラムの構造化に関する様々な機能を紹介します。「ブロック」「ループ (イテレーション)」「条件分岐」といった内容をとり扱います。
後半は、和音 (Chord) と旋律 (Scale) についてとりあげます。コード名やスケール名を指定するだけで複雑な和音や旋律を生成することが可能となります。
最後にステイーブ・ライヒの「ピアノフェイズ」のSonic Piによるコピーに挑戦します!
スライド資料
Sonic Piでプログラムの構造を作る
構造化プログラミング、3つの構成要素 順次 (Sequence)、反復 (Iteration)、分岐 (Selection)
たとえば、Processingだと…
// 順次
fill(31, 127, 255)
ellipse(widht/2, height/2, 100, 100);
// 反復
for(int i = 0; i < 100; i++){
...
}
//分岐
if(position.x > 100){
...
}
今までSonic Piで扱ってきたのは、順次と (単純な)反復
loop do
use_synth :fm
freq = choose([ 60, 67 ])
play freq
play freq + choose([ 0, 4, 5, 7])
play freq + choose([ 0, 4, 5, 7])
play freq + choose([-12, 0, 12])
sleep choose([ 0.25, 0.5])
end
より複雑な反復のパターンを理解 回数を指定した反復、反復のネスト
反復
回数を指定した反復
3.times do
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
end
反復のネスト(入れ子構造)
4.times do
sample :drum_heavy_kick
2.times do
sample :elec_blip2, rate: 2
sleep 0.25
end
sample :elec_snare
4.times do
sample :drum_tom_mid_soft
sleep 0.125
end
end
今まで使用してきた「loop」や「live-loop」は無限ループだった
loop do
4.times do
sample :drum_heavy_kick
2.times do
sample :elec_blip2, rate: 2
sleep 0.25
end
sample :elec_snare
4.times do
sample :drum_tom_mid_soft
sleep 0.125
end
end
4.times do
sample :drum_heavy_kick
2.times do
sample :elec_blip2, rate: 2
sleep 0.25
end
end
end
条件分岐
条件分岐の例
i = 0
loop do
if i % 4 == 0 then
sample :drum_heavy_kick
else
sample :drum_cymbal_closed
end
sleep 0.125
i = i+1
end
if文と、one_in() を組合せる
one_in(N) : N回に1回の割合で発生させるランダム サイコロを振る感覚
if と one_in のサンプル
loop do
if one_in(3)
sample :drum_heavy_kick
else
sample :drum_cymbal_closed
end
sleep 0.125
end
if と one_in のサンプル 2
loop do
if one_in(3)
sample :drum_heavy_kick
sleep 0.25
else
sample :drum_cymbal_closed
sleep 0.125
end
end
実習1
反復を利用して、かっこいいリズムパターンを組んでみる
反復とsleepによる微妙なニュアンス 条件分岐とone_inによるゆらぎ loopとlive_loop、どちらを使ったほうがやりやすいか?
例 : 複数のリズムの共存
live_loop :live do
sample :drum_heavy_kick
4.times do
sample :elec_blip2, rate: 2
sleep 1.0/8.0
end
sample :elec_snare
4.times do
sample :drum_tom_mid_soft
sleep 0.125
end
end
live_loop :live2 do
sample :drum_heavy_kick
3.times do
sample :elec_blip2, rate: 2
sleep 1.0/8.0
end
sample :elec_snare
4.times do
sample :drum_tom_mid_soft
sleep 0.125
end
end
Sonic Piのデータ構造
リスト(list)を使用してみる リスト: データの集合、配列のようなもの 前回、chooseを使用した際に既に使用していた
chooseとリスト
loop do
play choose([:c, :f, :g, :a, :b])
sleep 0.25
end
play [52, 55, 59]
play [52, 55, 59], amp: 0.3
play [:E3, :G3, :B3]
リストの要素にアクセス (55が演奏される)
loop do
play [52, 55, 59][1]
sleep 0.25
end
和音
chordを使用すると、コードネームを使用して和音を生成できる 様々な複雑な和音が用意されている
play chord(:C4, :major)
いろいろなコードが定義されているので、試してみる!
play chord(:C4, :major)
sleep 1.0
play chord(:C4, :major7)
sleep 1.0
play chord(:C4, :minor)
sleep 1.0
play chord(:C4, :minor7)
sleep 1.0
play chord(:C4, :dim)
sleep 1.0
play chord(:C4, :dim7)
sleep 1.0
play chord(:C4, :sus2)
sleep 1.0
play chord(:C4, :sus4)
sleep 1.0
play chord(:C4, :augmented)
sleep 1.0
playの代わりに play_pattern_timed を使うとリストをアルペジオ演奏できる play_pattern_timed コードのリスト, 速さ 例: Cメジャーを、0.25のタイミングで
play_pattern_timed chord(:C4, :major), 0.25
いろいろなアルペジオを試してみる
loop do
play_pattern_timed chord(:C4, :major), 0.25
sleep 0.5
play_pattern_timed chord(:C4, :major7), 0.25
sleep 0.5
play_pattern_timed chord(:C4, :minor), 0.25
sleep 0.5
play_pattern_timed chord(:C4, :minor7), 0.25
sleep 0.5
play_pattern_timed chord(:C4, :dim), 0.25
sleep 0.5
play_pattern_timed chord(:C4, :dim7), 0.25
sleep 0.5
play_pattern_timed chord(:C4, :add9), 0.25
sleep 0.5
play_pattern_timed chord(:C4, :add13), 0.25
sleep 0.5
end
音階(scale)
Sonic Piでは、和音と同様に様々な音階(scale)が定義されている 例:「ドレミファソラシド」が演奏される → メジャースケール
loop do
play_pattern_timed scale(:C4, :major), 0.25
end
いろいろな音階(scale)を試してみる
loop do
play_pattern_timed scale(:C4, :major), 0.25
sleep 0.25
play_pattern_timed scale(:C4, :minor), 0.25
sleep 0.25
play_pattern_timed scale(:C4, :aeolian), 0.25
sleep 0.25
play_pattern_timed scale(:C4, :ahirbhairav), 0.25
sleep 0.25
play_pattern_timed scale(:C4, :augmented), 0.25
sleep 0.25
play_pattern_timed scale(:C4, :augmented2), 0.25
sleep 0.25
play_pattern_timed scale(:C4, :bartok), 0.25
sleep 0.25
end
chooseとchord、chooseとscaleを組み合わせる
ランダムな選択と強い制約 制限された調整の中でのランダムが簡単に実現できる
例1: マイナーコード (短三和音) から音を1つ選ぶ
loop do
play choose(chord(:C4, :minor))
sleep 0.25
end
例2: メジャーコード (長三和音) から音を1つ選ぶ
loop do
play choose(chord(:C4, :major))
sleep 0.25
end
スケールを使用した即興
use_synth :prophet
live_loop :live do
play choose(scale(:c3, :minor, num_octaves: 3)), cutoff: rrand(60, 100)
play choose(scale(:c4, :minor, num_octaves: 3)), cutoff: rrand(60, 100)
play choose(scale(:c5, :minor, num_octaves: 3)), cutoff: rrand(60, 100)
sleep 0.25
end
スケールを書き換えて聞き比べてみる
use_synth :prophet
live_loop :live do
play choose(scale(:c3, :lydian, num_octaves: 3)), cutoff: rrand(60, 100)
play choose(scale(:c4, :lydian, num_octaves: 3)), cutoff: rrand(60, 100)
play choose(scale(:c5, :lydian, num_octaves: 3)), cutoff: rrand(60, 100)
sleep 0.25
end
複数の楽器で + さらにパラメータを加えてみる
live_loop :live do
use_synth :prophet
cut = rrand(20, 120)
6.times do
play choose(scale(:c2, :aeolian, num_octaves: 5)), cutoff: cut, pan: rrand(-1, 1)
end
use_synth :chiplead
4.times do
play choose(scale(:c3, :aeolian, num_octaves: 5)), cutoff: cut, pan: rrand(-1, 1), amp: 0.7
end
sleep 0.25
end
参考: 音階 (モード) による即興
次回までの課題!
これまで紹介してきたSonic Piの機能を活用して、ループする旋律を作曲する
楽器(synth)とサンプル(sample) 演奏(play)とパラメータ(amp, pan, atack, release, cutoff…) 乱数(rrand, rrand_i, choose, one_in) リスト(list) 和音(chord) 音階(scale)
次回簡単な発表会を行います!