Polyphonic.js (2277B)
1 import consts from './consts.js'; 2 import Envelope from 'envelope-generator'; 3 4 export default class Polyphonic { 5 constructor(audioContext) { 6 const masterVol = audioContext.createGain(); 7 masterVol.gain.value = 0.7; 8 masterVol.connect(audioContext.destination); 9 this.voices = {}; 10 this.audioContext = audioContext; 11 this.periodicWave = null; 12 this.masterVolume = masterVol; 13 } 14 setVolume(newVol) { 15 this.masterVolume.gain.value = newVol; 16 } 17 addVoice(note, adsr) { 18 this.voices[note.note] = this.voices[note.note] || []; 19 20 let osc = this.audioContext.createOscillator(); 21 let gain = this.audioContext.createGain(); 22 let envelope = new Envelope(this.audioContext, { 23 attackTime: adsr.attack, 24 decayTime: adsr.decay, 25 sustainLevel: adsr.sustain, 26 releaseTime: adsr.release, 27 maxLevel: 0.4 28 }); 29 30 osc.frequency.value = note.frequency; 31 gain.gain.setValueAtTime(0, 0) 32 if (this.periodicWave) { 33 osc.setPeriodicWave(this.periodicWave); 34 } 35 36 envelope.connect(gain.gain); 37 osc.connect(gain); 38 gain.connect(this.masterVolume); 39 40 osc.start(); 41 envelope.start(this.audioContext.currentTime - 0.1); 42 43 this.voices[note.note].push({ 44 note, 45 osc, 46 gain, 47 envelope 48 }); 49 } 50 removeVoice(note) { 51 const voiceList = this.voices[note.note]; 52 const voice = voiceList[voiceList.length - 1]; 53 voice.envelope.release(this.audioContext.currentTime); 54 voice.osc.stop(voice.envelope.getReleaseCompleteTime()); 55 setTimeout(() => { 56 voice.gain.disconnect(); 57 voiceList.splice(voiceList.indexOf(voice), 1); 58 }, 1000 * (voice.envelope.getReleaseCompleteTime() - this.audioContext.currentTime)); 59 } 60 changeWave(waveform) { 61 if (waveform !== this.periodicWave) { 62 this.periodicWave = waveform; 63 for (let noteVoices in this.voices) { 64 for (let voice of this.voices[noteVoices]) { 65 voice.osc.setPeriodicWave(this.periodicWave); 66 } 67 } 68 } 69 } 70 }