Javascriptで作曲できる！（OngaqJS）

この記事は　[ZOZOテクノロジーズ #2 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/zozo_tech2)  1２日目の記事になります。

昨日の記事は @satto_sann の 「[WSL2 + Ubuntu18.04 + Docker環境構築](https://qiita.com/satto_sann/items/b4f332cd76b48659f11e)」です。


# はじめに
今年ももう終わり...
そういえば１曲も作ってない！という焦燥感と、Adventカレンダーを書かなければいけない！という焦燥感を
同時に解消してくれるJavaScriptライブラリがありました。

＼ OngaqJS ／
https://www.ongaqjs.com/

# まずは完成品から
https://soundcloud.com/cnbjpn/qiita
＊音色は全てフリープランのものです。
＊２小節のループを内部録音してからDAWでフェードアウトつけてます。

# 使い方
<a href="https://www.ongaqjs.com/tutorial/">チュートリアル</a>と<a href="https://www.ongaqjs.com/api/">ドキュメント</a>がわかりやすかったので、
触りながら読み進めると良い感じです。

 1.鳴らす楽器を決めて

```js
const my_piano = new Part ({
	sound: "jazz_guitar"
})
```

 2.鳴らすキー、タイミングや音量を決めて

```js
my_piano.add( new Filter({
    key: ["D3","F3#","B4"],
    length: 6,
    measure: 1,
    volume: 40,
    active: (b,m) => b === 4 && m === 0|| b === 10 && m === 0|| b === 0 && m === 1
}))
```

 3.鳴らす

```js
ongaq.add(my_piano)
```


以下の部分は、

```.js
    key: ["D3","F3#","B4"],
    active: (b,m) => b === 4 && m === 0|| b === 10 && m === 0|| b === 0 && m === 1
```


ピアノロールにすると以下の譜面になります。
![qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266693/79c9cac2-1465-ae01-842a-9f710e12bdf6.png)

# 所感
チュートリアルも分かりやすく、意図したタイミングで音を鳴らせた瞬間が快感だったので興味ある方はぜひ触ってみてください！
今回は音を鳴らすまで試してみましたが、リファクタリングも楽しくできそうです。
MIDIの軽さを利用して、LPサイトなどへの仕掛けとして利用できれば面白そうですね。



# 今回の曲のサンプルコード

```js
const ongaq = new Ongaq ({
	api_key: "***",
	volume: 100,
	bpm: 120,
	onReady: ()=>{

		const button = document.getElementById("button")
		button.className = "button start"
		button.onclick = () => {
			if (ongaq.params.isPlaying) {
				ongaq.pause()
				button.className = "button start"
			} else {
				ongaq.start()
				button.className = "button pause"
			}
		}
	}
})


//ドラムパート
const my_drums = new Part ({
    sound: "small_cube_drums"
})

my_drums.add( new Filter ({
    key: "kick",
    volume: 60,
	active: beat => beat % 8 === 0
}))

my_drums.add( new Filter({
    key: ["hihat"],
    volume: 50,
    active: n => n % 8 === 4
}))

my_drums.add( new Filter({
    key: ["snare"],
    volume: 40,
    active: n => n % 16 === 8
}))

my_drums.add( new Filter({
    key: ["tom2"],
    volume: 30,
    active: (n,m) => n % 16 === 2 && m % 2 === 0 || n % 16 === 6 && m % 2 === 0
}))


//メインパート
const my_piano = new Part ({
	sound: "jazz_guitar"
})

my_piano.add( new Filter({
    key: ["D2","D3","F3#","B4","D4"],
    length: 6,
    measure: 1,
    volume: 50,
    active: (b,m) => b === 4 && m === 0|| b === 10 && m === 0|| b === 0 && m === 1
}))

my_piano.add( new Filter({
    key: ["D2","D3","F3#","C4"],
    length: 5,
    measure: 1,
    volume: 48,
    active: (b,m) => b === 6 && m === 1|| b === 12 && m === 1
}))


my_piano.add( new Filter({
    key: ["C2","C3","E3","A4"],
    length: 6,
    measure: 3,
    volume: 50,
    active: (b,m) => b === 4 && m === 2|| b === 10 && m === 2|| b === 0 && m === 3 || b === 12 && m === 3
}))

my_piano.add( new Filter({
    key: ["C2","C3","E3","G4"],
    length: 5,
    measure: 3,
    volume: 40,
    active: (b,m) => b === 6 && m === 3
}))

const my_route = new Part({
    sound: "plain_keyboard"
})

my_route.add( new Filter({
    key: "G1",
    length: 4,
    measure: 3,
    volume: 30,
    active: (b,m) => b === 0 && m === 0 || b === 8 && m === 0 || b === 14 && m === 0
}))

const my_hit = new Part({
    sound: "violin"
})

my_hit.add( new Filter({
    key: ["D3","F3#","B4","D4"],
    length: 6,
    measure: 3,
    volume: 5,
    pan: 10,
	active: (b,m) => b % 8 === 0 && m <= 1
}) )

my_hit.add( new Filter({
    key: ["C3","E3","A4"],
    length: 6,
    measure: 3,
    volume: 5,
	active: (b,m) => b % 8 === 0 && m >= 2
}) )


my_hit.add( new Filter({
    type: "pan",
    x: 10
}))


const my_strings = new Part({
    sound: "poly_synth"
})

my_strings.add( new Filter({
    key: ["F3#","B4"],
    length: 32,
    measure: 5,
    volume: 2,
    active: (b,m) => b === 0 && m === 0
}))

my_strings.add( new Filter({
    key: ["E3","A4"],
    length: 32,
    measure: 5,
    volume: 2,
    active: (b,m) => b === 0 && m === 2
}))

my_strings.add( new Filter({
    type: "pan",
    x: -10
}))


//ベース
const my_monobass = new Part({
    sound: "mono_bass"
})

my_monobass.add( new Filter({
    key: "G1",
    length: 4,
    measure: 3,
    volume: 30,
	active: (beat,m) => beat % 8 === 4 && m <= 1
}))

my_monobass.add( new Filter({
    key: "F1",
    length: 4,
    measure: 3,
    volume: 30,
	active: (beat,m) => beat % 8 === 4 && m >= 2
}))


//音楽再生
ongaq.add(my_drums)
ongaq.add(my_piano)
ongaq.add(my_strings)
ongaq.add(my_hit)
ongaq.add(my_route)
ongaq.add(my_monobass)

```