Vision
FeedBack can already score from multiple audio inputs — the desktop engine runs up to 8 independent source chains, and splitscreen can bind panels to extra capture devices. But managing those inputs is raw and single-input-minded: the Audio page models exactly one device+channel, splitscreen panels pick inputs by raw device name with a per-panel channel cycle and a manual ±5 ms latency nudge, and the tuner only listens to the primary input.
The proposal: named input profiles. You configure an input once — "Lead Guitar", "Bass", "Rhythm" — calibrate it, and then reference it by name everywhere:
- Audio page: create/manage profiles, see live meters and tuner readouts for every connected instrument at once, run calibration per profile.
- Splitscreen: each panel's input picker becomes a dropdown of profile names instead of raw device/channel controls.
- Tuner: an input selector so each band member can tune their own instrument.
Band use case: lead guitar on interface A input 1, rhythm on input 2, bass on interface B — set up once, calibrated, referenced by name from then on.
What already exists (so this is mostly UX + plumbing, not engine work)
- Engine (feedback-desktop):
SourcePool holds up to 8 SourceChains; each has its own YIN pitch detector, optional ML polyphonic detector (Basic Pitch/ONNX), onset detector, chart-scoring NoteVerifier + ChordScorer, per-source gain/meters/monitor-mute, and per-source latency offsets (setVerifierAutoOffset + setVerifierUserOffset, summed). Up to 3 extra capture devices via ExtraInputs. The full per-source N-API/IPC surface (addSource, bindInputDevice, setSourceInputChannel, getSourcePitchDetection, getSourceNoteVerdicts, setSourceChart, …) is already exposed through the preload bridge.
- note_detect:
createNoteDetector({ ownSource: true, deviceKey, channel, verifierOffsetMs }) already allocates its own engine source per instance, and launchCalibration() already measures level / channel / latency (used by input_setup's onboarding wizard).
- splitscreen: per-panel detectors with independent scoring already work — it's the selection UX (raw device names, channel cycling, manual nudge) that doesn't scale to a band.
What's missing: a naming + persistence + calibration-reuse layer, and consumers that speak it.
Proposed shape (open for discussion)
Profile = { id, name, icon, role (lead/rhythm/bass/any), deviceType, deviceName, channel, gainDb, calibratedOffsetMs, manualOffsetMs, noteDetection: { engine: "yin" | "ml" } }
- Persisted desktop-side (userData JSON,
feedback-input-profiles.json) since device identities are machine-local. Main process owns load/save; changes broadcast to all windows.
- A small runtime registry (
window.feedBackInputProfiles) published by the audio_engine plugin: list / acquire / release, owning the deviceKey 1..3 allocation + bindInputDevice refcounting so audio panel, splitscreen, tuner, and note_detect can't fight over extra-device slots.
role lets splitscreen auto-assign profiles to panels using the existing lead/rhythm/bass arrangement matching.
- Zero visual change by default: the Audio page looks exactly as it does today until you press "+ Add input"; profiles then render as cards (name, device/channel, live meter, live pitch readout, Calibrate button).
- Calibration reuses note_detect's existing wizard, targeted at a profile's device+channel, writing the measured offset/gain back into the profile.
- Everything feature-detects across repos so each piece lands independently and degrades to today's behavior (e.g. splitscreen falls back to its current raw pickers when no profiles exist).
Rough phasing
- feedback-desktop: profile store + IPC (
audio.profiles.* on the bridge) + a per-source gain export the engine is missing. Inert on its own.
- feedback-desktop (audio_engine panel): "+ Add input" → profile cards, live all-at-once meters/tuner readouts, runtime registry/allocator.
- note_detect:
createNoteDetector({ profileId }) + launchCalibration({ profileId }) with write-back.
- splitscreen: per-panel profile dropdown (by name), prefs, role auto-assign.
- feedback (tuner): input selector listing profile names, reading per-source raw frames.
Open questions — input welcome
- Should profiles also be published into the
audio-input capability domain as named sources (so input_setup / other capability consumers see them), or stay a separate desktop-side registry? The domain is single-select today; profiles are inherently multi-select.
- Offset model: calibrated + manual as separate summed fields (proposed) vs a single effective value?
- Should two profiles be allowed on the same device+channel (e.g. differently-calibrated variants)? Proposed: yes, with an informational badge.
- Per-profile detection engine (
yin vs ml/Basic Pitch) — worth exposing in v1, or default yin everywhere and add later?
- Anything web-only worth doing? This design is desktop-first since multi-device capture is a desktop-bridge capability; the browser path (getUserMedia) stays single-input.
Detailed file-level plan exists (engine APIs verified against source); happy to share in a follow-up comment or split per-repo issues once the shape settles.
Vision
FeedBack can already score from multiple audio inputs — the desktop engine runs up to 8 independent source chains, and splitscreen can bind panels to extra capture devices. But managing those inputs is raw and single-input-minded: the Audio page models exactly one device+channel, splitscreen panels pick inputs by raw device name with a per-panel channel cycle and a manual ±5 ms latency nudge, and the tuner only listens to the primary input.
The proposal: named input profiles. You configure an input once — "Lead Guitar", "Bass", "Rhythm" — calibrate it, and then reference it by name everywhere:
Band use case: lead guitar on interface A input 1, rhythm on input 2, bass on interface B — set up once, calibrated, referenced by name from then on.
What already exists (so this is mostly UX + plumbing, not engine work)
SourcePoolholds up to 8SourceChains; each has its own YIN pitch detector, optional ML polyphonic detector (Basic Pitch/ONNX), onset detector, chart-scoringNoteVerifier+ChordScorer, per-source gain/meters/monitor-mute, and per-source latency offsets (setVerifierAutoOffset+setVerifierUserOffset, summed). Up to 3 extra capture devices viaExtraInputs. The full per-source N-API/IPC surface (addSource,bindInputDevice,setSourceInputChannel,getSourcePitchDetection,getSourceNoteVerdicts,setSourceChart, …) is already exposed through the preload bridge.createNoteDetector({ ownSource: true, deviceKey, channel, verifierOffsetMs })already allocates its own engine source per instance, andlaunchCalibration()already measures level / channel / latency (used by input_setup's onboarding wizard).What's missing: a naming + persistence + calibration-reuse layer, and consumers that speak it.
Proposed shape (open for discussion)
Profile =
{ id, name, icon, role (lead/rhythm/bass/any), deviceType, deviceName, channel, gainDb, calibratedOffsetMs, manualOffsetMs, noteDetection: { engine: "yin" | "ml" } }feedback-input-profiles.json) since device identities are machine-local. Main process owns load/save; changes broadcast to all windows.window.feedBackInputProfiles) published by the audio_engine plugin:list / acquire / release, owning the deviceKey 1..3 allocation +bindInputDevicerefcounting so audio panel, splitscreen, tuner, and note_detect can't fight over extra-device slots.rolelets splitscreen auto-assign profiles to panels using the existing lead/rhythm/bass arrangement matching.Rough phasing
audio.profiles.*on the bridge) + a per-source gain export the engine is missing. Inert on its own.createNoteDetector({ profileId })+launchCalibration({ profileId })with write-back.Open questions — input welcome
audio-inputcapability domain as named sources (so input_setup / other capability consumers see them), or stay a separate desktop-side registry? The domain is single-select today; profiles are inherently multi-select.yinvsml/Basic Pitch) — worth exposing in v1, or default yin everywhere and add later?Detailed file-level plan exists (engine APIs verified against source); happy to share in a follow-up comment or split per-repo issues once the shape settles.