03e760631c
Inline keymap/level strip drawn into REAPER's embed bitmap, reusing the LICE idiom. Pure embed_strip layout/hit-test (tested); processor exposes the embed interface off queryInterface and publishes an RT-safe block peak for the level.
77 lines
4.3 KiB
C++
77 lines
4.3 KiB
C++
// embed_strip.h — PURE layout + hit-test for the S6 embedded TCP/MCP strip. NO VST3,
|
|
// NO REAPER, NO SWELL/LICE types at the boundary. The mirror of editor_geometry /
|
|
// mode_switch: the fiddly rectangle math for the compact inline keymap/level strip lives
|
|
// here so it is unit-tested outside the DAW, while the embed shell (reasampler_embed.cpp)
|
|
// marshals REAPER's embed messages (paint bitmap + mouse coords) into these functions.
|
|
//
|
|
// The strip is a single compact band REAPER draws inline in the track/mixer control panel
|
|
// (context TCP or MCP) via the Cockos embedded-UI surface. It shows:
|
|
// * the zone layout — each performance zone as a horizontal segment across the keyboard
|
|
// span (MIDI 0..127 mapped to the strip width), so the keymap reads at a glance; and
|
|
// * a thin level band at the bottom — a 0..1 activity indicator the shell fills.
|
|
// Interaction is zone SELECTION at most (S6 constraint: no new editing semantics) — a
|
|
// click maps to the zone whose key range covers that point, or -1.
|
|
//
|
|
// It reuses the same Rect + contains() as editor_geometry (the strip and the editor share
|
|
// one geometry idiom), so this header depends on editor_geometry.h rather than redefining
|
|
// a second rectangle type.
|
|
|
|
#pragma once
|
|
|
|
#include "editor_geometry.h" // Rect, contains — one shared geometry idiom
|
|
|
|
namespace reasampler::vst {
|
|
|
|
// The full MIDI key span the strip maps across its width. 128 keys (0..127); the strip's
|
|
// horizontal axis is this range, so a zone [lowNote, highNote] becomes a sub-rectangle.
|
|
inline constexpr int kEmbedKeyCount = 128;
|
|
|
|
// Fixed metrics for the strip, exposed so the shell and tests agree.
|
|
inline constexpr int kEmbedLevelBandHeight = 4; // the bottom activity band (px)
|
|
inline constexpr int kEmbedKeymapMinHeight = 6; // keymap area collapses no smaller
|
|
|
|
// One zone rendered on the strip: its inclusive MIDI key range. This is the minimal
|
|
// projection of a PerformanceZone the strip needs (it does not carry sample ids or PCM —
|
|
// the shell resolves labels; the strip only lays out ranges). lowNote/highNote are
|
|
// expected in [0,127] with low <= high, but the layout clamps defensively so a malformed
|
|
// zone never yields an out-of-strip rect.
|
|
struct EmbedZone {
|
|
int lowNote = 0;
|
|
int highNote = 127;
|
|
};
|
|
|
|
// The strip's regions, derived from the (w x h) embed area REAPER reports. Both clamp to
|
|
// the area so a degenerate (tiny) size never yields a region spilling outside the surface.
|
|
struct EmbedLayout {
|
|
Rect keymap; // top: the zone-segment band (the compact keymap)
|
|
Rect levelBand; // bottom: the thin level/activity indicator
|
|
};
|
|
|
|
// Divide a (w x h) embed area into the strip's regions. Pure: same inputs -> same layout.
|
|
// The level band takes a fixed height at the bottom (clamped so it never exceeds the area
|
|
// or starves the keymap below kEmbedKeymapMinHeight); the keymap takes the rest. A zero or
|
|
// negative size yields empty rects (no inversion).
|
|
EmbedLayout layoutEmbed(int w, int h);
|
|
|
|
// The horizontal sub-rectangle of the keymap band for a zone spanning [lowNote, highNote]
|
|
// (inclusive). The 128-key span maps linearly across keymap.width(); the returned rect
|
|
// spans the half-open pixel range [x(lowNote), x(highNote+1)) so adjacent zones (e.g.
|
|
// 0..59 and 60..127) tile without a gap or overlap. Notes are clamped to [0,127] and low
|
|
// is clamped to <= high, so a malformed zone yields an in-band (possibly zero-width) rect,
|
|
// never an inverted one. Pure.
|
|
Rect zoneSegmentRect(const EmbedLayout& layout, int lowNote, int highNote);
|
|
|
|
// The zone a click at (x, y) lands on, given the zones in draw order, or -1 for a click
|
|
// outside the keymap band or on a key not covered by any zone. When zones overlap on a
|
|
// key, the FIRST covering zone in order wins — mirroring the sampler core's first-match
|
|
// Keymap::resolve and the editor's zone order, so selection agrees with playback. Pure.
|
|
int zoneAtPoint(const EmbedLayout& layout, const EmbedZone* zones, int zoneCount, int x,
|
|
int y);
|
|
|
|
// The filled portion of the level band for a 0..1 level. Clamps level to [0,1]; the
|
|
// returned rect is the left sub-rectangle of levelBand whose width is level * band width
|
|
// (rounded down). level <= 0 -> empty rect; level >= 1 -> the whole band. Pure.
|
|
Rect levelFillRect(const EmbedLayout& layout, double level);
|
|
|
|
} // namespace reasampler::vst
|