The Short Version
Hamnsignal is not a web page that plays a file. It is a live system. SuperCollider continuously generates the music. A Rust relay listens to selected external sources and forwards normalized events and state into the musical system. The browser receives both a live audio stream and a separate graphics stream.
The essential rule is that external data does not directly move oscillators. It usually becomes musical pressure: slower release, darker tone, wider spread, more drift, or occasional civic gestures. Rain also has one deliberately quiet exception: it can open a sparse granular reading of the work's own recent harmonic memory. The city is translated before it is heard.
density, brightness, drift, releaseScale, spreadWhat Runs Where
Rust relay
Owns the boundary to the outside world. It polls, validates, normalizes, deduplicates, rate-limits, and forwards live data. It also broadcasts graphics events to connected browsers.
SuperCollider
Owns the musical interpretation. It decides how incoming state affects harmony, density, envelopes, gestures, phrase behavior, and synth parameters.
Browser
Owns the visual rendering and audio playback. It does not synthesize the music. It listens to Icecast for audio and to the relay WebSocket for graphics.
Two Kinds of External Data
The system keeps a hard distinction between slow conditions and punctual events. This matters musically.
Continuous State
Weather and river level are treated as atmosphere. They move slowly, are normalized into decimal values between 0.0 and 1.0, and decay when stale. They are allowed to change the climate of the piece, but not to shout.
- Rain can make the music denser, darker, less stable, and longer in release; actual rainfall can also open a very sparse internal granular layer.
- Wind can make pitch and image drift wider and less fixed.
- Light can increase brightness, register, and presence.
- River level can make the field darker, wider, and more lingering.
Discrete Events
Arrivals from selected Västtrafik stops are different. They are not averaged into a background number. They arrive as events, and SuperCollider may answer them with short-lived musical gestures.
- Ferries tend to become low harbour gestures.
- Trams tend to become lighter, more lateral urban reflections.
- Both are restrained by musical context so they do not become notification sounds.
What External Data Can Actually Do
External data can influence the piece live, but only through the contract the musical system exposes. The important controls are semantic, not raw DSP knobs.
density: how often new events are allowed to appear.register: whether the music leans lower or higher.spread: how wide the sound and image feel.brightness: how much upper colour and light are present.stability: how settled pitch, harmony, and image motion feel.drift: slow uncertainty, lateral pull, and weather-like motion.attackScale: how slowly sounds arrive.releaseScale: how long sounds let go.ampScale: conservative overall weight, not dramatic loudness automation.
The live-data layer can change how the piece breathes. It should not bypass musical restraint, rewrite the synth graph, or create hard jumps in oscillator parameters.
Examples From Relay To Synth
These examples show the current contract between the relay and SuperCollider. The numbers are normalized before they reach the musical layer, so the synth code is not reading millimetres of rain or raw river height directly. It receives a small set of musical controls and decides how to spend them. Rain additionally controls a tightly bounded granular-memory layer.
Rain: state pressure and granular memory
{
"type": "weather_state",
"path": "/live/weather/state",
"fields": {
"key": "precipitation",
"source": "weatherPrecipitation",
"raw_value": 1.5,
"normalized_value": 0.5
}
}
brightness down, density up, releaseScale up, stability down.At zero rain this layer is silent. Its density, duration, gain, filters, and stereo movement are strictly bounded, so rainfall changes the room without becoming a literal rain effect.
River level: slow harmonic weight
{
"path": "/ambient/bridge/input",
"args": ["river_level", "environment", "riverLevel", 0.555, true, 7200]
}
riverLevel.drift up, stability down, releaseScale up, spread up, brightness down.The river is therefore not a melodic line. It is closer to a pedal condition or acoustic gravity.
Light: higher presence
{
"type": "weather_state",
"path": "/live/weather/state",
"fields": {
"key": "global_radiation",
"source": "weatherGlobalRadiation",
"raw_value": 420,
"normalized_value": 0.467
}
}
brightness up, density up, register up.This is one reason the work can feel more awake in strong daylight without becoming louder in a simple volume-fader sense.
Ferry arrival: a low harbour gesture
{
"type": "live_arrival",
"path": "/live/arrival",
"fields": {
"site": "branno_husvik",
"mode": "ferry",
"line": "281"
}
}
/ambient/arrival.ambient_fm_voice, snaps pitch into the field, keeps it around 72-210 Hz, attack around 0.8 s, release around 11.5 s.Tram arrival: a lateral high reflection
{
"type": "live_arrival",
"path": "/live/arrival",
"fields": {
"site": "masthuggstorget",
"mode": "tram",
"line": "3"
}
}
ambient_high_pad, keeps pitch around 220-420 Hz, attack around 1.4 s, release around 8.8 s, pans by line and site.E45 traffic pressure: a temporary pulse field
{
"type": "traffic_state",
"path": "/live/traffic/state",
"fields": {
"key": "e45_queue",
"source": "trafikverket_traffic_flow",
"raw_value": 31.0,
"normalized_value": 0.595,
"musical_value": 0.0,
"musical_gate_open": false,
"queue_active": true
}
}
normalized_value is the observed traffic pressure for clients. The relay separately sends musical_value to SuperCollider; it is zero while musical_gate_open=false and can only open the dedicated pulse voice when the daytime gate and queue confirmation are both present. A level follower moves five percent of the remaining distance each second, producing the slow fade rather than a hard switch.normalized_value only adjusts voice amplitude modestly: 0.45 maps to 72 percent of the base amplitude and 1.0 maps to 100 percent. It fades in and out as a condition of the field, remains quieter than the main harbour voices, and bypasses the large master reverb.The traffic flow is not read as an alarm or a metronome whose speed follows traffic. It is translated into a temporary sense of civic time: the pulse may appear when the modern city is held in a queue or moves with shared intensity, then recede when that pressure has passed.
The main recurring voices still come from the scene and phrase engine. In those voices, brightness raises FM colour and filter light, stability reduces detune and pitch uncertainty, attackScale maps to about 2-8 seconds of arrival time, and releaseScale maps to about 5-16 seconds of letting go. That is why the same data can feel musical rather than descriptive: it changes phrasing, register, colour, and decay before it becomes sound.
Data Sources
Weather observations are based on SMHI Open Data, used under CC BY 4.0 and transformed into musical control values for Hamnsignal.
River level is obtained through Gothenburg City Open Data, via RiverService. Selected ferry and tram arrivals are obtained through the Vasttrafik API. E45 traffic-flow observations are obtained through Trafikverket Open Data, used under CC0 1.0. These sources are interpreted as slow conditions, occasional gestures, or a temporary pulse field; they do not directly produce sound.
Procedural Rules
The examples above explain what data is permitted to influence. This section explains what happens next: the live system treats every possible change as an offer, then decides whether it belongs in the music now. No incoming value has the authority to demand sound.
The governing rule: if an event would crowd the harmony, interrupt a more fragile voice, arrive too soon, or have no safe pitch, the preferred answer is silence, delay, a quieter fallback, or a different note.
Harmonic Body: How A Chord Is Allowed To Enter
The slow body chooses a root and a warm ratio shape. Each individual tone is tested against active voices, rather than being admitted as an entire block chord.
- 1Offer a field shapeThe active scene selects a low root and a simple shape such as root, third, fifth, octave, or added ninth.
- 2Snap each pitch into the living fieldThe candidate is brought toward the active harmonic field rather than entering as an unrelated absolute frequency.
- 3Test spacing and interval costThe new tone is compared with currently sounding voices. Tight clusters and severe intervals, especially high in the field, are penalized.If unsafe: choose another candidate, revoice a movable body tone, release a conflicting tone, or skip this event.
- 4Shape the envelope from current pressureDensity controls waiting; brightness, drift, spread, attack, and release describe how the permitted voice enters.
- 5Leave room after entryBody voices have scheduled releases and can yield when a cantus needs the register. A peripheral upper chord colour is additionally held back when a cantus or counterpoint is active, and releases quickly if one enters after it.
Cantus: How A Phrase Is Allowed To Speak
The cantus is not generated as a free melody. The system first selects a phrase state and a short motif, then every candidate note must pass register, spacing, and harmony checks. It normally occupies roughly 360-470 Hz and moves through a limited language of home, neighbour, warm third, fifth, and rare distant light.
- 1Is a phrase due?There must be sufficient space since the previous cantus. An anchor phrase is expected near the beginning, then returns only after several phrases and a cooldown.
- 2Choose a form stateOpening, ascent, suspension, repose, and return each constrain range, phrase length, motif choice, and tonal pull.
- 3Build a remembered contourThe system reuses, mutates, or rhetorically reshapes a small motif library. It avoids excessively tidy arches and mechanical repetition.
- 4Test every proposed noteIt must fit the cantus band, remain sufficiently separated from active cantus material, and avoid severe conflict with the current body.If it cannot fit: search another ratio, use a safe fallback, revoice a lower body tone, or omit the note.
- 5Protect the lineNew body tones can be moved away from the cantus. Higher cantus notes may use the more diffuse high-pad voice instead of a pointed lead sound.
Porous Cantus: A Guard Against The Isolated Horn
This rule changes timbre, not melody. It begins gently when a cantus rises above a low, open body and grows stronger with greater height and empty interval. The most isolated cases receive the full porous treatment.
- 1Measure exposureThe rule weighs three things continuously: cantus height above roughly 374 Hz, how far the body top has fallen below roughly 334 Hz, and the empty interval between them.
- 2Scale rather than switchNear the boundary the veil is slight. As all three conditions become stronger, the porous treatment increases toward its full value.
- 3Veil the coreThe cantus receives proportionally lower weight, a slower entrance, less bright FM core, and more air and softness. Its textural outer layer remains audible.
Civic Arrivals: How A Ferry Or Tram Is Allowed To Be Heard
Transport events are punctual and therefore pass through two layers of restraint: the relay first verifies the event, then SuperCollider makes it fit the living musical field.
- 1Is the arrival actually new?The relay ignores its initial snapshot, deduplicates known departures, and filters repeats.If not new: no sound is made.
- 2Has enough time passed?Global and site-level cooldowns stop the work from becoming a transport notification system.If too soon: suppress the gesture.
- 3Choose its musical characterFerries become low harbour landings through
ambient_fm_voice. Trams become higher, airier, more lateral reflections throughambient_high_pad. - 4Fit it to the current roomPitch is snapped into the field and constrained to the gesture's own register. Phrase state can soften or shift the profile before it enters.
Rare Counterpoint: A Response, Not A Layer
Counterpoint is a possible gesture within Hamnsignal's one continuous audio work. Its normal form is one low, quiet response after a cantus phrase. A rarer late form may enter at reduced weight while the final cantus note is still dissolving. It is part of the same restrained rule set, not a separate arrangement layer.
- 1Has the form opened the door?Normal counterpoint is only considered in repose or return, with several whole cantus phrases between responses.
- 2Is the field quiet enough?There can be no active cantus for the normal response, no recent civic arrival, and no crowded active-voice count. The overlap variant has its own late-phrase limits.If not: silence. A response is never owed.
- 3Find a low open toneIt searches roughly 248-342 Hz within the current field and the preceding cantus relation, rejecting congested or harsh candidates.If none exists: skip the response rather than forcing one.
- 4Answer once and slowlyOne low, long, softer voice enters. A second continuation is only a rare later possibility, never a parallel companion line.
The SuperCollider Boundary
SuperCollider receives normalized values and events through OSC. The control API validates and clamps values before they reach the scene and synth layers. The scene then decides what can happen musically at that moment.
This boundary is intentional. It lets the system accept new outside sources later without exposing fragile internals. A future data source should not need to know how the FM voice is built. It should only say what kind of pressure or event it represents.
The Internal Conductor
Live data is not the whole composition. An internal conductor also moves through slow dramaturgical states. It changes how receptive the work is to harbour, sea, weather, civic pressure, memory, and return.
This prevents the piece from becoming a dashboard. Rain does not always mean the same musical result. It is filtered through the current phrase state and the long-form emotional condition of the work.
Sound And Image Are Parallel
The sound and the image share event sources, but the browser is not a literal oscilloscope and not a copy of the SuperCollider server. The relay broadcasts normalized graphics events. The browser interprets them as fields, traces, rain, civic arrivals, and slow visual drift.
This means another client could exist. A mobile client, large wall client, or ASCII client can read the same event stream and produce a different visual interpretation of the same ongoing artwork.
Audio Transport
Audio is deliberately separate from graphics. SuperCollider produces the sound, JACK provides the headless audio route, ffmpeg encodes it, Icecast serves it, and the browser plays it as a live stream.
The relay does not own browser audio. That separation keeps audio transport replaceable and makes the web client simpler: graphics come over WebSocket, audio comes over HTTP.
What Can Change Live
Safe live changes
- semantic mappings
- arrival interpretation
- density and restraint rules
- which external sources are enabled
- relay forwarding to SuperCollider
Usually requires restart
- SynthDef topology
- master reverb structure
- JACK or audio routing
- Icecast service configuration
- browser code already loaded by a client
Why The Data Is Restrained
The piece is built around acceptance, consolation, civic memory, and slow environmental pressure. Direct sonification would be too literal and too nervous. The architecture exists to slow the world down before it enters the music.
If one rule summarizes the system, it is this: external data may change the conditions of the room, but the room decides how to answer.