import { Note, toCents } from './scale.mjs'; import GuitarFuzz from './vend/guitar-fuzz.mjs'; import Trombone from './vend/trombone.mjs'; const audioCtx = new AudioContext(); const fuzzWave = new PeriodicWave(audioCtx, { real: GuitarFuzz.real, imag: GuitarFuzz.imag }); const tromboneWave = new PeriodicWave(audioCtx, { real: Trombone.real, imag: Trombone.imag }); const globalGain = new GainNode(audioCtx, { gain: 0.06 }) export default class extends HTMLElement { static name = 'x-player' static register() { console.debug('Registering Element', this.name, this); customElements.define(this.name, this); } // oscillatornodes notes = []; getOffsets = () => []; detuneParams = []; constructor() { super(); console.debug('Player#constructor', this); } connectedCallback() { this.querySelector('.volume').onchange = e => { console.debug('vol changed', e, this.volume); globalGain.setValueAtTime(0.1, audioCtx.currentTime); globalGain.value = this.volume; } } get volume() { return Number(this.querySelector('.volume').value); } set volume(volume) { console.debug('Player#volume()', this, volume); this.querySelector('.volume').value = volume; } get isPlaying() { return this.classList.contains('playing'); } // offsets is an array of offsets in cents from A4. get offsets() { console.debug('offsets getoffsets', this.getOffsets); return this.getOffsets(); } set isPlaying(isPlaying) { console.debug('Player#isPlaying', this, isPlaying); if (isPlaying) { this.classList.add('playing'); this.start(); } else { this.classList.remove('playing'); this.stop(); } } start() { console.debug('Player#start', this); for (let i = 0; i < this.offsets.length; i++) { if (!this.notes[i]) { const note = new OscillatorNode(audioCtx, { frequency: 440, // a above middle c (c4) // detune: o, // type: 'sine', type: 'custom', periodicWave: tromboneWave, }); note.connect(globalGain).connect(audioCtx.destination); note.start(); this.notes[i] = note; } const note = this.notes[i]; note.detune.setValueAtTime(this.offsets[i], audioCtx.currentTime); } for (let j = this.notes.length-1; j >= this.offsets.length; j--) { this.notes[j].stop(); delete this.notes[j]; } } stop() { console.debug('Player#stop', this); this.notes.forEach(n => n.stop()); this.notes = []; } }