diff options
Diffstat (limited to 'client/lib')
| -rw-r--r-- | client/lib/color.js | 2 | ||||
| -rw-r--r-- | client/lib/kalimba.js | 49 | ||||
| -rw-r--r-- | client/lib/organ.js | 43 | ||||
| -rw-r--r-- | client/lib/sampler.js | 23 | ||||
| -rw-r--r-- | client/lib/scales.js | 8 | ||||
| -rw-r--r-- | client/lib/util.js | 15 |
6 files changed, 85 insertions, 55 deletions
diff --git a/client/lib/color.js b/client/lib/color.js index bea0330..bbc137e 100644 --- a/client/lib/color.js +++ b/client/lib/color.js @@ -62,7 +62,7 @@ function color(t, add, mul) { b = palette[1][i]; c = palette[2][i]; d = palette[3][i]; - rgb[i] = Math.round(channel(t, a, b, c, d, add, mul) * 255); + rgb[i] = Math.round(channel(-t, a, b, c, d, add, mul) * 255); } return "rgb(" + rgb + ")"; } diff --git a/client/lib/kalimba.js b/client/lib/kalimba.js index 64ace00..53fcb99 100644 --- a/client/lib/kalimba.js +++ b/client/lib/kalimba.js @@ -18,7 +18,7 @@ const samples = [ // { root: 671, fn: 'samples/380732__cabled-mess__sansula-09-e-raw.wav', }, ]; -function load(output) { +function load({ output }) { samples.forEach((sample) => { sample.players = []; sample.index = -1; @@ -45,15 +45,12 @@ function load(output) { ); } -let last = 440; - -function play(freq) { - last = freq; +function play(interval, root) { const sample = choice(samples); sample.index = (sample.index + 1) % sample.players.length; const player = sample.players[sample.index]; - player.playbackRate = freq / sample.root; + player.playbackRate = (interval * root) / sample.root; player.start(); } @@ -63,24 +60,24 @@ function pause() { export default { load, play, pause }; -// for help tuning -function keydown(e) { - // console.log(e.keyCode) - if (e.metaKey && last) { - let step = e.shiftKey ? (e.ctrlKey ? 0.01 : 0.1) : 1; - switch (e.keyCode) { - case 38: // up - e.preventDefault(); - samples[0].root -= step; - play(last); - break; - case 40: // down - e.preventDefault(); - samples[0].root += step; - play(last); - break; - } - console.log(samples[0].root); - } -} +// for help tuning the kalimba samples +// function keydown(e) { +// // console.log(e.keyCode) +// if (e.metaKey && last) { +// let step = e.shiftKey ? (e.ctrlKey ? 0.01 : 0.1) : 1; +// switch (e.keyCode) { +// case 38: // up +// e.preventDefault(); +// samples[0].root -= step; +// play(last); +// break; +// case 40: // down +// e.preventDefault(); +// samples[0].root += step; +// play(last); +// break; +// } +// console.log(samples[0].root); +// } +// } // window.addEventListener("keydown", keydown, true); diff --git a/client/lib/organ.js b/client/lib/organ.js index 652351e..e66f89d 100644 --- a/client/lib/organ.js +++ b/client/lib/organ.js @@ -4,30 +4,31 @@ */ import Tone from "tone"; -import { roundFreq } from "./util"; +import { roundInterval } from "./util"; -const oscillators = {}; +let root = 440; +let oscillators = {}; let output; let lastPlayed; function load(out) { output = out; } - -function isPlaying(freq) { - const rounded = roundFreq(freq); +function isPlaying(interval) { + const rounded = roundInterval(interval); const osc = oscillators[rounded]; return osc && osc.playing; } -function play(freq) { +function play(interval) { if (!output) { return; } - const rounded = roundFreq(freq); + const rounded = roundInterval(interval); const osc = (oscillators[rounded] = oscillators[rounded] || {}); if (!osc.el) { - osc.el = new Tone.Oscillator(freq, "sine"); + osc.interval = interval; + osc.el = new Tone.Oscillator(interval * root, "sine"); osc.el.connect(output); } osc.el.start(); @@ -36,13 +37,31 @@ function play(freq) { return osc; } -function pause(freq) { - const rounded = roundFreq(freq); +function pause(interval) { + const rounded = roundInterval(interval); if (!oscillators[rounded]) return; const osc = (oscillators[rounded] = oscillators[rounded] || {}); - if (osc.el) osc.el.stop(); + if (osc.el) { + osc.el.stop(); + } osc.playing = false; return osc; } -export default { load, isPlaying, play, pause, oscillators }; +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/sampler.js b/client/lib/sampler.js index 08f253d..69da86e 100644 --- a/client/lib/sampler.js +++ b/client/lib/sampler.js @@ -5,6 +5,8 @@ import Tone from "tone"; +let root = 440; + let output; let ready; let current = ""; @@ -72,14 +74,19 @@ export function loadSampleFromFile(file, url) { /** * Player */ -let last = 440; +let last = [1, 440]; -function play(freq) { - last = freq; +function stop() { + for (const sample of Object.values(samples)) { + sample.players.forEach((player) => player.stop()); + } +} +function play(interval, root) { + last = [interval, root]; const sample = samples[current]; sample.index = (sample.index + 1) % sample.players.length; const player = sample.players[sample.index]; - player.playbackRate = freq / sample.root; + player.playbackRate = (interval * root) / sample.root; player.start(); } @@ -87,7 +94,7 @@ function pause() { // no-op } -export default { load, play, pause }; +export default { load, play, pause, stop }; // for help tuning function keydown(e) { @@ -99,12 +106,14 @@ function keydown(e) { case 38: // up e.preventDefault(); sample.root -= step; - play(last); + stop(); + play(last[0], last[1]); break; case 40: // down e.preventDefault(); sample.root += step; - play(last); + stop(); + play(last[0], last[1]); break; } } diff --git a/client/lib/scales.js b/client/lib/scales.js index 87dcb0e..1e5afd6 100644 --- a/client/lib/scales.js +++ b/client/lib/scales.js @@ -19,11 +19,11 @@ import { let a, b; export const scales = [ - { name: "integer", get: (i, j) => [i + 1, j + 1] }, - { name: "subharmonic", get: (i, j) => [i + 1, i + j + 2] }, - { name: "harmonic", get: (i, j) => [i + j + 2, j + 1] }, + { name: "natural", get: (i, j) => [i + 1, j + 1] }, + { name: "undertone", get: (i, j) => [i + 1, i + j + 2] }, + { name: "overtone", get: (i, j) => [i + j + 2, j + 1] }, { - name: "prime", + name: "primes", reset: (x, y, w, h) => { a = Prime().skip(x).take(w).toJS(); b = Prime().skip(y).take(h).toJS(); diff --git a/client/lib/util.js b/client/lib/util.js index 5bf93dc..d0a3914 100644 --- a/client/lib/util.js +++ b/client/lib/util.js @@ -23,10 +23,13 @@ function choice(a) { function mod(n, m) { return n - m * Math.floor(n / m); } -function roundFreq(freq) { - return Math.round(freq * 100); +function roundInterval(interval) { + return Math.round(interval * 10000000); } -const frequencyInRange = (freq) => 20 < freq && freq < 15000; +const intervalInRange = (interval, root) => + 20 < interval * root && interval * root < 15000; +const lerp = (n, a, b) => (b - a) * n + a; +const clamp = (n, a = 0, b = 1) => (n < a ? a : n < b ? n : b); function requestAudioContext(fn) { if (window.location.protocol !== "https:") { @@ -75,7 +78,9 @@ export { choice, mod, browser, - roundFreq, - frequencyInRange, + lerp, + clamp, + roundInterval, + intervalInRange, requestAudioContext, }; |
