foo_vis_milk2 is a from-the-ground-up modernization of
Ryan Geiss' MilkDrop
2 open source release (version 2.25c, 5/13/13), rebuilt as a foobar2000 visualization
component. It carries the MilkDrop 2 preset ecosystem forward onto a
modern DirectX 11.1 pipeline while adding features, fixes, and platform
reach that go well beyond the original.
The list below highlights the improvements over the standard MilkDrop
2 open source release.
Rendering and Graphics
Modernization
Ported the entire renderer from DirectX 9 to
DirectX 11.1 (Direct3D 11.1, DXGI 1.6, Direct2D 1.1,
DirectWrite 1.1).
Shader Model 4.0/5.0 shader compilation selected
automatically from the GPU feature level.
Text layout and rendering moved from D3DX9/GDI to
DirectWrite + Direct2D — hardware-accelerated,
anti-aliased, and full Unicode.
Immediate-mode text queuing pipeline replacing the legacy
retained-mode text manager.
DXGI 1.6 integration: hybrid graphics (integrated +
discrete GPU) selection, high-DPI awareness, and multi-monitor
enumeration with fullscreen spanning.
HDR output — an opt-in FP16
(R16G16B16A16_FLOAT) presentation path with HDR10 display
detection and swap chain color-space negotiation; a final pass
linearizes the composited frame — MilkDrop output and overlaid text
alike — and encodes it for the display as either scRGB
linear or HDR10 (Rec.2020 + ST.2084 PQ,
R10G10B10A2_UNORM), so highlights above SDR white bloom
brighter.
Optional shader bytecode cache for faster preset
loading on subsequent runs, with clear-on-exit control.
Device-lost recovery with correct DPI/scaling
restoration.
Retired the legacy DirectX SDK, the DirectX End-User Runtimes, and
all D3DX dependencies (replaced with DirectXTK).
Preset
Compatibility and Automatic Shader Fixes
Compatible with the traditional MilkDrop 2
.milk preset ecosystem (Cream of the Crop,
original packs, BeatDrop collection, etc.), and additionally accepts the
MilkDrop 3 .milk2 format with all its features and
additional sprite blend modes.
Automatic DX9→DX11 shader fixes applied on load so
older presets work without user modifications:
IEEE 754 safe intrinsics for normalize(0),
sqrt(negative), log(x<=0),
tan() poles, pow(negative, frac),
asin()/acos() out of range,
atan2(0,0), and division by zero — preventing NaN
propagation through the feedback loop.
HLSL language fixes: bool-to-int l-value casts, implicit
double-to-float narrowing, self-shadowing variables, user variables
shadowing HLSL built-ins, matrix multiplication order, and macro
collision auto-#undef.
Backwards-compatibility shader flag plus Shader
Model 4.0 profile promotion so legacy DirectX 9-era HLSL syntax is
accepted.
Toggles for "Fix legacy shaders" and "Treat
shader compile warnings as errors" for preset development and
debugging.
One-shot shader source and disassembly dumps for
authoring and troubleshooting.
Expression Evaluation
Uses projectM
EEL as the default expression evaluator.
Original NS-EEL2 kept as a build-time-only
alternative (not linked in shipping builds).
Audio
Consumes floating-point audio directly from
foobar2000's playback pipeline instead of Winamp's 8-bit unsigned PCM
(single-precision float on 32-bit builds, double-precision
double on 64-bit builds).
Configurable FFT size for a high-resolution
sampler_fft spectrum.
Canonical GetFFT() /
GetWave() shader accessors — plus FFT
peak (GetFFTPeak(), GetFFTPeakHz())
and per-channel waveform (GetWaveLeft(),
GetWaveRight()) — with snake_case aliases for
audio-reactive shaders.
Smoothedbass/mid/treble/volume
bands exposed to shaders.
Shader Variables and
Accessors
Doubled the per-frame q variable bank
from q1–q32 to
q1–q64 (new
_qi–_qp uniform registers).
Mouse input in shaders — position
(mouse, mouse_x, mouse_y), hold,
and click.
System date/time uniforms — year,
month, day, weekday,
hour, minute, second, and total
seconds.
HSV color-shift controls
(colshift_hue/_saturation/_brightness)
with a built-in shiftHSV() helper.
Visualization intensity/shift/version and
gamma/echo constants.
Native builds for x86 (Win32), x64, ARM64, and
ARM64EC.
Ships as a foobar2000 component integrated into the
Default UI and Columns UI.
Configuration lives in foobar2000 preferences
(basic + advanced pages) instead of .ini files.
Linux support via Wine/Proton (e.g., SteamOS): an
exception firewall around the window procedure and render loop degrades
gracefully to a skipped frame instead of crashing, broader device-lost
recovery, and a Direct2D back-buffer interoperable fallback for
translation layers such as DXVK and vkd3d.
Requires only Windows 10+ with a DirectX 11.1 GPU; no external
runtimes.
Output Sharing and Window
Modes
Robust borderless fullscreen — a from-scratch,
borderless-window fullscreen path (deliberately not the Default
UI toggle_fullscreen() helper, which tears down and
recreates the instance) engineered for the most predictable, thorough
behavior across foobar2000's hosting models.
Works uniformly across Default UI elements, Columns UI
panels, and Popup dialog hosts, class-detecting each host
("Embedded Window Host" vs. "Popup Window Host") and fullscreening only
the paint window — exactly as games do — so the surrounding layout is
left intact.
Borderless (no exclusive mode) so it never seizes
the refresh rate, cooperates with the Desktop Window Manager, and keeps
Alt+Tab / Task View / move-to-monitor working.
State-preserving across the transition: window
placement, styles, owner, and live render state are captured on entry
and restored on exit back to the originating box, adapting to any layout
resize that happened meanwhile.
Popup decoupling — reparents and restyles the popup
host so the fullscreen window becomes independent of the main window and
appears correctly in the Task Switcher and Task View.
Proper identity — installs the component's
custom window icon on the fullscreen window instead of
showing a blank/system icon.
Topmost arbitration — temporarily clears the
foobar2000 "Always on top" state (which otherwise fights the Z-order)
and restores it on exit.
Display kept awake via
PowerCreateRequest() (system + display power request) and
screensaver suppressed while fullscreen, rescinded on
exit.
Auto-hiding cursor inside the fullscreen client
area (revealed for context-menu interaction), and transparency
automatically disabled on entry and re-established on exit.
Per-monitor by default (nearest display) with an
option to span the entire virtual screen; adapts to
resolution and DPI/scaling changes; supports multiple simultaneous
fullscreen instances.
Spout output — shares the live visualization as a
GPU texture over Spout (zero-copy
DirectX 11 texture sharing) for OBS and other Spout-aware apps.
Per-pixel transparency through DirectComposition —
a premultiplied-alpha swap chain bound to a composition visual for true
per-pixel window transparency; capability-probed, with a clean fallback
on hosts without DirectComposition (e.g., Wine/Proton).
Desktop watermark mode — a borderless,
click-through overlay with context-menu toggles to fill the
screen and sit below other windows as a
passive desktop watermark.
Input and Hotkeys
Rebindable keyboard shortcuts — a hotkey editor
with per-action overrides (persisted to the SQLite store
milk2_key.db), layered over the full built-in MilkDrop key
map.
Touch and pen gestures — pan to raise/lower the
preset rating, twist to toggle favorite, two-finger tap to toggle the
FPS display, and press-and-tap to step to the previous/next preset.
Mouse control — wheel to change presets,
double-click for fullscreen, and CTRL+Left-Click for a
screenshot.
Context-aware right-click menu — entries surface
only when their feature is enabled (preset schedule, annotations,
keybindings), reflect live state with check marks (playlist, album art,
help, transparency), and gray out actions that are unavailable in the
current mode (dialog commands while another dialog is open,
fullscreen-restricted items), with optional inline command
descriptions.
Presets, Sprites, and Text
Preset load dialog,
random/sequential ordering, 64-deep
history, preset lock, and per-preset
ratings (rating-weighted random selection).
Mashup mode — combine warp, comp, and base from
three different presets live.
18 transition blend patterns (fade,
directional/checkerboard wipe, plasma, radial, clock, spiral, rhombus,
curtain, bubble, and more) plus beat-driven hard cuts.
Preset schedule and preset picker
dialogs.
Preset annotations with a dedicated annotator
dialog (persisted to the SQLite store milk2_tag.db).
Recursive subdirectory preset scanning;
configurable preset directory with %fb2k_profile_path% and
environment-variable expansion.
Sprites (image overlays with blend modes),
custom messages, song-title
animations, and drag-and-drop of
.milk/.milk2 presets,
.wave/.shape definitions, and image files as
sprites (PNG, JPEG, DDS, BMP, TGA, TIFF, WebP, GIF, AVIF).
Album-art cover sprite driven by foobar2000
metadata and refreshed via remote signal.
Font picker with live preview — the font-selection
combo boxes render each face in its own typeface.
Shadertoy Subsystem
Built-in Shadertoy rendering subsystem that runs
GLSL shader-art presets alongside the MilkDrop engine, saved as the
JSON-based .milk3 format — extending the component beyond
the MilkDrop preset formats.
GLSL→HLSL transpiler — a pure text transform that
rewrites Shadertoy intrinsics (mix()→lerp(),
fract()→frac(),
mod()→glsl_mod() (floor-based modulo),
atan(y,x)→atan2(y,x),
texture*→tex2D*), guards reserved words,
expands vector-constructor splats, and corrects matrix-multiply
operand order for HLSL row-major semantics; compiled with
D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY.
Multi-pass pass graph: shared
Common code, Buffer A–D with
per-buffer double-buffered (ping-pong) feedback in FP16
(R16G16B16A16_FLOAT), and a final Image
pass to the screen.
Standard Shadertoy uniform set support (iResolution,
iTime, iTimeDelta, iFrame,
iFrameRate, iMouse, iDate,
iSampleRate,
iChannelTime/iChannelResolution).
Audio channel — a 512×2 texture (row 0 = FFT
spectrum with decaying-peak normalization, row 1 = waveform) bound as an
iChannel, so imported shaders react to foobar2000
audio.
Load and import paths: .milk3 from the
preset directory plus drag-and-drop of
.milk3 / .glsl / .frag /
.fs files onto the visualization; the engine switches to
Shadertoy automatically when a Shadertoy preset loads and back to
MilkDrop when a .milk/.milk2 preset
loads.
Remote Control
Milkwave-compatible named-pipe endpoint per
visualization instance:
\\.\pipe\Milkwave_<foobar2000 PID>_<instance ID>,
enabling PID-based discovery and duplex control with no hidden
windows.
Incoming commands include preset next/previous, screenshot capture,
fullscreen toggle, cover refresh, clear texts/sprites, custom message
injection, text/virtual-key input, preset lock/unlock, and a
STATE broadcast (PRESET=...,
SETTINGS=..., PROFILE=...).
Standalone Remote application (adapted Milkwave
Remote and upgraded to .NET 10) to drive the component over the pipe;
because the endpoint is Milkwave-compatible, the original Milkwave
Remote may also work.
Engineering and Developer
Experience
vis_milk2 modernized to C++20; builds
clean under /W4 /WX with no
exclusions.
Buildable with the AddressSanitizer (on Win32, x64,
and ARM64) plus profile and fuzzer configurations.
All string/memory operations migrated to secure CRT
variants; deprecated/insecure functions rewritten and unused
functionality removed.
Several hand-rolled containers/utilities replaced with
STL equivalents.
PCH + multiprocessor compilation for fast builds;
external libraries (foobar2000 SDK, Columns UI SDK, NS-EEL2, projectM
EEL, DirectXTK, CSV parser, JSON, SQLite, Spout) refactored into their
own Visual Studio projects, with an automated setup
script and patches that fetch, integrate, and wire each
dependency into the solution.
CI pipeline (GitHub Actions), a minimal
unit test with API service mocks, and enforced
formatting (ClangFormat), consistent line endings, and file
encodings.
Latest dependency versions across the board (foobar2000 SDK, Windows
11 SDK, MSVC toolset, projectM-eval, NS-EEL2, CSV and JSON parsers,
SQLite, Spout).
Thank you to everyone in the HydrogenAudio
forums who use and report issues. The component would not be
anywhere near this quality without our interactions.
Also big appreciation to the broader MilkDrop community: