fix(waveform): per-column min/max envelope fill eliminates gaps in steep segments

This commit is contained in:
2026-07-27 18:25:05 -04:00
parent e2bd4f4351
commit 20308c842e
5 changed files with 151 additions and 15 deletions
+14 -11
View File
@@ -8,7 +8,8 @@
#include <cstddef>
#include "bank_grid.h" // compressAmplitudeForDisplay — the shared dB display curve (pure)
#include "bank_grid.h" // compressAmplitudeForDisplay — the shared dB display curve (pure)
#include "vst/waveform_view.h" // columnMinMax — per-pixel-column envelope merge (pure)
// SWELL / LICE. On Windows use native Win32 (windows.h first); on mac/linux SWELL is
// provided by the host. Mirrors bank_panel.cpp's include discipline.
@@ -292,6 +293,8 @@ void drawWaveform(LICE_IBitmap* bmp, const KitBox& box, const Envelope& env) {
const int channels = static_cast<int>(env.size());
const int bandH = box.height / channels;
const int innerW = box.width - 4; // drawable pixel columns: box.x+2 .. box.x+2+innerW-1
for (int ch = 0; ch < channels; ++ch) {
const ChannelEnvelope& bins = env[static_cast<std::size_t>(ch)];
const int bandTop = box.y + ch * bandH;
@@ -301,19 +304,19 @@ void drawWaveform(LICE_IBitmap* bmp, const KitBox& box, const Envelope& env) {
LICE_Line(bmp, box.x + 2, midY, box.x + box.width - 2, midY,
midCol, 1.0f, 0, false);
const int nbins = static_cast<int>(bins.size());
if (nbins <= 0) continue;
if (bins.empty() || innerW <= 0) continue;
const int innerW = box.width - 4;
for (int i = 0; i < nbins; ++i) {
const int x = box.x + 2 +
(nbins > 1 ? (i * (innerW - 1)) / (nbins - 1) : 0);
// Same dB display compression as the panel thumbnail (bank_grid, pure) so a
// waveform reads identically wherever the kit draws it.
// Render one filled vertical span per pixel column. columnMinMax merges all
// bins that project to column `col` under the same partition as computeEnvelope,
// so every pixel column is covered with no gaps regardless of the bins-to-pixels
// ratio. Same dB display compression as the panel thumbnail (bank_grid, pure).
for (int col = 0; col < innerW; ++col) {
const MinMax mm = vst::columnMinMax(bins, innerW, col);
const int x = box.x + 2 + col;
int yMax = midY - static_cast<int>(
compressAmplitudeForDisplay(bins[static_cast<std::size_t>(i)].max) * halfSpan);
compressAmplitudeForDisplay(mm.max) * halfSpan);
int yMin = midY - static_cast<int>(
compressAmplitudeForDisplay(bins[static_cast<std::size_t>(i)].min) * halfSpan);
compressAmplitudeForDisplay(mm.min) * halfSpan);
if (yMax < bandTop) yMax = bandTop;
if (yMin > bandTop + bandH - 1) yMin = bandTop + bandH - 1;
LICE_Line(bmp, x, yMin, x, yMax, waveCol, 1.0f, 0, false);