1 /*
2  * Copyright (C) 2000-2018 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
4  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
5  * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
6  * Copyright (C) 2015-2017 Nick Mainsbridge <mainsbridge@gmail.com>
7  * Copyright (C) 2015-2018 Ben Loftis <ben@harrisonconsoles.com>
8  * Copyright (C) 2016 Tim Mayberry <mojofunk@gmail.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24 
25 #include <iostream>
26 #include <cmath>
27 #include <climits>
28 #include <algorithm>
29 #include <sstream>
30 
31 #include <glibmm/threads.h>
32 
33 #include "pbd/types_convert.h"
34 #include "pbd/xml++.h"
35 
36 #include "ardour/debug.h"
37 #include "ardour/filter.h"
38 #include "ardour/playlist.h"
39 #include "ardour/playlist_source.h"
40 #include "ardour/profile.h"
41 #include "ardour/region.h"
42 #include "ardour/region_factory.h"
43 #include "ardour/session.h"
44 #include "ardour/source.h"
45 #include "ardour/tempo.h"
46 #include "ardour/transient_detector.h"
47 #include "ardour/types_convert.h"
48 
49 #include "pbd/i18n.h"
50 
51 using namespace std;
52 using namespace ARDOUR;
53 using namespace PBD;
54 
55 namespace ARDOUR {
56 	class Progress;
57 	namespace Properties {
58 		PBD::PropertyDescriptor<bool> muted;
59 		PBD::PropertyDescriptor<bool> opaque;
60 		PBD::PropertyDescriptor<bool> locked;
61 		PBD::PropertyDescriptor<bool> video_locked;
62 		PBD::PropertyDescriptor<bool> automatic;
63 		PBD::PropertyDescriptor<bool> whole_file;
64 		PBD::PropertyDescriptor<bool> import;
65 		PBD::PropertyDescriptor<bool> external;
66 		PBD::PropertyDescriptor<bool> sync_marked;
67 		PBD::PropertyDescriptor<bool> left_of_split;
68 		PBD::PropertyDescriptor<bool> right_of_split;
69 		PBD::PropertyDescriptor<bool> hidden;
70 		PBD::PropertyDescriptor<bool> position_locked;
71 		PBD::PropertyDescriptor<bool> valid_transients;
72 		PBD::PropertyDescriptor<samplepos_t> start;
73 		PBD::PropertyDescriptor<samplecnt_t> length;
74 		PBD::PropertyDescriptor<samplepos_t> position;
75 		PBD::PropertyDescriptor<double> beat;
76 		PBD::PropertyDescriptor<samplecnt_t> sync_position;
77 		PBD::PropertyDescriptor<layer_t> layer;
78 		PBD::PropertyDescriptor<samplepos_t> ancestral_start;
79 		PBD::PropertyDescriptor<samplecnt_t> ancestral_length;
80 		PBD::PropertyDescriptor<float> stretch;
81 		PBD::PropertyDescriptor<float> shift;
82 		PBD::PropertyDescriptor<PositionLockStyle> position_lock_style;
83 		PBD::PropertyDescriptor<uint64_t> layering_index;
84 		PBD::PropertyDescriptor<std::string> tags;
85 		PBD::PropertyDescriptor<bool> contents;
86 	}
87 }
88 
89 PBD::Signal2<void,boost::shared_ptr<ARDOUR::RegionList>,const PropertyChange&> Region::RegionsPropertyChanged;
90 
91 void
make_property_quarks()92 Region::make_property_quarks ()
93 {
94 	Properties::muted.property_id = g_quark_from_static_string (X_("muted"));
95 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for muted = %1\n", Properties::muted.property_id));
96 	Properties::opaque.property_id = g_quark_from_static_string (X_("opaque"));
97 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for opaque = %1\n", Properties::opaque.property_id));
98 	Properties::locked.property_id = g_quark_from_static_string (X_("locked"));
99 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for locked = %1\n", Properties::locked.property_id));
100 	Properties::video_locked.property_id = g_quark_from_static_string (X_("video-locked"));
101 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for video-locked = %1\n", Properties::video_locked.property_id));
102 	Properties::automatic.property_id = g_quark_from_static_string (X_("automatic"));
103 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for automatic = %1\n", Properties::automatic.property_id));
104 	Properties::whole_file.property_id = g_quark_from_static_string (X_("whole-file"));
105 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for whole-file = %1\n", Properties::whole_file.property_id));
106 	Properties::import.property_id = g_quark_from_static_string (X_("import"));
107 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for import = %1\n", Properties::import.property_id));
108 	Properties::external.property_id = g_quark_from_static_string (X_("external"));
109 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for external = %1\n", Properties::external.property_id));
110 	Properties::sync_marked.property_id = g_quark_from_static_string (X_("sync-marked"));
111 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-marked = %1\n", Properties::sync_marked.property_id));
112 	Properties::left_of_split.property_id = g_quark_from_static_string (X_("left-of-split"));
113 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for left-of-split = %1\n", Properties::left_of_split.property_id));
114 	Properties::right_of_split.property_id = g_quark_from_static_string (X_("right-of-split"));
115 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for right-of-split = %1\n", Properties::right_of_split.property_id));
116 	Properties::hidden.property_id = g_quark_from_static_string (X_("hidden"));
117 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n", Properties::hidden.property_id));
118 	Properties::position_locked.property_id = g_quark_from_static_string (X_("position-locked"));
119 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n", Properties::position_locked.property_id));
120 	Properties::valid_transients.property_id = g_quark_from_static_string (X_("valid-transients"));
121 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for valid-transients = %1\n", Properties::valid_transients.property_id));
122 	Properties::start.property_id = g_quark_from_static_string (X_("start"));
123 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n", Properties::start.property_id));
124 	Properties::length.property_id = g_quark_from_static_string (X_("length"));
125 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for length = %1\n", Properties::length.property_id));
126 	Properties::position.property_id = g_quark_from_static_string (X_("position"));
127 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position = %1\n", Properties::position.property_id));
128 	Properties::beat.property_id = g_quark_from_static_string (X_("beat"));
129 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for beat = %1\n", Properties::beat.property_id));
130 	Properties::sync_position.property_id = g_quark_from_static_string (X_("sync-position"));
131 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-position = %1\n", Properties::sync_position.property_id));
132 	Properties::layer.property_id = g_quark_from_static_string (X_("layer"));
133 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layer = %1\n", Properties::layer.property_id));
134 	Properties::ancestral_start.property_id = g_quark_from_static_string (X_("ancestral-start"));
135 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-start = %1\n", Properties::ancestral_start.property_id));
136 	Properties::ancestral_length.property_id = g_quark_from_static_string (X_("ancestral-length"));
137 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-length = %1\n", Properties::ancestral_length.property_id));
138 	Properties::stretch.property_id = g_quark_from_static_string (X_("stretch"));
139 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretch = %1\n", Properties::stretch.property_id));
140 	Properties::shift.property_id = g_quark_from_static_string (X_("shift"));
141 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n", Properties::shift.property_id));
142 	Properties::position_lock_style.property_id = g_quark_from_static_string (X_("positional-lock-style"));
143 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position_lock_style = %1\n", Properties::position_lock_style.property_id));
144 	Properties::layering_index.property_id = g_quark_from_static_string (X_("layering-index"));
145 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layering_index = %1\n",	Properties::layering_index.property_id));
146 	Properties::tags.property_id = g_quark_from_static_string (X_("tags"));
147 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for tags = %1\n",	Properties::tags.property_id));
148 	Properties::contents.property_id = g_quark_from_static_string (X_("contents"));
149 	DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for contents = %1\n",	Properties::contents.property_id));
150 }
151 
152 void
register_properties()153 Region::register_properties ()
154 {
155 	_xml_node_name = X_("Region");
156 
157 	add_property (_muted);
158 	add_property (_opaque);
159 	add_property (_locked);
160 	add_property (_video_locked);
161 	add_property (_automatic);
162 	add_property (_whole_file);
163 	add_property (_import);
164 	add_property (_external);
165 	add_property (_sync_marked);
166 	add_property (_left_of_split);
167 	add_property (_right_of_split);
168 	add_property (_hidden);
169 	add_property (_position_locked);
170 	add_property (_valid_transients);
171 	add_property (_start);
172 	add_property (_length);
173 	add_property (_position);
174 	add_property (_beat);
175 	add_property (_sync_position);
176 	add_property (_ancestral_start);
177 	add_property (_ancestral_length);
178 	add_property (_stretch);
179 	add_property (_shift);
180 	add_property (_position_lock_style);
181 	add_property (_layering_index);
182 	add_property (_tags);
183 	add_property (_contents);
184 }
185 
186 #define REGION_DEFAULT_STATE(s,l) \
187 	_sync_marked (Properties::sync_marked, false) \
188 	, _left_of_split (Properties::left_of_split, false) \
189 	, _right_of_split (Properties::right_of_split, false) \
190 	, _valid_transients (Properties::valid_transients, false) \
191 	, _start (Properties::start, (s)) \
192 	, _length (Properties::length, (l)) \
193 	, _position (Properties::position, 0) \
194 	, _beat (Properties::beat, 0.0) \
195 	, _sync_position (Properties::sync_position, (s)) \
196 	, _quarter_note (0.0) \
197 	, _transient_user_start (0) \
198 	, _transient_analysis_start (0) \
199 	, _transient_analysis_end (0) \
200 	, _soloSelected (false) \
201 	, _muted (Properties::muted, false) \
202 	, _opaque (Properties::opaque, true) \
203 	, _locked (Properties::locked, false) \
204 	, _video_locked (Properties::video_locked, false) \
205 	, _automatic (Properties::automatic, false) \
206 	, _whole_file (Properties::whole_file, false) \
207 	, _import (Properties::import, false) \
208 	, _external (Properties::external, false) \
209 	, _hidden (Properties::hidden, false) \
210 	, _position_locked (Properties::position_locked, false) \
211 	, _ancestral_start (Properties::ancestral_start, (s)) \
212 	, _ancestral_length (Properties::ancestral_length, (l)) \
213 	, _stretch (Properties::stretch, 1.0) \
214 	, _shift (Properties::shift, 1.0) \
215 	, _position_lock_style (Properties::position_lock_style, _type == DataType::AUDIO ? AudioTime : MusicTime) \
216 	, _layering_index (Properties::layering_index, 0) \
217 	, _tags (Properties::tags, "") \
218 	, _contents (Properties::contents, false)
219 
220 #define REGION_COPY_STATE(other) \
221 	  _sync_marked (Properties::sync_marked, other->_sync_marked) \
222 	, _left_of_split (Properties::left_of_split, other->_left_of_split) \
223 	, _right_of_split (Properties::right_of_split, other->_right_of_split) \
224 	, _valid_transients (Properties::valid_transients, other->_valid_transients) \
225 	, _start(Properties::start, other->_start) \
226 	, _length(Properties::length, other->_length) \
227 	, _position(Properties::position, other->_position) \
228 	, _beat (Properties::beat, other->_beat) \
229 	, _sync_position(Properties::sync_position, other->_sync_position) \
230 	, _quarter_note (other->_quarter_note) \
231 	, _user_transients (other->_user_transients) \
232 	, _transient_user_start (other->_transient_user_start) \
233 	, _transients (other->_transients) \
234 	, _transient_analysis_start (other->_transient_analysis_start) \
235 	, _transient_analysis_end (other->_transient_analysis_end) \
236 	, _soloSelected (false) \
237 	, _muted (Properties::muted, other->_muted) \
238 	, _opaque (Properties::opaque, other->_opaque) \
239 	, _locked (Properties::locked, other->_locked) \
240 	, _video_locked (Properties::video_locked, other->_video_locked) \
241 	, _automatic (Properties::automatic, other->_automatic) \
242 	, _whole_file (Properties::whole_file, other->_whole_file) \
243 	, _import (Properties::import, other->_import) \
244 	, _external (Properties::external, other->_external) \
245 	, _hidden (Properties::hidden, other->_hidden) \
246 	, _position_locked (Properties::position_locked, other->_position_locked) \
247 	, _ancestral_start (Properties::ancestral_start, other->_ancestral_start) \
248 	, _ancestral_length (Properties::ancestral_length, other->_ancestral_length) \
249 	, _stretch (Properties::stretch, other->_stretch) \
250 	, _shift (Properties::shift, other->_shift) \
251 	, _position_lock_style (Properties::position_lock_style, other->_position_lock_style) \
252 	, _layering_index (Properties::layering_index, other->_layering_index) \
253 	, _tags (Properties::tags, other->_tags) \
254 	, _contents (Properties::contents, other->_contents)
255 
256 /* derived-from-derived constructor (no sources in constructor) */
Region(Session & s,samplepos_t start,samplecnt_t length,const string & name,DataType type)257 Region::Region (Session& s, samplepos_t start, samplecnt_t length, const string& name, DataType type)
258 	: SessionObject(s, name)
259 	, _type(type)
260 	, REGION_DEFAULT_STATE(start,length)
261 	, _last_length (length)
262 	, _last_position (0)
263 	, _first_edit (EditChangesNothing)
264 	, _layer (0)
265 	, _changemap (0)
266 {
267 	register_properties ();
268 
269 	/* no sources at this point */
270 }
271 
272 /** Basic Region constructor (many sources) */
Region(const SourceList & srcs)273 Region::Region (const SourceList& srcs)
274 	: SessionObject(srcs.front()->session(), "toBeRenamed")
275 	, _type (srcs.front()->type())
276 	, REGION_DEFAULT_STATE(0,0)
277 	, _last_length (0)
278 	, _last_position (0)
279 	, _first_edit (EditChangesNothing)
280 	, _layer (0)
281 	, _changemap (0)
282 {
283 	register_properties ();
284 
285 	_type = srcs.front()->type();
286 
287 	use_sources (srcs);
288 
289 	assert(_sources.size() > 0);
290 	assert (_type == srcs.front()->type());
291 }
292 
293 /** Create a new Region from an existing one */
Region(boost::shared_ptr<const Region> other)294 Region::Region (boost::shared_ptr<const Region> other)
295 	: SessionObject(other->session(), other->name())
296 	, _type (other->data_type())
297 	, REGION_COPY_STATE (other)
298 	, _last_length (other->_last_length)
299 	, _last_position(other->_last_position) \
300 	, _first_edit (EditChangesNothing)
301 	, _layer (other->_layer)
302 	, _changemap (other->_changemap)
303 {
304 	register_properties ();
305 
306 	/* override state that may have been incorrectly inherited from the other region
307 	 */
308 
309 	_position = other->_position;
310 	_locked = false;
311 	_whole_file = false;
312 	_hidden = false;
313 
314 	use_sources (other->_sources);
315 	set_master_sources (other->_master_sources);
316 
317 	_position_lock_style = other->_position_lock_style.val();
318 	_first_edit = other->_first_edit;
319 
320 	_start = other->_start;
321 	_beat = other->_beat;
322 	_quarter_note = other->_quarter_note;
323 
324 	/* sync pos is relative to start of file. our start-in-file is now zero,
325 	 * so set our sync position to whatever the the difference between
326 	 * _start and _sync_pos was in the other region.
327 	 *
328 	 * result is that our new sync pos points to the same point in our source(s)
329 	 * as the sync in the other region did in its source(s).
330 	 *
331 	 * since we start at zero in our source(s), it is not possible to use a sync point that
332 	 * is before the start. reset it to _start if that was true in the other region.
333 	 */
334 
335 	if (other->sync_marked()) {
336 		if (other->_start < other->_sync_position) {
337 			/* sync pos was after the start point of the other region */
338 			_sync_position = other->_sync_position - other->_start;
339 		} else {
340 			/* sync pos was before the start point of the other region. not possible here. */
341 			_sync_marked = false;
342 			_sync_position = _start;
343 		}
344 	} else {
345 		_sync_marked = false;
346 		_sync_position = _start;
347 	}
348 
349 	assert (_type == other->data_type());
350 }
351 
352 /** Create a new Region from part of an existing one.
353  *
354  * the start within \a other is given by \a offset
355  * (i.e. relative to the start of \a other's sources, the start is \a offset + \a other.start()
356  */
Region(boost::shared_ptr<const Region> other,MusicSample offset)357 Region::Region (boost::shared_ptr<const Region> other, MusicSample offset)
358 	: SessionObject(other->session(), other->name())
359 	, _type (other->data_type())
360 	, REGION_COPY_STATE (other)
361 	, _last_length (other->_last_length)
362 	, _last_position(other->_last_position) \
363 	, _first_edit (EditChangesNothing)
364 	, _layer (other->_layer)
365 	, _changemap (other->_changemap)
366 {
367 	register_properties ();
368 
369 	/* override state that may have been incorrectly inherited from the other region
370 	 */
371 
372 	_locked = false;
373 	_whole_file = false;
374 	_hidden = false;
375 
376 	use_sources (other->_sources);
377 	set_master_sources (other->_master_sources);
378 
379 	_position = other->_position + offset.sample;
380 	_start = other->_start + offset.sample;
381 
382 	/* prevent offset of 0 from altering musical position */
383 	if (offset.sample != 0) {
384 		const double offset_qn = _session.tempo_map().exact_qn_at_sample (other->_position + offset.sample, offset.division)
385 			- other->_quarter_note;
386 
387 		_quarter_note = other->_quarter_note + offset_qn;
388 		_beat = _session.tempo_map().beat_at_quarter_note (_quarter_note);
389 	} else {
390 		_quarter_note = _session.tempo_map().quarter_note_at_beat (_beat);
391 	}
392 
393 	/* if the other region had a distinct sync point
394 	 * set, then continue to use it as best we can.
395 	 * otherwise, reset sync point back to start.
396 	 */
397 
398 	if (other->sync_marked()) {
399 		if (other->_sync_position < _start) {
400 			_sync_marked = false;
401 			_sync_position = _start;
402 		} else {
403 			_sync_position = other->_sync_position;
404 		}
405 	} else {
406 		_sync_marked = false;
407 		_sync_position = _start;
408 	}
409 
410 	assert (_type == other->data_type());
411 }
412 
413 /** Create a copy of @param other but with different sources. Used by filters */
Region(boost::shared_ptr<const Region> other,const SourceList & srcs)414 Region::Region (boost::shared_ptr<const Region> other, const SourceList& srcs)
415 	: SessionObject (other->session(), other->name())
416 	, _type (srcs.front()->type())
417 	, REGION_COPY_STATE (other)
418 	, _last_length (other->_last_length)
419 	, _last_position (other->_last_position)
420 	, _first_edit (EditChangesID)
421 	, _layer (other->_layer)
422 	, _changemap (other->_changemap)
423 {
424 	register_properties ();
425 
426 	_locked = false;
427 	_position_locked = false;
428 
429 	other->_first_edit = EditChangesName;
430 
431 	if (other->_extra_xml) {
432 		_extra_xml = new XMLNode (*other->_extra_xml);
433 	} else {
434 		_extra_xml = 0;
435 	}
436 
437 	use_sources (srcs);
438 	assert(_sources.size() > 0);
439 }
440 
~Region()441 Region::~Region ()
442 {
443 	DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
444 	drop_sources ();
445 }
446 
447 void
set_playlist(boost::weak_ptr<Playlist> wpl)448 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
449 {
450 	_playlist = wpl.lock();
451 }
452 
453 bool
set_name(const std::string & str)454 Region::set_name (const std::string& str)
455 {
456 	if (_name == str) {
457 		return true;
458 	}
459 
460 	SessionObject::set_name (str); // EMIT SIGNAL NameChanged()
461 	assert (_name == str);
462 	send_change (Properties::name);
463 	return true;
464 }
465 
466 void
set_selected_for_solo(bool yn)467 Region::set_selected_for_solo(bool yn)
468 {
469 	if (_soloSelected != yn) {
470 
471 		boost::shared_ptr<Playlist> pl (playlist());
472 		if (pl){
473 			if (yn) {
474 				pl->AddToSoloSelectedList(this);
475 			} else {
476 				pl->RemoveFromSoloSelectedList(this);
477 			}
478 		}
479 
480 		_soloSelected = yn;
481 	}
482 }
483 
484 void
set_length(samplecnt_t len,const int32_t sub_num)485 Region::set_length (samplecnt_t len, const int32_t sub_num)
486 {
487 	//cerr << "Region::set_length() len = " << len << endl;
488 	if (locked()) {
489 		return;
490 	}
491 
492 	if (_length != len && len != 0) {
493 
494 		/* check that the current _position wouldn't make the new
495 		 * length impossible.
496 		 */
497 
498 		if (max_samplepos - len < _position) {
499 			return;
500 		}
501 
502 		if (!verify_length (len)) {
503 			return;
504 		}
505 
506 
507 		set_length_internal (len, sub_num);
508 		_whole_file = false;
509 		first_edit ();
510 		maybe_uncopy ();
511 		maybe_invalidate_transients ();
512 
513 		if (!property_changes_suspended()) {
514 			recompute_at_end ();
515 		}
516 
517 		send_change (Properties::length);
518 	}
519 }
520 
521 void
set_length_internal(samplecnt_t len,const int32_t sub_num)522 Region::set_length_internal (samplecnt_t len, const int32_t sub_num)
523 {
524 	_last_length = _length;
525 	_length = len;
526 }
527 
528 void
maybe_uncopy()529 Region::maybe_uncopy ()
530 {
531 	/* this does nothing but marked a semantic moment once upon a time */
532 }
533 
534 void
first_edit()535 Region::first_edit ()
536 {
537 	boost::shared_ptr<Playlist> pl (playlist());
538 
539 	if (_first_edit != EditChangesNothing && pl) {
540 
541 		_name = RegionFactory::new_region_name (_name);
542 		_first_edit = EditChangesNothing;
543 
544 		send_change (Properties::name);
545 
546 		RegionFactory::CheckNewRegion (shared_from_this());
547 	}
548 }
549 
550 bool
at_natural_position() const551 Region::at_natural_position () const
552 {
553 	boost::shared_ptr<Playlist> pl (playlist());
554 
555 	if (!pl) {
556 		return false;
557 	}
558 
559 	boost::shared_ptr<Region> whole_file_region = get_parent();
560 
561 	if (whole_file_region) {
562 		if (_position == whole_file_region->position() + _start) {
563 			return true;
564 		}
565 	}
566 
567 	return false;
568 }
569 
570 void
move_to_natural_position()571 Region::move_to_natural_position ()
572 {
573 	boost::shared_ptr<Playlist> pl (playlist());
574 
575 	if (!pl) {
576 		return;
577 	}
578 
579 	boost::shared_ptr<Region> whole_file_region = get_parent();
580 
581 	if (whole_file_region) {
582 		set_position (whole_file_region->position() + _start);
583 	}
584 }
585 
586 void
special_set_position(samplepos_t pos)587 Region::special_set_position (samplepos_t pos)
588 {
589 	/* this is used when creating a whole file region as
590 	 * a way to store its "natural" or "captured" position.
591 	 */
592 
593 	_position = pos;
594 }
595 
596 void
set_position_lock_style(PositionLockStyle ps)597 Region::set_position_lock_style (PositionLockStyle ps)
598 {
599 	if (_position_lock_style != ps) {
600 
601 		boost::shared_ptr<Playlist> pl (playlist());
602 
603 		_position_lock_style = ps;
604 
605 		send_change (Properties::position_lock_style);
606 	}
607 }
608 
609 void
update_after_tempo_map_change(bool send)610 Region::update_after_tempo_map_change (bool send)
611 {
612 	boost::shared_ptr<Playlist> pl (playlist());
613 
614 	if (!pl) {
615 		return;
616 	}
617 
618 	if (_position_lock_style == AudioTime) {
619 		/* don't signal as the actual position has not chnged */
620 		recompute_position_from_lock_style (0);
621 		return;
622 	}
623 
624 	/* prevent movement before 0 */
625 	const samplepos_t pos = max ((samplepos_t) 0, _session.tempo_map().sample_at_beat (_beat));
626 	/* we have _beat. update sample position non-musically */
627 	set_position_internal (pos, false, 0);
628 
629 	/* do this even if the position is the same. this helps out
630 	 * a GUI that has moved its representation already.
631 	 */
632 
633 	if (send) {
634 		send_change (Properties::position);
635 	}
636 }
637 
638 void
set_position(samplepos_t pos,int32_t sub_num)639 Region::set_position (samplepos_t pos, int32_t sub_num)
640 {
641 	if (!can_move()) {
642 		return;
643 	}
644 
645 	/* do this even if the position is the same. this helps out
646 	 * a GUI that has moved its representation already.
647 	 */
648 	PropertyChange p_and_l;
649 
650 	p_and_l.add (Properties::position);
651 
652 	if (position_lock_style() == AudioTime) {
653 		set_position_internal (pos, true, sub_num);
654 	} else {
655 		if (!_session.loading()) {
656 			_beat = _session.tempo_map().exact_beat_at_sample (pos, sub_num);
657 			_quarter_note = _session.tempo_map().quarter_note_at_beat (_beat);
658 		}
659 
660 		set_position_internal (pos, false, sub_num);
661 	}
662 
663 	if (position_lock_style() == MusicTime) {
664 		p_and_l.add (Properties::length);
665 	}
666 
667 	send_change (p_and_l);
668 
669 }
670 
671 void
set_position_internal(samplepos_t pos,bool allow_bbt_recompute,const int32_t sub_num)672 Region::set_position_internal (samplepos_t pos, bool allow_bbt_recompute, const int32_t sub_num)
673 {
674 	/* We emit a change of Properties::position even if the position hasn't changed
675 	 * (see Region::set_position), so we must always set this up so that
676 	 * e.g. Playlist::notify_region_moved doesn't use an out-of-date last_position.
677 	 */
678 	_last_position = _position;
679 
680 	if (_position != pos) {
681 		_position = pos;
682 
683 		if (allow_bbt_recompute) {
684 			recompute_position_from_lock_style (sub_num);
685 		} else {
686 			/* MusicTime dictates that we glue to ardour beats. the pulse may have changed.*/
687 			_quarter_note = _session.tempo_map().quarter_note_at_beat (_beat);
688 		}
689 
690 		/* check that the new _position wouldn't make the current
691 		 * length impossible - if so, change the length.
692 		 *
693 		 * XXX is this the right thing to do?
694 		 */
695 		if (max_samplepos - _length < _position) {
696 			_last_length = _length;
697 			_length = max_samplepos - _position;
698 		}
699 	}
700 }
701 
702 void
set_position_music(double qn)703 Region::set_position_music (double qn)
704 {
705 	if (!can_move()) {
706 		return;
707 	}
708 
709 	/* do this even if the position is the same. this helps out
710 	 * a GUI that has moved its representation already.
711 	 */
712 	PropertyChange p_and_l;
713 
714 	p_and_l.add (Properties::position);
715 
716 	if (!_session.loading()) {
717 		_beat = _session.tempo_map().beat_at_quarter_note (qn);
718 	}
719 
720 	/* will set sample accordingly */
721 	set_position_music_internal (qn);
722 
723 	if (position_lock_style() == MusicTime) {
724 		p_and_l.add (Properties::length);
725 	}
726 
727 	send_change (p_and_l);
728 }
729 
730 void
set_position_music_internal(double qn)731 Region::set_position_music_internal (double qn)
732 {
733 	/* We emit a change of Properties::position even if the position hasn't changed
734 	 * (see Region::set_position), so we must always set this up so that
735 	 * e.g. Playlist::notify_region_moved doesn't use an out-of-date last_position.
736 	 */
737 	_last_position = _position;
738 
739 	if (_quarter_note != qn) {
740 		_position = _session.tempo_map().sample_at_quarter_note (qn);
741 		_quarter_note = qn;
742 
743 		/* check that the new _position wouldn't make the current
744 		 * length impossible - if so, change the length.
745 		 *
746 		 * XXX is this the right thing to do?
747 		 */
748 		if (max_samplepos - _length < _position) {
749 			_last_length = _length;
750 			_length = max_samplepos - _position;
751 		}
752 	}
753 }
754 
755 /** A gui may need to create a region, then place it in an initial
756  * position determined by the user.
757  * When this takes place within one gui operation, we have to reset
758  * _last_position to prevent an implied move.
759  */
760 void
set_initial_position(samplepos_t pos)761 Region::set_initial_position (samplepos_t pos)
762 {
763 	if (!can_move()) {
764 		return;
765 	}
766 
767 	if (_position != pos) {
768 		_position = pos;
769 
770 		/* check that the new _position wouldn't make the current
771 		 * length impossible - if so, change the length.
772 		 *
773 		 * XXX is this the right thing to do?
774 		 */
775 
776 		if (max_samplepos - _length < _position) {
777 			_last_length = _length;
778 			_length = max_samplepos - _position;
779 		}
780 
781 		recompute_position_from_lock_style (0);
782 		/* ensure that this move doesn't cause a range move */
783 		_last_position = _position;
784 	}
785 
786 
787 	/* do this even if the position is the same. this helps out
788 	 * a GUI that has moved its representation already.
789 	 */
790 	send_change (Properties::position);
791 }
792 
793 void
recompute_position_from_lock_style(const int32_t sub_num)794 Region::recompute_position_from_lock_style (const int32_t sub_num)
795 {
796 	_beat = _session.tempo_map().exact_beat_at_sample (_position, sub_num);
797 	_quarter_note = _session.tempo_map().exact_qn_at_sample (_position, sub_num);
798 }
799 
800 void
nudge_position(sampleoffset_t n)801 Region::nudge_position (sampleoffset_t n)
802 {
803 	if (locked() || video_locked()) {
804 		return;
805 	}
806 
807 	if (n == 0) {
808 		return;
809 	}
810 
811 	samplepos_t new_position = _position;
812 
813 	if (n > 0) {
814 		if (_position > max_samplepos - n) {
815 			new_position = max_samplepos;
816 		} else {
817 			new_position += n;
818 		}
819 	} else {
820 		if (_position < -n) {
821 			new_position = 0;
822 		} else {
823 			new_position += n;
824 		}
825 	}
826 	/* assumes non-musical nudge */
827 	set_position_internal (new_position, true, 0);
828 
829 	send_change (Properties::position);
830 }
831 
832 void
set_ancestral_data(samplepos_t s,samplecnt_t l,float st,float sh)833 Region::set_ancestral_data (samplepos_t s, samplecnt_t l, float st, float sh)
834 {
835 	_ancestral_length = l;
836 	_ancestral_start = s;
837 	_stretch = st;
838 	_shift = sh;
839 }
840 
841 void
set_start(samplepos_t pos)842 Region::set_start (samplepos_t pos)
843 {
844 	if (locked() || position_locked() || video_locked()) {
845 		return;
846 	}
847 	/* This just sets the start, nothing else. It effectively shifts
848 	 * the contents of the Region within the overall extent of the Source,
849 	 * without changing the Region's position or length
850 	 */
851 
852 	if (_start != pos) {
853 
854 		if (!verify_start (pos)) {
855 			return;
856 		}
857 
858 		set_start_internal (pos);
859 		_whole_file = false;
860 		first_edit ();
861 		maybe_invalidate_transients ();
862 
863 		send_change (Properties::start);
864 	}
865 }
866 
867 void
move_start(sampleoffset_t distance,const int32_t sub_num)868 Region::move_start (sampleoffset_t distance, const int32_t sub_num)
869 {
870 	if (locked() || position_locked() || video_locked()) {
871 		return;
872 	}
873 
874 	samplepos_t new_start;
875 
876 	if (distance > 0) {
877 
878 		if (_start > max_samplepos - distance) {
879 			new_start = max_samplepos; // makes no sense
880 		} else {
881 			new_start = _start + distance;
882 		}
883 
884 		if (!verify_start (new_start)) {
885 			return;
886 		}
887 
888 	} else if (distance < 0) {
889 
890 		if (_start < -distance) {
891 			new_start = 0;
892 		} else {
893 			new_start = _start + distance;
894 		}
895 
896 	} else {
897 		return;
898 	}
899 
900 	if (new_start == _start) {
901 		return;
902 	}
903 
904 	set_start_internal (new_start, sub_num);
905 
906 	_whole_file = false;
907 	first_edit ();
908 
909 	send_change (Properties::start);
910 }
911 
912 void
trim_front(samplepos_t new_position,const int32_t sub_num)913 Region::trim_front (samplepos_t new_position, const int32_t sub_num)
914 {
915 	modify_front (new_position, false, sub_num);
916 }
917 
918 void
cut_front(samplepos_t new_position,const int32_t sub_num)919 Region::cut_front (samplepos_t new_position, const int32_t sub_num)
920 {
921 	modify_front (new_position, true, sub_num);
922 }
923 
924 void
cut_end(samplepos_t new_endpoint,const int32_t sub_num)925 Region::cut_end (samplepos_t new_endpoint, const int32_t sub_num)
926 {
927 	modify_end (new_endpoint, true, sub_num);
928 }
929 
930 void
modify_front(samplepos_t new_position,bool reset_fade,const int32_t sub_num)931 Region::modify_front (samplepos_t new_position, bool reset_fade, const int32_t sub_num)
932 {
933 	if (locked()) {
934 		return;
935 	}
936 
937 	samplepos_t end = last_sample();
938 	samplepos_t source_zero;
939 
940 	if (_position > _start) {
941 		source_zero = _position - _start;
942 	} else {
943 		source_zero = 0; // its actually negative, but this will work for us
944 	}
945 
946 	if (new_position < end) { /* can't trim it zero or negative length */
947 
948 		samplecnt_t newlen = 0;
949 
950 		if (!can_trim_start_before_source_start ()) {
951 			/* can't trim it back past where source position zero is located */
952 			new_position = max (new_position, source_zero);
953 		}
954 
955 		if (new_position > _position) {
956 			newlen = _length - (new_position - _position);
957 		} else {
958 			newlen = _length + (_position - new_position);
959 		}
960 
961 		trim_to_internal (new_position, newlen, sub_num);
962 
963 		if (reset_fade) {
964 			_right_of_split = true;
965 		}
966 
967 		if (!property_changes_suspended()) {
968 			recompute_at_start ();
969 		}
970 
971 		maybe_invalidate_transients ();
972 	}
973 }
974 
975 void
modify_end(samplepos_t new_endpoint,bool reset_fade,const int32_t sub_num)976 Region::modify_end (samplepos_t new_endpoint, bool reset_fade, const int32_t sub_num)
977 {
978 	if (locked()) {
979 		return;
980 	}
981 
982 	if (new_endpoint > _position) {
983 		trim_to_internal (_position, new_endpoint - _position, sub_num);
984 		if (reset_fade) {
985 			_left_of_split = true;
986 		}
987 		if (!property_changes_suspended()) {
988 			recompute_at_end ();
989 		}
990 	}
991 }
992 
993 /** @param new_endpoint New region end point, such that, for example,
994  * a region at 0 of length 10 has an endpoint of 9.
995  */
996 void
trim_end(samplepos_t new_endpoint,const int32_t sub_num)997 Region::trim_end (samplepos_t new_endpoint, const int32_t sub_num)
998 {
999 	modify_end (new_endpoint, false, sub_num);
1000 }
1001 
1002 void
trim_to(samplepos_t position,samplecnt_t length,const int32_t sub_num)1003 Region::trim_to (samplepos_t position, samplecnt_t length, const int32_t sub_num)
1004 {
1005 	if (locked()) {
1006 		return;
1007 	}
1008 
1009 	trim_to_internal (position, length, sub_num);
1010 
1011 	if (!property_changes_suspended()) {
1012 		recompute_at_start ();
1013 		recompute_at_end ();
1014 	}
1015 }
1016 
1017 void
trim_to_internal(samplepos_t position,samplecnt_t length,const int32_t sub_num)1018 Region::trim_to_internal (samplepos_t position, samplecnt_t length, const int32_t sub_num)
1019 {
1020 	samplepos_t new_start;
1021 
1022 	if (locked()) {
1023 		return;
1024 	}
1025 
1026 	sampleoffset_t const start_shift = position - _position;
1027 
1028 	if (start_shift > 0) {
1029 
1030 		if (_start > max_samplepos - start_shift) {
1031 			new_start = max_samplepos;
1032 		} else {
1033 			new_start = _start + start_shift;
1034 		}
1035 
1036 	} else if (start_shift < 0) {
1037 
1038 		if (_start < -start_shift && !can_trim_start_before_source_start ()) {
1039 			new_start = 0;
1040 		} else {
1041 			new_start = _start + start_shift;
1042 		}
1043 
1044 	} else {
1045 		new_start = _start;
1046 	}
1047 
1048 	if (!verify_start_and_length (new_start, length)) {
1049 		return;
1050 	}
1051 
1052 	PropertyChange what_changed;
1053 
1054 	if (_start != new_start) {
1055 		set_start_internal (new_start, sub_num);
1056 		what_changed.add (Properties::start);
1057 	}
1058 
1059 
1060 	/* Set position before length, otherwise for MIDI regions this bad thing happens:
1061 	 * 1. we call set_length_internal; length in beats is computed using the region's current
1062 	 *    (soon-to-be old) position
1063 	 * 2. we call set_position_internal; position is set and length in samples re-computed using
1064 	 *    length in beats from (1) but at the new position, which is wrong if the region
1065 	 *    straddles a tempo/meter change.
1066 	 */
1067 
1068 	if (_position != position) {
1069 		if (!property_changes_suspended()) {
1070 			_last_position = _position;
1071 		}
1072 		set_position_internal (position, true, sub_num);
1073 		what_changed.add (Properties::position);
1074 	}
1075 
1076 	if (_length != length) {
1077 		if (!property_changes_suspended()) {
1078 			_last_length = _length;
1079 		}
1080 		set_length_internal (length, sub_num);
1081 		what_changed.add (Properties::length);
1082 	}
1083 
1084 	_whole_file = false;
1085 
1086 	PropertyChange start_and_length;
1087 
1088 	start_and_length.add (Properties::start);
1089 	start_and_length.add (Properties::length);
1090 
1091 	if (what_changed.contains (start_and_length)) {
1092 		first_edit ();
1093 	}
1094 
1095 	if (!what_changed.empty()) {
1096 		send_change (what_changed);
1097 	}
1098 }
1099 
1100 void
set_hidden(bool yn)1101 Region::set_hidden (bool yn)
1102 {
1103 	if (hidden() != yn) {
1104 		_hidden = yn;
1105 		send_change (Properties::hidden);
1106 	}
1107 }
1108 
1109 void
set_whole_file(bool yn)1110 Region::set_whole_file (bool yn)
1111 {
1112 	_whole_file = yn;
1113 	/* no change signal */
1114 }
1115 
1116 void
set_automatic(bool yn)1117 Region::set_automatic (bool yn)
1118 {
1119 	_automatic = yn;
1120 	/* no change signal */
1121 }
1122 
1123 void
set_muted(bool yn)1124 Region::set_muted (bool yn)
1125 {
1126 	if (muted() != yn) {
1127 		_muted = yn;
1128 		send_change (Properties::muted);
1129 	}
1130 }
1131 
1132 void
set_opaque(bool yn)1133 Region::set_opaque (bool yn)
1134 {
1135 	if (opaque() != yn) {
1136 		_opaque = yn;
1137 		send_change (Properties::opaque);
1138 	}
1139 }
1140 
1141 void
set_locked(bool yn)1142 Region::set_locked (bool yn)
1143 {
1144 	if (locked() != yn) {
1145 		_locked = yn;
1146 		send_change (Properties::locked);
1147 	}
1148 }
1149 
1150 void
set_video_locked(bool yn)1151 Region::set_video_locked (bool yn)
1152 {
1153 	if (video_locked() != yn) {
1154 		_video_locked = yn;
1155 		send_change (Properties::video_locked);
1156 	}
1157 }
1158 
1159 void
set_position_locked(bool yn)1160 Region::set_position_locked (bool yn)
1161 {
1162 	if (position_locked() != yn) {
1163 		_position_locked = yn;
1164 		send_change (Properties::locked);
1165 	}
1166 }
1167 
1168 /** Set the region's sync point.
1169  *  @param absolute_pos Session time.
1170  */
1171 void
set_sync_position(samplepos_t absolute_pos)1172 Region::set_sync_position (samplepos_t absolute_pos)
1173 {
1174 	/* position within our file */
1175 	samplepos_t const file_pos = _start + (absolute_pos - _position);
1176 
1177 	if (file_pos != _sync_position) {
1178 		_sync_marked = true;
1179 		_sync_position = file_pos;
1180 		if (!property_changes_suspended()) {
1181 			maybe_uncopy ();
1182 		}
1183 
1184 		send_change (Properties::sync_position);
1185 	}
1186 }
1187 
1188 void
clear_sync_position()1189 Region::clear_sync_position ()
1190 {
1191 	if (sync_marked()) {
1192 		_sync_marked = false;
1193 		if (!property_changes_suspended()) {
1194 			maybe_uncopy ();
1195 		}
1196 
1197 		send_change (Properties::sync_position);
1198 	}
1199 }
1200 
1201 /* @return the sync point relative the first sample of the region */
1202 sampleoffset_t
sync_offset(int & dir) const1203 Region::sync_offset (int& dir) const
1204 {
1205 	if (sync_marked()) {
1206 		if (_sync_position > _start) {
1207 			dir = 1;
1208 			return _sync_position - _start;
1209 		} else {
1210 			dir = -1;
1211 			return _start - _sync_position;
1212 		}
1213 	} else {
1214 		dir = 0;
1215 		return 0;
1216 	}
1217 }
1218 
1219 samplepos_t
adjust_to_sync(samplepos_t pos) const1220 Region::adjust_to_sync (samplepos_t pos) const
1221 {
1222 	int sync_dir;
1223 	sampleoffset_t offset = sync_offset (sync_dir);
1224 
1225 	// cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1226 
1227 	if (sync_dir > 0) {
1228 		if (pos > offset) {
1229 			pos -= offset;
1230 		} else {
1231 			pos = 0;
1232 		}
1233 	} else {
1234 		if (max_samplepos - pos > offset) {
1235 			pos += offset;
1236 		}
1237 	}
1238 
1239 	return pos;
1240 }
1241 
1242 /** @return Sync position in session time */
1243 samplepos_t
sync_position() const1244 Region::sync_position() const
1245 {
1246 	if (sync_marked()) {
1247 		return _position - _start + _sync_position;
1248 	} else {
1249 		/* if sync has not been marked, use the start of the region */
1250 		return _position;
1251 	}
1252 }
1253 
1254 void
raise()1255 Region::raise ()
1256 {
1257 	boost::shared_ptr<Playlist> pl (playlist());
1258 	if (pl) {
1259 		pl->raise_region (shared_from_this ());
1260 	}
1261 }
1262 
1263 void
lower()1264 Region::lower ()
1265 {
1266 	boost::shared_ptr<Playlist> pl (playlist());
1267 	if (pl) {
1268 		pl->lower_region (shared_from_this ());
1269 	}
1270 }
1271 
1272 
1273 void
raise_to_top()1274 Region::raise_to_top ()
1275 {
1276 	boost::shared_ptr<Playlist> pl (playlist());
1277 	if (pl) {
1278 		pl->raise_region_to_top (shared_from_this());
1279 	}
1280 }
1281 
1282 void
lower_to_bottom()1283 Region::lower_to_bottom ()
1284 {
1285 	boost::shared_ptr<Playlist> pl (playlist());
1286 	if (pl) {
1287 		pl->lower_region_to_bottom (shared_from_this());
1288 	}
1289 }
1290 
1291 void
set_layer(layer_t l)1292 Region::set_layer (layer_t l)
1293 {
1294 	_layer = l;
1295 }
1296 
1297 XMLNode&
state()1298 Region::state ()
1299 {
1300 	XMLNode *node = new XMLNode ("Region");
1301 	char buf2[64];
1302 
1303 	/* custom version of 'add_properties (*node);'
1304 	 * skip values that have have dedicated save functions
1305 	 * in AudioRegion::state()
1306 	 */
1307 	for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
1308 		if (!strcmp(i->second->property_name(), (const char*)"Envelope")) continue;
1309 		if (!strcmp(i->second->property_name(), (const char*)"FadeIn")) continue;
1310 		if (!strcmp(i->second->property_name(), (const char*)"FadeOut")) continue;
1311 		if (!strcmp(i->second->property_name(), (const char*)"InverseFadeIn")) continue;
1312 		if (!strcmp(i->second->property_name(), (const char*)"InverseFadeOut")) continue;
1313 		i->second->get_value (*node);
1314 	}
1315 
1316 	node->set_property ("id", id ());
1317 	node->set_property ("type", _type);
1318 
1319 	std::string fe;
1320 
1321 	switch (_first_edit) {
1322 	case EditChangesNothing:
1323 		fe = X_("nothing");
1324 		break;
1325 	case EditChangesName:
1326 		fe = X_("name");
1327 		break;
1328 	case EditChangesID:
1329 		fe = X_("id");
1330 		break;
1331 	default: /* should be unreachable but makes g++ happy */
1332 		fe = X_("nothing");
1333 		break;
1334 	}
1335 
1336 	node->set_property ("first-edit", fe);
1337 
1338 	/* note: flags are stored by derived classes */
1339 
1340 	for (uint32_t n=0; n < _sources.size(); ++n) {
1341 		snprintf (buf2, sizeof(buf2), "source-%d", n);
1342 		node->set_property (buf2, _sources[n]->id());
1343 	}
1344 
1345 	for (uint32_t n=0; n < _master_sources.size(); ++n) {
1346 		snprintf (buf2, sizeof(buf2), "master-source-%d", n);
1347 		node->set_property (buf2, _master_sources[n]->id ());
1348 	}
1349 
1350 	/* Only store nested sources for the whole-file region that acts
1351 	   as the parent/root of all regions using it.
1352 	*/
1353 
1354 	if (_whole_file && max_source_level() > 0) {
1355 
1356 		XMLNode* nested_node = new XMLNode (X_("NestedSource"));
1357 
1358 		/* region is compound - get its playlist and
1359 		   store that before we list the region that
1360 		   needs it ...
1361 		*/
1362 
1363 		for (SourceList::const_iterator s = _sources.begin(); s != _sources.end(); ++s) {
1364 			nested_node->add_child_nocopy ((*s)->get_state ());
1365 		}
1366 
1367 		if (nested_node) {
1368 			node->add_child_nocopy (*nested_node);
1369 		}
1370 	}
1371 
1372 	if (_extra_xml) {
1373 		node->add_child_copy (*_extra_xml);
1374 	}
1375 
1376 	return *node;
1377 }
1378 
1379 XMLNode&
get_state()1380 Region::get_state ()
1381 {
1382 	return state ();
1383 }
1384 
1385 int
set_state(const XMLNode & node,int version)1386 Region::set_state (const XMLNode& node, int version)
1387 {
1388 	PropertyChange what_changed;
1389 	return _set_state (node, version, what_changed, true);
1390 }
1391 
1392 int
_set_state(const XMLNode & node,int,PropertyChange & what_changed,bool send)1393 Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_changed, bool send)
1394 {
1395 	Timecode::BBT_Time bbt_time;
1396 
1397 	Stateful::save_extra_xml (node);
1398 
1399 	what_changed = set_values (node);
1400 
1401 	/* Regions derived from "Destructive/Tape" mode tracks in earlier
1402 	 * versions will have their length set to an extremely large value
1403 	 * (essentially the maximum possible length of a file). Detect this
1404 	 * here and reset to the actual source length (using the first source
1405 	 * as a proxy for all of them). For "previously destructive" sources,
1406 	 * this will correspond to the full extent of the data actually written
1407 	 * to the file (though this may include blank space if discontiguous
1408 	 * punches/capture passes were carried out.
1409 	 */
1410 
1411 	if (!_sources.empty() && _type == DataType::AUDIO) {
1412 		if (_length > _sources.front()->length(_position)) {
1413 			_length = _sources.front()->length(_position) - _start;
1414 		}
1415 	}
1416 
1417 	set_id (node);
1418 
1419 	if (_position_lock_style == MusicTime) {
1420 		std::string bbt_str;
1421 		if (node.get_property ("bbt-position", bbt_str)) {
1422 			if (sscanf (bbt_str.c_str(), "%d|%d|%d",
1423 				    &bbt_time.bars,
1424 				    &bbt_time.beats,
1425 				    &bbt_time.ticks) != 3) {
1426 				_position_lock_style = AudioTime;
1427 				_beat = _session.tempo_map().beat_at_sample (_position);
1428 			} else {
1429 				_beat = _session.tempo_map().beat_at_bbt (bbt_time);
1430 			}
1431 			/* no position property change for legacy Property, so we do this here */
1432 			_quarter_note = _session.tempo_map().quarter_note_at_beat (_beat);
1433 		}
1434 	}
1435 
1436 	/* fix problems with old sessions corrupted by impossible
1437 	   values for _stretch or _shift
1438 	*/
1439 	if (_stretch == 0.0f) {
1440 		_stretch = 1.0f;
1441 	}
1442 
1443 	if (_shift == 0.0f) {
1444 		_shift = 1.0f;
1445 	}
1446 
1447 	if (send) {
1448 		send_change (what_changed);
1449 	}
1450 
1451 	/* Quick fix for 2.x sessions when region is muted */
1452 	std::string flags;
1453 	if (node.get_property (X_("flags"), flags)) {
1454 		if (string::npos != flags.find("Muted")){
1455 			set_muted (true);
1456 		}
1457 	}
1458 
1459 	// saved property is invalid, region-transients are not saved
1460 	if (_user_transients.size() == 0){
1461 		_valid_transients = false;
1462 	}
1463 
1464 	return 0;
1465 }
1466 
1467 void
suspend_property_changes()1468 Region::suspend_property_changes ()
1469 {
1470 	Stateful::suspend_property_changes ();
1471 	_last_length = _length;
1472 	_last_position = _position;
1473 }
1474 
1475 void
mid_thaw(const PropertyChange & what_changed)1476 Region::mid_thaw (const PropertyChange& what_changed)
1477 {
1478 	if (what_changed.contains (Properties::length)) {
1479 		if (what_changed.contains (Properties::position)) {
1480 			recompute_at_start ();
1481 		}
1482 		recompute_at_end ();
1483 	}
1484 }
1485 
1486 void
send_change(const PropertyChange & what_changed)1487 Region::send_change (const PropertyChange& what_changed)
1488 {
1489 	if (what_changed.empty()) {
1490 		return;
1491 	}
1492 
1493 	Stateful::send_change (what_changed);
1494 
1495 	if (!Stateful::property_changes_suspended()) {
1496 
1497 		/* Try and send a shared_pointer unless this is part of the constructor.
1498 		 * If so, do nothing.
1499 		 */
1500 
1501 		try {
1502 			boost::shared_ptr<Region> rptr = shared_from_this();
1503 			if (_changemap) {
1504 				(*_changemap)[what_changed].push_back (rptr);
1505 			} else {
1506 				boost::shared_ptr<RegionList> rl (new RegionList);
1507 				rl->push_back (rptr);
1508 				RegionsPropertyChanged (rl, what_changed);
1509 			}
1510 		} catch (...) {
1511 			/* no shared_ptr available, relax; */
1512 		}
1513 	}
1514 }
1515 
1516 bool
overlap_equivalent(boost::shared_ptr<const Region> other) const1517 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1518 {
1519 	return coverage (other->first_sample(), other->last_sample()) != Evoral::OverlapNone;
1520 }
1521 
1522 bool
enclosed_equivalent(boost::shared_ptr<const Region> other) const1523 Region::enclosed_equivalent (boost::shared_ptr<const Region> other) const
1524 {
1525 	return (first_sample() >= other->first_sample() && last_sample() <= other->last_sample()) ||
1526 	       (first_sample() <= other->first_sample() && last_sample() >= other->last_sample()) ;
1527 }
1528 
1529 bool
layer_and_time_equivalent(boost::shared_ptr<const Region> other) const1530 Region::layer_and_time_equivalent (boost::shared_ptr<const Region> other) const
1531 {
1532 	return _layer == other->_layer &&
1533 		_position == other->_position &&
1534 		_length == other->_length;
1535 }
1536 
1537 bool
exact_equivalent(boost::shared_ptr<const Region> other) const1538 Region::exact_equivalent (boost::shared_ptr<const Region> other) const
1539 {
1540 	return _start == other->_start &&
1541 		_position == other->_position &&
1542 		_length == other->_length;
1543 }
1544 
1545 bool
size_equivalent(boost::shared_ptr<const Region> other) const1546 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1547 {
1548 	return _start == other->_start &&
1549 		_length == other->_length;
1550 }
1551 
1552 void
source_deleted(boost::weak_ptr<Source>)1553 Region::source_deleted (boost::weak_ptr<Source>)
1554 {
1555 	drop_sources ();
1556 
1557 	if (!_session.deletion_in_progress()) {
1558 		/* this is a very special case: at least one of the region's
1559 		   sources has bee deleted, so invalidate all references to
1560 		   ourselves. Do NOT do this during session deletion, because
1561 		   then we run the risk that this will actually result
1562 		   in this object being deleted (as refcnt goes to zero)
1563 		   while emitting DropReferences.
1564 		*/
1565 
1566 		drop_references ();
1567 	}
1568 }
1569 
1570 vector<string>
master_source_names()1571 Region::master_source_names ()
1572 {
1573 	SourceList::iterator i;
1574 
1575 	vector<string> names;
1576 	for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1577 		names.push_back((*i)->name());
1578 	}
1579 
1580 	return names;
1581 }
1582 
1583 void
set_master_sources(const SourceList & srcs)1584 Region::set_master_sources (const SourceList& srcs)
1585 {
1586 	for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1587 		(*i)->dec_use_count ();
1588 	}
1589 
1590 	_master_sources = srcs;
1591 	assert (_sources.size() == _master_sources.size());
1592 
1593 	for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1594 		(*i)->inc_use_count ();
1595 	}
1596 }
1597 
1598 bool
source_equivalent(boost::shared_ptr<const Region> other) const1599 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1600 {
1601 	if (!other)
1602 		return false;
1603 
1604 	if ((_sources.size() != other->_sources.size()) ||
1605 	    (_master_sources.size() != other->_master_sources.size())) {
1606 		return false;
1607 	}
1608 
1609 	SourceList::const_iterator i;
1610 	SourceList::const_iterator io;
1611 
1612 	for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1613 		if ((*i)->id() != (*io)->id()) {
1614 			return false;
1615 		}
1616 	}
1617 
1618 	for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1619 		if ((*i)->id() != (*io)->id()) {
1620 			return false;
1621 		}
1622 	}
1623 
1624 	return true;
1625 }
1626 
1627 bool
any_source_equivalent(boost::shared_ptr<const Region> other) const1628 Region::any_source_equivalent (boost::shared_ptr<const Region> other) const
1629 {
1630 	if (!other) {
1631 		return false;
1632 	}
1633 
1634 	SourceList::const_iterator i;
1635 	SourceList::const_iterator io;
1636 
1637 	for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1638 		if ((*i)->id() == (*io)->id()) {
1639 			return true;
1640 		}
1641 	}
1642 
1643 	return false;
1644 }
1645 
1646 std::string
source_string() const1647 Region::source_string () const
1648 {
1649 	//string res = itos(_sources.size());
1650 
1651 	stringstream res;
1652 	res << _sources.size() << ":";
1653 
1654 	SourceList::const_iterator i;
1655 
1656 	for (i = _sources.begin(); i != _sources.end(); ++i) {
1657 		res << (*i)->id() << ":";
1658 	}
1659 
1660 	for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1661 		res << (*i)->id() << ":";
1662 	}
1663 
1664 	return res.str();
1665 }
1666 
1667 void
deep_sources(std::set<boost::shared_ptr<Source>> & sources) const1668 Region::deep_sources (std::set<boost::shared_ptr<Source> > & sources) const
1669 {
1670 	for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1671 
1672 		boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1673 
1674 		if (ps) {
1675 			if (sources.find (ps) == sources.end()) {
1676 				/* (Playlist)Source not currently in
1677 				   accumulating set, so recurse.
1678 				*/
1679 				ps->playlist()->deep_sources (sources);
1680 			}
1681 		}
1682 
1683 		/* add this source */
1684 		sources.insert (*i);
1685 	}
1686 
1687 	for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1688 
1689 		boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1690 
1691 		if (ps) {
1692 			if (sources.find (ps) == sources.end()) {
1693 				/* (Playlist)Source not currently in
1694 				   accumulating set, so recurse.
1695 				*/
1696 				ps->playlist()->deep_sources (sources);
1697 			}
1698 		}
1699 
1700 		/* add this source */
1701 		sources.insert (*i);
1702 	}
1703 }
1704 
1705 bool
uses_source(boost::shared_ptr<const Source> source,bool shallow) const1706 Region::uses_source (boost::shared_ptr<const Source> source, bool shallow) const
1707 {
1708 	for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1709 		if (*i == source) {
1710 			return true;
1711 		}
1712 
1713 		if (!shallow) {
1714 			boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1715 
1716 			if (ps) {
1717 				if (ps->playlist()->uses_source (source)) {
1718 					return true;
1719 				}
1720 			}
1721 		}
1722 	}
1723 
1724 	for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1725 		if (*i == source) {
1726 			return true;
1727 		}
1728 
1729 		if (!shallow) {
1730 			boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1731 
1732 			if (ps) {
1733 				if (ps->playlist()->uses_source (source)) {
1734 					return true;
1735 				}
1736 			}
1737 		}
1738 	}
1739 
1740 	return false;
1741 }
1742 
1743 
1744 samplecnt_t
source_length(uint32_t n) const1745 Region::source_length(uint32_t n) const
1746 {
1747 	assert (n < _sources.size());
1748 	return _sources[n]->length (_position - _start);
1749 }
1750 
1751 bool
verify_length(samplecnt_t & len)1752 Region::verify_length (samplecnt_t& len)
1753 {
1754 	if (source() && source()->length_mutable()) {
1755 		return true;
1756 	}
1757 
1758 	samplecnt_t maxlen = 0;
1759 
1760 	for (uint32_t n = 0; n < _sources.size(); ++n) {
1761 		maxlen = max (maxlen, source_length(n) - _start);
1762 	}
1763 
1764 	len = min (len, maxlen);
1765 
1766 	return true;
1767 }
1768 
1769 bool
verify_start_and_length(samplepos_t new_start,samplecnt_t & new_length)1770 Region::verify_start_and_length (samplepos_t new_start, samplecnt_t& new_length)
1771 {
1772 	if (source() && source()->length_mutable()) {
1773 		return true;
1774 	}
1775 
1776 	samplecnt_t maxlen = 0;
1777 
1778 	for (uint32_t n = 0; n < _sources.size(); ++n) {
1779 		maxlen = max (maxlen, source_length(n) - new_start);
1780 	}
1781 
1782 	new_length = min (new_length, maxlen);
1783 
1784 	return true;
1785 }
1786 
1787 bool
verify_start(samplepos_t pos)1788 Region::verify_start (samplepos_t pos)
1789 {
1790 	if (source() && source()->length_mutable()) {
1791 		return true;
1792 	}
1793 
1794 	for (uint32_t n = 0; n < _sources.size(); ++n) {
1795 		if (pos > source_length(n) - _length) {
1796 			return false;
1797 		}
1798 	}
1799 	return true;
1800 }
1801 
1802 bool
verify_start_mutable(samplepos_t & new_start)1803 Region::verify_start_mutable (samplepos_t& new_start)
1804 {
1805 	if (source() && source()->length_mutable()) {
1806 		return true;
1807 	}
1808 
1809 	for (uint32_t n = 0; n < _sources.size(); ++n) {
1810 		if (new_start > source_length(n) - _length) {
1811 			new_start = source_length(n) - _length;
1812 		}
1813 	}
1814 	return true;
1815 }
1816 
1817 boost::shared_ptr<Region>
get_parent() const1818 Region::get_parent() const
1819 {
1820 	boost::shared_ptr<Playlist> pl (playlist());
1821 
1822 	if (pl) {
1823 		boost::shared_ptr<Region> r;
1824 		boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1825 
1826 		if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1827 			return boost::static_pointer_cast<Region> (r);
1828 		}
1829 	}
1830 
1831 	return boost::shared_ptr<Region>();
1832 }
1833 
1834 int
apply(Filter & filter,Progress * progress)1835 Region::apply (Filter& filter, Progress* progress)
1836 {
1837 	return filter.run (shared_from_this(), progress);
1838 }
1839 
1840 
1841 void
maybe_invalidate_transients()1842 Region::maybe_invalidate_transients ()
1843 {
1844 	bool changed = !_onsets.empty();
1845 	_onsets.clear ();
1846 
1847 	if (_valid_transients || changed) {
1848 		send_change (PropertyChange (Properties::valid_transients));
1849 		return;
1850 	}
1851 }
1852 
1853 void
transients(AnalysisFeatureList & afl)1854 Region::transients (AnalysisFeatureList& afl)
1855 {
1856 	int cnt = afl.empty() ? 0 : 1;
1857 
1858 	Region::merge_features (afl, _onsets, _position);
1859 	Region::merge_features (afl, _user_transients, _position + _transient_user_start - _start);
1860 	if (!_onsets.empty ()) {
1861 		++cnt;
1862 	}
1863 	if (!_user_transients.empty ()) {
1864 		++cnt;
1865 	}
1866 	if (cnt > 1) {
1867 		afl.sort ();
1868 		// remove exact duplicates
1869 		TransientDetector::cleanup_transients (afl, _session.sample_rate(), 0);
1870 	}
1871 }
1872 
1873 bool
has_transients() const1874 Region::has_transients () const
1875 {
1876 	if (!_user_transients.empty ()) {
1877 		assert (_valid_transients);
1878 		return true;
1879 	}
1880 	if (!_onsets.empty ()) {
1881 		return true;
1882 	}
1883 	return false;
1884 }
1885 
1886 void
merge_features(AnalysisFeatureList & result,const AnalysisFeatureList & src,const sampleoffset_t off) const1887 Region::merge_features (AnalysisFeatureList& result, const AnalysisFeatureList& src, const sampleoffset_t off) const
1888 {
1889 	for (AnalysisFeatureList::const_iterator x = src.begin(); x != src.end(); ++x) {
1890 		const sampleoffset_t p = (*x) + off;
1891 		if (p < first_sample() || p > last_sample()) {
1892 			continue;
1893 		}
1894 		result.push_back (p);
1895 	}
1896 }
1897 
1898 void
captured_xruns(XrunPositions & xruns,bool abs) const1899 Region::captured_xruns (XrunPositions& xruns, bool abs) const
1900 {
1901 	bool was_empty = xruns.empty ();
1902 	for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) {
1903 		XrunPositions const& x = (*i)->captured_xruns ();
1904 		for (XrunPositions::const_iterator p = x.begin (); p != x.end (); ++p) {
1905 			if (abs) {
1906 				xruns.push_back (*p);
1907 			} else if (*p >= _start && *p < _start + _length) {
1908 				xruns.push_back (*p - _start);
1909 			}
1910 		}
1911 	}
1912 	if (_sources.size () > 1 || !was_empty) {
1913 		sort (xruns.begin (), xruns.end ());
1914 		xruns.erase (unique (xruns.begin (), xruns.end ()), xruns.end ());
1915 	}
1916 }
1917 
1918 void
get_cue_markers(CueMarkers & cues,bool abs) const1919 Region::get_cue_markers (CueMarkers& cues, bool abs) const
1920 {
1921 	for (SourceList::const_iterator s = _sources.begin (); s != _sources.end(); ++s) {
1922 		CueMarkers const& x = (*s)->cue_markers ();
1923 		for (CueMarkers::const_iterator p = x.begin (); p != x.end (); ++p) {
1924 			if (abs) {
1925 				cues.insert (*p);
1926 			} else if (p->position() >= _start && p->position() < _start + _length) {
1927 				cues.insert (CueMarker (p->text(), p->position() - _start));
1928 			}
1929 		}
1930 	}
1931 }
1932 
1933 void
move_cue_marker(CueMarker const & cm,samplepos_t region_relative_position)1934 Region::move_cue_marker (CueMarker const & cm, samplepos_t region_relative_position)
1935 {
1936 	for (SourceList::const_iterator s = _sources.begin (); s != _sources.end(); ++s) {
1937 		(*s)->move_cue_marker (cm, start() + region_relative_position);
1938 	}
1939 }
1940 
1941 void
rename_cue_marker(CueMarker & cm,std::string const & str)1942 Region::rename_cue_marker (CueMarker& cm, std::string const & str)
1943 {
1944 	for (SourceList::const_iterator s = _sources.begin (); s != _sources.end(); ++s) {
1945 		(*s)->rename_cue_marker (cm, str);
1946 	}
1947 }
1948 
1949 void
drop_sources()1950 Region::drop_sources ()
1951 {
1952 	for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) {
1953 		(*i)->dec_use_count ();
1954 	}
1955 
1956 	_sources.clear ();
1957 
1958 	for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1959 		(*i)->dec_use_count ();
1960 	}
1961 
1962 	_master_sources.clear ();
1963 }
1964 
1965 void
use_sources(SourceList const & s)1966 Region::use_sources (SourceList const & s)
1967 {
1968 	set<boost::shared_ptr<Source> > unique_srcs;
1969 
1970 	for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1971 
1972 		_sources.push_back (*i);
1973 		(*i)->inc_use_count ();
1974 		_master_sources.push_back (*i);
1975 		(*i)->inc_use_count ();
1976 
1977 		/* connect only once to DropReferences, even if sources are replicated
1978 		 */
1979 
1980 		if (unique_srcs.find (*i) == unique_srcs.end ()) {
1981 			unique_srcs.insert (*i);
1982 			(*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1983 		}
1984 	}
1985 }
1986 
1987 Trimmable::CanTrim
can_trim() const1988 Region::can_trim () const
1989 {
1990 	CanTrim ct = CanTrim (0);
1991 
1992 	if (locked()) {
1993 		return ct;
1994 	}
1995 
1996 	/* if not locked, we can always move the front later, and the end earlier
1997 	 */
1998 
1999 	ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier);
2000 
2001 	if (start() != 0 || can_trim_start_before_source_start ()) {
2002 		ct = CanTrim (ct | FrontTrimEarlier);
2003 	}
2004 
2005 	if (!_sources.empty()) {
2006 		if ((start() + length()) < _sources.front()->length (0)) {
2007 			ct = CanTrim (ct | EndTrimLater);
2008 		}
2009 	}
2010 
2011 	return ct;
2012 }
2013 
2014 uint32_t
max_source_level() const2015 Region::max_source_level () const
2016 {
2017 	uint32_t lvl = 0;
2018 
2019 	for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
2020 		lvl = max (lvl, (*i)->level());
2021 	}
2022 
2023 	return lvl;
2024 }
2025 
2026 bool
is_compound() const2027 Region::is_compound () const
2028 {
2029 	return max_source_level() > 0;
2030 }
2031 
2032 void
post_set(const PropertyChange & pc)2033 Region::post_set (const PropertyChange& pc)
2034 {
2035 	_quarter_note = _session.tempo_map().quarter_note_at_beat (_beat);
2036 }
2037 
2038 void
set_start_internal(samplecnt_t s,const int32_t sub_num)2039 Region::set_start_internal (samplecnt_t s, const int32_t sub_num)
2040 {
2041 	_start = s;
2042 }
2043 
2044 samplepos_t
earliest_possible_position() const2045 Region::earliest_possible_position () const
2046 {
2047 	if (_start > _position) {
2048 		return 0;
2049 	} else {
2050 		return _position - _start;
2051 	}
2052 }
2053 
2054 samplecnt_t
latest_possible_sample() const2055 Region::latest_possible_sample () const
2056 {
2057 	samplecnt_t minlen = max_samplecnt;
2058 
2059 	for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
2060 		/* non-audio regions have a length that may vary based on their
2061 		 * position, so we have to pass it in the call.
2062 		 */
2063 		minlen = min (minlen, (*i)->length (_position));
2064 	}
2065 
2066 	/* the latest possible last sample is determined by the current
2067 	 * position, plus the shortest source extent past _start.
2068 	 */
2069 
2070 	return _position + (minlen - _start) - 1;
2071 }
2072