シリーズ
GPUSound入門
https://qiita.com/MachiaWorx/items/68f8691d0866e0e0ff68
GPUSound入門(2)
https://qiita.com/MachiaWorx/items/75c63dff12b4a6189a35
音量変更(Amp/エンベロープ)
vec2 mainSound( float time )
{
// A 440 Hz wave that attenuates quickly overt time
return vec2( sin(6.2831*440.0*time)*exp(-3.0*time) );
}
前回時点でサイン波の出力は可能になりました。
ここに発音後、持続時や出始めの音量の推移をもってより楽器っぽく音が鳴ります。
ということでコントロール方法をいくつか記載してみます。
まずは前回出てきたexp関数の役割について書いていきます。
exp関数は、いわゆる「e^x」のことですね。
対数グラフはいい資料があったのでこっちを御覧ください。
(Googleさんやってくれるわ)
コレ見て分かるのは、「マイナスの値に行くほど0に収束していく」ということです。
よって、このグラフは工夫することでデータを収束させるのに使うことができるということです。
制御については、「時間が経過するほどこのグラフのマイナス部分に進んでいく」という形にすれば、値は正の値を取りつつ0に近づいていくという形になります。
これは値を減衰させるのにとっても便利です。
あと、x=0のとき、e^x = 1なので、倍数にするのに便利です。(元の数を参照できる)
ということで、これで減衰を表現したのが上記SampleCodeのext関数部分なんですね。
同じ考えで、徐々に音量が上がっていく形にするには「特定の値に収束していく」式を当てはめればいいんです。
今回は面倒なので、そのままexp関数を使いたいと思いますが、無限に値が増加していくため、clamp関数で値の範囲を指定する形にしてみます。
ということでアタック・リリース(ディケイかな?)をゆるくフェードさせたのが下記ソースです。
vec2 mainSound( float time )
{
// A 440 Hz wave that attenuates quickly overt time
return vec2( sin(6.2831*440.0*time)
*clamp(exp(time)-1.,0.0,1.0)
*exp(-time)
);
}
こんな感じで音を作り込んでいけば、シンセサイザーの音はどうにかなりそうです。
のこぎり波
あとサイン波だけじゃ物足りないので、他の波形も作ってみます。
参考資料があったので連携。
http://www.graffathon.fi/2016/presentations/additive_slides.pdf
どちらかと言うとのこぎり波形な感じ。
#define PI 3.14159
float saw(float phase) {
float s = 0.0;
for (int k = 1; k <= 8; k++) {
s += (sin(2.0*PI*float(k)*phase) / float(k));
}
return (1.0/2.0) - (1.0/PI)*s - 0.5;
}
vec2 mainSound( float time )
{
// FM音源
return vec2( saw(time*440.0) *exp(-3.*time) );
}
他には三角波をサイン波だけで作る資料とか。
無限フーリエ級数の式をこっちに書いていく形になります。
もっと計算を単純にしてもいいとは思いますが、まずは正確な式を書いてそっから単純化していくと形を維持しやすいかと思います。
実際矩形とかすげえ簡単に書くことができますしね・・・
FM音源
せっかくなのでオールドロマン溢れるFM音源も実装させてみましょう。
(いやFM8とかで現役なのわかりますけど自分がFM音源と聞いてガレッガとか思い浮かべるので・・・)
FM音源については下記URL参照。
https://ja.wikipedia.org/wiki/FM%E9%9F%B3%E6%BA%90
つまりサイン波を定義する波形の周期を更にサイン波で振動させることで、
音をグワングワン揺らすことが可能になるんですね。
実際のFM音源では更に並列にしたり多重で変調かけたりしますが、
まずはキャリア-モジュレータ1組を作成することにします。
式は、以下の通り。
a * sin( 2PIfatime + b * sin(2PIfbtime) )
a : 振幅
fa: キャリア(基準になる発振器)の周波数
b : 変調指数(適当に決めるヤツ)
fb: モジュレータ(キャリアを揺らす発振器)の周波数
これを少し整えてみると下記のコードになります。
vec2 mainSound( float time )
{
// FM音源
return vec2( sin(6.2831*440.0*time
+4.0* sin(6.2831*220.0*time))
*exp(-3.*time)
);
}
FM音源も理論が分かると結構コンパクトに書くことができてしまいます。
フィードバックとかは別途処理書かなきゃいけないですけど。
終わり
とりあえず音色の説明は最低限これがあれば困らねえだろうというのを書いてみました。
これでベース・メロディ・パッド等書けるかと思います。
あとはドラムとか必要かもしれませんね。
これは別項目で書いてみます。