56 lines
3.0 KiB
C++
56 lines
3.0 KiB
C++
#pragma once
|
|
// card_meta — pure formatting for the L7 decorative card metadata overlay. Each bank
|
|
// card overlays capture length as bars.beats.subdivisions (bottom-LEFT, musical) and
|
|
// seconds.milliseconds (bottom-RIGHT, wall-clock). Both read-outs are DECORATIVE and
|
|
// non-interactive; the bank_panel draws them via the L1 kit. The formatting itself is
|
|
// pure string work over the sample's stamped tempo + meter + length, so it is
|
|
// unit-tested outside the DAW (CLAUDE.md §load-bearing split).
|
|
//
|
|
// PURE MODULE: NO REAPER types, NO SWELL, NO LICE, NO vendor/ includes. Standard
|
|
// library only. Mirror of tooltip's prefix-strip helper.
|
|
|
|
#include <string>
|
|
|
|
namespace reasampler {
|
|
|
|
// The musical length inputs, taken straight off a Sample (L7 F1 capture-time stamp):
|
|
// lengthSeconds — captured length in wall-clock seconds (>= 0).
|
|
// tempoBpm — project tempo (BPM) at capture (Sample.captureTempo); 0 = unknown.
|
|
// timeSigNum — meter numerator at capture (Sample.captureTimeSigNum); 0 = unstamped.
|
|
// timeSigDenom — meter denominator at capture (Sample.captureTimeSigDenom); 0 = unstamped.
|
|
struct MusicalLength {
|
|
double lengthSeconds = 0.0;
|
|
double tempoBpm = 0.0;
|
|
int timeSigNum = 0;
|
|
int timeSigDenom = 0;
|
|
};
|
|
|
|
// bars.beats.subdivisions from a capture-time tempo + meter stamp (musical read-out).
|
|
//
|
|
// Derivation: one quarter-note lasts 60 / tempo seconds; a beat in this meter lasts
|
|
// (4 / timeSigDenom) quarter-notes; a bar holds timeSigNum beats. From lengthSeconds we
|
|
// get total beats, split into whole bars (÷ timeSigNum) + whole leftover beats + a
|
|
// subdivision remainder scaled to 1..N of the next beat. The output is 1-BASED and
|
|
// zero-padded to two subdivision digits: "1.1.00" is exactly one bar-start (a
|
|
// zero-length or bar-aligned capture), "2.3.50" is 1 bar + 2 beats + half a beat.
|
|
//
|
|
// Contract / edge cases (all tested):
|
|
// * UNSTAMPED meter (timeSigNum <= 0 || timeSigDenom <= 0) OR unknown tempo
|
|
// (tempoBpm <= 0): returns "" — no musical read-out is derivable (the caller keeps
|
|
// the s.ms read-out). This is the pre-L7-sample fallback (blank musical read-out).
|
|
// * zero length: "1.1.00" (bar 1, beat 1, no subdivision) — the musical origin.
|
|
// * exact bar boundary: the beat rolls to 1 and the bar increments (never "1.5.00"
|
|
// in 4/4 — that reads as "2.1.00").
|
|
// * long captures: bars grow without cap ("129.1.00" is fine).
|
|
// The subdivision is 0..99 (hundredths of a beat), floored — a display quantum, not a
|
|
// tick-accurate PPQ (the model refuses to invent PPQ; this is a decorative read-out).
|
|
std::string formatBarsBeats(const MusicalLength& m);
|
|
|
|
// seconds.milliseconds from a wall-clock length (always derivable, meter-independent).
|
|
// * "S.mmm" — integer seconds, a dot, zero-padded 3-digit milliseconds (rounded to nearest ms).
|
|
// e.g. 0.0 -> "0.000", 1.5 -> "1.500", 62.037 -> "62.037".
|
|
// * negative length is clamped to "0.000" (a length is never negative; defensive).
|
|
std::string formatSecondsMs(double lengthSeconds);
|
|
|
|
} // namespace reasampler
|