summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Cully <bjc@spork.org>2025-07-28 15:24:01 -0400
committerBrian Cully <bjc@spork.org>2025-07-28 15:24:01 -0400
commitd9be9dc9a0b72b08d5bfaf3803bb4c2ba1fb84d1 (patch)
tree71f73442a325623bc5556681a86d1287e4270245
parent7ca6bcfb6cab46103f2f6d8e714c3e06b8157033 (diff)
downloadchords-d9be9dc9a0b72b08d5bfaf3803bb4c2ba1fb84d1.tar.gz
chords-d9be9dc9a0b72b08d5bfaf3803bb4c2ba1fb84d1.zip
wip: get tones playing again
-rw-r--r--index.html2
-rw-r--r--main.mjs13
-rw-r--r--player.mjs84
3 files changed, 78 insertions, 21 deletions
diff --git a/index.html b/index.html
index 6595fb9..83ed31a 100644
--- a/index.html
+++ b/index.html
@@ -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>
diff --git a/main.mjs b/main.mjs
index 38cfc60..ad45d90 100644
--- a/main.mjs
+++ b/main.mjs
@@ -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 => {
diff --git a/player.mjs b/player.mjs
index 070a8b7..988d5d6 100644
--- a/player.mjs
+++ b/player.mjs
@@ -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 = [];
}
}