mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 06:44:57 +01:00
random commit to facilitate trivial move of work from laptop back to main system
This commit is contained in:
parent
5836a4f2b6
commit
f67029bd02
36 changed files with 195 additions and 837 deletions
|
|
@ -284,7 +284,7 @@ AutomationController::set_freq_beats(double beats)
|
|||
const ARDOUR::ParameterDescriptor& desc = _controllable->desc();
|
||||
const ARDOUR::Session& session = _controllable->session();
|
||||
const samplepos_t pos = session.transport_sample();
|
||||
const ARDOUR::Tempo& tempo = session.tempo_map().tempo_at_sample (pos);
|
||||
const Temporal::Tempo& tempo = session.tempo_map().metric_at (pos).tempo();
|
||||
const double bpm = tempo.note_types_per_minute();
|
||||
const double bps = bpm / 60.0;
|
||||
const double freq = bps / beats;
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ using namespace std;
|
|||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace Editing;
|
||||
|
||||
using namespace Temporal;
|
||||
|
||||
#define TIME_TO_SAMPLES(x) (_distance_measure (x, Temporal::AudioTime))
|
||||
#define SAMPLES_TO_TIME(x) (_distance_measure (x, alist->time_domain()))
|
||||
|
|
@ -496,9 +496,8 @@ AutomationLine::ContiguousControlPoints::compute_x_bounds (PublicEditor& e)
|
|||
before_x = line.nth (front()->view_index() - 1)->get_x();
|
||||
|
||||
const samplepos_t pos = e.pixel_to_sample(before_x);
|
||||
const Meter& meter = map.meter_at_sample (pos);
|
||||
const samplecnt_t len = ceil (meter.samples_per_bar (map.tempo_at_sample (pos), e.session()->sample_rate())
|
||||
/ (Temporal::ticks_per_beat * meter.divisions_per_bar()) );
|
||||
const TempoMetric& metric = map.metric_at (pos);
|
||||
const samplecnt_t len = ceil (metric.samples_per_bar (pos) / (Temporal::ticks_per_beat * metric.meter().divisions_per_bar()));
|
||||
const double one_tick_in_pixels = e.sample_to_pixel_unrounded (len);
|
||||
|
||||
before_x += one_tick_in_pixels;
|
||||
|
|
@ -512,9 +511,8 @@ AutomationLine::ContiguousControlPoints::compute_x_bounds (PublicEditor& e)
|
|||
after_x = line.nth (back()->view_index() + 1)->get_x();
|
||||
|
||||
const samplepos_t pos = e.pixel_to_sample(after_x);
|
||||
const Meter& meter = map.meter_at_sample (pos);
|
||||
const samplecnt_t len = ceil (meter.samples_per_bar (map.tempo_at_sample (pos), e.session()->sample_rate())
|
||||
/ (Temporal::ticks_per_beat * meter.divisions_per_bar()));
|
||||
const TempoMetric& metric = map.metric_at (pos);
|
||||
const samplecnt_t len = ceil (metric.samples_per_bar (pos) / (Temporal::ticks_per_beat * metric.meter().divisions_per_bar()));
|
||||
const double one_tick_in_pixels = e.sample_to_pixel_unrounded (len);
|
||||
|
||||
after_x -= one_tick_in_pixels;
|
||||
|
|
|
|||
|
|
@ -1805,9 +1805,9 @@ private:
|
|||
Curves tempo_curves;
|
||||
|
||||
void remove_metric_marks ();
|
||||
void draw_metric_marks (const ARDOUR::Metrics& metrics);
|
||||
void draw_metric_marks (const Temporal::TempoMap::Metrics& metrics);
|
||||
|
||||
void compute_current_bbt_points (std::vector<ARDOUR::TempoMap::BBTPoint>& grid, samplepos_t left, samplepos_t right);
|
||||
void compute_current_bbt_points (std::vector<Temporal::Point>& grid, samplepos_t left, samplepos_t right);
|
||||
|
||||
void tempo_map_changed (const PBD::PropertyChange&);
|
||||
void tempometric_position_changed (const PBD::PropertyChange&);
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ using namespace PBD;
|
|||
using namespace Gtk;
|
||||
using namespace Gtkmm2ext;
|
||||
using namespace Editing;
|
||||
using namespace Temporal;
|
||||
|
||||
using std::string;
|
||||
|
||||
/* Functions supporting the incorporation of external (non-captured) audio material into ardour */
|
||||
|
|
@ -280,7 +282,9 @@ Editor::import_smf_tempo_map (Evoral::SMF const & smf, timepos_t const & pos)
|
|||
}
|
||||
|
||||
const samplecnt_t sample_rate = _session->sample_rate ();
|
||||
TempoMap new_map (sample_rate);
|
||||
#warning NUTEMPO need to be able to create a tempo map with no entries
|
||||
// TempoMap new_map (sample_rate);
|
||||
TempoMap new_map (Tempo (120), Meter (4, 4), sample_rate);
|
||||
Meter last_meter (4.0, 4.0);
|
||||
bool have_initial_meter = false;
|
||||
|
||||
|
|
@ -294,10 +298,12 @@ Editor::import_smf_tempo_map (Evoral::SMF const & smf, timepos_t const & pos)
|
|||
Temporal::BBT_Time bbt; /* 1|1|0 which is correct for the no-meter case */
|
||||
|
||||
if (have_initial_meter) {
|
||||
new_map.add_tempo (tempo, t->time_pulses/ (double)smf.ppqn() / 4.0, 0, MusicTime);
|
||||
#warning NUTEMPO check API for this
|
||||
// new_map.add_tempo (tempo, t->time_pulses/ (double)smf.ppqn() / 4.0, 0, BeatTime);
|
||||
if (!(meter == last_meter)) {
|
||||
bbt = new_map.bbt_at_quarter_note (t->time_pulses/(double)smf.ppqn());
|
||||
new_map.add_meter (meter, bbt, 0, MusicTime);
|
||||
bbt = new_map.bbt_at (Beats::from_double (t->time_pulses/(double)smf.ppqn()));
|
||||
#warning NUTEMPO check API for this
|
||||
//new_map.add_meter (meter, bbt, 0, MusicTime);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -311,7 +317,8 @@ Editor::import_smf_tempo_map (Evoral::SMF const & smf, timepos_t const & pos)
|
|||
last_meter = meter;
|
||||
}
|
||||
|
||||
_session->tempo_map() = new_map;
|
||||
#warning NUTEMPO need an assignment API for TempoMap
|
||||
//_session->tempo_map() = new_map;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -3717,7 +3717,7 @@ BBTRulerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
|
|||
#warning NUTEMPO fixme needs new tempo map
|
||||
#if 0
|
||||
TempoMap& map (_editor->session()->tempo_map());
|
||||
_tempo = const_cast<TempoSection*> (&map.tempo_section_at_sample (raw_grab_sample()));
|
||||
_tempo = const_cast<TempoSection*> (&map.metric_at (raw_grab_sample().tempo()));
|
||||
|
||||
if (adjusted_current_time (event, false) <= _tempo->time()) {
|
||||
_drag_valid = false;
|
||||
|
|
@ -3748,7 +3748,7 @@ BBTRulerDrag::setup_pointer_offset ()
|
|||
/* get current state */
|
||||
_before_state = &map.get_state();
|
||||
|
||||
const double beat_at_sample = max (0.0, map.beat_at_sample (raw_grab_sample()));
|
||||
const double beat_at_sample = max (0.0, map.beat_at (raw_grab_sample()));
|
||||
const uint32_t divisions = _editor->get_grid_beat_divisions (0);
|
||||
double beat = 0.0;
|
||||
|
||||
|
|
@ -3762,7 +3762,7 @@ BBTRulerDrag::setup_pointer_offset ()
|
|||
beat = floor (beat_at_sample) + (floor (((beat_at_sample - floor (beat_at_sample)) * 4)) / 4);
|
||||
}
|
||||
|
||||
_grab_qn = map.quarter_note_at_beat (beat);
|
||||
_grab_qn = map.quarter_note_at (beat);
|
||||
|
||||
_pointer_offset = raw_grab_sample() - map.sample_at_quarter_note (_grab_qn);
|
||||
|
||||
|
|
|
|||
|
|
@ -875,7 +875,7 @@ private:
|
|||
|
||||
bool _copy;
|
||||
bool _movable;
|
||||
ARDOUR::Tempo _grab_bpm;
|
||||
Temporal::Tempo _grab_bpm;
|
||||
double _grab_qn;
|
||||
XMLNode* _before_state;
|
||||
};
|
||||
|
|
@ -931,9 +931,9 @@ public:
|
|||
|
||||
private:
|
||||
double _grab_qn;
|
||||
ARDOUR::Tempo _grab_tempo;
|
||||
ARDOUR::TempoSection* _tempo;
|
||||
ARDOUR::TempoSection* _next_tempo;
|
||||
Temporal::Tempo _grab_tempo;
|
||||
Temporal::TempoPoint* _tempo;
|
||||
Temporal::TempoPoint* _next_tempo;
|
||||
bool _drag_valid;
|
||||
XMLNode* _before_state;
|
||||
};
|
||||
|
|
@ -962,7 +962,7 @@ public:
|
|||
|
||||
private:
|
||||
double _grab_qn;
|
||||
ARDOUR::TempoSection* _tempo;
|
||||
Temporal::TempoPoint* _tempo;
|
||||
XMLNode* _before_state;
|
||||
bool _drag_valid;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1032,7 +1032,7 @@ ExportFormatDialog::update_time (AnyTime& time, AudioClock const& clock)
|
|||
break;
|
||||
case AudioClock::BBT:
|
||||
time.type = AnyTime::BBT;
|
||||
_session->bbt_time (samples, time.bbt);
|
||||
_session->bbt_time (timepos_t (samples), time.bbt);
|
||||
break;
|
||||
case AudioClock::Seconds:
|
||||
case AudioClock::MinSec:
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ using namespace Gtk;
|
|||
using namespace Gtkmm2ext;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace Temporal;
|
||||
|
||||
TempoDialog::TempoDialog (TempoMap& map, samplepos_t sample, const string&)
|
||||
: ArdourDialog (_("New Tempo"))
|
||||
|
|
@ -55,16 +56,17 @@ TempoDialog::TempoDialog (TempoMap& map, samplepos_t sample, const string&)
|
|||
, pulse_selector_label (_("Pulse:"), ALIGN_LEFT, ALIGN_CENTER)
|
||||
, tap_tempo_button (_("Tap tempo"))
|
||||
{
|
||||
Tempo tempo (map.tempo_at_sample (sample));
|
||||
Temporal::BBT_Time when (map.bbt_at_sample (sample));
|
||||
TempoMetric metric (map.metric_at (sample));
|
||||
Temporal::BBT_Time when (metric.bbt_at (sample));
|
||||
Tempo& tempo (metric.tempo());
|
||||
|
||||
init (when, tempo.note_types_per_minute(), tempo.end_note_types_per_minute(), tempo.note_type(), TempoSection::Constant, true, MusicTime);
|
||||
init (when, tempo.note_types_per_minute(), tempo.end_note_types_per_minute(), tempo.note_type(), Tempo::Constant, true, BeatTime);
|
||||
}
|
||||
|
||||
TempoDialog::TempoDialog (TempoMap& map, TempoSection& section, const string&)
|
||||
TempoDialog::TempoDialog (TempoMap& map, TempoPoint& point, const string&)
|
||||
: ArdourDialog (_("Edit Tempo"))
|
||||
, _map (&map)
|
||||
, _section (§ion)
|
||||
, _section (&point)
|
||||
, bpm_adjustment (60.0, 1.0, 999.9, 0.1, 1.0)
|
||||
, bpm_spinner (bpm_adjustment)
|
||||
, end_bpm_adjustment (60.0, 1.0, 999.9, 0.1, 1.0)
|
||||
|
|
@ -75,13 +77,13 @@ TempoDialog::TempoDialog (TempoMap& map, TempoSection& section, const string&)
|
|||
, pulse_selector_label (_("Pulse:"), ALIGN_LEFT, ALIGN_CENTER)
|
||||
, tap_tempo_button (_("Tap tempo"))
|
||||
{
|
||||
Temporal::BBT_Time when (map.bbt_at_sample (section.sample()));
|
||||
init (when, section.note_types_per_minute(), section.end_note_types_per_minute(), section.note_type(), section.type()
|
||||
, section.initial() || section.locked_to_meter(), section.position_lock_style());
|
||||
Temporal::BBT_Time when (map.bbt_at (point.time()));
|
||||
init (when, _section->note_types_per_minute(), _section->end_note_types_per_minute(), _section->note_type(), _section->type(),
|
||||
(map.is_initial (point) ||(map.time_domain() == Temporal::BarTime)), map.time_domain());
|
||||
}
|
||||
|
||||
void
|
||||
TempoDialog::init (const Temporal::BBT_Time& when, double bpm, double end_bpm, double note_type, TempoSection::Type type, bool initial, PositionLockStyle style)
|
||||
TempoDialog::init (const Temporal::BBT_Time& when, double bpm, double end_bpm, double note_type, Tempo::Type type, bool initial, TimeDomain style)
|
||||
{
|
||||
vector<string> strings;
|
||||
NoteTypes::iterator x;
|
||||
|
|
|
|||
|
|
@ -43,18 +43,18 @@
|
|||
class TempoDialog : public ArdourDialog
|
||||
{
|
||||
public:
|
||||
TempoDialog (ARDOUR::TempoMap&, samplepos_t, const std::string & action);
|
||||
TempoDialog (ARDOUR::TempoMap&, ARDOUR::TempoSection&, const std::string & action);
|
||||
TempoDialog (Temporal::TempoMap&, samplepos_t, const std::string & action);
|
||||
TempoDialog (Temporal::TempoMap&, Temporal::TempoPoint&, const std::string & action);
|
||||
|
||||
double get_bpm ();
|
||||
double get_end_bpm ();
|
||||
double get_note_type ();
|
||||
bool get_bbt_time (Temporal::BBT_Time&);
|
||||
ARDOUR::TempoSection::Type get_tempo_type ();
|
||||
ARDOUR::PositionLockStyle get_lock_style ();
|
||||
Temporal::Tempo::Type get_tempo_type ();
|
||||
Temporal::TimeDomain get_lock_style ();
|
||||
|
||||
private:
|
||||
void init (const Temporal::BBT_Time& start, double bpm, double end_bpm, double note_type, ARDOUR::TempoSection::Type type, bool movable, ARDOUR::PositionLockStyle style);
|
||||
void init (const Temporal::BBT_Time& start, double bpm, double end_bpm, double note_type, Temporal::TempoPoint::Type type, bool movable, Temporal::TimeDomain style);
|
||||
bool is_user_input_valid() const;
|
||||
void bpm_changed ();
|
||||
bool bpm_button_press (GdkEventButton* );
|
||||
|
|
@ -72,10 +72,10 @@ private:
|
|||
typedef std::map<std::string,float> NoteTypes;
|
||||
NoteTypes note_types;
|
||||
|
||||
typedef std::map<std::string, ARDOUR::TempoSection::Type> TempoTypes;
|
||||
typedef std::map<std::string, Temporal::Tempo::Type> TempoTypes;
|
||||
TempoTypes tempo_types;
|
||||
|
||||
typedef std::map<std::string, ARDOUR::PositionLockStyle> LockStyles;
|
||||
typedef std::map<std::string, Temporal::TimeDomain> LockStyles;
|
||||
LockStyles lock_styles;
|
||||
|
||||
bool tapped; // whether the tap-tempo button has been clicked
|
||||
|
|
@ -84,8 +84,8 @@ private:
|
|||
double last_t;
|
||||
gint64 first_t;
|
||||
|
||||
ARDOUR::TempoMap* _map;
|
||||
ARDOUR::TempoSection* _section;
|
||||
Temporal::TempoMap* _map;
|
||||
Temporal::TempoPoint* _section;
|
||||
|
||||
Gtk::ComboBoxText pulse_selector;
|
||||
Gtk::Adjustment bpm_adjustment;
|
||||
|
|
@ -107,16 +107,16 @@ class MeterDialog : public ArdourDialog
|
|||
{
|
||||
public:
|
||||
|
||||
MeterDialog (ARDOUR::TempoMap&, samplepos_t, const std::string & action);
|
||||
MeterDialog (ARDOUR::TempoMap&, ARDOUR::MeterSection&, const std::string & action);
|
||||
MeterDialog (Temporal::TempoMap&, samplepos_t, const std::string & action);
|
||||
MeterDialog (Temporal::TempoMap&, Temporal::MeterPoint&, const std::string & action);
|
||||
|
||||
double get_bpb ();
|
||||
double get_note_type ();
|
||||
ARDOUR::PositionLockStyle get_lock_style ();
|
||||
Temporal::TimeDomain get_lock_style ();
|
||||
bool get_bbt_time (Temporal::BBT_Time&);
|
||||
|
||||
private:
|
||||
void init (const Temporal::BBT_Time&, double, double, bool, ARDOUR::PositionLockStyle style);
|
||||
void init (const Temporal::BBT_Time&, double, double, bool, Temporal::TimeDomain style);
|
||||
bool is_user_input_valid() const;
|
||||
bool entry_key_press (GdkEventKey* );
|
||||
bool entry_key_release (GdkEventKey* );
|
||||
|
|
@ -126,7 +126,7 @@ private:
|
|||
typedef std::map<std::string,float> NoteTypes;
|
||||
NoteTypes note_types;
|
||||
|
||||
typedef std::map<std::string, ARDOUR::PositionLockStyle> LockStyles;
|
||||
typedef std::map<std::string, Temporal::TimeDomain> LockStyles;
|
||||
LockStyles lock_styles;
|
||||
|
||||
Gtk::Entry bpb_entry;
|
||||
|
|
|
|||
|
|
@ -116,6 +116,10 @@ namespace Evoral {
|
|||
class Curve;
|
||||
}
|
||||
|
||||
namespace Temporal {
|
||||
class TempoMap;
|
||||
}
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Amp;
|
||||
|
|
@ -168,7 +172,6 @@ class SessionPlaylists;
|
|||
class SoloMuteRelease;
|
||||
class Source;
|
||||
class Speakers;
|
||||
class TempoMap;
|
||||
class TransportMaster;
|
||||
struct TransportFSM;
|
||||
class Track;
|
||||
|
|
@ -782,7 +785,7 @@ public:
|
|||
|
||||
void sync_time_vars();
|
||||
|
||||
void bbt_time (samplepos_t when, Temporal::BBT_Time&);
|
||||
void bbt_time (Temporal::timepos_t const & when, Temporal::BBT_Time&);
|
||||
void timecode_to_sample(Timecode::Time& timecode, samplepos_t& sample, bool use_offset, bool use_subframes) const;
|
||||
void sample_to_timecode(samplepos_t sample, Timecode::Time& timecode, bool use_offset, bool use_subframes) const;
|
||||
void timecode_time (Timecode::Time &);
|
||||
|
|
@ -825,8 +828,8 @@ public:
|
|||
bool loop_is_possible () const;
|
||||
PBD::Signal0<void> PunchLoopConstraintChange;
|
||||
|
||||
TempoMap& tempo_map() { return *_tempo_map; }
|
||||
const TempoMap& tempo_map() const { return *_tempo_map; }
|
||||
Temporal::TempoMap& tempo_map() { return *_tempo_map; }
|
||||
const Temporal::TempoMap& tempo_map() const { return *_tempo_map; }
|
||||
void maybe_update_tempo_from_midiclock_tempo (float bpm);
|
||||
|
||||
unsigned int get_xrun_count () const {return _xrun_count; }
|
||||
|
|
@ -1864,8 +1867,8 @@ private:
|
|||
int send_full_time_code (samplepos_t, pframes_t nframes);
|
||||
void send_song_position_pointer (samplepos_t);
|
||||
|
||||
TempoMap *_tempo_map;
|
||||
void tempo_map_changed (const PBD::PropertyChange&);
|
||||
Temporal::TempoMap *_tempo_map;
|
||||
void tempo_map_changed ();
|
||||
|
||||
/* edit/mix groups */
|
||||
|
||||
|
|
|
|||
|
|
@ -1,645 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2006-2017 Paul Davis <paul@linuxaudiosystems.com>
|
||||
* Copyright (C) 2006 Hans Fugal <hans@fugal.net>
|
||||
* Copyright (C) 2007-2015 David Robillard <d@drobilla.net>
|
||||
* Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
|
||||
* Copyright (C) 2015-2017 Ben Loftis <ben@harrisonconsoles.com>
|
||||
* Copyright (C) 2015-2017 Nick Mainsbridge <mainsbridge@gmail.com>
|
||||
* Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
|
||||
* Copyright (C) 2015 Colin Fletcher <colin.m.fletcher@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __ardour_tempo_h__
|
||||
#define __ardour_tempo_h__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <glibmm/threads.h>
|
||||
|
||||
#include "pbd/undo.h"
|
||||
#include "pbd/enum_convert.h"
|
||||
|
||||
#include "pbd/stateful.h"
|
||||
#include "pbd/statefuldestructible.h"
|
||||
|
||||
#include "temporal/beats.h"
|
||||
|
||||
#include "ardour/ardour.h"
|
||||
|
||||
class BBTTest;
|
||||
class FrameposPlusBeatsTest;
|
||||
class FrameposMinusBeatsTest;
|
||||
class TempoTest;
|
||||
class XMLNode;
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
enum PositionLockStyle {
|
||||
AudioTime,
|
||||
MusicTime
|
||||
};
|
||||
|
||||
class Meter;
|
||||
class TempoMap;
|
||||
|
||||
// Find a better place for these
|
||||
LIBARDOUR_API bool bbt_time_to_string (const Temporal::BBT_Time& bbt, std::string& str);
|
||||
LIBARDOUR_API bool string_to_bbt_time (const std::string& str, Temporal::BBT_Time& bbt);
|
||||
|
||||
/** Tempo, the speed at which musical time progresses (BPM). */
|
||||
class LIBARDOUR_API Tempo {
|
||||
public:
|
||||
/**
|
||||
* @param npm Note Types per minute
|
||||
* @param type Note Type (default `4': quarter note)
|
||||
*/
|
||||
Tempo (double npm, double type=4.0) // defaulting to quarter note
|
||||
: _note_types_per_minute (npm), _note_type (type), _end_note_types_per_minute (npm) {}
|
||||
Tempo (double start_npm, double type, double end_npm)
|
||||
: _note_types_per_minute (start_npm), _note_type (type), _end_note_types_per_minute (end_npm) {}
|
||||
|
||||
double note_types_per_minute () const { return _note_types_per_minute; }
|
||||
double note_types_per_minute (double note_type) const { return (_note_types_per_minute / _note_type) * note_type; }
|
||||
void set_note_types_per_minute (double npm) { _note_types_per_minute = npm; }
|
||||
double note_type () const { return _note_type; }
|
||||
|
||||
double quarter_notes_per_minute () const { return note_types_per_minute (4.0); }
|
||||
double pulses_per_minute () const { return note_types_per_minute (1.0); }
|
||||
|
||||
double end_note_types_per_minute () const { return _end_note_types_per_minute; }
|
||||
double end_note_types_per_minute (double note_type) const { return (_end_note_types_per_minute / _note_type) * note_type; }
|
||||
void set_end_note_types_per_minute (double npm) { _end_note_types_per_minute = npm; }
|
||||
|
||||
double end_quarter_notes_per_minute () const { return end_note_types_per_minute (4.0); }
|
||||
double end_pulses_per_minute () const { return end_note_types_per_minute (1.0); }
|
||||
|
||||
/** audio samples per note type.
|
||||
* if you want an instantaneous value for this, use TempoMap::samples_per_quarter_note_at() instead.
|
||||
* @param sr samplerate
|
||||
*/
|
||||
double samples_per_note_type (samplecnt_t sr) const {
|
||||
return (60.0 * sr) / _note_types_per_minute;
|
||||
}
|
||||
/** audio samples per quarter note.
|
||||
* if you want an instantaneous value for this, use TempoMap::samples_per_quarter_note_at() instead.
|
||||
* @param sr samplerate
|
||||
*/
|
||||
double samples_per_quarter_note (samplecnt_t sr) const {
|
||||
return (60.0 * sr) / quarter_notes_per_minute ();
|
||||
}
|
||||
|
||||
protected:
|
||||
double _note_types_per_minute;
|
||||
double _note_type;
|
||||
double _end_note_types_per_minute;
|
||||
};
|
||||
|
||||
/** Meter, or time signature (beats per bar, and which note type is a beat). */
|
||||
class LIBARDOUR_API Meter {
|
||||
public:
|
||||
Meter (double dpb, double bt)
|
||||
: _divisions_per_bar (dpb), _note_type (bt) {}
|
||||
|
||||
double divisions_per_bar () const { return _divisions_per_bar; }
|
||||
double note_divisor() const { return _note_type; }
|
||||
|
||||
double samples_per_bar (const Tempo&, samplecnt_t sr) const;
|
||||
double samples_per_grid (const Tempo&, samplecnt_t sr) const;
|
||||
|
||||
inline bool operator==(const Meter& other)
|
||||
{ return _divisions_per_bar == other.divisions_per_bar() && _note_type == other.note_divisor(); }
|
||||
|
||||
protected:
|
||||
/** The number of divisions in a bar. This is a floating point value because
|
||||
there are musical traditions on our planet that do not limit
|
||||
themselves to integral numbers of beats per bar.
|
||||
*/
|
||||
double _divisions_per_bar;
|
||||
|
||||
/** The type of "note" that a division represents. For example, 4.0 is
|
||||
a quarter (crotchet) note, 8.0 is an eighth (quaver) note, etc.
|
||||
*/
|
||||
double _note_type;
|
||||
};
|
||||
|
||||
/** A section of timeline with a certain Tempo or Meter. */
|
||||
class LIBARDOUR_API MetricSection {
|
||||
public:
|
||||
MetricSection (double pulse, double minute, PositionLockStyle pls, bool is_tempo, samplecnt_t sample_rate)
|
||||
: _pulse (pulse), _minute (minute), _initial (false), _position_lock_style (pls), _is_tempo (is_tempo), _sample_rate (sample_rate) {}
|
||||
|
||||
virtual ~MetricSection() {}
|
||||
|
||||
const double& pulse () const { return _pulse; }
|
||||
void set_pulse (double pulse) { _pulse = pulse; }
|
||||
|
||||
double minute() const { return _minute; }
|
||||
virtual void set_minute (double m) {
|
||||
_minute = m;
|
||||
}
|
||||
|
||||
samplepos_t sample () const { return sample_at_minute (_minute); }
|
||||
|
||||
void set_initial (bool yn) { _initial = yn; }
|
||||
bool initial() const { return _initial; }
|
||||
|
||||
/* MeterSections are not stateful in the full sense,
|
||||
but we do want them to control their own
|
||||
XML state information.
|
||||
*/
|
||||
virtual XMLNode& get_state() const = 0;
|
||||
|
||||
virtual int set_state (const XMLNode&, int version);
|
||||
|
||||
PositionLockStyle position_lock_style () const { return _position_lock_style; }
|
||||
void set_position_lock_style (PositionLockStyle ps) { _position_lock_style = ps; }
|
||||
bool is_tempo () const { return _is_tempo; }
|
||||
|
||||
samplepos_t sample_at_minute (const double& time) const;
|
||||
double minute_at_sample (const samplepos_t sample) const;
|
||||
|
||||
protected:
|
||||
void add_state_to_node (XMLNode& node) const;
|
||||
|
||||
private:
|
||||
|
||||
double _pulse;
|
||||
double _minute;
|
||||
bool _initial;
|
||||
PositionLockStyle _position_lock_style;
|
||||
const bool _is_tempo;
|
||||
samplecnt_t _sample_rate;
|
||||
};
|
||||
|
||||
/** A section of timeline with a certain Meter. */
|
||||
class LIBARDOUR_API MeterSection : public MetricSection, public Meter {
|
||||
public:
|
||||
MeterSection (double pulse, double minute, double beat, const Temporal::BBT_Time& bbt, double bpb, double note_type, PositionLockStyle pls, samplecnt_t sr)
|
||||
: MetricSection (pulse, minute, pls, false, sr), Meter (bpb, note_type), _bbt (bbt), _beat (beat) {}
|
||||
|
||||
MeterSection (const XMLNode&, const samplecnt_t sample_rate);
|
||||
|
||||
static const std::string xml_state_node_name;
|
||||
|
||||
XMLNode& get_state() const;
|
||||
|
||||
void set_beat (std::pair<double, Temporal::BBT_Time>& w) {
|
||||
_beat = w.first;
|
||||
_bbt = w.second;
|
||||
}
|
||||
|
||||
const Temporal::BBT_Time& bbt() const { return _bbt; }
|
||||
const double& beat () const { return _beat; }
|
||||
void set_beat (double beat) { _beat = beat; }
|
||||
|
||||
private:
|
||||
Temporal::BBT_Time _bbt;
|
||||
double _beat;
|
||||
};
|
||||
|
||||
/** A section of timeline with a certain Tempo. */
|
||||
class LIBARDOUR_API TempoSection : public MetricSection, public Tempo {
|
||||
public:
|
||||
enum Type {
|
||||
Ramp,
|
||||
Constant,
|
||||
};
|
||||
|
||||
TempoSection (const double& pulse, const double& minute, Tempo tempo, PositionLockStyle pls, samplecnt_t sr)
|
||||
: MetricSection (pulse, minute, pls, true, sr), Tempo (tempo), _c (0.0), _active (true), _locked_to_meter (false), _clamped (false) {}
|
||||
|
||||
TempoSection (const XMLNode&, const samplecnt_t sample_rate);
|
||||
|
||||
static const std::string xml_state_node_name;
|
||||
|
||||
XMLNode& get_state() const;
|
||||
|
||||
double c () const { return _c; }
|
||||
void set_c (double c) { _c = c; }
|
||||
|
||||
Type type () const { if (note_types_per_minute() == end_note_types_per_minute()) { return Constant; } else { return Ramp; } }
|
||||
|
||||
bool active () const { return _active; }
|
||||
void set_active (bool yn) { _active = yn; }
|
||||
|
||||
bool locked_to_meter () const { return _locked_to_meter; }
|
||||
void set_locked_to_meter (bool yn) { _locked_to_meter = yn; }
|
||||
|
||||
bool clamped () const { return _clamped; }
|
||||
void set_clamped (bool yn) { _clamped = yn; }
|
||||
|
||||
Tempo tempo_at_minute (const double& minute) const;
|
||||
double minute_at_ntpm (const double& ntpm, const double& pulse) const;
|
||||
|
||||
Tempo tempo_at_pulse (const double& pulse) const;
|
||||
double pulse_at_ntpm (const double& ntpm, const double& minute) const;
|
||||
|
||||
double pulse_at_minute (const double& minute) const;
|
||||
double minute_at_pulse (const double& pulse) const;
|
||||
|
||||
double compute_c_pulse (const double& end_ntpm, const double& end_pulse) const;
|
||||
double compute_c_minute (const double& end_ntpm, const double& end_minute) const;
|
||||
|
||||
double pulse_at_sample (const samplepos_t sample) const;
|
||||
samplepos_t sample_at_pulse (const double& pulse) const;
|
||||
|
||||
Temporal::BBT_Time legacy_bbt () { return _legacy_bbt; }
|
||||
|
||||
private:
|
||||
|
||||
/* tempo ramp functions. zero-based with time in minutes,
|
||||
* 'tick tempo' in ticks per minute and tempo in bpm.
|
||||
* time relative to section start.
|
||||
*/
|
||||
double a_func (double end_tpm, double c_func) const;
|
||||
double c_func (double end_tpm, double end_time) const;
|
||||
|
||||
double _tempo_at_time (const double& time) const;
|
||||
double _time_at_tempo (const double& tempo) const;
|
||||
|
||||
double _tempo_at_pulse (const double& pulse) const;
|
||||
double _pulse_at_tempo (const double& tempo) const;
|
||||
|
||||
double _pulse_at_time (const double& time) const;
|
||||
double _time_at_pulse (const double& pulse) const;
|
||||
|
||||
/* this value provides a fractional offset into the bar in which
|
||||
the tempo section is located in. A value of 0.0 indicates that
|
||||
it occurs on the first beat of the bar, a value of 0.5 indicates
|
||||
that it occurs halfway through the bar and so on.
|
||||
|
||||
this enables us to keep the tempo change at the same relative
|
||||
position within the bar if/when the meter changes.
|
||||
*/
|
||||
|
||||
double _c;
|
||||
bool _active;
|
||||
bool _locked_to_meter;
|
||||
bool _clamped;
|
||||
Temporal::BBT_Time _legacy_bbt;
|
||||
};
|
||||
|
||||
typedef std::list<MetricSection*> Metrics;
|
||||
|
||||
/** Helper class to keep track of the Meter *AND* Tempo in effect
|
||||
at a given point in time.
|
||||
*/
|
||||
class LIBARDOUR_API TempoMetric {
|
||||
public:
|
||||
TempoMetric (const Meter& m, const Tempo& t)
|
||||
: _meter (&m), _tempo (&t), _minute (0.0), _pulse (0.0) {}
|
||||
|
||||
void set_tempo (const Tempo& t) { _tempo = &t; }
|
||||
void set_meter (const Meter& m) { _meter = &m; }
|
||||
void set_minute (double m) { _minute = m; }
|
||||
void set_pulse (const double& p) { _pulse = p; }
|
||||
|
||||
void set_metric (const MetricSection* section) {
|
||||
const MeterSection* meter;
|
||||
const TempoSection* tempo;
|
||||
if ((meter = dynamic_cast<const MeterSection*>(section))) {
|
||||
set_meter(*meter);
|
||||
} else if ((tempo = dynamic_cast<const TempoSection*>(section))) {
|
||||
set_tempo(*tempo);
|
||||
}
|
||||
|
||||
set_minute (section->minute());
|
||||
set_pulse (section->pulse());
|
||||
}
|
||||
|
||||
const Meter& meter() const { return *_meter; }
|
||||
const Tempo& tempo() const { return *_tempo; }
|
||||
double minute() const { return _minute; }
|
||||
const double& pulse() const { return _pulse; }
|
||||
|
||||
private:
|
||||
const Meter* _meter;
|
||||
const Tempo* _tempo;
|
||||
double _minute;
|
||||
double _pulse;
|
||||
};
|
||||
|
||||
/** Tempo Map - mapping of timecode to musical time.
|
||||
* convert audio-samples, sample-rate to Bar/Beat/Tick, Meter/Tempo
|
||||
*/
|
||||
class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
|
||||
{
|
||||
public:
|
||||
TempoMap (samplecnt_t sample_rate);
|
||||
~TempoMap();
|
||||
|
||||
TempoMap& operator= (TempoMap const &);
|
||||
|
||||
/* measure-based stuff */
|
||||
|
||||
enum BBTPointType {
|
||||
Bar,
|
||||
Beat,
|
||||
};
|
||||
|
||||
struct BBTPoint {
|
||||
Meter meter;
|
||||
Tempo tempo;
|
||||
samplepos_t sample;
|
||||
uint32_t bar;
|
||||
uint32_t beat;
|
||||
double qn;
|
||||
|
||||
BBTPoint (const MeterSection& m, const Tempo& t, samplepos_t f,
|
||||
uint32_t b, uint32_t e, double qnote)
|
||||
: meter (m), tempo (t), sample (f), bar (b), beat (e), qn (qnote) {}
|
||||
|
||||
Temporal::BBT_Time bbt() const { return Temporal::BBT_Time (bar, beat, 0); }
|
||||
operator Temporal::BBT_Time() const { return bbt(); }
|
||||
operator samplepos_t() const { return sample; }
|
||||
bool is_bar() const { return beat == 1; }
|
||||
};
|
||||
|
||||
template<class T> void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) {
|
||||
Glib::Threads::RWLock::ReaderLock lm (lock);
|
||||
(obj.*method)(_metrics);
|
||||
}
|
||||
|
||||
void get_grid (std::vector<BBTPoint>&,
|
||||
samplepos_t start, samplepos_t end, uint32_t bar_mod = 0);
|
||||
|
||||
void midi_clock_beat_at_of_after (samplepos_t const pos, samplepos_t& clk_pos, uint32_t& clk_beat);
|
||||
|
||||
static const Tempo& default_tempo() { return _default_tempo; }
|
||||
static const Meter& default_meter() { return _default_meter; }
|
||||
|
||||
/* because tempi may be ramped, this is only valid for the instant requested.*/
|
||||
double samples_per_quarter_note_at (const samplepos_t, const samplecnt_t sr) const;
|
||||
|
||||
const TempoSection& tempo_section_at_sample (samplepos_t sample) const;
|
||||
TempoSection& tempo_section_at_sample (samplepos_t sample);
|
||||
const MeterSection& meter_section_at_sample (samplepos_t sample) const;
|
||||
const MeterSection& meter_section_at_beat (double beat) const;
|
||||
|
||||
TempoSection* previous_tempo_section (TempoSection*) const;
|
||||
TempoSection* next_tempo_section (TempoSection*) const;
|
||||
|
||||
/** add a tempo section locked to pls. ignored values will be set in recompute_tempi()
|
||||
* @param pulse pulse position of new section. ignored if \p pls == AudioTime
|
||||
* @param sample frame position of new section. ignored if \p pls == MusicTime
|
||||
* @param pls the position lock style
|
||||
*/
|
||||
TempoSection* add_tempo (const Tempo&, const double& pulse, const samplepos_t sample, PositionLockStyle pls);
|
||||
|
||||
/** add a meter section locked to \p pls . ignored values will be set in recompute_meters()
|
||||
* @param meter the Meter to be added
|
||||
* @param where bbt position of new section
|
||||
* @param sample frame position of new section. ignored if \p pls == MusicTime
|
||||
*
|
||||
* note that \p sample may also be ignored if it would create an un-solvable map
|
||||
* (previous audio-locked tempi may place the requested beat at an earlier time than sample)
|
||||
* in which case the new meter will be placed at the specified BBT.
|
||||
* @param pls the position lock style
|
||||
*
|
||||
* adding an audio-locked meter will add a meter-locked tempo section at the meter position.
|
||||
* the meter-locked tempo tempo will be the Tempo at the beat
|
||||
*/
|
||||
MeterSection* add_meter (const Meter& meter, const Temporal::BBT_Time& where, samplepos_t sample, PositionLockStyle pls);
|
||||
|
||||
void remove_tempo (const TempoSection&, bool send_signal);
|
||||
void remove_meter (const MeterSection&, bool send_signal);
|
||||
|
||||
void replace_tempo (TempoSection&, const Tempo&, const double& pulse, const samplepos_t sample, PositionLockStyle pls);
|
||||
|
||||
void replace_meter (const MeterSection&, const Meter&, const Temporal::BBT_Time& where, samplepos_t sample, PositionLockStyle pls);
|
||||
|
||||
MusicSample round_to_bar (samplepos_t sample, Temporal::RoundMode dir);
|
||||
MusicSample round_to_beat (samplepos_t sample, Temporal::RoundMode dir);
|
||||
MusicSample round_to_quarter_note_subdivision (samplepos_t fr, int sub_num, Temporal::RoundMode dir);
|
||||
|
||||
void set_length (samplepos_t samples);
|
||||
|
||||
XMLNode& get_state (void);
|
||||
int set_state (const XMLNode&, int version);
|
||||
|
||||
void dump (std::ostream&) const;
|
||||
void clear ();
|
||||
|
||||
TempoMetric metric_at (Temporal::BBT_Time bbt) const;
|
||||
|
||||
/** Return the TempoMetric at sample @p t, and point @p last to the latest
|
||||
* metric change <= t, if it is non-NULL.
|
||||
*/
|
||||
TempoMetric metric_at (samplepos_t, Metrics::const_iterator* last=NULL) const;
|
||||
|
||||
Metrics::const_iterator metrics_end() { return _metrics.end(); }
|
||||
|
||||
void change_existing_tempo_at (samplepos_t, double bpm, double note_type, double end_ntpm);
|
||||
void change_initial_tempo (double ntpm, double note_type, double end_ntpm);
|
||||
|
||||
void insert_time (samplepos_t, samplecnt_t);
|
||||
bool remove_time (samplepos_t where, samplecnt_t amount); //returns true if anything was moved
|
||||
|
||||
int n_tempos () const;
|
||||
int n_meters () const;
|
||||
|
||||
samplecnt_t sample_rate () const { return _sample_rate; }
|
||||
|
||||
/* TEMPO- AND METER-SENSITIVE FUNCTIONS
|
||||
|
||||
bbt_at_sample(), sample_at_bbt(), beat_at_sample(), sample_at_beat()
|
||||
and bbt_duration_at()
|
||||
are all sensitive to tempo and meter, and will give answers
|
||||
that align with the grid formed by tempo and meter sections.
|
||||
|
||||
They SHOULD NOT be used to determine the position of events
|
||||
whose location is canonically defined in Temporal::Beats.
|
||||
*/
|
||||
|
||||
double beat_at_sample (const samplecnt_t sample) const;
|
||||
samplepos_t sample_at_beat (const double& beat) const;
|
||||
|
||||
const Meter& meter_at_sample (samplepos_t) const;
|
||||
|
||||
/* bbt - it's nearly always better to use meter-based beat (above)
|
||||
unless tick resolution is desirable.
|
||||
*/
|
||||
Temporal::BBT_Time bbt_at_sample (samplepos_t when);
|
||||
Temporal::BBT_Time bbt_at_sample_rt (samplepos_t when) const;
|
||||
samplepos_t sample_at_bbt (const Temporal::BBT_Time&);
|
||||
|
||||
double beat_at_bbt (const Temporal::BBT_Time& bbt);
|
||||
Temporal::BBT_Time bbt_at_beat (const double& beats);
|
||||
|
||||
double quarter_note_at_bbt (const Temporal::BBT_Time& bbt);
|
||||
double quarter_note_at_bbt_rt (const Temporal::BBT_Time& bbt);
|
||||
Temporal::BBT_Time bbt_at_quarter_note (const double& quarter_note);
|
||||
|
||||
samplecnt_t bbt_duration_at (samplepos_t, const Temporal::BBT_Time&, int dir);
|
||||
samplepos_t samplepos_plus_bbt (samplepos_t pos, Temporal::BBT_Time b) const;
|
||||
|
||||
/* TEMPO-SENSITIVE FUNCTIONS
|
||||
|
||||
These next 2 functions will all take tempo in account and should be
|
||||
used to determine position (and in the last case, distance in beats)
|
||||
when tempo matters but meter does not.
|
||||
|
||||
They SHOULD be used to determine the position of events
|
||||
whose location is canonically defined in Temporal::Beats.
|
||||
*/
|
||||
|
||||
samplepos_t samplepos_plus_qn (samplepos_t, Temporal::Beats) const;
|
||||
Temporal::Beats framewalk_to_qn (samplepos_t pos, samplecnt_t distance) const;
|
||||
|
||||
/* quarter note related functions are also tempo-sensitive and ignore meter.
|
||||
quarter notes may be compared with and assigned to Temporal::Beats.
|
||||
*/
|
||||
double quarter_note_at_sample (const samplepos_t sample) const;
|
||||
double quarter_note_at_sample_rt (const samplepos_t sample) const;
|
||||
samplepos_t sample_at_quarter_note (const double quarter_note) const;
|
||||
|
||||
samplecnt_t samples_between_quarter_notes (const double start, const double end) const;
|
||||
double quarter_notes_between_samples (const samplecnt_t start, const samplecnt_t end) const;
|
||||
|
||||
double quarter_note_at_beat (const double beat) const;
|
||||
double beat_at_quarter_note (const double beat) const;
|
||||
|
||||
/* obtain a musical subdivision via a sample position and magic note divisor.*/
|
||||
double exact_qn_at_sample (const samplepos_t sample, const int32_t sub_num) const;
|
||||
double exact_beat_at_sample (const samplepos_t sample, const int32_t sub_num) const;
|
||||
|
||||
Tempo tempo_at_sample (const samplepos_t sample) const;
|
||||
samplepos_t sample_at_tempo (const Tempo& tempo) const;
|
||||
Tempo tempo_at_quarter_note (const double& beat) const;
|
||||
double quarter_note_at_tempo (const Tempo& tempo) const;
|
||||
|
||||
void gui_set_tempo_position (TempoSection*, const samplepos_t sample, const int& sub_num);
|
||||
void gui_set_meter_position (MeterSection*, const samplepos_t sample);
|
||||
bool gui_change_tempo (TempoSection*, const Tempo& bpm);
|
||||
void gui_stretch_tempo (TempoSection* tempo, const samplepos_t sample, const samplepos_t end_sample, const double start_qnote, const double end_qnote);
|
||||
void gui_stretch_tempo_end (TempoSection* tempo, const samplepos_t sample, const samplepos_t end_sample);
|
||||
bool gui_twist_tempi (TempoSection* first, const Tempo& bpm, const samplepos_t sample, const samplepos_t end_sample);
|
||||
|
||||
std::pair<double, samplepos_t> predict_tempo_position (TempoSection* section, const Temporal::BBT_Time& bbt);
|
||||
bool can_solve_bbt (TempoSection* section, const Temporal::BBT_Time& bbt);
|
||||
|
||||
PBD::Signal1<void,const PBD::PropertyChange&> MetricPositionChanged;
|
||||
void fix_legacy_session();
|
||||
void fix_legacy_end_session();
|
||||
|
||||
samplepos_t music_origin ();
|
||||
|
||||
private:
|
||||
/* prevent copy construction */
|
||||
TempoMap (TempoMap const&);
|
||||
|
||||
TempoSection* previous_tempo_section_locked (const Metrics& metrics, TempoSection*) const;
|
||||
TempoSection* next_tempo_section_locked (const Metrics& metrics, TempoSection*) const;
|
||||
|
||||
double beat_at_minute_locked (const Metrics& metrics, const double& minute) const;
|
||||
double minute_at_beat_locked (const Metrics& metrics, const double& beat) const;
|
||||
|
||||
double pulse_at_beat_locked (const Metrics& metrics, const double& beat) const;
|
||||
double beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const;
|
||||
|
||||
double pulse_at_minute_locked (const Metrics& metrics, const double& minute) const;
|
||||
double minute_at_pulse_locked (const Metrics& metrics, const double& pulse) const;
|
||||
|
||||
Tempo tempo_at_minute_locked (const Metrics& metrics, const double& minute) const;
|
||||
double minute_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const;
|
||||
|
||||
Tempo tempo_at_pulse_locked (const Metrics& metrics, const double& pulse) const;
|
||||
double pulse_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const;
|
||||
|
||||
Temporal::BBT_Time bbt_at_minute_locked (const Metrics& metrics, const double& minute) const;
|
||||
double minute_at_bbt_locked (const Metrics& metrics, const Temporal::BBT_Time&) const;
|
||||
|
||||
double beat_at_bbt_locked (const Metrics& metrics, const Temporal::BBT_Time& bbt) const ;
|
||||
Temporal::BBT_Time bbt_at_beat_locked (const Metrics& metrics, const double& beats) const;
|
||||
|
||||
double pulse_at_bbt_locked (const Metrics& metrics, const Temporal::BBT_Time& bbt) const;
|
||||
Temporal::BBT_Time bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const;
|
||||
|
||||
double minutes_between_quarter_notes_locked (const Metrics& metrics, const double start_qn, const double end_qn) const;
|
||||
double quarter_notes_between_samples_locked (const Metrics& metrics, const samplecnt_t start, const samplecnt_t end) const;
|
||||
|
||||
const TempoSection& tempo_section_at_minute_locked (const Metrics& metrics, double minute) const;
|
||||
TempoSection& tempo_section_at_minute_locked (const Metrics& metrics, double minute);
|
||||
const TempoSection& tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const;
|
||||
|
||||
const MeterSection& meter_section_at_minute_locked (const Metrics& metrics, double minute) const;
|
||||
const MeterSection& meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const;
|
||||
|
||||
bool check_solved (const Metrics& metrics) const;
|
||||
bool set_active_tempi (const Metrics& metrics, const samplepos_t sample);
|
||||
|
||||
bool solve_map_minute (Metrics& metrics, TempoSection* section, const double& minute);
|
||||
bool solve_map_pulse (Metrics& metrics, TempoSection* section, const double& pulse);
|
||||
bool solve_map_minute (Metrics& metrics, MeterSection* section, const double& minute);
|
||||
bool solve_map_bbt (Metrics& metrics, MeterSection* section, const Temporal::BBT_Time& bbt);
|
||||
|
||||
double exact_beat_at_sample_locked (const Metrics& metrics, const samplepos_t sample, const int32_t sub_num) const;
|
||||
double exact_qn_at_sample_locked (const Metrics& metrics, const samplepos_t sample, const int32_t sub_num) const;
|
||||
|
||||
double minute_at_sample (const samplepos_t sample) const;
|
||||
samplepos_t sample_at_minute (const double minute) const;
|
||||
|
||||
friend class ::BBTTest;
|
||||
friend class ::FrameposPlusBeatsTest;
|
||||
friend class ::FrameposMinusBeatsTest;
|
||||
friend class ::TempoTest;
|
||||
|
||||
static Tempo _default_tempo;
|
||||
static Meter _default_meter;
|
||||
|
||||
Metrics _metrics;
|
||||
samplecnt_t _sample_rate;
|
||||
mutable Glib::Threads::RWLock lock;
|
||||
|
||||
void recompute_tempi (Metrics& metrics);
|
||||
void recompute_meters (Metrics& metrics);
|
||||
void recompute_map (Metrics& metrics, samplepos_t end = -1);
|
||||
|
||||
MusicSample round_to_type (samplepos_t fr, Temporal::RoundMode dir, BBTPointType);
|
||||
|
||||
const MeterSection& first_meter() const;
|
||||
MeterSection& first_meter();
|
||||
const TempoSection& first_tempo() const;
|
||||
TempoSection& first_tempo();
|
||||
|
||||
void do_insert (MetricSection* section);
|
||||
|
||||
TempoSection* add_tempo_locked (const Tempo&, double pulse, double minute
|
||||
, PositionLockStyle pls, bool recompute, bool locked_to_meter = false, bool clamped = false);
|
||||
|
||||
MeterSection* add_meter_locked (const Meter&, const Temporal::BBT_Time& where, samplepos_t sample, PositionLockStyle pls, bool recompute);
|
||||
|
||||
bool remove_tempo_locked (const TempoSection&);
|
||||
bool remove_meter_locked (const MeterSection&);
|
||||
|
||||
TempoSection* copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section) const;
|
||||
MeterSection* copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section) const;
|
||||
};
|
||||
|
||||
}; /* namespace ARDOUR */
|
||||
|
||||
LIBARDOUR_API std::ostream& operator<< (std::ostream&, const ARDOUR::Meter&);
|
||||
LIBARDOUR_API std::ostream& operator<< (std::ostream&, const ARDOUR::Tempo&);
|
||||
LIBARDOUR_API std::ostream& operator<< (std::ostream&, const ARDOUR::MetricSection&);
|
||||
|
||||
namespace PBD {
|
||||
DEFINE_ENUM_CONVERT (ARDOUR::TempoSection::Type)
|
||||
}
|
||||
#include "temporal/tempo.h"
|
||||
|
||||
#endif /* __ardour_tempo_h__ */
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@
|
|||
|
||||
namespace ARDOUR {
|
||||
|
||||
class TempoMap;
|
||||
class Session;
|
||||
class AudioEngine;
|
||||
class Location;
|
||||
|
|
|
|||
|
|
@ -115,8 +115,6 @@ setup_enum_writer ()
|
|||
Source::Flag _Source_Flag;
|
||||
DiskIOProcessor::Flag _DiskIOProcessor_Flag;
|
||||
Location::Flags _Location_Flags;
|
||||
PositionLockStyle _PositionLockStyle;
|
||||
TempoSection::Type _TempoSection_Type;
|
||||
Track::FreezeState _Track_FreezeState;
|
||||
AutomationList::InterpolationStyle _AutomationList_InterpolationStyle;
|
||||
AnyTime::Type _AnyTime_Type;
|
||||
|
|
@ -568,10 +566,6 @@ setup_enum_writer ()
|
|||
REGISTER_CLASS_ENUM (Location, IsClockOrigin);
|
||||
REGISTER_BITS (_Location_Flags);
|
||||
|
||||
REGISTER_CLASS_ENUM (TempoSection, Ramp);
|
||||
REGISTER_CLASS_ENUM (TempoSection, Constant);
|
||||
REGISTER (_TempoSection_Type);
|
||||
|
||||
REGISTER_CLASS_ENUM (Track, NoFreeze);
|
||||
REGISTER_CLASS_ENUM (Track, Frozen);
|
||||
REGISTER_CLASS_ENUM (Track, UnFrozen);
|
||||
|
|
@ -736,10 +730,6 @@ setup_enum_writer ()
|
|||
REGISTER_ENUM(InhibitAlways);
|
||||
REGISTER(_ScreenSaverMode);
|
||||
|
||||
REGISTER_ENUM(AudioTime);
|
||||
REGISTER_ENUM(MusicTime);
|
||||
REGISTER(_PositionLockStyle);
|
||||
|
||||
REGISTER_ENUM (Small);
|
||||
REGISTER_ENUM (Medium);
|
||||
REGISTER_ENUM (Large);
|
||||
|
|
|
|||
|
|
@ -354,6 +354,7 @@ CLASSKEYS(LuaDialog::ProgressWindow);
|
|||
*/
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace Temporal;
|
||||
|
||||
/** Access libardour global configuration */
|
||||
static RCConfiguration* _libardour_config () {
|
||||
|
|
@ -1866,63 +1867,35 @@ LuaBindings::common (lua_State* L)
|
|||
|
||||
.beginClass <Tempo> ("Tempo")
|
||||
.addConstructor <void (*) (double, double, double)> ()
|
||||
.addFunction ("note_type", &Tempo::note_type)
|
||||
.addFunction ("note_types_per_minute", (double (Tempo::*)() const)&Tempo::note_types_per_minute)
|
||||
.addFunction ("end_note_types_per_minute", (double (Tempo::*)() const)&Tempo::end_note_types_per_minute)
|
||||
.addFunction ("quarter_notes_per_minute", &Tempo::quarter_notes_per_minute)
|
||||
.addFunction ("samples_per_quarter_note", &Tempo::samples_per_quarter_note)
|
||||
.addFunction ("samples_per_note_type", &Tempo::samples_per_note_type)
|
||||
.addFunction ("note_type", &Temporal::Tempo::note_type)
|
||||
.addFunction ("note_types_per_minute", (double (Temporal::Tempo::*)() const)&Temporal::Tempo::note_types_per_minute)
|
||||
.addFunction ("quarter_notes_per_minute", &Temporal::Tempo::quarter_notes_per_minute)
|
||||
.addFunction ("samples_per_quarter_note", &Temporal::Tempo::samples_per_quarter_note)
|
||||
.addFunction ("samples_per_note_type", &Temporal::Tempo::samples_per_note_type)
|
||||
.endClass ()
|
||||
|
||||
.beginClass <Meter> ("Meter")
|
||||
.addConstructor <void (*) (double, double)> ()
|
||||
.addFunction ("divisions_per_bar", &Meter::divisions_per_bar)
|
||||
.addFunction ("note_divisor", &Meter::note_divisor)
|
||||
.addFunction ("samples_per_bar", &Meter::samples_per_bar)
|
||||
.addFunction ("samples_per_grid", &Meter::samples_per_grid)
|
||||
.addFunction ("note_value", &Meter::note_value)
|
||||
.endClass ()
|
||||
|
||||
#warning NUTEMPO need to consider which methods to use here since ::add_* are private right now and many others have changed
|
||||
#if 0
|
||||
.beginClass <TempoMap> ("TempoMap")
|
||||
.addFunction ("add_tempo", &TempoMap::add_tempo)
|
||||
.addFunction ("add_meter", &TempoMap::add_meter)
|
||||
.addFunction ("tempo_section_at_sample", (TempoSection& (TempoMap::*)(samplepos_t))&TempoMap::tempo_section_at_sample)
|
||||
.addFunction ("meter_section_at_sample", &TempoMap::meter_section_at_sample)
|
||||
.addFunction ("tempo_section_at_frame", (TempoSection& (TempoMap::*)(samplepos_t))&TempoMap::tempo_section_at_sample)
|
||||
.addFunction ("tempo_section_at_frame", (const TempoSection& (TempoMap::*)(samplepos_t) const)&TempoMap::tempo_section_at_sample)
|
||||
.addFunction ("meter_section_at_frame", &TempoMap::meter_section_at_sample)
|
||||
.addFunction ("meter_section_at_beat", &TempoMap::meter_section_at_beat)
|
||||
.addFunction ("bbt_at_sample", &TempoMap::bbt_at_sample)
|
||||
.addFunction ("exact_beat_at_sample", &TempoMap::exact_beat_at_sample)
|
||||
.addFunction ("exact_qn_at_sample", &TempoMap::exact_qn_at_sample)
|
||||
.addFunction ("bbt_at_frame", &TempoMap::bbt_at_sample)
|
||||
.addFunction ("exact_beat_at_frame", &TempoMap::exact_beat_at_sample)
|
||||
.addFunction ("exact_qn_at_frame", &TempoMap::exact_qn_at_sample)
|
||||
.addFunction ("samplepos_plus_qn", &TempoMap::samplepos_plus_qn)
|
||||
.addFunction ("framewalk_to_qn", &TempoMap::framewalk_to_qn)
|
||||
.addFunction ("previous_tempo_section", &TempoMap::previous_tempo_section)
|
||||
.addFunction ("next_tempo_section", &TempoMap::next_tempo_section)
|
||||
.endClass ()
|
||||
|
||||
.beginClass <MetricSection> ("MetricSection")
|
||||
.addFunction ("pulse", &MetricSection::pulse)
|
||||
.addFunction ("set_pulse", &MetricSection::set_pulse)
|
||||
.addFunction ("sample", &MetricSection::sample)
|
||||
.addFunction ("minute", &MetricSection::minute)
|
||||
.addFunction ("initial", &MetricSection::initial)
|
||||
.addFunction ("is_tempo", &MetricSection::is_tempo)
|
||||
.addFunction ("sample_at_minute", &MetricSection::sample_at_minute)
|
||||
.addFunction ("minute_at_sample", &MetricSection::minute_at_sample)
|
||||
.endClass ()
|
||||
|
||||
.deriveClass <TempoSection, MetricSection> ("TempoSection")
|
||||
.addCast<Tempo> ("to_tempo")
|
||||
.addFunction ("c", (double(TempoSection::*)()const)&TempoSection::c)
|
||||
.addFunction ("active", &TempoSection::active)
|
||||
.addFunction ("locked_to_meter", &TempoSection::locked_to_meter)
|
||||
.addFunction ("clamped", &TempoSection::clamped)
|
||||
.endClass ()
|
||||
|
||||
.deriveClass <MeterSection, MetricSection> ("MeterSection")
|
||||
.addCast<Meter> ("to_meter")
|
||||
.addFunction ("bbt", &MeterSection::bbt)
|
||||
.addFunction ("beat", &MeterSection::beat)
|
||||
.addFunction ("set_beat", (void(MeterSection::*)(double))&MeterSection::set_beat)
|
||||
.endClass ()
|
||||
|
||||
#endif
|
||||
.beginClass <ChanCount> ("ChanCount")
|
||||
.addConstructor <void (*) (DataType, uint32_t)> ()
|
||||
.addFunction ("get", &ChanCount::get)
|
||||
|
|
@ -2099,19 +2072,25 @@ LuaBindings::common (lua_State* L)
|
|||
.addConst ("SyncPoint", ARDOUR::RegionPoint(SyncPoint))
|
||||
.endNamespace ()
|
||||
|
||||
#warning NUTEMPO add timeline types here instead
|
||||
#if 0
|
||||
.beginNamespace ("TempoSection")
|
||||
.beginNamespace ("PositionLockStyle")
|
||||
.addConst ("AudioTime", ARDOUR::PositionLockStyle(AudioTime))
|
||||
.addConst ("MusicTime", ARDOUR::PositionLockStyle(MusicTime))
|
||||
.endNamespace ()
|
||||
.endNamespace ()
|
||||
#endif
|
||||
|
||||
#warning NUTEMPO fix types here
|
||||
#if 0
|
||||
.beginNamespace ("TempoSection")
|
||||
.beginNamespace ("Type")
|
||||
.addConst ("Ramp", ARDOUR::TempoSection::Type(TempoSection::Ramp))
|
||||
.addConst ("Constant", ARDOUR::TempoSection::Type(TempoSection::Constant))
|
||||
.endNamespace ()
|
||||
.endNamespace ()
|
||||
#endif
|
||||
|
||||
.beginNamespace ("TrackMode")
|
||||
.addConst ("Normal", ARDOUR::TrackMode(Start))
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ static const size_t NBUFS = 4;
|
|||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace Temporal;
|
||||
|
||||
bool LV2Plugin::force_state_save = false;
|
||||
int32_t LV2Plugin::_ui_style_flat = 0;
|
||||
|
|
@ -2573,7 +2574,7 @@ static bool
|
|||
write_position(LV2_Atom_Forge* forge,
|
||||
LV2_Evbuf* buf,
|
||||
const TempoMetric& t,
|
||||
Temporal::BBT_Time& bbt,
|
||||
BBT_Time& bbt,
|
||||
double speed,
|
||||
double time_scale,
|
||||
double bpm,
|
||||
|
|
@ -2596,7 +2597,7 @@ write_position(LV2_Atom_Forge* forge,
|
|||
lv2_atom_forge_key(forge, urids.time_bar);
|
||||
lv2_atom_forge_long(forge, bbt.bars - 1);
|
||||
lv2_atom_forge_key(forge, urids.time_beatUnit);
|
||||
lv2_atom_forge_int(forge, t.meter().note_divisor());
|
||||
lv2_atom_forge_int(forge, t.meter().note_value());
|
||||
lv2_atom_forge_key(forge, urids.time_beatsPerBar);
|
||||
lv2_atom_forge_float(forge, t.meter().divisions_per_bar());
|
||||
lv2_atom_forge_key(forge, urids.time_beatsPerMinute);
|
||||
|
|
@ -2653,7 +2654,15 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||
}
|
||||
|
||||
if (_bpm_control_port) {
|
||||
|
||||
float bpm = tmap.tempo_at_sample (start0).note_types_per_minute();
|
||||
TempoMapPoints tempo_map_points;
|
||||
tmap.get_grid (tempo_map_points, start, end, 0);
|
||||
TempoMapPoint first_tempo_map_point = tempo_map_points.front();
|
||||
|
||||
/* note that this is not necessarily quarter notes */
|
||||
const double bpm = first_tempo_map_point.tempo().note_types_per_minute();
|
||||
|
||||
if (*_bpm_control_port != bpm) {
|
||||
AutomationCtrlPtr c = get_automation_control (_bpm_control_port_index);
|
||||
if (c && c->ac) {
|
||||
|
|
@ -2661,6 +2670,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||
c->ac->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
|
||||
}
|
||||
}
|
||||
|
||||
*_bpm_control_port = bpm;
|
||||
}
|
||||
|
||||
|
|
@ -2735,14 +2745,14 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||
|
||||
if (valid && (flags & PORT_INPUT)) {
|
||||
if ((flags & PORT_POSITION)) {
|
||||
|
||||
Temporal::BBT_Time bbt (tmap.bbt_at_sample (start0));
|
||||
const Temporal::TempoMetric& metric (tmap.metric_at (start0));
|
||||
Temporal::BBT_Time bbt (metric.bbt_at (start0));
|
||||
double time_scale = Port::speed_ratio ();
|
||||
double bpm = tmap.tempo_at_sample (start0).note_types_per_minute();
|
||||
double beatpos = (bbt.bars - 1) * tmetric.meter().divisions_per_bar()
|
||||
double bpm = metric.tempo().note_types_per_minute();
|
||||
double beatpos = (bbt.bars - 1) * metric.meter().divisions_per_bar()
|
||||
+ (bbt.beats - 1)
|
||||
+ (bbt.ticks / Temporal::ticks_per_beat);
|
||||
beatpos *= tmetric.meter().note_divisor() / 4.0;
|
||||
beatpos *= metric.note_value() / 4.0;
|
||||
if (start != _next_cycle_start ||
|
||||
speed != _next_cycle_speed ||
|
||||
time_scale != _prev_time_scale ||
|
||||
|
|
@ -2750,7 +2760,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||
bpm != _current_bpm) {
|
||||
// Transport or Tempo has changed, write position at cycle start
|
||||
write_position(&_impl->forge, _ev_buffers[port_index],
|
||||
tmetric, bbt, speed, time_scale, bpm, start, 0);
|
||||
metric, bbt, speed, time_scale, bpm, start, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2766,10 +2776,11 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||
const uint32_t type = _uri_map.urids.midi_MidiEvent;
|
||||
const samplepos_t tend = end;
|
||||
++metric_i;
|
||||
while (m != m_end || (metric_i != tmap.metrics_end() &&
|
||||
(*metric_i)->sample() < tend)) {
|
||||
MetricSection* metric = (metric_i != tmap.metrics_end())
|
||||
? *metric_i : NULL;
|
||||
|
||||
while (m != m_end || (metric_i != tmap.metrics_end() && (*metric_i)->sample() < tend)) {
|
||||
|
||||
MetricSection* metric = (metric_i != tmap.metrics_end()) ? *metric_i : NULL;
|
||||
|
||||
if (m != m_end && (!metric || metric->sample() > (*m).time())) {
|
||||
const Evoral::Event<samplepos_t> ev(*m, false);
|
||||
if (ev.time() < nframes) {
|
||||
|
|
@ -2779,12 +2790,11 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||
++m;
|
||||
} else {
|
||||
assert (metric);
|
||||
tmetric.set_metric(metric);
|
||||
Temporal::BBT_Time bbt;
|
||||
bbt = tmap.bbt_at_sample (metric->sample());
|
||||
double bpm = tmap.tempo_at_sample (start0 /*XXX metric->sample() */).note_types_per_minute();
|
||||
bbt = metric.bbt();
|
||||
double bpm = metric.tempo().note_types_per_minute();
|
||||
|
||||
write_position(&_impl->forge, _ev_buffers[port_index],
|
||||
tmetric, bbt, speed, Port::speed_ratio (),
|
||||
metric, bbt, speed, Port::speed_ratio (),
|
||||
bpm, metric->sample(),
|
||||
metric->sample() - start0);
|
||||
++metric_i;
|
||||
|
|
|
|||
|
|
@ -157,7 +157,8 @@ MIDIClock_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now
|
|||
void
|
||||
MIDIClock_TransportMaster::calculate_one_ppqn_in_samples_at(samplepos_t time)
|
||||
{
|
||||
const double samples_per_quarter_note = _session->tempo_map().samples_per_quarter_note_at (time, ENGINE->sample_rate());
|
||||
const Temporal::TempoMetric& metric = _session->tempo_map().metric_at (time);
|
||||
const double samples_per_quarter_note = metric.tempo().samples_per_quarter_note (ENGINE->sample_rate());
|
||||
|
||||
one_ppqn_in_samples = samples_per_quarter_note / double (ppqn);
|
||||
// DEBUG_TRACE (DEBUG::MidiClock, string_compose ("at %1, one ppqn = %2 [spl] spqn = %3, ppqn = %4\n", time, one_ppqn_in_samples, samples_per_quarter_note, ppqn));
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ class Speakers;
|
|||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace Temporal;
|
||||
|
||||
bool Session::_disable_all_loaded_plugins = false;
|
||||
bool Session::_bypass_all_loaded_plugins = false;
|
||||
|
|
@ -2194,9 +2195,8 @@ Session::preroll_samples (samplepos_t pos) const
|
|||
{
|
||||
const float pr = Config->get_preroll_seconds();
|
||||
if (pos >= 0 && pr < 0) {
|
||||
const Tempo& tempo = _tempo_map->tempo_at_sample (pos);
|
||||
const Meter& meter = _tempo_map->meter_at_sample (pos);
|
||||
return meter.samples_per_bar (tempo, sample_rate()) * -pr;
|
||||
Temporal::TempoMetric const & metric (_tempo_map->metric_at (pos));
|
||||
return metric.samples_per_bar (sample_rate()) * -pr;
|
||||
}
|
||||
if (pr < 0) {
|
||||
return 0;
|
||||
|
|
@ -5545,7 +5545,7 @@ Session::available_capture_duration ()
|
|||
}
|
||||
|
||||
void
|
||||
Session::tempo_map_changed (const PropertyChange&)
|
||||
Session::tempo_map_changed ()
|
||||
{
|
||||
clear_clicks ();
|
||||
|
||||
|
|
@ -7428,10 +7428,9 @@ void
|
|||
Session::maybe_update_tempo_from_midiclock_tempo (float bpm)
|
||||
{
|
||||
if (_tempo_map->n_tempos() == 1) {
|
||||
TempoSection& ts (_tempo_map->tempo_section_at_sample (0));
|
||||
if (fabs (ts.note_types_per_minute() - bpm) > (0.01 * ts.note_types_per_minute())) {
|
||||
const Tempo tempo (bpm, 4.0, bpm);
|
||||
_tempo_map->replace_tempo (ts, tempo, 0.0, 0.0, AudioTime);
|
||||
Temporal::TempoMetric const & metric (_tempo_map->metric_at (0));
|
||||
if (fabs (metric.tempo().note_types_per_minute() - bpm) > (0.01 * metric.tempo().note_types_per_minute())) {
|
||||
_tempo_map->change_tempo (metric.tempo(), Tempo (bpm, 4.0, bpm));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace Temporal;
|
||||
|
||||
Pool Click::pool ("click", sizeof (Click), 1024);
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ Pool Click::pool ("click", sizeof (Click), 1024);
|
|||
* (session.h does not include tempo.h so making this
|
||||
* a Session member variable is tricky.)
|
||||
*/
|
||||
static vector<TempoMap::BBTPoint> _click_points;
|
||||
static TempoMapPoints _click_points;
|
||||
|
||||
void
|
||||
Session::add_click (samplepos_t pos, bool emphasis)
|
||||
|
|
@ -123,7 +124,7 @@ Session::click (samplepos_t cycle_start, samplecnt_t nframes)
|
|||
const samplepos_t end = start + move;
|
||||
|
||||
_click_points.clear ();
|
||||
_tempo_map->get_grid (_click_points, start, end);
|
||||
_tempo_map->get_grid (_click_points, samples_to_superclock (start, sample_rate()), samples_to_superclock (end, sample_rate()));
|
||||
|
||||
if (distance (_click_points.begin(), _click_points.end()) == 0) {
|
||||
start += move;
|
||||
|
|
@ -131,17 +132,14 @@ Session::click (samplepos_t cycle_start, samplecnt_t nframes)
|
|||
continue;
|
||||
}
|
||||
|
||||
for (vector<TempoMap::BBTPoint>::iterator i = _click_points.begin(); i != _click_points.end(); ++i) {
|
||||
assert ((*i).sample >= start && (*i).sample < end);
|
||||
switch ((*i).beat) {
|
||||
case 1:
|
||||
add_click ((*i).sample, true);
|
||||
break;
|
||||
default:
|
||||
if (click_emphasis_data == 0 || (Config->get_use_click_emphasis () == false) || (click_emphasis_data && (*i).beat != 1)) { // XXX why is this check needed ?? (*i).beat !=1 must be true here
|
||||
add_click ((*i).sample, false);
|
||||
}
|
||||
break;
|
||||
for (TempoMapPoints::iterator i = _click_points.begin(); i != _click_points.end(); ++i) {
|
||||
|
||||
assert (superclock_to_samples ((*i).sclock(), sample_rate()) >= start && superclock_to_samples ((*i).sclock(), sample_rate()) < end);
|
||||
|
||||
if (i->bbt().is_bar() && (click_emphasis_data && Config->get_use_click_emphasis())) {
|
||||
add_click ((*i).sclock(), true);
|
||||
} else {
|
||||
add_click ((*i).sclock(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +311,6 @@ Session::setup_click_sounds (Sample** data, Sample const * default_data, samplec
|
|||
void
|
||||
Session::setup_click_sounds (int which)
|
||||
{
|
||||
_click_points.reserve (8);
|
||||
clear_clicks ();
|
||||
|
||||
if (which == 0 || which == 1) {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class Command;
|
|||
|
||||
using namespace PBD;
|
||||
using namespace ARDOUR;
|
||||
using namespace Temporal;
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -263,9 +263,8 @@ Session::post_engine_init ()
|
|||
/* tempo map requires sample rate knowledge */
|
||||
|
||||
delete _tempo_map;
|
||||
_tempo_map = new TempoMap (_current_sample_rate);
|
||||
_tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
|
||||
_tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
|
||||
_tempo_map = new Temporal::TempoMap (Temporal::Tempo (120), Temporal::Meter (4, 4), _current_sample_rate);
|
||||
_tempo_map->Changed.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this));
|
||||
} catch (std::exception const & e) {
|
||||
error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
|
||||
return -2;
|
||||
|
|
|
|||
|
|
@ -47,9 +47,9 @@ using namespace PBD;
|
|||
/* BBT TIME*/
|
||||
|
||||
void
|
||||
Session::bbt_time (samplepos_t when, Temporal::BBT_Time& bbt)
|
||||
Session::bbt_time (timepos_t const & when, Temporal::BBT_Time& bbt)
|
||||
{
|
||||
bbt = _tempo_map->bbt_at_sample (when);
|
||||
bbt = _tempo_map->bbt_at (when);
|
||||
}
|
||||
|
||||
/* Timecode TIME */
|
||||
|
|
@ -241,7 +241,7 @@ Session::convert_to_samples (AnyTime const & position)
|
|||
|
||||
switch (position.type) {
|
||||
case AnyTime::BBT:
|
||||
return _tempo_map->sample_at_bbt (position.bbt);
|
||||
return Temporal::superclock_to_samples (_tempo_map->superclock_at (position.bbt), _current_sample_rate);
|
||||
break;
|
||||
|
||||
case AnyTime::Timecode:
|
||||
|
|
@ -272,11 +272,12 @@ Session::convert_to_samples (AnyTime const & position)
|
|||
ARDOUR::samplecnt_t
|
||||
Session::any_duration_to_samples (samplepos_t position, AnyTime const & duration)
|
||||
{
|
||||
#warning NUTEMPO THIS NEEDS A COMPLETE REVISION TO USE IMPLICIT CONVERSIONS ETC.
|
||||
double secs;
|
||||
|
||||
switch (duration.type) {
|
||||
case AnyTime::BBT:
|
||||
return (samplecnt_t) ( _tempo_map->samplepos_plus_bbt (position, duration.bbt) - position);
|
||||
return Temporal::superclock_to_samples (_tempo_map->superclock_plus_bbt (Temporal::samples_to_superclock (position, _current_sample_rate), duration.bbt), _current_sample_rate) - position;
|
||||
break;
|
||||
|
||||
case AnyTime::Timecode:
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@
|
|||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
using namespace Temporal;
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define ENSURE_PROCESS_THREAD do {} while (0)
|
||||
|
|
@ -527,15 +527,14 @@ Session::start_transport (bool after_loop)
|
|||
* - use [fixed] tempo/meter at _transport_sample
|
||||
* - calc duration of 1 bar + time-to-beat before or at transport_sample
|
||||
*/
|
||||
const Tempo& tempo = _tempo_map->tempo_at_sample (_transport_sample);
|
||||
const Meter& meter = _tempo_map->meter_at_sample (_transport_sample);
|
||||
TempoMetric const & tempometric = _tempo_map->metric_at (_transport_sample);
|
||||
|
||||
const double num = meter.divisions_per_bar ();
|
||||
const double den = meter.note_divisor ();
|
||||
const double barbeat = _tempo_map->exact_qn_at_sample (_transport_sample, 0) * den / (4. * num);
|
||||
const double bar_fract = fmod (barbeat, 1.0); // fraction of bar elapsed.
|
||||
const double num = tempometric.divisions_per_bar ();
|
||||
/* XXX possible optimization: get meter and BBT time in one call */
|
||||
const Temporal::BBT_Time bbt = _tempo_map->bbt_at (_transport_sample);
|
||||
const double bar_fract = (double) bbt.beats / tempometric.divisions_per_bar();
|
||||
|
||||
_count_in_samples = meter.samples_per_bar (tempo, _current_sample_rate);
|
||||
_count_in_samples = tempometric.samples_per_bar (_current_sample_rate);
|
||||
|
||||
double dt = _count_in_samples / num;
|
||||
if (bar_fract == 0) {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "pbd/i18n.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace Temporal;
|
||||
|
||||
#define SHOW_CALLBACK(MSG) DEBUG_TRACE (PBD::DEBUG::VSTCallbacks, string_compose (MSG " val = %1 idx = %2\n", index, value))
|
||||
|
||||
|
|
@ -187,27 +188,27 @@ intptr_t Session::vst_callback (
|
|||
timeinfo->sampleRate = session->sample_rate();
|
||||
|
||||
if (value & (kVstTempoValid)) {
|
||||
const Tempo& t (session->tempo_map().tempo_at_sample (now));
|
||||
const Tempo& t (session->tempo_map().metric_at (now).tempo());
|
||||
timeinfo->tempo = t.quarter_notes_per_minute ();
|
||||
newflags |= (kVstTempoValid);
|
||||
}
|
||||
if (value & (kVstTimeSigValid)) {
|
||||
const MeterSection& ms (session->tempo_map().meter_section_at_sample (now));
|
||||
const Meter& ms (session->tempo_map().metric_at (now).meter());
|
||||
timeinfo->timeSigNumerator = ms.divisions_per_bar ();
|
||||
timeinfo->timeSigDenominator = ms.note_divisor ();
|
||||
timeinfo->timeSigDenominator = ms.note_value ();
|
||||
newflags |= (kVstTimeSigValid);
|
||||
}
|
||||
if ((value & (kVstPpqPosValid)) || (value & (kVstBarsValid))) {
|
||||
Temporal::BBT_Time bbt;
|
||||
|
||||
try {
|
||||
bbt = session->tempo_map().bbt_at_sample_rt (now);
|
||||
bbt = session->tempo_map().bbt_at (now);
|
||||
bbt.beats = 1;
|
||||
bbt.ticks = 0;
|
||||
/* exact quarter note */
|
||||
double ppqBar = session->tempo_map().quarter_note_at_bbt_rt (bbt);
|
||||
double ppqBar = session->tempo_map().quarter_note_at (bbt);
|
||||
/* quarter note at sample position (not rounded to note subdivision) */
|
||||
double ppqPos = session->tempo_map().quarter_note_at_sample_rt (now);
|
||||
double ppqPos = session->tempo_map().quarter_note_at (now);
|
||||
if (value & (kVstPpqPosValid)) {
|
||||
timeinfo->ppqPos = ppqPos;
|
||||
newflags |= kVstPpqPosValid;
|
||||
|
|
@ -313,7 +314,7 @@ intptr_t Session::vst_callback (
|
|||
SHOW_CALLBACK ("audioMasterTempoAt");
|
||||
// returns tempo (in bpm * 10000) at sample sample location passed in <value>
|
||||
if (session) {
|
||||
const Tempo& t (session->tempo_map().tempo_at_sample (value));
|
||||
const Tempo& t (session->tempo_map().metric_at (value).tempo());
|
||||
return t.quarter_notes_per_minute() * 1000;
|
||||
} else {
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace Temporal;
|
||||
|
||||
MidiClockTicker::MidiClockTicker (Session* s)
|
||||
{
|
||||
|
|
@ -166,7 +167,8 @@ MidiClockTicker::tick (samplepos_t start_sample, samplepos_t end_sample, pframes
|
|||
uint32_t beat_pos;
|
||||
samplepos_t clk_pos;
|
||||
|
||||
_session->tempo_map ().midi_clock_beat_at_of_after (start_sample + _mclk_out_latency.max, clk_pos, beat_pos);
|
||||
#warning NUTEMPO need to reimplement this in TempoMap
|
||||
// _session->tempo_map ().midi_clock_beat_at_of_after (start_sample + _mclk_out_latency.max, clk_pos, beat_pos);
|
||||
|
||||
_beat_pos = beat_pos;
|
||||
_next_tick = clk_pos - _mclk_out_latency.max;
|
||||
|
|
@ -213,8 +215,8 @@ out:
|
|||
double
|
||||
MidiClockTicker::one_ppqn_in_samples (samplepos_t transport_position) const
|
||||
{
|
||||
const double samples_per_quarter_note = _session->tempo_map ().samples_per_quarter_note_at (transport_position, _session->nominal_sample_rate ());
|
||||
|
||||
Tempo const & tempo (_session->tempo_map().metric_at (transport_position).tempo());
|
||||
const double samples_per_quarter_note = tempo.samples_per_quarter_note (_session->nominal_sample_rate());
|
||||
return samples_per_quarter_note / 24.0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -441,7 +441,8 @@ def build(bld):
|
|||
#obj.add_objects = 'default/libs/surfaces/control_protocol/smpte_1.o'
|
||||
|
||||
if bld.is_defined('HAVE_LILV') :
|
||||
obj.source += ['lv2_plugin.cc', 'lv2_evbuf.c', 'uri_map.cc']
|
||||
# obj.source += ['lv2_plugin.cc', 'lv2_evbuf.c', 'uri_map.cc']
|
||||
obj.source += ['lv2_evbuf.c', 'uri_map.cc']
|
||||
obj.uselib += ['LILV']
|
||||
if bld.is_defined('HAVE_SUIL'):
|
||||
obj.uselib += ['SUIL']
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "jack_session.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace Temporal;
|
||||
using std::string;
|
||||
|
||||
JACKSession::JACKSession (Session* s)
|
||||
|
|
@ -128,14 +129,14 @@ JACKSession::timebase_callback (jack_transport_state_t /*state*/,
|
|||
TempoMetric metric (tempo_map.metric_at (tf));
|
||||
|
||||
try {
|
||||
bbt = tempo_map.bbt_at_sample_rt (tf);
|
||||
bbt = tempo_map.bbt_at (tf);
|
||||
|
||||
pos->bar = bbt.bars;
|
||||
pos->beat = bbt.beats;
|
||||
pos->tick = bbt.ticks;
|
||||
|
||||
pos->beats_per_bar = metric.meter().divisions_per_bar();
|
||||
pos->beat_type = metric.meter().note_divisor();
|
||||
pos->beat_type = metric.meter().note_value();
|
||||
pos->ticks_per_beat = Temporal::ticks_per_beat;
|
||||
pos->beats_per_minute = metric.tempo().note_types_per_minute();
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
#include "pbd/pthread_utils.h"
|
||||
#include "pbd/memento_command.h"
|
||||
|
||||
#include "temporal/tempo.h"
|
||||
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/location.h"
|
||||
#include "ardour/tempo.h"
|
||||
|
|
@ -37,6 +39,7 @@
|
|||
#include "pbd/i18n.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace Temporal;
|
||||
|
||||
PBD::Signal2<void,std::string,std::string> BasicUI::AccessAction;
|
||||
|
||||
|
|
@ -543,10 +546,10 @@ BasicUI::jump_by_seconds (double secs, LocateTransportDisposition ltd)
|
|||
}
|
||||
|
||||
void
|
||||
BasicUI::jump_by_bars (double bars, LocateTransportDisposition ltd)
|
||||
BasicUI::jump_by_bars (int bars, LocateTransportDisposition ltd)
|
||||
{
|
||||
TempoMap& tmap (session->tempo_map());
|
||||
Temporal::BBT_Time bbt (tmap.bbt_at_sample (session->transport_sample()));
|
||||
Temporal::BBT_Time bbt (tmap.bbt_at (session->transport_sample()));
|
||||
|
||||
bars += bbt.bars;
|
||||
if (bars < 0) {
|
||||
|
|
@ -561,14 +564,14 @@ BasicUI::jump_by_bars (double bars, LocateTransportDisposition ltd)
|
|||
}
|
||||
|
||||
void
|
||||
BasicUI::jump_by_beats (double beats, LocateTransportDisposition ltd)
|
||||
BasicUI::jump_by_beats (int beats, LocateTransportDisposition ltd)
|
||||
{
|
||||
TempoMap& tmap (session->tempo_map ());
|
||||
double qn_goal = tmap.quarter_note_at_sample (session->transport_sample ()) + beats;
|
||||
if (qn_goal < 0.0) {
|
||||
qn_goal = 0.0;
|
||||
Beats qn_goal = timepos_t (session->transport_sample ()).beats() + Beats (beats, 0);
|
||||
|
||||
if (qn_goal < Beats()) {
|
||||
qn_goal = Beats();
|
||||
}
|
||||
session->request_locate (tmap.sample_at_quarter_note (qn_goal), ltd);
|
||||
session->request_locate (timepos_t (qn_goal).samples());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -76,8 +76,8 @@ class LIBCONTROLCP_API BasicUI {
|
|||
double transport_rolling () const;
|
||||
|
||||
void jump_by_seconds (double sec, ARDOUR::LocateTransportDisposition ltd = ARDOUR::RollIfAppropriate);
|
||||
void jump_by_bars (double bars, ARDOUR::LocateTransportDisposition ltd = ARDOUR::RollIfAppropriate);
|
||||
void jump_by_beats (double beats, ARDOUR::LocateTransportDisposition ltd = ARDOUR::RollIfAppropriate);
|
||||
void jump_by_bars (int bars, ARDOUR::LocateTransportDisposition ltd = ARDOUR::RollIfAppropriate);
|
||||
void jump_by_beats (int beats, ARDOUR::LocateTransportDisposition ltd = ARDOUR::RollIfAppropriate);
|
||||
|
||||
ARDOUR::samplepos_t transport_sample ();
|
||||
void locate (ARDOUR::samplepos_t sample, ARDOUR::LocateTransportDisposition ltd);
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ FaderPort8::periodic ()
|
|||
_timecode = Timecode::timecode_format_time(TC);
|
||||
|
||||
char buf[16];
|
||||
Temporal::BBT_Time BBT = session->tempo_map ().bbt_at_sample (session->transport_sample ());
|
||||
Temporal::BBT_Time BBT = session->tempo_map ().bbt_at (session->transport_sample ());
|
||||
snprintf (buf, sizeof (buf),
|
||||
" %02" PRIu32 "|%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32,
|
||||
BBT.bars % 100, BBT.beats %100,
|
||||
|
|
|
|||
|
|
@ -1155,7 +1155,7 @@ MackieControlProtocol::format_bbt_timecode (samplepos_t now_sample)
|
|||
{
|
||||
Temporal::BBT_Time bbt_time;
|
||||
|
||||
session->bbt_time (now_sample, bbt_time);
|
||||
session->bbt_time (timepos_t (now_sample), bbt_time);
|
||||
|
||||
// The Mackie protocol spec is built around a BBT time display of
|
||||
//
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ OSCGlobalObserver::tick ()
|
|||
if (feedback[5]) { // Bar beat enabled
|
||||
Temporal::BBT_Time bbt_time;
|
||||
|
||||
session->bbt_time (now_sample, bbt_time);
|
||||
session->bbt_time (timepos_t (now_sample), bbt_time);
|
||||
|
||||
// semantics: BBB/bb/tttt
|
||||
ostringstream os;
|
||||
|
|
|
|||
|
|
@ -603,7 +603,7 @@ TrackMixLayout::update_clocks ()
|
|||
}
|
||||
|
||||
char buf[16];
|
||||
Temporal::BBT_Time BBT = session.tempo_map().bbt_at_sample (pos);
|
||||
Temporal::BBT_Time BBT = session.tempo_map().bbt_at (pos);
|
||||
|
||||
#define BBT_BAR_CHAR "|"
|
||||
|
||||
|
|
|
|||
|
|
@ -22,12 +22,13 @@
|
|||
|
||||
using namespace ARDOUR;
|
||||
using namespace ArdourSurface;
|
||||
using namespace Temporal;
|
||||
|
||||
double
|
||||
ArdourTransport::tempo () const
|
||||
{
|
||||
Tempo tempo = session ().tempo_map ().tempo_at_sample (0);
|
||||
return tempo.note_type () * tempo.pulses_per_minute ();
|
||||
const Tempo& tempo (session ().tempo_map ().metric_at (0).tempo());
|
||||
return tempo.note_types_per_minute ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -35,8 +36,9 @@ ArdourTransport::set_tempo (double bpm)
|
|||
{
|
||||
bpm = std::max (0.01, bpm);
|
||||
TempoMap& tempo_map = session ().tempo_map ();
|
||||
Tempo tempo (bpm, tempo_map.tempo_at_sample (0).note_type (), bpm);
|
||||
tempo_map.add_tempo (tempo, 0.0, 0, AudioTime);
|
||||
Tempo tempo (bpm, tempo_map.metric_at (0).tempo().note_type ());
|
||||
#warning NUTEMPO need some API to do this
|
||||
// tempo_map.add_tempo (tempo, 0.0, 0, AudioTime);
|
||||
}
|
||||
|
||||
double
|
||||
|
|
|
|||
|
|
@ -1683,7 +1683,7 @@ TempoMap::get_grid (TempoMapPoints& ret, superclock_t start, superclock_t end, u
|
|||
assert (!_tempos.empty());
|
||||
assert (!_meters.empty());
|
||||
|
||||
DEBUG_TRACE (DEBUG::TemporalMap, string_compose (">>> GRID START %1 .. %2 (barmod = %3)\n", start, end, bar_mod));
|
||||
DEBUG_TRACE (DEBUG::TemporalMap, string_compose (">>> GRID START %1 .. %2 (barmod = %3)\n", start, end, bar_mod))
|
||||
|
||||
Tempos::iterator t (_tempos.begin());
|
||||
Meters::iterator m (_meters.begin());
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
namespace ARDOUR {
|
||||
class Variant; /* Can stay since LV2 has no way to exchange beats as anything except double */
|
||||
/* these all need fixing to not use ::to_double() */
|
||||
class TempoMap;
|
||||
class Track;
|
||||
class MidiStretch;
|
||||
class MidiModel;
|
||||
|
|
@ -440,7 +439,6 @@ private:
|
|||
|
||||
/* almost nobody should ever be allowed to use this method */
|
||||
friend class TempoPoint;
|
||||
friend class ARDOUR::TempoMap;
|
||||
friend class ARDOUR::Track;
|
||||
friend class ARDOUR::Variant;
|
||||
friend class ARDOUR::MidiStretch;
|
||||
|
|
|
|||
|
|
@ -472,6 +472,10 @@ class LIBTEMPORAL_API TempoMetric {
|
|||
BBT_Time bbt_at (superclock_t sc) const;
|
||||
superclock_t superclock_at (BBT_Time const &) const;
|
||||
|
||||
samplepos_t samples_per_bar (samplecnt_t sr) const {
|
||||
return superclock_to_samples (superclocks_per_bar (sr), sr);
|
||||
}
|
||||
|
||||
protected:
|
||||
TempoPoint* _tempo;
|
||||
MeterPoint* _meter;
|
||||
|
|
@ -723,7 +727,7 @@ class LIBTEMPORAL_API TempoMap : public PBD::StatefulDestructible
|
|||
TimeDomain time_domain() const { return _time_domain; }
|
||||
void set_time_domain (TimeDomain td);
|
||||
|
||||
void get_grid (TempoMapPoints& points, superclock_t start, superclock_t end, uint32_t bar_mod);
|
||||
void get_grid (TempoMapPoints& points, superclock_t start, superclock_t end, uint32_t bar_mod = 0);
|
||||
|
||||
typedef std::list<Point*> Metrics;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue