A system reading

Hamnsignal Architecture

How live city data reaches SuperCollider without becoming literal sonification, and how the same ongoing work becomes sound, image, and stream.

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.

Continuous state
SMHI / RiverServicetemperature, wind, rain, light, river level
Semantic controlsdensity, brightness, drift, releaseScale, spread
Discrete events
Vasttrafikselected ferry and tram arrivals
Arrival gestureslow harbour landings, lateral rail reflections
Distribution
SuperCollider / relaysound events, phrase state, live-data state
ClientsIcecast audio plus WebSocket graphics

What 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
  }
}
RelayPolls SMHI precipitation and normalizes it from 0-3 mm into a decimal value between 0.0 and 1.0.
SuperCollider statebrightness down, density up, releaseScale up, stability down.
Granular memoryAbove zero rainfall, a capped, sparse reader takes brief fragments from a rolling memory of the warm body voices. It never reads an external rain recording, the cantus, or counterpoint.
Musical resultFuture body and cantus voices become darker, closer together in time, longer to release, and slightly less settled. At the same time, thin, wide fragments can appear as a low-level shimmer; rare east-west wind passes may travel across the stereo field.

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]
}
RelayPolls the Eriksberg level value and forwards it as riverLevel.
SuperCollider statedrift up, stability down, releaseScale up, spread up, brightness down.
Musical resultThe field leans darker, wider, more suspended, and less mechanically fixed.

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
  }
}
RelayPolls SMHI global radiation and normalizes it from 0-900 W/m2 into a decimal value between 0.0 and 1.0.
SuperCollider statebrightness up, density up, register up.
Musical resultThe next voices can become brighter, slightly more present, and more willing to sit higher.

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"
  }
}
RelayDeduplicates and rate-limits selected arrival events before sending /ambient/arrival.
SuperCollider gestureUses ambient_fm_voice, snaps pitch into the field, keeps it around 72-210 Hz, attack around 0.8 s, release around 11.5 s.
Musical resultA soft low arrival appears inside the harmony, more like a harbour body entering the piece than an alert.

Tram arrival: a lateral high reflection

{
  "type": "live_arrival",
  "path": "/live/arrival",
  "fields": {
    "site": "masthuggstorget",
    "mode": "tram",
    "line": "3"
  }
}
RelayApplies arrival spacing so repeated trams cannot flood the piece.
SuperCollider gestureUses ambient_high_pad, keeps pitch around 220-420 Hz, attack around 1.4 s, release around 8.8 s, pans by line and site.
Musical resultA thinner urban reflection crosses the field, brighter and more lateral than a ferry gesture.

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
  }
}
RelayPolls three independently assessed E45/Oscarsleden segments in one TrafficFlow request every two minutes during the 03:00-21:00 Europe/Stockholm musical window and every ten minutes during 21:00-03:00. Järntorget, Rosenlund, and Gullbergsvass remain available as a continuous observed traffic field. Traffic pressure requires five consecutive fresh readings across at least two sections: either a shared queue at or below 46 km/h, with each eligible detector carrying at least 180 vehicles per hour, or high combined movement above the local section thresholds (11,000 / 16,000 / 17,000 vehicles per hour). Two clearly free readings at or above 58 km/h, with flow below the lower release thresholds (8,500 / 12,000 / 13,000), release it after four minutes.
SuperCollider statenormalized_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.
Musical resultA confirmed condition slowly admits a fixed 152 BPM drum field: kick on every eighth note, backbeat on two and four, dark quarter-note cymbal ticks, and one restrained open tick after each fourth beat. It has no fills, tempo changes, or changing accents. Its arrangement never responds to traffic severity. Within an already confirmed condition, 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.

  1. 1
    Offer a field shapeThe active scene selects a low root and a simple shape such as root, third, fifth, octave, or added ninth.
  2. 2
    Snap each pitch into the living fieldThe candidate is brought toward the active harmonic field rather than entering as an unrelated absolute frequency.
  3. 3
    Test 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.
  4. 4
    Shape the envelope from current pressureDensity controls waiting; brightness, drift, spread, attack, and release describe how the permitted voice enters.
  5. 5
    Leave 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.

  1. 1
    Is 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.
  2. 2
    Choose a form stateOpening, ascent, suspension, repose, and return each constrain range, phrase length, motif choice, and tonal pull.
  3. 3
    Build a remembered contourThe system reuses, mutates, or rhetorically reshapes a small motif library. It avoids excessively tidy arches and mechanical repetition.
  4. 4
    Test 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.
  5. 5
    Protect 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.

  1. 1
    Measure 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.
  2. 2
    Scale rather than switchNear the boundary the veil is slight. As all three conditions become stronger, the porous treatment increases toward its full value.
  3. 3
    Veil 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.

  1. 1
    Is the arrival actually new?The relay ignores its initial snapshot, deduplicates known departures, and filters repeats.
    If not new: no sound is made.
  2. 2
    Has enough time passed?Global and site-level cooldowns stop the work from becoming a transport notification system.
    If too soon: suppress the gesture.
  3. 3
    Choose its musical characterFerries become low harbour landings through ambient_fm_voice. Trams become higher, airier, more lateral reflections through ambient_high_pad.
  4. 4
    Fit 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.

  1. 1
    Has the form opened the door?Normal counterpoint is only considered in repose or return, with several whole cantus phrases between responses.
  2. 2
    Is 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.
  3. 3
    Find 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.
  4. 4
    Answer 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.