# 🌍 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 ```bash 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`: ```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: ```json "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: ```bash 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 < ` + `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/` floats to `127.0.0.1:9001`. Point TouchDesigner's OSC In, or a Max-for-Live OSC device, at that port. - **MIDI:** set `"midi": {"enabled": true}` in `config.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.