summaryrefslogtreecommitdiff
path: root/client/lib
diff options
context:
space:
mode:
Diffstat (limited to 'client/lib')
-rw-r--r--client/lib/color.js2
-rw-r--r--client/lib/kalimba.js49
-rw-r--r--client/lib/organ.js43
-rw-r--r--client/lib/sampler.js23
-rw-r--r--client/lib/scales.js8
-rw-r--r--client/lib/util.js15
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,
};