diff options
Diffstat (limited to 'libs/ardour/ardour/tempo.h')
-rw-r--r-- | libs/ardour/ardour/tempo.h | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h new file mode 100644 index 0000000000..2f04f603e7 --- /dev/null +++ b/libs/ardour/ardour/tempo.h @@ -0,0 +1,323 @@ +/* + Copyright (C) 2000 Paul Davis + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#ifndef __ardour_tempo_h__ +#define __ardour_tempo_h__ + +#include <list> +#include <string> +#include <vector> +#include <cmath> +#include <pthread.h> +#include <pbd/lockmonitor.h> +#include <pbd/undo.h> +#include <sigc++/signal.h> + +#include <ardour/ardour.h> +#include <ardour/stateful.h> +#include <ardour/state_manager.h> + +class XMLNode; + +using std::list; +using std::vector; + +namespace ARDOUR { + +class Tempo { + public: + Tempo (double bpm) + : _beats_per_minute (bpm) {} + Tempo (const Tempo& other) { + _beats_per_minute = other._beats_per_minute; + } + void operator= (const Tempo& other) { + if (&other != this) { + _beats_per_minute = other._beats_per_minute; + } + } + + double beats_per_minute () const { return _beats_per_minute; } + double frames_per_beat (jack_nframes_t sr) const { + return ((60.0 * sr) / _beats_per_minute); + } + + protected: + double _beats_per_minute; +}; + +class Meter { + public: + static const double ticks_per_beat; + + Meter (double bpb, double bt) + : _beats_per_bar (bpb), _note_type (bt) {} + Meter (const Meter& other) { + _beats_per_bar = other._beats_per_bar; + _note_type = other._note_type; + } + void operator= (const Meter& other) { + if (&other != this) { + _beats_per_bar = other._beats_per_bar; + _note_type = other._note_type; + } + } + + double beats_per_bar () const { return _beats_per_bar; } + double note_divisor() const { return _note_type; } + + double frames_per_bar (const Tempo&, jack_nframes_t sr) const; + + protected: + + /* this is the number of beats in a bar. it is a real value + because there are musical traditions on our planet + that do not limit themselves to integral numbers of beats + per bar. + */ + + double _beats_per_bar; + + /* this is the type of "note" that a beat represents. for example, + 4.0 would be a quarter (crotchet) note, 8.0 would be an eighth + (quaver) note, etc. + */ + + double _note_type; +}; + +class MetricSection { + public: + MetricSection (const BBT_Time& start) + : _start (start), _frame (0), _movable (true) {} + virtual ~MetricSection() {} + + const BBT_Time& start() const { return _start; } + const jack_nframes_t frame() const { return _frame; } + + void set_movable (bool yn) { _movable = yn; } + bool movable() const { return _movable; } + + virtual void set_frame (jack_nframes_t f) { + _frame = f; + }; + + virtual void set_start (const BBT_Time& w) { + _start = w; + } + + /* 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; + + private: + BBT_Time _start; + jack_nframes_t _frame; + bool _movable; +}; + +class MeterSection : public MetricSection, public Meter { + public: + MeterSection (const BBT_Time& start, double bpb, double note_type) + : MetricSection (start), Meter (bpb, note_type) {} + MeterSection (const XMLNode&); + + static const string xml_state_node_name; + + XMLNode& get_state() const; +}; + +class TempoSection : public MetricSection, public Tempo { + public: + TempoSection (const BBT_Time& start, double qpm) + : MetricSection (start), Tempo (qpm) {} + TempoSection (const XMLNode&); + + static const string xml_state_node_name; + + XMLNode& get_state() const; +}; + +typedef list<MetricSection*> Metrics; + +class TempoMapState : public StateManager::State { + public: + TempoMapState (std::string why) + : StateManager::State (why) { + metrics = new Metrics; + } + + Metrics *metrics; +}; + +class TempoMap : public Stateful, public StateManager { + public: + + TempoMap (jack_nframes_t frame_rate); + ~TempoMap(); + + /* measure-based stuff */ + + enum BBTPointType { + Bar, + Beat, + }; + + struct BBTPoint { + BBTPointType type; + jack_nframes_t frame; + const Meter* meter; + const Tempo* tempo; + uint32_t bar; + uint32_t beat; + + BBTPoint (const Meter& m, const Tempo& t, jack_nframes_t f, BBTPointType ty, uint32_t b, uint32_t e) + : type (ty), frame (f), meter (&m), tempo (&t), bar (b), beat (e) {} + }; + + typedef vector<BBTPoint> BBTPointList; + + template<class T> void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) { + LockMonitor lm (lock, __LINE__, __FILE__); + (obj.*method)(*metrics); + } + + BBTPointList *get_points (jack_nframes_t start, jack_nframes_t end) const; + + void bbt_time (jack_nframes_t when, BBT_Time&) const; + jack_nframes_t frame_time (const BBT_Time&) const; + jack_nframes_t bbt_duration_at (jack_nframes_t, const BBT_Time&, int dir) const; + + static const Tempo& default_tempo() { return _default_tempo; } + static const Meter& default_meter() { return _default_meter; } + + const Tempo& tempo_at (jack_nframes_t); + const Meter& meter_at (jack_nframes_t); + + void add_tempo(const Tempo&, BBT_Time where); + void add_meter(const Meter&, BBT_Time where); + + void move_tempo (TempoSection&, const BBT_Time& to); + void move_meter (MeterSection&, const BBT_Time& to); + + void remove_tempo(const TempoSection&); + void remove_meter(const MeterSection&); + + void replace_tempo (TempoSection& existing, const Tempo& replacement); + void replace_meter (MeterSection& existing, const Meter& replacement); + + + jack_nframes_t round_to_bar (jack_nframes_t frame, int dir); + + jack_nframes_t round_to_beat (jack_nframes_t frame, int dir); + + jack_nframes_t round_to_beat_subdivision (jack_nframes_t fr, int sub_num); + + jack_nframes_t round_to_tick (jack_nframes_t frame, int dir); + + void set_length (jack_nframes_t frames); + + XMLNode& get_state (void); + int set_state (const XMLNode&); + + void dump (std::ostream&) const; + void clear (); + + UndoAction get_memento() const; + + /* this is a helper class that we use to be able to keep + track of which meter *AND* tempo are in effect at + a given point in time. + */ + + class Metric { + public: + Metric (const Meter& m, const Tempo& t) : _meter (&m), _tempo (&t), _frame (0) {} + + void set_tempo (const Tempo& t) { _tempo = &t; } + void set_meter (const Meter& m) { _meter = &m; } + void set_frame (jack_nframes_t f) { _frame = f; } + void set_start (const BBT_Time& t) { _start = t; } + + const Meter& meter() const { return *_meter; } + const Tempo& tempo() const { return *_tempo; } + jack_nframes_t frame() const { return _frame; } + const BBT_Time& start() const { return _start; } + + private: + const Meter* _meter; + const Tempo* _tempo; + jack_nframes_t _frame; + BBT_Time _start; + + }; + + Metric metric_at (BBT_Time bbt) const; + Metric metric_at (jack_nframes_t) const; + void bbt_time_with_metric (jack_nframes_t, BBT_Time&, const Metric&) const; + + private: + static Tempo _default_tempo; + static Meter _default_meter; + + Metrics *metrics; + jack_nframes_t _frame_rate; + jack_nframes_t last_bbt_when; + bool last_bbt_valid; + BBT_Time last_bbt; + mutable PBD::Lock lock; + + void timestamp_metrics (); + + + jack_nframes_t round_to_type (jack_nframes_t fr, int dir, BBTPointType); + + jack_nframes_t frame_time_unlocked (const BBT_Time&) const; + + void bbt_time_unlocked (jack_nframes_t, BBT_Time&) const; + + jack_nframes_t bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir) const; + + const MeterSection& first_meter() const; + const TempoSection& first_tempo() const; + + jack_nframes_t count_frames_between (const BBT_Time&, const BBT_Time&) const; + jack_nframes_t count_frames_between_metrics (const Meter&, const Tempo&, const BBT_Time&, const BBT_Time&) const; + + int move_metric_section (MetricSection&, const BBT_Time& to); + void do_insert (MetricSection* section); + + Change restore_state (StateManager::State&); + StateManager::State* state_factory (std::string why) const; + + bool in_set_state; + + /* override state_manager::save_state so we can check in_set_state */ + + void save_state (std::string why); + +}; + +}; /* namespace ARDOUR */ + +#endif /* __ardour_tempo_h__ */ |