#include <glibmm/threads.h>
#include "pbd/xml++.h"
+#include "pbd/types_convert.h"
#include "ardour/debug.h"
#include "ardour/filter.h"
#include "ardour/source.h"
#include "ardour/tempo.h"
#include "ardour/transient_detector.h"
+#include "ardour/types_convert.h"
#include "pbd/i18n.h"
, _position (Properties::position, 0) \
, _beat (Properties::beat, 0.0) \
, _sync_position (Properties::sync_position, (s)) \
- , _pulse (0.0) \
+ , _quarter_note (0.0) \
, _transient_user_start (0) \
, _transient_analysis_start (0) \
, _transient_analysis_end (0) \
, _position(Properties::position, other->_position) \
, _beat (Properties::beat, other->_beat) \
, _sync_position(Properties::sync_position, other->_sync_position) \
- , _pulse (other->_pulse) \
+ , _quarter_note (other->_quarter_note) \
, _user_transients (other->_user_transients) \
, _transient_user_start (other->_transient_user_start) \
, _transients (other->_transients) \
_start = other->_start;
_beat = other->_beat;
- _pulse = other->_pulse;
+ _quarter_note = other->_quarter_note;
/* sync pos is relative to start of file. our start-in-file is now zero,
so set our sync position to whatever the the difference between
the start within \a other is given by \a offset
(i.e. relative to the start of \a other's sources, the start is \a offset + \a other.start()
*/
-Region::Region (boost::shared_ptr<const Region> other, frameoffset_t offset, const int32_t sub_num)
+Region::Region (boost::shared_ptr<const Region> other, MusicFrame offset)
: SessionObject(other->session(), other->name())
, _type (other->data_type())
, REGION_COPY_STATE (other)
/* override state that may have been incorrectly inherited from the other region
*/
- _position = other->_position + offset;
_locked = false;
_whole_file = false;
_hidden = false;
use_sources (other->_sources);
set_master_sources (other->_master_sources);
- _start = other->_start + offset;
- _beat = _session.tempo_map().exact_beat_at_frame (_position, sub_num);
- _pulse = _session.tempo_map().exact_qn_at_frame (_position, sub_num) / 4.0;
+ _position = other->_position + offset.frame;
+ _start = other->_start + offset.frame;
+
+ /* prevent offset of 0 from altering musical position */
+ if (offset.frame != 0) {
+ const double offset_qn = _session.tempo_map().exact_qn_at_frame (other->_position + offset.frame, offset.division)
+ - other->_quarter_note;
+
+ _quarter_note = other->_quarter_note + offset_qn;
+ _beat = _session.tempo_map().beat_at_quarter_note (_quarter_note);
+ } else {
+ _quarter_note = _session.tempo_map().quarter_note_at_beat (_beat);
+ }
/* if the other region had a distinct sync point
set, then continue to use it as best we can.
_position_lock_style = ps;
- if (_position_lock_style == MusicTime) {
- _beat = _session.tempo_map().beat_at_frame (_position);
- _pulse = _session.tempo_map().pulse_at_frame (_position);
- }
-
send_change (Properties::position_lock_style);
}
}
return;
}
- const framepos_t pos = _session.tempo_map().frame_at_beat (_beat);
+ /* prevent movement before 0 */
+ const framepos_t pos = max ((framepos_t) 0, _session.tempo_map().frame_at_beat (_beat));
/* we have _beat. update frame position non-musically */
set_position_internal (pos, false, 0);
return;
}
- if (sub_num == 0) {
- set_position_internal (pos, true, 0);
- } else {
- double beat = _session.tempo_map().exact_beat_at_frame (pos, sub_num);
- _beat = beat;
- _pulse = _session.tempo_map().exact_qn_at_frame (pos, sub_num) / 4.0;
- set_position_internal (pos, false, sub_num);
- }
-
/* do this even if the position is the same. this helps out
a GUI that has moved its representation already.
*/
PropertyChange p_and_l;
p_and_l.add (Properties::position);
- /* Currently length change due to position change is only implemented
- for MidiRegion (Region has no length in beats).
- Notify a length change regardless (its more efficient for MidiRegions),
- and when Region has a _length_beats we will need it here anyway).
- */
- p_and_l.add (Properties::length);
+
+ if (position_lock_style() == AudioTime) {
+ set_position_internal (pos, true, sub_num);
+ } else {
+ if (!_session.loading()) {
+ _beat = _session.tempo_map().exact_beat_at_frame (pos, sub_num);
+ _quarter_note = _session.tempo_map().quarter_note_at_beat (_beat);
+ }
+
+ set_position_internal (pos, false, sub_num);
+ }
+
+ if (position_lock_style() == MusicTime) {
+ p_and_l.add (Properties::length);
+ }
send_change (p_and_l);
}
-/** A gui may need to create a region, then place it in an initial
- * position determined by the user.
- * When this takes place within one gui operation, we have to reset
- * _last_position to prevent an implied move.
- */
void
-Region::set_initial_position (framepos_t pos)
+Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute, const int32_t sub_num)
{
- if (!can_move()) {
- return;
- }
+ /* We emit a change of Properties::position even if the position hasn't changed
+ (see Region::set_position), so we must always set this up so that
+ e.g. Playlist::notify_region_moved doesn't use an out-of-date last_position.
+ */
+ _last_position = _position;
if (_position != pos) {
_position = pos;
+ if (allow_bbt_recompute) {
+ recompute_position_from_lock_style (sub_num);
+ } else {
+ /* MusicTime dictates that we glue to ardour beats. the pulse may have changed.*/
+ _quarter_note = _session.tempo_map().quarter_note_at_beat (_beat);
+ }
+
/* check that the new _position wouldn't make the current
length impossible - if so, change the length.
XXX is this the right thing to do?
*/
-
if (max_framepos - _length < _position) {
_last_length = _length;
_length = max_framepos - _position;
}
-
- recompute_position_from_lock_style (0);
- /* ensure that this move doesn't cause a range move */
- _last_position = _position;
}
+}
+void
+Region::set_position_music (double qn)
+{
+ if (!can_move()) {
+ return;
+ }
/* do this even if the position is the same. this helps out
a GUI that has moved its representation already.
*/
- send_change (Properties::position);
+ PropertyChange p_and_l;
+
+ p_and_l.add (Properties::position);
+
+ if (!_session.loading()) {
+ _beat = _session.tempo_map().beat_at_quarter_note (qn);
+ }
+
+ /* will set frame accordingly */
+ set_position_music_internal (qn);
+
+ if (position_lock_style() == MusicTime) {
+ p_and_l.add (Properties::length);
+ }
+
+ send_change (p_and_l);
}
void
-Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute, const int32_t sub_num)
+Region::set_position_music_internal (double qn)
{
/* We emit a change of Properties::position even if the position hasn't changed
(see Region::set_position), so we must always set this up so that
*/
_last_position = _position;
- if (_position != pos) {
- _position = pos;
+ if (_quarter_note != qn) {
+ _position = _session.tempo_map().frame_at_quarter_note (qn);
+ _quarter_note = qn;
- if (allow_bbt_recompute) {
- recompute_position_from_lock_style (sub_num);
- } else {
- /* MusicTime dictates that we glue to ardour beats. the pulse may have changed.*/
- _pulse = _session.tempo_map().pulse_at_beat (_beat);
+ /* check that the new _position wouldn't make the current
+ length impossible - if so, change the length.
+
+ XXX is this the right thing to do?
+ */
+ if (max_framepos - _length < _position) {
+ _last_length = _length;
+ _length = max_framepos - _position;
}
+ }
+}
+
+/** A gui may need to create a region, then place it in an initial
+ * position determined by the user.
+ * When this takes place within one gui operation, we have to reset
+ * _last_position to prevent an implied move.
+ */
+void
+Region::set_initial_position (framepos_t pos)
+{
+ if (!can_move()) {
+ return;
+ }
+
+ if (_position != pos) {
+ _position = pos;
/* check that the new _position wouldn't make the current
length impossible - if so, change the length.
XXX is this the right thing to do?
*/
+
if (max_framepos - _length < _position) {
_last_length = _length;
_length = max_framepos - _position;
}
+
+ recompute_position_from_lock_style (0);
+ /* ensure that this move doesn't cause a range move */
+ _last_position = _position;
}
+
+
+ /* do this even if the position is the same. this helps out
+ a GUI that has moved its representation already.
+ */
+ send_change (Properties::position);
}
void
Region::recompute_position_from_lock_style (const int32_t sub_num)
{
_beat = _session.tempo_map().exact_beat_at_frame (_position, sub_num);
- _pulse = _session.tempo_map().exact_qn_at_frame (_position, sub_num) / 4.0;
+ _quarter_note = _session.tempo_map().exact_qn_at_frame (_position, sub_num);
}
void
Region::state ()
{
XMLNode *node = new XMLNode ("Region");
- char buf[64];
char buf2[64];
- LocaleGuard lg;
- const char* fe = NULL;
/* custom version of 'add_properties (*node);'
* skip values that have have dedicated save functions
i->second->get_value (*node);
}
- id().print (buf, sizeof (buf));
- node->add_property ("id", buf);
- node->add_property ("type", _type.to_string());
+ node->set_property ("id", id ());
+ node->set_property ("type", _type);
+
+ std::string fe;
switch (_first_edit) {
case EditChangesNothing:
break;
}
- node->add_property ("first-edit", fe);
+ node->set_property ("first-edit", fe);
/* note: flags are stored by derived classes */
for (uint32_t n=0; n < _sources.size(); ++n) {
snprintf (buf2, sizeof(buf2), "source-%d", n);
- _sources[n]->id().print (buf, sizeof(buf));
- node->add_property (buf2, buf);
+ node->set_property (buf2, _sources[n]->id());
}
for (uint32_t n=0; n < _master_sources.size(); ++n) {
snprintf (buf2, sizeof(buf2), "master-source-%d", n);
- _master_sources[n]->id().print (buf, sizeof (buf));
- node->add_property (buf2, buf);
+ node->set_property (buf2, _master_sources[n]->id ());
}
/* Only store nested sources for the whole-file region that acts
int
Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_changed, bool send)
{
- XMLProperty const * prop;
Timecode::BBT_Time bbt_time;
Stateful::save_extra_xml (node);
set_id (node);
if (_position_lock_style == MusicTime) {
- if ((prop = node.property ("bbt-position")) != 0) {
- if (sscanf (prop->value().c_str(), "%d|%d|%d",
+ std::string bbt_str;
+ if (node.get_property ("bbt-position", bbt_str)) {
+ if (sscanf (bbt_str.c_str(), "%d|%d|%d",
&bbt_time.bars,
&bbt_time.beats,
&bbt_time.ticks) != 3) {
} else {
_beat = _session.tempo_map().beat_at_bbt (bbt_time);
}
+ /* no position property change for legacy Property, so we do this here */
+ _quarter_note = _session.tempo_map().quarter_note_at_beat (_beat);
}
}
- _pulse = _session.tempo_map().pulse_at_beat (_beat);
-
/* fix problems with old sessions corrupted by impossible
values for _stretch or _shift
*/
}
/* Quick fix for 2.x sessions when region is muted */
- if ((prop = node.property (X_("flags")))) {
- if (string::npos != prop->value().find("Muted")){
+ std::string flags;
+ if (node.get_property (X_("flags"), flags)) {
+ if (string::npos != flags.find("Muted")){
set_muted (true);
}
}
void
Region::post_set (const PropertyChange& pc)
{
- if (pc.contains (Properties::position)) {
- recompute_position_from_lock_style (0);
- }
+ _quarter_note = _session.tempo_map().quarter_note_at_beat (_beat);
}
void