diff --git a/MainWindow.xaml b/MainWindow.xaml
index 249c282..e0e4173 100644
--- a/MainWindow.xaml
+++ b/MainWindow.xaml
@@ -924,6 +924,12 @@
VerticalAlignment="Stretch"/>
+
+
+
Raised when playback ends or is stopped (not on natural-end loop).
- public event Action? PlaybackEnded;
+ public event Action? PlaybackEnded;
public string? TrackPath { get; private set; }
@@ -122,6 +122,6 @@ public sealed class MusicPlayer : IDisposable
return;
}
- PlaybackEnded?.Invoke();
+ PlaybackEnded?.Invoke(e.Exception);
}
}
diff --git a/ViewModels/MainViewModel.cs b/ViewModels/MainViewModel.cs
index c793651..53b6536 100644
--- a/ViewModels/MainViewModel.cs
+++ b/ViewModels/MainViewModel.cs
@@ -476,6 +476,7 @@ public class MainViewModel : ViewModelBase
// ─── Mic status dot (the MIC button) ───
private static readonly SolidColorBrush MicProblemBrush = CreateBrush("#f1c40f");
+ private static readonly SolidColorBrush TraxIdleBrush = CreateBrush("#555");
/// Mic connection state, driven by the mixer's MicConnected/MicFailed
/// events and the startup device check (see StartMicCaptureAsync).
@@ -525,12 +526,19 @@ public class MainViewModel : ViewModelBase
}
}
- /// TRAX status dot: green = playing, yellow = loaded/stopped, red = no track.
+ private string? _traxError;
+
+ /// Error message from the last TRAX load/playback failure; null = no error.
+ public string? TraxError
+ {
+ get => _traxError;
+ private set => SetProperty(ref _traxError, value);
+ }
+
+ /// TRAX status dot: green = playing, gray = idle or no track.
public SolidColorBrush TraxDotBrush => _musicPlayer.IsPlaying
? BarOnBrush
- : _music != null && !string.IsNullOrWhiteSpace(_music.TrackPath)
- ? MicProblemBrush
- : BarOffBrush;
+ : TraxIdleBrush;
public string TraxToolTip => _musicPlayer.TrackName != null
? $"TRAX: {_musicPlayer.TrackName} — left-click {(IsMusicPlaying ? "pauses" : "plays")}, right-click chooses a track"
@@ -574,13 +582,14 @@ public class MainViewModel : ViewModelBase
_musicPlayer.Load(_music.TrackPath);
UpdateTraxLocalGain();
_music.IsEnabled = true;
+ TraxError = null;
if (play)
_musicPlayer.Play();
}
catch (Exception ex)
{
AppLog.Write($"TRAX: failed to load '{_music.TrackPath}': {ex.Message}");
- _music = null;
+ TraxError = $"Failed to load: {Path.GetFileName(_music.TrackPath)} — {ex.Message}";
}
RefreshTraxUi();
ScheduleSave();
@@ -590,10 +599,13 @@ public class MainViewModel : ViewModelBase
private void PauseTrax() => _musicPlayer.Pause();
- private void OnTraxPlaybackEnded()
+ private void OnTraxPlaybackEnded(Exception? ex)
{
- // Natural end loops inside the player; here only an explicit stop or a
- // device failure lands — flip the dot back to loaded/stopped.
+ if (ex != null)
+ {
+ AppLog.Write($"TRAX: playback error: {ex.Message}");
+ TraxError = $"Playback error: {ex.Message}";
+ }
RefreshTraxUi();
}