- world_zodiac.py: Chinese zodiac year/element + 2-hour animal, N/S summer (computed) - world_fire.py: live wildfires from NASA EONET (the fire element) - overlapping groups: a source can now belong to many concept groups at once (elements fire/earth/air/water/spirit, plus wealth + summer vibes) — they stack - transform.py: member_groups (1:many) replaces 1:1 grouping Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| .claude | ||
| strudel | ||
| viz | ||
| workers | ||
| .gitignore | ||
| cities.json | ||
| config.json | ||
| godstrument.txt | ||
| hub.py | ||
| matrix.py | ||
| normalize.py | ||
| README.md | ||
| recorder.py | ||
| requirements.txt | ||
| run.py | ||
| timewarp.py | ||
| transform.py | ||
🌍 GODSTRUMENT
An instrument where your hand, the room, and the planet are the same kind of thing.
Godstrument is a multi-modal sensor-fusion instrument. Every input — a hand sensor, the room's microphone, a satellite, the price of bitcoin, an earthquake on the other side of the Earth — is turned into a clean control signal and fired at a central hub. The hub normalizes and smooths everything, runs it through a modulation matrix, and pours the result out as MIDI/OSC for Ableton or TouchDesigner, plus a live web visualizer so you can watch the planet play.
Nothing here needs the physical sensors to run. The world-data feeds and a sensor simulator give you a fully playable instrument today; the ESP32 + ToF + light hardware slot into the exact same OSC contract when they arrive.
The architecture (everything is an OSC source)
hand / room / sky / markets / humanity outputs
───────────────────────────────────── ───────────
sim_esp32 ─┐ ┌─► OSC /out/* → Ableton / TouchDesigner
world_* ─┤ │
audio ─┼─► OSC 9000 ─► HUB ─► mod-matrix ─────┼─► MIDI CC / notes (optional, via IAC)
vision ─┤ normalize + One-Euro │
midi ─┘ + impulse envelopes └─► WebSocket 8765 → 🖥 visualizer (http 8088)
normalize.py— One Euro filter (jitter-free, low-lag), adaptive normalization (auto-scales unknown/drifting ranges to 0..1), impulse envelopes (events → decaying signals), slew.matrix.py— the patchbay: N sources × M destinations, each cable with an amount, response curve, polarity, optional threshold gate and quantize-to-scale (so a data stream picks notes in a key instead of wobbling formlessly).hub.py— receives all OSC, runs the control-rate clock, evaluates the matrix, drives the outputs + websocket.config.json— the current patch: which source routes to which destination. This is where you compose.workers/— one process per source, each just emits OSC.viz/index.html— the live console.
The starter patch
The sun opens the master filter · bitcoin volatility drives the hats and plays
the lead melody in a minor pentatonic · Delhi's air becomes distortion grit ·
every Wikipedia edit on Earth is a glitch burst · earthquakes open the reverb
void and choose the bass note · Tokyo's weather brightens the pads · aircraft
aloft thicken the drone · your (simulated) hand morphs the wavetable and feeds
the delay. Edit config.json to rewire any of it.
Run it
python3 -m venv .venv
./.venv/bin/pip install python-osc websockets
./.venv/bin/python run.py
Then open http://localhost:8088. That's it — real planetary data starts flowing in seconds.
Profiles: --profile core (default: simulator + all world feeds),
--profile world (data only), --profile all (adds mic/webcam/MIDI workers if
their optional libs are installed), --profile minimal (just the simulator).
Live data sources (all free, all keyless)
| Source | Feed | Character |
|---|---|---|
| Earthquakes | USGS all-hour GeoJSON | event triggers |
| Weather | Open-Meteo | slow / mood |
| Air quality | Open-Meteo air-quality | slow / grit |
| Solar wind | NOAA SWPC | slow LFO |
| ISS position | open-notify | drift |
| Crypto ticks | Binance websocket | sub-second chaos / rhythm |
| Aircraft | OpenSky | swarm / drone |
| Wikipedia edits | Wikimedia SSE stream | human pulse / glitch |
| Local sky | computed (NOAA solar position) | day/night LFO, per-venue |
| Humanity | modelled vital rates | births/deaths/growth velocity |
| Ephemeris / almanac | computed (Swiss Ephemeris) | planets, moon, planting calendar |
| National debt | US Treasury (no key) | slow dark ballast + daily churn |
| Inflation | US BLS CPI (no key) | grinding pressure |
| Human condition | World Bank (no key) | poverty, hunger, fertility, life expectancy |
The dark half (debt, inflation, pollution, quakes, the death rate) balances the bright (births, moon, harmony, fertility, daylight) — group your sources by feeling, not category: a "shadow" group, a "sad" group, whatever you blend. Congress-trade and conflict feeds are possible too but need keyed/curated sources.
Spells
Save a whole configuration — routes, groups, orbits, and the live mix (gains,
mutes, freezes) — as a named spell from the ⚙ panel's SPELLS section (save,
then load from the dropdown). Casting a saved spell restores the exact state.
They live in patches/*.json.
Performance mode
Press P for a clean projection view: the editing chrome vanishes, the source readouts declutter, and a rotating line of "dispatches from the world" (bitcoin at $62,902 · the moon is 81% lit · mercury is retrograde · M4.2 earthquake) appears for the audience. Open the console on a second monitor / projector and hit P. (Curated selections + MIDI-mappable display controls are the next layer.)
Strudel & MIDI voices
The ⚙ Web MIDI out already turns every destination into CC/notes, so any synth
becomes an output that "receives sources." strudel/godstrument.md is a starter
kit that drives a live Strudel track (free/open, no Ableton) from the hub's
CC map — plus a no-MIDI websocket path for a custom web-audio synth.
Playing it live — the performance layer
Raw data is honest but mechanical. The tweak layer (transform.py) lets you
play it: gain, offset (bend/lean), invert, freeze (a CDJ-style hold —
"stop the planet here"), and smooth (make a signal liquid or snap it tight).
Groups let one control lean on many sources at once. The starter patch
defines three — planet (local world), cosmos (shared sky), human — and
binds live controls to them in config.json:
"controls": [
{"src": "hand.open", "target": "@planet", "param": "gain", "min": 0.2, "max": 1.4},
{"src": "midi.cc.1", "target": "@cosmos", "param": "offset", "min": -0.3, "max": 0.3},
{"src": "midi.cc.20","target": "@planet", "param": "freeze", "min": 0.0, "max": 1.0}
]
src is any signal — a hardware knob (midi.cc.1, via the MIDI worker), a hand
sensor (hand.open, tof.near), or another data stream. So a physical knob, or
your open palm, becomes a macro over four data sources at once.
Time-warp — scratch a month of the planet
run.py --profile warp swaps the live quake + weather feeds for replay
workers (timewarp.py): they fetch history and play it back compressed on a
loop — 26 days of global earthquakes into 5 minutes, a week of weather into 4 —
so glacial data finally has agency in a track.
Because a replay has a playhead, you can scrub it. The warp section in
config.json binds a control to each loop's jog:
"warp": {
"quakes": {"port": 9101, "rate_src": "tof.cx", "nudge_src": "tof.near"}
}
So your hand (or a knob) sets the warp speed and shoves the playhead forward/back like a CDJ platter. A month of the Earth's seismicity becomes a loopable, scratchable rhythm.
Memory — record everything, replay anything
run.py --record runs recorder.py alongside the live rig, taps the hub, and
writes every signal + event to godstrument.db (SQLite — live and historical in
one file). Then replay_db.py can time-warp any recorded signal — not just
feeds with a public history API, but your own hand, the room mic, the ToF sensor:
python workers/replay_db.py --signals tof.cx,tof.cy,audio.rms --window last:3d --into 240
Footprint is small (change-based logging + a decimation cap). Measured:
~68 bytes/sample, so world data ≈ 80 MB/day (most of it the Wikipedia
firehose — throttle it and it's ~15 MB/day); fast local sensors at 20 Hz are the
main cost. A 3–5 day rolling buffer is a few hundred MB — trivial, fine on a
Pi's SD card. Prune with DELETE FROM samples WHERE t < <cutoff> + VACUUM.
recorder.py --stats prints size / signals / span.
Your own market — the dealgod feed
run.py --dealgod runs workers/world_dealgod.py, which reads price history from
the basegod warehouse (dealgod.price_events, ~4M rows) over the tailnet —
read-only, a single server-side aggregate query, no writes — bins it into an
activity curve and an average-price curve, and replays them compressed +
jog-scrubbable. Your deal-flow becomes a control source: market activity drives
the hats and nudges tempo; average price adds grit and plays the lead melody
(G dorian). Flags: --ssh, --days, --into. Point --ssh at a dashboard_ro
host for strict least-privilege networked access.
The heavens — real ephemeris, no downloads
world_ephemeris.py computes actual planetary positions with the Swiss Ephemeris
(Moshier mode — no data files, 3000 BC–3000 AD). Nothing is stored or fetched;
the sky is generated on demand, like the sun worker. It emits moon phase,
zodiac longitudes (natural LFOs from monthly to Saturn's 29-year wheel),
aspect tension/harmony, and retrograde flags. In the starter patch the
moon sets the master space, Mercury retrograde smears the delay, hard aspects add
grit, Saturn weights the drone. Ephemeris is computed, not ingested — the
opposite of big data (pip install pyswisseph, zero downloads).
The console is playable
The visualizer isn't just a display — it's a control surface. Click any source
sphere to mute / unmute it (it gets a red slash). The ⚙ button, top-right,
opens a panel with per-group mute / freeze / gain macros (planet, cosmos,
humanity, market, sky). Commands travel back to the hub over the same websocket,
so it stays in sync. Deep patch editing — routes, curves, ranges — still lives in
config.json.
Web MIDI (Chrome/Edge): the ⚙ panel has a WEB MIDI section — enable MIDI,
pick an out port and the destinations stream as CC/notes straight to your DAW
(no Python/IAC needed), pick an in port and hit MIDI learn to bind a knob
to any control (click a slider / mute / sphere, then move the knob; saved to
localStorage). Web MIDI needs a secure context: localhost works as-is; a
VPS-hosted console needs HTTPS (e.g. tailscale serve). The browser runs the
MIDI, so a remote-hosted page still drives the MIDI on your laptop.
The planting almanac
world_almanac.py computes the old sow-by-the-moon calendar from the same sky —
no data, no downloads. The zodiac's four elements cycle fire→earth→air→water, and
biodynamic tradition maps them to crop types, so the Moon walks a slow four-step
sequencer (changing every ~2.25 days): earth=root, water=leaf, air=flower,
fire=fruit/seed. It also emits waxing/waning (sow above vs below ground), the
Moon's ascending/descending declination cycle (~27.3d), and a fertility score.
The instrument's character can follow the moon through the garden.
Planetary orbits
Any group can be assigned a planet ("orbit": "neptune" in config.json); its
whole contribution then waxes and wanes at that planet's real relative orbital
rate. With orbit_base_seconds mapping one Earth year, Mercury (your market)
pulses every ~14s, Mars (humanity) every ~113s, Saturn (cosmos) every ~29min,
Neptune (the sky) every ~2.7h. Group your sources by planet and the solar system
becomes a bank of LFOs spanning seconds to a lifetime.
Wiring it on stage — the editing console
The console is fully live-editable, no config file needed:
- Drag a source sphere onto a destination to patch a new cable.
- Shift-click any node for its inspector — what it is, every cable in/out, an amount slider and an unpatch × per connection.
- ⌘/Ctrl-click spheres to multi-select, then group them into a new macro.
- Mutes, group macros, and Web MIDI live in the ⚙ panel.
It all travels to the hub over the websocket (add_route / remove_route /
set_route / make_group), which rewires the modulation matrix in real time.
Sending it to Ableton / TouchDesigner
- OSC: the hub streams
/out/<destination>floats to127.0.0.1:9001. Point TouchDesigner's OSC In, or a Max-for-Live OSC device, at that port. - MIDI: set
"midi": {"enabled": true}inconfig.json, create an IAC bus in Audio MIDI Setup → MIDI Studio,pip install python-rtmidi, and the hub sends CC + notes to it. Map the CCs in Ableton with MIDI-learn.
Adding real hardware later
The ESP32 firmware just has to send the same OSC addresses the simulator does
(/gs/tof/cx, /gs/tof/cy, /gs/tof/near, /gs/light/lux,
/gs/light/flash/event) to your Mac's IP on port 9000. Kill sim_esp32.py,
power on the board, nothing else changes.