foo_vis_milk2 Manualfoo_vis_milk2 is a DirectX 11.1 music visualizer
component for foobar2000, based on the MilkDrop 2 engine. It renders
real-time visual effects driven by audio input, using HLSL shaders and a
per-frame expression evaluation system. foo_vis_milk2
supports x86, x64, ARM64 and ARM64EC architectures.
foo_vis_milk2.fb2k-component from the component
page or GitHub
Releases.foo_vis_milk2.fb2k-component via File
> Preferences > Components > Install...Once running, the visualizer receives audio and metadata directly from foobar2000's playback pipeline. Play music and visuals respond automatically.
Press F1 for the built-in help overlay.
Some features such as hybrid graphics, high DPI displays, and HDR may require a newer DXGI version than what is available on the system.
| Mode | Activation | Description |
|---|---|---|
| Embedded | Default | Renders inside a foobar2000 layout panel (Default UI or Columns UI) |
| Fullscreen | ALT+ENTER | Borderless fullscreen window on the current monitor |
| Multi-monitor fullscreen | ALT+ENTER (with option) | Spans fullscreen across all monitors |
| Transparent | F10 | Transparent window (Default UI windowed only) |
In fullscreen, the mouse cursor auto-hides after a short period of inactivity within the window and reappears when the mouse moves or the context menu is open; it is restored when leaving fullscreen.
Note: keyboard shortcuts assume the MilkDrop visualization window is focused, and that foobar2000 or the operating system has not reassigned the same key combinations as global/application hotkeys.
| Key | Action |
|---|---|
| SPACE | Random preset (soft blend) |
| BACKSPACE | Previous preset (up to 64 in history) |
| H | Hard cut to next preset (instant) |
| R | Toggle random/sequential order |
| L | Open preset load dialog |
| A | Mashup — load warp from one preset, comp from another, base from a third |
| INSERT | Rename the selected preset in the load dialog |
| SCROLL LOCK | Lock/unlock current preset |
| ? / / | Cycle transition blend pattern forward/back |
| F11 / SHIFT+F11 | Cycle hard-cut mode forward/back |
| + / - | Rate current preset (better/worse) |
| Key | Action |
|---|---|
| i / I | Zoom in / out |
| o / O | Shrink / grow warp amplitude |
| [ / ] | Push motion left / right |
| { / } | Push motion up / down |
| < / > | Rotate left / right |
| g / G | Decrease / increase gamma |
| Key | Action |
|---|---|
| w / W | Cycle waveform mode forward / back |
| j / J | Scale waveform down / up |
| e / E | Make waveform transparent / solid |
| Key | Action |
|---|---|
| q / Q | Scale second graphics layer down / up |
| F | Flip second graphics layer (4 orientations) |
| Key | Action |
|---|---|
| ! | Randomize warp shader |
| @ | Randomize composite shader |
| CTRL+A | Arm one-shot shader disassembly dump for next warp/comp shader compile |
| CTRL+D | Arm one-shot shader source dump for next warp/comp shader compile |
| Key | Action |
|---|---|
| F1 | Help screen |
| F2 | Song title |
| F3 | Song length |
| F4 | Preset name |
| F5 | FPS display |
| F6 | Preset rating |
| F8 | Jump to preset directory |
| F9 | Shader help |
| Key | Action |
|---|---|
| T | Song title animation |
| Y | Custom message mode (type 00-99 to display) |
| K | Sprite mode (type 00-99 to display) |
| SHIFT+K | Sprite kill mode |
| CTRL+T | Kill song title |
| CTRL+Y | Kill custom messages |
| CTRL+K | Kill all sprites |
| CTRL+L | Toggle auto-load embedded sprites |
| DELETE | Delete message/sprite |
| SHIFT+DELETE | Delete oldest sprite |
| CTRL+SHIFT+DELETE | Clear all sprites |
| F7 | Reload message INI (in message mode) |
| Key | Action |
|---|---|
| Z | Previous track |
| X | Play |
| C | Pause |
| V | Stop |
| B | Next track |
| u / U | Toggle shuffle forward / back |
| P | Show playlist |
| UP / DOWN | Volume up / down |
| LEFT / RIGHT | Rewind / forward 5 seconds |
| SHIFT+LEFT / SHIFT+RIGHT | Rewind / forward 30 seconds |
| Key | Action |
|---|---|
| ESC | Toggle interactive mode or exit fullscreen |
| ALT+ENTER | Toggle fullscreen |
| ALT+K | Launch preferences |
| CTRL+R | Reset preset timer to zero |
| PRINT SCREEN / CTRL+F12 / CTRL+Left Click | Screenshot (PNG) |
These shortcuts fine-tune the per-pixel transparency used by the Transparent window mode (F10, Default UI windowed only). They only have a visible effect while transparency is active, they persist across sessions, and they work whether or not rebindable keyboard shortcuts are enabled (when enabled, they can be reassigned in the shortcut editor).
| Key | Parameter | Default | Range | Controls |
|---|---|---|---|---|
| SHIFT+UP / SHIFT+DOWN | Key strength | 100% | 0–400% | How quickly pixel brightness becomes opaque |
| CTRL+SHIFT+UP / DOWN | Opacity floor | 0% | 0–100% | Minimum opacity added to every pixel |
| CTRL+UP / CTRL+DOWN | Transparency amount | 100% | 0–100% | How much of the brightness keying is applied overall |
Per pixel, on-screen opacity is
saturate(brightness × key_strength + opacity_floor),
blended toward the fully opaque frame by the transparency amount. At the
defaults, dark and black regions are see-through to the desktop while
bright regions stay solid. Starting from the defaults:
The context menu's Reset Opacity command (shown while transparent) restores all three values to their defaults.
When Enable rebindable keyboard shortcuts is on in
Advanced Preferences, the built-in key map can be overridden per action
from a visual editor. Open it from the right-click context menu via
Edit Keybindings... (this dialog is available only in
builds compiled with hotkey support). Per-action overrides are persisted
to milk2_key.db in the milkdrop2 configuration directory
and layered over the built-in defaults.
The editor lists every remappable command with two columns:
Editor controls:
Changes take effect immediately. Actions with no default binding (for example, opening the annotation manager or schedule editor) can be given a key here.
| Input | Action |
|---|---|
| Right-click | Open the visualization context menu |
| Context Menu key | Open the same context menu at the cursor position |
| Mouse wheel up / down | Previous / next preset (blocked while preset schedule mode is active) |
| Double left-click | Toggle fullscreen |
| CTRL+Left Click | Save screenshot (PNG) |
You can drag and drop exactly one file onto the visualization window at a time:
.milk or .milk2: loads the dropped
preset..milk3, .glsl, .frag, or
.fs: loads/imports the dropped Shadertoy preset (in builds
compiled with Shadertoy support)..wave: imports a custom wave into the first available
wave slot..shape: imports a custom shape into the first available
shape slot.Supported image extensions for drag and drop are: .png,
.jpg, .dds, .bmp,
.tga, .jpeg, .jfif,
.dib, .tiff, .tif,
.webp, .gif, and .avif.
When the visualization window has touch or pen input, the following gestures are recognized:
| Gesture | Action |
|---|---|
| Pan (vertical drag) | Raise (drag up) or lower (drag down) the current preset's rating |
| Twist / rotate | Toggle the current preset's Favorite flag |
| Two-finger tap | Toggle the FPS display |
| Press-and-tap | Step to the previous / next preset by the side tapped (blocked while a preset schedule is active or the preset is locked) |
Right-clicking the visualization (or pressing the Context Menu key) opens a popup menu with runtime controls.
| Menu Item | What It Does |
|---|---|
| (current preset filename) | Shows the current preset name (display-only). |
| Next Preset | Loads the next preset. Disabled while preset schedule mode is active. |
| Previous Preset | Loads the previous preset. Disabled while preset schedule mode is active. |
| Random Preset | Loads a random preset. Disabled while preset schedule mode is active. |
| Lock Preset | Toggles preset lock. When enabled, automatic preset changes are prevented. |
| Schedule Presets | Toggles schedule order mode when a preset schedule is loaded. Disabled when preset lock is on. |
| Show Playlist | Toggles the on-screen playlist panel. |
| Show Album Art | Toggles album art visibility by launching/removing sprite
img100 (when milk2_img.ini is present). Uses
embedded album metadata art when Artwork display format
is empty, or the configured Artwork display format
override when non-empty. |
| Launch Title | Launches the current track title animation immediately. |
| Show Help | Toggles the startup/help overlay text. |
| Edit Annotations... | Opens the preset annotation manager. Shown only when preset annotations are enabled. Disabled while other dialogs are open. |
| Edit Schedule... | Opens the preset schedule editor for milk2_sch.csv.
Shown only when the preset schedule editor is enabled. Disabled while
other dialogs are open. |
| Edit Keybindings... | Opens the keyboard shortcut editor. Shown only when rebindable keyboard shortcuts are enabled. Disabled while other dialogs are open. |
| Open Preferences | Opens MilkDrop 2 preferences. Disabled in fullscreen. |
| Explore Presets | Opens the preset directory in Explorer. Disabled in fullscreen. |
| Explore Configuration | Opens the milkdrop2 directory in Explorer. Disabled in fullscreen. |
| Fullscreen | Enters or exits fullscreen mode. |
Selecting Show Album Art launches sprite ID
100 using the behavior script from [img100] in
milk2_img.ini.
Menu command descriptions can be toggled in Advanced Preferences via Enable context menu descriptions.
Open File > Preferences > Visualization > MilkDrop 2 to configure the component. Settings are stored in foobar2000's preferences system rather than INI files.
| Setting | Default | Description |
|---|---|---|
| Start with preset lock ON | Off | Automatically start in preset-lock mode so the preset will not change until manually changed. |
| Auto-lock preset when no music | Off | Prevent preset changes when no music is playing. |
| Sequential preset order | Off | Play presets in directory order instead of random. |
| Enable recursive presets | Off | Include presets from subdirectories. When enabled, all presets are assigned a uniform rating of 3.0 (file I/O is skipped for performance). |
| Disable preset rating | Off | Turn off the rating system so all presets have an equal chance of being selected. |
| Setting | Default | Description |
|---|---|---|
| Time between presets | 16.0s | Minimum time between automatic preset changes (soft cuts). Range: 0.1–3600. |
| Additional random time | 10.0s | Extra random seconds added to the interval between preset changes. Range: 0.0–3600. |
| Blend time (auto/soft cut) | 2.7s | Duration of automatic preset transitions triggered by the timer. |
| Blend time (user/hard cut initiated) | 1.7s | Duration of preset transitions triggered by pressing H or SPACE. |
| Setting | Default | Description |
|---|---|---|
| Disable hard cuts | On | Prevent loud beats from triggering instant preset changes. |
| Time between hard cuts | 60.0s | Minimum time between beat-triggered hard cuts. |
| Hard cut loudness threshold | 2.5 | Sensitivity of beat detection (range: 1.25–3.25). Lower values trigger hard cuts more easily. |
| Beat sensitivity control | Off | Enable runtime beat sensitivity adjustment via ALT+UP/DOWN. |
Press F11 (or SHIFT+F11 to go backward) to cycle hard-cut modes.
| Mode | Name (OSD) | Behavior |
|---|---|---|
| 0 | Off | Disables beat-triggered preset changes. |
| 1 | Normal | Adaptive loudness-based hard cuts. Uses combined bass/mid/treble energy and performs an instant random preset cut when the threshold is exceeded. |
| 2 | Bass Blend | Bass-triggered next-preset blend (~0.95s), rate-limited to about 1.0s between triggers. |
| 3 | Bass | Bass-triggered instant hard cut to next preset. |
| 4 | Middle | Midrange-triggered instant hard cut to next preset. |
| 5 | Treble | Treble-triggered instant hard cut to next preset. |
| 6 | Bass Fast Blend | Bass-triggered fast blend (~0.4s), rate-limited to about 0.5s between triggers. |
| 7 | Treble Fast Blend | Treble-triggered fast blend (~0.4s), rate-limited to about 0.5s between triggers. |
| 8 | Bass Blend and Treble Hard Cut | Bass causes a short blend (~0.24s) while treble causes an instant hard cut; each trigger path is rate-limited to about 0.48s. |
| 9 | Rhythmic | Bass or treble triggers an instant hard cut, rate-limited to about 0.23s. |
| 10 | 2 Beats | Strong bass beat detection; hard cut on every second detected beat. |
| 11 | 4 Beats | Strong bass beat detection; hard cut on every fourth detected beat. |
| 12 | Kinetronix (Vizikord) | Strong bass beat detection; alternates next/previous preset each beat, plus periodic extra next-preset jumps. |
Notes:
| Setting | Default | Description |
|---|---|---|
| Enable song title animations | On | Automatically launch a title animation when the track changes. |
| Song title animation duration | 1.7s | How long the title animation plays. |
| Time between random song titles | -1.0 | Mean time between randomly-launched title animations. Negative values disable random launching. |
| Time between random custom messages | -1.0 | Mean time between randomly-launched custom messages from
milk2_msg.ini. Negative values disable random
launching. |
| Title format | %title% |
foobar2000 title format string used when displaying the current track. |
| Artwork format | (empty) | foobar2000 title format expression for artwork path resolution. Empty uses album metadata lookup. |
| Show album | Off | Display album artwork. |
The Artwork format preference (labeled Artwork display format in the dialog) supports these patterns:
C:\Music\art\default.jpg.$directory_path(%path%)\cover.jpg or
$replace(%path%,%filename_ext%,jpg).Keep in mind:
<ERROR>.| Setting | Default | Description |
|---|---|---|
| Pixel shaders | Auto | Target shader model for compilation. Options: Auto (recommended), Disabled, SM 2.0, SM 2.x, SM 4.0, SM 5.0. |
| Mesh size | 48 | Warp mesh subdivision level (GridX). Options: 8–192. Larger values produce finer distortion. GridY is calculated as GridX × 3/4. |
| Texture size | Auto | Internal render target resolution. Options: 256, 512, 1024, 2048, 4096, nearest power of 2, or exact window size. |
| Canvas stretch | Auto (0) | Internal rendering resolution relative to window. Options: Auto, 100% (none), 125%, 133%, 150%, 167%, 200%, 300%, 400%. Higher values render at a smaller internal resolution stretched up for display. |
| Enable HDR | Off | Enable HDR rendering output (requires DXGI support). |
| Screen-dependent rendering | Off | Enable rendering that adapts to the screen configuration. |
| Setting | Default | Description |
|---|---|---|
| Max. video memory | 16 MB | Maximum video RAM for texture caching. Range: 0–2 GB. The image-count cap is no longer exposed; the texture cache is governed solely by this byte budget (LRU eviction). |
| Bass/Mid | 200 Hz | Frequency boundary between the bass and midrange bands. |
| Mid/Treble | 4000 Hz | Frequency boundary between the midrange and treble bands. |
| FFT size | 2048 | FFT window size (in samples) used to build the high-resolution
spectrum read by GetFFT/get_fft in pixel
shaders. Options: 512, 1024, 2048, 4096, 8192. Must be a power of two;
larger values give finer frequency resolution. Does not affect beat
detection. |
| Setting | Default | Description |
|---|---|---|
| Maximum frame rate | 30 | Maximum frame updates per second. |
| Allow page tearing | Off | Allow frame presentation mid-scan for lower latency at the cost of visual tearing. Requires visualization restart. |
| Span all monitors (fullscreen) | Off | Make the fullscreen window extend across all connected monitors. |
| Setting | Default | Description |
|---|---|---|
| Auto-load embedded sprites | On | Automatically load sprite images referenced by presets. |
| Enable shader caching | Off | Cache compiled shader bytecode to milkdrop2\cache\ for
faster loading on subsequent runs. |
| Disable warnings | Off | Hide error and warning messages that appear in the upper-right corner of the screen. |
| Show "Press F1 for Help" | On | Display the startup help hint. |
The Fonts... button on the preferences page opens a Fonts dialog for configuring the typefaces used by on-screen text (the main help/info text, song titles, preset info, and additional named font slots).
Each font row has a combo box for choosing the face; the combo boxes render each face name in its own typeface, so you can preview how each font looks before selecting it. The dialog also exposes each slot's size, bold/italic style, and color where applicable. Changes apply when you confirm the dialog.
The Liga column's checkboxes are disabled (read-only). Standard ligatures (e.g., "fi") are enabled for all fonts by default; only the song-title font sets this automatically, disabling ligatures when its face would otherwise force an unwanted "Th" ligature.
Open File > Preferences > Advanced > Visualization > MilkDrop 2 to access advanced settings.
Settings are listed below in the order they appear in the dialog.
| Setting | Default | Description |
|---|---|---|
| Preset directory | (empty) | Override the default preset directory path. When empty, uses
milkdrop2\presets\. Supports
%fb2k_profile_path% and environment-variable
expansion. |
| Fix legacy shaders | On | Automatically apply DX9-to-DX11 shader compatibility fixes (IEEE 754 safe intrinsics, bool-to-int conversions, variable shadowing renames). Disable only for debugging. |
| Treat shader compile warnings as errors | Off | Promote HLSL compilation warnings to errors, causing the shader to fail instead of compiling with warnings. Enable only for preset development. |
| Clear shader cache on exit | Off | Delete all cached shader bytecode files in
milkdrop2\cache\ when foobar2000 exits. |
| Enable context menu descriptions | On | Enable descriptive text for context-menu commands in Default UI. |
| Enable preset schedule editor | Off | Show the Edit Schedule... context-menu command for
editing milk2_sch.csv. When off, the command is
hidden. |
| Enable preset annotations | Off | Enable per-preset ratings, flags, and notes stored in
milk2_tag.db, and show the Edit
Annotations... context-menu command. When off, none of the
annotation behavior is active. |
| Enable rebindable keyboard shortcuts | Off | Enable the hotkey editor and per-action key overrides persisted to
milk2_key.db, layered over the built-in key map.
(Available only in builds compiled with hotkey support.) |
| Enable per-pixel window transparency | Off | Enable the DirectComposition per-pixel transparent window path used by the Transparent window mode (F10). Hidden when running under Wine/Proton, where it is unsupported. |
| Enable remote control | Off | Enable Milkwave-compatible named pipe control via
\\.\pipe\Milkwave_<foobar2000 PID>_<instance ID>.
Applied when the visualization instance is created. |
| Enable Spout output | Off | Share the live visualization as a GPU texture over Spout for OBS, Resolume, TouchDesigner, and other Spout-aware apps. (Available only in builds compiled with Spout support.) |
| Enable HDR output | Off | Enable the opt-in scRGB FP16 HDR presentation path with HDR10 display detection. (Available only in builds compiled with HDR support.) |
| Debug output | Off | Emit additional diagnostic messages (console). Shader dumps are
armed separately with CTRL+D (source) and
CTRL+A (disassembly) and written to
milkdrop2\debug\. |
| Message executable | (empty) | Optional external command used to generate dynamic text for message
slot 99. |
| Message arguments | (empty) | Optional argument string passed to Message executable. Environment variables are expanded before launch. |
Note: The Enable remote control setting is intended to apply on visualization startup. If changed while the visualizer is already running, close and reopen the visualization window (or restart foobar2000). The same applies to toggling the context-menu commands gated by Enable preset schedule editor, Enable preset annotations, and Enable rebindable keyboard shortcuts.
When enabled, each visualization instance creates a named pipe endpoint:
\\.\pipe\Milkwave_<foobar2000 PID>_<instance ID>
Supported incoming commands:
| Command | Effect | | -------------------------------------- |
---------------------------------------------------- |
--------------------------------- | | SIGNAL\|NEXT_PRESET |
Load next preset | | SIGNAL\|PREV_PRESET | Load previous
preset | | SIGNAL\|CAPTURE or CAPTURE |
Capture screenshot | | SIGNAL\|FULLSCREEN | Toggle
fullscreen | | SIGNAL\|COVER_CHANGED | Refresh album-art
sprite | | CLEARTEXTS | Clear active text overlays | |
CLEARSPRITES | Clear active sprites | |
MSG=<text> or MSG\|TEXT=<text> |
Launch custom message in slot 99 | |
SEND=<text> | Send text input to waitstring/message
input handlers | | SEND=0xNN | Send a virtual key
(0xNN hex) | |
PRESET_LOCK=<0/1/ON/OFF/LOCK/UNLOCK> | Set
preset-lock state | | STATE | Broadcast current
PRESET=..., SETTINGS | ..., and
PROFILE=... responses |
Presets are .milk files that define visual behavior
through per-frame equations, per-pixel equations, custom shapes, custom
waves, and HLSL shaders. foo_vis_milk2 is compatible with
the MilkDrop 2 preset ecosystem.
When you exit mashup mode with ESC, any pending mashup selections are applied and a warning is shown that mixed preset code may not serialize/reload identically.
The visualizer supports 18 blend patterns for smooth preset transitions, including:
Press SCROLL LOCK to lock the current preset, preventing auto-advance and random selection.
Press + or - to rate the current
preset. Ratings are stored as fRating inside the
[preset00] section of each .milk file (float,
0.0–5.0). When random mode uses weighted ratings (optional),
higher-rated presets appear more frequently.
Recursive mode and ratings: When recursive
subdirectory scanning is enabled, the rating system is effectively
disabled. Reading the fRating value from every
.milk file in a deep directory tree would be too slow, so
recursive mode assigns a hardcoded rating of 3.0 to all
presets. To use per-preset ratings, disable recursive scanning.
Annotations are per-preset metadata — a rating, a set of flags,
free-form notes, and the last recorded error — kept
separately from the .milk files
themselves. They are stored in a plain SQLite database,
milk2_tag.db, in the milkdrop2 configuration directory, so
external tools can read or edit them without touching the presets.
The feature is controlled by Enable preset annotations in Advanced Preferences (off by default). When it is off, none of the behavior below is active.
Open the manager from the right-click context menu via Edit Annotations... (shown only while annotations are enabled). The action can also be assigned a key in the rebindable hotkeys dialog ("Open annotations"); it has no default binding.
Annotation fields
| Field | Meaning |
|---|---|
| Rating | Integer 0–5, where 0 means "unset". This is the
annotation-store rating, distinct from the .milk file's own
fRating. |
| Flags | Any combination of Favorite (F),
Skip (S), Broken
(B), and Error (!). |
| Notes | Free-form text. |
| Error | The last error text and time recorded for the preset (set automatically; see below). |
Flags are shown as a badge appended to the on-screen preset name,
e.g. [F], [S], [B], or
[!].
How the rating gets populated
The annotation rating is written in exactly one place: when you rate
the currently playing preset with + /
- (the same action shown by F6). That
syncs MilkDrop's live fRating into the annotation store,
rounded to 0–5.
Adding a preset in the manager with Add... creates a
placeholder row with rating 0; the dialog has no rating
editor and does not read the preset's existing fRating. To
give an added preset a non-zero rating, play it and rate it.
Flags and selection
Manager actions
Default location:
<foobar2000 profile>\milkdrop2\presets
Configure via File > Preferences > Visualization > MilkDrop 2. Subdirectories are scanned recursively (optional).
In the preset load dialog, press INSERT on a preset file to rename it.
.milk2 stays .milk2).MAX_PATH.foo_vis_milk2 persists two related values per UI
instance:
m_szPresetDir)m_szLastPreset)Save behavior on close/layout save:
Restore behavior on next launch:
Practical note:
Press M to open the preset editing menu. Each editable section of the running preset is listed as a menu item. Navigate with UP / DOWN and press RETURN to enter text editing mode (called a "waitstring").
| Section | State field |
|---|---|
| Preset initialization code | m_szPerFrameInit |
| Per-frame equations | m_szPerFrameExpr |
| Per-vertex equations | m_szPerPixelExpr |
| Warp shader (HLSL) | m_szWarpShadersText |
| Composite shader (HLSL) | m_szCompShadersText |
| Custom wave/shape code | Per-wave/shape init and per-frame fields |
| Key | Action |
|---|---|
| Characters | Insert (or overtype) at cursor |
| LEFT / RIGHT | Move cursor |
| HOME / END | Jump to start / end of line |
| UP / DOWN | Move between lines (code mode) |
| BACKSPACE / DELETE | Delete before / after cursor |
| INSERT | Toggle insert / overtype mode |
| SHIFT + arrows | Text selection |
| CTRL+C / CTRL+X | Copy / cut selection |
| CTRL+V | Paste |
| CTRL+ENTER | Commit edit (code mode) |
| RETURN | Insert newline (code) or commit edit (non-code) |
| ESCAPE | Cancel — discard all changes |
When you commit an edit (CTRL+ENTER for code, RETURN for non-code strings):
m_pState).RecompileExpressions() runs under a critical section lock.
The new expressions take effect immediately.RecompilePShader() compiles the new shader. If compilation
fails, a fallback shader is substituted automatically and an error
message is displayed.Edits are applied to the running preset state only and are not saved to disk. Changes are lost when:
To persist changes, explicitly save the preset:
.milk file)During a preset transition (two presets blending), the menu shows the
incoming (new) preset, not the outgoing one.
Internally, m_pState is swapped to point at the new preset
when the blend begins:
The same applies to .milk2 double-preset files — the
blend-to sub-preset becomes m_pState.
Place a milk2_sch.csv (CSV with header row) or
milk2_sch.txt in the active preset directory to define a
custom playback order (and optional per-preset FPS caps). When present,
the visualizer reads the file to schedule presets instead of using
random or sequential selection. The CSV is parsed by the external
csv-parser library.
Schema (header row required):
preset (required): preset filename relative to the
preset directory, for example MyPreset.milk.duration (required): seconds to stay on this preset.
Must be > 0.blend (optional): blend time in seconds for this
transition. If omitted, the normal auto-blend setting is used.fps (optional): max FPS override for this row.
0 means unlimited.1..200 sets that exact max FPS.Additional behavior:
duration = inf (or equivalent positive infinity) locks
that preset (no automatic advance).Example:
preset,duration,blend,fps
martin - lonely goose.milk,90,1.5,60
Stahlregen - Simple Spectrum (together).milk,45,,0
Flexi - wolfram's rule 90 [rise of the log attack].milk,inf,0.8,30
Rather than editing milk2_sch.csv by hand, open the
visual editor from the right-click context menu via Edit
Schedule... (shown only while Enable preset schedule
editor is on in Advanced Preferences). It reads
milk2_sch.csv from the active preset directory and lists
each row with its Preset, Duration,
Blend, FPS, and Lock
state. The action can also be assigned a key in the rebindable hotkeys
dialog; it has no default binding.
Editor actions:
0 or less falls back to 16 seconds; leaving
Blend or FPS blank stores "unset" (use
the default). Check Lock to store inf
(that preset does not auto-advance).milk2_sch.csv
atomically, reload the schedule, and jump to the next scheduled preset.
Nothing is written to disk until you use this.The Add... buttons in both the schedule editor and the annotation manager open a shared modal Select Preset dialog that lists the presets in the active directory:
In builds compiled with Shadertoy support, foo_vis_milk2
includes a Shadertoy rendering subsystem that runs GLSL shader-art
presets alongside the MilkDrop engine. Shadertoy presets are stored in
the JSON-based .milk3 format.
.milk3 files placed in the
active preset directory appear alongside
.milk/.milk2 presets. You can also drag and
drop .milk3, .glsl, .frag, or
.fs files onto the visualization window to load/import
them..milk/.milk2 preset
loads.mix()→lerp(),
fract()→frac(), mod(),
atan(y,x)→atan2(y,x), and
texture*→tex2D*) and compiled with
backwards-compatibility enabled.iResolution, iTime,
iTimeDelta, iFrame, iFrameRate,
iMouse, iDate, iSampleRate,
iChannelTime/iChannelResolution).iChannel so
imported shaders react to foobar2000 audio.foo_vis_milk2 receives audio directly from foobar2000's
playback engine as floating-point audio_sample values — no
audio routing or virtual cables are needed.
Precision by target architecture:
audio_sample is 32-bit
single-precision (float).audio_sample is
64-bit double-precision (double).foo_vis_milk2 normalizes incoming audio to two waveform
channels before analysis/rendering:
Mixing notes:
audio_sample input values are converted
to float and accumulated into float waveform buffers.GetFFT/get_fft; see the Image Cache
and Audio preferences| Variable | Description |
|---|---|
bass |
Low-frequency energy (immediate) |
mid |
Mid-frequency energy (immediate) |
treb |
High-frequency energy (immediate) |
bass_att |
Low-frequency energy (attack-smoothed) |
mid_att |
Mid-frequency energy (attack-smoothed) |
treb_att |
High-frequency energy (attack-smoothed) |
The message system displays user-defined text overlays on screen.
Messages are defined in milk2_msg.ini (located in
milkdrop2\) with up to 100 message slots (00–99) and up to
16 font definitions (00–15). The maximum file size is 64 KB.
milk2_msg.ini from disk without restarting.message99)99 can be used as a dynamic "fortune" message
style.99 replaces its text with captured process
output.message99 from milk2_msg.ini is used as
fallback.Both milk2_msg.ini and milk2_img.ini are
parsed by the Windows GetPrivateProfileString()
API. The only officially recognized comment prefix is
; (semicolon) at the start of a line.
Lines beginning with // are tolerated because the API
silently skips lines that are not valid [section] headers
or key=value pairs, but ; is the recommended
comment style.
All parameters have defaults and can be omitted, except for the
text field of each message.
Fonts are defined in [font##] sections (where
## is 00–15). Messages reference
fonts by their ID and can optionally override individual font
properties.
| Parameter | Type | Range | Description |
|---|---|---|---|
face |
string | — | Font face name (e.g., arial, courier new,
garamond) |
bold |
integer | 0–1 | Bold text |
ital |
integer | 0–1 | Italic text |
r |
integer | 0–255 | Red color component |
g |
integer | 0–255 | Green color component |
b |
integer | 0–255 | Blue color component |
Messages are defined in [message##] sections (where
## is 00–99).
| Parameter | Type | Range | Default | Description |
|---|---|---|---|---|
text |
string | — | — | (Required) The text to display. Use %
for special characters. |
font |
integer | 0–15 | 0 | Font ID to use |
size |
integer | 0–100 | 50 | Font size (0 = tiny, 100 = enormous, 40–60 = normal range) |
growth |
float | 0.25–4.0 | 1.0 | Scale factor over time (0.5 = shrink to half, 2.0 = grow to double) |
x |
float | 0.0–1.0 | 0.5 | Horizontal center position (0.0 = left, 1.0 = right) |
y |
float | 0.0–1.0 | 0.5 | Vertical center position (0.0 = top, 1.0 = bottom) |
randx |
float | 0.0–1.0 | 0.0 | Random offset applied to x (±) |
randy |
float | 0.0–1.0 | 0.0 | Random offset applied to y (±) |
time |
float | 0.0–999.0 | 1.0 | Display duration in seconds |
fade |
float | 0.0–1.0 | 0.3 | Fraction of time spent fading in |
Any message can override its referenced font's properties inline:
| Parameter | Type | Range | Description |
|---|---|---|---|
face |
string | — | Override font face |
bold |
integer | 0–1 | Override bold |
ital |
integer | 0–1 | Override italic |
r |
integer | 0–255 | Override red color |
g |
integer | 0–255 | Override green color |
b |
integer | 0–255 | Override blue color |
randr |
integer | 0–255 | Random offset applied to red (±) |
randg |
integer | 0–255 | Random offset applied to green (±) |
randb |
integer | 0–255 | Random offset applied to blue (±) |
[font00]
face=arial
bold=1
ital=0
[message00]
text=This is a test...
font=0
fade=0.4
time=1.2
size=50
growth=2.0
x=0.5
y=0.2Sprites are animated image overlays managed via
milk2_img.ini (located in milkdrop2\). Each
sprite has an image file, blend mode, position, scale, rotation, and
programmable animation code using EEL expressions. Up to 16 sprites can
be on screen simultaneously, and up to 100 runtime sprite definitions
(00–99) can exist in the file.
Album art uses the same sprite system via a special
[img100] section. Sprite ID 100 is reserved
for album art and is the only sprite that persists across preset
changes.
The file uses the same INI comment conventions as
milk2_msg.ini: lines starting with
; are comments (see File Format above).
| Extension | Format |
|---|---|
.jpg |
JPEG |
.png |
PNG |
.bmp |
Windows Bitmap |
.tga |
Targa |
.dds |
DirectDraw Surface |
Use .jpg for automatic extension probing. Explicit
img= paths can also use
.jpeg/.jfif when supported by WIC codecs.
The img= line is mandatory for normal runtime sprite
slots (img00-img99). Paths can be relative or
absolute:
| Path Style | Example | Resolves To |
|---|---|---|
| Relative | img=billy.jpg |
milkdrop2\billy.jpg |
| Relative | img=..\billy.jpg |
Parent of milkdrop2\ |
| Relative | img=images\billy.jpg |
milkdrop2\images\billy.jpg |
| Absolute | img=c:\blah\billy.jpg |
Exact path |
| Invalid | img=c:billy.jpg |
Must specify full path |
| Invalid | img=\billy.jpg |
Must specify drive letter |
For album art (img100), the image source comes from
current track artwork (embedded metadata or Artwork display
format), so img= is not required.
| Key | Action |
|---|---|
| K | Enter sprite mode (type 00–99 to load) |
| SHIFT+K | Sprite kill mode |
| CTRL+K | Kill all sprites |
| CTRL+L | Toggle auto-load embedded sprites |
| DELETE | Delete a sprite |
| SHIFT+DELETE | Delete oldest sprite |
| CTRL+SHIFT+DELETE | Clear all sprites |
Each sprite definition has init code
(init_1, init_2, ...) that runs once at
launch, and per-frame code (code_1,
code_2, ...) that runs every frame. All mathematical
functions available in MilkDrop preset equations are available in sprite
code.
Custom variables can be defined in init code by assigning a value. They persist across frames and can be read/modified in per-frame code.
| Variable | Description |
|---|---|
time |
Seconds elapsed since the sprite was launched |
frame |
Number of frames since the sprite was launched |
fps |
Current frame rate |
progress |
Progress through the current preset (0.0–1.0) |
bass, mid, treb |
Current audio band energy (1.0 = normal, <1 = quiet, >1 = loud) |
bass_att, mid_att,
treb_att |
Attack-smoothed (damped) audio band energy |
| Variable | Range / Type | Description |
|---|---|---|
x |
0.0–1.0 | Horizontal center position (0 = left, 1 = right) |
y |
0.0–1.0 | Vertical center position (0 = top, 1 = bottom) |
r |
0.0–1.0 | Red color brightness |
g |
0.0–1.0 | Green color brightness |
b |
0.0–1.0 | Blue color brightness |
a |
0.0–1.0 | Opacity (alpha). Effect depends on blendmode; sometimes
has no effect. |
sx |
float | Horizontal scale (1.0 = fill screen, 0.5 = half, 2.0 = double) |
sy |
float | Vertical scale (1.0 = fill screen, 0.5 = half, 2.0 = double) |
rot |
float | Rotation in radians (0–2π). π/2 = 90° CCW, π = 180°, 3π/2 = 270°. |
flipx |
0 or 1 | Flip the sprite horizontally |
flipy |
0 or 1 | Flip the sprite vertically |
repeatx |
float | Horizontal texture tiling count (default 1). Non-power-of-two source images may cause banding artifacts on some hardware. |
repeaty |
float | Vertical texture tiling count (default 1) |
done |
0 or 1 | Set to nonzero to terminate the sprite and free its resources.
Example: done=above(frame,500); terminates after 500
frames. Use time or frame/fps for
framerate-independent timing. |
burn |
0 or 1 | If nonzero, the sprite burns into MilkDrop's background animation.
Set to 1 continuously for trailing effects, or set to 1 only on the last
frame (with done=1) for a one-time burn-in like song
titles. |
Set blendmode in init code to control how the sprite
composites onto the screen.
| Mode | Name | Description |
|---|---|---|
| 0 | Blend | Image multiplied by (r,g,b), then alpha-blended using
a. |
| 1 | Decal | Image multiplied by (r*a, g*a, b*a), pasted opaquely.
a < 1 darkens the sprite. |
| 2 | Additive | Image multiplied by (r*a, g*a, b*a), added to
background (brightens). a < 1 darkens. |
| 3 | SrcColor | Per-pixel alpha derived from pixel brightness. White = opaque, black
= transparent. a has no effect. |
| 4 | ColorKey | Pixels matching the colorkey color are transparent; all
others are opaque. Requires colorkey=0xRRGGBB line. |
| 5 | Multiply | Multiply blend |
| 6 | Subtract | Subtractive blend |
| 7 | Invert | Invert blend |
| 8 | Cut-off | Cut-off blend |
| 9 | Darken | Darken blend |
| 10 | Vivid | Vivid blend |
When blendmode = 4, a colorkey line is
required:
colorkey=0x000000The value is a 24-bit hexadecimal color (0xRRGGBB):
0x000000 — black is transparent0xFFFFFF — white is transparent0x0000FF — blue is transparentThe alpha value (a) still modulates overall sprite
opacity when using color keying. This mode works best in 32-bit
color.
Presets can reference embedded sprites that load automatically when the preset is active. Toggle auto-loading with CTRL+L.
Auto-load compatibility is enabled for .milk2 presets
and for compatible MilkDrop 3 preset states.
img100)To customize album-art motion/compositing, script
[img100] in milk2_img.ini.
Regression note: during the initial MilkDrop 3 blend-mode parity
update, scripted img100 behavior could be bypassed, which
caused artwork to appear centered on-screen. This has been restored for
the next release.
[img100]
init_1=blendmode = 3;
init_2=x = -100;
init_3=orig_y = 0.5;
code_1=time_to_reset = below(x,-0.5);
code_2=x = x*(1-time_to_reset) + time_to_reset*(1.5 + 0.01*rand(100) + 3);
code_3=orig_y = orig_y*(1-time_to_reset) + time_to_reset*(0.3 + 0.4*0.01*rand(100));
code_4=sx = sx*(1-time_to_reset) + time_to_reset*(0.25 + 0.4*0.01*rand(100));
code_5=sy = sx;
code_6=x = x - 0.008 + 0.0033*sin(time*1.371);
code_7=y = orig_y + 0.12*sin(time*1.9);foo_vis_milk2 displays current track information using
foobar2000's title format system. The format string is configurable in
preferences.
Displayed information includes:
Presets support up to 16 custom shapes with EEL expression-based definitions:
Shapes are drawn into the render target with alpha blending or additive blending.
Presets support up to 16 custom waveforms with:
Custom wave and shape definitions can be exported as standalone files from the in-app menu:
.wave file (default path:
milkdrop2\waves\file.wave).shape file (default path:
milkdrop2\shapes\file.shape)These exports are useful for reusing wave/shape definitions across presets or sharing them independently.
milkdrop2\screenshots\| Variable | Description |
|---|---|
time |
Elapsed time in seconds |
fps |
Current frames per second |
frame |
Frame counter |
progress |
Preset progress (0.0–1.0) |
bass, mid, treb |
Frequency band energy |
bass_att, mid_att,
treb_att |
Attack-smoothed frequency bands |
meshx, meshy |
Warp mesh dimensions |
pixelsx, pixelsy |
Screen resolution |
aspectx, aspecty |
Aspect ratio |
mousex, mousey |
Mouse position |
mousedown, mouseclick |
Mouse button state |
| Variable | Description |
|---|---|
zoom, zoomexp |
Zoom parameters |
rot |
Rotation |
warp |
Warp distortion amount |
cx, cy |
Center position |
dx, dy |
Displacement |
sx, sy |
Scale |
wave_mode |
Waveform visualization mode |
wave_x, wave_y |
Waveform position |
wave_r, wave_g, wave_b,
wave_a |
Waveform color and alpha |
wave_mystery |
Waveform mystery parameter |
wave_usedots, wave_thick,
wave_additive, wave_brighten |
Waveform flags |
ob_size, ob_r, ob_g,
ob_b, ob_a |
Outer border |
ib_size, ib_r, ib_g,
ib_b, ib_a |
Inner border |
mv_x, mv_y, mv_dx,
mv_dy, mv_l, mv_r,
mv_g, mv_b, mv_a |
Motion vectors |
decay |
Feedback decay |
gamma |
Gamma correction |
echo_zoom, echo_alpha,
echo_orient |
Video echo |
darken_center, wrap,
invert |
Additional effects |
t1–t8 |
Temporary per-frame variables |
q1–q64 |
User variables (passed from init to per-frame) |
foo_vis_milk2 supports inter-process communication via
the WM_MILK2 window message for external control:
| Command | Description |
|---|---|
IPC_GETVERSION |
Plugin version |
IPC_GETVERSIONSTRING |
Version string |
IPC_ISPLAYING |
Playback state (playing/paused/stopped) |
IPC_SETPLAYLISTPOS |
Set current playlist position |
IPC_GETLISTLENGTH |
Get playlist length |
IPC_GETLISTPOS |
Get current position |
IPC_GETPLAYLISTTITLEW |
Formatted title of a track |
IPC_GET_PLAYING_TITLE |
Currently playing title |
| Path | Description |
|---|---|
milkdrop2\ |
Base directory (under foobar2000 profile) |
milkdrop2\presets\ |
Preset directory (*.milk, *.milk2,
*.milk3) |
*.milk |
Single-state preset file (stored in the preset directory) |
*.milk2 |
Double-state preset file (stored in the preset directory) |
*.milk3 |
Shadertoy preset file (stored in the preset directory; Shadertoy builds only) |
milkdrop2\waves\ |
Export/import directory for custom wave definitions |
*.wave |
Exported custom wave definition file |
milkdrop2\shapes\ |
Export/import directory for custom shape definitions |
*.shape |
Exported custom shape definition file |
milkdrop2\textures\ |
Texture files referenced by presets |
milkdrop2\cache\ |
Compiled shader bytecode cache
({prefix}-{checksum}.shader) |
milkdrop2\debug\ |
Shader dumps for debugging
({preset}_{type}_{fn}_{profile}.hlsl and
.asm) |
milkdrop2\screenshots\ |
Screenshot output directory |
milkdrop2\milk2_msg.ini |
Custom message definitions (slots 00-99) |
milkdrop2\milk2_img.ini |
Sprite/texture definitions (slots 00-99) |
milkdrop2\milk2_tag.db |
Preset annotations database (when preset annotations are enabled) |
milkdrop2\milk2_key.db |
Rebindable keyboard shortcut overrides (hotkey-enabled builds) |
milk2_sch.csv |
Optional preset scheduling file (in preset directory) |
milk2_sch.txt |
Alternate file name for optional preset scheduling (still CSV with header) |