-Generates a full-frame color layer from low/high colors, shaped by audio energy and a response curve, for beat-synced compositing.
- Really useful effect for generating, shaping, and outputting a flashing white or black image (to be composited into another clip)
- Inline fast-path bin indices for alpha=255 pixels: raw byte value == rounded bin, no float needed
- Replaced byte_bin() (std::round + clamp) with (int)(val * 255.0f + 0.5f)
- Pre-computed waveform_offset_map[] to eliminate a multiply per pixel in inner loop
- Pointer increment instead of row + x * 4 per pixel
- int64_t pixel_count instead of double pixel_total
- Result: 49 → 89 FPS (~1.8x), all unit tests pass
- Replaced std::round() with +0.5f cast in clampByte — equivalent for non-negative values, significantly cheaper
- Removed redundant clamp01() inside sample_curve_lut — inputs are already clamped at all call sites
- Added early exit when all parameters are at default values — skips the pixel loop entirely for no-op frames
- Marked clamp01, clampByte, and smooth_midtones as inline — makes inlining intent explicit for the hot-path helpers
- Cache y-pre-lerped bilinear columns for soft and clump noise, refreshing only when the x-cell index changes (~every 7 px for soft, ~every 9 px for clump at defaults). Fine grain hash is similarly cached per cell. This cuts amortized hash_coords + mix32 calls from ~56 to ~9 per pixel in the fully-featured case.
- hoist all y-dependent values out of the x-loop; replace std::round in clampByte; extract salt magic numbers to named constants; move alpha_percent to the write-back branch where it's actually needed; collapse the color-apply branch to use_color_variation directly.
- Render phase scope rainbow colors against the trace bounds instead of the full canvas so centered scopes show a full color range at normal intensity.
- Replace the expensive antialiased QPainterPath rendering path with a reserved polyline, lower the max trace detail, and use cheaper pen joins for faster painting.
- Replace raw milliseconds output with FPS (frames / elapsed_seconds) as the
primary metric, reported in a markdown table with a sqrt-scaled bar chart
- Run each trial 3 times and report the median, discarding the cold-cache first
run as a natural outlier for stable, repeatable results across invocations
- Seek to frame 241 (10s into the 24fps source) before timing begins, including
seek cost in the measurement — mirrors real OpenShot scrubbing behavior
- Use 120 frames per trial (up from mixed 30/60) for more stable FPS readings
- Timeline tests now render at 1280x720 @ 29.97fps (was 1920x1080 @ 24fps),
matching source resolution so all tests are roughly comparable
- FrameMapper reduced to a single 30000/1001 rate (was 5 rates sharing a cache)
- Add Effect_ColorGrade, Effect_FilmGrain, Effect_Shadow, Effect_Glow trials
- Remove combined AudioVisualization aggregate trials (redundant with per-mode rows)
- Remove Effect_AudioVisualization_VUMeter and _Bars (too fast to be informative)
- Guard all effect includes and trials with __has_include so the benchmark
compiles and runs against older libopenshot builds, silently skipping effects
that did not exist yet
- Suppress FFmpeg/codec log output via av_log_set_level(AV_LOG_QUIET)
- Add TTY-only spinner with per-trial run counter (e.g. [2/3]) during execution
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-Set the parent timeline before hydrating clips inserted through JSON diffs, matching full project JSON load behavior. This lets copied/pasted clips expose timeline context while their nested readers are rebuilt.
-Avoid clobbering valid stored dimensions for audio-only FFmpeg readers with the 720x480 fallback. The fallback is now only used when width or height are missing, while parent timeline preview dimensions can still override when available.
-Add regression coverage for audio-only FFmpegReader JSON hydration and timeline JSON-diff insertion preserving 1280x720 dimensions.
- Fix Neon/Soft/Clean fill alphas — were far too low, colors appeared nearly invisible on dark backgrounds
- Fix Neon glow on waveform — double-reduced alpha and too-narrow spread made it invisible
- Fix Rainbow mode on waveform/filled waveform — now sweeps hue horizontally via QLinearGradient, no per-segment loop
- Line waveform now follows true ±signal instead of magnitude envelope; remove unused bottom_edge
- Remove Retro style — too visually similar to Clean to justify
- Minimal style is now fully opaque (fill alpha 1.0)
- Clip waveform shortcut defaults to Minimal style + Filled Waveform