2010年7月11日日曜日

Tokyo SuperCollider #1 - ワークショップ資料

第一回目のワークショップの資料です。
テキストファイルのダウンロードはこちらからどうぞ。

//Tokyo SuperCollider #1 
//HACKERSPACE@TAMABI 100710

//--0. SuperColliderとは?

//--0.1 SuperCollider
SuperCollider 
リアルタイム音響合成のためのプログラミング言語と環境(アプリケーション)

ダウンロードはこちらから

もともとはJames McCartney個人によって開発が進められ、1996年に有償のソフトウェアとして最初のリリースが行われました。2002年からはGPLライセンスのもとオープンソースのフリーソフトウェアとして有志で開発が進められています。ちなみに、現在James McCartneyAppleでエンジニアとして働いているというのは有名な話です。

*おまけ:SC1.0の写真がここで見れます。

・最新のバージョン
最新の安定版は3.3.1ですが、すでに3.4rc(release candidate:リリース候補)が公式発表されていて、まもなく3.4にアップデートされると思われます。3.3.13.4rcでは若干違う部分がありますが、以下のコードは両方で問題なく動作します。
3.4rcのダウンロードはこちらから


//--0.2 SuperColliderフォルダの中身






















上から順に、

"ChangeLog" 
仕様変更の履歴。

"COPYING"
著作権。

"examples"
プログラムの実例集。
*いろいろ実行してみることをおすすめします。

"Help"
ヘルプファイル。
*全てhtmlファイルになっていて、リンクをたどっていけます。
書いてあるコードはSCで開いてそのまま実行できるのでとても便利です。
ここから直接開くことはほとんどありません。

"plugins"
UGen/ユニットジェネレーター(発信器、フィルタ、増幅機など音響・信号処理を行うオブジェクト)がコンパイル前のバイナリ形式でここに格納されていて、サーバー(scsynth)によって読み込まれます。

"preferences"
不明。情報募集中です。
中身は空。環境設定用のファイル?

"README"
お決まりのファイル。はじめに読む短い説明書。

"SCClassLibrary"
SC言語で使用するクラス(特定の機能を持ったひとまとまりのプログラム)の格納庫。

"sclang"
SCのプログラミング言語。「クライアント」

"scsynth"
SCの音響合成エンジン。「サーバー」

"sounds"
サウンドファイルのためのデフォルトフォルダ。

"SuperCollider.app"
SCクライアントアプリケーション。プログラムの開発・実行環境。


//--0.3 SuperColliderの仕組み
SCは基本的に「クライアント」と「サーバー」の二つの別のプログラムによって構成されています。

「クライアント」
"sclang"
オブジェクト指向のプログラミング言語、「SuperCollider
つまりわたしたちが実際にテキストウィンドウへ記述していく文字列のことです。

「サーバー」
"scsynth"
音響生成エンジン。ローカル上、場合によってはネットワーク上の別のコンピュータなど、バックグラウンドで動くプログラム。主にC++で書かれています。

SCではこのクライアントとサーバーの二つがUDPまたはTCPを介してOSCメッセージをやり取りすることでさまざまな処理を行っています。















*参照:ClientVsServer SCフォルダの中身でいうと、
1"scsynth"23"sclang"、4が"SuperCollider.app"
それら全てを合わせたものが5"SuperCollider application"に相当する、
と僕は思っているのですが、違うかもしれません。この辺り詳しい方間違いあれば訂正お願いします。)


//--1. SuperColliderの基本操作

//--1.1 SuperCollider.appを起動する

まず、日本語環境だといろいろと不具合があるので、起動前に言語環境は英語に設定します。


起動後、画面には以下の三つが表示されます。

1. post window
プログラムの実行結果やエラーメッセージが表示されます。

2. localhost server window
アプリケーション起動時のデフォルトサーバー。
SCクライアントアプリケーションとは別のアプリケーション(scsynth)として、独自のアドレススペース内で動くサーバーです。

3. internal server window
sclang/SCクライアントアプリケーションと同じスペース内で動くサーバーです。
共有メモリにアクセス可能なので、scope window(後述)を利用できます。

localhostinternalの二つのウィンドウは、サーバー(音響生成エンジン、scsynth)をSCクライアントアプリケーション側で表したもので、プログラムの動作状況に関する情報を表示してくれたり、サーバーの起動、終了、録音などの操作をするGUI(グラフィックユーザーインターフェース)を提供してくれます。

参照:Server  (特にLocal vs. Internalの項)



//--1.2 基本操作

【プログラムを実行する】

1行のプログラム
実行したい行で

enterreturnではないことに注意してください)
ctrl+return
ctrl+c
fn+return
shift+return

いずれかのキーを押す。
Windowsctrl+enter


1+1 //実行してみる

post window"2"と出力されます


*複数行のプログラム
実行したい範囲のテキストをマウスなどで選択して、上記キーを押す。

*プログラムが複数行にわたる時はプログラムを「;」で区切ります。
ないとエラーになります。最終行にはなくても良いですが、
普段から「;」をつけるくせをつけておいても良いかもしれません。

a= 2;
a+3

*コードによっては「;」がないと、うしろに続くコメントが色付けされません。
//ところで、これがコメントです。

/*
これもコメントです。
コメントです。
*/

1+2 //abc
1+2; //abc

*プログラムを”()”でくくってあげると選択しやすくなります。

( //左の括弧をダブルクリック、または括弧内でcmd+shift+bで選択できます。
a= 2;
b= 3;
a+b
)


【文字に色をつける】
cmd+'」を押す。
*「 ' 」キーはUSキーボードならreturnキーの左にあると思います。JISキーボードの場合はshift+7で入力します。


【ヘルプを見る】
調べたい範囲のテキストを選択して、cmd+dキーを押します。WindowsF1

//単語をダブルクリックやalt+shift+矢印キーなどで選択して、上記キーを試してみてください。
Server 
GUI
UGens


SCをリコンパイルする】
cmd + k」を押す。
何かよくわからないけどおかしいな、という時にSCをリコンパイルすると上手くいったりすることがあります。
リコンパイルとは再起動のようなものです。フリーズ(虹色くるくる)してしまって強制終了ということもあるので
試す前には必ず保存「cmd+s」しましょう。


//--1.3 予備知識

【オブジェクト指向】
SuperCollierは完全なオブジェクト指向言語です。
SC言語では全ての文字列はオブジェクトとして扱われます。

オブジェクト.メソッド

メソッド(オブジェクト)

といった書式でオブジェクトにメッセージを送ることでプログラムを行っていきます。

オブジェクト指向についてはtn8さんのサイトにとっても親切な説明があります。
参照:オブジェクト指向のスーパーコライダー


【ユニットジェネレーター】
UGenは発信器、フィルタ、増幅機などの音響・信号処理モジュールで、音響生成のために相互連結することができる
SCには250以上のUGenがある(参照: UGen, UGens, Tour_of_UGens


【いろいろな括弧の意味】
"":ダブルクォーテーション => 文字列を表します。

{}:中括弧 => 関数(=引数(ひきすう)と呼ばれるデータを受け取り、定められた通りの処理を実行して結果を返す一連の命令群)を表します。

():小括弧 => まとめて実行されるひとまとまりのプログラムや、計算順位、関数の引数、クラスの引数を表します。

[]:大括弧 => Array(配列)、List、出力チャンネルを表します。


【文法最低限】
*四則演算
1+4  
2-3
3*2
4/1
3.14*2; //int(整数)やfloat(少数)など数の型(タイプ)を宣言しなくても良い。
1+2*3; //計算順序は常に左から右
1+(2*3) //特定の箇所の計算順位を高めたかったら()でくくる。


*グローバル変数(プログラムのどこからでも参照・更新できる変数)
a~zまでのアルファベット一文字は宣言なしでグローバル変数として使用できます。
通常は任意の文字列の頭に「~」をつけて宣言します。

a= 1
a+2
a

b= 3
b+4
b

~abc= a*10
~abc= ~abc*10
~abc

一文字のグローバル変数は素早くテストする時などには便利ですが、
複雑なプログラムの中では「~」つけて宣言した方が良いことが多いです。

*ローカル変数(単に変数と呼ぶことが多いです)
(
var a; //アルファベット一文字ですが、このブロック内(括弧の中)では通常の変数(ローカル変数)として扱われることに注意してください。
a= 10; //数値10を代入
a+b //ローカル変数a+上で宣言したグローバル変数b
)

(
var foo=1, bar=2; //宣言時に初期値を代入することもできます
foo+bar;
)
*配列
[1, 2, 3]

[1, 2, 3]+1

[1, 2, 3] + [1, 2, 3]


*文法について詳しくは@ksyJpさんの、この記事が素晴らしいです。




//--2. 音を出す

//--2.1 サーバーを起動する
まずはサーバーを起動(boot)します。サーバーが起動していなければ音は出ません。
GUIBootボタンでも起動できますが、せっかくなのでコードで起動してみましょう

s.boot //起動時のデフォルト、localhostサーバーが起動します
s.quit //終了

sはグローバル変数。デフォルトでlocalhostサーバーが代入されています。

s= 1; //任意のオブジェクトに置き換え可能ですが、おすすめしません。
s.boot //エラーになります。

Server.local.boot //localhost起動
Server.local.quit //終了

s= Server.local // 再度「s」にlocalhostを代入
s.boot //起動します
s.quit

Server.internal.boot //internal起動
Server.internal.quit //終了

(
Server.default= Server.internal; //デフォルトをinternal
s= Server.default; //s」にServer.defaultを代入
s.boot // internal起動
)

s.quit //internal終了

*無駄な処理を避けるため、サーバーは基本的にどちらか一つ起動するようにしてください。


//--2.2 {関数}.play
*わりと大きな音が出るので、音量に注意してください

//まずはデフォルトサーバーをlocalに戻して起動
(
Server.default= Server.local;
s= Server.default;
s.boot
)

{SinOsc.ar}.play //左チャンネルからピーと音が出ます。
//.(ピリオド)で音を止めます。

play{SinOsc.ar} //このように書いても良いです。

//SinOscはサイン波を生成するUGen
//".ar"UGenをオーディオレイト(デフォルトは毎秒44100サンプル)で出力するメソッド

SinOscのヘルプを見てみる

SinOsc.ar(freq, phase, mul, add)と書いてある
()の中は引数で、左から、周波数(1秒毎の波の振動数≒音高、デフォルト値=440)、位相(≒波の横位置、デフォルト値=0)、乗数(波の振れ幅≒音量、デフォルト値=1)、加数(波の縦位置、デフォルト値=0

*新しいUGenを見たらすぐにヘルプを開いて、どのような引数をとるのか確認しましょう

【注意】
基本的にはmul+addの合計値は必ず、-1~1の範囲に収まるようにしてください。それ以上だと音が割れます。何かの間違いでここの値が100などになっていて、気づかずに実行した場合もう二度とSCを触りたくなくなるような爆音を聞くことになります。

{SinOsc.ar(441, 0, 1)}.play
{SinOsc.ar(1200, 0, 0.5)}.play
{SinOsc.ar(200, 0, 0.2)}.play

s.quit //localサーバー終了


//.scope
".scope"internal起動時のみ有効で、波形を表示してくれます。
".play"defaultサーバーが起動時のみ有効です。

Server.internal.boot //internalサーバーを起動

{SinOsc.ar(441, 0, 0.5)}.scope
{SinOsc.ar(441, 0, 0, 0.8)}.scope

//ステレオで音を出す
{SinOsc.ar([441, 441], 0, 0.5)}.scope 

//左右の周波数をずらす
{SinOsc.ar([441, 443], 0, 0.5)}.scope

//ステレオ、ショートカット
{SinOsc.ar(200, 0, 0.5)!2}.scope //!は演算子。"a!b"ab個複製する
//上のコードは下と同じです。
{[SinOsc.ar(200, 0, 0.5),SinOsc.ar(200, 0, 0.5)]}.scope

//簡単なミックス
{(SinOsc.ar*0.1)+(Saw.ar*0.1)!2}.scope //Sawはノコギリ波を生成するUGen

//いろいろなUGen
{[(Gendy1.ar*0.1)+(GrayNoise.ar*0.1), (LFNoise2.ar*0.1)+(Formant.ar*0.1)]}.scope

*ヘルプを見てみましょう
参照:UGens

//モジュレーション
{SinOsc.ar(SinOsc.ar(2, 0, 200, 200), 0, 0.4)!2}.scope

{SinOsc.ar(Saw.ar(4, 200, 200), 0, 0.3)!2}.scope

{SinOsc.ar(VarSaw.ar(8, 0.5, 120, 400), 0, 0.4)!2}.scope

//より複雑なモジュレーション
(
{
SinOsc.ar(
SinOsc.ar([3,7], 0, 3, SinOsc.kr(9, 0, 900, 90)), 
0, 
SinOsc.kr(7, 0, 0.2, 0.25)
)!2}.play
)

(
{
SinOsc.ar(
SinOsc.ar([3,7], 0, 3, SinOsc.kr(9, 0, 900, 90)), 
SinOsc.ar(88,0,8), 
SinOsc.kr(7, 0, 0.1, 0.1)
)!2}.play
)

".kr"はコントロールレイト(UGenが生成する64サンプルごとに一回)で出力するメソッド。

Server.internal.quit //internalサーバーを終了


//--2.3 sc140をやってみる

sc140とは、SC140字以内のコードを書いてtwitterでつぶやくことです。
たった140字でとても面白い音がなるコードがたくさんあります。
気に入ったものを解読していくのは良い勉強になると思います。



s.boot //localサーバー起動

//SinOscだけでもモジュレーションを使っていろいろ楽しめます
play{SinOsc.ar(SinOsc.ar(2,0,SinOsc.ar(SinOsc.kr(12,0,4,16),400,800),SinOsc.ar(8,60,240)),0,SinOsc.ar(4,0,0.2,0.2))!2}

play{SinOsc.ar(SinOsc.ar(8,0,SinOsc.ar(8,0,88,888)),SinOsc.ar(888,0,8),SinOsc.ar(8,0,0.22,0.22))!2}



//--3. 音源(楽器)を作る

//--3.1 SynthDef
SynthDef"synth definition"音源を定義するクラス

SynthDef(\音源名, {|引数|
音源;
Out.ar(bus, 音源) //Outは音の出力先、出力内容を指定するためのUGen
}).send(s); //SynthDefをサーバーに送る

または

SynthDef("音源名", {arg 引数;
音源;
Out.ar(bus, 音源)
}).send(s);

というふうに書きます。
上と下の例では、音源名と引数の書き方が異なります。
上の例の方が入力する文字数は少なくてすみます。
\JISキーボードの場合、option+¥で入力します。
よく使うのでことえりの環境設定で¥キーで入力する文字を\に変更しておくことをおすすめします。

busは音の信号路(≒出力チャンネル)0=>左チャンネル、1=右チャンネル
SCには0~127まで128個のバスががあります。
2以降に音を送っても、マルチチャンネル再生環境でなければ音は鳴りません。


//実際に書いてみましょう
まずはlocalサーバーをデフォルトに戻して起動
(
Server.default= Server.local;
s= Server.default;
s.boot
)

//実際に動くSynthDefを書きます
(
SynthDef(\tama, {|frq= 441|
var snd; //変数を宣言
snd= SinOsc.ar(frq, 0, 0.2);
Out.ar(0, snd);
}).send(s)


//--3.2 Synthメソッドで音を出す
Synth(\tama)
a= Synth(\tama)
//引数の値は再生時に変更できる
a.set(\frq, 210)
//終了
a.free

//一つのSynthDefから複数の別の音を出せます

a= Synth(\tama)
b= Synth(\tama)
c= Synth(\tama)

a.set(\frq, 100)
b.set(\frq, 100*2)
c.set(\frq, 100*3)

a.free
b.free
c.free


//--3.3 Pan2 +EnvGen

Pan2はステレオの音の位置をコントロールするためのUGen
//Pan2(入力、 音の位置:-1=左、0=真ん中、1=右、 入力レベル)

(
SynthDef(\tamabi, {|frq=800, amp=0.5|
var snd;
snd= SinOsc.ar(frq, 0, amp);
Out.ar(0, Pan2.ar(snd));
}).send(s)
)

a= Synth(\tamabi);
a.set(\frq, 1200, \amp, 1);
a.free

//パンニング
(
SynthDef(\tamabi, {|frq=800, amp=0.5, pan=1|
var snd;
snd= SinOsc.ar(frq, 0, amp);
Out.ar(0, Pan2.ar(snd, SinOsc.kr(pan))); //sin波で音の位置をコントロールする
}).send(s)
)

a= Synth(\tamabi)
a.set(\pan, 4)
a.set(\pan, 8)
a.set(\pan, 12)
a.set(\pan, 24)
a.free


//エンベロープを使う
エンベロープは音量をコントロールするための一本の曲線のようなものと考えてください。

//いろいろな種類のエンベロープがあります
Env.perc.plot
Env.sine.plot
Env.adsr.plot

//".test"を使って簡単に音を確認できます。
Env.perc.test
Env.sine.test
Env.adsr.test

参照:Env

//エンベロープを使ったSynthDef
(
SynthDef(\hacker, {|frq= 200, amp=0.5, atk=0, rel=1|
var env, snd;
env= EnvGen.kr(Env.perc(atk, rel), doneAction:2); //EnvGenはエンベロープ生成するUGen
snd= Saw.ar(frq, amp*env); //ここで音量にエンベロープをかける。Sawはノコギリ波を生成するUGen
Out.ar(0, Pan2.ar(snd));
}).send(s)
)

*エンベロープの指定には基本的に、.arではなく.krで必要十分な結果が得られます。
.ar.krを正しく使い分けることでCPUを節約できます。

doneActioneはエンベロープを生成し終わった後の挙動を指定するための引数。
0は何もしない。1は一時停止。2はエンベロープ生成後にsynthを解放(.free)する。
参照:UGen-doneActions 


Synth(\hacker)
Synth(\hacker,[\atk, 0.01, \rel, 0.1])
Synth(\hacker,[\atk, 0.01, \rel, 0.1])
Synth(\hacker,[\frq, 120, \atk, 0.01, \rel, 0.1])




//--4. シーケンスを書いてみる

まずは音源を用意

(
SynthDef(\melo, {|frq= 785, amp= 0.5, atk= 0.005, rel= 0.2|
var env, snd;
env= EnvGen.kr(Env.perc(atk, rel), doneAction:2);
snd= SinOsc.ar(frq, 0, amp*env);
Out.ar(0, Pan2.ar(snd));
}).store
)
//.storeメッセージを使うとSynthDefは、HD/ユーザ-/自分のアカウント/ライブラリ/Application Support/SuperCollider/synthdefsの中に小さなバイナリファイルとして保存されます。今からPbindでこのSynthDefを使うために保存します。

HDにファイルを残したくなく、一時的にメモリへ保存したい場合は、「.store」を「.add」(3.4rcから追加されたメソッド)または「.memStore」に置き換えてください。「.memStore」は将来的に使えなくなるそうです。


//--4.1 Pbind 
PbindPatternというSCのシーケンスを書くためのクラスの一種。
手軽にいろんな要素をコントロールしてシーケンスを書ける

a= Pbind(\instrument, \melo).play //なぜか音が小さい。何も指定しなければamp0.1くらいになる。。?
a.stop


a= Pbind(\instrument, \melo, \amp, 0.5).play
a.stop

a= Pbind(\instrument, \melo, \amp, 0.1).play
a.stop

//テンポをbpm120に変える。デフォルトのテンポはbpm60
Tempo.bpm= 120;

a= Pbind(\instrument, \melo, \amp, 0.4).play
a.stop


a= Pbind(\instrument, \melo, \dur, 0.25).play // \durduration、音の鳴る間隔を調整する

"\~""key"と呼ばれるもので、"\instrument""freq"のようにデフォルトで設定されたものや
自分がSynthDefで指定した引数をコントロールできる

a.stop


//--4.2 Pseq
Pseqsequential(順次的)なパターンをつくる。

a= Pbind(\instrument, \melo, \frq, Pseq([900, 600, 800], inf), \dur, 0.2, \amp, 0.5).play
a.stop

"inf"Pseqの引数「repeat」で、[]内の数字の繰り返しがinfinite(無限)に続くという意味です。
ここに何も書いていなければ一回で、数字が書いてあればその数を実行して終了します。

//一回で終わる
a= Pbind(\instrument, \melo, \frq, Pseq([900, 600, 800]), \dur, 0.2, \amp, 0.5).play

//三回で終わる
a= Pbind(\instrument, \melo, \frq, Pseq([900, 600, 800], 3), \dur, 0.2, \amp, 0.5).play

//一つのSynthDefから複数のPatternを作って
a= Pbind(\instrument, \melo, \frq, Pseq([1200, 600, 900], inf), \dur, Pseq([0.4, 0.8], inf), \amp,0.5).play

b= Pbind(\instrument, \melo, \frq, Pseq([900, 600, 800], inf), \amp, Pseq([0.3, 0.6], inf), \rel, 0.1).play

c= Pbind(\instrument, \melo, \frq, Pseq([2400, 1800], inf), \dur, Pseq([0.4, 0.3], inf),\amp, Pseq([0.1, 0.4, 0.2], inf), \rel, 0.05).play


b.stop

b.start

c.stop

c.play

a.stop

b.stop

c.stop


//--4.3 Ppar
Pparは複数のPbindを並行(parallel)に走らせることができる

(
a= Ppar([
Pbind(\instrument, \melo, \frq, 400),
Pbind(\instrument, \melo, \frq, Pseq([200, 300, 400], inf), \dur, 0.5)
]).play
)

a.stop


//ドラムパターンを作ってみる

音源を用意

//kick
(
SynthDef(\kick, {|frq= 55, amp= 0.8, rel= 0.3|
var e, s, f;
e= EnvGen.kr(Env.perc(0, rel), doneAction:2);
s= SinOsc.ar(frq, pi/2, amp); //piは円周率3.14....
f= RHPF.ar(s, frq, 0.5, amp*e); //レゾナント・ハイパスフィルタ
Out.ar(0, Pan2.ar(f, 0));
}).store;

Synth(\kick)

//hat
(
SynthDef(\hat, {|frq= 5500, amp= 0.5, rel= 0.08|
var e, s, f;
e= EnvGen.kr(Env.perc(0, rel), doneAction:2);
s= WhiteNoise.ar(amp);
f= HPF.ar(s, frq, amp*e); //ハイパスフィルタ
Out.ar(0, Pan2.ar(f, 0));
}).store;
)

Synth(\hat)


//snare
(
SynthDef(\snare, {|frq= 5000, amp= 0.9, rel= 0.1|
var e, s, s2, f; 
e= EnvGen.kr(Env.perc(0, rel), doneAction:2);
s= BrownNoise.ar(amp);
s2= GrayNoise.ar(amp*e);
f= BPF.ar(s+s2, frq, 0.5, amp*e); //バンドパスフィルタ
Out.ar(0, Pan2.ar(s2+f, 0)); //フィルタを通したs+s2=fs2を足して出力している
}).store;
)

Synth(\snare)
a= Pbind(\instrument, \snare, \amp, 0.5).play

//シーケンス:kick + hat 
(
a= Ppar([
Pbind(\instrument, \kick, \frq, 60, \amp, 0.7, 
\rel, Pseq([0.9, 0.5], inf)
),
Pbind(\instrument, \hat, \amp, Pseq([0, 0.8],inf), \dur, 0.5)
]).play
)

a.stop

//シーケンス:kick + hat + snare
(
a= Ppar([
Pbind(\instrument, \kick, \frq, 60, \amp, 0.7, \rel, Pseq([0.9, 0.5], inf)),
Pbind(\instrument, \hat, \amp, Pseq([0, 0.8],inf), \dur, 0.5),
Pbind(\instrument, \snare, \amp, Pseq([0, 0.5], inf))
]).play
)

//シーケンス:kick + hat + snare 2
(
a= Ppar([
Pbind(\instrument, \kick, \amp, 0.7, 
\rel, Pseq([0.9, 0.5, 0.25, 0.7], inf)
),
Pbind(\instrument, \hat
\frq, Pseq([4500, 5500, 6000], inf), 
\amp, Pseq([0, 0.7, 0, 0.9], inf),
\dur, Pseq([0.47, 0.53], inf)
),
Pbind(\instrument, \snare, \frq, 5000, 
\amp, Pseq([0, 0.2, 0.2], inf),
\rel, Pseq([0.2, 0.3], inf),
\dur, Pseq([1, 0.5, 0.25], inf)
)
]).play
)
//シーケンス:kick + hat + snare + melo
(
a= Ppar([
Pbind(\instrument, \kick, \frq, 50, \amp, 0.7, 
\rel, Pseq([0.9, 0.5, 0.25, 0.7], inf)
),
Pbind(\instrument, \hat
\frq, Pseq([4500, 5500, 6000], inf), 
\amp, Pseq([0, 0.7, 0, 0.9], inf),
\dur, Pseq([0.47, 0.53], inf)
),
Pbind(\instrument, \snare, \frq, 5000, 
\amp, Pseq([0, 0.2, 0.25], inf),
\rel, Pseq([0.12, 0.15], inf),
\dur, Pseq([1, 0.5, 0.25], inf)
),
Pbind(\instrument, \melo, \frq, 400),
Pbind(\instrument, \melo, \frq, Pseq([200, 300, 400], inf), \dur, 0.5)
]).play
)

*シーケンスの作り方には他にもたくさんの方法があります。
いろいろと調べて自分の一番好きな方法を見つけてみてください。

参照:Taskで自作シーケンサを作る



//------------------
文責: 安田到 - i@itaru.org

0 件のコメント:

コメントを投稿