見出し画像

グラニュラーシンセシス

グラニュラーシンセシスが可能なクラス、GrainBufというクラスについて書きます。
手順的にはバッファに波形を読み込ませてパラメーターをいじるだけ、簡単です。

*今回使うwavファイルを添付しますので、よかったらダウンロードして使ってください。

*「オーディオファイルを鳴らす」の回で使ったwavファイルをモノラルにしたものです。

グラニュラーはステレオファイルに対しても可能なのですが、バッファに読み込む時にちょっと工夫が必要ですので、まずはモノラルファイルを使って。ステレオファイルについては最後に書きます。


グラニュラーしたいファイルをバッファに読み込ませる


「オーディオファイルを鳴らす」の回ではwav波形をバッファに読み込ませて、PlayBufで鳴らしました。手順的にはあのときと全く同じで、使うクラスがPlayBufの代わりにGrainBufになる、それだけです。


(まずcommand+bでサーバ起動します。)
(メニューからBootSeverを選択してもOKです。)

最初に、オーディオファイルをバッファに読み込ませて、変数bに入れます。
(ファイルパスについてはご自身の置き場に合わせてください。)

b = Buffer.read(s, "/Users/kurikuro/Desktop/samples/rythm01_mono441.wav");


読み込んだ波形を再生して確認します。

b.play;

モノラルファイルですので、この段階では左チャンネルからしか鳴らないはずで、それで正常です。
これでオーディオファイルをGrainBufで使う準備ができました。


GrainBuf


さて、GrainBufのパラメータと初期値は以下のとおりです。
GrainBuf.ar(numChannels: 1, trigger: 0, dur: 1, sndbuf, rate: 1, pos: 0, interp: 2, pan: 0, envbufnum: -1, maxGrains: 512, mul: 1, add: 0)

ひとつずつ簡単に説明を書きます。

numChannels:読み込ませたファイルのチャンネル数で、モノラルの場合は1です。
trigger:グレイン(音の粒)を再生させるトリガー。ここが0より上(正の値)だとトリガーが発生します。
dur:グレイン(音の粒)の長さです。(秒)
sndbuf:音声ファイルを読み込ませたバッファです。今回は変数bです。
rate:グレイン(音の粒)が再生されるピッチです。
pos:読み込ませたファイル上のポジション。0がファイルの頭で1がファイルのお尻。ここで設定したポジションからdurの長さの波形がループ再生されるイメージです。
interp:グレイン(音の粒)をピッチシフトしたときの波形補間です。1で補間ナシ、2で線形補間、3で曲線補間、デフォルトは2です。
pan:グレイン(音の粒)が再生されるPANポジションですが、バッファに読み込ませたファイルがモノラルのときはここの数値は無視されるそうです。なぜ?と思いますけど…ヘルプにそう書かれています。。ちなみにステレオファイルのときは”Pan2クラスと同じ様に機能します”と書かれてあるんですけど、、ステレオファイルでもここの値は効かないんですよねー。。ただ、ステレオファイルはそのファイルの時点でパンニングされた音になっているので困ることはないとは思います。
envbufnum:グレイン(音の粒)同士のつなぎ目のエンベロープを、デフォルトのものを使うか自作のものを使うか。-1でデフォルトのハニングEnvです。
デフォルトのハニングEnvはこんな形をしています。

maxGrains:グレイン(音の粒)同士の重なり合いをいくつまで許容するかの値でデフォルト512です。
muladdは、いつものやつです。振幅と、振幅に加算減算する値です。


パラメータがたくさんありますが、エディットの肝のなるのはtrigger/dur/rate/posの4つで、その他は固定値でよいと思います。
では、trigger/dur/rate/posあたりをいじっていきます。
まずは一例です。

(
{
	var sig;
	sig = GrainBuf.ar(
		1,//mono
		Impulse.ar(50),//trigger
		0.1,//dur
		b,
		1,//rate
		MouseX.kr(0,1).poll,//pos
		2,//interp:linear
		0,//pan
		-1,//hanning
		512,//maxGrains
		1,//mul
		0//add
	);
	sig = Pan2.ar(sig, 0) * 0.5;
}.play;
)

マウスの左右位置をゆっくりずらしていくと、グレインの再生位置が変わっていくのがわかると思います。
元がリズムループだとは思えないような音が出てきます。
(音をPan2に入れているので左右のセンターから出力されるはずです。)

トリガーにImpulseを使っています。
SuperColliderのトリガーは、「0から正の値に移行したとき」に発生します。
それが周期的に起きればいいので、Impulseである必要はなく、SinOscでもLFSawでもOKです。

上記コードの中の、トリガーの頻度(50の部分)やdurを変えてみると発見があると思います。

頻度を500とかまで上げると、とんでもない感じになってきました。
(音量が突然上がる場合があるので、最後信号に0.2掛けました。)

(
{
	var sig;
	sig = GrainBuf.ar(
		1,//mono
		Impulse.ar(500),//trigger
		0.3,//dur
		b,
		1,//rate
		MouseX.kr(0,1).poll,//pos
		2,//interp:linear
		0,//pan
		-1,//hanning
		512,//maxGrains
		1,//mul
		0//add
	);
	sig = Pan2.ar(sig, 0) * 0.2;
}.play;
)



次の例では、トリガーの頻度を下げました。
また、マウスの縦位置でrateが変わるようにしています。
rateは1が元のピッチのまま、0.5でオクターブ下、2でオクターブ上(4で2オクターブ上)、というふうに変わります。
なので次の例だと、マウスが画面一番下にあるときはオクターブ下で、マウスが画面一番上にあるときは2オクターブ上です。
(今回はリズムループのサンプルですが、もっと音程感のあるサンプルだと顕著に差を感じられます。)
あと、interp以降のパラメータはデフォルトのままなので消しました。

(
{
	var sig;
	sig = GrainBuf.ar(
		1,//mono
		Impulse.ar(20),//trigger
		0.3,//dur
		b,
		MouseY.kr(0.5,4),//rate
		MouseX.kr(0,1),//pos
	);
	sig = Pan2.ar(sig, 0) * 0.5;
}.play;
)



これまでマウスの左右位置で決めていたposを、自動で0→1に変化するようにしたいと思います。
Lineを使って、2秒間で0から1に値が変わるようにします。

(
{
	var sig;
	sig = GrainBuf.ar(
		1,//mono
		Impulse.ar(20),//trigger
		0.1,//dur
		b,
		1,//rate
		Line.kr(0,1,2,doneAction:2),//pos
	);
	sig = Pan2.ar(sig, 0) * 0.5;
}.play;
)

これも、トリガー頻度やdurを色々と変えて試してみると面白いです。
あと、Lineを2秒ではなく他の秒数にしても。
元のリズムに何かエフェクトをかけたような音色になったりします。


さて、Lineだとポジションが0(ファイルの頭)から始まって1(ファイルのお尻)で止まったっきりでしたが、今度はLFSawを使ってみます。
LFSawは0→1の動きを繰り返し行うので、リズムをループ再生させるような効果が出ます。

(
{
	var sig;
	sig = GrainBuf.ar(
		1,//mono
		Impulse.ar(80),//trigger
		1/80*2,//dur
		b,
		1,//rate
		LFSaw.ar(0.25,1),//pos
	);
	sig = Pan2.ar(sig, 0) * 0.5;
}.play;
)

この状態でトリガー頻度やdur、さらにLFSawの周期を変えてみるのも面白いです。


ちょっと脱線してLFSawの位相の話


先ほどのコードでLFSawのphaseを1にしているのには理由があります。
range(0,1)のときphaseが0だと、LFSawは0.5から開始されます。

phaseが0のLFSaw

posに対するLFSawなので、ファイル真ん中あたりからフレーズが開始されることになります。
phaseを1にすることで開始位相が変わり、LFSawは0から開始されます。

phaseが1のLFSaw

これでファイルの頭からフレーズが開始されることになります。
(純粋に0→1を繰り返すことになります。)

phaseを0.5など他の値にしてどんな差があるか実験することもできます。ただし有効な値は0から2です。

LFSawの開始位相については「LFオシレーター」の回でもパンニングを操る例で取り上げていますので、興味のある方はそちらもどうぞ。


さらにヤバいエディット


先ほどのコードをさらにエディットして、
LFSaw.ar(0.25,1)を
LFSaw.ar(0.25,1).neg
に変えてやると逆再生のようになりますし、
LFTri.ar(0.25,3).range(0,1)だと、0→1→0→1を繰り返すので、順再生/逆再生を繰り返す感じになります。

(
{
	var sig;
	sig = GrainBuf.ar(
		1,//mono
		Impulse.ar(80),//trigger
		1/80*2,//dur
		b,
		1,//rate
		// LFSaw.ar(0.25,1).neg,//pos
		LFTri.ar(0.25,3).range(0,1),//pos
	);
	sig = Pan2.ar(sig, 0) * 0.5;
}.play;
)


さらにさらに、
SinOsc.ar(0.25).range(0,1)や
LFNoise0.ar(30).range(0,1)
などに変えてやると、かなりヤバい感じになります。
下記は、他のパラメータも周期的な数値にしてみたものです。

(
{
	var sig;
	sig = GrainBuf.ar(
		1,//mono
		Impulse.ar(80),//trigger
		SinOsc.ar(1.2).range(1/80,10/80),//dur
		b,
		LFNoise0.ar(0.7).range(0.5,2),//rate
		// LFSaw.ar(0.25,1).neg,//pos
		// LFNoise0.ar(30).range(0,1),//pos
		SinOsc.ar(0.25).range(0,1),//pos
	);
	sig = Pan2.ar(sig, 0) * 0.5;
}.play;
)

これはヤバすぎる・・・同じリズムネタとは思えないです。

まだまだ遊びがいがありそうですよね。
しかもこれ、ひとつのサンプルをいじってるだけですから。サンプルを入れ替えるとまた違う気持ち良さを発見できると思います。


ステレオファイルのバッファ読み込み


最後に、バッファに読み込むオーディオファイルがステレオの場合についてです。
Buffer.readではなく
Buffer.readChannnelを使って、片チャンずつ読み込む必要があります。
(下記コード内のstereo_sample.wavは架空のステレオファイルです。)

c = Buffer.readChannel(s, "/Users/kurikuro/Desktop/samples/stereo_sample.wav", channels:[0]);
c.play;
c.numChannels;


d = Buffer.readChannel(s, "/Users/kurikuro/Desktop/samples/stereo_sample.wav", channels:[1]);
d.play;
d.numChannels;

上記のように、片チャンずつ読み込んで、使う時に[c, d]というかたちで使います。

(
{
	var sig;
	sig = GrainBuf.ar(
		2,
		Impulse.ar(0.5),
		2,//dur
		[c, d],
		1,//rate
		0,//pos
		2,
		0,//pan
		-1,//hangingwindow
		512,//maxGrains
		1,//mul
		0//add
	);
	sig = sig * 0.5;
}.play;
)

その他のパラメータについてはモノラルの時と同じです。


<目次へ>
https://note.com/sc3/n/nb08177c4c011


いいなと思ったら応援しよう!