/**
A game of aural telephone — a simulation of the following instruction piece:
Each musician has their own base reaction time (from 150 - 350 ms), with minor variation from note to note. To interact:
You can also reassign who is watching whom by ctrl + left clicking or using the alphabet keys. For example, typing "a" then "w" will have the conductor listen to w, creating a loop. "a" then "a" will return the conductor to introversion.
The built in MIDI piano sound really isn't conducive to the found sound requirement, so I've made a recording of various objects in my room being struck by this network via Maple and Reason, featuring:
Velcro, lightswitches, cardboard boxes, water bottles, desk lights, door locks, heaters, springs, guitar cases...
As a deviation, I've also recorded a version where some of the musicians play parts of more standard instruments: xylophone and bass.
Further exploration is to be done with learning (faster reaction times when the next beat comes in an expected place) and the influence of others (the tendency to fall into a pattern related to nearby sounds).
*/ import promidi.*; int midiPort = 0; float musicianSize = 20; int reactionAvg = 250; // global mean int reactionVar = 100; // individual variance int reactionMod = 50; // per clap variation int fadeOut = 200; int minVelocity = 30; int maxVelocity = 100; int[] notes = { 45, 47, 48, 50, 52, 53, 55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72, 74, 76, 77, 79, 81, 83, 84, 86, 88}; Musicians m; PFont trebuchet; MidiIO midiIO; MidiOut midiOut; void setup() { size(470, 470); colorMode(HSB, 1); trebuchet = loadFont("TrebuchetMS-9.vlw"); textFont(trebuchet, 9); m = new Musicians(26, new ForceDirectedGraph()); midiIO = MidiIO.getInstance(this); midiOut = midiIO.openOutput(midiPort); } void draw() { background(1); m.update(); if(dragged != null) { Vector3D xy = m.fdg.remap(mouseX, mouseY); dragged.particle.moveTo(xy.x(), xy.y(), 0); } m.render(); } Musician dragged, watcher; void keyPressed() { if(key == ' ') m.clap(); else if(keyCode == TAB) { m.panic(); setup(); } else if(keyCode == BACKSPACE) watcher = null; else if(key >= 'a' && key <= 'z') connect(m.get(str(char(key)))); } void connect(Musician selected) { if(watcher == null) { watcher = selected; watcher.highlight(); } else { if(selected != null) if(watcher == selected) watcher.watch(null); else watcher.watch(selected); watcher.highlight(); watcher = null; } } void mousePressed() { Vector3D xy = m.fdg.remap(mouseX, mouseY); Musician cur = m.at(xy.x(), xy.y()); if(cur != null) { if(mouseButton == RIGHT) cur.forceClap(); else if(watcher != null || (keyPressed && keyCode == CONTROL)) connect(cur); else dragged = cur; } } void mouseReleased() { dragged = null; }