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 } from './lib/util' let instrument = kalimba let hash = window.location.hash || window.location.search if (hash.match('sin') || hash.match('organ')) { instrument = organ } 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 let erasing = false let lastFreq = 0 let notes = [] requestAudioContext( () => { for (var i = 0; i < ws; i++) { notes[i] = [] for (var j = 0; j < hs; j++) { notes[i][j] = add(i, j) } } life.init(notes, assign) }) function play(freq) { freq.playing = true instrument.play(freq.frequency) freq.div.classList.add('playing') life.assign_item(freq, true) } function pause(freq) { 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) } else { pause(freq) } } function toggle(freq) { assign(freq, freq.playing = !freq.playing) } 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 = `
${a}<\/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) 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) if (dragging) { if (erasing) { pause( freq ) } else { 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 } 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) { if (dragging) { if (erasing) { pause( freq ) } else { toggle( freq ) } } lastFreq = freq } }) document.addEventListener('touchend', () => { dragging = false }) } function swap_instrument(){ instrument = (instrument === kalimba) ? organ : kalimba } let life_bpm = 50 window.addEventListener("keydown", keydown, true) function keydown(e){ // console.log(e.keyCode) switch (e.keyCode){ case 32: // space life.toggle() break case 38: // up life_bpm += e.shiftKey ? 1 : 5 life_bpm = Math.max(1, life_bpm) life.setTempo(life_bpm) break case 40: // down life_bpm -= e.shiftKey ? 1 : 5 life.setTempo(life_bpm) break case 83: // s swap_instrument() break } } keys.listen(function(index){ // const freq = scales.current().index(index) // document.body.style.backgroundColor = color( index / scales.current().scale.length ) // instrument.toggle(freq) })