Synth Class の設計図
Web Audio API の基本的な使い方がわかりましたので、ここからは本格的にシンセサイザーを作っていきます。まずは、鍵盤部分や MIDI Keyboard の入力の処理等を除いた、純粋に音を鳴らす目的だけを達成するための Synth Class を作ります。

Synth Class の全体図

Synth Class から生成されたインスタンスには、play と stop というメソッドがあり、このメソッドに対して、MIDI Note Number を渡すことで、音がなったり、停止したりします。
次のコードはイメージです。
index.js
1
import Synth from '/src/Synth'
2
3
// インスタンスを作成する際に波形の種類、設定などを渡す
4
const settings = 'someSettings'
5
const synth = new Synth(settings)
6
7
const options1 = {
8
midiNoteNumber: 70,
9
}
10
// .play に midiNote を渡すと再生する
11
const result1 = synth.play(options1)
12
13
console.log({ result1 })
14
15
const options2 = {
16
midiNoteNumber: 70,
17
}
18
// .stop に midiNote を渡すと停止する
19
const result2 = synth.stop(options2)
20
21
console.log({ result2 })
22
Copied!
Synth.js
1
class Synth {
2
constructor(settings) {
3
// 各種設定を持つ
4
// 波形等々
5
this.settings = settings
6
}
7
8
// midiNoteNumber を受け取って再生する
9
play({ midiNoteNumber }) {
10
return `play ${midiNoteNumber}`
11
}
12
13
// midiNoteNumber を受け取って停止する
14
stop({ midiNoteNumber }) {
15
return `stop ${midiNoteNumber}`
16
}
17
}
18
19
export default Synth
20
Copied!

.play(), .stop() 設計図

具体的に synth.play() , synth.stop() メソッドについて考えていきます。
ポイントは this.oscillatorArray の存在です。この配列は、最初は 128 の長さを持つ、中身が空の配列ですが、オシレータが再生された際には、対応する index へとオシレーターが保存されます。例えば MIDI Note Number 70 をオシレーターが再生された場合には、そのオシレーターは this.oscillatorArray[70] の中に保存されます。そして、MIDI Note Number 70 を停止する場合には、 this.oscillatorArray[70] に入っているオシレーターに .stop() すれば良いわけです。
また、再生中ではないオシレーターを止めようとした場合には、特に何もしません。再生中かどうかは、配列にオシレーターが存在するか存在しないかで判定します。
Synth.js
1
class Synth {
2
constructor(settings) {
3
this.settings = settings
4
this.destination = 'destination'
5
// この配列に再生中のオシレーターが、
6
// index = midiNoteNumber の場所に保存される
7
// midiNote 60 を再生するオシレーターは
8
// this.oscillatorArray[60] に保存される
9
this.oscillatorArray = Array.from({ length: 128 })
10
11
// this.oscillatorArray が何個あるか確認
12
console.log(this.oscillatorArray.map((o, index) => index))
13
}
14
15
// midiNoteNumber からその周波数を再生する
16
// オシレーターを作成する
17
createOscillator({ midiNoteNumber, wave }) {
18
return `oscilator with ${midiNoteNumber}, ${wave}`
19
}
20
21
// midiNoteNumber を受け取って再生する
22
play({ midiNoteNumber }) {
23
const wave = 'sine'
24
const oscillator = this.createOscillator({ midiNoteNumber, wave })
25
// connect と play をする
26
// oscillator.connect(this.destination)
27
// oscillator.play()
28
29
// oscillator を配列に保存する
30
this.oscillatorArray[midiNoteNumber] = oscillator
31
// 中身確認
32
console.log(this.oscillatorArray)
33
return `play ${midiNoteNumber}`
34
}
35
36
// midiNoteNumber を受け取って停止する
37
stop({ midiNoteNumber }) {
38
// midiNoteNumber に対応する index に
39
// 再生中のオシレーターがあるか確認する
40
const targetOscillator = this.oscillatorArray[midiNoteNumber]
41
if (!targetOscillator) {
42
// ないときは停止すべき対象がないので
43
// 特に何もしない
44
return `not ${midiNoteNumber} playing`
45
}
46
47
// 対象がある場合は止める
48
//targetOscillator.stop()
49
50
// 本来であれば、止めるだけで配列が空になるが、
51
// ダミーのコードなので、そこに目印を入れることにする
52
this.oscillatorArray[midiNoteNumber] = `stop ${midiNoteNumber}`
53
// 中身確認
54
console.log(this.oscillatorArray)
55
return `stop ${midiNoteNumber}`
56
}
57
}
58
59
export default Synth
60
Copied!
index.js
1
import Synth from '/src/Synth'
2
3
// インスタンスを作成する際に波形の種類、設定などを渡す
4
const settings = 'someSettings'
5
const synth = new Synth(settings)
6
7
const options1 = {
8
midiNoteNumber: 70,
9
}
10
// .play に midiNote を渡すと再生する
11
const result1 = synth.play(options1)
12
13
console.log({ result1 })
14
15
const options2 = {
16
midiNoteNumber: 70,
17
}
18
// .stop に midiNote を渡すと停止する
19
const result2 = synth.stop(options2)
20
21
console.log({ result2 })
22
23
const options3 = {
24
midiNoteNumber: 100,
25
}
26
// .stop に再生していない midiNote を渡すと
27
// 特に何もしない
28
const result3 = synth.stop(options3)
29
30
console.log({ result2 })
Copied!

設計図まとめ

以下の画像は上記コードの実行時のコンソール画面の内容ですが、次のことがわかります。(CodeSandbox 側ではなく Chrome でご確認ください)
    this.oscillatorArray は index: 0~127, length: 128 の空の配列
    synth.play({midiNoteNumber: 70}) をすると、 再生中のオシレータが、対応する index に保存される
    synth.stop({midiNoteNumber: 70}) をすると、 対応する index に保存されている再生中のオシレーターを停止させる。
では次の章から実装していきましょう。
Last modified 3yr ago