superclock_ticks_per_second: use an (inline) accessor, change value

We do not want a value as large as the previous one, which limits the time
range that can be represented in 62 bits unnecessarily. The new value is
9 times smaller than the previous value, and loses only 384000 as a significant
factor.

This commit also switches to using an (inline) accessor for superclock_ticks_per_second,
making it possible in debug/testing phases to spot early/illegal uses of the value.
This commit is contained in:
Paul Davis 2022-03-17 14:14:41 -06:00
parent 641589c56a
commit a803dd0df8
7 changed files with 40 additions and 30 deletions

View file

@ -31,6 +31,7 @@
#include "pbd/ringbuffer.h"
#include "temporal/bbt_time.h"
#include "temporal/superclock.h
#include "ardour/midi_state_tracker.h"
#include "ardour/processor.h"
@ -43,10 +44,6 @@ class StepSequencer;
typedef uint64_t superclock_t;
static const superclock_t superclock_ticks_per_second = 508032000; // 2^10 * 3^4 * 5^3 * 7^2
inline superclock_t superclock_to_samples (superclock_t s, int sr) { return (s * sr) / superclock_ticks_per_second; }
inline superclock_t samples_to_superclock (int samples, int sr) { return (samples * superclock_ticks_per_second) / sr; }
class BeatBox : public ARDOUR::Processor {
public:
BeatBox (ARDOUR::Session& s);

View file

@ -561,7 +561,7 @@ LuaBindings::common (lua_State* L)
.beginNamespace ("Temporal")
.addConst ("superclock_ticks_per_second", Temporal::superclock_ticks_per_second)
.addFunction ("superclock_ticks_per_second", Temporal::superclock_ticks_per_second)
.addConst ("ticks_per_beat", Temporal::ticks_per_beat)
.beginClass <Temporal::ratio_t> ("ratio")

View file

@ -341,15 +341,6 @@ Session::Session (AudioEngine &eng,
g_atomic_int_set (&_seek_counter, 0);
g_atomic_int_set (&_butler_seek_counter, 0);
/* create a new "default" tempo map. This maybe reset/overwritten by
* the session if it already exists during ::set_state()
*/
TempoMap::SharedPtr tmcopy (TempoMap::write_copy());
/* this discards the copy that was made, and installs the new default tempo map */
tmcopy.reset (new TempoMap (Tempo (120, 4), Meter (4, 4)));
TempoMap::update (tmcopy);
created_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
pthread_mutex_init (&_rt_emit_mutex, 0);

View file

@ -19,13 +19,22 @@
#include "temporal/superclock.h"
#ifndef COMPILER_MSVC
Temporal::superclock_t Temporal::superclock_ticks_per_second = 508032000; // 2^10 * 3^4 * 5^3 * 7^2
Temporal::superclock_t Temporal::_superclock_ticks_per_second = 56448000; /* 2^10 * 3^2 * 5^3 * 7^2 */
#endif
int Temporal::most_recent_engine_sample_rate = 48000; /* have to pick something as a default */
bool Temporal::scts_set = false;
void
Temporal::set_sample_rate (int sr)
{
most_recent_engine_sample_rate = sr;
}
void
Temporal::set_superclock_ticks_per_second (Temporal::superclock_t sc)
{
_superclock_ticks_per_second = sc;
scts_set = true;
}

View file

@ -534,10 +534,10 @@ TempoPoint::quarters_at_superclock (superclock_t sc) const
superclock_t sc_delta = sc - _sclock;
/* convert sc into superbeats, given that sc represents some number of seconds */
const superclock_t whole_seconds = sc_delta / superclock_ticks_per_second;
const superclock_t remainder = sc_delta - (whole_seconds * superclock_ticks_per_second);
const superclock_t whole_seconds = sc_delta / superclock_ticks_per_second();
const superclock_t remainder = sc_delta - (whole_seconds * superclock_ticks_per_second());
const int64_t supernotes = ((_super_note_type_per_second) * whole_seconds) + int_div_round (superclock_t ((_super_note_type_per_second) * remainder), superclock_ticks_per_second);
const int64_t supernotes = ((_super_note_type_per_second) * whole_seconds) + int_div_round (superclock_t ((_super_note_type_per_second) * remainder), superclock_ticks_per_second());
/* multiply after divide to reduce overflow risk */
const int64_t superbeats = int_div_round (supernotes, (superclock_t) _note_type) * 4;
@ -2186,7 +2186,7 @@ std::operator<<(std::ostream& str, TempoMetric const & tm)
std::ostream&
std::operator<<(std::ostream& str, TempoMapPoint const & tmp)
{
str << '@' << std::setw (12) << tmp.sclock() << ' ' << tmp.sclock() / (double) superclock_ticks_per_second
str << '@' << std::setw (12) << tmp.sclock() << ' ' << tmp.sclock() / (double) superclock_ticks_per_second()
<< " secs " << tmp.sample (TEMPORAL_SAMPLE_RATE) << " samples"
<< (tmp.is_explicit_tempo() ? " EXP-T" : " imp-t")
<< (tmp.is_explicit_meter() ? " EXP-M" : " imp-m")
@ -2362,7 +2362,7 @@ TempoMap::get_state ()
XMLNode* node = new XMLNode (X_("TempoMap"));
node->set_property (X_("time-domain"), _time_domain);
node->set_property (X_("superclocks-per-second"), superclock_ticks_per_second);
node->set_property (X_("superclocks-per-second"), superclock_ticks_per_second());
XMLNode* children;
@ -2397,7 +2397,9 @@ TempoMap::set_state (XMLNode const & node, int version)
/* global map properties */
/* XXX this should probably be at the global level in the session file because it affects a lot more than just the tempo map, potentially */
node.get_property (X_("superclocks-per-second"), superclock_ticks_per_second);
superclock_t sc;
node.get_property (X_("superclocks-per-second"), sc);
set_superclock_ticks_per_second (sc);
node.get_property (X_("time-domain"), _time_domain);

View file

@ -19,7 +19,9 @@
#ifndef __ardour_superclock_h__
#define __ardour_superclock_h__
#include <cstdlib>
#include <stdint.h>
#include <csignal>
#include "pbd/integer_division.h"
@ -30,17 +32,26 @@ namespace Temporal {
typedef int64_t superclock_t;
#ifndef COMPILER_MSVC
extern superclock_t superclock_ticks_per_second;
extern superclock_t _superclock_ticks_per_second;
#else
static superclock_t superclock_ticks_per_second = 508032000; // 2^10 * 3^4 * 5^3 * 7^2
static superclock_t _superclock_ticks_per_second = 56448000; /* 2^10 * 3^2 * 5^3 * 7^2 */
#endif
static inline superclock_t superclock_to_samples (superclock_t s, int sr) { return int_div_round (s * sr, superclock_ticks_per_second); }
static inline superclock_t samples_to_superclock (int64_t samples, int sr) { return int_div_round (samples * superclock_ticks_per_second, superclock_t (sr)); }
extern bool scts_set;
#ifdef DEBUG_EARLY_SCTS_USE
static inline superclock_t superclock_ticks_per_second() { if (!scts_set) { raise (SIGUSR2); } return _superclock_ticks_per_second; }
#else
static inline superclock_t superclock_ticks_per_second() { return _superclock_ticks_per_second; }
#endif
static inline superclock_t superclock_to_samples (superclock_t s, int sr) { return int_div_round (s * sr, superclock_ticks_per_second()); }
static inline superclock_t samples_to_superclock (int64_t samples, int sr) { return int_div_round (samples * superclock_ticks_per_second(), superclock_t (sr)); }
extern int most_recent_engine_sample_rate;
LIBTEMPORAL_API void set_sample_rate (int sr);
LIBTEMPORAL_API void set_superclock_ticks_per_second (superclock_t sc);
}

View file

@ -210,9 +210,9 @@ class LIBTEMPORAL_API Tempo : public Rampable {
/* these five methods should only be used to show and collect information to the user (for whom
* bpm as a floating point number is the obvious representation)
*/
double note_types_per_minute () const { return (superclock_ticks_per_second * 60.0) / _superclocks_per_note_type; }
double end_note_types_per_minute () const { return (superclock_ticks_per_second * 60.0) / _end_superclocks_per_note_type; }
double quarter_notes_per_minute() const { return (superclock_ticks_per_second * 60.0 * 4.0) / (_note_type * _superclocks_per_note_type); }
double note_types_per_minute () const { return (superclock_ticks_per_second() * 60.0) / _superclocks_per_note_type; }
double end_note_types_per_minute () const { return (superclock_ticks_per_second() * 60.0) / _end_superclocks_per_note_type; }
double quarter_notes_per_minute() const { return (superclock_ticks_per_second() * 60.0 * 4.0) / (_note_type * _superclocks_per_note_type); }
double samples_per_note_type(samplecnt_t sr) const { return superclock_to_samples (superclocks_per_note_type (), sr); }
double samples_per_quarter_note(samplecnt_t sr) const { return superclock_to_samples (superclocks_per_quarter_note(), sr); }
void set_note_types_per_minute (double npm) { _superclocks_per_note_type = double_npm_to_scpn (npm); }
@ -301,7 +301,7 @@ class LIBTEMPORAL_API Tempo : public Rampable {
Type _type;
static inline uint64_t double_npm_to_snps (double npm) { return (uint64_t) llround (npm * big_numerator / 60); }
static inline superclock_t double_npm_to_scpn (double npm) { return (superclock_t) llround ((60./npm) * superclock_ticks_per_second); }
static inline superclock_t double_npm_to_scpn (double npm) { return (superclock_t) llround ((60./npm) * superclock_ticks_per_second()); }
private:
void set_ramped (bool yn);
@ -416,7 +416,7 @@ class /*LIBTEMPORAL_API*/ TempoPoint : public Tempo, public tempo_hook, public v
*/
LIBTEMPORAL_API double note_types_per_minute_at_DOUBLE (timepos_t const & pos) const {
return (superclock_ticks_per_second * 60.0) / superclocks_per_note_type_at (pos);
return (superclock_ticks_per_second() * 60.0) / superclocks_per_note_type_at (pos);
}
LIBTEMPORAL_API double omega() const { return _omega; }