foo_wavebar

foo_wavebar is a foobar2000 component that renders the waveform of the playing or selected track as an interactive seek bar. It provides a single Waveform Seek Bar panel — available in both the Default UI and Columns UI — backed by a shared analysis cache and swappable rendering engines.

Highlights

Rendering and Graphics

Waveform Analysis and Caching

Display and Styling

Configuration and Control

Platform and Interface

Verification

Run Requirements and Installation

Adding a Panel

The panel begins analyzing the current track automatically and shows an incremental waveform (if enabled) until the scan completes.

Usage

The panel is driven by the mouse directly on its surface and by a right-click context menu. Global behavior is set on the preferences page and each panel has its own configuration dialog.

Mouse Behavior

All panel instances share the same mouse-driven playback controls.

Action Stopped Paused Playing
Left-click Start playback at the clicked position. Move playback to the clicked position and remain paused. Continue playback from the clicked position.
Left double-click Start playback from the beginning of the current track, regardless of the clicked position. Resume playback from the position held before the double-click. Pause playback at the position held before the double-click.
Left drag Preview and seek without starting playback. Seek to the release position and remain paused. Continue playback from the release position.
Middle-click Start playback of the current track. Resume playback. Pause playback.
Mouse wheel No playback action; the event is passed to the parent window. Seek backward or forward and remain paused. Seek backward or forward and continue playing.
Right-click Open the context menu (downmix, scale mode, configuration and preferences). Same as stopped. Same as stopped.
Back / Forward (thumb) button Toggle borderless fullscreen for this panel. Same as stopped. Same as stopped.

Wheel direction, step size, and units are configurable in the global preferences. In Default UI layout-editing mode, right-click is passed to the host layout editor. Either mouse thumb button (XBUTTON1 / XBUTTON2) toggles fullscreen, matching the Fullscreen context-menu item and Alt+Enter.

Modified action Behavior
Ctrl + left drag Copy the selected waveform audio range to the clipboard.
Ctrl + Shift + left-click Save a waveform screenshot in <foobar2000 profile folder>\wavebar.

Context Menu

Right-click a panel to open the context menu. When the host layout is in editing mode (Default UI) or a Preferences/Configure dialog is open, some items are grayed out.

Preferences

The global preferences page lives under File > Preferences > Tools > Waveform Seek Bar. Its settings apply to every panel except where a panel overrides them in its own configuration dialog.

Configuration Dialog

Each panel has its own configuration dialog, opened from the context menu's Configure... item. Changes apply to that panel only and are reflected in real time. Only one configuration dialog can be open at a time.

Front end:

Color overrides:

Presets:

Tuning:

Channels:

Open Preferences: opens the global Waveform Seek Bar preferences page.

Reset to defaults: resets every setting in the dialog to the built-in defaults.

The component adds a Waveform Seek Bar submenu under foobar2000's Library main menu with cache-maintenance commands:

The active command's status, progress and Pause/Resume/Cancel controls are shown on the Waveform Seek Bar preferences page. Only one cache-maintenance command runs at a time.

Advanced Preferences

Under Preferences > Advanced > Tools > Waveform Seek Bar:

Rendering Engines

Three rendering front ends are available; the default renderer for new panels is set on the preferences page and each panel can override it.

If the selected engine cannot be created, the component automatically falls back to the next available one.

Screenshot

Hold Ctrl + Shift and left-click a panel to save a screenshot of the current waveform. The image is written as a PNG to the <foobar2000 profile folder>\wavebar directory, named wave_YYYYMMDD_HHMMSS_mmm.png.

Clipboard

Hold Ctrl and left-drag across a panel to select an audio range. On release, that range of the current track is rendered to the Windows clipboard as WAV audio, preserving the source channel count and sample rate. Dragging outside the panel cancels the selection.

Title Formatting

The component exposes a %wavebar_channels% Title Format field that resolves to the channel count of the track's cached waveform, for use in playlists and other Title Format contexts.

Waveform Cache Storage

Each stored signal contains minimum, maximum, and RMS arrays of 32-bit floats. The original 2048-bucket format therefore requires 2048 * 3 * 4 = 24,576 bytes (24 KiB) per signal before compression. The 4096-bucket format requires 48 KiB per signal.

Stored layout 2048 buckets per track 2048 buckets for 100k tracks 4096 buckets per track 4096 buckets for 100k tracks
Mono source or Store analyzed tracks in mono 24 KiB 2.46 GB 48 KiB 4.92 GB
Stereo plus accurate mono envelope 72 KiB 7.37 GB 144 KiB 14.75 GB
5.1 plus accurate mono envelope 168 KiB 17.20 GB 336 KiB 34.41 GB

These are uncompressed payload sizes. Track duration does not affect the stored size; channel count does. Short tracks that use the special resampling path are not persisted.

In actual use the compressed BLOB payload was 72.35% of the raw size. The complete SQLite database averaging 54.2 KiB per track for a 2048 bucket format.

Cache format Projected 100k tracks
Original 2048 buckets, measured 5.42 GB
4096 buckets, projected at the measured compression ratio approximately 10.8 GB

Waveform cache writes use zlib's default level 6.

Running foobar2000 under Proton

When foobar2000 is installed as a non-Steam title, it can be launched against its Proton prefix directly from the command line. Replace <id> with the app's compatdata identifier and adjust the Proton build path if you use a different Proton version.

STEAM_COMPAT_DATA_PATH="/home/deck/.steam/steam/steamapps/compatdata/<id>" \
STEAM_COMPAT_CLIENT_INSTALL_PATH="/home/deck/.steam/steam" \
"/home/deck/.steam/steam/steamapps/common/Proton - Experimental/proton" run \
"/home/deck/.steam/steam/steamapps/compatdata/<id>/pfx/drive_c/users/steamuser/foobar2000/foobar2000.exe"

Fonts under Wine and Proton

The configuration and preferences dialogs request the "Segoe UI" font. Windows ships this font, but Wine and Proton do not, so they substitute a default sans-serif face (often Liberation Sans or the host desktop font). To restore a Segoe UI-like appearance, use one of the following approaches. In each case, restart foobar2000 afterward.

  1. Copy Segoe UI into the prefix (most faithful; requires a Windows license). Locate the Wine/Proton prefix foobar2000 runs in. For a Steam/Proton shortcut this is ~/.steam/steam/steamapps/compatdata/<AppID>/pfx; for plain Wine it is $WINEPREFIX (default ~/.wine). Copy the Segoe UI family (segoeui.ttf, segoeuib.ttf, segoeuii.ttf, segoeuiz.ttf, segoeuil.ttf, seguisb.ttf, segoeuisl.ttf, seguibl.ttf and their italics) from a licensed C:\Windows\Fonts into <prefix>/drive_c/windows/Fonts/.
  2. Use Selawik (open, metric-compatible). Microsoft's MIT-licensed Selawik font is a drop-in, metric-compatible substitute for Segoe UI. Install selawik*.ttf into the prefix Fonts folder, then map the name: under the HKEY_CURRENT_USER\Software\Wine\Fonts\Replacements registry key, add a string value named Segoe UI with data Selawik.
  3. Substitute a font already on the system. Using the same Wine\Fonts\Replacements key, map Segoe UI to a similar installed face such as Open Sans, Noto Sans or Liberation Sans.

Note 1: The Wine\Fonts\Replacements key is also where to look for (and delete) an existing Segoe UI (and Segoe UI Semibold) mapping if a copied font is not being picked up. A stray mapping to a serif face such as Times New Roman is a common reason the dialogs render in a serif font even when Segoe UI is installed.

Note 2: Copying Segoe UI from a licensed Windows installation for personal use is permitted; it may not be redistributed, which is why Selawik exists for bundling a prefix.

Window Scaling under Wine and Proton

If the dialogs render too small or too large under Wine or Proton, adjust the prefix's DPI. Scaling is controlled through winecfg.

  1. Open winecfg for the prefix foobar2000 uses:
  1. In winecfg, open the Graphics tab and change the Screen resolution DPI value. 96 dpi is 100%; common steps are 120 (125%), 144 (150%) and 192 (200%). Higher values enlarge the entire UI; lower values shrink it.
  2. Click Apply / OK.

Note: The DPI value is stored in the registry at HKEY_CURRENT_USER\Control Panel\Desktop\LogPixels (a decimal REG_DWORD, e.g. 120), which you can also set directly with wine regedit instead of winecfg.

Custom Shaders (Experimental)

⚠️ HUGE NOTE — SUBJECT TO CHANGE WITHOUT NOTICE OR WARNING ⚠️

This is an experimental, unstable, developer-oriented feature. The shader interface described below — the entry points, texture and sampler registers, the Parameters constant-buffer layout and field meanings, the vertex feed, and the waveform texture format — may change, break, or be removed entirely in any build, with no notice, no warning, no migration path, and no attempt to preserve compatibility. A shader that works today may fail to compile or render incorrectly after any update. Do not rely on it. There is no guarantee of stability, support, or persistence.

The Direct3D 11 engine can load an external HLSL pixel/vertex shader at runtime, replacing the built-in waveform shader for that panel.

Loading a shader

Persistence

Whether a dropped shader persists depends on where the file lives:

To clear a custom shader (whether persisted or session-only) and restore the built-in one, use Reset custom shader in the panel's right-click menu (shown only while a Direct3D 11 panel has a shader active), or choose a preset whose shader path is empty.

Presets store the shader as a relative shader_path string in their JSON, for example:

"shader_path": "shaders/bars_reflection.hlsl"

Authoring a shader

A shader only needs to define a vertex entry point VS (compiled as vs_4_0) and a pixel entry point PS (compiled as ps_4_0). The component automatically prepends the shared declarations below before compiling, so your shader must not declare or #include the textures, sampler, constant buffer, or the VS_IN/PS_IN structs — just use them:

Texture2D<float4> tex   : register(t0); // waveform envelope
Texture2D<float4> bgTex : register(t1); // parent background (transparency)
SamplerState      sTex  : register(s0);

// Constant buffer — the field order and packing are load-bearing.
cbuffer Parameters : register(b0)
{
    float4 backgroundColor;
    float4 highlightColor;    // played wave color
    float4 selectionColor;
    float4 textColor;         // unplayed wave color (foreground)
    float2 viewportSize;      // current channel band size, in pixels
    float  cursorPos;         // play cursor, 0..1 along the time axis
    float  seekPos;           // seek target, 0..1
    bool   playbackActive;    // playback is active; drives played coloring
    bool   seeking;
    bool   horizontal;        // panel orientation
    bool   flipped_h;         // horizontal (time-axis) mirror
    bool   shade_played;
    bool   useCustomColors;   // 7-slot palette vs 4-color style
    bool   half_wave;
    bool   transparent;
    bool   flipped_v;         // vertical (amplitude) mirror
    bool   gap_dark;
    bool   cursorVisible;     // draw the cursor line marker
    float  scanProgress;      // waveform analysis progress, 0..1
    float4 rmsColor;
    float4 rmsPlayedColor;
    float4 fillPlayedColor;
    float4 bgPlayedColor;
    float4 fillUnplayedColor;
    float4 bgUnplayedColor;
    float4 cursorParams;      // .x width px, .y alpha, .z edge-fade, .w zero-line
    float4 cursorExtras;      // additional cursor and sampled-line state
    float4 windowSize;        // .xy window px, .z channel gap px, .w reveal-played
};

struct VS_IN { float2 pos : POSITION; float2 tc : TEXCOORD0; };
struct PS_IN { float4 pos : SV_POSITION; float2 tc : TEXCOORD0; };

So a minimal shader file is just your VS and PS (plus any helpers). Reported compile errors count from line 1 of your file. Because the block is prepended, these declarations may change between builds (see the warning above).

Pipeline conventions:

The component only provides these inputs — it is entirely up to the shader writer to honor them. The constant-buffer fields largely correspond to Configuration dialog settings; if a shader ignores a field or uses it differently, the matching tuning control will have no effect, a different effect, or an unintended effect. For example, a shader that never reads shade_played, half_wave, cursorParams, the color fields, and so on will not respond to those settings, and the built-in behavior for them does not apply. Matching the tuning dialog is the shader's responsibility, not the component's.

Reference

Component Identifiers (GUIDs)

Item GUID Purpose
Default UI element 7AFF636B-616F-4EBB-990C-9CDC09FE1527 The "Waveform Seek Bar" Default UI panel.
Columns UI panel 1758AA44-F83A-432F-88AA-A0E98497CCD3 The "Waveform Seek Bar" Columns UI panel.
Columns UI toolbar 398D31E4-6C1F-4545-9FE8-B546D1AFFC75 The "Waveform Seek Bar" Columns UI toolbar (rebar) variant.
Preferences page 6F2A9D31-8C44-4E2B-9F51-7A3E0B6C1D02 Page under Preferences > Tools.
Advanced Preferences branch CB775F9B-E3E7-40C5-A1DF-9FFA10BD3765 "Waveform Seek Bar" branch under Advanced > Tools.
Main menu group 25053399-FCE4-4ED3-8571-7E5E877C2D28 "Waveform Seek Bar" submenu under Library.
Cache service FAB05A5F-6018-4AB5-A27F-3A4753E7C9DC Waveform analysis/cache service.
Player service 39912A07-E84D-4DF9-8A27-6A3F75D7E363 Playback interface service.
Waveform query C0B698B5-D347-46B2-B64F-820A7470000B Asynchronous waveform request object.
Main menu: Sync waveforms with Library 3F6C1A82-9D4E-4B7A-B1C2-5E8F0A6D3C74 Command.
Main menu: Rescan all waveforms 287AEEC4-F88A-4520-9E3B-D4B6FD9C242F Command.
Main menu: Remove stale waveforms A8BD96C9-C4B6-4DEE-B29E-0695574F8C9C Command.
Main menu: Compact waveform database 506880BC-E8C9-4256-8F56-55C37315C705 Command.
Context menu: Extract/analyze DFEA3DE8-45B7-485B-8FDA-96187986AED5 Playlist context-menu command (analyze selection).
Context menu: Force re-extract E97BB75F-98DF-45D6-96D8-FC78FB2B07E8 Playlist context-menu command (re-analyze selection).
Context menu: Remove waveform B84348AD-40F2-4F22-8CAF-DDE9354C0855 Playlist context-menu command (remove selection's waveform).

Preferences Options

Global settings on the Preferences > Tools > Waveform Seek Bar page, persisted as foobar2000 cfg_var entries.

Option GUID Type Default
Match pattern A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E01 cfg_string Built-in match pattern
Use custom colors A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E02 cfg_bool false
Color palette A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E03 cfg_struct Built-in 7-slot palette
FPS A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E04 cfg_int 30
Seek per wheel notch (amount) A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E07 cfg_int 10
Wheel seek unit A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E08 cfg_int seconds
Invert wheel direction A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E09 cfg_bool false
Waveform track A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E0A cfg_int Playing track
Waveform storage A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E0D cfg_int Streams and tracks in library
Abort when below real time A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E0F cfg_bool true
Use saved defaults A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E16 cfg_bool false
Default renderer A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E17 cfg_int 0 (Direct3D 11.1)
Analyze tracks outside library A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E19 cfg_bool true
Incremental updates A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E1A cfg_bool true
Store analyzed tracks in mono A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E1B cfg_bool false
Concurrent scanning threads 48E5BCD0-48E8-4BBA-9D5E-8D7C1E93B511 cfg_int 3 (clamped 1–16)
Halt waveform processing A2C1E6F0-3B14-4E90-9C21-0F1A6D9B7E1C cfg_bool false (toggled from context menu)

Configuration Options

Per-panel settings from the Configure... dialog. Each panel instance stores these together as a JSON blob in its Default UI element / Columns UI panel configuration (keyed by the panel GUID above), not as individual cfg_var entries. The JSON keys, types, defaults and ranges are:

JSON key Type Default Range / values
frontend enum 0 (Direct3D 11.1) 0 = Direct3D 11.1, 2 = Direct2D 1.1, 3 = GDI
legacy_rendering bool false 4-color styling instead of the 7-slot palette
custom_colors[7] color palette colors Per-slot RGBA override values
custom_override[7] bool all false Per-slot: use the custom color instead of the global one
has_border bool false Draw window border
always_show_cursor bool false Show the play cursor over the waveform while playing; when off, it appears only if no waveform is available (never while stopped)
cursor_width float 2 Logical pixels, DPI-scaled at draw; fractional so any device-pixel width is selectable (~0.164)
cursor_translucency int 100 10100 percent opaque
soft_cursor bool false Draw the cursor with a soft feathered glow instead of a hard edge
no_seek_color bool false Draw the live-seek/scrub marker in the cursor color instead of a derived contrast color
shade_played bool true Shade the played portion
reveal_played bool false Draw only the played portion
flip_display bool false Flip horizontally (reverse time)
flip_vertical bool false Flip vertically (mirror amplitude)
flip_alternate bool false Flip every other channel (butterfly stereo; half-wave mode only)
half_wave bool false Draw only the upper half
zero_line bool false Draw the silence/zero line
edge_fade bool false Feather the waveform silhouette with anti-aliasing (Direct3D 11 and GDI)
scale int 0 (Original) 0 = Original, 1 = Normalize, 2 = RG track, 3 = RG album
db_scale bool false Amplitude on a decibel (dB) scale
db_floor float -60 -120-20 dB
scale_multiplier float 1.0 0.15.0
replaygain_boost_db int 0 030 dB
transparent_background bool false Pseudo-transparent background compositing
channel_gap float 2 Logical pixels between channel bands, DPI-scaled at draw; fractional so any device-pixel gap is selectable (032, Direct3D 11 only)
gap_dark bool false Darken the channel gap with translucent black (Direct3D 11 only)
shader_path string "" Relative path (under wavebar\) to a custom HLSL shader; empty = built-in (Direct3D 11 only, experimental)
downmix_display enum 0 (None) 0 = None, 1 = Mono, 2 = Stereo
channel_order list default order Channel enable/disable flags and top-to-bottom order
display_mode enum 0 (Normal) 05 (Normal, Only + half, Only - half, Average, Minimum, Maximum)

Advanced Options

Checkboxes under the Preferences > Advanced > Tools > Waveform Seek Bar branch (branch GUID CB775F9B-E3E7-40C5-A1DF-9FFA10BD3765).

Option GUID Default Effect
Optimize memory 2A4F1C8E-71B3-4D62-9A0E-5C2D88146F93 Checked (true) Releases GPU resources for hidden panels and rebuilds on show.
Disable flip-model presentation A2755B1A-7073-4F8D-974E-C4343B4CB39A Unchecked (false) Uses the legacy blt (DISCARD) swap effect instead of the DXGI flip model (Direct3D 11 and Direct2D); keeps the panel DWM-composited.
Debug output 1830F07C-5983-4F1D-8B3F-AD0151D8DD22 Unchecked (false) Logs scanning, screenshot and clipboard activity to the console.