From 04b17ff1abe7f9ae0562a1db855851431513c60c Mon Sep 17 00:00:00 2001 From: Ednunp <29843396+Ednunp@users.noreply.github.com> Date: Thu, 11 Jun 2026 21:38:38 +0100 Subject: [PATCH] Release v3.8: New profile (blank template renamed), password-mismatch warning stays up, IP-pinning docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- MANUAL.md | 44 +++++++---- RELEASE_NOTES.md | 35 +++----- readme.html | 40 ++++++---- src/RemSound.App/AboutDialog.cs | 17 ++++ src/RemSound.App/MainForm.cs | 92 +++++++++++++++++++++- src/RemSound.App/ProfileSelectionDialog.cs | 40 +++++++--- src/RemSound.App/Program.cs | 9 ++- src/RemSound.App/RemSound.App.csproj | 2 +- 8 files changed, 210 insertions(+), 69 deletions(-) diff --git a/MANUAL.md b/MANUAL.md index e7c1928..8abbec8 100644 --- a/MANUAL.md +++ b/MANUAL.md @@ -54,7 +54,7 @@ There is no central server, no account, and nothing stored online. The sound goe Let's assume you and a friend both have RemSound running, and that your two computers can reach each other on the network (the same Wi-Fi, the same Tailscale account, and so on). - 1. Start RemSound. The first thing you'll see is the **profile picker**. On a brand-new install your only choice is **(Blank template)** — select it and press Enter or click OK. Later, once you've saved a setup or two of your own, this is the dialog where you choose which one to load. See Profiles for the full story. + 1. Start RemSound. The first thing you'll see is the **profile picker**. On a brand-new install your only choice is **New profile** — select it and press Enter or click OK. Later, once you've saved a setup or two of your own, this is the dialog where you choose which one to load. See Profiles for the full story. 2. Once the main window opens, go to the **Audio inputs and outputs** tab. Tick **Receive audio (Alt+R)** , then tick the device you want incoming sound played through in **WASAPI outputs for received sound (Alt+3)**. 3. On the same tab, tick **Send my audio (Alt+S)** and tick your microphone in **WASAPI inputs to send (Alt+5)**. 4. Go to the **Connectivity** tab, find your friend in the **Discovered peers (Alt+D)** list, and tick them. If they aren't showing up, use **Add peer by IP (Alt+A)** and type their address. @@ -72,23 +72,25 @@ RemSound saves your whole setup — which devices are ticked, whether you're sen ### The startup picker -When RemSound starts, the first thing you see is the profile picker. It is a list of your saved profile names, with an extra entry called **(Blank template)** at the top. The keys are deliberately simple: +When RemSound starts, the first thing you see is the profile picker. It is a list of your saved profile names, with an extra entry called **New profile** at the top. The keys are deliberately simple: Key| Action ---|--- Up / Down| Move between profiles in the list. -Enter| Load the highlighted profile (or the blank template) and open the main window. +Enter| Load the highlighted profile (or a new profile) and open the main window. OK button| Same as Enter. Del| Delete the highlighted profile, after a yes / no confirmation. Browse… button| Choose a different folder to read profiles from. Handy if you keep your profiles in Dropbox or another sync folder so they follow you between computers. Your choice is remembered next time RemSound starts. Esc| Deliberately does nothing here. You have to pick a profile to start the program. Alt+F4| Closes the dialog and quits RemSound — in other words, “I don't want to start the program right now.” -The first profile in the list is highlighted to begin with, so on a fresh install where the only entry is **(Blank template)** , you just press Enter to get going. +The first profile in the list is highlighted to begin with, so on a fresh install where the only entry is **New profile** , you just press Enter to get going. -### What “Blank template” means +### What “New profile” means -The blank template is a one-off session with all the defaults: nothing ticked in any device list, neither Receive nor Send turned on, the standard sound settings, no ASIO driver chosen, no remembered peers, and the standard hotkeys. You'd pick it for a quick session you don't plan to save, or as a clean starting point for a new profile. The Save button is hidden while you're on the blank template — there's no existing setup to update, only a new one to save. +A new profile is a one-off session with all the defaults: nothing ticked in any device list, neither Receive nor Send turned on, the standard sound settings, no ASIO driver chosen, no remembered peers, and the standard hotkeys. You'd pick it for a quick session you don't plan to save, or as a clean starting point for a new profile. The Save button is hidden while you're on a new profile — there's no existing setup to update, only a new one to save. + +**Starting a new profile later:** the picker only appears at startup, and if you've set RemSound to _start in a specific profile_ you skip straight past it. So to start a brand-new profile at any time, use **File → New profile** (Ctrl+N, or Alt+F, W) — it opens a fresh, default session, ready for you to set up and then Save as. If your current profile has unsaved changes, it offers to save them first. ### Saving and updating @@ -96,8 +98,8 @@ The File menu has two ways to save: Item| What it does ---|--- -**File → Save (Ctrl+S)**| Updates the current profile with whatever your settings are right now. If you're on the blank template, this turns into Save as instead, because there's no existing profile to update. -**File → Save as… (Alt+F, A)**| Always available. Asks you for a name. From the blank template, this is how you create your first profile. From an existing profile, it makes a fresh copy under a new name and switches to that copy. +**File → Save (Ctrl+S)**| Updates the current profile with whatever your settings are right now. If you're on a new profile, this turns into Save as instead, because there's no existing profile to update. +**File → Save as… (Alt+F, A)**| Always available. Asks you for a name. From a new profile, this is how you create your first profile. From an existing profile, it makes a fresh copy under a new name and switches to that copy. The window title bar always shows which profile is in use: `RemSound — Active profile: My session name`. @@ -235,11 +237,12 @@ The File menu holds everything to do with profiles — opening, saving, renaming Item| Shortcut| What it does ---|---|--- +**New profile**| Ctrl+N, or Alt+F, W| Starts a brand-new profile from scratch — a fresh, unsaved session (everything unticked, nothing connected, default settings). This is how you create a profile for a different setup at any time, _even when RemSound is set to start straight into a specific profile and you never see the picker_. If your current profile has unsaved changes, it offers to save them first. Once you've set things up, use Save as to give the new profile a name. **Open profile …**| Ctrl+O, or Alt+F, O| Opens a Windows file picker showing your profiles folder. Pick a profile, and RemSound reloads using it (the window closes and reopens with all that profile's device choices, peers and settings restored). To delete a profile, right-click its entry inside the file picker and choose Delete — that lets Windows handle the deletion. **Recent profiles →**| Alt+F, R| A submenu listing the last five profiles you've opened, most recent first. Each row has a single-digit shortcut: while the submenu is open, press **1** for the most recent, **2** for the next, and so on up to **5**. Or just select the one you want. It reloads the profile the same way Open profile does. If a recent profile's file has been deleted or moved away, it's left out of the submenu (it stays in the list in case the file comes back later — for example when you reconnect an external drive). If the list is empty, you see a greyed-out “(No recent profiles)” entry. The same list appears in the system-tray icon's **Profiles** submenu, with the same number shortcuts, so you can switch profiles without re-opening the main window. -**Save**| Ctrl+S| Updates the current profile with your current settings. If there's no current profile (you're on the blank template), this becomes Save as automatically. -**Save as …**| Alt+F, A| Asks for a name and saves a copy. Use it to save your current setup under a new name, or to save for the first time from the blank template. -**Rename current profile …**| Alt+F, M| Renames the current profile's file and updates the window title. Does nothing on the blank template (there's no profile to rename). +**Save**| Ctrl+S| Updates the current profile with your current settings. If there's no current profile (you're on a new profile), this becomes Save as automatically. +**Save as …**| Alt+F, A| Asks for a name and saves a copy. Use it to save your current setup under a new name, or to save for the first time from a new profile. +**Rename current profile …**| Alt+F, M| Renames the current profile's file and updates the window title. Does nothing on a new profile (there's no profile to rename). **Lock profile (read-only)** (tickable)| Alt+F, L| When ticked, the current profile is loaded for use but RemSound will not save any of your changes back to it. The window title shows “(read-only)” so you can tell at a glance. Save (Ctrl+S) politely refuses with a hint to use Save as instead, and closing RemSound never asks “save changes?” — it just closes. Anything you've changed during the session is forgotten when RemSound closes; the file on disk is left exactly as it was. The lock setting is saved on the profile itself, so it sticks across launches. See Locking a profile for the full story. **Minimise to tray**| Alt+F, N| Hides the window down to the system tray (the small icons near the clock). The tray icon's hover summary tells you what RemSound is doing, and right-clicking it gives you Show RemSound, Enable sending, Enable receiving, your Profiles submenu, and Exit — see The system tray icon and its menu for the full rundown. To bring the window back, double-click the tray icon, pick “Show RemSound” from its menu, or use the “Show or hide window” global hotkey (set in the Keyboard shortcuts dialog, default Ctrl+Shift+F10). **Exit**| Alt+F, X (or Alt+F4)| Closes RemSound. If you have unsaved profile changes (and the profile isn't locked), it asks you first. @@ -303,7 +306,7 @@ Control| Shortcut| What it does **WASAPI inputs to send**| Alt+5| Tick which Windows input devices to capture (microphones, line-ins). **ASIO inputs to send**| Alt+2| (Shown when an ASIO driver is chosen.) Tick which ASIO channel pairs to capture and send. -All the device lists are checkable lists — tick or untick an item to include or exclude that device. Profiles save which devices are ticked; the blank template starts with everything unticked. +All the device lists are checkable lists — tick or untick an item to include or exclude that device. Profiles save which devices are ticked; a new profile starts with everything unticked. ### Receiving @@ -445,6 +448,19 @@ List| Contents| What ticking does There's also the **Add peer by IP (Alt+A)** button, which opens a small box for a computer name or address. It's useful for a first connection over a VPN, where discovery hasn't reached the other computer yet. +### Connecting to one specific IP address (and only that one) + +RemSound can reach another computer two ways, and the difference matters if a computer has more than one IP address: + + * **By name** — ticking someone in **Discovered peers**. RemSound found them from their announcement and the entry shows their computer name. This is the easy, automatic way on an ordinary network. + * **By a fixed IP** — **Add peer by IP (Alt+A)** , then type the exact address, for example `10.8.0.1`. RemSound talks to _that address and nothing else_ : it doesn't look up a name, so it can never drift to a different IP, and if that address isn't reachable, no connection is made at all. + + + +So to force a connection to one specific IP — say a machine that appears under two addresses and you only want one of them — add it by that IP and tick only that entry. If the same machine also turns up in Discovered peers under its _other_ address, it shows as a separate entry that you simply leave unticked; RemSound keeps the two apart by their actual address, so they never merge. + +Either way, **the profile remembers exactly what you ticked.** Tick a discovered name and the profile reconnects by that name next time; add and tick an IP and the profile reconnects to that exact IP. So the way to make a profile always use one specific IP is simply to add and tick it by that IP, then save the profile. + ### You only hear peers you've ticked Even if a peer is sending sound your way, you won't hear it until you've ticked their checkbox. This is deliberate — connecting is a step where you give your consent. A peer's name appears in Discovered the moment they come online, but they can't make any sound on your speakers until you say yes. @@ -718,7 +734,7 @@ Alt+A| Focus Artefact sound type Key| Action ---|--- -Ctrl+S| Save the current profile (or Save as if on the blank template) +Ctrl+S| Save the current profile (or Save as if on a new profile) Ctrl+K| Open the Keyboard shortcuts dialog Ctrl+P| Open the Preferences dialog Ctrl+R| Start or stop recording (toggles) @@ -1171,7 +1187,7 @@ NAT| Short for “Network Address Translation”. The way your router lets sever Carrier-grade NAT| An extra layer of NAT that some internet providers (especially on mobile broadband and some cable connections) put in between your router and the rest of the internet. Your home router opens a port fine, but the provider's NAT in front of it still blocks incoming connections. RemSound's UPnP status line warns you when this is the case — the way through it is a VPN like Tailscale, or the relay server. Auto-tune| RemSound automatically adjusting the latency target based on how evenly packets are arriving. Off by default; turn it on with the Continuous auto-tune checkbox on the Audio profile tab. Profile| A saved snapshot of every RemSound setting and choice — device ticks, send / receive states, codec, latency, peers, hotkeys, ASIO driver choice, the lot. Stored as one settings file. You pick one at startup, and can switch with File → Open profile. -Blank template| An entry in the startup profile picker that begins a session with all the defaults — nothing ticked, no peers, no saved name. A clean starting point for a new profile, or for a one-off session you don't plan to save. +New profile| An entry in the startup profile picker that begins a session with all the defaults — nothing ticked, no peers, no saved name. A clean starting point for a new profile, or for a one-off session you don't plan to save. Lock to audio clock| A sending-side timing mode that takes its timing straight from the sound device's hardware clock instead of from Windows. Removes a few milliseconds of wobble at tight latency targets. Off by default. Set with the checkbox of the same name on the Audio profile tab. Concealment| A receiving-side feature that fills brief gaps in the playback reserve with a small noise burst (the default) or an obvious click. You choose which on the Audio profile tab, in the _Artefact sound type_ list. Opus also has its own repair of lost packets on top of this. Remote control| A RemSound feature that lets one connected peer adjust another peer's listening volume (or toggle their receive mute) using global hotkeys. There are two sets of commands: one adjusts the receiver's RemSound volume slider, the other adjusts the receiver's Windows volume. Off by default on both ends; the receiver opts in via “Accept remote volume commands from peers” in the Preferences dialog (Ctrl+P), and the sender sets up hotkeys in the Keyboard shortcuts dialog (Ctrl+K). Designed for the “I'm NVDA-Remote'd into my desktop and want to nudge the laptop's volume” case. See section 15. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index f8f3e74..557b50d 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,45 +1,36 @@ -# RemSound v3.7 +# RemSound v3.8 -A smoothness-and-diagnosis release: changing devices mid-session no longer crackles, a one-off computer hiccup no longer balloons your latency, the microphone-privacy warning catches the hidden kinds of block, and the log now records enough to prove what happened when something goes wrong. +A usability release from user reports: you can now create a new profile at any time, the "different passwords" warning stays put, and the manual explains how to pin a connection to a specific IP. -## Changing devices mid-session is smoother +## New profile, any time -When you change capture devices — ticking sources on or off, or bringing an ASIO driver in or out — RemSound used to rebuild its sound engine immediately on every single change. A quick run of changes meant several rebuilds back to back, each one an audible crackle. Now RemSound **waits a moment for you to finish and rebuilds once**, to the final state. Reconfiguring no longer fights you. +There's a new **New profile** item at the top of the **File** menu (and **Ctrl+N**). It opens a fresh, unsaved session, so you can build a profile for a different setup from scratch. -## The auto-tuner ignores one-off hiccups +This closes a real gap: if you'd set RemSound to **start in a specific profile**, you booted straight past the profile picker and had **no way to reach a clean slate** to start something new — your only escape was opening an old profile by luck. Now you always can, without unchecking your startup setting. If your current profile has unsaved changes, New profile offers to save them first. The startup picker and the window title now read **"New profile"** as well, where they used to say "blank template". -Continuous auto-tune sizes your latency cushion from how late packets are arriving. It used to react to the **single worst moment** it had seen — so one brief stall (the kind a driver or Windows hiccup causes once and never again) could balloon the cushion to its maximum and disrupt audio for far longer than the hiccup itself. It now only raises the cushion when late audio **keeps coming** — sustained jitter still gets a fast response, a lone blip gets ignored. +## The "different passwords" warning stays on screen -## The mic-privacy warning catches hidden blocks +When you connect to someone whose password doesn't match yours, RemSound warns you. That warning was being raised from the once-a-second status update, which kept rebuilding the peer list underneath it and knocked it out of the foreground — so it could **flash away before you reached OK**. It now holds still and stays in front until you dismiss it. -Windows can block an app's microphone in ways that don't show up as the two obvious switches: a per-app block aimed at one program alone, or a block set by an administrator or workplace policy with no visible switch at all. When one of those is in place, the mic silently sends nothing — and RemSound's warning used to miss both kinds. It now **catches them too**, so "my mic sends silence and nothing warned me" should be gone. +## Pin a connection to a specific IP (documentation) -## The log can now prove what happened - -Four additions to RemSound's diagnostic log, aimed squarely at the questions we couldn't answer from past logs: - -- **How loud is what you're sending** (`capPeak` each second) — so silence versus real audio is now a fact in the log, not a guess. -- **The mic-privacy check's verdict** at every startup — whether or not it warned. -- **Every device tick/untick you make**, and **every device change Windows reports** — so when the device set changes mid-session, the log shows exactly what drove it. -- Auto-tune now logs both the worst moment it saw and the value it actually acted on, so you can see when it ignored a one-off spike. - -Nothing about these is audible — they just make the next bug report solvable from the first log. +If a computer has more than one IP address and you want to reach **only one** of them, you can — and you always could: use **Add peer by IP** and type the exact address. RemSound then talks to that address and nothing else (no name lookup, so it can't drift to a different IP). The manual now has a section, *"Connecting to one specific IP address (and only that one)"*, explaining the difference between connecting by name and by a fixed IP, and confirming that a profile remembers exactly what you ticked. ## Compatibility -**v3.7 talks to v3.3 through v3.6 with no trouble** — the over-the-network format hasn't changed, so you don't have to update both ends at once. (Everyone still needs **v3.3 or newer**, where end-to-end encryption came in.) +**v3.8 talks to v3.3 through v3.7 with no trouble** — the over-the-network format is unchanged, so you don't have to update both ends at once. (Everyone still needs **v3.3 or newer**, where end-to-end encryption came in.) ## Install -1. Download `RemSound-v3.7.zip` from this release. +1. Download `RemSound-v3.8.zip` from this release. 2. Close RemSound. 3. Extract the zip **over your existing RemSound folder**, overwriting program files when prompted. The zip is program files only — it won't touch your settings, profiles, logs, recordings, or sounds. 4. Run `RemSound.exe`. ## Upgrading -**From v3.6:** Help → Check for updates installs v3.7 with the new in-app updater — and if it ever can't finish, it puts v3.6 back exactly as it was. +**From v3.6 or v3.7:** Help → Check for updates installs v3.8 with the in-app updater — and if it can't finish, it puts your old version back exactly as it was. -**From v1.9–v3.5:** Check for updates works, but it uses your current version's older updater for this one hop. If auto-update has been failing on your machine, install by hand using the steps above — every update after that uses the new installer. +**From v1.9–v3.5:** Check for updates works, but it uses your current version's older updater for this one hop. If auto-update has been failing on your machine, install by hand using the steps above. **v1.8 and earlier:** the auto-updater in those versions can't install updates at all — install by hand using the steps above. diff --git a/readme.html b/readme.html index d8578a4..8955f07 100644 --- a/readme.html +++ b/readme.html @@ -76,7 +76,7 @@ ul, ol { padding-left: 1.4em; }

Let's assume you and a friend both have RemSound running, and that your two computers can reach each other on the network (the same Wi-Fi, the same Tailscale account, and so on).

    -
  1. Start RemSound. The first thing you'll see is the profile picker. On a brand-new install your only choice is (Blank template) — select it and press Enter or click OK. Later, once you've saved a setup or two of your own, this is the dialog where you choose which one to load. See Profiles for the full story.
  2. +
  3. Start RemSound. The first thing you'll see is the profile picker. On a brand-new install your only choice is New profile — select it and press Enter or click OK. Later, once you've saved a setup or two of your own, this is the dialog where you choose which one to load. See Profiles for the full story.
  4. Once the main window opens, go to the Audio inputs and outputs tab. Tick Receive audio (Alt+R), then tick the device you want incoming sound played through in WASAPI outputs for received sound (Alt+3).
  5. On the same tab, tick Send my audio (Alt+S) and tick your microphone in WASAPI inputs to send (Alt+5).
  6. Go to the Connectivity tab, find your friend in the Discovered peers (Alt+D) list, and tick them. If they aren't showing up, use Add peer by IP (Alt+A) and type their address.
  7. @@ -95,12 +95,12 @@ ul, ol { padding-left: 1.4em; }

    The startup picker

    -

    When RemSound starts, the first thing you see is the profile picker. It is a list of your saved profile names, with an extra entry called (Blank template) at the top. The keys are deliberately simple:

    +

    When RemSound starts, the first thing you see is the profile picker. It is a list of your saved profile names, with an extra entry called New profile at the top. The keys are deliberately simple:

    - + @@ -108,11 +108,13 @@ ul, ol { padding-left: 1.4em; }
    KeyAction
    Up / DownMove between profiles in the list.
    EnterLoad the highlighted profile (or the blank template) and open the main window.
    EnterLoad the highlighted profile (or a new profile) and open the main window.
    OK buttonSame as Enter.
    DelDelete the highlighted profile, after a yes / no confirmation.
    Browse… buttonChoose a different folder to read profiles from. Handy if you keep your profiles in Dropbox or another sync folder so they follow you between computers. Your choice is remembered next time RemSound starts.
    Alt+F4Closes the dialog and quits RemSound — in other words, “I don't want to start the program right now.”
    -

    The first profile in the list is highlighted to begin with, so on a fresh install where the only entry is (Blank template), you just press Enter to get going.

    +

    The first profile in the list is highlighted to begin with, so on a fresh install where the only entry is New profile, you just press Enter to get going.

    -

    What “Blank template” means

    +

    What “New profile” means

    -

    The blank template is a one-off session with all the defaults: nothing ticked in any device list, neither Receive nor Send turned on, the standard sound settings, no ASIO driver chosen, no remembered peers, and the standard hotkeys. You'd pick it for a quick session you don't plan to save, or as a clean starting point for a new profile. The Save button is hidden while you're on the blank template — there's no existing setup to update, only a new one to save.

    +

    A new profile is a one-off session with all the defaults: nothing ticked in any device list, neither Receive nor Send turned on, the standard sound settings, no ASIO driver chosen, no remembered peers, and the standard hotkeys. You'd pick it for a quick session you don't plan to save, or as a clean starting point for a new profile. The Save button is hidden while you're on a new profile — there's no existing setup to update, only a new one to save.

    + +

    Starting a new profile later: the picker only appears at startup, and if you've set RemSound to start in a specific profile you skip straight past it. So to start a brand-new profile at any time, use File → New profile (Ctrl+N, or Alt+F, W) — it opens a fresh, default session, ready for you to set up and then Save as. If your current profile has unsaved changes, it offers to save them first.

    Saving and updating

    @@ -120,8 +122,8 @@ ul, ol { padding-left: 1.4em; } - - + +
    ItemWhat it does
    File → Save (Ctrl+S)Updates the current profile with whatever your settings are right now. If you're on the blank template, this turns into Save as instead, because there's no existing profile to update.
    File → Save as… (Alt+F, A)Always available. Asks you for a name. From the blank template, this is how you create your first profile. From an existing profile, it makes a fresh copy under a new name and switches to that copy.
    File → Save (Ctrl+S)Updates the current profile with whatever your settings are right now. If you're on a new profile, this turns into Save as instead, because there's no existing profile to update.
    File → Save as… (Alt+F, A)Always available. Asks you for a name. From a new profile, this is how you create your first profile. From an existing profile, it makes a fresh copy under a new name and switches to that copy.

    The window title bar always shows which profile is in use: RemSound — Active profile: My session name.

    @@ -267,11 +269,12 @@ ul, ol { padding-left: 1.4em; } + - - - + + + @@ -341,7 +344,7 @@ ul, ol { padding-left: 1.4em; }
    ItemShortcutWhat it does
    New profileCtrl+N, or Alt+F, WStarts a brand-new profile from scratch — a fresh, unsaved session (everything unticked, nothing connected, default settings). This is how you create a profile for a different setup at any time, even when RemSound is set to start straight into a specific profile and you never see the picker. If your current profile has unsaved changes, it offers to save them first. Once you've set things up, use Save as to give the new profile a name.
    Open profile…Ctrl+O, or Alt+F, OOpens a Windows file picker showing your profiles folder. Pick a profile, and RemSound reloads using it (the window closes and reopens with all that profile's device choices, peers and settings restored). To delete a profile, right-click its entry inside the file picker and choose Delete — that lets Windows handle the deletion.
    Recent profiles →Alt+F, RA submenu listing the last five profiles you've opened, most recent first. Each row has a single-digit shortcut: while the submenu is open, press 1 for the most recent, 2 for the next, and so on up to 5. Or just select the one you want. It reloads the profile the same way Open profile does. If a recent profile's file has been deleted or moved away, it's left out of the submenu (it stays in the list in case the file comes back later — for example when you reconnect an external drive). If the list is empty, you see a greyed-out “(No recent profiles)” entry. The same list appears in the system-tray icon's Profiles submenu, with the same number shortcuts, so you can switch profiles without re-opening the main window.
    SaveCtrl+SUpdates the current profile with your current settings. If there's no current profile (you're on the blank template), this becomes Save as automatically.
    Save as…Alt+F, AAsks for a name and saves a copy. Use it to save your current setup under a new name, or to save for the first time from the blank template.
    Rename current profile…Alt+F, MRenames the current profile's file and updates the window title. Does nothing on the blank template (there's no profile to rename).
    SaveCtrl+SUpdates the current profile with your current settings. If there's no current profile (you're on a new profile), this becomes Save as automatically.
    Save as…Alt+F, AAsks for a name and saves a copy. Use it to save your current setup under a new name, or to save for the first time from a new profile.
    Rename current profile…Alt+F, MRenames the current profile's file and updates the window title. Does nothing on a new profile (there's no profile to rename).
    Lock profile (read-only) (tickable)Alt+F, LWhen ticked, the current profile is loaded for use but RemSound will not save any of your changes back to it. The window title shows “(read-only)” so you can tell at a glance. Save (Ctrl+S) politely refuses with a hint to use Save as instead, and closing RemSound never asks “save changes?” — it just closes. Anything you've changed during the session is forgotten when RemSound closes; the file on disk is left exactly as it was. The lock setting is saved on the profile itself, so it sticks across launches. See Locking a profile for the full story.
    Minimise to trayAlt+F, NHides the window down to the system tray (the small icons near the clock). The tray icon's hover summary tells you what RemSound is doing, and right-clicking it gives you Show RemSound, Enable sending, Enable receiving, your Profiles submenu, and Exit — see The system tray icon and its menu for the full rundown. To bring the window back, double-click the tray icon, pick “Show RemSound” from its menu, or use the “Show or hide window” global hotkey (set in the Keyboard shortcuts dialog, default Ctrl+Shift+F10).
    ExitAlt+F, X (or Alt+F4)Closes RemSound. If you have unsaved profile changes (and the profile isn't locked), it asks you first.
    ASIO inputs to sendAlt+2(Shown when an ASIO driver is chosen.) Tick which ASIO channel pairs to capture and send.
    -

    All the device lists are checkable lists — tick or untick an item to include or exclude that device. Profiles save which devices are ticked; the blank template starts with everything unticked.

    +

    All the device lists are checkable lists — tick or untick an item to include or exclude that device. Profiles save which devices are ticked; a new profile starts with everything unticked.

    Receiving

    @@ -490,6 +493,15 @@ Audient USB Audio ASIO Driver — Pair 3 (channels 5/6): Loop-back 1 (L) / L

    There's also the Add peer by IP (Alt+A) button, which opens a small box for a computer name or address. It's useful for a first connection over a VPN, where discovery hasn't reached the other computer yet.

    +

    Connecting to one specific IP address (and only that one)

    +

    RemSound can reach another computer two ways, and the difference matters if a computer has more than one IP address:

    + +

    So to force a connection to one specific IP — say a machine that appears under two addresses and you only want one of them — add it by that IP and tick only that entry. If the same machine also turns up in Discovered peers under its other address, it shows as a separate entry that you simply leave unticked; RemSound keeps the two apart by their actual address, so they never merge.

    +

    Either way, the profile remembers exactly what you ticked. Tick a discovered name and the profile reconnects by that name next time; add and tick an IP and the profile reconnects to that exact IP. So the way to make a profile always use one specific IP is simply to add and tick it by that IP, then save the profile.

    +

    You only hear peers you've ticked

    Even if a peer is sending sound your way, you won't hear it until you've ticked their checkbox. This is deliberate — connecting is a step where you give your consent. A peer's name appears in Discovered the moment they come online, but they can't make any sound on your speakers until you say yes.

    @@ -763,7 +775,7 @@ Audient USB Audio ASIO Driver — Pair 3 (channels 5/6): Loop-back 1 (L) / L

    File menu shortcuts (work from any tab)

    - + @@ -1218,7 +1230,7 @@ Use whatever key combinations you prefer (for example Ctrl+Shift+Up / Ctrl+Shift - + diff --git a/src/RemSound.App/AboutDialog.cs b/src/RemSound.App/AboutDialog.cs index 33bbe23..841a003 100644 --- a/src/RemSound.App/AboutDialog.cs +++ b/src/RemSound.App/AboutDialog.cs @@ -20,6 +20,23 @@ internal sealed class AboutDialog : Form /// updates" path. private const string ReleaseNotes = """ + RemSound v3.8 + + You can now start a brand-new profile at any time. A + new "New profile" item at the top of the File menu (or + Ctrl+N) opens a fresh, unsaved profile, so you can set up + a profile for a different connection from scratch — even + when RemSound is set to start straight into a specific + profile and you'd otherwise never see the picker. If your + current profile has unsaved changes, it offers to save + them first. The startup picker and the window title now + say "New profile" too, where they used to say "blank + template". + + And the "you and the other person have different + passwords" warning now stays on screen until you press + OK, instead of flashing away before you could reach it. + RemSound v3.7 Changing audio devices mid-session is smoother. A quick diff --git a/src/RemSound.App/MainForm.cs b/src/RemSound.App/MainForm.cs index 1ee62f2..22ef227 100644 --- a/src/RemSound.App/MainForm.cs +++ b/src/RemSound.App/MainForm.cs @@ -537,6 +537,13 @@ public sealed class MainForm : Form private string? currentProfilePath; private Profile? pendingProfile; public string? NextProfileTitleToLoad { get; private set; } + + /// Set by File → New profile. Program.cs's relaunch loop checks this FIRST and, when + /// true, rebuilds the form on a fresh blank template (, no title) + /// instead of loading a saved profile. It's the only way to reach a blank template mid-session + /// — the fix for being unable to create a new profile when "start with a specific profile" + /// boots the user straight past the picker (issue #6). + public bool LoadBlankTemplateNext { get; private set; } /// Full path of the next profile to load, set when the user opens a file via /// File → Open profile. Program.cs prefers this over /// when non-null — it deserialises the JSON from this exact path, not from the active @@ -1442,6 +1449,17 @@ public sealed class MainForm : Form var fileMenu = new ToolStripMenuItem("&File") { AccessibleName = "File menu" }; var helpMenu = new ToolStripMenuItem("&Help") { AccessibleName = "Help menu" }; + // New profile — starts a fresh blank template as a new unsaved session. Lives at the top of + // the File menu (the conventional New / Open / Save order) and, crucially, is reachable even + // when "start with a specific profile" boots straight past the picker (issue #6). Mnemonic + // Alt+F, W ('w' — N is taken by Minimise) plus the conventional Ctrl+N global shortcut. + var newProfileItem = new ToolStripMenuItem("Ne&w profile") + { + ShortcutKeys = Keys.Control | Keys.N, + AccessibleName = "New profile", + }; + newProfileItem.Click += (_, _) => NewProfile(); + var openItem = new ToolStripMenuItem("&Open profile...") { ShortcutKeys = Keys.Control | Keys.O, @@ -1534,6 +1552,7 @@ public sealed class MainForm : Form fileMenu.DropDownItems.AddRange(new ToolStripItem[] { + newProfileItem, openItem, recentProfilesMenu, saveItem, @@ -1810,6 +1829,49 @@ public sealed class MainForm : Form } } + /// File → New profile. Starts a fresh blank template as a new unsaved session — the way + /// to create a profile from scratch even when "start with a specific profile" boots the user + /// straight past the picker (issue #6). Offers to save the current profile first if it has + /// unsaved changes, then hands off to Program.cs's loop via . + private void NewProfile() + { + // Don't silently lose unsaved work when abandoning the current session for a blank one. + if (unsavedChanges && profileStore is not null && !currentProfileReadOnly) + { + var result = MessageBox.Show(this, + "You have unsaved changes to your current profile. Save them before starting a new profile?\n\n" + + "Yes — save, then start a new profile.\nNo — discard the changes and start a new profile.\nCancel — stay where you are.", + "RemSound — unsaved changes", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button3); + if (result == DialogResult.Cancel) return; + if (result == DialogResult.Yes) + { + if (string.IsNullOrEmpty(currentProfileTitle)) + { + // Current session is itself a blank template — needs a name before it can be saved. + var saveTitle = ProfileSaveAsPrompt.Show(this, profileStore, null); + if (string.IsNullOrEmpty(saveTitle)) return; // cancelled the name prompt → abort the whole thing + SaveProfileTo(saveTitle, showConfirmation: false); + } + else + { + SaveProfileTo(currentProfileTitle, showConfirmation: false); + } + } + // No → fall through, discarding the unsaved changes. + } + + // No profile-switch cue here — deliberately. Unlike Recent/Open (which play it on click), + // opening a fresh blank template should be silent; the switch sound feels wrong for "start + // new" (Ed, 2026-06-11). The rebuilt form never replays the cue either (see OnShown), so the + // entire New-profile path stays quiet. + LoadBlankTemplateNext = true; + // Stay in the tray if we were there, mirroring the quick-switch behaviour. + startNextInstanceMinimized = !Visible || WindowState == FormWindowState.Minimized; + AppendLogEntry("new profile: loading blank template"); + Close(); + } + /// Build the Record menu — Start/stop recording (toggling label), recording /// settings dialog, open the configured folder, and change the configured folder. /// Ctrl+R is the global toggle so the user can start/stop without going through the @@ -5699,14 +5761,14 @@ public sealed class MainForm : Form /// Window title shows the active profile name explicitly so the user knows what /// they're editing. Format: "RemSound — Active profile: My profile name" (loaded) or - /// just "RemSound" (blank template). Read-only profiles get a " (read-only)" suffix so + /// "RemSound — New profile" (a fresh, unsaved session). Read-only profiles get a " (read-only)" suffix so /// NVDA announces the lock state on every title change and sighted users see it at a /// glance — important context that "anything I change here won't be saved". private string FormatWindowTitle(string? loadedTitle) { var readOnlySuffix = currentProfileReadOnly ? " (read-only)" : ""; return string.IsNullOrEmpty(loadedTitle) - ? $"{AppName}{readOnlySuffix}" + ? $"{AppName} — New profile{readOnlySuffix}" : $"{AppName} — Active profile: {loadedTitle}{readOnlySuffix}"; } @@ -6080,11 +6142,16 @@ public sealed class MainForm : Form MarkProfileDirty(); } + /// True while a peer-security warning dialog is on screen — set so the 1 Hz status + /// tick that raises it can't re-enter and stack (or churn the UI under) a second one. + private bool securityWarningShowing; + /// Once a second, surface any password mismatch / out-of-date peer the receiver has /// detected from peers' advertised fingerprints — once per change, not every tick — so a /// silent encrypted stream is never an unexplained mystery. private void CheckPeerSecurity() { + if (securityWarningShowing) return; // a warning is already up — don't re-enter or stack foreach (var kv in receiver.GetPeerSecurityStatuses()) { var addr = kv.Key; @@ -6101,7 +6168,24 @@ public sealed class MainForm : Form var msg = status == PeerSecurityStatus.PasswordMismatch ? $"You and {addr} have different passwords, so no audio will pass between you.\n\nMake sure you've both set the same password (File → Change this profile's password)." : $"{addr} is running an older version of RemSound that can't connect securely. They need to update before audio can flow between you."; - MessageBox.Show(this, msg, AppName, MessageBoxButtons.OK, MessageBoxIcon.Warning); + // Show it front-and-centre, and FREEZE the 1 Hz status tick while it's up. This dialog is + // raised FROM that tick; left running, the tick keeps firing into the modal loop and + // re-runs the peer-list rebuild (SyncAllPeerLists) UNDER the dialog, which knocks it out + // of the foreground — it "flashed away before I could click OK" (Ed, 2026-06-11). The + // timer-stop + re-entry guard make exactly one warning show and stay put until dismissed. + securityWarningShowing = true; + statusTimer.Stop(); + try + { + ForegroundDialog.Show(owner => + MessageBox.Show(owner, msg, AppName, MessageBoxButtons.OK, MessageBoxIcon.Warning)); + } + finally + { + statusTimer.Start(); + securityWarningShowing = false; + } + return; // one warning per tick; a second affected peer surfaces on the next tick } } @@ -7241,7 +7325,7 @@ public sealed class MainForm : Form // is what unblocks NVDA-less or remote-session-dropped shutdowns from deadlocking // on a dialog the user can't reach. var skipPrompt = !string.IsNullOrEmpty(NextProfileTitleToLoad) || ReloadFromScratch - || currentProfileReadOnly || updatingInProgress; + || LoadBlankTemplateNext || currentProfileReadOnly || updatingInProgress; if (!skipPrompt && profileStore is not null && unsavedChanges) { diff --git a/src/RemSound.App/ProfileSelectionDialog.cs b/src/RemSound.App/ProfileSelectionDialog.cs index 73c20da..434b56b 100644 --- a/src/RemSound.App/ProfileSelectionDialog.cs +++ b/src/RemSound.App/ProfileSelectionDialog.cs @@ -4,7 +4,7 @@ namespace RemSound.App; /// /// Modal dialog shown at app startup to pick which profile to load. Listbox of saved -/// profile titles plus a synthetic "(Blank template)" entry for an unsaved-defaults +/// profile titles plus a synthetic "New profile" entry for a fresh unsaved-defaults /// session. Enter or OK selects; Esc does nothing (deliberately disabled — picking is /// required); Alt+F4 closes the dialog and exits the app; Del on a profile prompts to /// delete it with a yes/no confirm. The user can also browse to a custom profiles @@ -19,7 +19,15 @@ namespace RemSound.App; /// internal sealed class ProfileSelectionDialog : Form { - private const string BlankTemplateLabel = "(Blank template)"; + // The synthetic top-of-list entry that starts a fresh, unsaved session. A distinct marker TYPE + // (not a magic string) so it can never be confused with a real profile a user happens to name + // "New profile" — identity is by type; the display text is its ToString(). + private const string NewProfileLabel = "New profile"; + private static readonly NewProfileMarker NewProfileEntry = new(); + private sealed record NewProfileMarker + { + public override string ToString() => NewProfileLabel; + } private ProfileStore store; private readonly ListBox listBox; @@ -59,7 +67,7 @@ internal sealed class ProfileSelectionDialog : Form var instructions = new Label { - Text = "Select a profile and press Enter, or pick \"" + BlankTemplateLabel + "\" to start fresh.", + Text = "Select a profile and press Enter, or pick \"" + NewProfileLabel + "\" to start a new one.", Dock = DockStyle.Top, AutoSize = false, Height = 36, @@ -123,7 +131,7 @@ internal sealed class ProfileSelectionDialog : Form var prevSelectedTitle = GetSelectedTitle(); listBox.BeginUpdate(); listBox.Items.Clear(); - listBox.Items.Add(BlankTemplateLabel); + listBox.Items.Add(NewProfileEntry); foreach (var t in store.ListProfileTitles()) { // Wrap each title in a ProfileListItem so the displayed text can carry a @@ -153,9 +161,9 @@ internal sealed class ProfileSelectionDialog : Form folderLabel.AccessibleName = folderLabel.Text; } - /// Returns the currently-selected profile title (or the BlankTemplateLabel - /// constant for the blank template), unwrapping the ProfileListItem if needed. Returns - /// null when nothing is selected. Used by accept / delete to key into the store. + /// Returns the currently-selected profile title, unwrapping the ProfileListItem if + /// needed. Returns null for the synthetic "New profile" entry and when nothing is selected + /// (callers distinguish those by checking the item type directly). private string? GetSelectedTitle() { var item = listBox.SelectedItem; @@ -165,6 +173,7 @@ internal sealed class ProfileSelectionDialog : Form private static string? TitleOfItem(object? item) => item switch { null => null, + NewProfileMarker => null, // the synthetic "New profile" entry has no saved title string s => s, ProfileListItem p => p.Title, _ => item.ToString(), @@ -197,21 +206,24 @@ internal sealed class ProfileSelectionDialog : Form private void Accept() { - var selected = GetSelectedTitle(); - if (string.IsNullOrEmpty(selected)) return; - if (selected == BlankTemplateLabel) + var item = listBox.SelectedItem; + if (item is null) return; + if (item is NewProfileMarker) { + // New profile = a fresh unsaved session; a null title/profile signals that to the caller. SelectedTitle = null; SelectedProfile = null; } else { + var selected = TitleOfItem(item); + if (string.IsNullOrEmpty(selected)) return; SelectedTitle = selected; SelectedProfile = store.Load(selected); if (SelectedProfile is null) { MessageBox.Show(this, - $"Could not read profile \"{selected}\". Treating as blank template.", + $"Could not read profile \"{selected}\". Starting a new profile instead.", "RemSound", MessageBoxButtons.OK, MessageBoxIcon.Warning); SelectedTitle = null; } @@ -222,8 +234,10 @@ internal sealed class ProfileSelectionDialog : Form private void DeleteSelected() { - var selected = GetSelectedTitle(); - if (string.IsNullOrEmpty(selected) || selected == BlankTemplateLabel) return; + var item = listBox.SelectedItem; + if (item is null or NewProfileMarker) return; // can't delete the "New profile" entry + var selected = TitleOfItem(item); + if (string.IsNullOrEmpty(selected)) return; var result = MessageBox.Show(this, $"Delete profile \"{selected}\"? This cannot be undone.", "Confirm delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); diff --git a/src/RemSound.App/Program.cs b/src/RemSound.App/Program.cs index 5d50d3e..ea21293 100644 --- a/src/RemSound.App/Program.cs +++ b/src/RemSound.App/Program.cs @@ -235,7 +235,14 @@ internal static class Program // (e.g. legacy switch-by-title flows that pre-date the path tracking). nextPath = form.NextProfilePathToLoad; var nextTitle = form.NextProfileTitleToLoad; - if (!string.IsNullOrEmpty(nextPath)) + if (form.LoadBlankTemplateNext) + { + // File → New profile: rebuild on a fresh blank template, no saved profile. + profile = Profile.NewBlank(); + title = null; + nextPath = null; + } + else if (!string.IsNullOrEmpty(nextPath)) { try { diff --git a/src/RemSound.App/RemSound.App.csproj b/src/RemSound.App/RemSound.App.csproj index 4942cc4..2f14e3e 100644 --- a/src/RemSound.App/RemSound.App.csproj +++ b/src/RemSound.App/RemSound.App.csproj @@ -14,7 +14,7 @@ tag_name on the latest GitHub release; bump it on every public release. The AssemblyVersion / FileVersion default to this value, and Assembly.GetName().Version is what the About dialog and the updater both read. --> - 3.7.0 + 3.8.0
    KeyAction
    Ctrl+SSave the current profile (or Save as if on the blank template)
    Ctrl+SSave the current profile (or Save as if on a new profile)
    Ctrl+KOpen the Keyboard shortcuts dialog
    Ctrl+POpen the Preferences dialog
    Ctrl+RStart or stop recording (toggles)
    Carrier-grade NATAn extra layer of NAT that some internet providers (especially on mobile broadband and some cable connections) put in between your router and the rest of the internet. Your home router opens a port fine, but the provider's NAT in front of it still blocks incoming connections. RemSound's UPnP status line warns you when this is the case — the way through it is a VPN like Tailscale, or the relay server.
    Auto-tuneRemSound automatically adjusting the latency target based on how evenly packets are arriving. Off by default; turn it on with the Continuous auto-tune checkbox on the Audio profile tab.
    ProfileA saved snapshot of every RemSound setting and choice — device ticks, send / receive states, codec, latency, peers, hotkeys, ASIO driver choice, the lot. Stored as one settings file. You pick one at startup, and can switch with File → Open profile.
    Blank templateAn entry in the startup profile picker that begins a session with all the defaults — nothing ticked, no peers, no saved name. A clean starting point for a new profile, or for a one-off session you don't plan to save.
    New profileAn entry in the startup profile picker that begins a session with all the defaults — nothing ticked, no peers, no saved name. A clean starting point for a new profile, or for a one-off session you don't plan to save.
    Lock to audio clockA sending-side timing mode that takes its timing straight from the sound device's hardware clock instead of from Windows. Removes a few milliseconds of wobble at tight latency targets. Off by default. Set with the checkbox of the same name on the Audio profile tab.
    ConcealmentA receiving-side feature that fills brief gaps in the playback reserve with a small noise burst (the default) or an obvious click. You choose which on the Audio profile tab, in the Artefact sound type list. Opus also has its own repair of lost packets on top of this.
    Remote controlA RemSound feature that lets one connected peer adjust another peer's listening volume (or toggle their receive mute) using global hotkeys. There are two sets of commands: one adjusts the receiver's RemSound volume slider, the other adjusts the receiver's Windows volume. Off by default on both ends; the receiver opts in via “Accept remote volume commands from peers” in the Preferences dialog (Ctrl+P), and the sender sets up hotkeys in the Keyboard shortcuts dialog (Ctrl+K). Designed for the “I'm NVDA-Remote'd into my desktop and want to nudge the laptop's volume” case. See section 15.