// embed_strip.cpp — see embed_strip.h. Pure math; no host types. #include "core/instrument/ui/embed_strip.h" #include namespace reasampler::instrument::ui { namespace { // Clamp a MIDI note to [0, kEmbedKeyCount-1]. int clampNote(int n) { if (n < 0) return 0; if (n > kEmbedKeyCount - 1) return kEmbedKeyCount - 1; return n; } // Map a key boundary in [0, kEmbedKeyCount] to an x pixel inside a band of the given // left/width. keyEdge is a boundary (0..128), so keyEdge==128 maps to the band's right. // Integer math, floored — a zone's left uses floor(low) and its right uses floor(high+1), // which tiles adjacent zones without a seam. int keyEdgeToX(int bandLeft, int bandWidth, int keyEdge) { if (keyEdge <= 0) return bandLeft; if (keyEdge >= kEmbedKeyCount) return bandLeft + bandWidth; return bandLeft + (keyEdge * bandWidth) / kEmbedKeyCount; } } // namespace EmbedLayout layoutEmbed(int w, int h) { const int cw = std::max(0, w); const int ch = std::max(0, h); EmbedLayout out; // The level band takes a fixed height at the bottom, but never so much that the keymap // above it falls below its minimum (or that the band exceeds the area). On a very short // area the band yields to the keymap entirely. int bandH = std::min(kEmbedLevelBandHeight, ch); if (ch - bandH < kEmbedKeymapMinHeight) { bandH = std::max(0, ch - kEmbedKeymapMinHeight); } const int keymapBottom = ch - bandH; out.keymap = Rect::ltrb(0, 0, cw, keymapBottom); out.levelBand = Rect::ltrb(0, keymapBottom, cw, ch); return out; } Rect zoneSegmentRect(const EmbedLayout& layout, int lowNote, int highNote) { const Rect& band = layout.keymap; const int bandWidth = std::max(0, band.width); int lo = clampNote(lowNote); int hi = clampNote(highNote); if (lo > hi) lo = hi; // defensive: a malformed zone collapses rather than inverts const int leftX = keyEdgeToX(band.x, bandWidth, lo); const int rightX = keyEdgeToX(band.x, bandWidth, hi + 1); return Rect::ltrb(leftX, band.y, std::max(leftX, rightX), band.bottom()); } int zoneAtPoint(const EmbedLayout& layout, const EmbedZone* zones, int zoneCount, int x, int y) { if (zoneCount <= 0 || zones == nullptr) return -1; if (!contains(layout.keymap, x, y)) return -1; // First covering zone in draw order wins (first-match, mirroring the core's resolve). for (int i = 0; i < zoneCount; ++i) { const Rect r = zoneSegmentRect(layout, zones[i].lowNote, zones[i].highNote); if (contains(r, x, y)) return i; } return -1; // on the band but on an uncovered key } Rect levelFillRect(const EmbedLayout& layout, double level) { const Rect& band = layout.levelBand; if (band.width <= 0 || band.height <= 0) return Rect{}; double l = level; if (l < 0.0) l = 0.0; if (l > 1.0) l = 1.0; const int fillW = static_cast(l * band.width); if (fillW <= 0) return Rect{}; return Rect::ltrb(band.x, band.y, band.x + fillW, band.bottom()); } } // namespace reasampler::instrument::ui