Commit Graph
146 Commits
Author SHA1 Message Date
EdnunpandClaude Opus 4.8 90a1ab3257 Visual polish pass: modern font, light/dark theme, app icon, accent, health cue
A do-no-harm cosmetic pass — all changes are colours/fonts/spacing/icons only; no control types or
accessibility wiring changed, so NVDA behaviour is unchanged. Held for next release.

 * Segoe UI 9pt app-wide (ApplicationDefaultFont) — was the legacy default font.
 * Follow the Windows light/dark theme via Application.SetColorMode, driven by a new AppConfig.ThemeMode
   ("system"/"light"/"dark", default system) read at startup in Program.Main (guarded — a failure just
   leaves the classic theme). New Preferences → General → "Colour theme (Alt+T)" picker; takes effect
   next launch.
 * Custom app icon (equalizer-bars motif): multi-size remsound.ico, embedded + set as ApplicationIcon,
   on the main window and the tray icon (dialogs are FixedDialog, no title-bar icon).
 * New Theme helper (accent colour, section-header + dialog-heading label factories, health colours)
   and StatusDot (a small NVDA-invisible colour dot).
 * Connectivity tab grouped under "Peers" and "Connect manually, and locking" section headers.
 * Connection-health colour dot in the status footer (green streaming / amber idle / grey off); the
   health text is unchanged.
 * Bold headings on the Rename peer, Add EQ band and Manage named peers dialogs.
 * EQ curve: soft translucent fill under the response line.

Audio I/O tab left un-restructured on purpose (its conditional ASIO rows make a blind layout change too
risky); its existing labels already read clearly. Manual updated. Build clean; --selftest passes;
deployed to both test folders.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 08:47:26 +01:00
EdnunpandClaude Opus 4.8 3c449d78b3 Named-peers registry + Options → Manage named peers dialog
Turns the flat friendly-name map into a proper machine-wide book (AppConfig.NamedPeers), and adds a
management dialog. Held for next release.

 * New NamedPeer record (machine name, friendly name, last address, last-seen UTC). AppConfig gains
   NamedPeers; the legacy PeerFriendlyNames map is migrated into it once on load, then no longer
   written. The book stays machine-wide and profile-independent (it always was — this just enriches it).
 * Only deliberately-renamed peers are recorded (per Ed) so the list can't balloon. A named peer's
   last address / last-seen are updated in memory each tick while connected; persisted on address
   change and on app close (timestamp-only changes don't thrash the disk).
 * Options → Manage named peers (Alt+O, N): lists each named peer as "friendly — machine — last seen
   date, address"; Rename (Alt+R / F2 / double-click) reuses RenamePeerDialog; Delete (Alt+D / Del)
   forgets the name. Edits refresh the connected/discovered lists, the volume/pan/EQ list and details
   box live.
 * ApplyFriendlyName now records machine name + last address alongside the name.

Manual updated (readme.html + MANUAL.md). Build clean; --selftest passes; deployed to both test folders.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 08:20:31 +01:00
EdnunpandClaude Opus 4.8 289bb2b15c F2 renames the highlighted connected peer (Windows Explorer idiom); manual note
Held for next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 08:08:47 +01:00
EdnunpandClaude Opus 4.8 f35f6c3c28 Peer rename + details box on Connectivity tab; Add band dialog fixes
Add band dialog (from testing feedback):
 * Tab order is now Start, End, Gain, OK, Cancel (OK was after Cancel).
 * Gain box takes decimals like 1.5 (half-dB steps); parametric list shows one decimal.
 * The two frequency boxes start empty — nothing prepopulated to mislead; both required on OK.

New Connectivity-tab feature (held for next release):
 * Rename peer (Alt+M) opens a dialog to give a peer a friendly name, with a Clear custom name
   button. Names are keyed by the peer's MACHINE NAME (stable across restarts, IP changes and
   networks), stored machine-wide in AppConfig.PeerFriendlyNames, and resolved everywhere a peer
   shows: both peer lists (via PeerListItem.DisplayNameProvider), the volume/pan/EQ list, the
   status line and split-recording filenames. Manual-by-IP peers with no announced name fall back
   to keying by address.
 * Peer details (Alt+E): a read-only box for the highlighted connected peer showing name, machine
   name, IP, connected-for, link health + ping, what they're sending, and whether they're
   receiving our audio. "Sending: 2 devices on ASIO at 48 kHz, Opus" is derived from the live
   receive streams — each stream is one device and its lane gives WASAPI vs ASIO — so NO protocol
   change and no new privacy exposure. AudioReceiver.ActiveFormatsFromAddress added for this.

Manual updated (readme.html + MANUAL.md). Build clean; --selftest passes; deployed to both test
folders. Held for next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:56:42 +01:00
EdnunpandClaude Opus 4.8 033edd776f Volume/pan/EQ tab overhaul: one master switch, peer checklist, 16-band parametric EQ
Reworks the per-peer shaping tab (held for next release):

 * Renamed the tab to "Volume, pan and EQ for peers"; the Preferences toggle now defaults ON.
 * Collapsed the two master switches (Enable EQ / Enable pan) into ONE: "Enable volume, pan and
   EQ for all peers" (Alt+E). Volume now obeys it too. PeerDspChain.Build takes a single enabled
   flag; Profile.EnableAllPeerShaping replaces the two bools (old ones kept for load-migration).
 * Peer picker is now a CheckedListBox: ticking a peer shapes them (per-peer bypass via new
   PeerShaping.Enabled, default true); the focused row is the one the controls edit. Effective
   shaping = master switch AND that peer's tick. Letter-nav suppressed so keys never toggle a tick.
 * Three EQ modes, renamed: "3 band simple EQ", "12 band advanced graphic EQ", and the new
   "16 band parametric EQ" (PeerEqMode.Parametric16Band).
 * Parametric EQ: up to 16 user bands, each a boost/cut across a start->end range (PeerShaping
   .ParametricBands; ParametricToPeaking maps range -> peaking centre+Q, shared by DSP and curve).
   Add band dialog (spin-or-type, numeric-only, live preview, OK/Escape); Bands list sorted
   bass->treble reading "X Hz to Y Hz, plus/minus N dB"; Delete key / Delete button, multi-select.
   Set peer EQ to default clears the parametric list too.
 * dB now spoken as words ("plus 3 dB" / "minus 6 dB" / "flat") on the graphic sliders and the
   parametric list, since NVDA users typically have punctuation off and never hear a "+".
 * New unbound machine-wide global shortcut "Toggle volume, pan and EQ for all peers" (not stored
   in any profile) via the hotkey controller + settings store.
 * Renamed the Inputs/outputs "Set volume for all received audio" to "Master receive volume".
 * Added EqCurveControl: a purely-visual EQ response graph (not focusable, invisible to NVDA).
 * Full manual sweep (readme.html + regenerated MANUAL.md).

Build clean; --selftest passes. Deployed to both test folders. Held for next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:21:18 +01:00
EdnunpandClaude Opus 4.8 eaae76d015 Manual: document Pan and EQ, multi-track/raw recording, new naming, and the tab
Full sweep of readme.html (regenerated MANUAL.md) for the held batch:
 * New section 9 "Pan and EQ tab" — per-peer volume/pan/EQ, the two master switches, the peer
   picker, 3-band and 12-band (31/63/80/125/250/500 Hz, 1/2/4/6/8/16 kHz) EQ, reset button,
   real-time, saved per profile; shown via the "Show the Pan and EQ tab" Preferences checkbox.
   Sections 9-24 renumbered to 10-25; TOC entry added.
 * Recording section: the two new tickboxes (split into per-peer tracks; bypass pan/EQ for raw),
   and the new date-folder / "<time> RemSound recording <machine>" / multi-track-folder naming.
 * Section 4 tab list, keyboard-shortcuts (Pan and EQ tab: Alt+E/P/U/L/N/Q/M), and a Preferences
   mention. Replaced a stale old-format recording-filename example.

Held for next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 20:43:23 +01:00
EdnunpandClaude Opus 4.8 57847ff358 Pan/EQ: label the advanced mode "12 band"; single recordings include the machine name
Two of Ed's test findings: the EQ mode picker still said "10 band advanced EQ" (it's 12 now);
and a single-file recording's name now carries the recorder's machine name too —
"<HH-mm-ss> RemSound recording <machine>.<ext>" — matching the split tracks. Held for release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 20:36:17 +01:00
EdnunpandClaude Opus 4.8 c138fdf39c Pan/EQ: 12-band advanced EQ — swap 3 kHz for 80 Hz
Ed's tweak: drop 3 kHz, add 80 Hz in the low end (between 63 and 125). Still 12 bands, so no
array-length change. Held for next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 20:21:39 +01:00
EdnunpandClaude Opus 4.8 bbfa76945a Recording settings: open focused on the first checkbox, not the option columns
The dialog set sourceList.TabIndex=0, so it grabbed initial focus and the user landed partway
down, past the two new toggles. Put the toggles first in tab order (and ordered the containers,
so the top row precedes the grid), and force focus to the split-tracks checkbox on show.

Held for next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 20:20:31 +01:00
EdnunpandClaude Opus 4.8 d0d14ab95c Pan/EQ: 12-band advanced EQ (add 3 kHz and 6 kHz)
Ed wanted a band between 4 and 8 kHz. Advanced EQ goes from 10 to 12 bands: added 6 kHz (4-8
gap) and 3 kHz (2-4 gap) for even resolution through the presence region. PeerShaping
.AdvancedBandsDb default is now 12; MainForm.NormalizeBands grows an older 10-length array on
load so nothing breaks. (Feature unreleased, so no shipped settings to migrate.) Held for
next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 20:16:21 +01:00
EdnunpandClaude Opus 4.8 fc4ad3bb92 Recording fixes: date folders on top, and multi-track honours the Source setting
Two issues Ed found testing:
 * The default recordings path was recordings\<machine>\, so date folders nested under a
   machine-name folder. Dropped the per-machine subfolder — recordings now nest by date at the
   top (recordings\<yyyy-MM-dd>\...); the machine name still appears in split-track file names.
 * Multi-track always created the "me" (sent) track regardless of the Source setting, so a
   receive-only recording wrongly produced a track of your own machine. Multi-track now follows
   Source like single-file does: peer (received) tracks unless "sent only", and your own (sent)
   track only when Source is "both" or "sent only".

Held for next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 20:10:39 +01:00
EdnunpandClaude Opus 4.8 6b1e65f418 Pan/EQ: add a per-peer volume slider (before pan)
Ed's request — an individual level fader per peer, sitting just before the pan control on the
Pan and EQ tab. New PeerShaping.Volume (0..1, default 1.0 = 100% = transparent), always applied
(no master switch — unity does nothing). It folds into PeerDspChain's L/R gain alongside pan
(gainL = panL*vol, gainR = panR*vol), so it's another per-sample multiply, zero added latency,
and multiplies with the global volume (per-peer fader -> mix -> master). Slider is 0-100%,
saved per profile, announces "Volume: N percent". Shaped recording captures it; raw (bypass)
recording doesn't. Held for next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:45:52 +01:00
EdnunpandClaude Opus 4.8 efa9435da7 Recording: sum each peer's streams per track (record how it sounds)
Follow-up to the multi-track feature (Ed): the split path wrote each per-peer tap straight to
that peer's file, so a peer sending on more than one lane stacked their streams sequentially
instead of summing. Playback and the single-file path already sum; now the per-peer path does
too. Each PeerTrack accumulates that peer's block(s) per render and flushes the sum once on the
block boundary (OnRecordBlockComplete = FlushPeerTracks). "Sum to listen, sum to record."

Held for next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:39:09 +01:00
EdnunpandClaude Opus 4.8 de55230048 Multi-track + shaped/raw recording (per-peer split tracks) — held for next release
Recording Settings gains two per-profile toggles (Ed's request):
 * "Split recording into separate tracks" — each recording becomes a folder with one file per
   connected peer (their received audio only) plus one for your own send.
 * "Bypass pan and EQ when recording" — record the RAW audio (before pan/EQ) instead of the
   shaped audio you hear; applies to single and split.

Engine: a per-peer record tap in SessionPlayout hands each peer's block to the recorder RAW
(before pan/EQ) or SHAPED (after) per the bypass flag; PlayoutEngine propagates the tap to all
sessions (+ inherits on reconnect) and fires OnRecordBlockComplete each render; AudioReceiver
exposes SetPeerRecordTap / OnRecordBlockComplete. AudioRecorder now accepts an explicit path and
exposes ExtensionFor. RecordingController composes one AudioRecorder per track: multi-track =
a recorder per connected peer + a "me" recorder; single-track shaped = the existing mixed tap;
single-track raw (bypass) = sum each peer's raw block per render, flushed on the block boundary.

Naming (Ed's scheme, sortable): <recordings>/<yyyy-MM-dd>/ then, single-track, "<HH-mm-ss>
RemSound recording.<ext>"; multi-track, a folder "<HH-mm-ss> RemSound recording multi track/"
containing "<machine name> <HH-mm-ss>.<ext>" per peer (name or IP) and for your own send.

Known edge (noted): a peer using sender-side BothIndependent (two lanes) records both lanes to
one file in a split recording; single-track bypass sums per render in the Mixed path. Off by
default (both toggles unticked = today's behaviour). Builds clean; pending Ed's hands-on test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:05:00 +01:00
EdnunpandClaude Opus 4.8 703e6a022d Fix #18: accept audio from all of a multi-homed sender's source IPs
A sender reachable at more than one IP at once (e.g. LAN + Tailscale/VPN) picks its own
egress interface per packet, so its audio can arrive from a different IP than the single
address we discovered/dialled and allow-listed. The receiver then silently dropped every
Format/Audio packet (packetsRejectedNotAllowed climbing) while heartbeats — which skip the
allow-list — kept the peer showing connected: connected but silent. (Reported by
Jonathans859 building the RemSoundApple client; receiver-side, affects any multi-homed
sender incl. Windows<->Windows over a VPN.)

Discovery now remembers ALL source IPs per peer InstanceId (PeerDiscoveryService
.addressesById, expired on the same 8 s window; GetKnownAddresses). PushAllowedReceiveSenders
unions each selected peer's endpoint address with every address that peer has announced from,
so audio from any of the peer's interfaces is accepted. The SEND targets are unchanged
(still single-address) — only the accept-list widens, and only to other addresses the SAME
peer (by InstanceId) announced from, so it can't accept an unrelated machine.

Held for next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 14:26:42 +01:00
EdnunpandClaude Opus 4.8 1c1bf5a5cb Per-peer pan + EQ ("Pan and EQ" tab) — off by default, held for next release
New feature (Ed's jam-mixing request): pan and EQ each peer's signal independently.

Engine (zero added latency — per-sample, applied to each peer's isolated block just
before the mix): PeerDspChain (balance pan + RBJ biquad EQ) built on the UI thread and
swapped onto SessionPlayout via a volatile reference; PlayoutEngine remembers it per
address so a reconnecting peer keeps its shaping; AudioReceiver.SetPeerDsp facade.

Model: per-profile PeerShaping dict (keyed by peer address) + EnablePan/EnableEqForPeers
master switches; machine-wide AppConfig.ShowPanEqTab. Fixed band layouts in PeerEqBands
(3-band tone control: bass/mids/treble shelves+bell; 10-band ISO graphic EQ), +/-12 dB.

UI: a "Pan and EQ" tab (before Audio profile, shown only when ShowPanEqTab is on) with
the two enables, a connected-peer picker, a pan slider (balance, keeps stereo), a
"reset EQ" button (clears both modes' bands, leaves pan), a 3/10-band mode picker and its
band sliders — all TrackBars (arrow + page-up/down), updating in real time and saved per
profile. Sliders set a friendly AccessibleName on change (pan centre/left/right %, band
dB). "Show the Pan and EQ tab" checkbox added to Preferences > General.

Everything is off by default (tab hidden, both enables off), so this is dormant for all
users until switched on. Builds clean. Pending Ed's hands-on testing before release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 13:54:30 +01:00
EdnunpandClaude Opus 4.8 d7f6d9fd9d Release v4.9: lock a profile to fixed peer addresses (#17)
Ships the per-profile "Lock to these exact peer addresses, no matter what" toggle.
Version 4.9; About changelog + RELEASE_NOTES added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 17:04:22 +01:00
EdnunpandClaude Opus 4.8 c7d422e3ba Add per-profile "Lock to exact peer addresses" setting (#17, held for next release)
Feature request from the same singer: a way to pin a profile to exact peer addresses
so RemSound never matches the other computer by its advertised name and never switches
to a different address it discovers — for a machine reachable at two addresses at once
(VPN + LAN), they want only the one they chose, and would rather the connection die than
wander. The logical end of the v4.7/v4.8 direction.

New per-profile Profile.LockPeerAddresses (default false), round-tripped through
RemSoundSettingsStore (ApplyProfile/CopyTo + Load/SaveLockPeerAddresses), mirroring the
PriorityMode pattern. New AccessibleCheckBox on the Connectivity tab ("Lock to these exact
peer addresses, no matter what — never follow names or switch", Alt+L), saved with the
profile, marks the profile dirty on change. When set, RefreshKnownPeers early-returns
before the discovered-peer merge and the address-follow, so the profile's peers stay
exactly as set (the allow-list is still pushed). Off = unchanged behaviour.

Manual: rewrote the "Connecting to one specific IP" section (which over-promised that
add-by-IP "can never drift" — the merge/follow could) into an unambiguous "Locking a
profile to one exact address" section, plus a Connectivity-tab control-table row.

Held for the next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 15:31:50 +01:00
EdnunpandClaude Opus 4.8 0df2a576fc Release v4.8: fix rare crash from endpoint thrash on a dual-address peer (#16)
The same singer hit a rare crash: their transmitter (COMP3) was reachable at two
addresses at once — the VPN address 10.8.0.1 they chose and that machine's wireless
192.168.3.245 — and the discovery-driven endpoint-follow ping-ponged the connection
between the two (the log shows four moves in 58 ms) right where the process died with
no shutdown line, no managed exception, no dialog: a hard crash from the receiver
audio-session teardown/rebuild churn the thrash caused.

Fix: the follow loop now never moves off an endpoint that's still answering heartbeats,
only follows once the current one has been unreachable for a sustained grace period
(6 s), only to an address that is itself answering, and never more than once per cooldown
(15 s) — so it can't thrash, and a peer reached on a working address stays put (honours
the singer's "just stay on 10.8.0.1"). New endpointUnreachableSinceUtc + lastEndpointMoveUtc
state; genuine DHCP/network moves are still followed a few seconds later.

Also: a global crash handler (Program.WriteCrashReport on AppDomain.UnhandledException +
TaskScheduler.UnobservedTaskException) writes a crash-*.txt into the logs folder, so a
future "RemSound just vanished" report leaves a stack behind. Removed a stale doc comment
left over from the v4.7 adoption removal. Manual gains a "RemSound closed unexpectedly"
troubleshooting entry. Version 4.8; About + RELEASE_NOTES updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 22:57:49 +01:00
EdnunpandClaude Opus 4.8 64d5cb5a86 Release v4.7: keep trying your configured peer after a reboot (#15)
Removes the heartbeat "adopt a live address" feature (added v1.6). On a LAN with
more than one RemSound machine it could latch a receiver onto an unrelated sender
that happened to be pinging the audio port — then never recover to the real peer,
needing a manual restart (the singer's #15, with log). The feature guessed peer
identity from an untracked ping source with no way to verify it was the same peer;
on the stable VPN/LAN addresses RemSound is actually used with, it only ever caused
harm, since same-address reconnect already works via the continuous heartbeat.
Removed TryAdoptLiveHeartbeatAddress + IsPrivateLanAddress (MainForm) and
GetUntrackedPingSources + recentPingSources (HeartbeatService); the identity-safe
discovery-based following (by verified peer ID) stays. Manual troubleshooting entry
rewritten to match.

Also bundles the held changes since v4.6: status reads line-by-line with GB totals
and double-press-to-copy, CPU/memory in the status, the Install Scripts folder, and
the what's-new-after-failed-update fix. Version 4.7; About + RELEASE_NOTES updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 22:41:43 +01:00
EdnunpandClaude Opus 4.8 843be9b7fb Speak-status: drop the double-press-copy Preferences toggle
Andre confirmed (via NVDA speech history) that holding the speak-status hotkey
doesn't repeat or spam — so the defensive toggle that let users disable the
double-press-to-copy was needless configurability. Removed the Preferences
checkbox and the DoublePressStatusToCopy setting; double-press-to-copy (Andre's
own idea) stays, now simply always on. There was never any debounce/anti-spam
code to remove — the only timing is the 600 ms double-tap detection window, which
is the feature itself. Manual updated to drop the toggle line.

Held for the next release (the toggle never shipped).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 18:55:03 +01:00
EdnunpandClaude Opus 4.8 6c36369806 Docs: correct RemSound's origin story (true remote-audio-monitoring use)
The manual intro and the repo README both carried an invented origin (a guitarist
and singer playing together, "built by a sound designer"). RemSound was actually
built to hear the audio from a powerful computer while working remotely from a
lighter one — other programs can move audio between PCs, but none did it quite the
way Ed wanted. Reworded the manual opening (readme.html) and the README audience
and "Who made this" lines to tell one true, consistent story in Ed's voice. The
music-together and podcast uses stay as the genuine secondary use cases they are.

readme.html ships to users on the next release; README/MANUAL update on push.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 16:04:31 +01:00
EdnunpandClaude Opus 4.8 771a358a87 Status box: show RemSound's own CPU and memory usage (held for next release)
New last status line "CPU usage 2% and memory 184 MB" — CPU as a share of the whole machine
(Task Manager style: process CPU-time delta / wall-clock / logical-core count), memory as the
working set via the same MB-to-GB formatter the totals use. Sampled on the existing once-a-second
status tick with a cached Process handle. Shows on screen and reads/copies with the rest of the
status (Ed's idea).

Held for the next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 15:22:40 +01:00
EdnunpandClaude Opus 4.8 be32a060e7 Add "double-press to copy status" toggle + document the spoken-status changes (held for next release)
Preferences General-tab checkbox "Double-press the speak-status hotkey to copy the status to the
clipboard" (Alt+C), machine-wide (AppConfig.DoublePressStatusToCopy), on by default. When off, a
double press just reads the status again. SpeakStatusLine reads the flag only when the timing already
qualifies, so a normal single press never touches the config. Manual's speak-status section now
covers the line-by-line read, GB totals, and the double-press copy + its toggle.

Held for the next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 14:47:02 +01:00
EdnunpandClaude Opus 4.8 0fe9637356 Status speech: read line-by-line, MB->GB on totals, double-press to copy (held for next release)
Andre's feedback on the spoken status (the issue #13 feature):
- Speak the status one line at a time instead of collapsing the lines into a run-on sentence —
  this also removes the doubled "." the collapse produced (each line already ended in a period).
- Totals switch to GB once they reach a gigabyte ("4.5 GB" vs "4558.2 MB"), via a FormatDataSize
  helper used by the readout itself so the on-screen and spoken figures stay consistent.
- A quick DOUBLE press of the speak-status hotkey copies the status to the clipboard (with a
  "copied" announcement) so it can be shared with others.

Held for the next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 14:31:03 +01:00
EdnunpandClaude Opus 4.8 f9b3ed9e67 Add Install Scripts (winget .NET 10 install) for the no-runtime case (held for next release)
RemSound is a .NET 10 app, so it can't install its own runtime — it can't start without it. A
plain .cmd/.ps1 (which run on what's already in Windows) sidesteps that: double-click
"Install Scripts\Install .NET for RemSound.cmd" and it winget-installs the .NET 10 Desktop Runtime
(Microsoft.DotNet.DesktopRuntime.10), falling back to opening Microsoft's download page if winget
is absent. Modelled on Andre Louis's accessible-sensor-readout Install_Scripts (his install .NET
Framework 4.8 because SR is Framework; ours installs the .NET 10 Desktop Runtime RemSound needs).

Bundled into the build + release zip via csproj Content + EnsureInstallScriptsPublished target.
Manual Quick-start note points users here if RemSound won't start. Held for the next release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 14:24:20 +01:00
EdnunpandClaude Opus 4.8 e710834458 Fix what's-new re-appearing after a failed update (held for next release)
Replace the running-version-vs-saved-version trigger for the "what's new" popup with a
one-shot marker the updater writes ONLY on a successful update (UpdateApplier success
path). A failed/rolled-back update never writes it (and clears any stale one), so it can
no longer re-trigger what's-new — the old best-effort flag save could lose a race during
the update churn and leave the version mismatched, which was the bug.

New WhatsNewMarker seam (Write/Exists/Consume) + a SelfTest case for the consume-once
contract. MaybeShowWhatsNewAfterUpdate now shows iff the marker is present, then deletes
it; still records LastWhatsNewVersion for the import-offer's upgrade detection.

Not released yet — bundling with the connection-retry (#15) work in the next release.
No version bump, no manual change (internal fix).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 17:16:54 +01:00
EdnunpandClaude Opus 4.8 36431d6d39 Release v4.6: follow the Windows default audio device (output + input)
- New "Use Windows default audio device, follows Windows changes" entry at the top of the
  received-output and send-input WASAPI lists. Resolves the current Windows default live,
  re-routes automatically when the default device changes, works alongside specific devices,
  and persists across launches (a follower can't go stale). Optional "untick the others?"
  prompt with a remembered "don't ask again", reset via a new Options item "Reset the default
  audio device prompt".
- Manual updated for the feature, plus a sweep that corrected the now-stale Options-menu
  section (retired Startup-behaviour item, four->five Preferences tabs, missing entries).
  About changelog and RELEASE_NOTES updated; version 4.6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 11:41:58 +01:00
EdnunpandClaude Opus 4.8 962f35ab80 Release v4.5: import shortcuts on pre-4.4 upgrade + clearer shortcuts dialog
- Pre-v4.4 upgraders are offered a one-time dialog to copy their keyboard shortcuts
  from one of their profiles (still readable in the profile files) instead of being
  reset. Users who already went through v4.4's reset are deliberately NOT re-offered
  (gated on KeyboardShortcutsGlobalNoticeShown). New KeyboardShortcutImportDialog +
  AppConfig.KeyboardShortcutsImportOffered + MainFormHotkeyController.ReloadAndReRegisterAll.
- Keyboard shortcuts dialog: new "Clear this shortcut" button; Delete inside the
  capture box leaves a shortcut unassigned.
- Relabelled the three RemSound-app remote rows to "Send remote RemSound volume/..."
  to distinguish them from the Windows-global ones.
- Manual (readme.html + MANUAL.md), About changelog, RELEASE_NOTES updated; version 4.5.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 06:36:00 +01:00
EdnunpandClaude Opus 4.8 8a1bc0c813 Release v4.4: keyboard shortcuts are now machine-wide, not per-profile
Fixes issue #14: shortcuts were stored on each Profile, so one set on profile A
didn't apply on profile B and seemed to vanish on switch. They now live in
AppConfig (one set shared by every profile). RemSoundSettingsStore's Load*/Save*
hotkey methods re-point to AppConfig (callers unchanged); the per-profile cache
fields, profile load/save plumbing, and the HotkeySetting helper class are removed.
Profile's HotkeyRecord fields stay only for back-compat deserialization.

On upgrade, shortcuts reset to defaults (there's no single correct set to carry over
since profiles could hold different/partial sets). A one-time startup notice tells
upgraders to re-set them; fresh installs are silently marked done (nothing to reset).

Manual, About changelog and RELEASE_NOTES updated; csproj <Version> 4.4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 23:11:53 +01:00
EdnunpandClaude Opus 4.8 32be3426e7 Release v4.3.1: quieter default update sound
Both update cue variants ("update 1.wav" / "update 2.wav") replaced with a
gentler mix that signals an incoming update without interrupting work mid-flow.
About-box note added (tidied wording); csproj <Version> bumped to 4.3.1. No code
changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:46:46 +01:00
EdnunpandClaude Opus 4.8 fd5c31740a Release v4.3: speak status line (Tolk) + Logging tab with housekeeping
- New screen-reader hotkey "Speak the RemSound status information" (issue #13):
  reads the status line aloud through the active screen reader via Tolk, fires from
  anywhere (system-wide), unset by default. Built behind an IScreenReaderOutput seam
  so a future build can swap Tolk for Prism on Windows 10+ without touching callers.
  Tolk DLLs vendored under tolk/ and shipped next to the exe.
- New Logging tab in Preferences: Enable logs + Write logs now moved there, plus
  opt-in startup "warn if logs folder exceeds N MB" and "delete logs older than N days",
  and a "Delete all logs" button (Yes/No confirm). New LogMaintenance helper + AppConfig
  settings drive it.
- Manual (readme.html + regenerated MANUAL.md), About changelog and RELEASE_NOTES
  updated in plain English; csproj <Version> bumped to 4.3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:09:06 +01:00
EdnunpandClaude Opus 4.8 034a7de632 Release v4.2: fix connect-freeze (#10) and new-profile minimize (#12); smoother WASAPI timing
- Connect no longer freezes: PushDiscoveryUnicastHints resolved remembered
  hostnames with synchronous Dns.GetHostAddresses on the UI thread, blocking the
  whole window for the DNS timeout on an unresolvable name. A screen-reader user
  experiences that as the entire machine locking up. Resolution now runs off the
  UI thread. Same class of bug as the v3.0.1 UPnP-on-the-UI-thread hang. (#10)

- New profile / profile switch no longer hides the window: OnShown ORed the
  global StartMinimised into every instance, so creating a new profile while
  Start minimised was on dropped the window to the tray and looked like a crash.
  StartMinimised now applies only to a genuine cold launch; relaunches honour the
  explicit per-instance flag. (#12)

- Smoother WASAPI audio: the receive producer loop and sender mix loop pace
  themselves with WaitHandle.WaitOne, bound by the system timer (~15.6ms default).
  Without a fine timer the 10ms feed slips to ~16-31ms and delivers audio in
  chunky bursts (the desktop-render chunkiness behind Andre's dropouts/lag). New
  SystemTimerResolution holds a 1ms timer whenever a stream is live, independent
  of the opt-in Priority mode.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 09:21:04 +01:00
EdnunpandClaude Opus 4.8 5abbeefe29 v4.1: two screen-reader fixes — silent start-in-tray, announce on restore
- Starting straight into the tray (StartMinimised / --minimized) no longer plays the "minimise"
  cue; only a genuine user minimise does (the startup path passes playCue:false)
- Restoring the window from the tray now lands focus on a real named control on the active tab so
  NVDA announces it, instead of resting on the role-less QuietTabControl and surfacing silently
- Shared the focus-a-leaf-for-announcement helper between the main window and Preferences

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:59:59 +01:00
EdnunpandClaude Opus 4.8 a408d2b56e v4.0: full audio-cue system, cause-aware auto-tune, four-tab Preferences, install-side default sounds
Audio cues
- Cues for send/receive on-off, minimise/restore, checkbox tick/untick, and tab switch
- Soft keyboard clicks while typing, with a distinct passkey sound on password fields
- Per-cue "Choose sound" variant picker; "(none)" silences a cue; front-most missing-sound warning
- Send/receive cues take priority over the generic checkbox sound; programmatic ticks stay silent

Preferences
- Redesigned into four tabs (General, Audio cues, Startup behaviour, Update settings)
- Startup behaviour moved in from the Options menu
- NVDA now announces the dialog on open (focus a real named control, not the quiet tab control)

Auto-tune
- Cause-aware: tells device render-callback stalls (more buffer can't fix) apart from genuine
  network/buffer starvation, so it no longer pins latency high on chunky onboard cards
- Lowering the target eases the buffer down (glide) instead of trimming it, so no clicks while tuning

Sounds layout
- Shipped defaults moved out of the per-user folder into an install-side "default sounds" folder,
  so updates can refresh them; user customs are Browse-picked file paths and are left untouched
- Startup migration removes both legacy sound folders; verified from oldest (v1.0-v3.3) and v3.4 layouts

Quiet automated launches
- New --silent launch flag mutes all cue sounds and suppresses the startup dialogs (migration notice,
  update check, Realtek/mic/missing-sound warnings) so test launches never disturb the user
- run-tests / build-release / SelfTest repointed to the new "default sounds" layout

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 11:57:19 +01:00
EdnunpandClaude Opus 4.8 0b7ad49021 Fix: passkey sound now layers in on password fields
RemSound's password boxes are deliberately NOT PasswordChar-masked (a screen-reader user can't see
a mask), so the key-click hook's "is this a password field?" check (UseSystemPasswordChar /
PasswordChar) was always false and the distinct passkey.wav never played. Password fields now mark
themselves with Tag = KeyClickService.PasswordFieldTag, and the hook checks that (keeping the
masking-flag check as a fallback). Tagged both password fields - ProfilePasswordDialog (which all
password entry routes through, including the send/receive streaming gate) and
ProfilePasswordManagerDialog. So a key click + passkey now layer together on every password keystroke.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 07:23:54 +01:00
EdnunpandClaude Opus 4.8 56417eb7c3 Cues: send/receive checkboxes' own cue sounds take priority over the generic checkbox sound
The Send/receive checkboxes have dedicated cue sounds (send/receive turned on/off) AND would
otherwise also fire the generic checkbox tick/untick. AccessibleCheckBox gains a SuppressCheckSound
gate; the send/receive checkboxes set it so that when their dedicated cue is on, only that cue
plays. When the dedicated cue is "(none)", the gate returns false and the generic checkbox sound
plays as normal - so the checkbox sound never overrides the purpose-built send/receive sounds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 06:53:36 +01:00
EdnunpandClaude Opus 4.8 2eaf7da184 Manual: document the Preferences tabs, the cue "(none)" model, and the missing-file warning
Audio cues section rewritten for the redesign: the cue list is a plain list you arrow through to
hear each cue, the "Choose sound" list's "(none)" entry turns a cue off (no more tickboxes), and
a new note covers the front-most "couldn't find the sound file" warning + auto-disable. Startup
behaviour section and the Menus -> Preferences entry updated for the four-tab Preferences dialog
(General / Audio cues / Startup behaviour / Update settings) and the retired Options-menu item.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 06:47:57 +01:00
EdnunpandClaude Opus 4.8 e8dcf724d8 Cues: front-most "missing sound file" warning + auto-disable
When a cue is switched on but its sound file can't be found (the player resolved to null - e.g.
a custom WAV was deleted, or a chosen sound is gone), RemSound now turns that cue off and tells
the user, front-most even when minimised (RestoreFromTray first), once per cue per session:
"RemSound was unable to find the <cue> sound file used when <event> happens. RemSound has set
this particular audio cue to not play for now, until a new sound file is specified."

CheckForMissingEnabledCues runs on first show (Shown) and after every cue reload (so it catches
a just-deleted custom WAV when the user closes Preferences). Per-profile cues are turned off via
the settings store, machine-wide cues via AppConfig.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 06:43:48 +01:00
EdnunpandClaude Opus 4.8 75e7432fcb Preferences: four accessible tabs (General / Audio cues / Startup behaviour / Update settings)
The Preferences dialog is now a QuietTabControl with four tabs (same accessible tab approach as
the main window; Ctrl+Tab / arrows switch tabs):

- General: profiles-folder browse, accept-remote-volume, UPnP, enable logs / write logs now.
- Audio cues: the redesigned cue UI (plain cue list + "(none)" sound option) + keyboard clicks.
- Startup behaviour: Start minimised / Start with Windows / Start with a specific profile -
  moved here from the standalone Options-menu dialog, wiring and persistence unchanged (AppConfig
  + the Windows auto-start registry entry).
- Update settings: startup-check, frequency, check-now, silent-install, show-what's-new.

Removed the Options-menu "Startup behaviour" item and deleted the now-unused
StartupBehaviourDialog.cs (and dropped it from the self-test's accessibility audit). The audit
still passes on the tabbed dialog with no mnemonic clashes (Alt-letters are isolated per tab).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 06:39:57 +01:00
EdnunpandClaude Opus 4.8 0bd3ef0018 Audio cues: redesign the cue UI - plain cue list + a "(none)" sound option replaces the tickboxes
The per-cue enable tickboxes are gone. The cue list is now a plain list of names; arrowing it
previews that cue's current sound (custom or chosen default). The sound list below gains a
"(none)" entry at the top: picking it turns the cue off (reusing each cue's existing on/off
storage - per-profile cues persist off-ness in the profile, machine-wide cues in global
settings), and picking a numbered variant turns the cue on and records that sound. All cues
default on, on the first variant; "(none)" is never the default.

Part of the larger Preferences overhaul; the 4-tab restructure, the Startup-behaviour/Update
moves, and the missing-file error are the remaining steps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 00:50:45 +01:00
EdnunpandClaude Opus 4.8 aed555cc2e Reset-ASIO button + checkbox tick/untick sounds (parts 1-2 of the cue/preferences overhaul)
Part 1 - "Uncheck all inputs and outputs" button now also resets the ASIO driver to "(none)":
renamed to say so, and UncheckAllDevices sets asioDriverBox to row 0 for a full clean
WASAPI-only, nothing-selected state.

Part 2 - checkbox tick/untick sounds: every checkbox toggle anywhere in RemSound now plays a
short cue (check.wav on tick, uncheck.wav on untick) - instant feedback on which way a box
went, especially in the inputs/outputs lists. New CheckSoundService + two machine-wide cues
(CheckboxOn/Off) with the usual numbered-variant + Preferences treatment. Hooked from
AccessibleCheckBox.OnCheckedChanged and the device lists' WireCheckedListAccessibility, both
gated on the control being Focused so a genuine user toggle clicks but bulk programmatic
(un)checking (profile load, "uncheck all") stays silent. Reloaded at startup and on cue change.

Tests + manual updated; .sfk byproducts cleared.

Remaining for the overhaul (next): tabbed Preferences (General / Audio cues / Startup behaviour /
Update settings), the cue-list redesign with a "none" option replacing per-cue checkboxes, moving
Startup behaviour out of the Options menu, and a front-most "missing sound file" error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 00:42:41 +01:00
EdnunpandClaude Opus 4.8 8763470037 Audio cues: add send/receive on-off and minimise/restore cues (2 sounds each), drop .sfk byproducts
Six new machine-wide cues, each with the same numbered-variant + Preferences treatment as
the others (enable tickbox, Choose default sound picker, Play/Browse):

- Send turned on / off, Receive turned on / off: fire from OnStreamingCheckboxChanged, so
  they sound whether the user clicked the in-window tickbox or pressed the mute shortcut
  (the hotkey flips .Checked, which routes through the same handler). Suppressed during
  profile load by the existing password-gate guard, so loading a profile doesn't blast them.
- Minimise (hide) / Restore (show): fire from the tray controller's Minimize()/Restore() on a
  genuine visibility transition (guarded against no-op / startup-minimise).

Enable flags + custom-WAV overrides for these six live machine-wide in AppConfig
(EnableSendOnCue.., MachineCueCustomPaths) - they're app-level feedback, not per-profile
audio - so no Profile/settings-cache plumbing. TryLoadCueSound now also honours the
machine-wide custom path. PreferencesDialog gains a MachineRow helper + the six rows.

Sounds: shipped via the existing sounds\*.wav wildcard. Fixed an obvious typo in the
supplied files ("rcieve off 1.wav" -> "recieve off 1.wav") so receive-off has both variants.
Renamed the old single-name cue WAVs to Ed's numbered-variant set; added key/passkey and the
new cue sounds.

build-release.ps1: new step deletes the SoundForge .sfk peak-file byproducts from sounds\
before packaging (they never shipped - build is *.wav only - this just keeps the tree tidy).

Tests + manual updated for the six new cues.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 00:18:09 +01:00
EdnunpandClaude Opus 4.8 e526014e6a Audio cues: per-cue default-sound picker, keyboard-click typing feedback, passkey on password fields
Cue sounds now ship as numbered variants ("connect 1.wav", "connect 2.wav", ...); the
count is never hard-coded so more can be added with no code change.

- CueSounds.cs: discovers a cue's "<base> <n>.wav" variants (case-insensitive) and
  resolves the active default: per-profile custom WAV > machine-wide chosen variant >
  first variant > silent. Wired into MainForm.TryLoadCueSound, the startup cue in
  Program.cs, and PreferencesDialog.ResolveCueFilePath.
- AppConfig: DefaultCueSounds (machine-wide cueId -> chosen filename) and
  EnableKeyboardClicks (on by default).
- Preferences: a "Choose default sound" listbox under the cue checklist - it lists the
  selected cue's variants, arrowing it previews each sound and makes it that cue's
  default. Plus a "Play keyboard clicks when typing into any edit field" checkbox.
- KeyClickService.cs: an app-wide WM_CHAR message filter + a low-latency NAudio mixer.
  Typing into any edit field plays a random key click (key 1..N.wav); password fields
  also play passkey.wav at the same instant. On/off live from the Preferences toggle.
  Inert if the sounds are missing or the device won't open; never consumes the keystroke.
- csproj: ship every sounds\*.wav via a wildcard (variants, key clicks, passkey, future
  additions) instead of stale per-file canonical names.
- Tests: resource checks (self-test + run-tests.ps1) now verify each cue has >=1 variant
  and that key 1.wav / passkey.wav are present. Accessibility audit still green with the
  new Preferences controls (Alt+D, Alt+K - no mnemonic clashes).
- Manual: variant picker, keyboard clicks, and the new sound-file naming documented.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 00:06:07 +01:00
EdnunpandClaude Opus 4.8 ad66fe5364 Test suite: richer diagnostics, headless accessibility audit, perf/leak sanity
Andre's three "bigger ideas" from RemSound-smoke-test-agent-brief.md:

- Richer diagnostics: --diagnostics now includes a live localhost audio self-check
  (PCM + Opus, with packet/underrun/drop/buffer/latency counters), the most recent
  session snapshot parsed from the log (codec, send/receive state, buffer, drops,
  heartbeat), and a recent-warnings/errors digest from the log. BuildDiagnosticsReport
  gained a runLiveAudioProbe flag so the self-test's privacy check stays fast.

- Headless accessibility audit: new --selftest step constructs the dialogs that can be
  built without hardware (Startup behaviour, Recording settings, Preferences) and checks
  every actionable control announces a name and that Alt-key mnemonics are unique within
  a container. MainForm is out of scope (its constructor opens audio/hotkeys/sockets).
  Dialogs that won't construct are skipped, not failed. Currently audits 3, no violations.

- Perf/leak sanity: new --perftest command runs several audio-loopback cycles and reports
  whether handle/memory/thread counts stay bounded (handles ratcheting up cycle-on-cycle is
  the leak fingerprint, given RemSound's handle-leak history). Lenient thresholds; logs the
  numbers for build-to-build comparison. Wired into run-tests.ps1.

- Shared AudioLoopback helper (used by the self-test, diagnostics and perf test) so all
  three exercise the identical real capture/encode/network/decode path on test port 47929.

- csproj: the four previously-unconditional cue Content items are now Exists-guarded like
  the rest, so a mid-edit sounds\ folder doesn't break the dev build; the gate still
  enforces the required cues before release.

Help + manual updated (--perftest, --smoke-test, --config-dir, richer --selftest).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 23:45:08 +01:00
EdnunpandClaude Opus 4.8 832ed40bf7 Test suite: add --config-dir isolation, --smoke-test alias, and a cold-start/close gate step
Adopted from Andre's RemSound-smoke-test-agent-brief.md - the gaps our pack didn't
already cover:

- --config-dir <folder>: redirect ALL user state (config, profiles, logs, cue
  sounds) to an explicit folder for this process only, applied at the very start of
  Program.Main before the layout migration runs. Lets a test exercise a real build
  without touching the user's live settings (the brief's safety rule 1). Works with
  every command. AppConfig gains SetUserDataDirectoryOverride / an override on
  UserDataDirectory; CommandLine.TryGetConfigDir parses it early.
- --smoke-test / --smoketest: alias for --selftest, matching the brief's vocabulary.
- run-tests.ps1: a cold-start + clean-close smoke (brief baseline steps 3-4) -
  launches the GUI minimized against an isolated --config-dir, confirms it stays up,
  that it used the isolated folder (real settings untouched), and that --close shuts
  it down with no orphan process. SKIPs cleanly if a RemSound instance is already
  running (machine-wide single-instance lock).

Manual + --help updated for both switches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 23:12:22 +01:00
EdnunpandClaude Opus 4.8 141c5e8ce1 Add build-and-test suite (in-app self-test + publish gate); fix release-zip missing sounds
The test suite, modelled on Andre's Sensor Readout (an in-app self-test + a build
script), runnable as one step before every publish.

Part 1 - in-app multi-step self-test (SelfTest.cs), run by --selftest:
  audio round-trip (PCM + Opus over localhost, dedicated test port so it never
  clashes with a running instance), encryption right/wrong-password + fingerprint,
  packet framing + malformed rejection, client<->server wire-format compatibility,
  settings save/reload, profile save/reload (temp folder), diagnostics-report
  privacy (never leaks a password), and bundled-resources present. Each step is
  timed and reported PASS/FAIL/SKIP; exit 0 only if nothing failed. Replaces the
  old single-shot --selftest. RunDiagnostics refactored to expose
  BuildDiagnosticsReport(AppConfig) for the privacy step.

Part 2 - run-tests.ps1: builds, then checks the package (sounds, readme, native
  opus, framework-dependent, dll version == csproj), the About-box changelog, the
  client/server wire contract (relay magic/version/port still match RemPacket),
  the CLI surface, and runs --selftest. build-release.ps1 now runs this gate first
  and aborts the release if it fails.

Bug caught + fixed: the published release zip carried ZERO cue sounds (startup
  sound + connect/disconnect/etc.) - MSBuild's incremental Content-copy marker
  skipped sounds\ on a fresh publish. Added an AfterTargets=Publish copy in the
  csproj that lands every cue WAV in the published sounds\ folder regardless of
  the marker. Verified: a staging publish now contains all 9 cue WAVs.

Manual/help: --selftest description updated (readme.html + MANUAL.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 23:01:40 +01:00
EdnunpandClaude Opus 4.8 05b218825d Release v3.9: silent-mic fix, buffer drain, idle-send guard, start-up sound, command-line
- Receiver: a plain (Mixed) stream now renders on an active lane when the
  receiver is in two-lane (ASIO) mode, instead of being decoded into a ring
  nothing reads. Fixes one-way silence ("my mic works for me but not for them").
- Receiver: drift resampler gains a buffer-depth correction term so a bloated
  standing buffer eases back to the latency target over a long session.
- App: don't send audio until a peer is genuinely reachable (issue #8); status
  no longer shows phantom send traffic with nobody connected.
- App: start-up cue sound (machine-wide toggle + custom path in Preferences).
- App: command-line options (CommandLine.cs) -- --devices, --selftest,
  --diagnostics, --log, --close, --profile, --connect, --minimized, --version,
  --help. New "Command-line options" manual section (readme.html + MANUAL.md).
- Version 3.9; About-dialog and RELEASE_NOTES updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:57:36 +01:00
EdnunpandClaude Opus 4.8 84c4a47411 v3.9.1: plain/WASAPI streams now play on an ASIO-mode receiver (silent-mic fix)
Receiver: a Mixed (plain) session is rendered on an active lane in BothIndependent mode instead of being skipped, so a WASAPI-only sender is no longer silent to a receiver that has an ASIO driver selected. Also port the per-session buffer depth-drain (stops the receive jitter buffer bloating).

Sender: add sndAudFr meter (audio frames actually sent) to localise capture vs send.

App: startup sound cue (machine-wide, Preferences); stop sending audio when no peer is reachable (issue #8). Version 3.9.1.

Server (relay): fix updater version-compare for multi-dot tags, guard the main loop against crashes, reject spoofed BYE from a mismatched endpoint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:00:33 +01:00
EdnunpandClaude Opus 4.8 04b17ff1ab Release v3.8: New profile (blank template renamed), password-mismatch warning stays up, IP-pinning docs
New profile: a File-menu item + Ctrl+N that loads a fresh blank template as a
new unsaved session via a LoadBlankTemplateNext handoff to Program.cs's relaunch
loop — reachable even when "start with a specific profile" boots past the picker
(issue #6). Offers to save the current profile first if dirty; deliberately
silent (no profile-switch cue).

Renamed the user-facing "blank template" to "New profile": the picker's synthetic
entry (now a distinct marker TYPE, collision-safe against a real profile named
"New profile"), the window title ("RemSound — New profile"), and the manual.

Fixed the password-mismatch warning flashing away: it's raised from the 1 Hz
statusTimer, which kept firing into the modal loop and rebuilt the peer lists
(SyncAllPeerLists) under the dialog, knocking it out of the foreground. Now the
tick is frozen while it's up, it's routed through ForegroundDialog, and a
re-entry guard ensures one warning that stays put. Audited: it was the only
popup raised from a recurring timer.

Docs: manual section "Connecting to one specific IP address (and only that one)"
explaining by-name vs by-fixed-IP and that a profile saves the exact address
(issue #7 — functionality already existed); About box + RELEASE_NOTES for v3.8;
MANUAL.md regenerated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 21:38:38 +01:00