diff options
author | David Robillard <d@drobilla.net> | 2014-11-22 04:05:42 -0500 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2014-11-22 04:05:42 -0500 |
commit | c1cfa12d6e5136d2e3e5501e83ff74c5009a9e60 (patch) | |
tree | 56d2811bc8b9d6f2a5accfa8e497ddd5976c7c7a /libs/ardour | |
parent | cae74309a583c29dd6cc2081425c2e7b673ea13e (diff) |
Wrap MusicalTime in a class.
This lets us get a more explicit handle on time conversions, and is the main
step towards using actual beat:tick time and getting away from floating point
precision problems.
Diffstat (limited to 'libs/ardour')
-rw-r--r-- | libs/ardour/ardour/automation_control.h | 1 | ||||
-rw-r--r-- | libs/ardour/ardour/automation_list.h | 5 | ||||
-rw-r--r-- | libs/ardour/ardour/beats_frames_converter.h | 28 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_model.h | 23 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_region.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_source.h | 12 | ||||
-rw-r--r-- | libs/ardour/ardour/smf_source.h | 7 | ||||
-rw-r--r-- | libs/ardour/beats_frames_converter.cc | 33 | ||||
-rw-r--r-- | libs/ardour/import.cc | 17 | ||||
-rw-r--r-- | libs/ardour/midi_diskstream.cc | 2 | ||||
-rw-r--r-- | libs/ardour/midi_model.cc | 20 | ||||
-rw-r--r-- | libs/ardour/midi_region.cc | 18 | ||||
-rw-r--r-- | libs/ardour/midi_source.cc | 6 | ||||
-rw-r--r-- | libs/ardour/midi_state_tracker.cc | 2 | ||||
-rw-r--r-- | libs/ardour/midi_stretch.cc | 4 | ||||
-rw-r--r-- | libs/ardour/quantize.cc | 12 | ||||
-rw-r--r-- | libs/ardour/smf_source.cc | 54 | ||||
-rw-r--r-- | libs/ardour/tempo.cc | 22 | ||||
-rw-r--r-- | libs/ardour/test/framepos_minus_beats_test.cc | 17 | ||||
-rw-r--r-- | libs/ardour/test/framepos_plus_beats_test.cc | 16 |
20 files changed, 173 insertions, 128 deletions
diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h index 639c5b5287..d73b2fc822 100644 --- a/libs/ardour/ardour/automation_control.h +++ b/libs/ardour/ardour/automation_control.h @@ -24,6 +24,7 @@ #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> +#include "evoral/types.hpp" #include "pbd/controllable.h" #include "evoral/Control.hpp" diff --git a/libs/ardour/ardour/automation_list.h b/libs/ardour/ardour/automation_list.h index 72c26420c0..28f9be3fd4 100644 --- a/libs/ardour/ardour/automation_list.h +++ b/libs/ardour/ardour/automation_list.h @@ -27,6 +27,9 @@ #include <glibmm/threads.h> +#include "evoral/ControlList.hpp" +#include "evoral/Parameter.hpp" + #include "pbd/undo.h" #include "pbd/xml++.h" #include "pbd/statefuldestructible.h" @@ -34,8 +37,6 @@ #include "ardour/ardour.h" -#include "evoral/ControlList.hpp" - namespace ARDOUR { class AutomationList; diff --git a/libs/ardour/ardour/beats_frames_converter.h b/libs/ardour/ardour/beats_frames_converter.h index 2e170d278a..ada09b1179 100644 --- a/libs/ardour/ardour/beats_frames_converter.h +++ b/libs/ardour/ardour/beats_frames_converter.h @@ -20,6 +20,8 @@ */ #include "evoral/TimeConverter.hpp" +#include "evoral/types.hpp" + #include "ardour/libardour_visibility.h" #include "ardour/types.h" @@ -34,15 +36,35 @@ class TempoMap; * from some origin (supplied to the constructor in frames), and converts * them to the opposite unit, taking tempo changes into account. */ -class LIBARDOUR_API BeatsFramesConverter : public Evoral::TimeConverter<double,framepos_t> { +class LIBARDOUR_API BeatsFramesConverter + : public Evoral::TimeConverter<Evoral::MusicalTime,framepos_t> { public: BeatsFramesConverter (TempoMap& tempo_map, framepos_t origin) + : Evoral::TimeConverter<Evoral::MusicalTime, framepos_t> (origin) + , _tempo_map(tempo_map) + {} + + framepos_t to (Evoral::MusicalTime beats) const; + Evoral::MusicalTime from (framepos_t frames) const; + +private: + TempoMap& _tempo_map; +}; + +/** Converter between beats and frames. Takes distances in beats or frames + * from some origin (supplied to the constructor in frames), and converts + * them to the opposite unit, taking tempo changes into account. + */ +class LIBARDOUR_API DoubleBeatsFramesConverter + : public Evoral::TimeConverter<double,framepos_t> { +public: + DoubleBeatsFramesConverter (TempoMap& tempo_map, framepos_t origin) : Evoral::TimeConverter<double, framepos_t> (origin) , _tempo_map(tempo_map) {} - framepos_t to (double beats) const; - double from (framepos_t frames) const; + framepos_t to (double beats) const; + double from (framepos_t frames) const; private: TempoMap& _tempo_map; diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index dc1c7af0e9..31df5ef040 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -116,16 +116,11 @@ public: struct NoteChange { NoteDiffCommand::Property property; NotePtr note; - uint32_t note_id; - - union { - uint8_t old_value; - TimeType old_time; - }; - union { - uint8_t new_value; - TimeType new_time; - }; + uint32_t note_id; + uint8_t old_value; // or... + TimeType old_time; // this + uint8_t new_value; // or... + TimeType new_time; // this }; typedef std::list<NoteChange> ChangeList; @@ -209,16 +204,16 @@ public: struct Change { PatchChangePtr patch; Property property; - gint patch_id; + gint patch_id; + TimeType old_time; union { - TimeType old_time; uint8_t old_channel; int old_bank; uint8_t old_program; }; + TimeType new_time; union { uint8_t new_channel; - TimeType new_time; uint8_t new_program; int new_bank; }; @@ -311,7 +306,5 @@ private: } /* namespace ARDOUR */ -/* This is a very long comment and stuff oh my god it's so long what are we going to do oh no oh no*/ - #endif /* __ardour_midi_model_h__ */ diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index 38229b998b..2a4e3a6190 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -23,6 +23,8 @@ #include <vector> +#include "evoral/types.hpp" + #include "ardour/ardour.h" #include "ardour/region.h" diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index 65e382c4b7..2ce92ba3cf 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -43,7 +43,7 @@ template<typename T> class MidiRingBuffer; class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_shared_from_this<MidiSource> { public: - typedef double TimeType; + typedef Evoral::MusicalTime TimeType; MidiSource (Session& session, std::string name, Source::Flag flags = Source::Flag(0)); MidiSource (Session& session, const XMLNode&); @@ -120,7 +120,7 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha */ virtual void mark_midi_streaming_write_completed ( Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_option, - Evoral::MusicalTime when = 0); + Evoral::MusicalTime when = Evoral::MusicalTime()); virtual void session_saved(); @@ -134,8 +134,8 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha bool length_mutable() const { return true; } - void set_length_beats(double l) { _length_beats = l; } - double length_beats() const { return _length_beats; } + void set_length_beats(TimeType l) { _length_beats = l; } + TimeType length_beats() const { return _length_beats; } virtual void load_model(bool lock=true, bool force_reload=false) = 0; virtual void destroy_model() = 0; @@ -194,8 +194,8 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha mutable Evoral::Sequence<Evoral::MusicalTime>::const_iterator _model_iter; mutable bool _model_iter_valid; - mutable double _length_beats; - mutable framepos_t _last_read_end; + mutable Evoral::MusicalTime _length_beats; + mutable framepos_t _last_read_end; /** The total duration of the current capture. */ framepos_t _capture_length; diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h index 84c45f9b3c..1c1f2bbcba 100644 --- a/libs/ardour/ardour/smf_source.h +++ b/libs/ardour/ardour/smf_source.h @@ -56,7 +56,8 @@ public: void mark_streaming_midi_write_started (NoteMode mode); void mark_streaming_write_completed (); - void mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption, Evoral::MusicalTime when = 0); + void mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption, + Evoral::MusicalTime when = Evoral::MusicalTime()); XMLNode& get_state (); int set_state (const XMLNode&, int version); @@ -88,8 +89,8 @@ public: framepos_t position, framecnt_t cnt); - double _last_ev_time_beats; - framepos_t _last_ev_time_frames; + Evoral::MusicalTime _last_ev_time_beats; + framepos_t _last_ev_time_frames; /** end time (start + duration) of last call to read_unlocked */ mutable framepos_t _smf_last_read_end; /** time (in SMF ticks, 1 tick per _ppqn) of the last event read by read_unlocked */ diff --git a/libs/ardour/beats_frames_converter.cc b/libs/ardour/beats_frames_converter.cc index 94042b1b03..b99edbf51e 100644 --- a/libs/ardour/beats_frames_converter.cc +++ b/libs/ardour/beats_frames_converter.cc @@ -31,26 +31,43 @@ namespace ARDOUR { * taking tempo changes into account. */ framepos_t -BeatsFramesConverter::to (double beats) const +BeatsFramesConverter::to (Evoral::MusicalTime beats) const { - if (beats < 0) { + if (beats < Evoral::MusicalTime()) { std::cerr << "negative beats passed to BFC: " << beats << std::endl; PBD::stacktrace (std::cerr, 30); + return 0; } - assert (beats >= 0); - framecnt_t r = _tempo_map.framepos_plus_beats (_origin_b, beats) - _origin_b; - return r; + return _tempo_map.framepos_plus_beats (_origin_b, beats) - _origin_b; } /** Takes a duration in frames and considers it as a distance from the origin * supplied to the constructor. Returns the equivalent number of beats, * taking tempo changes into account. */ -double +Evoral::MusicalTime BeatsFramesConverter::from (framepos_t frames) const { - double b = _tempo_map.framewalk_to_beats (_origin_b, frames); - return b; + return _tempo_map.framewalk_to_beats (_origin_b, frames); +} + +/** As above, but with beats in double instead (for GUI). */ +framepos_t +DoubleBeatsFramesConverter::to (double beats) const +{ + if (beats < 0.0) { + std::cerr << "negative beats passed to BFC: " << beats << std::endl; + PBD::stacktrace (std::cerr, 30); + return 0; + } + return _tempo_map.framepos_plus_beats (_origin_b, Evoral::MusicalTime(beats)) - _origin_b; +} + +/** As above, but with beats in double instead (for GUI). */ +double +DoubleBeatsFramesConverter::from (framepos_t frames) const +{ + return _tempo_map.framewalk_to_beats (_origin_b, frames).to_double(); } } /* namespace ARDOUR */ diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc index ae5f751767..38a3da2fdc 100644 --- a/libs/ardour/import.cc +++ b/libs/ardour/import.cc @@ -389,10 +389,11 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status, } smfs->append_event_unlocked_beats( - Evoral::Event<double>(0, - (double)t / (double)source->ppqn(), - size, - buf)); + Evoral::Event<Evoral::MusicalTime>( + 0, + Evoral::MusicalTime::ticks_at_rate(t, source->ppqn()), + size, + buf)); if (status.progress < 0.99) { status.progress += 0.01; @@ -403,10 +404,10 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status, /* we wrote something */ - const framepos_t pos = 0; - const double length_beats = ceil(t / (double)source->ppqn()); - BeatsFramesConverter converter(smfs->session().tempo_map(), pos); - smfs->update_length(pos + converter.to(length_beats)); + const framepos_t pos = 0; + const Evoral::MusicalTime length_beats = Evoral::MusicalTime::ticks_at_rate(t, source->ppqn()); + BeatsFramesConverter converter(smfs->session().tempo_map(), pos); + smfs->update_length(pos + converter.to(length_beats.round_up_to_beat())); smfs->mark_streaming_write_completed (); if (status.cancel) { diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index 69eca996aa..40d333d584 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -927,7 +927,7 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen /* set length in beats to entire capture length */ BeatsFramesConverter converter (_session.tempo_map(), capture_info.front()->start); - const double total_capture_beats = converter.from (total_capture); + const Evoral::MusicalTime total_capture_beats = converter.from (total_capture); _write_source->set_length_beats (total_capture_beats); /* flush to disk: this step differs from the audio path, diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 259a04bc0f..6c2132562a 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -226,13 +226,13 @@ MidiModel::NoteDiffCommand::change (const NotePtr note, Property prop, break; case StartTime: - if (Evoral::musical_time_equal (note->time(), new_time)) { + if (note->time() == new_time) { return; } change.old_time = note->time(); break; case Length: - if (Evoral::musical_time_equal (note->length(), new_time)) { + if (note->length() == new_time) { return; } change.old_time = note->length(); @@ -556,7 +556,7 @@ MidiModel::NoteDiffCommand::unmarshal_note (XMLNode *xml_note) time_str >> time; } else { warning << "note information missing time" << endmsg; - time = 0; + time = MidiModel::TimeType(); } if ((prop = xml_note->property("length")) != 0) { @@ -564,7 +564,7 @@ MidiModel::NoteDiffCommand::unmarshal_note (XMLNode *xml_note) length_str >> length; } else { warning << "note information missing length" << endmsg; - length = 1; + length = MidiModel::TimeType(1); } if ((prop = xml_note->property("velocity")) != 0) { @@ -1253,7 +1253,7 @@ MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n) { XMLProperty* prop; Evoral::event_id_t id = 0; - Evoral::MusicalTime time = 0; + Evoral::MusicalTime time = Evoral::MusicalTime(); int channel = 0; int program = 0; int bank = 0; @@ -1439,7 +1439,7 @@ MidiModel::write_to (boost::shared_ptr<MidiSource> source) source->drop_model(); source->mark_streaming_midi_write_started (note_mode()); - for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) { + for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) { source->append_event_unlocked_beats(*i); } @@ -1469,7 +1469,7 @@ MidiModel::sync_to_source () ms->mark_streaming_midi_write_started (note_mode()); - for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) { + for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) { ms->append_event_unlocked_beats(*i); } @@ -1503,7 +1503,7 @@ MidiModel::write_section_to (boost::shared_ptr<MidiSource> source, Evoral::Music source->drop_model(); source->mark_streaming_midi_write_started (note_mode()); - for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) { + for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) { const Evoral::Event<Evoral::MusicalTime>& ev (*i); if (ev.time() >= begin_time && ev.time() < end_time) { @@ -1662,7 +1662,7 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg) TimeType ea = note->end_time(); const Pitches& p (pitches (note->channel())); - NotePtr search_note(new Note<TimeType>(0, 0, 0, note->note())); + NotePtr search_note(new Note<TimeType>(0, TimeType(), TimeType(), note->note())); set<NotePtr> to_be_deleted; bool set_note_length = false; bool set_note_time = false; @@ -1979,7 +1979,7 @@ MidiModel::insert_silence_at_start (TimeType t) for (Controls::iterator i = controls().begin(); i != controls().end(); ++i) { boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (i->second); XMLNode& before = ac->alist()->get_state (); - i->second->list()->shift (0, t); + i->second->list()->shift (0, t.to_double()); XMLNode& after = ac->alist()->get_state (); s->session().add_command (new MementoCommand<AutomationList> (new MidiAutomationListBinder (s, i->first), &before, &after)); } diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index 71fd796b81..f6631b9de5 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -28,6 +28,8 @@ #include <glibmm/fileutils.h> #include <glibmm/miscutils.h> +#include "evoral/types.hpp" + #include "pbd/xml++.h" #include "pbd/basename.h" @@ -78,7 +80,7 @@ MidiRegion::register_properties () /* Basic MidiRegion constructor (many channels) */ MidiRegion::MidiRegion (const SourceList& srcs) : Region (srcs) - , _start_beats (Properties::start_beats, 0) + , _start_beats (Properties::start_beats, Evoral::MusicalTime()) , _length_beats (Properties::length_beats, midi_source(0)->length_beats()) { register_properties (); @@ -92,7 +94,7 @@ MidiRegion::MidiRegion (const SourceList& srcs) MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other) : Region (other) , _start_beats (Properties::start_beats, other->_start_beats) - , _length_beats (Properties::length_beats, (Evoral::MusicalTime) 0) + , _length_beats (Properties::length_beats, Evoral::MusicalTime()) { update_length_beats (); register_properties (); @@ -105,14 +107,14 @@ MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other) /** Create a new MidiRegion that is part of an existing one */ MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, frameoffset_t offset) : Region (other, offset) - , _start_beats (Properties::start_beats, (Evoral::MusicalTime) 0) - , _length_beats (Properties::length_beats, (Evoral::MusicalTime) 0) + , _start_beats (Properties::start_beats, Evoral::MusicalTime()) + , _length_beats (Properties::length_beats, Evoral::MusicalTime()) { BeatsFramesConverter bfc (_session.tempo_map(), _position); Evoral::MusicalTime const offset_beats = bfc.from (offset); - _start_beats = other->_start_beats + offset_beats; - _length_beats = other->_length_beats - offset_beats; + _start_beats = other->_start_beats.val() + offset_beats; + _length_beats = other->_length_beats.val() - offset_beats; register_properties (); @@ -216,7 +218,7 @@ MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute) /* zero length regions don't exist - so if _length_beats is zero, this object is under construction. */ - if (_length_beats) { + if (_length_beats.val() == Evoral::MusicalTime()) { /* leave _length_beats alone, and change _length to reflect the state of things at the new position (tempo map may dictate a different number of frames */ @@ -440,7 +442,7 @@ MidiRegion::fix_negative_start () model()->insert_silence_at_start (c.from (-_start)); _start = 0; - _start_beats = 0; + _start_beats = Evoral::MusicalTime(); } /** Transpose the notes in this region by a given number of semitones */ diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 823ca9dc5c..1c050733c2 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -153,13 +153,13 @@ MidiSource::set_state (const XMLNode& node, int /*version*/) bool MidiSource::empty () const { - return _length_beats == 0; + return !_length_beats; } framecnt_t MidiSource::length (framepos_t pos) const { - if (_length_beats == 0) { + if (!_length_beats) { return 0; } @@ -198,7 +198,7 @@ MidiSource::midi_read (Evoral::EventSink<framepos_t>& dst, if (_model) { // Find appropriate model iterator - Evoral::Sequence<double>::const_iterator& i = _model_iter; + Evoral::Sequence<Evoral::MusicalTime>::const_iterator& i = _model_iter; if (_last_read_end == 0 || start != _last_read_end || !_model_iter_valid) { // Cached iterator is invalid, search for the first event past start i = _model->begin(converter.from(start), false, filtered); diff --git a/libs/ardour/midi_state_tracker.cc b/libs/ardour/midi_state_tracker.cc index f006004621..0eac3819f2 100644 --- a/libs/ardour/midi_state_tracker.cc +++ b/libs/ardour/midi_state_tracker.cc @@ -173,7 +173,7 @@ MidiStateTracker::resolve_notes (MidiSource& src, Evoral::MusicalTime time) this, (int) note, (int) channel, time)); _active_notes[note + 128 * channel]--; /* don't stack events up at the same time */ - time += 1.0/128.0; + time += Evoral::MusicalTime::tick(); } } } diff --git a/libs/ardour/midi_stretch.cc b/libs/ardour/midi_stretch.cc index 38cab08ace..f5b3a47b41 100644 --- a/libs/ardour/midi_stretch.cc +++ b/libs/ardour/midi_stretch.cc @@ -95,9 +95,9 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress*) /* Note: pass true into force_discrete for the begin() iterator so that the model doesn't * do interpolation of controller data when we stretch. */ - for (Evoral::Sequence<MidiModel::TimeType>::const_iterator i = old_model->begin (0, true); + for (Evoral::Sequence<MidiModel::TimeType>::const_iterator i = old_model->begin (MidiModel::TimeType(), true); i != old_model->end(); ++i) { - const double new_time = i->time() * _request.time_fraction; + const MidiModel::TimeType new_time = i->time() * (double)_request.time_fraction; // FIXME: double copy Evoral::Event<MidiModel::TimeType> ev(*i, true); diff --git a/libs/ardour/quantize.cc b/libs/ardour/quantize.cc index 7da1edaaa1..13b1cf3b36 100644 --- a/libs/ardour/quantize.cc +++ b/libs/ardour/quantize.cc @@ -58,6 +58,8 @@ Quantize::operator () (boost::shared_ptr<MidiModel> model, double position, std::vector<Evoral::Sequence<Evoral::MusicalTime>::Notes>& seqs) { + /* TODO: Rewrite this to be precise with fixed point? */ + /* Calculate offset from start of model to next closest quantize step, to quantize relative to actual session beats (etc.) rather than from the start of the model. @@ -77,8 +79,8 @@ Quantize::operator () (boost::shared_ptr<MidiModel> model, */ for (Evoral::Sequence<MidiModel::TimeType>::Notes::iterator i = (*s).begin(); i != (*s).end(); ++i) { - double new_start = round (((*i)->time() - offset) / _start_grid) * _start_grid + offset; - double new_end = round (((*i)->end_time() - offset) / _end_grid) * _end_grid + offset; + double new_start = round (((*i)->time().to_double() - offset) / _start_grid) * _start_grid + offset; + double new_end = round (((*i)->end_time().to_double() - offset) / _end_grid) * _end_grid + offset; if (_swing > 0.0 && !even) { @@ -104,18 +106,18 @@ Quantize::operator () (boost::shared_ptr<MidiModel> model, } - double delta = new_start - (*i)->time(); + double delta = new_start - (*i)->time().to_double(); if (fabs (delta) >= _threshold) { if (_snap_start) { delta *= _strength; cmd->change ((*i), MidiModel::NoteDiffCommand::StartTime, - (*i)->time() + delta); + (*i)->time().to_double() + delta); } } if (_snap_end) { - delta = new_end - (*i)->end_time(); + delta = new_end - (*i)->end_time().to_double(); if (fabs (delta) >= _threshold) { double new_dur = new_end - new_start; diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index 8a956495a5..1ffcdac1b2 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -225,7 +225,7 @@ SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination, BeatsFramesConverter converter(_session.tempo_map(), source_start); - const uint64_t start_ticks = (uint64_t)(converter.from(start) * ppqn()); + const uint64_t start_ticks = converter.from(start).to_ticks(); DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start in ticks %1\n", start_ticks)); if (_smf_last_read_end == 0 || start != _smf_last_read_end) { @@ -273,7 +273,7 @@ SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination, /* Note that we add on the source start time (in session frames) here so that ev_frame_time is in session frames. */ - const framepos_t ev_frame_time = converter.to(time / (double)ppqn()) + source_start; + const framepos_t ev_frame_time = converter.to(Evoral::MusicalTime::ticks_at_rate(time, ppqn())) + source_start; if (ev_frame_time < start + duration) { destination.write (ev_frame_time, ev_type, ev_size, ev_buffer); @@ -377,9 +377,9 @@ SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source, return cnt; } -/** Append an event with a timestamp in beats (double) */ +/** Append an event with a timestamp in beats */ void -SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev) +SMFSource::append_event_unlocked_beats (const Evoral::Event<Evoral::MusicalTime>& ev) { if (!_writing || ev.size() == 0) { return; @@ -389,10 +389,10 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev) name().c_str(), ev.id(), ev.time(), ev.size()); for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");*/ - double time = ev.time(); + Evoral::MusicalTime time = ev.time(); if (time < _last_ev_time_beats) { - const double difference = _last_ev_time_beats - time; - if (difference / (double)ppqn() < 1.0) { + const Evoral::MusicalTime difference = _last_ev_time_beats - time; + if (difference.to_double() / (double)ppqn() < 1.0) { /* Close enough. This problem occurs because Sequence is not actually ordered due to fuzzy time comparison. I'm pretty sure this is inherently a bad idea which causes problems all over the @@ -401,7 +401,7 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev) } else { /* Out of order by more than a tick. */ warning << string_compose(_("Skipping event with unordered beat time %1 < %2 (off by %3 beats, %4 ticks)"), - ev.time(), _last_ev_time_beats, difference, difference / (double)ppqn()) + ev.time(), _last_ev_time_beats, difference, difference.to_double() / (double)ppqn()) << endmsg; return; } @@ -421,8 +421,8 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev) _length_beats = max(_length_beats, time); - const double delta_time_beats = time - _last_ev_time_beats; - const uint32_t delta_time_ticks = (uint32_t)lrint(delta_time_beats * (double)ppqn()); + const Evoral::MusicalTime delta_time_beats = time - _last_ev_time_beats; + const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn()); Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id); _last_ev_time_beats = time; @@ -448,9 +448,9 @@ SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, fr return; } - BeatsFramesConverter converter(_session.tempo_map(), position); - const double ev_time_beats = converter.from(ev.time()); - Evoral::event_id_t event_id; + BeatsFramesConverter converter(_session.tempo_map(), position); + const Evoral::MusicalTime ev_time_beats = converter.from(ev.time()); + Evoral::event_id_t event_id; if (ev.id() < 0) { event_id = Evoral::next_event_id(); @@ -459,10 +459,10 @@ SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, fr } if (_model) { - const Evoral::Event<double> beat_ev (ev.event_type(), - ev_time_beats, - ev.size(), - const_cast<uint8_t*>(ev.buffer())); + const Evoral::Event<Evoral::MusicalTime> beat_ev (ev.event_type(), + ev_time_beats, + ev.size(), + const_cast<uint8_t*>(ev.buffer())); _model->append (beat_ev, event_id); } @@ -470,7 +470,7 @@ SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, fr const Evoral::MusicalTime last_time_beats = converter.from (_last_ev_time_frames); const Evoral::MusicalTime delta_time_beats = ev_time_beats - last_time_beats; - const uint32_t delta_time_ticks = (uint32_t)(lrint(delta_time_beats * (double)ppqn())); + const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn()); Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id); _last_ev_time_frames = ev.time(); @@ -516,7 +516,7 @@ SMFSource::mark_streaming_midi_write_started (NoteMode mode) MidiSource::mark_streaming_midi_write_started (mode); Evoral::SMF::begin_write (); - _last_ev_time_beats = 0.0; + _last_ev_time_beats = Evoral::MusicalTime(); _last_ev_time_frames = 0; } @@ -586,8 +586,8 @@ SMFSource::safe_midi_file_extension (const string& file) } static bool compare_eventlist ( - const std::pair< Evoral::Event<double>*, gint >& a, - const std::pair< Evoral::Event<double>*, gint >& b) { + const std::pair< Evoral::Event<Evoral::MusicalTime>*, gint >& a, + const std::pair< Evoral::Event<Evoral::MusicalTime>*, gint >& b) { return ( a.first->time() < b.first->time() ); } @@ -620,7 +620,7 @@ SMFSource::load_model (bool lock, bool force_reload) Evoral::SMF::seek_to_start(); uint64_t time = 0; /* in SMF ticks */ - Evoral::Event<double> ev; + Evoral::Event<Evoral::MusicalTime> ev; uint32_t scratch_size = 0; // keep track of scratch and minimize reallocs @@ -632,7 +632,7 @@ SMFSource::load_model (bool lock, bool force_reload) bool have_event_id; // TODO simplify event allocation - std::list< std::pair< Evoral::Event<double>*, gint > > eventlist; + std::list< std::pair< Evoral::Event<Evoral::MusicalTime>*, gint > > eventlist; for (unsigned i = 1; i <= num_tracks(); ++i) { if (seek_to_track(i)) continue; @@ -658,8 +658,8 @@ SMFSource::load_model (bool lock, bool force_reload) if (!have_event_id) { event_id = Evoral::next_event_id(); } - uint32_t event_type = midi_parameter_type(buf[0]); - double event_time = time / (double) ppqn(); + const uint32_t event_type = midi_parameter_type(buf[0]); + const Evoral::MusicalTime event_time = Evoral::MusicalTime::ticks_at_rate(time, ppqn()); #ifndef NDEBUG std::string ss; @@ -674,7 +674,7 @@ SMFSource::load_model (bool lock, bool force_reload) #endif eventlist.push_back(make_pair ( - new Evoral::Event<double> ( + new Evoral::Event<Evoral::MusicalTime> ( event_type, event_time, size, buf, true) , event_id)); @@ -693,7 +693,7 @@ SMFSource::load_model (bool lock, bool force_reload) eventlist.sort(compare_eventlist); - std::list< std::pair< Evoral::Event<double>*, gint > >::iterator it; + std::list< std::pair< Evoral::Event<Evoral::MusicalTime>*, gint > >::iterator it; for (it=eventlist.begin(); it!=eventlist.end(); ++it) { _model->append (*it->first, it->second); delete it->first; diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index 57bf9fe674..1767c8100d 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -1891,10 +1891,11 @@ TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const framecnt_t distance_frames = (next_tempo == metrics.end() ? max_framepos : ((*next_tempo)->frame() - pos)); /* Distance to the end in beats */ - Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate); + Evoral::MusicalTime distance_beats = Evoral::MusicalTime::ticks_at_rate( + distance_frames, tempo->frames_per_beat (_frame_rate)); /* Amount to subtract this time */ - double const delta = min (distance_beats, beats); + Evoral::MusicalTime const delta = min (distance_beats, beats); DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tdistance to %1 = %2 (%3 beats)\n", (next_tempo == metrics.end() ? max_framepos : (*next_tempo)->frame()), @@ -1902,7 +1903,7 @@ TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const /* Update */ beats -= delta; - pos += delta * tempo->frames_per_beat (_frame_rate); + pos += delta.to_ticks(tempo->frames_per_beat (_frame_rate)); DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnow at %1, %2 beats left\n", pos, beats)); @@ -1999,10 +2000,11 @@ TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const framecnt_t distance_frames = (pos - tempo->frame()); /* Distance to the start in beats */ - Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate); + Evoral::MusicalTime distance_beats = Evoral::MusicalTime::ticks_at_rate( + distance_frames, tempo->frames_per_beat (_frame_rate)); /* Amount to subtract this time */ - double const sub = min (distance_beats, beats); + Evoral::MusicalTime const sub = min (distance_beats, beats); DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tdistance to %1 = %2 (%3 beats)\n", tempo->frame(), distance_frames, distance_beats)); @@ -2035,7 +2037,7 @@ TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const } } else { pos -= llrint (beats * tempo->frames_per_beat (_frame_rate)); - beats = 0; + beats = Evoral::MusicalTime(); } } @@ -2216,7 +2218,7 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const string_compose ("frame %1 walk by %2 frames, start with tempo = %3 @ %4\n", pos, distance, *((const Tempo*)tempo), tempo->frame())); - Evoral::MusicalTime beats = 0; + Evoral::MusicalTime beats = Evoral::MusicalTime(); while (distance) { @@ -2234,8 +2236,8 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const distance_to_end = end - pos; } - /* Amount to subtract this time */ - double const sub = min (distance, distance_to_end); + /* Amount to subtract this time in frames */ + framecnt_t const sub = min (distance, distance_to_end); DEBUG_TRACE (DEBUG::TempoMath, string_compose ("to reach end at %1 (end ? %2), distance= %3 sub=%4\n", end, (next_tempo == metrics.end()), distance_to_end, sub)); @@ -2244,7 +2246,7 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const pos += sub; distance -= sub; assert (tempo); - beats += sub / tempo->frames_per_beat (_frame_rate); + beats += Evoral::MusicalTime::ticks_at_rate(sub, tempo->frames_per_beat (_frame_rate)); DEBUG_TRACE (DEBUG::TempoMath, string_compose ("now at %1, beats = %2 distance left %3\n", pos, beats, distance)); diff --git a/libs/ardour/test/framepos_minus_beats_test.cc b/libs/ardour/test/framepos_minus_beats_test.cc index 01bafc1606..e4c4844146 100644 --- a/libs/ardour/test/framepos_minus_beats_test.cc +++ b/libs/ardour/test/framepos_minus_beats_test.cc @@ -7,6 +7,7 @@ CPPUNIT_TEST_SUITE_REGISTRATION (FrameposMinusBeatsTest); using namespace std; using namespace ARDOUR; using namespace Timecode; +using namespace Evoral; /* Basic tests with no tempo / meter changes */ void @@ -25,11 +26,11 @@ FrameposMinusBeatsTest::singleTempoTest () map.add_tempo (tempo, BBT_Time (1, 1, 0)); /* Subtract 1 beat from beat 3 of the first bar */ - framepos_t r = map.framepos_minus_beats (frames_per_beat * 2, 1); + framepos_t r = map.framepos_minus_beats (frames_per_beat * 2, MusicalTime(1)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (frames_per_beat * 1)); /* Subtract 4 beats from 3 beats in, to go beyond zero */ - r = map.framepos_minus_beats (frames_per_beat * 3, 4); + r = map.framepos_minus_beats (frames_per_beat * 3, MusicalTime(4)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (- frames_per_beat)); } @@ -69,15 +70,15 @@ FrameposMinusBeatsTest::doubleTempoTest () /* Now some tests */ /* Subtract 1 beat from 1|2 */ - framepos_t r = map.framepos_minus_beats (24e3, 1); + framepos_t r = map.framepos_minus_beats (24e3, MusicalTime(1)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (0)); /* Subtract 2 beats from 4|2 (over the tempo change) */ - r = map.framepos_minus_beats (288e3 + 12e3, 2); + r = map.framepos_minus_beats (288e3 + 12e3, MusicalTime(2)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (288e3 - 24e3)); /* Subtract 2.5 beats from 4|2 (over the tempo change) */ - r = map.framepos_minus_beats (288e3 + 12e3, 2.5); + r = map.framepos_minus_beats (288e3 + 12e3, MusicalTime(2.5)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (288e3 - 24e3 - 12e3)); } @@ -123,15 +124,15 @@ FrameposMinusBeatsTest::doubleTempoWithMeterTest () /* Now some tests */ /* Subtract 1 beat from 1|2 */ - framepos_t r = map.framepos_minus_beats (24e3, 1); + framepos_t r = map.framepos_minus_beats (24e3, MusicalTime(1)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (0)); /* Subtract 2 beats from 4|2 (over the tempo change) */ - r = map.framepos_minus_beats (288e3 + 12e3, 2); + r = map.framepos_minus_beats (288e3 + 12e3, MusicalTime(2)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (288e3 - 24e3)); /* Subtract 2.5 beats from 4|2 (over the tempo change) */ - r = map.framepos_minus_beats (288e3 + 12e3, 2.5); + r = map.framepos_minus_beats (288e3 + 12e3, MusicalTime(2.5)); CPPUNIT_ASSERT_EQUAL (r, framepos_t (288e3 - 24e3 - 12e3)); } diff --git a/libs/ardour/test/framepos_plus_beats_test.cc b/libs/ardour/test/framepos_plus_beats_test.cc index c95c2a7a66..abe1310f62 100644 --- a/libs/ardour/test/framepos_plus_beats_test.cc +++ b/libs/ardour/test/framepos_plus_beats_test.cc @@ -25,11 +25,11 @@ FrameposPlusBeatsTest::singleTempoTest () map.add_tempo (tempo, BBT_Time (1, 1, 0)); /* Add 1 beat to beat 3 of the first bar */ - framepos_t r = map.framepos_plus_beats (frames_per_beat * 2, 1); + framepos_t r = map.framepos_plus_beats (frames_per_beat * 2, Evoral::MusicalTime(1)); CPPUNIT_ASSERT_EQUAL (framepos_t (frames_per_beat * 3), r); /* Add 4 beats to a -ve frame of 1 beat before zero */ - r = map.framepos_plus_beats (-frames_per_beat * 1, 4); + r = map.framepos_plus_beats (-frames_per_beat * 1, Evoral::MusicalTime(4)); CPPUNIT_ASSERT_EQUAL (framepos_t (frames_per_beat * 3), r); } @@ -69,15 +69,15 @@ FrameposPlusBeatsTest::doubleTempoTest () /* Now some tests */ /* Add 1 beat to 1|2 */ - framepos_t r = map.framepos_plus_beats (24e3, 1); + framepos_t r = map.framepos_plus_beats (24e3, Evoral::MusicalTime(1)); CPPUNIT_ASSERT_EQUAL (framepos_t (48e3), r); /* Add 2 beats to 3|4 (over the tempo change) */ - r = map.framepos_plus_beats (264e3, 2); + r = map.framepos_plus_beats (264e3, Evoral::MusicalTime(2)); CPPUNIT_ASSERT_EQUAL (framepos_t (264e3 + 24e3 + 12e3), r); /* Add 2.5 beats to 3|3|960 (over the tempo change) */ - r = map.framepos_plus_beats (264e3 - 12e3, 2.5); + r = map.framepos_plus_beats (264e3 - 12e3, Evoral::MusicalTime(2.5)); CPPUNIT_ASSERT_EQUAL (framepos_t (264e3 + 24e3 + 12e3), r); } @@ -123,15 +123,15 @@ FrameposPlusBeatsTest::doubleTempoWithMeterTest () /* Now some tests */ /* Add 1 beat to 1|2 */ - framepos_t r = map.framepos_plus_beats (24e3, 1); + framepos_t r = map.framepos_plus_beats (24e3, Evoral::MusicalTime(1)); CPPUNIT_ASSERT_EQUAL (framepos_t (48e3), r); /* Add 2 beats to 3|4 (over the tempo change) */ - r = map.framepos_plus_beats (264e3, 2); + r = map.framepos_plus_beats (264e3, Evoral::MusicalTime(2)); CPPUNIT_ASSERT_EQUAL (framepos_t (264e3 + 24e3 + 12e3), r); /* Add 2.5 beats to 3|3|960 (over the tempo change) */ - r = map.framepos_plus_beats (264e3 - 12e3, 2.5); + r = map.framepos_plus_beats (264e3 - 12e3, Evoral::MusicalTime(2.5)); CPPUNIT_ASSERT_EQUAL (framepos_t (264e3 + 24e3 + 12e3), r); } |