instrument: spline EGs — hard points on the one shared spline, a drawn contour per envelope beside its staged state, payload v13
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "core/audio/peaks.h" // computeEnvelope (waveform binning)
|
||||
#include "core/instrument/ui/spline_edit.h" // splineOverlayBox (the contour's mapping box)
|
||||
#include "core/instrument/ui/waveform_view.h" // waveformSurface / laneEnvelope / frameToX
|
||||
#include "shell/instrument/editor_internal.h" // kit adapters
|
||||
#include "shell/instrument/reasampler_processor.h"
|
||||
@@ -131,11 +132,59 @@ void ReaSamplerEditor::paintWaveform(LICE_IBitmap* bmp, const Rect& band) {
|
||||
paintEnvelopeOverlay(bmp, overlay, frames);
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::paintSplineOverlay(LICE_IBitmap* bmp, const OverlayArea& waveArea) {
|
||||
const VelocityCurve::Box box = splineOverlayBox(waveArea);
|
||||
if (box.width <= 0 || box.height <= 1) return;
|
||||
const VelocityCurve& curve = splineFor(overlayEnv_);
|
||||
|
||||
// One eval per drawn column, through the curve's own pixel maps, so the trace and the
|
||||
// handles share the coordinate system the hit-test resolves against.
|
||||
const LICE_pixel line = toLice(roleColor(Role::OverlayTrace));
|
||||
int prevX = 0, prevY = 0;
|
||||
for (int px = 0; px <= box.width; ++px) {
|
||||
const int cx = box.left + px;
|
||||
const double t = curve.pointFromPixel(box, cx, box.top).velocity;
|
||||
const int cy = curve.pixelFromPoint(box, {t, curve.eval(t)}).y;
|
||||
if (px > 0) LICE_Line(bmp, prevX, prevY, cx, cy, line, 1.0f, 0, true);
|
||||
prevX = cx;
|
||||
prevY = cy;
|
||||
}
|
||||
|
||||
// Handles carry two independent states on the same mark, so they use two independent
|
||||
// channels: SIZE is the grab (the staged painter's grammar — a hotter hue reads as lower
|
||||
// contrast over the lime, see its note), and HOLLOW is hard. The corner itself is the
|
||||
// primary hard cue, but a corner between two near-collinear segments has none to show.
|
||||
const LICE_pixel handle = toLice(roleColor(Role::OverlayTrace));
|
||||
const LICE_pixel core = toLice(roleColor(Role::BgBase));
|
||||
const std::vector<instrument::engine::VelocityPoint>& pts = curve.points();
|
||||
for (std::size_t i = 0; i < pts.size(); ++i) {
|
||||
const auto np = curve.pixelFromPoint(box, pts[i]);
|
||||
const bool grabbed =
|
||||
(drag_ == DragKind::kSplineNode && curvePointIndex_ == static_cast<int>(i));
|
||||
const int r = grabbed ? kEnvHandleGrabbedRadius : kEnvHandleRadius;
|
||||
const int ir = r - kEnvHandleRingPx;
|
||||
const int hx = (std::max)(box.left + r,
|
||||
(std::min)(box.left + box.width - 1 - r, np.x));
|
||||
const int hy = (std::max)(box.top + r,
|
||||
(std::min)(box.top + box.height - 1 - r, np.y));
|
||||
LICE_FillRect(bmp, hx - r, hy - r, 2 * r, 2 * r, handle, 1.0f, 0);
|
||||
if (pts[i].hard && ir > 0) {
|
||||
LICE_FillRect(bmp, hx - ir, hy - ir, 2 * ir, 2 * ir, core, 1.0f, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::paintEnvelopeOverlay(LICE_IBitmap* bmp, const OverlayArea& waveArea,
|
||||
std::int64_t frames) {
|
||||
if (overlayEnv_ == OverlayEnv::kNone) return; // no envelope selected is a resting state
|
||||
const Rect& area = waveArea.rect;
|
||||
if (frames <= 0 || area.width <= 0 || area.height <= 0) return;
|
||||
if (overlayIsSpline()) {
|
||||
// The contour is a pure function of normalized position, so it needs neither the frame
|
||||
// count nor the live rate the staged path below resolves its seconds against.
|
||||
paintSplineOverlay(bmp, waveArea);
|
||||
return;
|
||||
}
|
||||
const double rate = liveSampleRate();
|
||||
if (rate <= 0.0) return;
|
||||
const double totalSeconds = static_cast<double>(frames) / rate;
|
||||
|
||||
Reference in New Issue
Block a user