diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index 324a6c73a8..50f49b8d5e 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -25,6 +25,7 @@ #define __ardour_midi_model_h__ #include +#include #include #include @@ -252,6 +253,9 @@ public: PatchChangePtr unmarshal_patch_change (XMLNode *); }; + void create_mapping_stash (Temporal::Beats const & offset); + void rebuild_from_mapping_stash (Temporal::Beats const & offset); + /** Start a new NoteDiff command. * * This has no side-effects on the model or Session, the returned command @@ -359,6 +363,10 @@ private: MidiSource& _midi_source; InsertMergePolicy _insert_merge_policy; + + typedef std::map TempoMappingStash; + TempoMappingStash tempo_mapping_stash; + }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index 23f3690b8a..d2afd02b70 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -27,6 +27,7 @@ #include "temporal/beats.h" #include "temporal/range.h" +#include "temporal/types.h" #include "pbd/string_convert.h" @@ -54,7 +55,7 @@ class ThawList; template class MidiRingBuffer; -class LIBARDOUR_API MidiRegion : public Region +class LIBARDOUR_API MidiRegion : public Region, public Temporal::TimeThing { public: ~MidiRegion(); @@ -116,6 +117,9 @@ class LIBARDOUR_API MidiRegion : public Region timecnt_t const & read_length, MidiChannelFilter* filter) const; + void globally_change_time_domain (Temporal::TimeDomain from, Temporal::TimeDomain to); + void swap_domain (Temporal::TimeDomain, Temporal::TimeDomain); + protected: virtual bool can_trim_start_before_source_start () const { diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index b09c98cc89..0675583ee4 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -114,7 +114,7 @@ public: const DataType& data_type () const { return _type; } Temporal::TimeDomain time_domain() const; - void globally_change_time_domain (Temporal::TimeDomain from, Temporal::TimeDomain to); + virtual void globally_change_time_domain (Temporal::TimeDomain from, Temporal::TimeDomain to); /** How the region parameters play together: * diff --git a/libs/ardour/location.cc b/libs/ardour/location.cc index 866b4ba3e4..0a08eff0be 100644 --- a/libs/ardour/location.cc +++ b/libs/ardour/location.cc @@ -770,9 +770,13 @@ Location::globally_change_time_domain (Temporal::TimeDomain from, Temporal::Time if (_start.time_domain() == from) { + std::cerr << "switching location [" << name() << "] from " << _start; + _start.set_time_domain (to); _end.set_time_domain (to); + std::cerr << " to " << _start << std::endl; + domain_swap->add (_start); domain_swap->add (_end); } else { diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 3df1b29727..39d868008e 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -1772,3 +1772,101 @@ MidiModel::control_list_marked_dirty () ContentsChanged (); /* EMIT SIGNAL */ } + +void +MidiModel::create_mapping_stash (Temporal::Beats const & src_pos_offset) +{ + using namespace Evoral; + using namespace Temporal; + + TempoMap::SharedPtr tmap (TempoMap::use()); + + if (!tempo_mapping_stash.empty()) { + return; + } + + for (auto const & n : notes()) { + Event& on (n->on_event()); + superclock_t audio_time = tmap->superclock_at (src_pos_offset + on.time()); + tempo_mapping_stash.insert (std::make_pair (&on, audio_time)); + + Event& off (n->off_event()); + audio_time = tmap->superclock_at (src_pos_offset + off.time()); + tempo_mapping_stash.insert (std::make_pair (&off, audio_time)); + + } + + for (auto const & s : sysexes()) { + superclock_t audio_time = tmap->superclock_at (src_pos_offset + s->time()); + tempo_mapping_stash.insert (std::make_pair ((void*)s.get(), audio_time)); + } + + for (uint8_t chan = 0; chan < 16; ++chan) { + for (auto const & p : pitches(chan)) { + superclock_t audio_time = tmap->superclock_at (src_pos_offset + p->time()); + tempo_mapping_stash.insert (std::make_pair ((void*) &p, audio_time)); + } + } + + for (auto & c : controls()) { + std::shared_ptr l = c.second->list(); + if (l) { + l->set_time_domain (AudioTime); + } + } +} + +void +MidiModel::rebuild_from_mapping_stash (Temporal::Beats const & src_pos_offset) +{ + using namespace Evoral; + using namespace Temporal; + + if (tempo_mapping_stash.empty()) { + return; + } + + TempoMap::SharedPtr tmap (TempoMap::use()); + + for (auto & n : notes()) { + + Event& on (n->on_event()); + Event& off (n->off_event()); + + TempoMappingStash::iterator tms (tempo_mapping_stash.find (&on)); + assert (tms != tempo_mapping_stash.end()); + Beats beat_time (tmap->quarters_at_superclock (tms->second) - src_pos_offset); + on.set_time (beat_time); + + tms = tempo_mapping_stash.find (&off); + assert (tms != tempo_mapping_stash.end()); + beat_time = tmap->quarters_at_superclock (tms->second) - src_pos_offset; + off.set_time (beat_time); + + } + + for (auto & s : sysexes()) { + TempoMappingStash::iterator tms (tempo_mapping_stash.find ((void*) &s)); + assert (tms != tempo_mapping_stash.end()); + Beats beat_time (tmap->quarters_at_superclock (tms->second) - src_pos_offset); + s->set_time (beat_time); + } + + for (uint8_t chan = 0; chan < 16; ++chan) { + for (auto & p : pitches(chan)) { + TempoMappingStash::iterator tms (tempo_mapping_stash.find ((void*) &p)); + assert (tms != tempo_mapping_stash.end()); + Beats beat_time (tmap->quarters_at_superclock (tms->second) - src_pos_offset); + p->set_time (beat_time); + } + } + + for (auto & c : controls()) { + std::shared_ptr l = c.second->list(); + if (l) { + l->set_time_domain (BeatTime); + } + } + + tempo_mapping_stash.clear (); +} diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index d0f7a9b391..8c1d4de5ca 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -612,3 +612,25 @@ MidiRegion::merge (std::shared_ptr other_region) set_length (max (length(), position().distance (other_region->end()))); } + +void +MidiRegion::swap_domain (Temporal::TimeDomain from, Temporal::TimeDomain to) +{ + if (from == Temporal::BeatTime) { + model()->create_mapping_stash (source_position().beats()); + } else { + model()->rebuild_from_mapping_stash (source_position().beats()); + + _model_changed_connection.disconnect (); + model()->ContentsChanged (); + model()->ContentsChanged.connect_same_thread (_model_changed_connection, boost::bind (&MidiRegion::model_contents_changed, this)); + } +} + +void +MidiRegion::globally_change_time_domain (Temporal::TimeDomain from, Temporal::TimeDomain to) +{ + Region::globally_change_time_domain (from, to); + swap_domain (from, to); + Temporal::domain_swap->add (*this); +} diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index 20a7d3f85c..f7c91592eb 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -2199,7 +2199,9 @@ Region::globally_change_time_domain (Temporal::TimeDomain from, Temporal::TimeDo if (_length.val().time_domain() == from) { timecnt_t& l (_length.non_const_val()); + std::cerr << "old domain after GCTD " << _length.val() << std::endl; l.set_time_domain (to); Temporal::domain_swap->add (l); + std::cerr << "new domain after GCTD " << _length.val() << std::endl; } } diff --git a/libs/ardour/session_time.cc b/libs/ardour/session_time.cc index b98d1d9d08..db61df1d06 100644 --- a/libs/ardour/session_time.cc +++ b/libs/ardour/session_time.cc @@ -302,6 +302,8 @@ Session::any_duration_to_samples (samplepos_t position, AnyTime const & duration void Session::globally_change_time_domain (Temporal::TimeDomain from, Temporal::TimeDomain to) { + std::cerr << "GCTD from " << from << " to " << to << std::endl; + { std::shared_ptr rl (routes.reader()); diff --git a/libs/temporal/tempo.cc b/libs/temporal/tempo.cc index d2e8010c12..8d281fc539 100644 --- a/libs/temporal/tempo.cc +++ b/libs/temporal/tempo.cc @@ -4882,6 +4882,10 @@ DomainSwapInformation::undo () p->set_time_domain (previous); } + for (auto & tt : time_things) { + tt->swap_domain (previous == AudioTime ? BeatTime : AudioTime, previous); + } + clear (); } diff --git a/libs/temporal/temporal/tempo.h b/libs/temporal/temporal/tempo.h index 7d41efec9c..60e0521a41 100644 --- a/libs/temporal/temporal/tempo.h +++ b/libs/temporal/temporal/tempo.h @@ -1273,6 +1273,7 @@ class LIBTEMPORAL_API DomainSwapInformation { void add (timecnt_t& t) { counts.push_back (&t); } void add (timepos_t& p) { positions.push_back (&p); } + void add (TimeThing& tt) { time_things.push_back (&tt); } void clear (); private: @@ -1280,6 +1281,7 @@ class LIBTEMPORAL_API DomainSwapInformation { std::vector counts; std::vector positions; + std::vector time_things; TimeDomain previous; void undo (); diff --git a/libs/temporal/temporal/types.h b/libs/temporal/temporal/types.h index 5f308fd937..43d1730b4f 100644 --- a/libs/temporal/temporal/types.h +++ b/libs/temporal/temporal/types.h @@ -124,6 +124,11 @@ enum RoundMode { extern void setup_enum_writer (); +struct LIBTEMPORAL_API TimeThing { + virtual ~TimeThing() {} + virtual void swap_domain (Temporal::TimeDomain from, Temporal::TimeDomain to) = 0; +}; + } std::ostream& operator<< (std::ostream& o, Temporal::ratio_t const & r);