見出し画像

VOSCで自作Wavetableをモーフィングする(SuperCollider)

「Signal.sineFill()」の回

「Signal.sineFill()追記と、 Buffer.sine1(), Buffer.sine2()」の回

「Env.new().asSignal」の回

これらの回↑で作ったWavetable波形ふたつをモーフィング再生する方法について書きます。

手順1。
SC3のサーバを一度リブートします。
(ServerメニューからReboot Serverを選択。)

手順2。
ふたつのWavetable波形を作ります。

作る方法はいろいろありますが(上記リンク参照)…
ひとつめはEnvを利用して作ることにしました。

//Envで作る
(
~buf0 = Buffer.alloc(s, 2048);
~sig0 = Env.new(
	[0, -0.9, 0, 0.9, 0],
	[1, 2, 6, 6],
	[10, 10, 4, -6]).asSignal(1024);
~wt0 = ~sig0.asWavetable;
~buf0 = ~buf0.loadCollection(~wt0);
)


ふたつめは、sineFillを使って。

//sineFillで作る
(
~buf1 = Buffer.alloc(s, 2048);
~sig1 = Signal.sineFill(
	1024,
	[1, 0, 1/3, 0, 1/5, 0, 1/7, 0, 1/9, 0, 1/11],
	0!11
	);
~wt1 = ~sig1.asWavetable;
~buf1 = ~buf1.loadCollection(~wt1);
)

// ※0!11は[0,0,0,0,0,0,0,0,0,0,0]と書くのと同じです。


Oscを使って、作った波形をそれぞれ聴いて確認してみます。

{Osc.ar(~buf0.bufnum, 220, 0, 0.3)!2}.scope;
{Osc.ar(~buf1.bufnum, 220, 0, 0.3)!2}.scope;

ちなみに~buf0.bufnum/~buf1.bufnumはWavetableを入れたバッファのナンバーで、SC3によって勝手に割り振られます。
下記2行を実行すると、post windowでバッファナンバーの確認ができます。

~buf0.bufnum;
~buf1.bufnum;

冒頭(手順1)でReboot Serverしたので、今はpost windowに上記の実行結果が0と1と表示されていると思います。
※SC3のサーバを起動して、バッファを割り当てるたびに(0から始まって)1ずつカウントされます。リブートするとカウントは0に戻るしくみです。


手順3。
今度はVOscを使って鳴らします。

{VOsc.ar(0, 220, 0, 0.3)!2}.play;

VOscは最初の引数(パラメータ)が「鳴らしたいバッファのナンバー」ですので、1に書き換えるとバッファ1の音が鳴ります。

{VOsc.ar(1, 220, 0, 0.3)!2}.play;

お詫びと訂正(2024.04.27)
↑このコードは大半の人は音が出ない、と思われることが判明しました。
対処方法について、このページの最下部に追記しましたのでお読みください。
すみませんでした。
(追記を読んだあと、ぜひこの項目に戻ってきてください。)

そして、(ここからがVOscの本領発揮!!)0.5など0〜1の間の数字を入れると、バッファ0とバッファ1の中間の波形を計算して出力します。

{VOsc.ar(0.5, 220, 0, 0.3)!2}.scope;

というわけで、ここの値をスムーズに動くようにしてやればモーフィングの完成なのですが、その前に1点。
もしこの「手順3」のコードが鳴らない場合。。。
バッファナンバーが0と1になっていないのだと思います。

~buf0.bufnum;
~buf1.bufnum;
この結果が(例えば)3と4だった場合、手順3のコードを下記のように書き換えると出音の確認ができるはずです。

{VOsc.ar(3, 220, 0, 0.3)!2}.scope;

{VOsc.ar(4, 220, 0, 0.3)!2}.scope;

{VOsc.ar(3.5, 220, 0, 0.3)!2}.scope;

さらに、もし
~buf0.bufnum;
~buf1.bufnum;
この結果が続き番号ではない場合(例えば、0と3など)
(~buf1を作るときにいろいろ実験して何度か実行した、という方はこういう感じで続き番号ではなくなります。)
VOscではバッファナンバーが続き番号である必要があるので、もう一度「手順2」のコードを一度ずつ実行します。

//Envでつくる

//sineFillでつくる
というふたつのコードです。


すると
~buf0.bufnum;
~buf1.bufnum;
の結果が4と5とか、続き番号になります。

手順4。
モーフィングさせる。

VOscのひとつめのパラメータを0から1(とか1から0)に動かしてやります。

(
{
	var mod;
	mod = Line.kr(0, 1, 3.0);
	VOsc.ar(mod, 220, 0, 0.3)!2}.scope;
)

Line.kr(0, 1, 3.0)の0と1はバッファナンバーです。
3秒間で0から1に移り変わります。


バッファナンバーはウェーブテーブル作成するたびに自動割り当てされるので、いろいろ実験しているとそのたびにナンバーを確認するのは面倒です。下記のようにコード内にbufnumを書けばいちいちナンバー確認する必要がありません。
※ただし続き番号になっている必要はあります。

(
{
	var mod;
	mod = Line.kr(~buf0.bufnum, ~buf1.bufnum, 3.0);
	VOsc.ar(mod, 220, 0, 0.3)!2}.scope;
)


いろんなモジュレーション

モーフィングさせる方法はLineの他にもいろいろあります。
下記はMouseXに割り当てた例です。音が鳴っている間マウスを左右に動かすと音色も変わります。scopeウィンドウで波形の確認もできます。

(
{
	var mod;
	mod = MouseX.kr(~buf0.bufnum, ~buf1.bufnum);
	VOsc.ar(mod, 220, 0, 0.3)!2}.scope;
)


下記はサイン波で動かしてみた例です。
サイン波はデフォルトだと-1〜1を繰り返してしまいます。
ここでは0〜1を繰り返したいので、振幅(mul)を0.5にしてaddで0.5加えました。
これで「addのパラメータ0.5を中心に「上に0.5、下に0.5」動く」つまり0〜1を繰り返すことになります。それがわかりやすいように.pollをつけてみました。実行中ポストウィンドウに表示されます。

(
{
	var mod;
	mod = SinOsc.kr(1, mul:0.5, add:0.5).poll;
	VOsc.ar(mod, 220, 0, 0.3)!2}.scope;
)

SinOsc.kr(1
の1を他の数字にしてやるとモジュレーションの速さを変えられます。


次はLFPulseで動かしてみた例です。
LFPulseはデフォルトで0〜1を繰り返すのでmulとaddはいじっていません。
3つめの0.5はパルス幅です。
ただ、デフォルトのままだと0から1(または1から0)に移る時にプチノイズが発生したので.lagで少し緩やかに0から1(または1から0)に移るようにしました。

(
{
	var mod;
	mod = LFPulse.kr(0.5, 0, 0.5).lag(0.1);
	VOsc.ar(mod, 220, 0, 0.3)!2}.scope;
)

lagのカッコ内は0.1にしていますが、実は僕はその単位をよくわかっていません。
なのでいつも聴いた感じで調整します。

LFPulse.r(0.5
の0.5を他の数字にするとモジュレーションの速さを変えられますが、同時に.lagの数字も調整する必要がある場合もあります。
ですが、そのふたつがマッチしないときの出音も結構面白くなったりします。



最後にLFNoise0を使ってランダムに動かした例です。
SinOscの時と同じ理由でmulとaddを0.5にしています。

(
{
	var mod;
	mod = LFNoise0.kr(10, 0.5, 0.5).poll;
	VOsc.ar(mod, 220, 0, 0.3)!2}.scope;
)

上記の10の数字を変えてやるとランダムに動く速さを変えることができます。


今回のコードは、波形を見ながら再生させたかったので.scopeを使いましたが、波形を見る必要がないなら全て.playに置き換えることができます。
VOscはもちろんSynthDefにも入れられますし、いろいろ実験できて楽しいクラスです。


お詫びと訂正(2024.04.27)

VOscが鳴らすことができるのは、「Serverが持っているbufnum〝未満〟」のようです。
※確かな情報ではないですが、実験したらそんな感じです。

なので、ここまで
~buf0.bufnum;(←これが0)
~buf1.bufnum;(←これが1)
だけしか作ってない人は(ほとんどの人がそうだと思います)、VOscに入力できるのは0.9999999999まで、ということになり、

{VOsc.ar(1, 220, 0, 0.3)!2}.play;

このコード(1未満しか受け付けないのに1を入れている)の音が鳴らなかったと思います。
1未満であればよいので、以下のようにすると~buf1.bufnumに限りなく近い音色を聴くことはできます。

{VOsc.ar(0.99999, 220, 0, 0.3)!2}.play;

だけど、それだとなんだかなぁ、という感じなので・・・。
対処法として、仮に3つ目のbufnumを作っておく、というのはどうかなと思います。

(
~buf2 = Buffer.alloc(s, 2048);
~sig2 = Signal.sineFill(
1024,
[1, 0, 1/3, 0, 1/5, 0, 1/7, 0, 1/9, 0, 1/11],
0!11
);
~wt2 = ~sig2.asWavetable;
~buf2 = ~buf2.loadCollection(~wt2);
)

などを実行しておいて、Serverが持っているbufnumの最大値を2にしておきます。(下記を実行するとPost windowに2と出力されると思います。)

~buf2.bufnum;

これで、VOscが鳴らすことができるのは2未満ということになります(0〜1.99999999)。つまり、VOsc.arのひとつ目のパラメータを1にしてもOK。

{VOsc.ar(1, 220, 0, 0.3)!2}.play;

これが鳴るようになっているはずです。

この状態で、このページの「手順3」に戻っていただくと、記事を読み進めることができます。
気づくのが遅くてすみませんでした。




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


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