近況、エフェクト(1)

sc3.3 for win

些か旧聞ですがwin版sc3.3の安定版が出ました。
SuperCollider (SourceForge)
SuperCollider 3.3.1 win版について
でもって本文導入部分に多少の変更を要するとは思うのですが、各自よしなにお願い致す。

sc文法一覧

加えてこちらの記事が大変に素晴らしいですので、文法に詳しくなりたい人は是非読みましょう。奥深いわー
SuperCollider基礎文法最速マスター

ディレイいろいろ

さて我々は地道に泥臭く音いじりの方法について考えたいと思う。今回はいわゆるscのエフェクタ的用法について書きますが、その前に、と申しますか、PCならではの遅延(レイテンシ)というものが避けがたく存在しますゆえ、好き勝手なエフェクトは作れるものの単体機並みの反応速度は期待できない、という点に留意します。まあscに限った話でもないと思いますが、
環境にもよるが常にコンマ何秒の遅れが発生しますので、例えば楽器を通す場合には音楽的に「レイテンシが気にならない方向で」の使い方などを追って考える必要があるんでは、と思います。それはともかく、まずは音を入力しなければ話が始まりません。オーディオI/Fの用意は出来ているものとして、入力にはSoundInを使う。

SynthDef("input", {
var in;
in = SoundIn.ar(0);
Out.ar(0,in!2); 
}).play;

単に入力して聴いてるだけですが、ここで例のレイテンシが聴けると思います。これについては今後考えないようにして話を進める。
と言いつつ次はディレイの話なんですが、一番単純なディレイはDelayNであります。

SynthDef("delay", {
var in,out;
in = SoundIn.ar(0);
out = DelayN.ar(in,1,1);
Out.ar(0,out!2); 
}).play;

例によって個々のパラメータについては各自ヘルプを見るように。ここでは1秒遅れで音を返している。任意の時間後に音を遅らせて返せるというわけですが、しかしこれだけでは大して芸がないように思える。
いわゆるディレイと言った時に思い出すような、エコーみたいな効果を作るには、実はCombNを使うのが早い。

SynthDef("comb_delay", {
var in,out;
in = SoundIn.ar(0);
out = CombN.ar(in,0.1,0.1,1);
Out.ar(0,out!2); 
}).play;

ヘルプ見つついろいろパラメータをいじって戴きたいのですが、ここでdelaytimeを極端に短くしてdecaytimeを多めに(とはいえ程々に)とると、パイプの中を通ってきたような妙な音色が出てくる。

SynthDef("comb_filter", {
var in,out;
in = SoundIn.ar(0);
out = CombN.ar(in,0.1,0.01,0.5);
Out.ar(0,out!2); 
}).play;

確か、これのスペクトルを見ると櫛みたいにピークが立ってるのでコムフィルタと言う、と思いましたが、フランジャーやコーラスと呼ばれるものも実はこれの応用。
先程のエコーみたいなやつはフィードバックを使って次のように書くことも可能。

SynthDef("feedback_delay", {
var fb,in,out;
in = SoundIn.ar(0);
fb = LocalIn.ar(1);
out = DelayN.ar(in+fb,0.1,0.1);
LocalOut.ar(out*0.7);
Out.ar(0,out!2); 
}).play;

LocalIn、LocalOutというのが出てきましたが、これで出た音を再入力というかフィードバックしている。何でこんな面倒なことをするかというと、ここではDelayNですが、間にいろいろと他の処理をはさめたりしますので。
さらにLocalOutに「0.7」という数字がありますが、これはいわゆるフィードバック係数でして、どのくらいの割合の音量でフィードバックするかという。これが1以上になるとフィードバック音が消えなくなって音量が爆発します。特にLocalOutの中に書く必要はござりませんぬ。
さて先程のコムフィルタもそうですが、実のところエフェクトと呼ばれるものの多くがディレイから出来ているわけでして、フィルタなんかもそのひとつです。例えばCombNのdelaytimeを超短くすると、なんちゃってローパスフィルタになりますが、

SynthDef("pseudo_low_pass_filter", {
var in,out;
in = SoundIn.ar(0);
out = CombN.ar(in,0.1,0.000001,0.001);
Out.ar(0,out!2); 
}).play;

もちろんこんなものは非常に使いにくいので、scには一通りのフィルタが用意されている。ローパスフィルタはLPF。そのまんまだ。

SynthDef("low_pass_filter", {
var in,out;
in = SoundIn.ar(0);
out = LPF.ar(in,1000);
Out.ar(0,out!2); 
}).play;

DelayNを使って手抜きっぽくステレオ効果を作ることも出来る。

SynthDef("pseudo_stereo", {
var in,out;
in = SoundIn.ar(0);
out = DelayN.ar(in,0.1,[0,0.02]);
Out.ar(0,out); 
}).play;

左右のdelaytimeを微妙に違えているわけですが、定位感が若干アンバランスになるので注意です(先に音が届いた方向に音源があるように感じる)。
さてここまで、最も単純なディレイをDelayNと説明してきましたが(嘘。本当はDelay1と思いますが特殊な用途しか思いつかないので割愛)、DelayはわかるがNとは何だろうか。例えばdelaytimeを一定ではなく変動させてみたりすると妙な事が起こります。

SynthDef("delay_time_mod", {
var in,mod,out;
in = SoundIn.ar(0);
mod = SinOsc.ar(1,0,0.49,0.5);
out = DelayN.ar(in,1,mod);
Out.ar(0,out!2); 
}).play;

実は曲がった音に変なノイズが乗ってるんですが。DelayやCombにはNの他にLやCというのもありまして、曲がった波形の補間をしてくれる、というのだが、要はこうした使い方をするときに変なノイズが乗るのを防いでくれる。まあ好みの問題。

SynthDef("delay_time_mod_2", {
var in,mod,out;
in = SoundIn.ar(0);
mod = SinOsc.ar(1,0,0.49,0.5);
out = DelayL.ar(in,1,mod);
Out.ar(0,out!2); 
}).play;

あとdelaytimeを動かすことでさらにいろいろできます。アナログテープなどの再生速度をいじってるイメージ、と言えばたぶんそんな感じですが、例えばdelaytimeにSinOscをつっ込んでビブラートをかける。

SynthDef("vibrato", {
var in,mod,out;
in = SoundIn.ar(0);
mod = SinOsc.ar(10,0,0.005,0.01);
out = DelayL.ar(in,1,mod);
Out.ar(0,out!2); 
}).play;

ビブラートとそうでないのをぶつけるとフランジャになる。要は変動するコムフィルタ。

SynthDef("flanger", {
var in,mod,out;
in = SoundIn.ar(0);
mod = SinOsc.ar(0.3,0,0.001);
out = DelayL.ar(in,1,[0.001,0.001+mod]);
Out.ar(0,out!2); 
}).play;

ところでこうした時に使うSinOscなどのオシレータをLFOと言いますね。別にLFOは何だっていいわけです。

SynthDef("scratch", {
var in,mod,out;
in = SoundIn.ar(0);
mod = LFNoise0.ar(8,0.5,0.5);
out = DelayL.ar(in,1,mod);
Out.ar(0,out!2); 
}).play;

LFNoise0というのを入れてみましたが、これは言わば乱数発生器です。でもってLFNoiseにも0、1、2がありますが、LFNoise1とLFNoise2は波形の補間をするものであり、この場合の音の違いを各自試してみるが吉。
次にdelaytimeにPhasorを入れて逆再生、なのだがここでPhasorのrateが2なのは何故か、ということを考えはじめるとわけわからなくなれます。ディレイラインの中では常に音が進んでいるわけだから…等々。

SynthDef("reverse", {
var in,mod,out;
in = SoundIn.ar(0);
mod = Phasor.ar(0,2,0,44100);
out = DelayL.ar(in,1,mod/44100);
Out.ar(0,out!2); 
}).play;

ところで上の例では44100という数字が散見されますが、これはPhasorが「1サンプルごとにrate分ずつカウントアップする」という仕組みゆえでありまして、もう少し見やすい書き方をするなら以下のようにもできるかと。

SynthDef("reverse_2", {
var in,mod,out;
in = SoundIn.ar(0);
mod = Phasor.ar(0,2/44100,0,1);
out = DelayL.ar(in,1,mod);
Out.ar(0,out!2); 
}).play;

Phasorのrateをいろいろ変えるとピッチシフトになる。あるいは逆再生はピッチシフトの特殊なやつと言うべきか。

SynthDef("pitch_shift", {
var in,mod,out;
in = SoundIn.ar(0);
mod = Phasor.ar(0,0.5/44100,0,1);
out = DelayL.ar(in,1,mod);
Out.ar(0,out!2); 
}).play;

ピッチシフトにフィードバックをかますとどうなるか。

SynthDef("fb_pitch_shift", {
var fb,in,mod,out;
in = SoundIn.ar(0);
fb = LocalIn.ar(1);
mod = Phasor.ar(0,0.25/44100,0,1);
out = DelayL.ar(in+fb,1,mod);
LocalOut.ar(out/2);
Out.ar(0,out!2); 
}).play;

まあ結構荒っぽいわけですがピッチシフトの原理とは概ねこれであるわけです。これに窓かけしたりオーバーラップさせたりして音をきれいにしたのがPitchShift、という理解。

SynthDef("fb_pitch_shift_2", {
var fb,in,out;
in = SoundIn.ar(0);
fb = LocalIn.ar(1);
out = PitchShift.ar(in+fb,0.1,0.75);
LocalOut.ar(out);
Out.ar(0,out!2); 
}).play;

こんなもんか。結構たくさんになりましたが、ディレイだけでかなりのことができてしまう、というお話でした。