自己紹介
- 名前: notargs
作ったもの
- LGTM Shaders
- CRT Shader
今回話す内容
?「Game Jamでプログラマーのみのチームになってしまった…」
?「Game Jamでプログラマーのみのチームになってしまった…」
?「音楽素材どうしよう…」
?「Game Jamでプログラマーのみのチームになってしまった…」
?「音楽素材どうしよう…」
@「それ、シェーダーで作れますよ!!」
メリット
- プログラマーだけで楽曲制作が完結できる
- OpenGLとPCMにさえ対応していれば動くため、移植性が高い
- プロシージャルなので圧縮率が高い
デメリット
- 高度な知識と実装力が必要
- めんどくさい
手法
Transform Feedback
- 頂点シェーダでの計算結果を頂点バッファオブジェクトに再度格納する機能
- CPUからアクセス可能
Transform Feedback
- 頂点シェーダでの計算結果を頂点バッファオブジェクトに再度格納する機能
- CPUからアクセス可能
- GPGPUできる!!
シェーダーの中身
-
gl_vertexID
を元に、そのタイミングでの波形を返す関数 - 戻り値はステレオに対応した
vec2型
void main()
{
float time = gl_VertexID / 44100.0;
out_sample = mainSound(time) * 0.5;
}
再生処理
waveOutOpenとかで適当に流す
waveOutOpen(&h_wave_out, WAVE_MAPPER, &wave_format, reinterpret_cast<DWORD_PTR>(hWnd), 0, CALLBACK_WINDOW);
waveOutPrepareHeader(h_wave_out, &wave_hdr, sizeof(wave_hdr));
waveOutWrite(h_wave_out, &wave_hdr, sizeof(wave_hdr));
音階と周波数
- みんな大好きsinカーブ
- 濁りの無い音
- 横幅が周波数(音の高さ)で、1秒間の振幅数、hz(ヘルツ)で表す
- 縦幅が音量に対応している
- 間隔が大きければ低い音になります
音階の計算方法
- ラ(A)の音が440hz
- 周波数が二倍になると、音階が1オクターブ上がる
- 1オクターブは12音なので、下記の式で特定の音についての周波数が計算できる
float calcHertz(float scale)
{
return 440.0 * pow(2.0, scale / 12.0);
}
バスドラムの音を作る
- 低音でちょっとずつ音量を下げていく
- 音量とともに周波数も下げても面白い
ハイハット
- 一瞬だけ乱数を鳴らしてフェードアウトさせる
矩形波
- サインカーブと比べると少しトゲのある音
ストリングス(和音)
- 複数の音を鳴らすには単純に足し算すればいい
- 下の例文はAm7のコードを鳴らすコード
sound += rect(time * calcHertz(24.0)); // ラ(A)
sound += rect(time * calcHertz(28.0)); // ド(C)
sound += rect(time * calcHertz(31.0)); // ミ(E)
sound += rect(time * calcHertz(35.0)); // ソ(G)
ストリングス(和音)
ミキシング
- それぞれの音を関数として定義
- main直下で足し算することでミキシング
- 0.5などの数値を掛け算してボリュームを変更
- vec2を掛けることでパン(音の低位)を振る
vec2 mainSound(float time)
{
float sound = 0.0;
sound += bassDrum(time) * 0.5;
sound += snereDrum(time) * 0.5;
sound += hiHat(time) * 0.5;
sound += strings(time) * 0.2;
sound += bass(time) * 0.2;
if (abs(sound) > 1.0) sound /= abs(sound);
return vec2(sound);
}
最終的な曲のグラフ
実演
https://www.shadertoy.com/view/4l3GD2
※ このサンプルで使っているShaderToyではTransform Feedbackを使っていません