![見出し画像](https://assets.st-note.com/production/uploads/images/90375393/rectangle_large_type_2_a9184a10a64a57bd2c1602536c1b4018.png?width=1200)
Signal.sineFill()追記と、 Buffer.sine1(), Buffer.sine2()
前回の
(
~bfs1 = Buffer.alloc(s, 2048);
~sig1 = Signal.sineFill(1024, [1, 0.5, 0.3, 0.25, 0.2]);
~wt1 = ~sig1.asWavetable;
~bfs1.loadCollection(~wt1);
)
について少し詳細を書きます。
Signal.sineFill()の時点(2行目)では、いわば”連続した数値”の状態ですが、オシレーターとして使えるようにasWavetable(3行目)が数値間の補完をしてくれて、これによって滑らかな出音になります。
それを確かめるための実験として
~wt1 = ~sig1.asWavetable;
この行をコメントアウトして実行すると、補完されていない(エイリアスノイズのようなものを含む)波形の出音になってしまいます。
(
~bfs1 = Buffer.alloc(s, 2048);
~sig1 = Signal.sineFill(1024, [1, 0.5, 0.3, 0.25, 0.2]);
// ~wt1 = ~sig1.asWavetable;
~bfs1.loadCollection(~wt1);
)
// シーケンス
(
//Bus
~rvbBus = Bus.audio(s, 2);
SynthDef(\sinf, {
arg freq=220, gate=1;
var env, sig;
env = EnvGen.kr(Env.asr(0.001, 1, 0.05), gate, doneAction:2);
sig = Osc.ar(~bfs1.bufnum, freq, 0, 0.3);
Out.ar(~rvbBus, sig!2 * env);
}).add;
//reverb
SynthDef(\rvb, {
var eff, in;
in = In.ar(~rvbBus, 2);
eff = FreeVerb2.ar(in[0], in[1], 0.2, 0.8, 0.5);
Out.ar(0, eff);
}).add;
//Pbind
~pb1 = Pbind.new(
\instrument, \sinf,
\midinote, Pseq([60, 72, 55, 67, 65, 60, 55, 58], inf),
\dur, 0.5,
\sustain, 0.1);
Pfx(~pb1, \rvb).play(TempoClock(110/60));
)
あと前回、バッファのサイズは2048でじゅうぶんということを書いたのですが、バッファサイズを小さくすることで適正な数値かどうかの実験ができるなぁと思いましたので書きます。
例えば極端な話、バッファサイズを16とかにしたらどんな音になるでしょうか。
(
~bfs1 = Buffer.alloc(s, 16);
~sig1 = Signal.sineFill(8, [1]);
~wt1 = ~sig1.asWavetable;
~bfs1.loadCollection(~wt1);
)
※先ほどのシーケンスで鳴らすことができます。
なめらかなサイン波ではなく少し倍音が含まれる音が鳴ります。サンプル数が少ないためです。plotすることでもそれを確かめることができます。
![画像1](https://assets.st-note.com/production/uploads/images/85206705/picture_pc_d6abfdeb59e04258bd06b1072d7e94a3.png)
ちなみに作った波形をplotするには、~sig1をplotします。下記のような感じです。
(
~bfs1 = Buffer.alloc(s, 16);
~sig1 = Signal.sineFill(8, [1]);
~sig1.plot;
~wt1 = ~sig1.asWavetable;
~bfs1.loadCollection(~wt1);
)
(~bfs1を鳴らすので~bfs1.plot;としてしまいそうですがWavetable化してバッファに入れたあとだとplot波形がギザギザの見た目になってしまい正しく表示されません。)
バッファのサイズを大きくしていくと倍音のない純粋なサイン波が聞こえるようになります。そのサイズが適正なサイズかなと思います。
サイン波は倍音のないピュアな波形ですが、倍音を多く含むほど大きなサイズを設定しておくと安心、という感じではないしょうか。適正かどうか確かめるにはサイズの上げ下げで音質変化を観察するのがいいようです。
round()
ところでSignal.sineFill()で作った波形に、
「15.ひとつの波形からバリエーションを作る」で紹介しているメソッドを使うこともできます。
// cubedを使ってみた例
(
~bfs1 = Buffer.alloc(s, 2048);
~sig1 = Signal.sineFill(1024, [1, 0.5, 0.3, 0.25, 0.2]).cubed;
~wt1 = ~sig1.asWavetable;
~bfs1.loadCollection(~wt1);
)
fold2()やclip()なども面白く音色変化してくれるので「15.ひとつの波形からバリエーションを作る」のメソッドを色々と試してみたのですが、round()だけは音が出ませんでした。
エラーになるわけではないけど音になって出て来ないんです。
round()は数値を四捨五入することでsineFillの値をあえてスムーズではなくして音色変化を生みますが、それとasWavetableがうまく機能しないのかなと思います(個人的な予想)。
round()することで数値が非連続になってしまうので、それを正しく補完することができない・・・とか?
なので強引にround()した波形を使うなら、asWavetableの行をコメントアウトすると音が出るようにはなります。
(
~bfs1 = Buffer.alloc(s, 2048);
~sig1 = Signal.sineFill(1024, [1, 0.5, 0.3, 0.25, 0.2]).round(0.1);
// ~wt1 = ~sig1.asWavetable;
~bfs1.loadCollection(~wt1);
)
ただ前述したようにWavetable化していない波形なので音はエイリアスノイズを含むガビガビなものになります。(これはこれでカッコよく使ってもいいな、と。)
sine1()
実はBufferクラスにsine1()というメソッドが用意されていて、Signal.sineFill()と同じ機能をします。
(
~bfs2 = Buffer.alloc(s, 2048);
~bfs2.sine1([1, 1/2, 1/4, 1/8, 1/12, 1/16], asWavetable:true);
)
これでバッファに入ったので~bfs2をOSCに入れてシーケンスすれば鳴ってくれます。バッファにそのまま放り込むことができるので、コードがシンプルですね。
(
//Bus
~rvbBus = Bus.audio(s, 2);
SynthDef(\sinf, {
arg freq=220, gate=1;
var env, sig;
env = EnvGen.kr(Env.asr(0.001, 1, 0.05), gate, doneAction:2);
sig = Osc.ar(~bfs2.bufnum, freq, 0, 0.3);
Out.ar(~rvbBus, sig!2 * env);
}).add;
//reverb
SynthDef(\rvb, {
var eff, in;
in = In.ar(~rvbBus, 2);
eff = FreeVerb2.ar(in[0], in[1], 0.2, 0.8, 0.5);
Out.ar(0, eff);
}).add;
//Pbind
~pb1 = Pbind.new(
\instrument, \sinf,
\midinote, Pseq([60, 72, 55, 67, 65, 60, 55, 58], inf),
\dur, 0.5,
\sustain, 0.1);
Pfx(~pb1, \rvb).play(TempoClock(110/60));
)
(ここから下で例に出しているコードのバッファ(~bfs2)は、すべてこの↑シーケンスで鳴らすことができます。)
sine1()の各引数の意味は、
~bfs2.sine1([各倍音の音量(0〜1)], asWavetable:ウェーブテーブル化する/しない、のtrue/false);
です。
[各倍音の音量(0〜1)]については先ほどの例では第6倍音まで書き込んでますが、好きな数だけ書き込むことができます。
asWavetableは、たいていの場合trueでOKだと思いますが、Signal.sineFill()と同じく、plotするときはfalseにしてあげないとギザギザの見た目になってしまいます。
(
~bfs2 = Buffer.alloc(s, 2048);
~bfs2.sine1([1, 1/2, 1/4, 1/8, 1/12, 1/16], asWavetable:false);
~bfs2.plot;
)
sine2()
さてsine2()というメソッドもありまして、こちらにはちょっと便利なパラメータ(引数)が用意されてます。
~bfs2.sine2([サイン波をバッファ内で何サイクルさせるか], [各倍音の音量(0〜1)], asWavetable:ウェーブテーブル化する/しない、のtrue/false);
バッファ内で何サイクル?は、ちょっと伝わりづらいかもしれませんが、
1だと1周期(デフォルト)
2だと2周期(オクターブ上)
つまり下記のように一番左に1と書けば、2,3,4,5,6はその2倍音,3倍音,4倍音,5倍音,6倍音と捉えることができます。
(
~bfs2 = Buffer.alloc(s, 2048);
~bfs2.sine2([1, 2, 3, 4, 5, 6], [1, 1/2, 1/4, 1/8, 1/12, 1/16], asWavetable:true);
)
こんな感じに。
ここで便利なのが、奇数倍音だけ足す、とかが簡単にできることです。
(
~bfs2 = Buffer.alloc(s, 2048);
~bfs2.sine2([1, 3, 5, 7, 9, 11], [1, 1/2, 1/4, 1/8, 1/12, 1/16], asWavetable:true);
)
奇数にこだわらなくてもいいので、FM音源のシミュレートをしたり色々自由に遊べます。
(
~bfs2 = Buffer.alloc(s, 2048);
~bfs2.sine2([1, 4, 6, 10, 12, 16, 18], [1, 1/4, 1/2, 1/8, 1/4, 1/16, 1/8], asWavetable:true);
)
ただ、ふたつの[角カッコ]内の数字の個数は一致してないといけないというルールがあり、一致していないとエラーになります。[サイクルの個数が例えば6個]なら[音量の個数も6個]書く、ということです。
さらに、倍音の指定は整数でなくてもよい、という面白さ。
(
~bfs2 = Buffer.alloc(s, 2048);
~bfs2.sine2([1.25, 4.15, 6.25, 10.15, 12.25, 16.15, 18.25], [1, 1/4, 1/2, 1/8, 1/4, 1/16, 1/8], asWavetable:true);
)
(ちょっと細かいこと。
説明のために ”倍音” と書きましたが、正確には ”バッファ内で何サイクルさせるか” なので「1.25サイクル」としておくと、サイン波1.25サイクルをひとつのバッファに放り込み ”それを1サイクルとしてオシレートする” ので、1と指定したときと1.25と指定したときと音程が変わることはありません。あくまでも倍音構造が変化する。。うまく伝わってますでしょうか。でもあまり気にせず数字をいろいろと入れてみて楽しむのがいいです。)
![画像2](https://assets.st-note.com/production/uploads/images/85209481/picture_pc_a99e0b4841a0b9c1306306a86f96327b.png)
Buffer.alloc(s, 2048).sine2([1.25], [1], asWavetable:false).plot;
サイン波1.25周期分を1サイクルとしてオシレートする。
![画像3](https://assets.st-note.com/production/uploads/images/85209883/picture_pc_13141b658a02bdaf3c0cb84c7bd54bee.png)
Buffer.alloc(s, 2048).sine2([1], [1], asWavetable:false).plot;
普通のサイン波1周期分はこちら。
さらにさらに、clearFirstというパラメータ(引数)が用意されていて。
これは「指定した数のサイン波をバッファに入れるときに、まずバッファ内をクリアするかしないか(true/false)」というパラメータです。普通「するでしょ」と考えてしまうんですが(なのでデフォルトだとtrueになっていて何も書かなければtrueです)、でもクリアしない設定にすると「直前にバッファに入れた音色にプラスする形で次の音色を入れる」ことになり、つまり加算合成が可能になります。
(
~bfs2 = Buffer.alloc(s, 2048);
~bfs2.sine2([1], [1], asWavetable:true, clearFirst:true);
~bfs2.sine2([1.25], [0.2], asWavetable:true, clearFirst:false);
)
上のコードの、sine2([1], [1], をバッファに入れるときはバッファ内をクリアしています(clearFirst:true)。
次にsine2([1.25], [0.2], はクリアしないまま(clearFirst:false)バッファに入れています。
このようにすることで、[1]のサイン波に[1.25]のサイン波を少しだけ([0.2]の音量だけ)加算している状態で音が出ます。
clearFirst はsine1()にもあるんですが、sine1()だと倍音指定ができないので加算合成の利点があまり無いと思うんですよね。。足したければ元々の引数に設定すればいいので。。何かいい使い道をパッと思いついた方、教えてください〜。実験してみたいです。
<目次へ>
https://note.com/sc3/n/nb08177c4c011