summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2018-10-09 00:30:43 +0200
committerJules Laplace <julescarbon@gmail.com>2018-10-09 00:30:43 +0200
commit8848bc387d62e1667cdfa684f36c058d2619e6b3 (patch)
tree89c790f4bd6aa21fd12d3c943f4d5566a46bab28 /client
parenta411f4822a0b2fc72308bcd4af1bc3593aabd4ad (diff)
mass shooting sonification
Diffstat (limited to 'client')
-rw-r--r--client/data.js2
-rw-r--r--client/index.js111
-rw-r--r--client/lib/midi.js20
3 files changed, 113 insertions, 20 deletions
diff --git a/client/data.js b/client/data.js
index d48ccaa..d2a43aa 100644
--- a/client/data.js
+++ b/client/data.js
@@ -1,6 +1,6 @@
const files = [
// "gun_violence",
- "mass_shootings",
+ "mass_shootings_lite",
"gun_violence_by_month",
]
const parse = require('csv-parse')
diff --git a/client/index.js b/client/index.js
index e9a0873..58185a5 100644
--- a/client/index.js
+++ b/client/index.js
@@ -8,13 +8,12 @@ import {
midi_init,
play_note,
play_sequence,
- play_interval_sequence,
export_pattern_as_midi,
note_values,
MidiWriter,
} from './lib/midi'
import {
- requestAudioContext, ftom, norm, dataURItoBlob,
+ requestAudioContext, norm, dataURItoBlob,
get_bounds, get_diff_bounds,
transpose,
} from './lib/util'
@@ -36,7 +35,16 @@ midi_init()
/* initialization */
-let i = 0, datasets = {}, dataset = {}, bounds = {}, diff = []
+const mass_fields = [
+ "date", "timestamp",
+ "fatalities", "injured", "total_victims",
+ "age", "case", "weapon_type", "weapon_details"
+].reduce((a,b,i) => {
+ a[b] = i
+ return a
+}, {})
+
+let i = 0, mass_i = 0, datasets = {}, dataset = {}, bounds = {}, diff = []
let play_fn = play_sequence
data.load().then(lists => {
console.log(lists)
@@ -48,12 +56,93 @@ data.load().then(lists => {
name,
h: [name],
lines: [row.map(n => parseInt(n))],
+ play_fn: play_sequence,
}
})
+ datasets["Mass Shootings"] = lists.mass_shootings_lite
+ datasets["Mass Shootings"].name = "Mass Shootings"
+ datasets["Mass Shootings"].play_fn = play_mass_shootings
+ const lines = datasets["Mass Shootings"].lines.reverse()
+ const [min_y, ...rest] = lines[0][mass_fields.date].split('/')
+
+ datasets["Mass Shootings"].dates = lines.map(row => {
+ const [y, m, d] = row[mass_fields.date].split('/')
+ return (parseInt(y) - parseInt(min_y)) * 12 + parseInt(m)
+ })
+ datasets["Mass Shootings"].lines = [lines.map(row => Math.log(row[mass_fields.total_victims]))]
requestAudioContext(ready)
})
-//
+/* play function for mass shooting data w/ custom timing */
+
+let mass_rest = 0
+
+// export const note_values = [
+// [8, '8 measures', 8 * 512],
+// [4, '4 measures', 4 * 512],
+// [2, '2 measures', 2 * 512],
+// [1, 'whole note', 512],
+// [1/2, 'half note', 256],
+// [1/3, 'third note', [170, 170, 171]],
+// [1/4, 'quarter note', 128],
+// [1/5, 'fifth note', [51,51,51,51,52]],
+// [1/6, 'sixth note', [85, 85, 86, 85, 85, 86]],
+// [1/8, 'eighth note', 64],
+// [1/10, 'tenth note', [25,26,26,25,26,25,26,26,25,26]],
+// [1/12, 'twelfth note', [21,21,22, 21,21,22, 21,21,22, 21,21,22]],
+// [1/16, 'sixteenth note', 32],
+// [1/32, 'thirtysecond note', 16],
+// ]
+
+function play_mass_shootings(i, bounds, diff, note_time, channel="all", exporting) {
+ const { rows, min, max } = bounds
+ const y = 0
+ const x = i % rows[0].length
+ const n = rows[y][x]
+ let notes = [], midi_notes = []
+ console.log(i, mass_i, dataset.dates[mass_i])
+ while (i === dataset.dates[mass_i]) {
+ notes.push(dataset.lines[mass_i])
+ mass_i += 1
+ }
+ switch (notes.length) {
+ default:
+ case 0:
+ mass_rest += 1
+ break
+ case 1:
+ midi_notes.push(play_note( norm(n, min, max) * nx.multiply.value, 128, channel, exporting, mass_rest, 0))
+ break
+ case 2:
+ midi_notes.push(play_note( norm(n, min, max) * nx.multiply.value, 64, channel, exporting, mass_rest, 0))
+ midi_notes.push(play_note( norm(n, min, max) * nx.multiply.value, 64, channel, exporting, 0, 64))
+ break
+ case 3:
+ midi_notes.push(play_note( norm(n, min, max) * nx.multiply.value, 43, channel, exporting, mass_rest))
+ midi_notes.push(play_note( norm(n, min, max) * nx.multiply.value, 43, channel, exporting, 0, 43))
+ midi_notes.push(play_note( norm(n, min, max) * nx.multiply.value, 42, channel, exporting, 0, 85))
+ break
+ case 4:
+ midi_notes.push(play_note( norm(n, min, max) * nx.multiply.value, 32, channel, exporting, mass_rest))
+ midi_notes.push(play_note( norm(n, min, max) * nx.multiply.value, 32, channel, exporting, 0, 32))
+ midi_notes.push(play_note( norm(n, min, max) * nx.multiply.value, 32, channel, exporting, 0, 64))
+ midi_notes.push(play_note( norm(n, min, max) * nx.multiply.value, 32, channel, exporting, 0, 96))
+ break
+ }
+ if (mass_i > dataset.dates.length-1) {
+ mass_rest = 0
+ mass_i = 0
+ i = 0
+ } else {
+ i += 1
+ }
+ if (notes.length) {
+ mass_rest = 0
+ return [i, midi_notes]
+ }
+ mass_rest += 128
+ return [i, []]
+}
/* play next note according to sonification */
@@ -74,16 +163,12 @@ function play_next(){
function pick_dataset(key){
console.log('pick dataset:', key, datasets[key])
i = 0
+ mass_i = 0
+ mass_rest = 0
dataset = datasets[key]
bounds = get_bounds(dataset)
diff = get_diff_bounds(bounds.rows)
-}
-var behaviors = {
- sequence: { name: 'Sequence', fn: play_sequence },
- interval: { name: 'Intervals', fn: play_interval_sequence },
-}
-function pick_behavior(name){
- play_fn = behaviors[name].fn
+ play_fn = dataset.play_fn
}
/* build and bind the UI */
@@ -91,9 +176,7 @@ function pick_behavior(name){
function ready() {
scales.build_options(document.querySelector('#scale'))
build_options(document.querySelector('#dataset'), datasets, pick_dataset)
- build_options(document.querySelector('#behavior'), behaviors, pick_behavior)
- console.log(Nexus)
const dial_size = [50, 50]
Tone.Transport.bpm.value = DEFAULT_BPM
@@ -184,7 +267,7 @@ function ready() {
document.querySelector('.loading').classList.remove('loading')
document.querySelector('#dataset').value = 'Surrenders'
- pick_dataset('Surrenders')
+ pick_dataset('Mass Shootings')
play_next()
}
diff --git a/client/lib/midi.js b/client/lib/midi.js
index f2e0295..338526a 100644
--- a/client/lib/midi.js
+++ b/client/lib/midi.js
@@ -54,7 +54,7 @@ export function midi_init() {
/* play a single note */
-export function play_note(index, duration, channel="all", exporting=false){
+export function play_note(index, duration, channel="all", exporting=false, defer=0){
// console.log(index)
const scale = scales.current()
const freq = scale.index(index + Math.round(nx.offset.value), nx.octave.value)
@@ -71,9 +71,12 @@ export function play_note(index, duration, channel="all", exporting=false){
if (exporting || midiDevice) {
duration = duration || 60000 / Tone.Transport.bpm.value
if (! exporting) {
- midiDevice.playNote(note, channel, { duration })
- if (sendPitchBend) {
- midiDevice.sendPitchBend(cents, channel)
+ if (defer) {
+ setTimeout(() => {
+ play_midi_note(note, cents, channel, duration)
+ }, defer)
+ } else {
+ play_midi_note(note, cents, channel, duration)
}
}
} else {
@@ -82,6 +85,13 @@ export function play_note(index, duration, channel="all", exporting=false){
return note
}
+export function play_midi_note(note, cents, channel, duration) {
+ midiDevice.playNote(note, channel, { duration })
+ if (sendPitchBend) {
+ midiDevice.sendPitchBend(cents, channel)
+ }
+}
+
/* play the next note in sequence */
export function play_sequence(i, bounds, diff, note_time, channel="all", exporting) {
@@ -90,7 +100,7 @@ export function play_sequence(i, bounds, diff, note_time, channel="all", exporti
if (i >= count) i = 0
const y = Math.floor(i / rows[0].length)
const x = i % rows[0].length
- if (!x) console.log(y)
+ // if (!x) console.log(y)
const n = rows[y][x]
i += 1
if (i >= count) i = 0