summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2018-10-08 01:05:13 +0200
committerJules Laplace <julescarbon@gmail.com>2018-10-08 01:05:13 +0200
commit9e824cc6d358fc902b27e00e5a1e8f88e3610823 (patch)
treeb2aa1f0e514ddcc9a6843ba42481b75ae7127329 /client
parent81adbc30b2dbf9a24917694e22042762a930e00d (diff)
group and midi stuff
Diffstat (limited to 'client')
-rw-r--r--client/data.js5
-rw-r--r--client/index.js85
-rw-r--r--client/lib/midi.js13
-rw-r--r--client/lib/ui.js2
-rw-r--r--client/lib/util.js46
5 files changed, 53 insertions, 98 deletions
diff --git a/client/data.js b/client/data.js
index 733d3bf..1ddd664 100644
--- a/client/data.js
+++ b/client/data.js
@@ -1,6 +1,7 @@
const files = [
// "gun_violence",
"mass_shootings",
+ "gun_violence_by_month",
]
const parse = require('csv-parse')
@@ -9,7 +10,7 @@ const dataPromises = files.map(name => {
return rows.text()
}).then(text => {
return new Promise((resolve, reject) => {
- parse(text, {}, (err, lines) => resolve(lines))
+ parse(text, {}, (_, lines) => resolve(lines))
})
}).then(lines => {
console.log(name, lines)
@@ -24,7 +25,7 @@ const dataPromises = files.map(name => {
const allPromises = Promise.all(dataPromises).then(data => {
return data.reduce((a,b) => {
console.log(b)
- a[b.name.replace(/-/g, '_')] = b
+ a[b.name] = b
return a
}, {})
})
diff --git a/client/index.js b/client/index.js
index 65b15d3..74c9252 100644
--- a/client/index.js
+++ b/client/index.js
@@ -9,8 +9,10 @@ import {
play_note,
play_sequence,
play_interval_sequence,
+ export_pattern_as_midi,
note_values,
MidiWriter,
+ transpose,
} from './lib/midi'
import {
requestAudioContext, ftom, norm, dataURItoBlob,
@@ -19,18 +21,16 @@ import {
import {
update_value_on_change,
update_radio_value_on_change,
- build_options
+ build_options,
+ nx
} from './lib/ui'
import * as data from './data'
const DEFAULT_BPM = 60
-const nx = window.nx = {}
-
let recorder = null
let recording = false
-let sendPitchBend = false
midi_init()
@@ -39,81 +39,20 @@ midi_init()
let i = 0, datasets = {}, dataset = {}, bounds = {}, diff = []
let play_fn = play_sequence
data.load().then(lists => {
- console.log(lists)
- datasets = lists.map(list => {
- list.shift()
- switch(list.name) {
- case 'gun_violence':
- return gun_violence_melody(list)
- case 'mass_shootings':
- return {
- ...list,
- lines: list.lines.map(line => {
- // 0 case name
- // 1 location
- // 2 date
- // 3 summary
- // 4 fatalities
- // 5 injured
- // 6 total_victims
- // 7 location
- // 8 age_of_shooter
- // 9 prior_signs_mental_health_issues
- // 10 mental_health_details
- // 11 weapons_obtained_legally
- // 12 where_obtained
- // 13 weapon_type
- // 14 weapon_details
- // 15 race
- // 16 gender
- // 17 sources
- // 18 mental_health_sources
- // 19 sources_additional_age
- // 20 latitude
- // 21 longitude
- // 22 type (Spree / Mass)
- // 23 year
- })
- }
- break
- }
- })
- pick_dataset('mass shootings')
- requestAudioContext(ready)
+ // pick_dataset('mass shootings')
+ // requestAudioContext(ready)
+ console.log(lists)
+ transpose(lists.gun_violence_by_month.lines)
})
-function gun_violence_melody(list){
- let melody = []
- let lookup = {}
- let last = Date.now()
- let last_y = 2018
- let last_m = 3
- list.lines.forEach(line => {
- let [
- incident_id, date, state, city_or_county, address, n_killed, n_injured,
- incident_url, source_url, incident_url_fields_missing, congressional_district,
- gun_stolen, gun_type, incident_characteristics, latitude, location_description, longitude,
- n_guns_involved, notes,
- participant_age, participant_age_group, participant_gender,
- participant_name, participant_relationship, participant_status,
- participant_type,
- sources,
- state_house_district, state_senate_district
- ] = line
- let [ y, m, d ] = date.split('-')
- })
- return {
- ...list,
- lines: melody,
- }
-}
+//
/* play next note according to sonification */
function play_next(){
let note_time = 120000 / Tone.Transport.bpm.value * note_values[nx.timing.active][0] * nx.duration.value
setTimeout(play_next, note_time)
- let [new_i, notes] = play_fn(i, bounds, note_time)
+ let [new_i, notes] = play_fn(i, bounds, diff, note_time)
i = new_i
if (recording) {
let timing = note_values[nx.timing.active][2]
@@ -141,7 +80,7 @@ function pick_behavior(name){
/* build and bind the UI */
-function ready () {
+function ready() {
scales.build_options(document.querySelector('#scale'))
build_options(document.querySelector('#dataset'), datasets, pick_dataset)
build_options(document.querySelector('#behavior'), behaviors, pick_behavior)
@@ -205,7 +144,7 @@ function ready () {
const export_midi_button = document.querySelector('#export_midi')
export_midi_button.addEventListener('click', () => {
- export_pattern_as_midi(dataset.name, bounds, nx.tempo.value, nx.timing.active, play_fn)
+ export_pattern_as_midi(dataset.name, bounds, diff, nx.tempo.value, nx.timing.active, play_fn)
})
const record_midi_button = document.querySelector('#record_midi')
diff --git a/client/lib/midi.js b/client/lib/midi.js
index 05fd708..f2e0295 100644
--- a/client/lib/midi.js
+++ b/client/lib/midi.js
@@ -1,10 +1,13 @@
import Tone from 'tone'
import WebMidi from 'webmidi'
import scales from './scales'
-import { ftom } from './util'
+import { ftom, norm } from './util'
import kalimba from './kalimba'
+import { nx } from './ui'
+
let midiDevice
+let sendPitchBend = false
export const MidiWriter = require('midi-writer-js')
@@ -81,7 +84,7 @@ export function play_note(index, duration, channel="all", exporting=false){
/* play the next note in sequence */
-function play_sequence(i, bounds, note_time, channel="all") {
+export function play_sequence(i, bounds, diff, note_time, channel="all", exporting) {
const { rows, min, max } = bounds
const count = rows.length * rows[0].length
if (i >= count) i = 0
@@ -97,7 +100,7 @@ function play_sequence(i, bounds, note_time, channel="all") {
/* play the next row as an interval */
-function play_interval_sequence(i, bounds, note_time, channel="all") {
+export function play_interval_sequence(i, bounds, diff, note_time, channel="all", exporting) {
const { rows, min, max } = bounds
const count = rows.length
if (i >= count) i = 0
@@ -118,7 +121,7 @@ function play_interval_sequence(i, bounds, note_time, channel="all") {
/* generate a 1-track midi file by calling the play function repeatedly */
-function export_pattern_as_midi(datasetName, bounds, tempo, timingIndex, play_fn) {
+export function export_pattern_as_midi(datasetName, bounds, diff, tempo, timingIndex, play_fn) {
const behavior = document.querySelector('#behavior').value
const { rows } = bounds
let count = behavior === 'sequence' ? rows[0].length * rows.length : rows.length
@@ -128,7 +131,7 @@ function export_pattern_as_midi(datasetName, bounds, tempo, timingIndex, play_fn
let midi_track = new MidiWriter.Track()
midi_track.setTempo(tempo)
for (let i = 0, len = count; i < len; i++) {
- notes = play_fn(i, bounds, exporting = true)[1]
+ notes = play_fn(i, bounds, note_time, "all", true)[1]
if (timing.length) {
note_time = timing[i % timing.length]
} else {
diff --git a/client/lib/ui.js b/client/lib/ui.js
index f344f0e..b0909cd 100644
--- a/client/lib/ui.js
+++ b/client/lib/ui.js
@@ -1,3 +1,5 @@
+export const nx = window.nx = {}
+
/* ui - update an int/float value */
export function update_value_on_change(el, id, is_int, fn) {
diff --git a/client/lib/util.js b/client/lib/util.js
index 0685b9d..f33146f 100644
--- a/client/lib/util.js
+++ b/client/lib/util.js
@@ -1,21 +1,21 @@
import Tone from 'tone'
import StartAudioContext from './startAudioContext'
-const isIphone = (navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))
-const isIpad = (navigator.userAgent.match(/iPad/i))
-const isAndroid = (navigator.userAgent.match(/Android/i))
-const isMobile = isIphone || isIpad || isAndroid
-const isDesktop = ! isMobile
+export const isIphone = (navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))
+export const isIpad = (navigator.userAgent.match(/iPad/i))
+export const isAndroid = (navigator.userAgent.match(/Android/i))
+export const isMobile = isIphone || isIpad || isAndroid
+export const isDesktop = ! isMobile
document.body.classList.add(isMobile ? 'mobile' : 'desktop')
-const browser = { isIphone, isIpad, isMobile, isDesktop }
+export const browser = { isIphone, isIpad, isMobile, isDesktop }
-function choice (a){ return a[ Math.floor(Math.random() * a.length) ] }
-function mod(n,m){ return n-(m * Math.floor(n/m)) }
-function norm(n, min, max){ return (n - min) / (max - min) }
+export function choice (a){ return a[ Math.floor(Math.random() * a.length) ] }
+export function mod(n,m){ return n-(m * Math.floor(n/m)) }
+export function norm(n, min, max){ return (n - min) / (max - min) }
-function requestAudioContext (fn) {
+export function requestAudioContext (fn) {
if (isMobile) {
const container = document.createElement('div')
const button = document.createElement('div')
@@ -55,7 +55,7 @@ function requestAudioContext (fn) {
}
}
-function dataURItoBlob(dataURI) {
+export function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);
@@ -79,14 +79,14 @@ function dataURItoBlob(dataURI) {
return blob;
}
-function ftom(f) {
+export function ftom(f) {
// return (Math.log(f) - Math.log(261.626)) / Math.log(2) + 4.0
return 69 + 12 * Math.log2(f / 440)
}
-function mtof(m) {
+export function mtof(m) {
return 440 * Math.pow(2, (m - 69) / 12)
}
-function tap (fn) {
+export function tap (fn) {
return (e) => {
if (browser.isMobile) fn()
else if (e.press) fn()
@@ -95,7 +95,7 @@ function tap (fn) {
/* get minimum and maximum variance from row-to-row */
-function get_diff_bounds(rows){
+export function get_diff_bounds(rows){
const diffs = rows.map(row => {
const row_min = Math.min.apply(Math, row)
const row_max = Math.max.apply(Math, row)
@@ -108,7 +108,7 @@ function get_diff_bounds(rows){
/* get minimum and maximum values from a dataset */
-function get_bounds(dataset){
+export function get_bounds(dataset){
let rows = dataset.lines
// rows.forEach(row => row.shift())
rows = rows.map(a => a.map(n => parseFloat(n)))
@@ -125,7 +125,17 @@ function get_bounds(dataset){
return { rows, max, min }
}
+/* transpose a 2D array */
-
-export { choice, mod, norm, browser, get_bounds, get_diff_bounds, requestAudioContext, ftom, mtof, tap, dataURItoBlob }
+export function transpose(a) {
+ let i_len = a.length, j_len = a[0].length
+ let T = new Array(i_len)
+ for (let i = 0; i < i_len; i++) {
+ T[i] = new Array(j_len)
+ for (var j = 0; j < j_len; j++) {
+ T[i][j] = a[j][i]
+ }
+ }
+ return T
+}