LoginSignup
3
1

More than 5 years have passed since last update.

GPUSound入門(4) ドラムの作成、複数の音を鳴らす

Last updated at Posted at 2018-12-09

シリーズ

GPUSound入門
https://qiita.com/MachiaWorx/items/68f8691d0866e0e0ff68

GPUSound入門(2)
https://qiita.com/MachiaWorx/items/75c63dff12b4a6189a35

GPUSound入門(3)
https://qiita.com/MachiaWorx/items/43bc7868e9fc770b52f4

ドラムの音

シンセサイザー部分の次はドラムを作ることにします。

作り方はいくつかありますが、今回はノイズだけで作ることにします。

ノイズってどうやって出すの

まず再現性を高めるためのソースコードがある模様。

SampleCode_noise
float random (vec2 st) {
    return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123);
}

・・・なんですけどこのコードだと上から下まで均等に音が出るとはならない上に、フィルタの実装が難しい状態で何個もノイズ使うと同じ周波数というかノイズが純増になり、あっさり音割れしたりピークを超えて、音が聞こえないケースが出てきます。
(ってかありました)
あと別のノイズ使うにも引数になるvec2の値をどうするかで悩むケースが多々あります。

ということで自分は上記コードを一部使いつつも、別アプローチとして「基本波形を加工して、それをノイズとみなす」ことで対応してます。

SampleCode_crash
vec2 mainSound( float time )
{
    // A 440 Hz wave that attenuates quickly overt time
    return vec2( sin(6.2831*440.*time*sin(time*8000.))*exp(-3.0*time) );
}

この仕組は、基本波形を低周波数でFM変調させて鳴らしてます。
2種類振動を用いることで波形を複雑にしてる感じですね。
1秒あたり44100個のデータをプロットする関係上細かく振動させるとただのノイズになってしまうという考えから、振動を細かくしちゃいました。

この考えを使って実装していくと、周波数を変更することでノイズの種類をいくつか変更でき、なおかつ音の粒も比較的揃っているので耳にも優しい。

サイン波とかいくつかのオシレータ使ったんですがのこぎり波が今の所加工しやすいということで、デモではのこぎり波をFM変調させてます。
(今回乗っけたソースは実装の手間考えてサイン波にしてます)

また、新たに出てきたmax関数ですが何を実装してるかというと、減衰です。
すなわち前回とかで説明したexp関数でもOKです。
簡単に言うと、音量の最大値を取ってそれを反映させてます。

exp関数は弧を描くような減衰になるので、そうじゃない直線的な減衰・二次関数的な減衰等やりたいことによって種類を変えてくのが良いと思います。

直線:max関数
弧:exp関数

みたいな感じで。

あとドラムって何が必要だっけ

必要そうなのを列挙します。

  • バスドラム・・・低音を刻む
  • スネア・・・中~高音域を刻む、フィルイン等
  • ハイハット・・・高音域を刻む
  • タム・・・低~中音域を刻む、音階を持つケースがある(シモンズドラムとか)

必要に応じて作ってしまうのでいいと思います。

他に必要なものは・・・和音

これで楽器は揃ったんですが・・・

・・・はて、他の楽曲聞くと・・・一度にいっぱい音が鳴ってますね。
これは単純な話です。例えばベースとピアノが同時に鳴っていたら、その分同時に振動しているんですね。

ということで、前回の結果と今回の結果を同時に発音してみましょう。
ついでにサイン波は和音で鳴らしてみます。(適当に値を入れたので平均律に準拠した和音ではないですがご了承ください)

あと、まだ書くネタはあるので、先出し要素として左右、もしくはトータルの音量も調整してみました。
結局のところ吐き出すwavは2ch想定なので、今のデータの並びだったらvec2で調整できちゃうんですね。

SampleCode_total
vec2 mainSound( float time )
{
    // 和音とドラムのサンプル

    //クラッシュシンバルの音
    vec2 result = vec2( sin(6.2831*440.0*time*sin(time*20000.))*exp(-6.0*time) ) * vec2(1.0,0.2);

    //和音
    result += vec2( sin(6.2831*440.0*time)) * exp(-3.0*time);
    result += vec2( sin(6.2831*530.0*time)) * exp(-2.0*time) * vec2(0.5,0.7);
    result += vec2( sin(6.2831*670.0*time)) * exp(-2.0*time) * vec2(0.2,0.8);
    return result*0.8;
}

はい、これで複数の音が鳴りました。
上記みたいな記述をいっぱい積み重ねれば、曲ができてしまうんですね。

もちろんそんなまどろっこしいことを推奨しているわけではないですし、もっとコンパクトに書く方法はいたるところに転がってます。

次回以降

次回以降、応用というか自分が知っている範囲で実装できそうなシーケンス・音色・エフェクト等を記載してこうかと思います。

今回のデモ(a Stranger)で実装した要素やTDF後整理した実装等、
書くことはいくつかある(すでにリストアップした)ので、
これらを書いていく予定としておきます。

あと、実際のデモへの組み込みのソースコードとかも公開準備中です。
これでGPUSound使った提出作品が増えるといいなー。

3
1
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1