Skip to content

Join equation lines without a separator, like Milkdrop - #1068

Open
Coastrnaut wants to merge 1 commit into
projectM-visualizer:masterfrom
Coastrnaut:fix/equation-line-joining
Open

Coastrnaut wants to merge 1 commit into
projectM-visualizer:masterfrom
Coastrnaut:fix/equation-line-joining

Conversation

@Coastrnaut

@Coastrnaut Coastrnaut commented Nov 9, 2026 •

Copy link
Copy Markdown

Milkdrop reads the numbered code lines of a preset (per_frame_1=, per_frame_2=, …), removes // and \\ comments up to the end of each line and then joins the lines without any separator before compiling the expressions (ReadCode() and StripLinefeedCharsAndComments() in state.cpp). Its editor wrapped long lines when saving presets, often in the middle of a variable name or number:

per_pixel_1=rot=rot*atan2(-rad,sin(ang*20-ang*20*ang*10*atan2(above(bass,bass_Att),above(Treb,t
per_pixel_2=reb_Att))))*sin(Rad*ang*above(Bass,bass_Att))*rad-ang;

projectM joined the lines with a newline, which split these tokens (t / reb_Att, is_ / beat, …), so projectm-eval rejected the code and the whole preset failed to load. The documentation of GetCode() already said equations are returned as a single line with comments stripped.

This adds PresetFileParser::GetEquationCode(), which joins lines like Milkdrop does, and uses it for all expression code of presets and user sprites. Shader code still uses GetCode() and keeps its line breaks.

Results

  • 83 of the 100 presets that failed to load in the four packs below load now. The remaining 17 contain code that Milkdrop can't compile either (e.g. 0.99l, .-.4); Skip equation code that doesn't compile instead of failing the preset #1069 handles those.
  • For all 14,436 presets that already loaded, shader compile/link results and all rendered frames are identical to master.
  • New PresetFileParser tests, including the wrapped-token cases. All unit tests pass.

How I tested it

I loaded all 14,536 presets from cream-of-the-crop, en-d, milkdrop-original and projectm-classic one after another (Windows, RTX A6000), with the preset folders as texture search path, rendered 30 frames each with fixed audio and frame times, and recorded shader compile/link results, failed loads and frame hashes. For the pixel comparison both builds had their random seeds fixed (a local patch only, identical on both sides). The presets this PR fixes are excluded from the pixel comparison, since loading them changes shared state (e.g. the expression evaluator's random generator) for every preset after them.

Retested on current master (2026-11-12)

Milkdrop reads the numbered code lines of a preset, then removes // and
\ comments up to the end of each line and joins the lines without any
separator before compiling the expressions (ReadCode() and
StripLinefeedCharsAndComments() in state.cpp). Its editor wrapped long
lines when saving presets, often in the middle of a variable name or
number, e.g. "above(Treb,t" followed by "reb_Att)".

projectM joined the lines with a newline, which split these tokens and
made the expression parser reject the code, so the whole preset failed to
load. The header of GetCode() already documented equations as being
returned as a single line with comments stripped.

Add PresetFileParser::GetEquationCode(), which joins lines the way
Milkdrop does, and use it for all expression code of presets and user
sprites. Shader code still uses GetCode(), which keeps the line breaks.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant