43 friend class TempoMapWrapper;
60 friend void to_json (nlohmann::json &j,
const TempoEvent &e);
61 friend void from_json (
const nlohmann::json &j,
TempoEvent &e);
71 constexpr auto quarters_per_bar ()
const
76 constexpr auto ticks_per_bar ()
const
81 constexpr auto ticks_per_beat ()
const
87 is_different_time_signature (
const TimeSignatureEvent &other)
const
92 friend void to_json (nlohmann::json &j,
const TimeSignatureEvent &e);
93 friend void from_json (
const nlohmann::json &j, TimeSignatureEvent &e);
114 : sample_rate_ (sampleRate)
121 sample_rate_ = sampleRate;
138 throw std::invalid_argument (
"BPM must be positive");
139 if (tick < units::ticks (0))
140 throw std::invalid_argument (
"Tick must be non-negative");
143 if (events_.empty () && tick != units::ticks (0))
145 events_.push_back (default_tempo_);
149 auto it = std::ranges::find (events_, tick, [] (
const TempoEvent &e) {
152 if (it != events_.end ())
157 events_.push_back ({ tick, bpm, curve });
158 rebuild_cumulative_times ();
164 if (events_.size () > 1 && tick == units::ticks (0))
165 throw std::invalid_argument (
166 "Cannot remove first tempo event - remove other tempo event first");
168 auto it = std::ranges::find (events_, tick, [] (
const TempoEvent &e) {
171 if (it != events_.end ())
174 rebuild_cumulative_times ();
195 if (tick < units::ticks (0))
196 throw std::invalid_argument (
"Tick must be non-negative");
197 if (numerator <= 0 || denominator <= 0)
198 throw std::invalid_argument (
"Invalid time signature");
199 if (!events_.empty ())
200 throw std::logic_error (
201 "Time signature events must be added before tempo events");
204 if (time_sig_events_.empty () && tick != units::ticks (0))
206 time_sig_events_.push_back (default_time_sig_);
210 auto it = std::ranges::find (
211 time_sig_events_, tick,
212 [] (
const TimeSignatureEvent &e) {
return e.tick; });
213 if (it != time_sig_events_.end ())
215 time_sig_events_.erase (it);
218 time_sig_events_.push_back ({ tick, numerator, denominator });
225 if (time_sig_events_.size () > 1 && tick == units::ticks (0))
226 throw std::invalid_argument (
227 "Cannot remove time signature event at tick 0 - remove other events first");
229 auto it = std::ranges::find (
230 time_sig_events_, tick,
231 [] (
const TimeSignatureEvent &e) {
return e.tick; });
232 if (it != time_sig_events_.end ())
234 time_sig_events_.erase (it);
242 const auto &[events, cumulative_seconds] = get_events_or_default ();
247 if (it == events.begin ())
249 return units::seconds (0.0);
252 size_t index = std::distance (events.begin (), it) - 1;
253 const auto &startEvent = events[index];
254 const units::tick_t segmentStart = startEvent.tick;
255 const auto ticksFromStart =
256 tick -
static_cast<units::precise_tick_t
> (segmentStart);
257 const auto baseSeconds = cumulative_seconds[index];
260 if (index == events.size () - 1)
264 (ticksFromStart.in (units::ticks)
265 /
static_cast<double> (
get_ppq ()))
266 * (60.0 / startEvent.bpm));
269 const auto &endEvent = events[index + 1];
270 const units::tick_t segmentTicks = endEvent.tick - segmentStart;
271 const auto dSegmentTicks =
static_cast<units::precise_tick_t
> (segmentTicks);
278 (ticksFromStart.in (units::ticks)
279 /
static_cast<double> (
get_ppq ()))
280 * (60.0 / startEvent.bpm));
285 const double bpm0 = startEvent.bpm;
286 const double bpm1 = endEvent.bpm;
288 if (std::abs (bpm1 - bpm0) < 1e-5)
292 (ticksFromStart.in (units::ticks)
293 /
static_cast<double> (
get_ppq ()))
297 const auto fraction = ticksFromStart / dSegmentTicks;
298 const double currentBpm = bpm0 + (fraction * (bpm1 - bpm0));
302 (60.0 * dSegmentTicks.in (units::ticks))
303 / (
get_ppq () * (bpm1 - bpm0)) * std::log (currentBpm / bpm0));
315 units::sample_t tick_to_samples_rounded (units::precise_tick_t tick)
const
323 if (seconds <= units::seconds (0.0))
324 return units::ticks (0.0);
326 const auto &[events, cumulative_seconds] = get_events_or_default ();
329 auto it = std::ranges::upper_bound (cumulative_seconds, seconds);
331 (it == cumulative_seconds.begin ())
333 : std::distance (cumulative_seconds.begin (), it) - 1;
335 const auto baseSeconds = cumulative_seconds[index];
336 const auto timeInSegment = seconds - baseSeconds;
337 const TempoEvent &startEvent = events[index];
340 if (index == events.size () - 1)
343 timeInSegment.in (units::seconds) * (startEvent.bpm / 60.0);
344 return static_cast<units::precise_tick_t
> (startEvent.tick)
345 + units::ticks (beats *
get_ppq ());
348 const TempoEvent &endEvent = events[index + 1];
349 const units::tick_t segmentTicks = endEvent.tick - startEvent.tick;
350 const auto dSegmentTicks =
static_cast<units::precise_tick_t
> (segmentTicks);
356 timeInSegment.in (units::seconds) * (startEvent.bpm / 60.0);
357 return static_cast<units::precise_tick_t
> (startEvent.tick)
358 + units::ticks (beats *
get_ppq ());
363 const double bpm0 = startEvent.bpm;
364 const double bpm1 = endEvent.bpm;
366 if (std::abs (bpm1 - bpm0) < 1e-5)
369 timeInSegment.in (units::seconds) * (bpm0 / 60.0);
370 return static_cast<units::precise_tick_t
> (startEvent.tick)
371 + units::ticks (beats *
get_ppq ());
376 / (60.0 * dSegmentTicks.in (units::ticks));
377 const double expVal = std::exp (A * timeInSegment.in (units::seconds));
378 const double f = (expVal - 1.0) * (bpm0 / (bpm1 - bpm0));
380 return static_cast<units::precise_tick_t
> (startEvent.tick)
384 return static_cast<units::precise_tick_t
> (startEvent.tick);
390 const auto seconds = samples / sample_rate_;
401 if (time_sig_events_.empty ())
402 return default_time_sig_;
405 auto it = std::ranges::upper_bound (
407 if (it == time_sig_events_.begin ())
410 return default_time_sig_;
424 if (events_.empty ())
425 return default_tempo_.bpm;
429 if (it == events_.begin ())
432 return default_tempo_.bpm;
443 const auto &startEvent = *it;
444 const auto &endEvent = *(it + 1);
445 const units::tick_t segmentTicks = endEvent.tick - startEvent.tick;
446 const double fraction =
447 static_cast<units::precise_tick_t
> (tick - startEvent.tick)
448 /
static_cast<units::precise_tick_t
> (segmentTicks);
449 const double currentBpm =
450 startEvent.bpm + fraction * (endEvent.bpm - startEvent.bpm);
462 const auto &time_sig_events = get_time_signature_events_or_default ();
464 if (time_sig_events.empty ())
465 return { 1, 1, 1, 0 };
468 auto it = std::ranges::upper_bound (
470 if (it == time_sig_events.begin ())
472 it = time_sig_events.end ();
479 if (it == time_sig_events.end ())
481 return { 1, 1, 1, 0 };
484 const auto &sigEvent = *it;
485 const int numerator = sigEvent.numerator;
486 const int denominator = sigEvent.denominator;
489 const double quarters_per_bar = numerator * (4.0 / denominator);
490 const int64_t ticks_per_bar =
491 static_cast<int64_t
> (quarters_per_bar *
get_ppq ());
492 const int64_t ticks_per_beat = ticks_per_bar / numerator;
495 int64_t cumulative_bars = 1;
499 for (
auto prev = time_sig_events.begin (); prev != it; ++prev)
501 const int prev_numerator = prev->numerator;
502 const int prev_denominator = prev->denominator;
503 const double prev_quarters_per_bar =
504 prev_numerator * (4.0 / prev_denominator);
505 const int64_t prev_ticks_per_bar =
506 static_cast<int64_t
> (prev_quarters_per_bar *
get_ppq ());
509 auto next = std::next (prev);
510 const auto end_tick =
511 (next != time_sig_events.end ()) ? next->tick : sigEvent.tick;
512 const auto segment_ticks = end_tick - prev->tick;
515 (segment_ticks / prev_ticks_per_bar).in (units::ticks);
520 const auto ticks_since_sig = tick - sigEvent.tick;
521 const int64_t bars_since_sig =
522 ticks_since_sig.in (units::ticks) / ticks_per_bar;
523 const auto bar = cumulative_bars + bars_since_sig;
526 const int64_t ticks_in_bar =
527 ticks_since_sig.in (units::ticks) % ticks_per_bar;
528 const auto beat = 1 + (ticks_in_bar / ticks_per_beat);
531 const int64_t ticks_in_beat = ticks_in_bar % ticks_per_beat;
532 const auto sixteenth =
533 1 + (ticks_in_beat / ticks_per_sixteenth_.in (units::ticks));
534 const auto tick_in_sixteenth =
535 (ticks_in_beat % ticks_per_sixteenth_.in (units::ticks));
538 static_cast<int> (bar),
static_cast<int> (beat),
539 static_cast<int> (sixteenth),
static_cast<int> (tick_in_sixteenth)
543 MusicalPosition samples_to_musical_position (units::sample_t samples)
const
547 const auto tick = au::floor_as<int64_t> (
562 const auto &time_sig_events = get_time_signature_events_or_default ();
565 if (pos.bar < 1 || pos.beat < 1 || pos.sixteenth < 1 || pos.tick < 0)
567 throw std::invalid_argument (
"Invalid musical position");
570 auto cumulative_ticks = units::ticks (0);
574 for (
size_t i = 0; i < time_sig_events.size (); ++i)
576 const auto &
event = time_sig_events[i];
577 const int numerator =
event.numerator;
578 const int denominator =
event.denominator;
579 const double quarters_per_bar = numerator * (4.0 / denominator);
580 const int64_t ticks_per_bar =
581 static_cast<int64_t
> (quarters_per_bar *
get_ppq ());
584 auto bars_in_this_sig = units::ticks (0);
585 if (i < time_sig_events.size () - 1)
587 const units::tick_t next_tick = time_sig_events[i + 1].tick;
588 bars_in_this_sig = (next_tick -
event.tick) / ticks_per_bar;
592 bars_in_this_sig = units::ticks (pos.bar - current_bar + 1);
596 if (pos.bar < current_bar + bars_in_this_sig.in (units::ticks))
598 const int bar_in_seg = pos.bar - current_bar;
599 const auto bar_ticks =
600 event.tick + units::ticks (bar_in_seg * ticks_per_bar);
601 const int64_t ticks_per_beat = ticks_per_bar / numerator;
606 static_cast<int64_t
> (pos.beat - 1) * ticks_per_beat)
608 static_cast<int64_t
> (pos.sixteenth - 1)
609 * ticks_per_sixteenth_.in (units::ticks))
610 + units::ticks (pos.tick);
614 cumulative_ticks += bars_in_this_sig * ticks_per_bar;
615 current_bar += bars_in_this_sig.in (units::ticks);
618 return cumulative_ticks;
622 static consteval int get_ppq () {
return from_nttp (PPQ).in (units::ticks); }
627 return sample_rate_.in (units::sample_rate);
630 void set_default_bpm (
double bpm) { default_tempo_.
bpm = bpm; }
631 void set_default_time_signature (
int numerator,
int denominator)
639 const std::vector<TempoEvent> &get_tempo_events ()
const {
return events_; }
642 const std::vector<TimeSignatureEvent> &get_time_signature_events ()
const
644 return time_sig_events_;
648 void rebuild_cumulative_times ()
650 if (events_.empty ())
656 cumulative_seconds_.resize (events_.size ());
657 cumulative_seconds_[0] = units::seconds (0.0);
660 for (
size_t i = 0; i < events_.size () - 1; ++i)
662 const units::tick_t segmentTicks = events_[i + 1].tick - events_[i].tick;
663 cumulative_seconds_[i + 1] =
664 cumulative_seconds_[i]
665 + compute_segment_time (events_[i], events_[i + 1], segmentTicks);
670 units::precise_second_t compute_segment_time (
673 units::tick_t segmentTicks)
const
677 return units::seconds (
678 (
static_cast<units::precise_tick_t
> (segmentTicks).in (units::ticks)
679 /
static_cast<double> (
get_ppq ()))
680 * (60.0 / start.bpm));
684 const double bpm0 = start.bpm;
685 const double bpm1 = end.bpm;
687 if (std::abs (bpm1 - bpm0) < 1e-5)
689 return units::seconds (
690 (
static_cast<units::precise_tick_t
> (segmentTicks).in (units::ticks)
691 /
static_cast<double> (
get_ppq ()))
695 return units::seconds (
697 *
static_cast<units::precise_tick_t
> (segmentTicks).in (units::ticks))
698 / (
get_ppq () * (bpm1 - bpm0)) * std::log (bpm1 / bpm0));
700 return units::seconds (0.0);
703 auto get_events_or_default ()
const
705 if (events_.empty ())
707 return std::make_pair (
708 std::span{ &default_tempo_, 1 },
709 std::span{ &DEFAULT_CUMULATIVE_SECONDS, 1 });
712 return std::make_pair (
713 std::span{ events_.data (), events_.size () },
714 std::span{ cumulative_seconds_.data (), cumulative_seconds_.size () });
716 auto get_time_signature_events_or_default ()
const
718 if (time_sig_events_.empty ())
720 return std::span{ &default_time_sig_, 1 };
723 return std::span{ time_sig_events_.data (), time_sig_events_.size () };
727 void clear_tempo_events ()
730 cumulative_seconds_.clear ();
734 void clear_time_signature_events () { time_sig_events_.clear (); }
736 static constexpr std::string_view kTempoChangesKey =
"tempoChanges";
737 static constexpr std::string_view kTimeSignaturesKey =
"timeSignatures";
739 friend void from_json (
const nlohmann::json &j,
FixedPpqTempoMap &tempo_map);
742 units::precise_sample_rate_t sample_rate_;
743 static constexpr auto ticks_per_sixteenth_ =
746 static constexpr auto DEFAULT_BPM_EVENT =
TempoEvent{
749 static constexpr auto DEFAULT_TIME_SIG_EVENT =
751 static constexpr auto DEFAULT_CUMULATIVE_SECONDS = units::seconds (0.0);
754 TempoEvent default_tempo_{ DEFAULT_BPM_EVENT };
757 std::vector<TempoEvent> events_;
758 std::vector<TimeSignatureEvent> time_sig_events_;
759 std::vector<units::precise_second_t>