Bump to v2.0.0: ASIO startup splash so launch no longer looks frozen
Opening an ASIO driver takes 1-3 seconds, synchronously, during MainForm construction — confirmed in logs as a ~2.8s dead gap on an ASIO-profile launch (a WASAPI-only launch is ~131ms for the same stretch). During that gap the main window is blank / "Not Responding" and looks hung. New AsioLoadingSplash shows a small "Loading audio driver, please wait..." window on its OWN dedicated STA thread with its own message loop, so it stays painted while the main thread is blocked opening the driver. Program.cs starts it before new MainForm() and dismisses it after. Deliberately, the ASIO driver open stays on the main UI thread — that STA/message-pump thread is what ASIO/COM drivers are most compatible with, and moving the open off it risks breaking drivers that can't be tested. Only the cosmetic splash moved to a side thread; no ASIO/driver code is touched. Splash shows only for profiles with an ASIO driver selected; WASAPI-only profiles build fast and get no splash. Version bumped to 2.0.0 to mark the milestone. No wire-format or audio-pipeline changes — v1.5 through v2.0 interoperate. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
4344e3439d
commit
00cb4deef1
+15
-15
@@ -1,26 +1,26 @@
|
||||
# RemSound v1.9
|
||||
# RemSound v2.0
|
||||
|
||||
A critical fix to the auto-updater. Wire format and audio pipeline are unchanged from v1.4 onward — all versions interoperate.
|
||||
A smoother startup for setups that use an ASIO driver. Wire format and audio pipeline are unchanged from v1.4 onward — all versions interoperate.
|
||||
|
||||
## The fix
|
||||
## Change
|
||||
|
||||
**The auto-updater now actually installs updates.** Every release of RemSound up to and including v1.8 had a fault in the update step: the install-folder path passed to the internal file-copy command ended in a backslash, which Windows mis-interpreted, so the copy command was rejected and no files were ever replaced. "Check for updates" would download the new version, but the swap silently never happened and you stayed on the old version. That copy step is now fixed.
|
||||
**Startup no longer looks frozen when a profile uses an ASIO driver.** Opening an ASIO driver takes a couple of seconds, and that happens while the main window is being built — so the window used to appear blank or "Not Responding" during that time. RemSound now shows a small **"Loading audio driver, please wait..."** window while the driver opens, then brings up the main window as usual. Profiles that don't use an ASIO driver are unaffected — they start instantly, with no extra window.
|
||||
|
||||
## Important — install v1.9 by hand, just this once
|
||||
The ASIO driver itself is opened exactly as before; only the on-screen wait indicator was added, so this changes nothing about how RemSound talks to your audio hardware.
|
||||
|
||||
Because the fault was in the *old* version doing the updating, **"Check for updates" on v1.8 or earlier cannot install v1.9** — it will download it but fail to apply it. You need to install v1.9 manually this one time. After that the updater works correctly and every future update is automatic.
|
||||
## Install
|
||||
|
||||
To install v1.9 over an existing copy:
|
||||
|
||||
1. Download `RemSound-v1.9.zip` from this release.
|
||||
1. Download `RemSound-v2.0.zip` from this release.
|
||||
2. Close RemSound.
|
||||
3. Extract the zip **over your existing RemSound folder**, overwriting the program files when prompted. The zip contains program files only — it will **not** touch your profiles or your settings.
|
||||
4. Run `RemSound.exe`.
|
||||
|
||||
For a fresh install, just extract the zip anywhere you have write permission (e.g. `C:\RemSound\`, `Documents\RemSound\` — avoid `Program Files`) and run `RemSound.exe`. Allow on private networks when Windows Firewall prompts. Press F1 for the user manual.
|
||||
3. Extract the zip **over your existing RemSound folder**, overwriting program files when prompted. The zip is program files only — it will not touch your profiles or settings. (For a fresh install, just extract it anywhere you have write permission and run `RemSound.exe`.)
|
||||
4. Run `RemSound.exe`. Allow on private networks when Windows Firewall prompts. Press F1 for the user manual.
|
||||
|
||||
Requires the .NET 10 Desktop Runtime. If it's missing, Windows offers to fetch it on first launch.
|
||||
|
||||
## From v1.9 onward
|
||||
## Upgrading
|
||||
|
||||
**Help → Check for updates** works properly — v1.9 → v1.10 and every future release installs itself, no manual step needed.
|
||||
**v1.9 users:** Help → Check for updates works — it will fetch and install v2.0 automatically.
|
||||
|
||||
**v1.8 and earlier:** the auto-updater in those versions has a fault that prevents it from installing updates, so Check for updates will download v2.0 but not apply it. Install v2.0 by hand using the steps above — just this once. From the build you install onward, updates are automatic.
|
||||
|
||||
If you installed RemSound inside a synced folder (Dropbox etc.) and your install is v1.0 / v1.1 / v1.2, see the [v1.3 release notes](https://github.com/Ednunp/RemSound/releases/tag/v1.3) for one-time manual install steps.
|
||||
|
||||
@@ -20,6 +20,22 @@ internal sealed class AboutDialog : Form
|
||||
/// updates" path.</summary>
|
||||
private const string ReleaseNotes =
|
||||
"""
|
||||
RemSound v2.0
|
||||
|
||||
A smoother startup when a profile uses an ASIO driver.
|
||||
No wire-format or audio-pipeline changes — v1.5 through
|
||||
v2.0 peers interoperate.
|
||||
|
||||
Change:
|
||||
* Opening an ASIO driver takes a couple of seconds,
|
||||
and during that time the main window used to look
|
||||
frozen on startup. RemSound now shows a small
|
||||
"Loading audio driver" window while the driver
|
||||
opens, so startup no longer looks hung. The window
|
||||
then opens as normal. Profiles that don't use an
|
||||
ASIO driver are unaffected — they still start
|
||||
instantly, with no extra window.
|
||||
|
||||
RemSound v1.9
|
||||
|
||||
Critical auto-updater fix. No wire-format or
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using RemSound.Core;
|
||||
|
||||
namespace RemSound.App;
|
||||
|
||||
/// <summary>
|
||||
/// A small "Loading audio driver..." window shown on its OWN dedicated UI thread while the
|
||||
/// main thread builds <see cref="MainForm"/>.
|
||||
///
|
||||
/// Why it exists: opening an ASIO driver is slow — 1-3 seconds on many drivers — and that
|
||||
/// happens synchronously during MainForm construction. Without a splash the user sees
|
||||
/// nothing, or a blank "Not Responding" window shell, for those seconds, and it looks hung.
|
||||
///
|
||||
/// Why a SEPARATE thread: the ASIO driver must keep being opened on the main UI thread —
|
||||
/// that is the STA, message-pumping thread every ASIO / COM driver is most compatible with,
|
||||
/// and moving the driver open off it risks breaking drivers we cannot test. But the main
|
||||
/// thread is therefore blocked for the whole open, so a splash shown on it would itself be
|
||||
/// frozen. Running the splash on its own STA thread with its own message loop lets it paint
|
||||
/// and stay alive while the main thread is busy. No ASIO or driver code is touched — only
|
||||
/// this cosmetic window runs on the side thread.
|
||||
///
|
||||
/// Shown only for profiles that actually use an ASIO driver; a WASAPI-only profile builds
|
||||
/// the main window near-instantly and gets no splash (it would just flash).
|
||||
/// </summary>
|
||||
internal sealed class AsioLoadingSplash
|
||||
{
|
||||
private readonly Thread thread;
|
||||
private readonly ManualResetEventSlim shown = new(false);
|
||||
private volatile Form? form;
|
||||
|
||||
private AsioLoadingSplash()
|
||||
{
|
||||
thread = new Thread(RunSplash)
|
||||
{
|
||||
IsBackground = true,
|
||||
Name = "RemSound startup splash",
|
||||
};
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
// Wait (briefly, capped) for the window to actually be on screen before the caller
|
||||
// begins the slow ASIO work — so the user sees the splash, not a blank moment. The
|
||||
// cap means a splash hiccup can never stall startup.
|
||||
shown.Wait(TimeSpan.FromSeconds(2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the splash only when <paramref name="profile"/> has an ASIO driver selected —
|
||||
/// the only case where MainForm construction is slow. Returns null for WASAPI-only
|
||||
/// profiles. Dismiss the returned handle once the main window has been built.
|
||||
/// </summary>
|
||||
public static AsioLoadingSplash? StartIfNeeded(Profile? profile)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profile?.AsioDriverName)) return null;
|
||||
try
|
||||
{
|
||||
return new AsioLoadingSplash();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// The splash is purely cosmetic — if it can't even be created, let the app
|
||||
// start silently rather than have a splash failure block launch.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void RunSplash()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var splash = new Form
|
||||
{
|
||||
Text = "RemSound",
|
||||
FormBorderStyle = FormBorderStyle.FixedDialog,
|
||||
StartPosition = FormStartPosition.CenterScreen,
|
||||
ControlBox = false,
|
||||
MinimizeBox = false,
|
||||
MaximizeBox = false,
|
||||
ShowInTaskbar = false,
|
||||
TopMost = true,
|
||||
ClientSize = new Size(380, 96),
|
||||
AccessibleName = "RemSound is starting",
|
||||
};
|
||||
splash.Controls.Add(new Label
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
TextAlign = ContentAlignment.MiddleCenter,
|
||||
Text = "Loading audio driver, please wait...",
|
||||
AccessibleName = "Loading audio driver, please wait",
|
||||
});
|
||||
splash.Shown += (_, _) => shown.Set();
|
||||
form = splash;
|
||||
Application.Run(splash);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Never let a splash failure escape on its own thread.
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Unblock the constructor even if the window never managed to show.
|
||||
shown.Set();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the splash. Call from the main thread once <see cref="MainForm"/> has been
|
||||
/// constructed. Fire-and-forget — the splash's own background thread tears itself down.
|
||||
/// </summary>
|
||||
public void Dismiss()
|
||||
{
|
||||
try
|
||||
{
|
||||
shown.Set();
|
||||
var f = form;
|
||||
if (f is not null && f.IsHandleCreated && !f.IsDisposed)
|
||||
{
|
||||
f.BeginInvoke(() =>
|
||||
{
|
||||
try { f.Close(); }
|
||||
catch { /* already gone */ }
|
||||
});
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Cosmetic teardown — never throw into the startup path.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,13 @@ internal static class Program
|
||||
string? nextPath = null;
|
||||
while (true)
|
||||
{
|
||||
// Opening an ASIO driver is slow (1-3 s) and happens synchronously inside
|
||||
// MainForm construction. Show a "Loading audio driver" splash — on its own
|
||||
// thread, so it stays painted while this thread is busy — so startup doesn't
|
||||
// look hung. No-op for WASAPI-only profiles (construction is near-instant).
|
||||
var splash = AsioLoadingSplash.StartIfNeeded(profile);
|
||||
using var form = new MainForm(store, profile, title, nextPath);
|
||||
splash?.Dismiss();
|
||||
Application.Run(form);
|
||||
|
||||
if (form.ReloadFromScratch)
|
||||
|
||||
@@ -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. -->
|
||||
<Version>1.9.0</Version>
|
||||
<Version>2.0.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user