MusicBee Clouseau | Documentation | HALRAD Research

Clouseau

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.

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.

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
1PluginStartup0CorePlugin initialized successfully
2TrackChanged1PlayerCurrent track changed
3PlayStateChanged2PlayerPlay/pause/stop state changed
4AutoDjStarted3PlayerAutoDJ mode started
5AutoDjStopped4PlayerAutoDJ mode stopped
6VolumeMuteChanged5PlayerMute toggled
7VolumeLevelChanged6PlayerVolume level changed
8NowPlayingListChanged7Queue(Obsolete) Use PlayingTracksChanged
9NowPlayingArtworkReady8PlayerArtwork loaded for current track
10NowPlayingLyricsReady9PlayerLyrics loaded for current track
11TagsChanging10TagsTags about to be modified
12TagsChanged11TagsTags were modified
13RatingChanged12TagsTrack rating changed
14PlayCountersChanged13TagsPlay/skip count updated
15ScreenSaverActivating14SystemScreen saver about to activate
16RatingChanging15TagsRating about to change
17TrackChanging16PlayerTrack about to change
18ShutdownStarted17CoreMusicBee shutting down
19NowPlayingListEnded18QueueReached end of queue
20EmbedInPanel19UIPlugin panel embedded
21PlayerRepeatChanged20PlayerRepeat mode changed
22PlayerShuffleChanged21PlayerShuffle toggled
23PlayerEqualiserOnOffChanged22PlayerEqualizer toggled
24PlayerScrobbleChanged23PlayerScrobbling toggled
25ReplayGainChanged24PlayerReplayGain mode changed
26FileDeleting25LibraryFile about to be deleted
27FileDeleted26LibraryFile was deleted
28ApplicationWindowChanged27UIWindow state changed
29StopAfterCurrentChanged28PlayerStop after current toggled
30LibrarySwitched29LibraryActive library changed
31FileAddedToLibrary30LibraryNew file added to library
32FileAddedToInbox31LibraryNew file added to inbox
33SynchCompleted32SyncDevice sync completed
34DownloadCompleted33DownloadDownload finished
35MusicBeeStarted34CoreMusicBee fully initialized
36PlayingTracksChanged35QueueNow playing list modified
37PlayingTracksQueueChanged36QueueQueue portion changed
38PlaylistCreated37PlaylistNew playlist created
39PlaylistUpdated38PlaylistPlaylist modified
40PlaylistDeleted39PlaylistPlaylist deleted

MusicBee API Categories

1. MB_* - MusicBee Core

Core MusicBee operations: window handle, panels, menus, background tasks, localization.

2. Setting_* - Settings

Access MusicBee settings: storage path, skin, fonts, thresholds.

3. Library_* - Library Operations

Query library, get/set tags, manage artwork.

4. Player_* - Player Control

Playback control: play, pause, stop, volume, shuffle, repeat.

5. NowPlaying_* - Current Track

Information about the currently playing track.

6. NowPlayingList_* - Queue

Now Playing queue management.

7. Playlist_* - Playlists

Playlist management: create, modify, query.

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
CorePluginStartup, ShutdownStarted, MusicBeeStarted
PlayerTrackChanged, PlayStateChanged, Volume*, Shuffle, Repeat, etc.
QueuePlayingTracksChanged, NowPlayingListEnded, etc.
LibraryFileAdded*, FileDeleted, LibrarySwitched
TagsTagsChanged, RatingChanged, PlayCountersChanged
PlaylistPlaylistCreated, PlaylistUpdated, PlaylistDeleted
SyncSynchCompleted
DownloadDownloadCompleted
UIEmbedInPanel, ApplicationWindowChanged
SystemScreenSaverActivating

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

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:

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:

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.

3. Handle Leak Detection

Track Windows handles to find resource leaks before they crash MusicBee:

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:

  1. More than 75% of samples show positive growth (handles or memory increasing)
  2. 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:

How to Interpret Warnings

Scenario Meaning Action
Warning appears once, then clearsNormal startup overhead or temporary allocationNo action needed
Warning appears repeatedly over hoursLikely a real leakCheck metrics log for sustained growth
GDI Objects leakingFonts, brushes, bitmaps not disposedReview Graphics object lifecycle
USER Objects leakingWindows/controls not destroyedReview Form/Control disposal
Kernel Handles leakingFiles, registry, events not closedReview 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:

Create a dump: Dashboard > Diagnostics tab > "Create State Dump" button

5. Plugin Discovery

Scan and inspect all installed MusicBee plugins:

6. Rich Event Context

Every MusicBee event includes 30+ context fields:

Configuration

Settings File

Location: %AppData%\MusicBee\mb_clouseau\settings.json

Key Settings

Setting Default Description
Performance.TrackApiCallstrueEnable API call interception and timing
Performance.WarnThresholdMs100Warn when API call exceeds this (ms)
Performance.ErrorThresholdMs500Error when API call exceeds this (ms)
SystemMetrics.EnabledtrueCollect CPU, memory, disk metrics
SystemMetrics.CollectionIntervalMs5000How often to collect metrics (ms)
UI.AutoScrolltrueAuto-scroll log panel to newest entries
UI.MaxDisplayedEntries1000Maximum entries in log viewer
Advanced.BufferSize10000Log entries kept in memory

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.

Access: Dashboard > View menu > UI Gallery

App Spy Overlay

Transparent overlay that highlights UI elements under your cursor.

Access: Dashboard > View menu > Spy Overlay

Method Invoker

Browse loaded assemblies and invoke methods via reflection.

Access: Dashboard > Invoke tab > Open button, or View menu > Method Invoker

Event Inspector

View and manage event handlers attached to WinForms controls.

Access: Dashboard > Handlers tab > Event button

Menu Inspector

Walk MusicBee's menu hierarchy and invoke menu items.

Access: Dashboard > Handlers tab > Menu button

Spy Tab (Reflection Explorer)

Deep .NET introspection for exploring objects at runtime.

Access: Dashboard > 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:

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:

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.

Clouseau

MusicBee Clouseau