import Trombone from './vend/trombone.mjs'; export default class extends HTMLElement { static name = 'x-player' static register() { console.debug('Registering Element', this.name, this); customElements.define(this.name, this); } // A4 aFreq = 440; // oscillatornodes notes = []; getOffsets = () => []; constructor() { super(); console.debug('Player#constructor', this); } connectedCallback() { this.audioCtx = new AudioContext(); this.wave = new PeriodicWave(this.audioCtx, { real: Trombone.real, imag: Trombone.imag }); this.globalGain = this.audioCtx.createGain(); this.globalGain.connect(this.audioCtx.destination); this.globalGain.gain.setValueAtTime(this.volume, this.audioCtx.currentTime); this.querySelector('.volume').addEventListener('input', _ => { this.globalGain.gain.setValueAtTime(this.volume, this.audioCtx.currentTime); }); } get volume() { console.debug('Player#volume', this.querySelector('.volume').value) return Number(this.querySelector('.volume').value); } set volume(volume) { console.debug('Player#volume()', this, volume); this.querySelector('.volume').value = volume; } get isPlaying() { console.debug('Player#isPlaying', this, this.classList.contains('playing')); return this.classList.contains('playing'); } // offsets is an array of offsets in cents from A4. get offsets() { 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(); } } update() { console.debug('Player#update', this.offsets, this.notes); for (let i = 0; i < this.offsets.length; i++) { if (!this.notes[i]) { console.debug('new note for', i) const note = new OscillatorNode(this.audioCtx, { frequency: this.aFreq, type: 'custom', periodicWave: this.wave }); note.connect(this.globalGain); note.start(); this.notes[i] = note; } const note = this.notes[i]; note.detune.setValueAtTime(this.offsets[i], this.audioCtx.currentTime); } for (let j = this.notes.length-1; j >= this.offsets.length; j--) { const note = this.notes[j]; note.stop(); } this.notes = this.notes.slice(0, this.offsets.length); console.debug(' -- done', this.notes); } start() { console.debug('Player#start', this.notes); this.update(); this.audioCtx.resume(); } stop() { console.debug('Player#stop', this); this.audioCtx.suspend(); } }