64 lines
1.6 KiB
JavaScript
64 lines
1.6 KiB
JavaScript
export class Synth {
|
|
// SYNTH VOICE CONSTRUCTOR
|
|
constructor(audio, type, env = {
|
|
a: 0.2,
|
|
r: 0.5,
|
|
}) {
|
|
|
|
this.audio = audio
|
|
this.t = this.audio.currentTime
|
|
|
|
this.env = {
|
|
a: env.a,
|
|
r: env.r,
|
|
}
|
|
|
|
// PRIMARY GAIN
|
|
this.gain = this.audio.createGain()
|
|
this.gain.gain.value = 0
|
|
|
|
// PRIMARY VOICE
|
|
this.primVoice = this.audio.createOscillator()
|
|
this.primVoice.type = typeof type === 'string' ? type : 'sine'
|
|
this.primVoice.connect(this.gain)
|
|
this.primVoice.start()
|
|
|
|
// MOD GAIN
|
|
this.modGain = this.audio.createGain()
|
|
this.modGain.gain.value = 0
|
|
this.modGain.connect(this.gain)
|
|
|
|
// MOD VOICE
|
|
this.modVoice = this.audio.createOscillator()
|
|
this.modVoice.type = 'triangle'
|
|
this.modVoice.connect(this.modGain)
|
|
this.modVoice.start()
|
|
|
|
}
|
|
|
|
// OSC -> ADSR -> GAIN
|
|
noteOn(freq) {
|
|
// note frequency
|
|
this.freq = freq ? freq : (Math.random() * 350) + 150
|
|
this.primVoice.frequency.setValueAtTime(this.freq, this.t)
|
|
this.modVoice.frequency.setValueAtTime(this.freq - 20, this.t)
|
|
// clear preScheduled events
|
|
this.gain.gain.cancelScheduledValues(this.audio.currentTime)
|
|
// attack
|
|
this.gain.gain.setTargetAtTime(0.45, this.t + this.env.a, 0.2)
|
|
}
|
|
|
|
noteOff() {
|
|
// release
|
|
this.gain.gain.setTargetAtTime(0.0, this.t + this.env.r, 1)
|
|
}
|
|
|
|
mod() {
|
|
this.modGain.gain.cancelScheduledValues(this.audio.currentTime)
|
|
// attack
|
|
this.modGain.gain.setTargetAtTime(0.8, this.audio.currentTime, 0.5)
|
|
// release
|
|
this.modGain.gain.setTargetAtTime(0.8, this.audio.currentTime + 0.4, 0.5)
|
|
}
|
|
}
|