summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorJules Laplace <jules@okfoc.us>2017-04-23 22:17:43 -0400
committerJules Laplace <jules@okfoc.us>2017-04-23 22:17:43 -0400
commited62a07b37e666d1a5e972847460dee7f90b3987 (patch)
tree0ea651522ba3d46f58585b3847c175b8221b7e91 /client
triangle interval map
Diffstat (limited to 'client')
-rw-r--r--client/index.js56
-rw-r--r--client/lib/color.js31
-rw-r--r--client/lib/kalimba.js46
-rw-r--r--client/lib/keys.js39
-rw-r--r--client/lib/util.js3
5 files changed, 175 insertions, 0 deletions
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 = `<div>${i}<\/div><div>\/</div><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