Skip to content

Search documentation

Enter a title, API, or topic.

    ↑ ↓ NavigateEnter Open resultEsc Close

    <audio-live-view>

    Draw what is being heard right now. The newest column sits at the right edge and history slides left, so the strip reads as “now” scrolling away.

    This is the capability’s missing cardinality. Every other surface here draws data that already exists — a decoded clip, a peaks pyramid, a precomputed spectrogram. The only live path was <audio-view type="meter">, which is instantaneous: it has no time axis at all, so nothing could show what the microphone did a second ago. This element is the only live time-axis surface in the package.

    <script type="module">
    import { defineAudioLiveViewElement } from '@webmusic/audio/view/element';
    defineAudioLiveViewElement();
    </script>
    <audio-recorder id="rec"></audio-recorder>
    <audio-live-view source="#rec" type="waveform" window-seconds="4"></audio-live-view>
    <audio-live-view source="#rec" type="spectrogram" color-map="magma"></audio-live-view>
    @webmusic/audio/view/element<audio-live-view>
    Parameters
    <audio-live-view></audio-live-view>

    Two drawings live under one type, exactly as <audio-view> keeps waveform and spectrogram under one attribute: both are “append one column per frame and scroll”, and they differ only in how a column is painted. waveform reduces each frame to a min/max band; spectrogram paints one bin per row, low frequencies at the bottom, coloured through color-map. An unknown type falls back to waveform.

    The Element itself owns none of the live canvas machinery. Headless LiveViewController owns the borrowed-analyser sampling, scratch arrays, clock and bounded history; paintLiveProjection() owns only waveform/spectrogram pixels; published @webmusic/ui CanvasStage owns canvas creation, DPR/resize, RAF, accessible label, status overlay and teardown. The Element resolves attributes and the analyser source, then composes those three ports.

    source="#id" looks for a tap on the target in this order: .analyser, .inputAnalyser, .recorder?.inputAnalyser, .player?.analyser — so a player, a meter and a recorder all resolve without demanding one spelling. You can also assign .analyser directly, which overrides source.

    The node is borrowed. This element never creates, mutates or disposes it, so several views can read the same tap and disconnecting one leaves the others (and the recording) untouched.

    API
    Member Kind Default Description
    type attribute / property waveform waveform or spectrogram; unknown values fall back to waveform. Changing it starts a fresh history.
    source attribute — CSS selector of an element exposing an AnalyserNode. Changing it starts a fresh history.
    window-seconds attribute / .windowSeconds 5 Seconds of history the strip holds, minimum 0.5. Changing it starts a fresh history.
    height attribute 4rem Strip height — a bare number is px, or any CSS length.
    wave-color attribute currentColor Column fill for type="waveform".
    color-map attribute viridis Palette for type="spectrogram" (viridis · magma · grayscale · gray; an unknown name falls back to viridis).
    .analyser property — Borrow an AnalyserNode directly; overrides source. Never disposed here.
    .live property (getter) — Whether an analyser is currently resolved.
    webaudio:error event — detail = { error } if presenter sizing/animation or the draw adapter fails. { bubbles, composed }.

    The CanvasStage requests an initial draw and, when requestAnimationFrame is available, captures one column per frame while connected. It cancels its animation and resize observer on disconnect; hosts without RAF get the initial draw but no Element-owned timer fallback.

    With nothing to show, the shared status overlay says No live source — set source or .analyser until an analyser resolves, then Waiting for signal… until the first column arrives. Status text is accessible DOM rather than pixels painted into the canvas.

    Headless

    The model behind the drawing is LiveViewController from @webmusic/audio/view/headless. It borrows the analyser and owns type/window configuration, capture clock, reusable byte/float scratch arrays and a LiveScrollBuffer — a fixed-capacity ring covering the most recent windowSeconds. Capacity never grows, so a view that runs for hours has bounded history.

    import {createLiveViewController} from '@webmusic/audio/view/headless';
    import {paintLiveProjection} from '@webmusic/audio/view/render';
    const live = createLiveViewController({analyser, type: 'waveform', windowSeconds: 4});
    function draw(frame) {
    live.capture(frame.time);
    paintLiveProjection(frame, live.buffer, live.type, {waveColor: '#4a9eff'});
    }

    Changing analyser, type or window clears incompatible scratch/history state. The controller never schedules, mutates or disconnects the borrowed node. It is DOM-free and the painter accepts a structural canvas frame, so both halves are independently reusable without the Element.

    Styling

    The CanvasStage root is the labelled image; its internal canvas is presentational and its status overlay remains accessible. Its outer box uses the shared neutral --wm-component-* surface (or --wm-stage-surface-* for this presenter alone). Set the host height through the attribute, the waveform colour through wave-color or inherited color, and the full-bleed drawing viewport and status through --wm-stage-* / --wm-status-*:

    audio-live-view {
    color: #4a9eff; /* waveform columns, via currentColor */
    }
    <audio-live-view source="#rec" type="spectrogram" height="120" color-map="magma"></audio-live-view>

    Column width is the strip width divided by the ring’s capacity, so a shorter window-seconds gives wider columns rather than a stretched history. CanvasStage owns device-pixel sizing and redraws after host resize.