diff options
author | Carl Hetherington <carl@carlh.net> | 2011-12-29 22:14:15 +0000 |
---|---|---|
committer | Carl Hetherington <carl@carlh.net> | 2011-12-29 22:14:15 +0000 |
commit | b1775149307a157444c516693ad6b98a404ef1b2 (patch) | |
tree | ffdf04d8396cf53d5378c073a8d249150d5282eb /libs | |
parent | cabb76cce6203d34299136371078bd20b6abe1e3 (diff) |
Revert internals of the last layering-related commit, and go back a slightly-cleaned-up version of how it was before. Remove all layering modes; only option now is add-is-higher. Move-add-higher could easily be re-added if anyone uses it.
git-svn-id: svn://localhost/ardour2/branches/3.0@11111 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/ardour/playlist.h | 75 | ||||
-rw-r--r-- | libs/ardour/ardour/region.h | 26 | ||||
-rw-r--r-- | libs/ardour/ardour/region_sorters.h | 16 | ||||
-rw-r--r-- | libs/ardour/ardour/session_configuration_vars.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/types.h | 13 | ||||
-rw-r--r-- | libs/ardour/audio_diskstream.cc | 2 | ||||
-rw-r--r-- | libs/ardour/enums.cc | 19 | ||||
-rw-r--r-- | libs/ardour/playlist.cc | 601 | ||||
-rw-r--r-- | libs/ardour/region.cc | 77 | ||||
-rwxr-xr-x | libs/ardour/run-tests.sh | 2 | ||||
-rw-r--r-- | libs/ardour/session_state.cc | 22 | ||||
-rw-r--r-- | libs/ardour/test/playlist_layering_test.cc | 379 | ||||
-rw-r--r-- | libs/ardour/test/playlist_layering_test.h | 32 | ||||
-rw-r--r-- | libs/ardour/test/playlist_overlap_cache_test.cc | 119 | ||||
-rw-r--r-- | libs/ardour/test/playlist_overlap_cache_test.h | 20 | ||||
-rw-r--r-- | libs/ardour/test/test_needing_session.cc | 48 | ||||
-rw-r--r-- | libs/ardour/test/test_needing_session.h | 16 | ||||
-rw-r--r-- | libs/ardour/test/test_receiver.h | 37 | ||||
-rw-r--r-- | libs/ardour/wscript | 2 |
19 files changed, 304 insertions, 1204 deletions
diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index a8be02a0b9..a7ead83eef 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -44,9 +44,6 @@ #include "ardour/session_object.h" #include "ardour/data_type.h" -class PlaylistOverlapCacheTest; -class PlaylistLayeringTest; - namespace ARDOUR { class Session; @@ -225,10 +222,7 @@ public: framepos_t find_next_top_layer_position (framepos_t) const; uint32_t combine_ops() const { return _combine_ops; } - void relayer (boost::shared_ptr<Region>); - void relayer (boost::shared_ptr<Region>, double); - void suspend_relayer (); - void resume_relayer (); + uint64_t highest_layering_index () const; protected: friend class Session; @@ -355,7 +349,7 @@ public: boost::shared_ptr<Playlist> cut (framepos_t start, framecnt_t cnt, bool result_is_hidden); boost::shared_ptr<Playlist> copy (framepos_t start, framecnt_t cnt, bool result_is_hidden); - void relayer (RegionList const &); + void relayer (); void begin_undo (); void end_undo (); @@ -382,71 +376,6 @@ public: with its constituent regions */ virtual void pre_uncombine (std::vector<boost::shared_ptr<Region> >&, boost::shared_ptr<Region>) {} - -private: - friend class ::PlaylistOverlapCacheTest; - friend class ::PlaylistLayeringTest; - - /** A class which is used to store temporary (fractional) - * layer assignments for some regions. - */ - class TemporaryLayers - { - public: - void set (boost::shared_ptr<Region>, double); - double get (boost::shared_ptr<Region>) const; - - private: - typedef std::map<boost::shared_ptr<Region>, double> Map; - Map _map; - }; - - /** Class to sort by temporary layer, for use with std::list<>::sort() */ - class SortByTemporaryLayer - { - public: - SortByTemporaryLayer (TemporaryLayers const & t) - : _temporary_layers (t) {} - - bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) const { - return _temporary_layers.get (a) < _temporary_layers.get (b); - } - - private: - Playlist::TemporaryLayers const & _temporary_layers; - }; - - /** A cache of what overlaps what, for a given playlist in a given state. - * Divides a playlist up into time periods and notes which regions cover those - * periods, so that get() is reasonably quick. - */ - class OverlapCache - { - public: - OverlapCache (Playlist *); - - RegionList get (Evoral::Range<framepos_t>) const; - - private: - std::pair<int, int> cache_indices (Evoral::Range<framepos_t>) const; - - double _division_size; - std::vector<RegionList> _cache; - Evoral::Range<framepos_t> _range; - - static int const _divisions; - }; - - TemporaryLayers compute_temporary_layers (RegionList const &); - void commit_temporary_layers (TemporaryLayers const &); - - RegionList recursive_regions_touched (boost::shared_ptr<Region>, OverlapCache const &, boost::shared_ptr<Region>) const; - void recursive_regions_touched_sub (boost::shared_ptr<Region>, OverlapCache const &, boost::shared_ptr<Region>, RegionList &) const; - - void timestamp_layer_op (LayerOp, boost::shared_ptr<Region>); - uint64_t layer_op_counter; - - bool _relayer_suspended; }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index 4315ed7aa8..ab1559fc4a 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -65,6 +65,7 @@ namespace Properties { extern PBD::PropertyDescriptor<float> stretch; extern PBD::PropertyDescriptor<float> shift; extern PBD::PropertyDescriptor<PositionLockStyle> position_lock_style; + extern PBD::PropertyDescriptor<uint64_t> layering_index; }; class Playlist; @@ -112,7 +113,6 @@ class Region framepos_t start () const { return _start; } framecnt_t length () const { return _length; } layer_t layer () const { return _layer; } - Evoral::Range<framepos_t> bounds () const; framecnt_t source_length(uint32_t n) const; uint32_t max_source_level () const; @@ -202,7 +202,7 @@ class Region void cut_front (framepos_t new_position); void cut_end (framepos_t new_position); - void set_layer (layer_t l); /* ONLY Playlist should call this */ + void set_layer (layer_t l); /* ONLY Playlist can call this */ void raise (); void lower (); void raise_to_top (); @@ -252,8 +252,8 @@ class Region virtual boost::shared_ptr<Region> get_parent() const; - uint64_t last_layer_op (LayerOp) const; - void set_last_layer_op (LayerOp, uint64_t); + uint64_t layering_index () const { return _layering_index; } + void set_layering_index (uint64_t when) { _layering_index = when; } virtual bool is_dependent() const { return false; } virtual bool depends_on (boost::shared_ptr<Region> /*other*/) const { return false; } @@ -294,12 +294,11 @@ class Region void invalidate_transients (); - void drop_sources (); + void set_pending_layer (double); + bool reset_pending_layer (); + boost::optional<double> pending_layer () const; - /** @return our bounds the last time our relayer() method was called */ - Evoral::Range<framepos_t> last_relayer_bounds () const { - return Evoral::Range<framepos_t> (_last_relayer_bounds_from, _last_relayer_bounds_to); - } + void drop_sources (); protected: friend class RegionFactory; @@ -384,18 +383,15 @@ class Region PBD::Property<float> _stretch; PBD::Property<float> _shift; PBD::EnumProperty<PositionLockStyle> _position_lock_style; + PBD::Property<uint64_t> _layering_index; - /* XXX: could use a Evoral::Range<> but I'm too lazy to make PBD::Property serialize such a thing nicely */ - PBD::Property<framepos_t> _last_relayer_bounds_from; ///< from of our bounds last time relayer() was called - PBD::Property<framepos_t> _last_relayer_bounds_to; ///< to of our bounds last time relayer() was called - PBD::Property<uint64_t> _last_layer_op_add; - PBD::Property<uint64_t> _last_layer_op_bounds_change; - framecnt_t _last_length; framepos_t _last_position; mutable RegionEditState _first_edit; Timecode::BBT_Time _bbt_time; + boost::optional<double> _pending_layer; + void register_properties (); void use_sources (SourceList const &); diff --git a/libs/ardour/ardour/region_sorters.h b/libs/ardour/ardour/region_sorters.h index 0e3203ef20..baa3a3417d 100644 --- a/libs/ardour/ardour/region_sorters.h +++ b/libs/ardour/ardour/region_sorters.h @@ -36,22 +36,6 @@ struct RegionSortByLayer { } }; -struct RegionSortByAdd { - bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) { - return ( - (a->last_layer_op (LayerOpAdd) < b->last_layer_op (LayerOpAdd)) - ); - } -}; - -struct RegionSortByAddOrBounds { - bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) { - uint64_t const p = std::max (a->last_layer_op (LayerOpAdd), a->last_layer_op (LayerOpBoundsChange)); - uint64_t const q = std::max (b->last_layer_op (LayerOpAdd), b->last_layer_op (LayerOpBoundsChange)); - return p < q; - } -}; - } // namespace #endif /* __libardour_region_sorters_h__ */ diff --git a/libs/ardour/ardour/session_configuration_vars.h b/libs/ardour/ardour/session_configuration_vars.h index 57f390f100..87b317d3e8 100644 --- a/libs/ardour/ardour/session_configuration_vars.h +++ b/libs/ardour/ardour/session_configuration_vars.h @@ -47,8 +47,6 @@ CONFIG_VARIABLE_SPECIAL(std::string, audio_search_path, "audio-search-path", "", CONFIG_VARIABLE_SPECIAL(std::string, midi_search_path, "midi-search-path", "", search_path_expand) CONFIG_VARIABLE (std::string, bwf_country_code, "bwf-country-code", "US") CONFIG_VARIABLE (std::string, bwf_organization_code, "bwf-organization-code", "US") -CONFIG_VARIABLE (LayerModel, layer_model, "layer-model", AddOrBoundsChangeHigher) -CONFIG_VARIABLE (bool, relayer_on_all_edits, "relayer-on-all-edits", true) CONFIG_VARIABLE (std::string, auditioner_output_left, "auditioner-output-left", "default") CONFIG_VARIABLE (std::string, auditioner_output_right, "auditioner-output-right", "default") CONFIG_VARIABLE (bool, timecode_source_is_synced, "timecode-source-is-synced", true) diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index b5e5d89cc1..c2c7289329 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -409,12 +409,6 @@ namespace ARDOUR { ShortCrossfade }; - enum LayerModel { - LaterHigher, - AddOrBoundsChangeHigher, - AddHigher - }; - enum ListenPosition { AfterFaderListen, PreFaderListen @@ -592,11 +586,6 @@ namespace ARDOUR { FadeLogB }; - enum LayerOp { - LayerOpAdd, - LayerOpBoundsChange - }; - } // namespace ARDOUR @@ -613,7 +602,6 @@ std::istream& operator>>(std::istream& o, ARDOUR::PFLPosition& sf); std::istream& operator>>(std::istream& o, ARDOUR::AFLPosition& sf); std::istream& operator>>(std::istream& o, ARDOUR::RemoteModel& sf); std::istream& operator>>(std::istream& o, ARDOUR::ListenPosition& sf); -std::istream& operator>>(std::istream& o, ARDOUR::LayerModel& sf); std::istream& operator>>(std::istream& o, ARDOUR::InsertMergePolicy& sf); std::istream& operator>>(std::istream& o, ARDOUR::CrossfadeModel& sf); std::istream& operator>>(std::istream& o, ARDOUR::SyncSource& sf); @@ -634,7 +622,6 @@ std::ostream& operator<<(std::ostream& o, const ARDOUR::PFLPosition& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::AFLPosition& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::RemoteModel& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::ListenPosition& sf); -std::ostream& operator<<(std::ostream& o, const ARDOUR::LayerModel& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::InsertMergePolicy& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::CrossfadeModel& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::SyncSource& sf); diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index 83399d2962..9a227bf7a5 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -1510,6 +1510,8 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo } i_am_the_modifier++; + + region->set_pending_layer (max_layer); _playlist->add_region (region, (*ci)->start, 1, non_layered()); i_am_the_modifier--; diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 12de366c79..fcf3b031ad 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -73,7 +73,6 @@ setup_enum_writer () RemoteModel _RemoteModel; DenormalModel _DenormalModel; CrossfadeModel _CrossfadeModel; - LayerModel _LayerModel; InsertMergePolicy _InsertMergePolicy; ListenPosition _ListenPosition; SampleFormat _SampleFormat; @@ -264,11 +263,6 @@ setup_enum_writer () REGISTER_ENUM (ShortCrossfade); REGISTER (_CrossfadeModel); - REGISTER_ENUM (LaterHigher); - REGISTER_ENUM (AddOrBoundsChangeHigher); - REGISTER_ENUM (AddHigher); - REGISTER (_LayerModel); - REGISTER_ENUM (InsertMergeReject); REGISTER_ENUM (InsertMergeRelax); REGISTER_ENUM (InsertMergeReplace); @@ -711,19 +705,6 @@ std::ostream& operator<<(std::ostream& o, const ListenPosition& var) std::string s = enum_2_string (var); return o << s; } -std::istream& operator>>(std::istream& o, LayerModel& var) -{ - std::string s; - o >> s; - var = (LayerModel) string_2_enum (s, var); - return o; -} - -std::ostream& operator<<(std::ostream& o, const LayerModel& var) -{ - std::string s = enum_2_string (var); - return o << s; -} std::istream& operator>>(std::istream& o, InsertMergePolicy& var) { diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index a6925e444c..7ef59645d1 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -30,7 +30,6 @@ #include "pbd/convert.h" #include "pbd/failed_constructor.h" -#include "pbd/stacktrace.h" #include "pbd/stateful_diff_command.h" #include "pbd/xml++.h" @@ -187,8 +186,6 @@ Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, boo in_partition = false; subcnt = 0; _frozen = other->_frozen; - - layer_op_counter = other->layer_op_counter; } Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, framecnt_t cnt, string str, bool hide) @@ -256,6 +253,7 @@ Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, f plist.add (Properties::length, len); plist.add (Properties::name, new_name); plist.add (Properties::layer, region->layer()); + plist.add (Properties::layering_index, region->layering_index()); new_region = RegionFactory::RegionFactory::create (region, plist); @@ -318,9 +316,7 @@ Playlist::init (bool hide) in_partition = false; subcnt = 0; _frozen = false; - layer_op_counter = 0; _combine_ops = 0; - _relayer_suspended = false; _session.history().BeginUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::begin_undo, this)); _session.history().EndUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::end_undo, this)); @@ -485,8 +481,6 @@ Playlist::notify_region_moved (boost::shared_ptr<Region> r) { Evoral::RangeMove<framepos_t> const move (r->last_position (), r->length (), r->position ()); - /* We could timestamp the region's layer op here, but we're doing it in region_bounds_changed */ - if (holding_state ()) { pending_range_moves.push_back (move); @@ -503,8 +497,6 @@ Playlist::notify_region_moved (boost::shared_ptr<Region> r) void Playlist::notify_region_start_trimmed (boost::shared_ptr<Region> r) { - timestamp_layer_op (LayerOpBoundsChange, r); - if (r->position() >= r->last_position()) { /* trimmed shorter */ return; @@ -528,8 +520,6 @@ Playlist::notify_region_start_trimmed (boost::shared_ptr<Region> r) void Playlist::notify_region_end_trimmed (boost::shared_ptr<Region> r) { - timestamp_layer_op (LayerOpBoundsChange, r); - if (r->length() < r->last_length()) { /* trimmed shorter */ } @@ -556,8 +546,6 @@ Playlist::notify_region_added (boost::shared_ptr<Region> r) as though it could be. */ - timestamp_layer_op (LayerOpAdd, r); - if (holding_state()) { pending_adds.insert (r); pending_contents_change = true; @@ -566,7 +554,6 @@ Playlist::notify_region_added (boost::shared_ptr<Region> r) pending_contents_change = false; RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */ ContentsChanged (); /* EMIT SIGNAL */ - relayer (r); } } @@ -584,35 +571,31 @@ Playlist::flush_notifications (bool from_undo) in_flush = true; - /* We have: - - pending_bounds: regions whose bounds position and/or length changes - pending_removes: regions which were removed - pending_adds: regions which were added - pending_length: true if the playlist length might have changed - pending_contents_change: true if there was almost any change in the playlist - pending_range_moves: details of periods of time that have been moved about (when regions have been moved) - - */ - if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) { regions_changed = true; } - /* Make a list of regions that need relayering */ - RegionList regions_to_relayer; + /* we have no idea what order the regions ended up in pending + bounds (it could be based on selection order, for example). + so, to preserve layering in the "most recently moved is higher" + model, sort them by existing layer, then timestamp them. + */ + + // RegionSortByLayer cmp; + // pending_bounds.sort (cmp); for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) { - regions_to_relayer.push_back (*r); dependent_checks_needed.insert (*r); } for (s = pending_removes.begin(); s != pending_removes.end(); ++s) { remove_dependents (*s); + // cerr << _name << " sends RegionRemoved\n"; RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */ } for (s = pending_adds.begin(); s != pending_adds.end(); ++s) { + // cerr << _name << " sends RegionAdded\n"; /* don't emit RegionAdded signal until relayering is done, so that the region is fully setup by the time anyone hear's that its been added @@ -621,14 +604,18 @@ Playlist::flush_notifications (bool from_undo) } if (regions_changed || pending_contents_change) { + if (!in_set_state) { + relayer (); + } pending_contents_change = false; + // cerr << _name << " sends 5 contents change @ " << get_microseconds() << endl; ContentsChanged (); /* EMIT SIGNAL */ + // cerr << _name << "done contents change @ " << get_microseconds() << endl; } for (s = pending_adds.begin(); s != pending_adds.end(); ++s) { (*s)->clear_changes (); RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */ - regions_to_relayer.push_back (*s); } for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) { @@ -643,14 +630,6 @@ Playlist::flush_notifications (bool from_undo) RegionsExtended (pending_region_extensions); } - if (!regions_to_relayer.empty () && !from_undo) { - relayer (regions_to_relayer); - } - - if (pending_layering) { - LayeringChanged (); /* EMIT SIGNAL */ - } - clear_pending (); in_flush = false; @@ -686,6 +665,7 @@ Playlist::flush_notifications (bool from_undo) } if (itimes >= 1) { + region->set_pending_layer (DBL_MAX); add_region_internal (region, pos); pos += region->length(); --itimes; @@ -698,6 +678,7 @@ Playlist::flush_notifications (bool from_undo) for (int i = 0; i < itimes; ++i) { boost::shared_ptr<Region> copy = RegionFactory::create (region, true); + copy->set_pending_layer (DBL_MAX); add_region_internal (copy, pos); pos += region->length(); } @@ -718,6 +699,7 @@ Playlist::flush_notifications (bool from_undo) plist.add (Properties::layer, region->layer()); boost::shared_ptr<Region> sub = RegionFactory::create (region, plist); + sub->set_pending_layer (DBL_MAX); add_region_internal (sub, pos); } } @@ -758,6 +740,11 @@ Playlist::flush_notifications (bool from_undo) possibly_splice_unlocked (position, region->length(), region); + if (!holding_state ()) { + /* layers get assigned from XML state, and are not reset during undo/redo */ + relayer (); + } + /* we need to notify the existence of new region before checking dependents. Ick. */ notify_region_added (region); @@ -780,6 +767,7 @@ Playlist::flush_notifications (bool from_undo) _splicing = true; remove_region_internal (old); + newr->set_pending_layer (newr->layer ()); add_region_internal (newr, pos); _splicing = old_sp; @@ -817,6 +805,7 @@ Playlist::flush_notifications (bool from_undo) possibly_splice_unlocked (pos, -distance); if (!holding_state ()) { + relayer (); remove_dependents (region); } @@ -873,16 +862,12 @@ Playlist::flush_notifications (bool from_undo) * start and end if cutting == true. Regions that lie entirely within start and end are always * removed. */ + void Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist) { RegionList new_regions; - /* Don't relayer regions that are created during this operation; leave them - on the same region as the original. - */ - suspend_relayer (); - { RegionLock rlock (this); @@ -961,7 +946,8 @@ Playlist::flush_notifications (bool from_undo) plist.add (Properties::start, current->start() + (pos2 - pos1)); plist.add (Properties::length, pos3 - pos2); plist.add (Properties::name, new_name); - plist.add (Properties::layer, current->layer()); + plist.add (Properties::layer, current->layer ()); + plist.add (Properties::layering_index, current->layering_index ()); plist.add (Properties::automatic, true); plist.add (Properties::left_of_split, true); plist.add (Properties::right_of_split, true); @@ -980,7 +966,8 @@ Playlist::flush_notifications (bool from_undo) plist.add (Properties::start, current->start() + (pos3 - pos1)); plist.add (Properties::length, pos4 - pos3); plist.add (Properties::name, new_name); - plist.add (Properties::layer, current->layer()); + plist.add (Properties::layer, current->layer ()); + plist.add (Properties::layering_index, current->layering_index ()); plist.add (Properties::automatic, true); plist.add (Properties::right_of_split, true); @@ -1018,7 +1005,8 @@ Playlist::flush_notifications (bool from_undo) plist.add (Properties::start, current->start() + (pos2 - pos1)); plist.add (Properties::length, pos4 - pos2); plist.add (Properties::name, new_name); - plist.add (Properties::layer, current->layer()); + plist.add (Properties::layer, current->layer ()); + plist.add (Properties::layering_index, current->layering_index ()); plist.add (Properties::automatic, true); plist.add (Properties::left_of_split, true); @@ -1061,7 +1049,8 @@ Playlist::flush_notifications (bool from_undo) plist.add (Properties::start, current->start()); plist.add (Properties::length, pos3 - pos1); plist.add (Properties::name, new_name); - plist.add (Properties::layer, current->layer()); + plist.add (Properties::layer, current->layer ()); + plist.add (Properties::layering_index, current->layering_index ()); plist.add (Properties::automatic, true); plist.add (Properties::right_of_split, true); @@ -1108,8 +1097,6 @@ Playlist::flush_notifications (bool from_undo) for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) { check_dependents (*i, false); } - - resume_relayer (); } boost::shared_ptr<Playlist> @@ -1210,7 +1197,7 @@ Playlist::flush_notifications (bool from_undo) int itimes = (int) floor (times); framepos_t pos = position; framecnt_t const shift = other->_get_extent().second; - layer_t top_layer = regions.size(); + layer_t top = top_layer (); while (itimes--) { for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) { @@ -1220,7 +1207,7 @@ Playlist::flush_notifications (bool from_undo) the ordering they had in the original playlist. */ - copy_of_region->set_layer (copy_of_region->layer() + top_layer); + copy_of_region->set_pending_layer (copy_of_region->layer() + top); add_region_internal (copy_of_region, (*i)->position() + pos); } pos += shift; @@ -1242,6 +1229,7 @@ Playlist::flush_notifications (bool from_undo) while (itimes--) { boost::shared_ptr<Region> copy = RegionFactory::create (region, true); + copy->set_pending_layer (DBL_MAX); add_region_internal (copy, pos); pos += region->length(); } @@ -1259,6 +1247,7 @@ Playlist::flush_notifications (bool from_undo) plist.add (Properties::name, name); boost::shared_ptr<Region> sub = RegionFactory::create (region, plist); + sub->set_pending_layer (DBL_MAX); add_region_internal (sub, pos); } } @@ -1360,6 +1349,8 @@ Playlist::flush_notifications (bool from_undo) plist.add (Properties::length, before); plist.add (Properties::name, before_name); plist.add (Properties::left_of_split, true); + plist.add (Properties::layering_index, region->layering_index ()); + plist.add (Properties::layer, region->layer ()); /* note: we must use the version of ::create with an offset here, since it supplies that offset to the Region constructor, which @@ -1377,6 +1368,8 @@ Playlist::flush_notifications (bool from_undo) plist.add (Properties::length, after); plist.add (Properties::name, after_name); plist.add (Properties::right_of_split, true); + plist.add (Properties::layering_index, region->layering_index ()); + plist.add (Properties::layer, region->layer ()); /* same note as above */ right = RegionFactory::create (region, before, plist); @@ -1470,8 +1463,6 @@ Playlist::flush_notifications (bool from_undo) if (what_changed.contains (Properties::position)) { - timestamp_layer_op (LayerOpBoundsChange, region); - /* remove it from the list then add it back in the right place again. */ @@ -1512,7 +1503,7 @@ Playlist::flush_notifications (bool from_undo) pending_bounds.push_back (region); } else { notify_contents_changed (); - relayer (region); + relayer (); check_dependents (region, false); } } @@ -1572,9 +1563,9 @@ Playlist::flush_notifications (bool from_undo) notify_region_start_trimmed (region); } - if (what_changed.contains (Properties::layer)) { - notify_layering_changed (); - } + /* don't notify about layer changes, since we are the only object that can initiate + them, and we notify in ::relayer() + */ if (what_changed.contains (our_interests)) { save = true; @@ -2134,7 +2125,6 @@ Playlist::flush_notifications (bool from_undo) return -1; } - suspend_relayer (); freeze (); plist = node.properties(); @@ -2196,7 +2186,7 @@ Playlist::flush_notifications (bool from_undo) } add_region (region, region->position(), 1.0); - + region->resume_property_changes (); } @@ -2217,7 +2207,6 @@ Playlist::flush_notifications (bool from_undo) thaw (); notify_contents_changed (); - resume_relayer (); in_set_state--; first_set_state = false; @@ -2345,277 +2334,189 @@ Playlist::set_edit_mode (EditMode mode) _edit_mode = mode; } -/** Relayer a region. See the other relayer() methods for commentary. */ +struct RelayerSort { + bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) { + return a->layering_index() < b->layering_index(); + } +}; + void -Playlist::relayer (boost::shared_ptr<Region> region) +Playlist::relayer () { - if (_relayer_suspended) { + /* never compute layers when changing state for undo/redo or setting from XML */ + + if (in_update || in_set_state) { return; } - - RegionList r; - r.push_back (region); - relayer (r); -} -Playlist::TemporaryLayers -Playlist::compute_temporary_layers (RegionList const & relayer_regions) -{ - TemporaryLayers temporary_layers; - OverlapCache cache (this); + bool changed = false; - for (RegionList::const_iterator i = relayer_regions.begin(); i != relayer_regions.end(); ++i) { + /* Build up a new list of regions on each layer, stored in a set of lists + each of which represent some period of time on some layer. The idea + is to avoid having to search the entire region list to establish whether + each region overlaps another */ - DEBUG_TRACE (DEBUG::Layering, string_compose ("Compute temporary layer for %1\n", (*i)->name())); - - /* current_overlaps: regions that overlap *i now */ - RegionList current_overlaps = cache.get ((*i)->bounds ()); - current_overlaps.remove (*i); + /* how many pieces to divide this playlist's time up into */ + int const divisions = 512; - DEBUG_TRACE (DEBUG::Layering, "Current overlaps:\n"); - for (RegionList::iterator j = current_overlaps.begin(); j != current_overlaps.end(); ++j) { - DEBUG_TRACE (DEBUG::Layering, string_compose ("\t%1\n", (*j)->name())); - } - - /* overlaps_to_preserve: regions that overlap *i now, but which aren't being - worked on during this relayer: these will have their relationship with - *i preserved. - */ - RegionList overlaps_to_preserve; + /* find the start and end positions of the regions on this playlist */ + framepos_t start = INT64_MAX; + framepos_t end = 0; + for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { + start = min (start, (*i)->position()); + end = max (end, (*i)->position() + (*i)->length()); + } - /* overlaps_to_check: regions that overlap *i now, and must be checked to - see if *i is still on the correct layer with respect to them (according - to current layering rules). - */ - RegionList overlaps_to_check; + /* hence the size of each time division */ + double const division_size = (end - start) / double (divisions); - if (_session.config.get_relayer_on_all_edits () || (*i)->last_layer_op (LayerOpAdd) > (*i)->last_layer_op (LayerOpBoundsChange)) { - /* We're configured to relayer on all edits, or this region has had - no edit since it was added to the playlist, so we're relayering - the whole lot; in this case there are no `overlaps_to_preserve'. - */ - overlaps_to_check = current_overlaps; - } else { - /* We're only relayering new overlaps; find them */ - RegionList last_overlaps = cache.get ((*i)->last_relayer_bounds ()); - last_overlaps.remove (*i); - for (RegionList::const_iterator j = current_overlaps.begin(); j != current_overlaps.end(); ++j) { - if (find (last_overlaps.begin(), last_overlaps.end(), *j) == last_overlaps.end()) { - /* This is a new overlap, which must be checked */ - overlaps_to_check.push_back (*j); - } else { - /* This is an existing overlap, which must be preserved */ - overlaps_to_preserve.push_back (*j); - } - } - } + vector<vector<RegionList> > layers; + layers.push_back (vector<RegionList> (divisions)); - if (overlaps_to_check.empty ()) { - /* There are no overlaps to check, so just leave everything as it is */ - continue; - } + RegionList copy = regions.rlist(); + RegionList pending; - DEBUG_TRACE (DEBUG::Layering, "Overlaps to check:\n"); - for (RegionList::iterator j = overlaps_to_check.begin(); j != overlaps_to_check.end(); ++j) { - DEBUG_TRACE (DEBUG::Layering, string_compose ("\t%1\n", (*j)->name())); - } - - /* Put *i on our overlaps_to_check_list */ - overlaps_to_check.push_back (*i); + /* Remove regions with pending relayers */ + for (RegionList::iterator i = copy.begin(); i != copy.end(); ) { - /* And sort it according to the current layer model */ - switch (_session.config.get_layer_model()) { - case LaterHigher: - overlaps_to_check.sort (RegionSortByPosition ()); - break; - case AddOrBoundsChangeHigher: - overlaps_to_check.sort (RegionSortByAddOrBounds ()); - break; - case AddHigher: - overlaps_to_check.sort (RegionSortByAdd ()); - break; + RegionList::iterator j = i; + ++j; + + if ((*i)->pending_layer()) { + pending.push_back (*i); + copy.erase (i); } - /* Now find *i in our overlaps_to_check list; within this list it will be in the - right place wrt the current layering rules, so we can work out the layers of the - nearest regions below and above. - */ - double previous_layer = -DBL_MAX; - double next_layer = DBL_MAX; - RegionList::const_iterator j = overlaps_to_check.begin(); - while (*j != *i) { - previous_layer = temporary_layers.get (*j); + i = j; + } + + /* Sort the remainder */ + copy.sort (RelayerSort ()); + + /* Re-insert the pending layers in the right places */ + for (RegionList::iterator i = pending.begin(); i != pending.end(); ++i) { + RegionList::iterator j = copy.begin(); + while (j != copy.end ()) { + if ((*j)->pending_layer().get_value_or ((*j)->layer ()) > (*i)->pending_layer().get ()) { + break; + } ++j; } + copy.insert (j, *i); + } - /* we must have found *i */ - assert (j != overlaps_to_check.end ()); + bool had_pending = false; - ++j; - if (j != overlaps_to_check.end ()) { - next_layer = temporary_layers.get (*j); - } + for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) { - if (next_layer < previous_layer) { - /* If this happens, it means that it's impossible to put *i between overlaps_to_check - in a way that satisfies the current layering rule. So we'll punt and put *i - above previous_layer. - */ - next_layer = DBL_MAX; + /* reset the pending layer for every region now that we're relayering */ + if ((*i)->reset_pending_layer ()) { + had_pending = true; } - /* Now we know where *i and overlaps_to_preserve should go: between previous_layer and - next_layer. + /* find the time divisions that this region covers; if there are no regions on the list, + division_size will equal 0 and in this case we'll just say that + start_division = end_division = 0. */ - - DEBUG_TRACE (DEBUG::Layering, string_compose ("%1 and deps need to go between %2 and %3\n", (*i)->name(), previous_layer, next_layer)); - - /* Recurse into overlaps_to_preserve to find dependents */ - RegionList recursed_overlaps_to_preserve; - - for (RegionList::const_iterator k = overlaps_to_preserve.begin(); k != overlaps_to_preserve.end(); ++k) { - recursed_overlaps_to_preserve.push_back (*k); - RegionList touched = recursive_regions_touched (*k, cache, *i); - for (RegionList::iterator m = touched.begin(); m != touched.end(); ++m) { - if (find (recursed_overlaps_to_preserve.begin(), recursed_overlaps_to_preserve.end(), *m) == recursed_overlaps_to_preserve.end()) { - recursed_overlaps_to_preserve.push_back (*m); - } + int start_division = 0; + int end_division = 0; + + if (division_size > 0) { + start_division = floor ( ((*i)->position() - start) / division_size); + end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size ); + if (end_division == divisions) { + end_division--; } } - /* Put *i into the overlaps_to_preserve list */ - recursed_overlaps_to_preserve.push_back (*i); + assert (divisions == 0 || end_division < divisions); - /* Sort it by layer, so that we preserve layering */ - recursed_overlaps_to_preserve.sort (SortByTemporaryLayer (temporary_layers)); - - /* Divide available space up into chunks so that we can relayer everything in that space */ - double const space = (next_layer - previous_layer) / (recursed_overlaps_to_preserve.size() + 1); - - /* And relayer */ - int m = 1; - for (RegionList::const_iterator k = recursed_overlaps_to_preserve.begin(); k != recursed_overlaps_to_preserve.end(); ++k) { - temporary_layers.set (*k, previous_layer + space * m); - ++m; - } - } + /* find the lowest layer that this region can go on */ + size_t j = layers.size(); + while (j > 0) { + /* try layer j - 1; it can go on if it overlaps no other region + that is already on that layer + */ - return temporary_layers; -} + bool overlap = false; + for (int k = start_division; k <= end_division; ++k) { + RegionList::iterator l = layers[j-1][k].begin (); + while (l != layers[j-1][k].end()) { + if ((*l)->overlap_equivalent (*i)) { + overlap = true; + break; + } + l++; + } -/** Take a list of temporary layer indices and set up the layers of all regions - * based on them. - */ -void -Playlist::commit_temporary_layers (TemporaryLayers const & temporary_layers) -{ - /* Sort all the playlist's regions by layer, ascending */ - RegionList all_regions = regions.rlist (); - all_regions.sort (SortByTemporaryLayer (temporary_layers)); + if (overlap) { + break; + } + } - DEBUG_TRACE (DEBUG::Layering, "Commit layering:\n"); + if (overlap) { + /* overlap, so we must use layer j */ + break; + } - for (RegionList::iterator i = all_regions.begin(); i != all_regions.end(); ++i) { + --j; + } - /* Go through the regions that we have already layered and hence work - out the maximum layer index that is in used at some point during - region *i. - */ - - layer_t max_layer_here = 0; - bool have_overlap = false; - for (RegionList::iterator j = all_regions.begin(); j != i; ++j) { - if ((*j)->overlap_equivalent (*i)) { - max_layer_here = max ((*j)->layer (), max_layer_here); - have_overlap = true; - } + if (j == layers.size()) { + /* we need a new layer for this region */ + layers.push_back (vector<RegionList> (divisions)); } - if (have_overlap) { - /* *i overlaps something, so put it on the next available layer */ - (*i)->set_layer (max_layer_here + 1); - } else { - /* no overlap, so put on the bottom layer */ - (*i)->set_layer (0); + /* put a reference to this region in each of the divisions that it exists in */ + for (int k = start_division; k <= end_division; ++k) { + layers[j][k].push_back (*i); } - - DEBUG_TRACE (DEBUG::Layering, string_compose ("\t%1 temporary %2 committed %3\n", (*i)->name(), temporary_layers.get (*i), (*i)->layer())); - } -} -/** Relayer a list of regions. - * - * Taking each region R in turn, this method examines the regions O that overlap R in time. - * If the session configuration option "relayer-on-all-moves" is false, we reduce O so that - * it contains only those regions with which new overlaps have been formed since the last - * relayer. - * - * We then change the layer of R and its indirect overlaps so that R meets the current - * Session layer model with respect to O. See doc/layering. - */ + if ((*i)->layer() != j) { + changed = true; + } -void -Playlist::relayer (RegionList const & relayer_regions) -{ - if (_relayer_suspended) { - return; + (*i)->set_layer (j); } - /* We do this in two parts: first; compute `temporary layer' indices for - regions on the playlist. These are (possibly) fractional indices, which - are a convenient means of working with things when you want to insert layers - between others. - */ - - TemporaryLayers temporary_layers = compute_temporary_layers (relayer_regions); - - /* Second, we fix up these temporary layers and `commit' them by writing - them to the regions involved. - */ - - commit_temporary_layers (temporary_layers); -} - -/** Put a region on some fractional layer and sort everything else out around it. - * This can be used to force a region into some layering; for example, calling - * this method with temporary_layer == -0.5 will put the region at the bottom of - * the stack. - */ - -void -Playlist::relayer (boost::shared_ptr<Region> region, double temporary_layer) -{ - if (_relayer_suspended) { - return; + if (changed) { + notify_layering_changed (); } - TemporaryLayers t; - t.set (region, temporary_layer); - commit_temporary_layers (t); + if (had_pending) { + uint64_t i = 0; + for (RegionList::iterator j = copy.begin(); j != copy.end(); ++j) { + (*j)->set_layering_index (i++); + } + } } void Playlist::raise_region (boost::shared_ptr<Region> region) { - relayer (region, region->layer() + 1.5); + region->set_pending_layer (region->layer() + 1.5); + relayer (); } void Playlist::lower_region (boost::shared_ptr<Region> region) { - relayer (region, region->layer() - 1.5); + region->set_pending_layer (region->layer() - 1.5); + relayer (); } void Playlist::raise_region_to_top (boost::shared_ptr<Region> region) { - relayer (region, max_layer); + region->set_pending_layer (DBL_MAX); + relayer (); } void Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region) { - relayer (region, -0.5); + region->set_pending_layer (-0.5); + relayer (); } void @@ -2751,23 +2652,8 @@ Playlist::set_frozen (bool yn) } void -Playlist::timestamp_layer_op (LayerOp op, boost::shared_ptr<Region> region) -{ - region->set_last_layer_op (op, ++layer_op_counter); -} - - -/** Find the next or previous region after `region' (next if dir > 0, previous otherwise) - * and swap its position with `region'. - */ -void Playlist::shuffle (boost::shared_ptr<Region> region, int dir) { - /* As regards layering, the calls we make to set_position() will - perform layering as if the regions had been moved, which I think - is about right. - */ - bool moved = false; if (region->locked()) { @@ -2872,9 +2758,13 @@ Playlist::shuffle (boost::shared_ptr<Region> region, int dir) _shuffling = false; if (moved) { + + relayer (); check_dependents (region, false); + notify_contents_changed(); } + } bool @@ -3293,145 +3183,16 @@ Playlist::set_orig_track_id (const PBD::ID& id) _orig_track_id = id; } -/** Set the temporary layer for a region */ -void -Playlist::TemporaryLayers::set (boost::shared_ptr<Region> r, double l) -{ - _map[r] = l; -} - -/** Return the temporary layer for a region, if one has been specified - * to this TemporaryLayers object; if not return the region's current - * layer. - */ -double -Playlist::TemporaryLayers::get (boost::shared_ptr<Region> r) const +uint64_t +Playlist::highest_layering_index () const { - Map::const_iterator i = _map.find (r); - if (i != _map.end ()) { - return i->second; - } - - return double (r->layer ()); -} - -int const Playlist::OverlapCache::_divisions = 512; - -/** Set up an OverlapCache for a playlist; the cache will only be valid until - * the Playlist is changed. - */ -Playlist::OverlapCache::OverlapCache (Playlist* playlist) - : _range (0, 0) -{ - /* Find the start and end positions of the regions on this playlist */ - _range = Evoral::Range<framepos_t> (max_framepos, 0); - RegionList const & rl = playlist->region_list().rlist (); - for (RegionList::const_iterator i = rl.begin(); i != rl.end(); ++i) { - Evoral::Range<framepos_t> const b = (*i)->bounds (); - _range.from = min (_range.from, b.from); - _range.to = max (_range.to, b.to); - } - - /* Hence the size of each time divison */ - _division_size = (_range.to - _range.from) / double (_divisions); - - _cache.resize (_divisions); - - /* Build the cache */ - for (RegionList::const_iterator i = rl.begin(); i != rl.end(); ++i) { - pair<int, int> ind = cache_indices ((*i)->bounds ()); - for (int j = ind.first; j < ind.second; ++j) { - _cache[j].push_back (*i); - } - } -} - -/** @param range Range, in frames. - * @return From and to cache indices for (to is exclusive). - */ -pair<int, int> -Playlist::OverlapCache::cache_indices (Evoral::Range<framepos_t> range) const -{ - range.from = max (range.from, _range.from); - range.to = min (range.to, _range.to); - - pair<int, int> const p = make_pair ( - floor ((range.from - _range.from) / _division_size), - ceil ((range.to - _range.from) / _division_size) - ); - - assert (p.first >= 0); - assert (p.second <= _divisions); - - return p; -} - -/** Return the regions that overlap a given range. The returned list - * is not guaranteed to be in the same order as the Playlist that it was - * generated from. - */ -Playlist::RegionList -Playlist::OverlapCache::get (Evoral::Range<framepos_t> range) const -{ - if (_range.from == max_framepos) { - return RegionList (); - } - - RegionList r; + RegionLock rlock (const_cast<Playlist *> (this)); - pair<int, int> ind = cache_indices (range); - for (int i = ind.first; i < ind.second; ++i) { - for (RegionList::const_iterator j = _cache[i].begin(); j != _cache[i].end(); ++j) { - if ((*j)->coverage (range.from, range.to) != OverlapNone) { - r.push_back (*j); - } - } + uint64_t h = 0; + for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { + h = max (h, (*i)->layering_index ()); } - r.sort (); - r.unique (); - - return r; -} - -void -Playlist::suspend_relayer () -{ - _relayer_suspended = true; -} - -void -Playlist::resume_relayer () -{ - _relayer_suspended = false; -} - -/** Examine a region and return regions which overlap it, and also those which overlap those which overlap etc. - * @param ignore Optional region which should be treated as if it doesn't exist (ie not returned in the list, - * and not recursed into). - */ -Playlist::RegionList -Playlist::recursive_regions_touched (boost::shared_ptr<Region> region, OverlapCache const & cache, boost::shared_ptr<Region> ignore) const -{ - RegionList touched; - recursive_regions_touched_sub (region, cache, ignore, touched); - - touched.remove (region); - return touched; -} - -/** Recursive sub-routine of recursive_regions_touched */ -void -Playlist::recursive_regions_touched_sub ( - boost::shared_ptr<Region> region, OverlapCache const & cache, boost::shared_ptr<Region> ignore, RegionList & touched - ) const -{ - RegionList r = cache.get (region->bounds ()); - for (RegionList::iterator i = r.begin(); i != r.end(); ++i) { - if (find (touched.begin(), touched.end(), *i) == touched.end() && *i != ignore) { - touched.push_back (*i); - recursive_regions_touched_sub (*i, cache, ignore, touched); - } - } + return h; } diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index 89abdbd230..0ec8ee001b 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -73,10 +73,7 @@ namespace ARDOUR { PBD::PropertyDescriptor<float> stretch; PBD::PropertyDescriptor<float> shift; PBD::PropertyDescriptor<PositionLockStyle> position_lock_style; - PBD::PropertyDescriptor<framepos_t> last_relayer_bounds_from; - PBD::PropertyDescriptor<framepos_t> last_relayer_bounds_to; - PBD::PropertyDescriptor<uint64_t> last_layer_op_add; - PBD::PropertyDescriptor<uint64_t> last_layer_op_bounds_change; + PBD::PropertyDescriptor<uint64_t> layering_index; } } @@ -131,14 +128,8 @@ Region::make_property_quarks () DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n", Properties::shift.property_id)); Properties::position_lock_style.property_id = g_quark_from_static_string (X_("positional-lock-style")); DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position_lock_style = %1\n", Properties::position_lock_style.property_id)); - Properties::last_relayer_bounds_from.property_id = g_quark_from_static_string (X_("last-relayer-bounds-from")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for last_relayer_bounds_from = %1\n", Properties::last_relayer_bounds_from.property_id)); - Properties::last_relayer_bounds_to.property_id = g_quark_from_static_string (X_("last-relayer-bounds-to")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for last_relayer_bounds_to = %1\n", Properties::last_relayer_bounds_to.property_id)); - Properties::last_layer_op_add.property_id = g_quark_from_static_string (X_("last-layer-op-add")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for last_layer_op_add = %1\n", Properties::last_layer_op_add.property_id)); - Properties::last_layer_op_bounds_change.property_id = g_quark_from_static_string (X_("last-layer-op-bounds-change")); - DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for last_layer_op_bounds_change = %1\n", Properties::last_layer_op_bounds_change.property_id)); + Properties::layering_index.property_id = g_quark_from_static_string (X_("layering-index")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layering_index = %1\n", Properties::layering_index.property_id)); } void @@ -169,10 +160,7 @@ Region::register_properties () add_property (_stretch); add_property (_shift); add_property (_position_lock_style); - add_property (_last_relayer_bounds_from); - add_property (_last_relayer_bounds_to); - add_property (_last_layer_op_add); - add_property (_last_layer_op_bounds_change); + add_property (_layering_index); } #define REGION_DEFAULT_STATE(s,l) \ @@ -199,10 +187,7 @@ Region::register_properties () , _stretch (Properties::stretch, 1.0) \ , _shift (Properties::shift, 1.0) \ , _position_lock_style (Properties::position_lock_style, _type == DataType::AUDIO ? AudioTime : MusicTime) \ - , _last_relayer_bounds_from (Properties::last_relayer_bounds_from, 0) \ - , _last_relayer_bounds_to (Properties::last_relayer_bounds_to, 0) \ - , _last_layer_op_add (Properties::last_layer_op_add, 0) \ - , _last_layer_op_bounds_change (Properties::last_layer_op_bounds_change, 0) + , _layering_index (Properties::layering_index, 0) #define REGION_COPY_STATE(other) \ _sync_marked (Properties::sync_marked, other->_sync_marked) \ @@ -228,10 +213,7 @@ Region::register_properties () , _stretch (Properties::stretch, other->_stretch) \ , _shift (Properties::shift, other->_shift) \ , _position_lock_style (Properties::position_lock_style, other->_position_lock_style) \ - , _last_relayer_bounds_from (Properties::last_relayer_bounds_from, other->_last_relayer_bounds_from) \ - , _last_relayer_bounds_to (Properties::last_relayer_bounds_to, other->_last_relayer_bounds_to) \ - , _last_layer_op_add (Properties::last_layer_op_add, other->_last_layer_op_add) \ - , _last_layer_op_bounds_change (Properties::last_layer_op_bounds_change, other->_last_layer_op_bounds_change) + , _layering_index (Properties::layering_index, other->_layering_index) /* derived-from-derived constructor (no sources in constructor) */ Region::Region (Session& s, framepos_t start, framecnt_t length, const string& name, DataType type) @@ -243,6 +225,7 @@ Region::Region (Session& s, framepos_t start, framecnt_t length, const string& n , _first_edit (EditChangesNothing) { register_properties (); + /* no sources at this point */ } @@ -1134,12 +1117,9 @@ Region::set_layer (layer_t l) { if (_layer != l) { _layer = l; + send_change (Properties::layer); } - - Evoral::Range<framepos_t> const b = bounds (); - _last_relayer_bounds_from = b.from; - _last_relayer_bounds_to = b.to; } XMLNode& @@ -1330,19 +1310,6 @@ Region::send_change (const PropertyChange& what_changed) } } -void -Region::set_last_layer_op (LayerOp op, uint64_t when) -{ - switch (op) { - case LayerOpAdd: - _last_layer_op_add = when; - break; - case LayerOpBoundsChange: - _last_layer_op_bounds_change = when; - break; - } -} - bool Region::overlap_equivalent (boost::shared_ptr<const Region> other) const { @@ -1683,24 +1650,22 @@ Region::post_set (const PropertyChange& pc) } } -uint64_t -Region::last_layer_op (LayerOp op) const +void +Region::set_pending_layer (double l) { - switch (op) { - case LayerOpAdd: - return _last_layer_op_add; - case LayerOpBoundsChange: - return _last_layer_op_bounds_change; - } - - /* NOTREACHED */ - return 0; + _pending_layer = l; } -Evoral::Range<framepos_t> -Region::bounds () const +bool +Region::reset_pending_layer () { - return Evoral::Range<framepos_t> (_position, _position + _length); + bool const had = _pending_layer; + _pending_layer = boost::optional<double> (); + return had; } - +boost::optional<double> +Region::pending_layer () const +{ + return _pending_layer; +} diff --git a/libs/ardour/run-tests.sh b/libs/ardour/run-tests.sh index 76fc4f8aea..379678c968 100755 --- a/libs/ardour/run-tests.sh +++ b/libs/ardour/run-tests.sh @@ -19,8 +19,6 @@ export ARDOUR_PANNER_PATH=$libs/panners/2in2out:$libs/panners/1in2out:$libs/pann if [ "$1" == "--debug" ]; then gdb ./libs/ardour/run-tests -elif [ "$1" == "--valgrind" ]; then - valgrind --tool="memcheck" ./libs/ardour/run-tests else ./libs/ardour/run-tests fi diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 532d010680..7d6f44b786 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -974,27 +974,7 @@ int Session::load_options (const XMLNode& node) { LocaleGuard lg (X_("POSIX")); - - /* Copy the node */ - XMLNode node_copy = node; - - /* XXX: evil hack: fix up sessions from before the layering alterations - (during A3 beta) - */ - - XMLNodeList children = node_copy.children (); - for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) { - XMLProperty* p = (*i)->property (X_("name")); - if (p && p->name() == X_("name") && p->value() == X_("layer-model") ) { - p = (*i)->property (X_("value")); - if (p && p->value() == X_("MoveAddHigher")) { - (*i)->add_property (X_("value"), X_("AddOrBoundsChangeHigher")); - } - } - } - - config.set_variables (node_copy); - + config.set_variables (node); return 0; } diff --git a/libs/ardour/test/playlist_layering_test.cc b/libs/ardour/test/playlist_layering_test.cc index 23b22f9d90..fd0b6bc09c 100644 --- a/libs/ardour/test/playlist_layering_test.cc +++ b/libs/ardour/test/playlist_layering_test.cc @@ -1,14 +1,13 @@ -#include "pbd/compose.h" #include "midi++/manager.h" +#include "pbd/textreceiver.h" +#include "pbd/compose.h" +#include "ardour/session.h" +#include "ardour/audioengine.h" #include "ardour/playlist_factory.h" #include "ardour/source_factory.h" #include "ardour/region.h" #include "ardour/region_factory.h" -#include "ardour/session.h" -#include "ardour/audiosource.h" -#include "ardour/audioengine.h" #include "playlist_layering_test.h" -#include "test_receiver.h" CPPUNIT_TEST_SUITE_REGISTRATION (PlaylistLayeringTest); @@ -16,28 +15,68 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -int const PlaylistLayeringTest::num_regions = 6; +class TestReceiver : public Receiver +{ +protected: + void receive (Transmitter::Channel chn, const char * str) { + const char *prefix = ""; + + switch (chn) { + case Transmitter::Error: + prefix = ": [ERROR]: "; + break; + case Transmitter::Info: + /* ignore */ + return; + case Transmitter::Warning: + prefix = ": [WARNING]: "; + break; + case Transmitter::Fatal: + prefix = ": [FATAL]: "; + break; + case Transmitter::Throw: + /* this isn't supposed to happen */ + abort (); + } + + /* note: iostreams are already thread-safe: no external + lock required. + */ + + cout << prefix << str << endl; + + if (chn == Transmitter::Fatal) { + exit (9); + } + } +}; + +TestReceiver test_receiver; void PlaylistLayeringTest::setUp () { - TestNeedingSession::setUp (); - string const test_wav_path = "libs/ardour/test/test.wav"; + string const test_session_path = "libs/ardour/test/playlist_layering_test"; + string const test_wav_path = "libs/ardour/test/playlist_layering_test/playlist_layering_test.wav"; + system (string_compose ("rm -rf %1", test_session_path).c_str()); - _playlist = PlaylistFactory::create (DataType::AUDIO, *_session, "test"); - _source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, 44100); + init (false, true); + SessionEvent::create_per_thread_pool ("test", 512); - system ("pwd"); - - /* Must write some data to our source, otherwise regions which use it will - be limited in whether they can be trimmed or not. - */ - boost::shared_ptr<AudioSource> a = boost::dynamic_pointer_cast<AudioSource> (_source); - Sample silence[512]; - memset (silence, 0, 512 * sizeof (Sample)); - a->write (silence, 512); + test_receiver.listen_to (error); + test_receiver.listen_to (info); + test_receiver.listen_to (fatal); + test_receiver.listen_to (warning); + + AudioEngine* engine = new AudioEngine ("test", ""); + MIDI::Manager::create (engine->jack ()); + CPPUNIT_ASSERT (engine->start () == 0); - _region = new boost::shared_ptr<Region>[num_regions]; + _session = new Session (*engine, test_session_path, "playlist_layering_test"); + engine->set_session (_session); + + _playlist = PlaylistFactory::create (DataType::AUDIO, *_session, "test"); + _source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, 44100); } void @@ -45,303 +84,45 @@ PlaylistLayeringTest::tearDown () { _playlist.reset (); _source.reset (); - for (int i = 0; i < num_regions; ++i) { + for (int i = 0; i < 16; ++i) { _region[i].reset (); } - delete[] _region; - - TestNeedingSession::tearDown (); + AudioEngine::instance()->remove_session (); + delete _session; + EnumWriter::destroy (); + MIDI::Manager::destroy (); + AudioEngine::destroy (); } void -PlaylistLayeringTest::create_short_regions () +PlaylistLayeringTest::create_three_short_regions () { PropertyList plist; plist.add (Properties::start, 0); plist.add (Properties::length, 100); - for (int i = 0; i < num_regions; ++i) { + for (int i = 0; i < 3; ++i) { _region[i] = RegionFactory::create (_source, plist); - _region[i]->set_name (string_compose ("%1", char (int ('A') + i))); } } void -PlaylistLayeringTest::laterHigher_relayerOnAll_Test () -{ - _session->config.set_layer_model (LaterHigher); - _session->config.set_relayer_on_all_edits (true); - - create_short_regions (); - - /* three overlapping regions */ - _playlist->add_region (_region[A], 0); - _playlist->add_region (_region[B], 10); - _playlist->add_region (_region[C], 20); - /* and another non-overlapping one */ - _playlist->add_region (_region[D], 200); - - /* LaterHigher means that they should be arranged thus */ - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - _region[A]->set_position (5); - - /* Region move should have no effect in LaterHigher mode */ - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* C -> bottom should give C A B, not touching D */ - _region[C]->lower_to_bottom (); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* C -> top should go back to A B C, not touching D */ - _region[C]->raise_to_top (); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); -} - -void -PlaylistLayeringTest::addHigher_relayerOnAll_Test () -{ - _session->config.set_layer_model (AddHigher); - _session->config.set_relayer_on_all_edits (true); - - create_short_regions (); - - /* three overlapping regions */ - _playlist->add_region (_region[A], 0); - _playlist->add_region (_region[B], 10); - _playlist->add_region (_region[C], 20); - /* and another non-overlapping one */ - _playlist->add_region (_region[D], 200); - - /* AddHigher means that they should be arranged thus */ - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - _region[A]->set_position (5); - - /* region move should have no effect in AddHigher mode */ - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* C -> bottom should give C A B, not touching D */ - _region[C]->lower_to_bottom (); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* C -> top should go back to A B C, not touching D */ - _region[C]->raise_to_top (); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); -} - -void -PlaylistLayeringTest::addOrBoundsHigher_relayerOnAll_Test () +PlaylistLayeringTest::basicsTest () { - _session->config.set_layer_model (AddOrBoundsChangeHigher); - _session->config.set_relayer_on_all_edits (true); - - create_short_regions (); - - /* three overlapping regions */ - _playlist->add_region (_region[A], 0); - _playlist->add_region (_region[B], 10); - _playlist->add_region (_region[C], 20); - /* and another non-overlapping one */ - _playlist->add_region (_region[D], 200); - - /* AddOrBoundsHigher means that they should be arranged thus */ - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* region move should put A on top for B C A, not touching D */ - _region[A]->set_position (5); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* C -> bottom should give C B A, not touching D */ - _region[C]->lower_to_bottom (); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* C -> top should go back to B A C, not touching D */ - _region[C]->raise_to_top (); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* Put C on the bottom */ - _region[C]->lower_to_bottom (); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* Now move it slightly, and it should go back to the top again */ - _region[C]->set_position (21); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* Put C back on the bottom */ - _region[C]->lower_to_bottom (); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* Trim it slightly, and it should go back to the top again */ - _region[C]->trim_front (23); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* Same with the end */ - _region[C]->lower_to_bottom (); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - _region[C]->trim_end (118); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); -} - -void -PlaylistLayeringTest::addOrBoundsHigher_relayerWhenNecessary_Test () -{ - _session->config.set_layer_model (AddOrBoundsChangeHigher); - _session->config.set_relayer_on_all_edits (false); - - create_short_regions (); - - /* three overlapping regions */ - _playlist->add_region (_region[A], 0); - _playlist->add_region (_region[B], 10); - _playlist->add_region (_region[C], 20); - /* and another non-overlapping one */ - _playlist->add_region (_region[D], 200); - - /* AddOrBoundsHigher means that they should be arranged thus */ - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - _region[A]->set_position (5); - - /* region move should not have changed anything, since in - this mode we only relayer when there is a new overlap - */ - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* C -> bottom should give C A B, not touching D */ - _region[C]->lower_to_bottom (); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* C -> top should go back to A B C, not touching D */ - _region[C]->raise_to_top (); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* Put C on the bottom */ - _region[C]->lower_to_bottom (); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - - /* Now move it slightly, and it should stay where it is */ - _region[C]->set_position (21); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); -} - -void -PlaylistLayeringTest::lastLayerOpTest () -{ - create_short_regions (); - - _playlist->add_region (_region[A], 0); - CPPUNIT_ASSERT_EQUAL (_playlist->layer_op_counter, _region[A]->last_layer_op (LayerOpAdd)); - uint64_t const last_add = _region[A]->last_layer_op (LayerOpAdd); - - _region[A]->set_position (42); - CPPUNIT_ASSERT_EQUAL (_playlist->layer_op_counter, _region[A]->last_layer_op (LayerOpBoundsChange)); - CPPUNIT_ASSERT_EQUAL (last_add, _region[A]->last_layer_op (LayerOpAdd)); - - _region[A]->trim_front (46); - CPPUNIT_ASSERT_EQUAL (_playlist->layer_op_counter, _region[A]->last_layer_op (LayerOpBoundsChange)); - CPPUNIT_ASSERT_EQUAL (last_add, _region[A]->last_layer_op (LayerOpAdd)); - - _region[A]->trim_end (102); - CPPUNIT_ASSERT_EQUAL (_playlist->layer_op_counter, _region[A]->last_layer_op (LayerOpBoundsChange)); - CPPUNIT_ASSERT_EQUAL (last_add, _region[A]->last_layer_op (LayerOpAdd)); -} - -void -PlaylistLayeringTest::recursiveRelayerTest () -{ - _session->config.set_layer_model (AddOrBoundsChangeHigher); - _session->config.set_relayer_on_all_edits (false); - - create_short_regions (); + create_three_short_regions (); - _playlist->add_region (_region[A], 100); - _playlist->add_region (_region[B], 125); - _playlist->add_region (_region[C], 50); - _playlist->add_region (_region[D], 250); + _playlist->add_region (_region[0], 0); + _playlist->add_region (_region[1], 10); + _playlist->add_region (_region[2], 20); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); + CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[0]->layer ()); + CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[1]->layer ()); + CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[2]->layer ()); - _region[A]->set_position (200); + _region[0]->set_position (5); - CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ()); - CPPUNIT_ASSERT_EQUAL (layer_t (3), _region[C]->layer ()); + /* region move should have no effect */ + CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[0]->layer ()); + CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[1]->layer ()); + CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[2]->layer ()); } diff --git a/libs/ardour/test/playlist_layering_test.h b/libs/ardour/test/playlist_layering_test.h index ab5fe701b1..46285459ca 100644 --- a/libs/ardour/test/playlist_layering_test.h +++ b/libs/ardour/test/playlist_layering_test.h @@ -1,6 +1,5 @@ #include <cppunit/TestFixture.h> #include <cppunit/extensions/HelperMacros.h> -#include "test_needing_session.h" namespace ARDOUR { class Session; @@ -8,42 +7,23 @@ namespace ARDOUR { class Source; } -class PlaylistLayeringTest : public TestNeedingSession +class PlaylistLayeringTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE (PlaylistLayeringTest); - CPPUNIT_TEST (lastLayerOpTest); - CPPUNIT_TEST (addHigher_relayerOnAll_Test); - CPPUNIT_TEST (addOrBoundsHigher_relayerOnAll_Test); - CPPUNIT_TEST (laterHigher_relayerOnAll_Test); - CPPUNIT_TEST (addOrBoundsHigher_relayerWhenNecessary_Test); - CPPUNIT_TEST (recursiveRelayerTest); + CPPUNIT_TEST (basicsTest); CPPUNIT_TEST_SUITE_END (); public: void setUp (); void tearDown (); - void lastLayerOpTest (); - void addHigher_relayerOnAll_Test (); - void addOrBoundsHigher_relayerOnAll_Test (); - void laterHigher_relayerOnAll_Test (); - void addOrBoundsHigher_relayerWhenNecessary_Test (); - void recursiveRelayerTest (); + void basicsTest (); private: - void create_short_regions (); - - static int const num_regions; - enum { - A = 0, - B, - C, - D, - E, - F - }; + void create_three_short_regions (); + ARDOUR::Session* _session; boost::shared_ptr<ARDOUR::Playlist> _playlist; boost::shared_ptr<ARDOUR::Source> _source; - boost::shared_ptr<ARDOUR::Region>* _region; + boost::shared_ptr<ARDOUR::Region> _region[16]; }; diff --git a/libs/ardour/test/playlist_overlap_cache_test.cc b/libs/ardour/test/playlist_overlap_cache_test.cc deleted file mode 100644 index 9263d80d3b..0000000000 --- a/libs/ardour/test/playlist_overlap_cache_test.cc +++ /dev/null @@ -1,119 +0,0 @@ -#include "pbd/compose.h" -#include "ardour/playlist.h" -#include "ardour/playlist_factory.h" -#include "ardour/source_factory.h" -#include "ardour/region.h" -#include "ardour/region_sorters.h" -#include "ardour/region_factory.h" -#include "playlist_overlap_cache_test.h" - -using namespace std; -using namespace PBD; -using namespace ARDOUR; - -CPPUNIT_TEST_SUITE_REGISTRATION (PlaylistOverlapCacheTest); - -void -PlaylistOverlapCacheTest::tearDown () -{ - _playlist.reset (); - _source.reset (); - - TestNeedingSession::tearDown (); -} - -void -PlaylistOverlapCacheTest::basicTest () -{ - string const test_wav_path = "libs/ardour/test/test.wav"; - - _playlist = PlaylistFactory::create (DataType::AUDIO, *_session, "test"); - _source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, 44100); - - PropertyList plist; - plist.add (Properties::length, 256); - - boost::shared_ptr<Region> regionA = RegionFactory::create (_source, plist); - regionA->set_name ("A"); - _playlist->add_region (regionA, 0); - - - { - Playlist::OverlapCache cache (_playlist.get ()); - Playlist::RegionList rl = cache.get (Evoral::Range<framepos_t> (0, 256)); - CPPUNIT_ASSERT_EQUAL (size_t (1), rl.size ()); - CPPUNIT_ASSERT_EQUAL (regionA, rl.front ()); - - rl = cache.get (Evoral::Range<framepos_t> (-1000, 1000)); - CPPUNIT_ASSERT_EQUAL (size_t (1), rl.size ()); - CPPUNIT_ASSERT_EQUAL (regionA, rl.front ()); - } - - boost::shared_ptr<Region> regionB = RegionFactory::create (_source, plist); - regionA->set_name ("B"); - _playlist->add_region (regionB, 53); - - { - Playlist::OverlapCache cache (_playlist.get ()); - Playlist::RegionList rl = cache.get (Evoral::Range<framepos_t> (0, 256)); - CPPUNIT_ASSERT_EQUAL (size_t (2), rl.size ()); - rl.sort (RegionSortByPosition ()); - CPPUNIT_ASSERT_EQUAL (regionA, rl.front ()); - CPPUNIT_ASSERT_EQUAL (regionB, rl.back ()); - - rl = cache.get (Evoral::Range<framepos_t> (260, 274)); - CPPUNIT_ASSERT_EQUAL (size_t (1), rl.size ()); - CPPUNIT_ASSERT_EQUAL (regionB, rl.front ()); - } -} - -void -PlaylistOverlapCacheTest::stressTest () -{ - string const test_wav_path = "libs/ardour/test/test.wav"; - - _playlist = PlaylistFactory::create (DataType::AUDIO, *_session, "test"); - _source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, 44100); - - srand (42); - - int const num_regions = rand () % 256; - - for (int i = 0; i < num_regions; ++i) { - PropertyList plist; - plist.add (Properties::length, rand () % 32768); - boost::shared_ptr<Region> r = RegionFactory::create (_source, plist); - r->set_name (string_compose ("%1", i)); - _playlist->add_region (r, rand() % 32768); - } - - Playlist::OverlapCache cache (_playlist.get ()); - - int const tests = rand () % 256; - - for (int i = 0; i < tests; ++i) { - framepos_t const start = rand () % 32768; - framepos_t const length = rand () % 32768; - framepos_t const end = start + length; - - Playlist::RegionList cached = cache.get (Evoral::Range<framepos_t> (start, end)); - - Playlist::RegionList actual; - Playlist::RegionList regions = _playlist->region_list().rlist(); - for (Playlist::RegionList::iterator j = regions.begin(); j != regions.end(); ++j) { - if ((*j)->coverage (start, end) != OverlapNone) { - actual.push_back (*j); - } - } - - cached.sort (RegionSortByPosition ()); - actual.sort (RegionSortByPosition ()); - - CPPUNIT_ASSERT_EQUAL (actual.size (), cached.size ()); - Playlist::RegionList::iterator j = actual.begin (); - Playlist::RegionList::iterator k = cached.begin (); - for (; j != actual.end(); ++j, ++k) { - CPPUNIT_ASSERT_EQUAL (*j, *k); - } - } -} diff --git a/libs/ardour/test/playlist_overlap_cache_test.h b/libs/ardour/test/playlist_overlap_cache_test.h deleted file mode 100644 index c75d1691d9..0000000000 --- a/libs/ardour/test/playlist_overlap_cache_test.h +++ /dev/null @@ -1,20 +0,0 @@ -#include "test_needing_session.h" - -class PlaylistOverlapCacheTest : public TestNeedingSession -{ -public: - CPPUNIT_TEST_SUITE (PlaylistOverlapCacheTest); - CPPUNIT_TEST (basicTest); - CPPUNIT_TEST (stressTest); - CPPUNIT_TEST_SUITE_END (); - -public: - void tearDown (); - - void basicTest (); - void stressTest (); - -private: - boost::shared_ptr<ARDOUR::Playlist> _playlist; - boost::shared_ptr<ARDOUR::Source> _source; -}; diff --git a/libs/ardour/test/test_needing_session.cc b/libs/ardour/test/test_needing_session.cc deleted file mode 100644 index 5981553601..0000000000 --- a/libs/ardour/test/test_needing_session.cc +++ /dev/null @@ -1,48 +0,0 @@ -#include "midi++/manager.h" -#include "pbd/textreceiver.h" -#include "pbd/compose.h" -#include "pbd/enumwriter.h" -#include "ardour/session.h" -#include "ardour/audioengine.h" -#include "test_needing_session.h" -#include "test_receiver.h" - -using namespace std; -using namespace ARDOUR; -using namespace PBD; - -TestReceiver test_receiver; - -void -TestNeedingSession::setUp () -{ - string const test_session_path = "libs/ardour/test/test_session"; - system (string_compose ("rm -rf %1", test_session_path).c_str()); - - init (false, true); - SessionEvent::create_per_thread_pool ("test", 512); - - test_receiver.listen_to (error); - test_receiver.listen_to (info); - test_receiver.listen_to (fatal); - test_receiver.listen_to (warning); - - AudioEngine* engine = new AudioEngine ("test", ""); - MIDI::Manager::create (engine->jack ()); - CPPUNIT_ASSERT (engine->start () == 0); - - _session = new Session (*engine, test_session_path, "test_session"); - engine->set_session (_session); -} - -void -TestNeedingSession::tearDown () -{ - AudioEngine::instance()->remove_session (); - - delete _session; - - EnumWriter::destroy (); - MIDI::Manager::destroy (); - AudioEngine::destroy (); -} diff --git a/libs/ardour/test/test_needing_session.h b/libs/ardour/test/test_needing_session.h deleted file mode 100644 index 3839855179..0000000000 --- a/libs/ardour/test/test_needing_session.h +++ /dev/null @@ -1,16 +0,0 @@ -#include <cppunit/TestFixture.h> -#include <cppunit/extensions/HelperMacros.h> - -namespace ARDOUR { - class Session; -} - -class TestNeedingSession : public CppUnit::TestFixture -{ -public: - void setUp (); - void tearDown (); - -protected: - ARDOUR::Session* _session; -}; diff --git a/libs/ardour/test/test_receiver.h b/libs/ardour/test/test_receiver.h deleted file mode 100644 index 537bac3cff..0000000000 --- a/libs/ardour/test/test_receiver.h +++ /dev/null @@ -1,37 +0,0 @@ -#include "pbd/receiver.h" - -class TestReceiver : public Receiver -{ -protected: - void receive (Transmitter::Channel chn, const char * str) { - const char *prefix = ""; - - switch (chn) { - case Transmitter::Error: - prefix = ": [ERROR]: "; - break; - case Transmitter::Info: - /* ignore */ - return; - case Transmitter::Warning: - prefix = ": [WARNING]: "; - break; - case Transmitter::Fatal: - prefix = ": [FATAL]: "; - break; - case Transmitter::Throw: - /* this isn't supposed to happen */ - abort (); - } - - /* note: iostreams are already thread-safe: no external - lock required. - */ - - std::cout << prefix << str << std::endl; - - if (chn == Transmitter::Fatal) { - exit (9); - } - } -}; diff --git a/libs/ardour/wscript b/libs/ardour/wscript index e49be33b8c..42c72784f9 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -431,8 +431,6 @@ def build(bld): test/framepos_plus_beats_test.cc test/framepos_minus_beats_test.cc test/playlist_layering_test.cc - test/playlist_overlap_cache_test.cc - test/test_needing_session.cc test/testrunner.cc '''.split() |