Everything — your hand, the room, a satellite, the markets, the sky — becomes an OSC control signal fused through a modulation matrix. Includes: - hub + normalize (One-Euro) + matrix (curves/gates/quantize) + transform (tweaks/groups) - 20+ workers: sim sensors, 8 keyless world feeds, ephemeris/almanac/clock (computed), time-warp replay (quakes/weather/db), and the dealgod market warehouse feed - planetary orbital LFOs, SQLite recorder, city targeting - live browser console: mute, group macros, drag-to-patch, inspector, Web MIDI Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
68 lines
2.3 KiB
Python
68 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""The actual solar wind hitting Earth right now, opening the master filter — playing the sun.
|
|
NOAA SWPC reports live proton speed (km/s) of the solar wind stream; a faster gust is a
|
|
brighter, more open sound. The star's mood becomes the master filter cutoff."""
|
|
|
|
import argparse
|
|
import json
|
|
import time
|
|
import urllib.request
|
|
|
|
from pythonosc.udp_client import SimpleUDPClient
|
|
|
|
NAME = "world_sun"
|
|
URL = "https://services.swpc.noaa.gov/products/summary/solar-wind-speed.json"
|
|
POLL_INTERVAL = 60.0 # seconds between API polls (be kind to NOAA)
|
|
REEMIT_INTERVAL = 5.0 # re-fire last known value this often
|
|
UA = "Godstrument/1.0 (world_sun worker; +https://github.com/godstrument)"
|
|
|
|
|
|
def fetch_speed():
|
|
"""Fetch current solar-wind proton speed (km/s). Returns float or None on failure."""
|
|
req = urllib.request.Request(URL, headers={"User-Agent": UA})
|
|
with urllib.request.urlopen(req, timeout=15) as resp:
|
|
data = json.load(resp)
|
|
# Response is a JSON list; take [0]["proton_speed"].
|
|
return float(data[0]["proton_speed"])
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser(description="Emit live solar-wind speed as OSC.")
|
|
ap.add_argument("--host", default="127.0.0.1")
|
|
ap.add_argument("--port", type=int, default=9000)
|
|
args = ap.parse_args()
|
|
|
|
client = SimpleUDPClient(args.host, args.port)
|
|
print(f"[{NAME}] emitting /gs/sun/speed every {int(REEMIT_INTERVAL)}s")
|
|
|
|
last_value = None
|
|
last_poll = 0.0
|
|
backoff = 5.0
|
|
|
|
while True:
|
|
now = time.monotonic()
|
|
|
|
# Poll the API at most once per POLL_INTERVAL.
|
|
if now - last_poll >= POLL_INTERVAL or last_value is None:
|
|
try:
|
|
last_value = fetch_speed()
|
|
last_poll = now
|
|
backoff = 5.0 # reset backoff on success
|
|
except Exception as e:
|
|
print(f"[{NAME}] fetch failed: {e}; retrying in {backoff:.0f}s")
|
|
time.sleep(backoff)
|
|
backoff = min(backoff * 2, 120.0)
|
|
continue
|
|
|
|
# Re-emit last known value.
|
|
try:
|
|
client.send_message("/gs/sun/speed", float(last_value))
|
|
except Exception as e:
|
|
print(f"[{NAME}] send failed: {e}")
|
|
|
|
time.sleep(REEMIT_INTERVAL)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|