diff options
| -rw-r--r-- | index.html | 2 | ||||
| -rw-r--r-- | main.mjs | 13 | ||||
| -rw-r--r-- | player.mjs | 84 |
3 files changed, 78 insertions, 21 deletions
@@ -25,7 +25,7 @@ </template> <x-player> - <input type='range' min='0' max='1' value='0.1' step='0.1'> + <input class='volume' type='range' min='0' max='1' value='0.1' step='0.1'> <button class='play'>play ▶️</button> </x-player> <button class='save'>+</button> @@ -28,16 +28,18 @@ function play({ detail }) { } }).filter(n => n); - player = new Player(played.map(([n, o]) => { - return toCents([noteA, 4], [n, o]); - })); - player.start(); + const getOffsets = () => { + return played.map(([n, o]) => toCents([noteA, 4], [n, o])); + } + player = document.querySelector('x-player'); + player.getOffsets = getOffsets; + player.isPlaying = true; } function stop(e) { console.debug('got stopEvent', e); if (player) { - player.stop(); + player.isPlaying = false; } } @@ -62,6 +64,7 @@ function init() { Fretboard.register(); KeyPicker.register(); History.register(); + Player.register(); // todo: maybe just attach the listener to document? document.querySelectorAll(Fretboard.name).forEach(f => { @@ -14,34 +14,88 @@ const tromboneWave = new PeriodicWave(audioCtx, { const globalGain = new GainNode(audioCtx, { gain: 0.06 }) -export default class { +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 = []; - // offsets is an array of offsets in cents from A4. - constructor(offsets) { - console.debug('Player#constructor', this, offsets); - this.offsets = offsets; + 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; + } - this.notes = offsets.map(o => - new OscillatorNode(audioCtx, { - frequency: 440, // a above middle c (c4) - detune: o, - // type: 'sine', - type: 'custom', - periodicWave: tromboneWave, - })); + 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(); + } - this.notes.forEach(n => n.connect(globalGain).connect(audioCtx.destination)); + 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); - this.notes.forEach(n => n.start()); + 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 = []; } } |
