GLSL作曲入門

# 自己紹介
![128.png](https://qiita-image-store.s3.amazonaws.com/0/52576/cbd5d390-b236-1b5c-cc4e-0f6141774b06.png)

- 名前: notargs

# 作ったもの
- LGTM Shaders

![LGTM](https://github.com/notargs/LGTM-Shaders/raw/master/Shader010.gif) 

- CRT Shader

![CRT](http://wordpress.notargs.com/blog/wp-content/uploads/2016/01/%E7%84%A1%E9%A1%8C.gif)

---

# 今回話す内容

---

?「Game Jamでプログラマーのみのチームになってしまった…」

---

?「Game Jamでプログラマーのみのチームになってしまった…」
?「音楽素材どうしよう…」

---

?「Game Jamでプログラマーのみのチームになってしまった…」
?「音楽素材どうしよう…」

**@「それ、シェーダーで作れますよ！！」**

---

# メリット
- プログラマーだけで楽曲制作が完結できる
- OpenGLとPCMにさえ対応していれば動くため、移植性が高い
- プロシージャルなので圧縮率が高い

--- 

# デメリット
- 高度な知識と実装力が必要
- **めんどくさい**

---

# 手法

---

##Transform Feedback
- 頂点シェーダでの計算結果を頂点バッファオブジェクトに再度格納する機能
- CPUからアクセス可能

---

##Transform Feedback
- 頂点シェーダでの計算結果を頂点バッファオブジェクトに再度格納する機能
- CPUからアクセス可能
- **GPGPUできる！！**

---

## シェーダーの中身

- `gl_vertexID`を元に、そのタイミングでの波形を返す関数
- 戻り値はステレオに対応した`vec2型`

```glsl
void main() 
{
    float time = gl_VertexID / 44100.0;
    out_sample = mainSound(time) * 0.5;
}
```

---

## 再生処理
waveOutOpenとかで適当に流す

```C++
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));
```

---

# 音階と周波数

---
![SnapCrab_NoName_2017-1-25_11-20-6_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/52576/ab906506-145d-cbba-0e8b-0e1e99b2c0b3.png)

- みんな大好きsinカーブ
- 濁りの無い音

---

![SnapCrab_NoName_2017-1-24_5-8-6_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/52576/ca83b263-ba23-54e9-7765-9f8b25a5900c.png)
- 横幅が周波数（音の高さ）で、1秒間の振幅数、hz（ヘルツ）で表す
- 縦幅が音量に対応している

---
![SnapCrab_NoName_2017-1-25_11-17-52_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/52576/11d3eb88-04cb-f898-8d92-793d60193719.png)
- 間隔が狭ければ高い音に

---
![SnapCrab_NoName_2017-1-25_11-19-21_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/52576/d933fcfc-1753-0538-58c0-c4fa98b88d9f.png)

- 間隔が大きければ低い音になります

---
# 音階の計算方法
- ラ（A）の音が440hz
- 周波数が二倍になると、音階が1オクターブ上がる
- 1オクターブは12音なので、下記の式で特定の音についての周波数が計算できる

```glsl
float calcHertz(float scale)
{
    return 440.0 * pow(2.0, scale / 12.0);
}
```

---
# バスドラムの音を作る
- 低音でちょっとずつ音量を下げていく
- 音量とともに周波数も下げても面白い

![SnapCrab_NoName_2017-1-25_14-4-45_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/52576/c93c83ad-7b28-1376-4003-572f2823066e.png)


---

# ハイハット

- 一瞬だけ乱数を鳴らしてフェードアウトさせる

![SnapCrab_NoName_2017-1-25_14-12-51_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/52576/1ea3bd4e-1f93-860b-38d4-3c9860fd25f9.png)

---

# 矩形波
- サインカーブと比べると少しトゲのある音

![SnapCrab_NoName_2017-1-25_14-16-7_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/52576/9ba7e174-4794-9fd2-fc32-2e685a319be0.png)

---

# ストリングス（和音）
- 複数の音を鳴らすには単純に足し算すればいい
- 下の例文はAm7のコードを鳴らすコード

```glsl
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)
```

---

# ストリングス（和音）
- グラフで見るとこんな感じ
![SnapCrab_NoName_2017-1-25_14-23-59_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/52576/fb0f1dd3-78a2-5ba3-d05d-2e108a7ef3f6.png)

---

# ミキシング
- それぞれの音を関数として定義
- main直下で足し算することでミキシング
- 0.5などの数値を掛け算してボリュームを変更
- vec2を掛けることでパン（音の低位）を振る

```glsl
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);
}
```

---

# 最終的な曲のグラフ
![SnapCrab_NoName_2017-1-25_14-27-2_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/52576/6ecfdec6-c9ca-5721-5720-a544eadd653d.png)

---

# 実演
https://www.shadertoy.com/view/4l3GD2
*※ このサンプルで使っているShaderToyではTransform Feedbackを使っていません*