この記事は ZOZOテクノロジーズ #2 Advent Calendar 2020 12日目の記事になります。
昨日の記事は @satto_sann の 「WSL2 + Ubuntu18.04 + Docker環境構築」です。
はじめに
今年ももう終わり...
そういえば1曲も作ってない!という焦燥感と、Adventカレンダーを書かなければいけない!という焦燥感を
同時に解消してくれるJavaScriptライブラリがありました。
\ OngaqJS /
https://www.ongaqjs.com/
まずは完成品から
https://soundcloud.com/cnbjpn/qiita
*音色は全てフリープランのものです。
*2小節のループを内部録音してからDAWでフェードアウトつけてます。
使い方
チュートリアルとドキュメントがわかりやすかったので、
触りながら読み進めると良い感じです。
1.鳴らす楽器を決めて
const my_piano = new Part ({
sound: "jazz_guitar"
})
2.鳴らすキー、タイミングや音量を決めて
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.鳴らす
ongaq.add(my_piano)
以下の部分は、
key: ["D3","F3#","B4"],
active: (b,m) => b === 4 && m === 0|| b === 10 && m === 0|| b === 0 && m === 1
所感
チュートリアルも分かりやすく、意図したタイミングで音を鳴らせた瞬間が快感だったので興味ある方はぜひ触ってみてください!
今回は音を鳴らすまで試してみましたが、リファクタリングも楽しくできそうです。
MIDIの軽さを利用して、LPサイトなどへの仕掛けとして利用できれば面白そうですね。
今回の曲のサンプルコード
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)