Loading...
Searching...
No Matches
NoteValueGrid.hpp
1#pragma once
2#include <algorithm>
3#include <cmath>
4#include <cstdint>
5
6namespace Nodes
7{
17inline double grid_rate(double seconds, double tempo, bool note_value) noexcept
18{
19 if(!(seconds > 0.) || !(tempo > 0.))
20 return 0.;
21 double whole_notes = seconds * tempo / 240.;
22 if(note_value)
23 {
24 constexpr double unit = 256. * 9. * 5. * 7.;
25 whole_notes = std::max(1., std::round(whole_notes * unit)) / unit;
26 }
27 return 1. / whole_notes;
28}
29
38template <typename F>
39void for_each_pulse_point(
40 double start, double end, double origin, double unit, double quarters_in_bar,
41 F&& f) noexcept
42{
43 if(!(end > start) || !(unit > 0.) || !(quarters_in_bar > 0.))
44 return;
45 const auto point = [&](int64_t k) { return origin + double(k) * unit; };
46 auto k = int64_t(std::ceil((start - origin) / unit));
47 while(point(k - 1) >= start)
48 k--;
49 while(point(k) < start)
50 k++;
51
52 // The rate arrives rounded, so a step meant for a bar line can land a few
53 // millionths of a step from it: that close, it is on it.
54 constexpr double tolerance = 1e-4;
55 for(int count = 0; count < 1024; count++, k++)
56 {
57 const double p = point(k);
58 if(p >= end)
59 break;
60 const double bar
61 = origin
62 + std::floor((p - origin) / quarters_in_bar + tolerance) * quarters_in_bar;
63 const auto first_in_bar = int64_t(std::ceil((bar - origin) / unit - tolerance));
64 f(p, k - first_in_bar);
65 }
66}
67}