summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2021-05-27 18:12:46 +0200
committerJules Laplace <julescarbon@gmail.com>2021-05-27 18:12:46 +0200
commitdfcdf790e3879678d8b3a9b729cca03174b32d55 (patch)
treefcc86c5699b101fd632bc5fbccb97b0aa49f0629 /client
parent93a79463d42909928b4db9961e0cb1c40f847639 (diff)
quieter. rightclick to recenter fractions
Diffstat (limited to 'client')
-rw-r--r--client/index.js549
-rw-r--r--client/lib/output.js9
2 files changed, 306 insertions, 252 deletions
diff --git a/client/index.js b/client/index.js
index edc5281..87cf113 100644
--- a/client/index.js
+++ b/client/index.js
@@ -1,367 +1,418 @@
-import keys from './lib/keys'
-import color from './lib/color'
-import kalimba from './lib/kalimba'
-import life from './lib/life'
-import organ from './lib/organ'
-import { browser, requestAudioContext, choice } from './lib/util'
+import gcd from "compute-gcd";
-let instrument = kalimba
+import keys from "./lib/keys";
+import color from "./lib/color";
+import kalimba from "./lib/kalimba";
+import life from "./lib/life";
+import organ from "./lib/organ";
+import { browser, requestAudioContext, choice } from "./lib/util";
-const root = 440
-const s = 50
-const w = window.innerWidth
-const h = window.innerHeight
-const ws = Math.ceil(w/s), hs = Math.ceil(h/s)
+let instrument = kalimba;
-const add_on = 0
-const mul_on = 1.0
-const add_off = 0.1
-const mul_off = 0.9
+const root = 440;
+const s = 50;
+const w = window.innerWidth;
+const h = window.innerHeight;
+const ws = Math.ceil(w / s),
+ hs = Math.ceil(h / s);
-let dragging = false
-let erasing = false
-let lastFreq = 0
-let notes = []
+const add_on = 0;
+const mul_on = 1.0;
+const add_off = 0.1;
+const mul_off = 0.9;
-requestAudioContext( () => {
+let dragging = false;
+let erasing = false;
+let lastFreq = 0;
+let notes = [];
+
+requestAudioContext(() => {
for (var i = 0; i < ws; i++) {
- notes[i] = []
+ notes[i] = [];
for (var j = 0; j < hs; j++) {
- notes[i][j] = add(i, j)
+ notes[i][j] = add(i, j);
}
}
- life.init(notes, assign)
-})
+ life.init(notes, assign);
+});
function play(freq) {
- if (freq.playing) return
- freq.playing = true
- instrument.play(freq.frequency)
+ if (freq.playing) return;
+ freq.playing = true;
+ instrument.play(freq.frequency);
if (instrument === organ || hash || life.isRunning()) {
- freq.div.classList.add('playing')
+ freq.div.classList.add("playing");
}
- life.assign_item(freq, true)
+ life.assign_item(freq, true);
}
function pause(freq) {
- if (!freq.playing) return
- freq.playing = false
- instrument.pause(freq.frequency)
- freq.div.classList.remove('playing')
- life.assign_item(freq, false)
+ if (!freq.playing) return;
+ freq.playing = false;
+ instrument.pause(freq.frequency);
+ freq.div.classList.remove("playing");
+ life.assign_item(freq, false);
}
function assign(freq, state) {
if (state) {
- play(freq)
+ play(freq);
} else {
- pause(freq)
+ pause(freq);
}
}
function toggle(freq) {
- assign(freq, !freq.playing)
+ assign(freq, !freq.playing);
}
const gliderShape = [
- [0,0,0,0,0],
- [0,1,1,1,0],
- [0,0,0,1,0],
- [0,0,1,0,0],
- [0,0,0,0,0],
-]
-const gliderShapeFlip = gliderShape.map(a => a.slice(0).reverse())
+ [0, 0, 0, 0, 0],
+ [0, 1, 1, 1, 0],
+ [0, 0, 0, 1, 0],
+ [0, 0, 1, 0, 0],
+ [0, 0, 0, 0, 0],
+];
+const gliderShapeFlip = gliderShape.map((a) => a.slice(0).reverse());
const gliderShapes = [
gliderShape,
gliderShapeFlip,
gliderShape.slice(0).reverse(),
gliderShapeFlip.slice(0).reverse(),
-]
+];
function glider() {
- const x = Math.floor(Math.random() * ws)
- const y = Math.floor(Math.random() * hs)
- const shape = choice(gliderShapes)
- weave(x,y,shape)
+ const x = Math.floor(Math.random() * ws);
+ const y = Math.floor(Math.random() * hs);
+ const shape = choice(gliderShapes);
+ weave(x, y, shape);
}
-function weave (x,y,shape) {
- const xmag = shape.length
- const ymag = shape[0].length
- let i, j, px, py
+function weave(x, y, shape) {
+ const xmag = shape.length;
+ const ymag = shape[0].length;
+ let i, j, px, py;
for (i = 0; i < xmag; i++) {
for (j = 0; j < ymag; j++) {
- px = (x+i) % ws
- py = (y+j) % hs
- assign(notes[px][py], shape[i][j])
+ px = (x + i) % ws;
+ py = (y + j) % hs;
+ assign(notes[px][py], shape[i][j]);
}
}
}
-function forEach(f){
+function forEach(f) {
let i, j, note, s;
for (i = 0; i < ws; i++) {
for (j = 0; j < hs; j++) {
- note = notes[i][j]
- s = f(i, j, note.playing)
- assign(note, s)
+ note = notes[i][j];
+ s = f(i, j, note.playing);
+ assign(note, s);
}
}
}
-function clone(){
+function clone() {
let i, j;
- let a = []
+ let a = [];
for (i = 0; i < ws; i++) {
- a[i] = []
+ a[i] = [];
for (j = 0; j < hs; j++) {
- a[i][j] = notes[i][j].playing
+ a[i][j] = notes[i][j].playing;
}
}
- return a
+ return a;
}
-function move(dx,dy){
- let a = clone()
- forEach((x,y,state) => {
- x = (x+dx+ws)%ws
- y = (y+dy+hs)%hs
- return a[x][y]
- })
+function move(dx, dy) {
+ let a = clone();
+ forEach((x, y, state) => {
+ x = (x + dx + ws) % ws;
+ y = (y + dy + hs) % hs;
+ return a[x][y];
+ });
}
-function clear(){
+function clear() {
forEach(() => {
- return false
- })
+ return false;
+ });
}
-function stripex(odd){
- odd = !! odd
+function stripex(odd) {
+ odd = !!odd;
forEach((x) => {
- return x % 2 ? odd : !odd
- })
+ return x % 2 ? odd : !odd;
+ });
}
-function stripey(odd){
- odd = !! odd
- forEach((x,y) => {
- return y % 2 ? odd : !odd
- })
+function stripey(odd) {
+ odd = !!odd;
+ forEach((x, y) => {
+ return y % 2 ? odd : !odd;
+ });
}
-function checker(odd, n){
- odd = !! odd
- n = n || 1
- forEach((x,y) => {
- return ((Math.floor(x/n)%2) ^ (Math.floor(y/n)%2)) ? odd : !odd
- })
+function checker(odd, n) {
+ odd = !!odd;
+ n = n || 1;
+ forEach((x, y) => {
+ return Math.floor(x / n) % 2 ^ Math.floor(y / n) % 2 ? odd : !odd;
+ });
}
-function noise(n){
- n = n || 0.5
- n = n * n
+function noise(n) {
+ n = n || 0.5;
+ n = n * n;
forEach(() => {
- return Math.random() < n
- })
+ return Math.random() < n;
+ });
}
-function add (i, j) {
- const a = i + 1
- const b = j + 1
- const div = document.createElement('div')
- const frequency = root * a/b
- let add = 0
- let frac = Math.log2(a/b) % 1
- div.style.left = (i * s) + 'px'
- div.style.top = (j * s) + 'px'
- div.innerHTML = `<div>${a}<\/div><div>\/</div><div>${b}<\/div>`
- const freq = { frequency, div, i, j, playing: false }
- if (frac < 0) {
- frac += 1
- }
- if (a < b) {
- add = -Math.log(b/a) / 3.5
- }
- else {
- add = Math.log(a/b) / 6
- }
- if ( frac === 0) {
- div.style.fontWeight = '900'
- div.style.left = (i * s) + 'px'
- div.style.top = (j * s) + 'px'
- }
- div.style.backgroundColor = color(frac, add_off + add, mul_off)
+function add(i, j) {
+ const a = i + 1;
+ const b = j + 1;
+ const div = document.createElement("div");
+ const frequency = (root * a) / b;
+ let add = 0;
+ let frac;
+ div.style.left = i * s + "px";
+ div.style.top = j * s + "px";
+
+ const freq = {
+ frequency,
+ div,
+ i,
+ j,
+ playing: false,
+ recolor: (numerator, denominator) => {
+ let aa = a / numerator;
+ let bb = b / denominator;
+ if (aa < bb) {
+ add = -Math.log(bb / aa) / 3.5;
+ } else {
+ add = Math.log(aa / bb) / 6;
+ }
+ let a_inv = a * denominator;
+ let b_inv = b * numerator;
+ let ba_gcd = gcd(a_inv, b_inv);
+ let a_disp = a_inv / ba_gcd;
+ let b_disp = b_inv / ba_gcd;
+
+ frac = Math.log2(aa / bb) % 1;
+ let frac_orig = Math.log2(a / b) % 1;
+ if (frac < 0) {
+ frac += 1;
+ }
+ if (frac_orig < 0) {
+ frac += 1;
+ }
+ if (frac_orig === 0) {
+ div.style.fontWeight = "900";
+ } else {
+ div.style.fontWeight = "500";
+ }
+
+ div.innerHTML = `<div>${a_disp}</div><div>/</div><div>${b_disp}</div>`;
+ if (freq.playing) {
+ div.style.backgroundColor = color(frac, add + add_on, mul_on);
+ } else {
+ div.style.backgroundColor = color(frac, add + add_off, mul_off);
+ }
+ },
+ };
+
+ freq.recolor(1, 1);
if (browser.isDesktop) {
- div.addEventListener('mousedown', function(){
- div.style.backgroundColor = color(frac, add + add_on, mul_on)
- toggle( freq )
- erasing = !freq.playing
- })
- div.addEventListener('mouseenter', function(){
- div.style.backgroundColor = color(frac, add + add_on, mul_on)
+ div.addEventListener("mousedown", function (event) {
+ if (event.button === 2) {
+ // rightclick
+ event.preventDefault();
+ notes.forEach((row) => row.forEach((note) => note.recolor(a, b)));
+ return;
+ }
+ div.style.backgroundColor = color(frac, add + add_on, mul_on);
+ toggle(freq);
+ erasing = !freq.playing;
+ });
+ div.addEventListener("mouseenter", function () {
+ div.style.backgroundColor = color(frac, add + add_on, mul_on);
if (dragging) {
if (erasing) {
- pause( freq )
+ pause(freq);
} else {
- toggle( freq )
+ toggle(freq);
}
}
- })
- div.addEventListener('mouseleave', function(){
- div.style.backgroundColor = color(frac, add + add_off, mul_off)
- })
- }
- else {
- div.addEventListener('touchstart', function(e){
- e.preventDefault()
- toggle( freq )
- erasing = !freq.playing
- lastFreq = freq
- })
- }
- document.body.appendChild(div)
- return freq
+ });
+ div.addEventListener("mouseleave", function () {
+ div.style.backgroundColor = color(frac, add + add_off, mul_off);
+ });
+ div.addEventListener("contextmenu", function (event) {
+ if (!event.ctrlKey || !event.metaKey || !event.altKey) {
+ event.preventDefault();
+ }
+ });
+ } else {
+ div.addEventListener("touchstart", function (e) {
+ e.preventDefault();
+ toggle(freq);
+ erasing = !freq.playing;
+ lastFreq = freq;
+ });
+ }
+ document.body.appendChild(div);
+ return freq;
}
if (browser.isDesktop) {
- document.addEventListener('mousedown', () => { dragging = true })
- document.addEventListener('mouseup', () => { dragging = false })
-}
-else {
- document.addEventListener('touchstart', (e) => { e.preventDefault(); dragging = true })
- document.addEventListener('touchmove', (e) => {
- e.preventDefault()
- const x = Math.floor( e.touches[0].pageX / s )
- const y = Math.floor( e.touches[0].pageY / s )
- if (! (x in notes) || ! (y in notes[x])) return
- const freq = notes[x][y]
- if (freq !== lastFreq) {
+ document.addEventListener("mousedown", (event) => {
+ if (event.button !== 2) {
+ dragging = true;
+ }
+ });
+ document.addEventListener("mouseup", () => {
+ dragging = false;
+ });
+} else {
+ document.addEventListener("touchstart", (e) => {
+ e.preventDefault();
+ dragging = true;
+ });
+ document.addEventListener("touchmove", (e) => {
+ e.preventDefault();
+ const x = Math.floor(e.touches[0].pageX / s);
+ const y = Math.floor(e.touches[0].pageY / s);
+ if (!(x in notes) || !(y in notes[x])) return;
+ const freq = notes[x][y];
+ if (freq !== lastFreq) {
if (dragging) {
if (erasing) {
- pause( freq )
+ pause(freq);
} else {
- toggle( freq )
+ toggle(freq);
}
}
- lastFreq = freq
- }
- })
- document.addEventListener('touchend', () => { dragging = false })
+ lastFreq = freq;
+ }
+ });
+ document.addEventListener("touchend", () => {
+ dragging = false;
+ });
}
-function swap_instrument(){
- instrument = (instrument === kalimba) ? organ : kalimba
+function swap_instrument() {
+ instrument = instrument === kalimba ? organ : kalimba;
}
-let life_bpm = 50
-window.addEventListener("keydown", keydown, true)
-function keydown(e){
+let life_bpm = 50;
+window.addEventListener("keydown", keydown, true);
+function keydown(e) {
// console.log(e.keyCode)
- if (e.altKey || e.ctrlKey || e.metaKey) return
- switch (e.keyCode){
+ if (e.altKey || e.ctrlKey || e.metaKey) return;
+ switch (e.keyCode) {
case 32: // space
- life.toggle()
- break
+ life.toggle();
+ break;
case 188: // comma
- life_bpm += e.shiftKey ? 1 : 5
- life.setTempo(life_bpm)
- break
+ life_bpm += e.shiftKey ? 1 : 5;
+ life.setTempo(life_bpm);
+ break;
case 190: // period
- life_bpm -= e.shiftKey ? 1 : 5
- life_bpm = Math.max(1, life_bpm)
- life.setTempo(life_bpm)
- break
+ life_bpm -= e.shiftKey ? 1 : 5;
+ life_bpm = Math.max(1, life_bpm);
+ life.setTempo(life_bpm);
+ break;
case 37: // left
- move(1, 0)
- break
+ move(1, 0);
+ break;
case 38: // up
- move(0, 1)
- break
+ move(0, 1);
+ break;
case 39: // right
- move(-1, 0)
- break
+ move(-1, 0);
+ break;
case 40: // down
- move(0, -1)
- break
+ move(0, -1);
+ break;
case 71: // g
- glider()
- break
+ glider();
+ break;
case 83: // s
- swap_instrument()
- break
+ swap_instrument();
+ break;
case 67: // c
- clear()
- break
+ clear();
+ break;
case 87: // w
- clear()
- break
+ clear();
+ break;
case 78: // n
- noise(0.5)
- break
+ noise(0.5);
+ break;
case 69: // e
- stripex(Math.random() < 0.5)
- break
+ stripex(Math.random() < 0.5);
+ break;
case 82: // r
- stripey(Math.random() < 0.5)
- break
+ stripey(Math.random() < 0.5);
+ break;
case 84: // t
- checker(Math.random() < 0.5, 1)
- break
+ checker(Math.random() < 0.5, 1);
+ break;
case 89: // y
- checker(Math.random() < 0.5, 2)
- break
+ checker(Math.random() < 0.5, 2);
+ break;
case 85: // u
- checker(Math.random() < 0.5, 3)
- break
+ checker(Math.random() < 0.5, 3);
+ break;
case 73: // i
- checker(Math.random() < 0.5, 4)
- break
+ checker(Math.random() < 0.5, 4);
+ break;
case 79: // o
- checker(Math.random() < 0.5, 5)
- break
+ checker(Math.random() < 0.5, 5);
+ break;
case 80: // p
- checker(Math.random() < 0.5, 6)
- break
+ checker(Math.random() < 0.5, 6);
+ break;
case 219: // [
- checker(Math.random() < 0.5, 7)
- break
+ checker(Math.random() < 0.5, 7);
+ break;
case 221: // ]
- checker(Math.random() < 0.5, 11)
- break
+ checker(Math.random() < 0.5, 11);
+ break;
case 49: // 1
- noise(0.1)
- break
+ noise(0.1);
+ break;
case 50: // 2
- noise(0.2)
- break
+ noise(0.2);
+ break;
case 51: // 3
- noise(0.3)
- break
+ noise(0.3);
+ break;
case 52: // 4
- noise(0.4)
- break
+ noise(0.4);
+ break;
case 53: // 5
- noise(0.5)
- break
+ noise(0.5);
+ break;
case 54: // 6
- noise(0.6)
- break
+ noise(0.6);
+ break;
case 55: // 7
- noise(0.7)
- break
+ noise(0.7);
+ break;
case 56: // 8
- noise(0.8)
- break
+ noise(0.8);
+ break;
case 57: // 9
- noise(0.9)
- break
+ noise(0.9);
+ break;
case 48: // 0
- noise(1)
- break
+ noise(1);
+ break;
}
}
-keys.listen(function(index){
+keys.listen(function (index) {
// const freq = scales.current().index(index)
// document.body.style.backgroundColor = color( index / scales.current().scale.length )
// instrument.toggle(freq)
-})
+});
-let hash = window.location.hash || window.location.search
-if (hash.match('sin') || hash.match('organ')) {
- instrument = organ
+let hash = window.location.hash || window.location.search;
+if (hash.match("sin") || hash.match("organ")) {
+ instrument = organ;
}
-if (hash.match('glider')) {
- instrument = organ
- clear()
- glider()
- life.setTempo(life_bpm = 120 * 8)
- life.toggle()
+if (hash.match("glider")) {
+ instrument = organ;
+ clear();
+ glider();
+ life.setTempo((life_bpm = 120 * 8));
+ life.toggle();
}
diff --git a/client/lib/output.js b/client/lib/output.js
index 2155009..9947327 100644
--- a/client/lib/output.js
+++ b/client/lib/output.js
@@ -1,5 +1,8 @@
-import Tone from 'tone'
+import Tone from "tone";
-const compressor = new Tone.Compressor(-30, 3).toMaster()
+const compressor = new Tone.Compressor(-30, 3);
+const gain = new Tone.Gain(0.3);
+compressor.connect(gain);
+gain.toMaster();
-export default compressor
+export default compressor;