From ed62a07b37e666d1a5e972847460dee7f90b3987 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Sun, 23 Apr 2017 22:17:43 -0400 Subject: triangle interval map --- client/index.js | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ client/lib/color.js | 31 ++++++++++++++++++++++++++++ client/lib/kalimba.js | 46 ++++++++++++++++++++++++++++++++++++++++++ client/lib/keys.js | 39 +++++++++++++++++++++++++++++++++++ client/lib/util.js | 3 +++ 5 files changed, 175 insertions(+) create mode 100644 client/index.js create mode 100644 client/lib/color.js create mode 100644 client/lib/kalimba.js create mode 100644 client/lib/keys.js create mode 100644 client/lib/util.js (limited to 'client') diff --git a/client/index.js b/client/index.js new file mode 100644 index 0000000..62f7e53 --- /dev/null +++ b/client/index.js @@ -0,0 +1,56 @@ +import keys from './lib/keys' +import color from './lib/color' +import kalimba from './lib/kalimba' + +const root = 440 +const s = 50 +const w = window.innerWidth +const h = window.innerHeight +const ws = w/s, hs = h/s + +const add_on = 0 +const mul_on = 1.0 +const add_off = 0.1 +const mul_off = 0.9 + +let dragging = false + +for (var i = 0; i < ws; i++) { + for (var j = 0; j < hs; j++) { + add(i, j) + } +} + +function add (x, y) { + const i = Math.max(x, y) + 1 + const j = Math.min(x, y) + 1 + const div = document.createElement('div') + div.style.left = (x * s) + 'px' + div.style.top = (y * s) + 'px' + div.style.backgroundColor = color(i/j, add_off, mul_off) + if (x < y) div.style.opacity = 0.5 + div.innerHTML = `
${i}<\/div>
\/
${j}<\/div>` + div.addEventListener('mouseenter', function(){ + div.style.backgroundColor = color(i/j, add_on, mul_on) + if (dragging) { + kalimba.play( root * i/j ) + } + }) + div.addEventListener('mouseleave', function(){ + div.style.backgroundColor = color(i/j, add_off, mul_off) + }) + div.addEventListener('click', function(){ + kalimba.play( root * i/j ) + }) + document.body.appendChild(div) +} + +document.addEventListener('mousedown', () => { dragging = true }) +document.addEventListener('mouseup', () => { dragging = false }) + +keys.listen(function(index){ + // const freq = scales.current().index(index) + // document.body.style.backgroundColor = color( index / scales.current().scale.length ) + kalimba.play(freq) +}) + diff --git a/client/lib/color.js b/client/lib/color.js new file mode 100644 index 0000000..bd5b7ce --- /dev/null +++ b/client/lib/color.js @@ -0,0 +1,31 @@ + +const palettes = [ + [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0], [0.00, 0.33, 0.67]], + [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0], [0.00, 0.10, 0.20]], + [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0], [0.30, 0.20, 0.20]], + [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 0.5], [0.80, 0.90, 0.30]], + [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 0.7, 0.4], [0.00, 0.15, 0.20]], + [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [2.0, 1.0, 0.0], [0.50, 0.20, 0.25]], + [[0.8, 0.5, 0.4], [0.2, 0.4, 0.2], [2.0, 1.0, 1.0], [0.00, 0.25, 0.25]], +] + +let palette = palettes[0] + +function channel (t, a, b, c, d, add, mul) { + return a + b * Math.cos(2 * Math.PI * (c * t + d)) * mul + add +} + +function color (t, add, mul) { + let a, b, c, d + const rgb = [] + for (var i = 0; i < 3; i++) { + a = palette[0][i] + 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) + } + return 'rgb(' + rgb + ')' +} + +export default color diff --git a/client/lib/kalimba.js b/client/lib/kalimba.js new file mode 100644 index 0000000..b057666 --- /dev/null +++ b/client/lib/kalimba.js @@ -0,0 +1,46 @@ +import Tone from 'tone' +import { choice } from './util' + +const player_count = 4 + +const compressor = new Tone.Compressor(-30, 3).toMaster() + +const samples = [ + { root: 226, fn: 'samples/380737__cabled-mess__sansula-01-a-raw.wav', }, + { root: 267, fn: 'samples/380736__cabled-mess__sansula-02-c-raw.wav', }, + { root: 340, fn: 'samples/380735__cabled-mess__sansula-03-e-raw.wav', }, + { root: 452, fn: 'samples/380733__cabled-mess__sansula-06-a-02-raw.wav', }, + { root: 507, fn: 'samples/380734__cabled-mess__sansula-07-b-h-raw.wav', }, + { root: 535, fn: 'samples/380731__cabled-mess__sansula-08-c-raw.wav', }, + { root: 671, fn: 'samples/380732__cabled-mess__sansula-09-e-raw.wav', }, +] + +samples.forEach((sample) => { + sample.players = [] + sample.index = -1 + for (let i = 0; i < player_count; i++) { + let fn = sample.fn + if (window.location.href.match(/asdf.us/)) { + fn = 'http://asdf.us/kalimba/' + fn + } + let player = new Tone.Player({ + url: fn, + retrigger: true, + playbackRate: 1, + }) + player.connect(compressor) + sample.players.push(player) + } +}) + +function play (freq) { + const best = { sample: choice(samples) } + best.sample.index = (best.sample.index + 1) % player_count + + const player = best.sample.players[ best.sample.index ] + player.playbackRate = freq / best.sample.root + player.start() +} + +export default { play } + diff --git a/client/lib/keys.js b/client/lib/keys.js new file mode 100644 index 0000000..c9e51ac --- /dev/null +++ b/client/lib/keys.js @@ -0,0 +1,39 @@ +const keys = {} +const key_numbers = {} +const letters = "zxcvbnmasdfghjklqwertyuiop" +const numbers = "1234567890" + +let callback = function(){} + +letters.toUpperCase().split("").map(function(k,i){ + keys[k.charCodeAt(0)] = i +}) + +numbers.split("").map(function(k,i){ + keys[k.charCodeAt(0)] = i+letters.length + key_numbers[k.charCodeAt(0)] = true +}) + +window.addEventListener("keydown", keydown, true) +function keydown (e) { + if (e.altKey || e.ctrlKey || e.metaKey) { + e.stopPropagation() + return + } + if (document.activeElement instanceof HTMLInputElement && + (e.keyCode in key_numbers)) { + e.stopPropagation() + return + } + if (! (e.keyCode in keys)) return + var index = keys[e.keyCode] + if (e.shiftKey) index += letters.length + index -= 7 + callback(index) +} + +function listen (fn) { + callback = fn +} + +export default { listen } \ No newline at end of file diff --git a/client/lib/util.js b/client/lib/util.js new file mode 100644 index 0000000..b2d95f5 --- /dev/null +++ b/client/lib/util.js @@ -0,0 +1,3 @@ +function choice (a){ return a[ Math.floor(Math.random() * a.length) ] } + +export { choice } \ No newline at end of file -- cgit v1.2.3-70-g09d2