From 6e53264b8fc0ed94282bcce022f07c551e925547 Mon Sep 17 00:00:00 2001 From: julian laplace Date: Mon, 14 Jul 2025 16:58:49 +0200 Subject: pitched noise mode --- client/lib/bandpass.js | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ client/lib/kalimba.js | 2 +- client/lib/organ.js | 67 ---------------------------------- client/lib/sine.js | 92 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 190 insertions(+), 68 deletions(-) create mode 100644 client/lib/bandpass.js delete mode 100644 client/lib/organ.js create mode 100644 client/lib/sine.js (limited to 'client/lib') diff --git a/client/lib/bandpass.js b/client/lib/bandpass.js new file mode 100644 index 0000000..3e1ed16 --- /dev/null +++ b/client/lib/bandpass.js @@ -0,0 +1,97 @@ +/** + * Bandpassed noise organ + * @module lib/bandpass.js; + */ + +import Tone from "tone"; +import { roundInterval } from "./util"; + +let root = 440; + +let oscillators = {}; +let output; +let lastPlayed; +let noise; + +function load(out) { + output = out; +} +function isPlaying(interval) { + const rounded = roundInterval(interval); + const osc = oscillators[rounded]; + return osc && osc.playing; +} +function play(interval) { + if (!output) { + return; + } + if (!noise) { + noise = new Tone.Noise().start(); + } + const rounded = roundInterval(interval); + const osc = (oscillators[rounded] = oscillators[rounded] || {}); + if (!osc.el) { + osc.interval = interval; + osc.el = new Tone.Filter(interval * root, "bandpass"); + osc.el.Q.value = 100; + } + noise.connect(osc.el); + osc.el.connect(output); + osc.playing = true; + lastPlayed = osc; + return osc; +} + +function pause(interval) { + const rounded = roundInterval(interval); + if (!oscillators[rounded]) return; + const osc = (oscillators[rounded] = oscillators[rounded] || {}); + osc.el.disconnect(output); + noise.disconnect(osc.el); + osc.playing = false; + return osc; +} +function toggle(interval) { + const rounded = roundInterval(interval); + const osc = (oscillators[rounded] = oscillators[rounded] || {}); + if (osc && osc.playing) { + pause(interval); + } else { + play(interval); + } +} + +function setRoot(newRoot) { + root = newRoot; + for (const osc of Object.values(oscillators)) { + osc.el.frequency.value = osc.interval * newRoot; + } +} +function stop() { + for (const osc of Object.values(oscillators)) { + if (!osc.playing) { + continue; + } + osc.el.disconnect(output); + noise.disconnect(osc.el); + osc.playing = false; + delete osc.el; + } + oscillators = {}; +} +function getPlaying() { + return Object.values(oscillators) + .filter((osc) => osc.playing) + .map((osc) => osc.interval); +} + +export default { + load, + isPlaying, + getPlaying, + play, + pause, + toggle, + stop, + setRoot, +}; diff --git a/client/lib/kalimba.js b/client/lib/kalimba.js index 53fcb99..c3ee30f 100644 --- a/client/lib/kalimba.js +++ b/client/lib/kalimba.js @@ -33,7 +33,7 @@ function load({ output }) { playbackRate: 1, }); player.name = fn; - const gain = new Tone.Gain(1.6); + const gain = new Tone.Gain(0.15); player.connect(gain); gain.connect(output); sample.players.push(player); diff --git a/client/lib/organ.js b/client/lib/organ.js deleted file mode 100644 index e66f89d..0000000 --- a/client/lib/organ.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Sine wave organ - * @module lib/organ.js; - */ - -import Tone from "tone"; -import { roundInterval } from "./util"; - -let root = 440; - -let oscillators = {}; -let output; -let lastPlayed; - -function load(out) { - output = out; -} -function isPlaying(interval) { - const rounded = roundInterval(interval); - const osc = oscillators[rounded]; - return osc && osc.playing; -} -function play(interval) { - if (!output) { - return; - } - const rounded = roundInterval(interval); - const osc = (oscillators[rounded] = oscillators[rounded] || {}); - if (!osc.el) { - osc.interval = interval; - osc.el = new Tone.Oscillator(interval * root, "sine"); - osc.el.connect(output); - } - osc.el.start(); - osc.playing = true; - lastPlayed = osc; - return osc; -} - -function pause(interval) { - const rounded = roundInterval(interval); - if (!oscillators[rounded]) return; - const osc = (oscillators[rounded] = oscillators[rounded] || {}); - if (osc.el) { - osc.el.stop(); - } - osc.playing = false; - return osc; -} - -function setRoot(newRoot) { - root = newRoot; - for (const osc of Object.values(oscillators)) { - osc.el.frequency.value = osc.interval * newRoot; - } -} -function stop() { - for (const osc of Object.values(oscillators)) { - osc.el.stop(); - osc.el.disconnect(); - osc.playing = false; - delete osc.el; - } - oscillators = {}; -} - -export default { load, isPlaying, play, pause, stop, setRoot }; diff --git a/client/lib/sine.js b/client/lib/sine.js new file mode 100644 index 0000000..b414b27 --- /dev/null +++ b/client/lib/sine.js @@ -0,0 +1,92 @@ +/** + * Sine wave organ + * @module lib/sine.js; + */ + +import Tone from "tone"; +import { roundInterval } from "./util"; + +let root = 440; + +let oscillators = {}; +let output; +let lastPlayed; + +function load(out) { + output = out; +} +function isPlaying(interval) { + const rounded = roundInterval(interval); + const osc = oscillators[rounded]; + return osc && osc.playing; +} +function play(interval) { + if (!output) { + return; + } + const rounded = roundInterval(interval); + const osc = (oscillators[rounded] = oscillators[rounded] || {}); + if (!osc.el) { + osc.interval = interval; + osc.el = new Tone.Oscillator(interval * root, "sine"); + osc.gain = new Tone.Gain(0.025); + osc.el.connect(osc.gain); + osc.gain.connect(output); + } + osc.el.start(); + osc.playing = true; + lastPlayed = osc; + return osc; +} + +function pause(interval) { + const rounded = roundInterval(interval); + if (!oscillators[rounded]) return; + const osc = (oscillators[rounded] = oscillators[rounded] || {}); + if (osc.el) { + osc.el.stop(); + } + osc.playing = false; + return osc; +} +function toggle(interval) { + const rounded = roundInterval(interval); + const osc = (oscillators[rounded] = oscillators[rounded] || {}); + if (osc && osc.playing) { + pause(interval); + } else { + play(interval); + } +} + +function setRoot(newRoot) { + root = newRoot; + for (const osc of Object.values(oscillators)) { + osc.el.frequency.value = osc.interval * newRoot; + } +} +function stop() { + for (const osc of Object.values(oscillators)) { + osc.el.stop(); + osc.el.disconnect(); + osc.playing = false; + delete osc.el; + } + oscillators = {}; +} +function getPlaying() { + return Object.values(oscillators) + .filter((osc) => osc.playing) + .map((osc) => osc.interval); +} + +export default { + load, + isPlaying, + getPlaying, + play, + pause, + toggle, + stop, + setRoot, +}; -- cgit v1.2.3-70-g09d2