66 lines
2.4 KiB
C++
66 lines
2.4 KiB
C++
// card_meta — pure implementation. See card_meta.h.
|
|
|
|
#include "core/ui/card_meta.h"
|
|
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
|
|
namespace reasampler::ui {
|
|
|
|
Rect cardNameStrip(const Rect& cell) {
|
|
// Both strips plus a waveform band at least as tall as one strip; below that the card
|
|
// is a text block, not a thumbnail.
|
|
const int minHeight = 3 * kCardStripHeight;
|
|
if (cell.width <= 2 * kCardStripPad || cell.height < minHeight) return Rect{};
|
|
// Inset by 1px from the top edge so the name never sits on the selection border.
|
|
return Rect{cell.x + kCardStripPad, cell.y + 1,
|
|
cell.width - 2 * kCardStripPad, kCardStripHeight};
|
|
}
|
|
|
|
std::string formatBarsBeats(const MusicalLength& m) {
|
|
if (m.tempoBpm <= 0.0 || m.timeSigNum <= 0 || m.timeSigDenom <= 0) return {};
|
|
|
|
const double len = m.lengthSeconds > 0.0 ? m.lengthSeconds : 0.0;
|
|
|
|
// A quarter-note is 60/tempo s; a beat is (4/denom) quarter-notes.
|
|
const double secondsPerBeat = (60.0 / m.tempoBpm) * (4.0 / m.timeSigDenom);
|
|
double totalBeats = len / secondsPerBeat;
|
|
|
|
// Snap to an exact beat within epsilon so a bar-aligned capture reads "2.1.00" rather than
|
|
// "1.4.99" from FP error just under the boundary.
|
|
const double snapped = std::floor(totalBeats + 0.5);
|
|
if (std::fabs(totalBeats - snapped) < 1e-6) totalBeats = snapped;
|
|
|
|
double wholeBeats = std::floor(totalBeats);
|
|
double frac = totalBeats - wholeBeats;
|
|
|
|
const long wb = static_cast<long>(wholeBeats);
|
|
const long bar = wb / m.timeSigNum + 1;
|
|
const long beat = wb % m.timeSigNum + 1;
|
|
|
|
int sub = static_cast<int>(std::floor(frac * 100.0));
|
|
if (sub < 0) sub = 0;
|
|
if (sub > 99) sub = 99;
|
|
|
|
char buf[48];
|
|
std::snprintf(buf, sizeof(buf), "%ld.%ld.%02d", bar, beat, sub);
|
|
return buf;
|
|
}
|
|
|
|
std::string formatSecondsMs(double lengthSeconds) {
|
|
double len = lengthSeconds > 0.0 ? lengthSeconds : 0.0;
|
|
|
|
long secs = static_cast<long>(std::floor(len));
|
|
// Round to nearest ms, not floor: FP storage error would otherwise render e.g. "62.036"
|
|
// for a value that should read "62.037".
|
|
int ms = static_cast<int>((len - static_cast<double>(secs)) * 1000.0 + 0.5);
|
|
if (ms >= 1000) { ms -= 1000; ++secs; } // rounding can carry into the next second
|
|
if (ms < 0) ms = 0;
|
|
|
|
char buf[48];
|
|
std::snprintf(buf, sizeof(buf), "%ld.%03d", secs, ms);
|
|
return buf;
|
|
}
|
|
|
|
} // namespace reasampler::ui
|