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.
%wavebar_channels% Title Format field.experimental-11.0-20260713 (Wine 11.0):
foo_wavebar.fb2k-component) from the component
page.foo_wavebar.fb2k-component into foobar2000 using
the File > Preferences > Components >
Install... menu item.wavecache.db), saved presets,
screenshots and clipboard data all live in the
<foobar2000 profile folder>\wavebar directory.The panel begins analyzing the current track automatically and shows an incremental waveform (if enabled) until the scan completes.
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.
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. |
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.
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.
VACUUM.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:
<name>.json in the
wavebar directory.default is reserved.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.
Under Preferences > Advanced > Tools > Waveform Seek Bar:
DISCARD) swap effect instead of the DXGI flip model
for the Direct3D 11 and Direct2D renderers. Disabled by default. Enable
it to keep the panel DWM-composited and avoid windowed
independent-flip/overlay promotion (for example NVIDIA "G-Sync
fullscreen only" engaging system-wide variable refresh), at the cost of
the flip model's efficiency.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.
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.
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.
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.
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.
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"STEAM_COMPAT_DATA_PATH points at the app's
compatdata/<id> directory; its pfx
subfolder is the Wine prefix used for the fonts and scaling tweaks
below.STEAM_COMPAT_CLIENT_INSTALL_PATH points at the Steam
installation root.foobar2000.exe inside
the prefix.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.
~/.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/.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.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\Replacementskey is also where to look for (and delete) an existingSegoe UI(andSegoe UI Semibold) mapping if a copied font is not being picked up. A stray mapping to a serif face such asTimes New Romanis 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.
If the dialogs render too small or too large under Wine or Proton, adjust the prefix's DPI. Scaling is controlled through winecfg.
WINEPREFIX=<prefix> winecfg.winetricks, select the prefix, then
choose Run winecfg.protontricks, select the prefix,
then choose Run winecfg.Note: The DPI value is stored in the registry at
HKEY_CURRENT_USER\Control Panel\Desktop\LogPixels(a decimalREG_DWORD, e.g. 120), which you can also set directly withwine regeditinstead of winecfg.
⚠️ 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
Parametersconstant-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.
.hlsl
extension onto the panel.Whether a dropped shader persists depends on where the file lives:
<foobar2000 profile>\wavebar\, e.g.
wavebar\shaders\my.hlsl) — the panel stores a
relative path to it. This persists with the panel, is
written into presets, and is reloaded on restart.
Because presets carry the path, choosing a preset also switches
the shader. If the referenced file is missing when it loads, an
error is logged and the built-in shader is used.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"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:
POSITION and TEXCOORD0 are both
float2. Multi-channel tracks are drawn as stacked bands,
once per enabled channel, each in its own viewport.tc.x is time in [0, 1] (with the horizontal
flip already applied) and tc.y is the amplitude axis in
[-1, 1], with 0 at the band centre line.4096 × 1
R32G32B32A32_FLOAT texture holding the signed envelope per
texel: .r = lower peak [-1, 1],
.g = upper peak [-1, 1], .b = RMS
[0, 1]. Mip levels are envelope-preserving (peaks are not
averaged away) so narrow panels keep their detail.transparent is
set, sample bgTex at
input.pos.xy / windowSize.xy to composite over the parent
window; otherwise fall back to backgroundColor.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.
| 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). |
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) |
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.1–64) |
cursor_translucency |
int | 100 |
10–100 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.1–5.0 |
replaygain_boost_db |
int | 0 |
0–30 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 (0–32,
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) |
0–5 (Normal, Only + half, Only - half,
Average, Minimum, Maximum) |
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. |