MusicBee Clouseau
Documentation
Clouseau is a comprehensive diagnostic and introspection tool for MusicBee plugin developers. Beyond event logging, it provides deep reflection capabilities for exploring assemblies, invoking methods, and inspecting UI internals.
Overview
Purpose: Clouseau helps you understand MusicBee's plugin API and debug your own plugins through event monitoring and runtime introspection.
- Event Logging: Subscribe to all 40 MusicBee notification types with rich context (30+ fields per event)
- API Interception: Track timing and statistics for 60+ MusicBee API calls with slow call detection
- System Metrics: Monitor CPU, memory, GC pressure, and handle leaks in real-time
- Leak Detection: Track GDI, USER, and Kernel handle trends to identify resource leaks before they crash MusicBee
- Plugin Discovery: Scan and inspect all installed MusicBee plugins
- Assembly Browser: Explore all loaded .NET assemblies, namespaces, and types
- Method Invoker: Call any method via reflection with parameter input and return value display
- Menu Inspector: Walk MusicBee's complete menu hierarchy and invoke items programmatically
- Event Handler Inspector: View all event handlers attached to any WinForms control
- Spy Tab: Deep object inspection showing properties, fields, and runtime values
Scope: Clouseau runs as a MusicBee plugin and only inspects within MusicBee's process. Events are MusicBee notifications only. The Assembly Browser shows assemblies loaded in MusicBee (MusicBee.exe, plugins, .NET framework). System Metrics report MusicBee process stats. It cannot see other applications or system-wide activity outside MusicBee's sandbox.
About
Tools Menu
Dockable Panel
Live Events
Dashboard
Notification Subscription
ReceiveNotificationFlags
Clouseau subscribes to all four notification flags:
_about.ReceiveNotifications =
ReceiveNotificationFlags.PlayerEvents | // 0x1
ReceiveNotificationFlags.DataStreamEvents | // 0x2
ReceiveNotificationFlags.TagEvents | // 0x4
ReceiveNotificationFlags.DownloadEvents; // 0x8
NotificationType Events (40 Total)
| # | Event | Value | Category | Description |
|---|---|---|---|---|
| 1 | PluginStartup | 0 | Core | Plugin initialized successfully |
| 2 | TrackChanged | 1 | Player | Current track changed |
| 3 | PlayStateChanged | 2 | Player | Play/pause/stop state changed |
| 4 | AutoDjStarted | 3 | Player | AutoDJ mode started |
| 5 | AutoDjStopped | 4 | Player | AutoDJ mode stopped |
| 6 | VolumeMuteChanged | 5 | Player | Mute toggled |
| 7 | VolumeLevelChanged | 6 | Player | Volume level changed |
| 8 | NowPlayingListChanged | 7 | Queue | (Obsolete) Use PlayingTracksChanged |
| 9 | NowPlayingArtworkReady | 8 | Player | Artwork loaded for current track |
| 10 | NowPlayingLyricsReady | 9 | Player | Lyrics loaded for current track |
| 11 | TagsChanging | 10 | Tags | Tags about to be modified |
| 12 | TagsChanged | 11 | Tags | Tags were modified |
| 13 | RatingChanged | 12 | Tags | Track rating changed |
| 14 | PlayCountersChanged | 13 | Tags | Play/skip count updated |
| 15 | ScreenSaverActivating | 14 | System | Screen saver about to activate |
| 16 | RatingChanging | 15 | Tags | Rating about to change |
| 17 | TrackChanging | 16 | Player | Track about to change |
| 18 | ShutdownStarted | 17 | Core | MusicBee shutting down |
| 19 | NowPlayingListEnded | 18 | Queue | Reached end of queue |
| 20 | EmbedInPanel | 19 | UI | Plugin panel embedded |
| 21 | PlayerRepeatChanged | 20 | Player | Repeat mode changed |
| 22 | PlayerShuffleChanged | 21 | Player | Shuffle toggled |
| 23 | PlayerEqualiserOnOffChanged | 22 | Player | Equalizer toggled |
| 24 | PlayerScrobbleChanged | 23 | Player | Scrobbling toggled |
| 25 | ReplayGainChanged | 24 | Player | ReplayGain mode changed |
| 26 | FileDeleting | 25 | Library | File about to be deleted |
| 27 | FileDeleted | 26 | Library | File was deleted |
| 28 | ApplicationWindowChanged | 27 | UI | Window state changed |
| 29 | StopAfterCurrentChanged | 28 | Player | Stop after current toggled |
| 30 | LibrarySwitched | 29 | Library | Active library changed |
| 31 | FileAddedToLibrary | 30 | Library | New file added to library |
| 32 | FileAddedToInbox | 31 | Library | New file added to inbox |
| 33 | SynchCompleted | 32 | Sync | Device sync completed |
| 34 | DownloadCompleted | 33 | Download | Download finished |
| 35 | MusicBeeStarted | 34 | Core | MusicBee fully initialized |
| 36 | PlayingTracksChanged | 35 | Queue | Now playing list modified |
| 37 | PlayingTracksQueueChanged | 36 | Queue | Queue portion changed |
| 38 | PlaylistCreated | 37 | Playlist | New playlist created |
| 39 | PlaylistUpdated | 38 | Playlist | Playlist modified |
| 40 | PlaylistDeleted | 39 | Playlist | Playlist deleted |
MusicBee API Categories
1. MB_* - MusicBee Core
Core MusicBee operations: window handle, panels, menus, background tasks, localization.
MB_Trace()- Write to MusicBee trace logMB_GetWindowHandle()- Get main window handleMB_AddMenuItem()- Add menu itemMB_AddPanel()- Add dockable panelMB_CreateBackgroundTask()- Create background task
2. Setting_* - Settings
Access MusicBee settings: storage path, skin, fonts, thresholds.
Setting_GetPersistentStoragePath()- Plugin data folderSetting_GetSkin()- Current skin nameSetting_GetValue()- Get setting by ID
3. Library_* - Library Operations
Query library, get/set tags, manage artwork.
Library_QueryFilesEx()- Query all library filesLibrary_GetFileTag()- Get metadata tagLibrary_SetFileTag()- Set metadata tagLibrary_GetArtworkEx()- Get artwork
4. Player_* - Player Control
Playback control: play, pause, stop, volume, shuffle, repeat.
Player_GetPlayState()- Current play statePlayer_GetPosition()- Playback position (ms)Player_PlayPause()- Toggle play/pausePlayer_GetVolume()- Get volume (0.0-1.0)
5. NowPlaying_* - Current Track
Information about the currently playing track.
NowPlaying_GetFileUrl()- Current track pathNowPlaying_GetDuration()- Duration (ms)NowPlaying_GetFileTag()- Get tag valueNowPlaying_GetArtwork()- Get artwork
6. NowPlayingList_* - Queue
Now Playing queue management.
NowPlayingList_GetCurrentIndex()- Current indexNowPlayingList_QueueNext()- Queue as nextNowPlayingList_Clear()- Clear queue
7. Playlist_* - Playlists
Playlist management: create, modify, query.
Playlist_QueryPlaylists()- List playlistsPlaylist_CreatePlaylist()- Create playlistPlaylist_AppendFiles()- Add files
Log Entry Structure
{
"ts": "2026-01-01 14:32:01.234",
"level": "INFO",
"seq": "1234",
"cat": "Player",
"event": "TrackChanged",
"eventId": "1",
"msg": "Now playing: Dark Side of the Moon - Pink Floyd",
"src": "C:\\Music\\song.mp3",
"Timestamp": "2026-01-01T14:32:01.234Z",
"Artist": "Pink Floyd",
"Title": "Dark Side of the Moon",
"Album": "DSOTM",
"Duration": "234000",
"Bitrate": "320",
"Format": "FLAC",
"Position": "0"
}
The events.jsonl file contains one JSON object per line with ALL context data for easy parsing.
Log Categories
| Category | Events |
|---|---|
| Core | PluginStartup, ShutdownStarted, MusicBeeStarted |
| Player | TrackChanged, PlayStateChanged, Volume*, Shuffle, Repeat, etc. |
| Queue | PlayingTracksChanged, NowPlayingListEnded, etc. |
| Library | FileAdded*, FileDeleted, LibrarySwitched |
| Tags | TagsChanged, RatingChanged, PlayCountersChanged |
| Playlist | PlaylistCreated, PlaylistUpdated, PlaylistDeleted |
| Sync | SynchCompleted |
| Download | DownloadCompleted |
| UI | EmbedInPanel, ApplicationWindowChanged |
| System | ScreenSaverActivating |
Settings File
Location: %AppData%\MusicBee\mb_clouseau\settings.json
{
"logLevel": "verbose",
"enabledCategories": ["Player", "Library", "Tags", "Queue", "Playlist"],
"fileLogging": true,
"maxLogSizeMB": 10,
"autoScroll": true,
"timestampFormat": "HH:mm:ss.fff",
"showSourceFile": true,
"exportFormat": "json"
}
Architecture
mb_clouseau/
├── mb_clouseau.csproj # Project file
├── plugin/
│ ├── Plugin.cs # Entry point, event routing, inline log panel
│ ├── MusicBeeInterface.cs # MusicBee API definitions (44KB)
│ ├── NLog.config # Logging configuration
│ ├── settings.json # Default settings template
│ ├── Core/
│ │ ├── ClouseauSettings.cs # Settings manager (JSON)
│ │ ├── LogManager.cs # NLog wrapper with named loggers
│ │ └── StateManager.cs # Session state, event counts
│ ├── Logging/
│ │ ├── LogEntry.cs # Structured log entry model
│ │ ├── EventLogger.cs # Event handler with rich context for all 40 events
│ │ └── LogBuffer.cs # Thread-safe ring buffer with filtering/export
│ ├── Metrics/
│ │ ├── MetricsCollector.cs # Orchestrator (5s collection, 30s logging)
│ │ ├── MetricsSnapshot.cs # Snapshot data model
│ │ ├── SystemMetrics.cs # CPU, memory, disk
│ │ ├── ProcessMetrics.cs # MusicBee process stats
│ │ ├── ClrMetrics.cs # GC, heap, threading
│ │ └── AudioMetrics.cs # Audio device info
│ ├── Introspection/
│ │ ├── PluginInfo.cs # Plugin metadata model
│ │ ├── PluginDiscovery.cs # Plugin folder scanner
│ │ ├── PluginMonitor.cs # Track plugin registrations
│ │ ├── ApiInterceptor.cs # Hook MusicBee API calls
│ │ └── StateDumper.cs # Deep state snapshots
│ └── UI/
│ ├── LogViewerPanel.cs # Standalone log panel component
│ ├── SettingsDialog.cs # Full settings UI with tabs
│ └── DashboardForm.cs # Dashboard window with multiple tabs
├── deploy/www/ # Website files
├── README.md
├── SPEC.md
└── CHANGELOG.md
Building from Source
Prerequisites
- Visual Studio 2022 or .NET SDK
- .NET Framework 4.8 targeting pack
Build Commands
# Using build script
build.cmd Release
# Or using dotnet directly
dotnet build -c Release
Either method works. Output: publish\mb_clouseau.dll
Innovative Features
What makes Clouseau unique for MusicBee plugin development:
1. API Call Interception
Hook into MusicBee's API to log all plugin interactions. Every API call is timed and recorded:
- Call Statistics: Count, min/max/average duration per method
- Slow Call Detection: Alerts when calls exceed thresholds (default: warn at 100ms, error at 500ms)
- Anomaly Detection: Detects rapid-fire calls (>100/second) and high error rates (>10%)
- Recent Call History: Last 1,000 API calls with timing data
Enable/Disable: Settings > Introspection tab > "Track API Calls" checkbox, or set Performance.TrackApiCalls in settings.json
2. CLR/.NET Internals
Deep visibility into the .NET runtime - data developers rarely see:
- GC Collection Counts: Gen 0, Gen 1, Gen 2 (full) collections
- % Time in GC: How much CPU time the garbage collector consumes
- Heap Sizes: Gen 0/1/2 heap and Large Object Heap (LOH) sizes
- GC Pressure Detection: Automatic alerts when GC is working too hard
What is GC Pressure? When your application allocates memory rapidly, the garbage collector must run frequently to reclaim it. High GC pressure means >5 Gen 2 collections per minute or >20% time spent in GC. This causes application pauses and performance issues. Clouseau detects this automatically and logs warnings.
Metrics Tab
3. Handle Leak Detection
Track Windows handles to find resource leaks before they crash MusicBee:
- GDI Objects: Fonts, brushes, bitmaps, device contexts
- USER Objects: Windows, menus, icons, cursors
- Kernel Handles: Files, registry keys, events, mutexes
- Trend Analysis: 5-second snapshots over 1-minute sliding window
- Leak Source Identification: Reports which handle type is leaking (GDI, USER, or Kernel)
Understanding Leak Warnings: The leak detector uses a 60-second sliding window (12 samples at 5-second intervals). A warning fires when both conditions are met:
- More than 75% of samples show positive growth (handles or memory increasing)
- Cumulative increase exceeds threshold (10+ handles/minute or 5+ MB/minute)
Why Warnings Appear and Disappear
This is expected behavior, not a bug. Here's how it works:
- Plugin loads: Handles increase consistently (+2, +3, +2 per sample) → Warning fires after 30 seconds
- Plugin stabilizes: Growth stops or GC runs, some samples show negative deltas → <75% positive samples → Warning clears
- Oldest samples age out: After 60 seconds, the initial growth samples drop from the window → Warning stays clear
How to Interpret Warnings
| Scenario | Meaning | Action |
|---|---|---|
| Warning appears once, then clears | Normal startup overhead or temporary allocation | No action needed |
| Warning appears repeatedly over hours | Likely a real leak | Check metrics log for sustained growth |
| GDI Objects leaking | Fonts, brushes, bitmaps not disposed | Review Graphics object lifecycle |
| USER Objects leaking | Windows/controls not destroyed | Review Form/Control disposal |
| Kernel Handles leaking | Files, registry, events not closed | Review file/stream disposal |
Thresholds: Handle leak = 10+ handles gained per minute with sustained trend. Memory leak = 5+ MB gained per minute with sustained trend. Detection requires at least 30 seconds (6 samples) of data.
4. Deep State Dumps
Capture complete application state for debugging:
- Player state (current track, position, volume, shuffle, repeat)
- Loaded assemblies and their versions
- Thread information and stack traces
- Memory snapshot with heap statistics
- Registered plugins and their metadata
- Queue contents and playlist state
Create a dump: Dashboard > Diagnostics tab > "Create State Dump" button
Dumps Tab
5. Plugin Discovery
Scan and inspect all installed MusicBee plugins:
- Plugin name, version, author, type
- File location and load status
- Validation indicators (valid plugin vs. failed to load)
- Error details for plugins that failed to initialize
Plugins Tab
6. Rich Event Context
Every MusicBee event includes 30+ context fields:
- Track Metadata: Artist, Title, Album, Genre, Year, Rating, BPM, etc.
- Playback State: Position, Duration, Volume, Shuffle, Repeat, Crossfade
- Audio Properties: Bitrate, Sample Rate, Channels, Format, Codec
- Queue Info: Current index, has next/prior tracks
- File Properties: Size, Date Added, Last Played, Play Count
Events Tab
Configuration
Settings File
Location: %AppData%\MusicBee\mb_clouseau\settings.json
Key Settings
| Setting | Default | Description |
|---|---|---|
Performance.TrackApiCalls | true | Enable API call interception and timing |
Performance.WarnThresholdMs | 100 | Warn when API call exceeds this (ms) |
Performance.ErrorThresholdMs | 500 | Error when API call exceeds this (ms) |
SystemMetrics.Enabled | true | Collect CPU, memory, disk metrics |
SystemMetrics.CollectionIntervalMs | 5000 | How often to collect metrics (ms) |
UI.AutoScroll | true | Auto-scroll log panel to newest entries |
UI.MaxDisplayedEntries | 1000 | Maximum entries in log viewer |
Advanced.BufferSize | 10000 | Log entries kept in memory |
General
Metrics
Introspection
UI
Export
Advanced
Advanced Introspection Tools
Clouseau includes powerful introspection tools for deep debugging and exploration of MusicBee internals.
UI Gallery
Screenshot mode for capturing plugin dialogs and MusicBee windows.
- Auto-Refresh: Periodically capture updated screenshots
- Window Discovery: Lists all open windows and dialogs
- Export: Save screenshots for documentation or bug reports
Access: Dashboard > View menu > UI Gallery
App Spy Overlay
Transparent overlay that highlights UI elements under your cursor.
- Control Info: Name, type, and bounds of controls
- Click-Through: Overlay doesn't interfere with normal use
- Real-Time: Updates as you move the mouse
Access: Dashboard > View menu > Spy Overlay
Method Invoker
Browse loaded assemblies and invoke methods via reflection.
- Assembly Browser: Tree view of all loaded assemblies and types
- Method Filtering: Show/hide private methods, search by name
- Parameter Input: UI for entering method parameters with type validation
- Return Values: Display formatted results and execution time
- Static Methods: Invoke without requiring an object instance
Access: Dashboard > Invoke tab > Open button, or View menu > Method Invoker
Invoke Tab
Method Invoker
Event Inspector
View and manage event handlers attached to WinForms controls.
- Handler Discovery: List all event handlers on any control
- Handler Details: See method name, target type, and visibility
- Invoke Handlers: Trigger event handlers manually for testing
- Control Tree: Navigate the UI hierarchy to find controls
Access: Dashboard > Handlers tab > Event button
Handlers Tab
Event Inspector
Menu Inspector
Walk MusicBee's menu hierarchy and invoke menu items.
- Menu Tree: Complete hierarchy of all menus and submenus
- Item Details: Text, shortcut keys, enabled/checked state
- Invoke Items: Click menu items programmatically
- Search: Find menu items by text
Access: Dashboard > Handlers tab > Menu button
Menu Inspector
Spy Tab (Reflection Explorer)
Deep .NET introspection for exploring objects at runtime.
- Properties & Fields: View all properties and fields with values
- Type Information: See types, access modifiers, attributes
- Event Handlers: List subscribed handlers on any control
- Object Selection: Select controls via overlay for inspection
Access: Dashboard > Spy tab
Spy Tab
Use Cases
Plugin Development
See exactly what events fire when users interact with MusicBee. Understand the sequence and timing of notifications.
Debugging
When your plugin isn't receiving expected events, use Clouseau to verify what's actually happening.
Performance Profiling
Identify slow API calls, memory leaks, and GC pressure that affect user experience.
API Discovery
Learn what data is available from each API method by watching real calls in action.
Plugin Conflict Analysis
Watch what other plugins are doing. Debug conflicts by seeing who's changing what and when.
UI Reverse Engineering
Use the Spy Overlay and Event Inspector to understand how MusicBee's UI is constructed and how controls interact.
Case Study: Cross-Thread Panel Creation
This case study demonstrates how Clouseau's own logging capabilities helped diagnose a subtle UI bug.
The Problem
The Clouseau dockable panel appeared blank on MusicBee startup. The panel header (Clear, Dashboard, Settings buttons) was visible, but the ListBox showing events was completely empty. Toggling the panel off and back on would make it work correctly.
Initial Debugging Attempts
Several fixes were tried without success:
- Deferred control creation with
Application.Idle VisibleChanged/ParentChangedevent handlers with forced refreshHandleCreatedevent for timer initializationBeginInvokefor deferred updates- Delayed timer refresh (1.5 seconds after startup)
- Switching from owner-draw to standard ListBox mode
None of these worked because they were treating symptoms, not the root cause.
Using the Logs
The breakthrough came from checking Clouseau's own error log:
%AppData%\MusicBee\mb_clouseau\logs\errors.log
The log revealed the exact exception:
2026-01-01 03:38:13|ERROR|Clouseau.UI|Failed to create dockable panel
System.ArgumentException: Controls created on one thread cannot be parented
to a control on a different thread.
at System.Windows.Forms.Control.ControlCollection.Add(Control value)
at MusicBeePlugin.Plugin.OnDockablePanelCreated(Control panel)
Root Cause
MusicBee calls OnDockablePanelCreated from a background thread during startup, but WinForms controls must be created and parented on the UI thread. The exception was being caught and logged, but the panel appeared blank because no controls were added.
The Fix
public int OnDockablePanelCreated(Control panel)
{
// Initialize plugin (safe on any thread)
if (!_initialized) InitializePlugin();
// Marshal control creation to UI thread if needed
if (panel.InvokeRequired)
{
LogManager.UI.Debug("Marshaling to UI thread");
panel.Invoke(new Action(() => CreatePanelControls(panel)));
}
else
{
CreatePanelControls(panel);
}
return Convert.ToInt32(250 * dpiScaling);
}
Key Takeaways
1. Check the logs first: Clouseau logs to errors.log, events.log, and clouseau.log. The error log captured the exact exception with stack trace.
2. Log file locations:
%AppData%\MusicBee\mb_clouseau\logs\errors.log- Exceptions and errors%AppData%\MusicBee\mb_clouseau\logs\clouseau.log- General plugin activity%AppData%\MusicBee\mb_clouseau\logs\events.log- MusicBee notification events
3. Cross-thread exceptions in WinForms: When a panel appears blank or controls don't show, check for thread affinity issues. Use InvokeRequired and Invoke to marshal to the UI thread.
4. Silent failures: The try/catch was logging the error but the blank panel gave no visual indication. Always check logs when UI doesn't behave as expected.
5. Eat your own dogfood: Using Clouseau to debug Clouseau proved the value of comprehensive logging for plugin development.
MusicBee Clouseau