implement methods in TempoMap for walking a given distance along a tempo map and returning the resulting time; add a new property, _length_beats, to MidiRegion; use previously mentioned methods to keep _length_beats up to date as regions are moved AND as tempo map changes occur
git-svn-id: svn://localhost/ardour2/branches/3.0@8274 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
df5e700f90
commit
e3c67bceb8
@ -117,6 +117,7 @@ class MidiRegion : public Region
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend class RegionFactory;
|
friend class RegionFactory;
|
||||||
|
PBD::Property<Evoral::MusicalTime> _length_beats;
|
||||||
|
|
||||||
MidiRegion (const SourceList&);
|
MidiRegion (const SourceList&);
|
||||||
MidiRegion (boost::shared_ptr<const MidiRegion>, frameoffset_t offset = 0, bool offset_relative = true);
|
MidiRegion (boost::shared_ptr<const MidiRegion>, frameoffset_t offset = 0, bool offset_relative = true);
|
||||||
@ -134,6 +135,8 @@ class MidiRegion : public Region
|
|||||||
void recompute_at_end ();
|
void recompute_at_end ();
|
||||||
|
|
||||||
void set_position_internal (framepos_t pos, bool allow_bbt_recompute);
|
void set_position_internal (framepos_t pos, bool allow_bbt_recompute);
|
||||||
|
void set_length_internal (framecnt_t len);
|
||||||
|
void update_length_beats ();
|
||||||
|
|
||||||
void model_changed ();
|
void model_changed ();
|
||||||
void model_automation_state_changed (Evoral::Parameter const &);
|
void model_automation_state_changed (Evoral::Parameter const &);
|
||||||
@ -143,6 +146,8 @@ class MidiRegion : public Region
|
|||||||
PBD::ScopedConnection _model_connection;
|
PBD::ScopedConnection _model_connection;
|
||||||
PBD::ScopedConnection _source_connection;
|
PBD::ScopedConnection _source_connection;
|
||||||
PBD::ScopedConnection _model_contents_connection;
|
PBD::ScopedConnection _model_contents_connection;
|
||||||
|
|
||||||
|
double _last_length_beats;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace ARDOUR */
|
} /* namespace ARDOUR */
|
||||||
|
@ -325,6 +325,7 @@ class Region
|
|||||||
|
|
||||||
void trim_to_internal (framepos_t position, framecnt_t length, void *src);
|
void trim_to_internal (framepos_t position, framecnt_t length, void *src);
|
||||||
virtual void set_position_internal (framepos_t pos, bool allow_bbt_recompute);
|
virtual void set_position_internal (framepos_t pos, bool allow_bbt_recompute);
|
||||||
|
virtual void set_length_internal (framepos_t pos);
|
||||||
void modify_front (framepos_t new_position, bool reset_fade, void* src);
|
void modify_front (framepos_t new_position, bool reset_fade, void* src);
|
||||||
void modify_end (framepos_t new_position, bool reset_fade, void* src);
|
void modify_end (framepos_t new_position, bool reset_fade, void* src);
|
||||||
|
|
||||||
|
@ -204,15 +204,13 @@ class TempoMap : public PBD::StatefulDestructible
|
|||||||
framecnt_t frame_time (const Timecode::BBT_Time&) const;
|
framecnt_t frame_time (const Timecode::BBT_Time&) const;
|
||||||
framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir) const;
|
framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir) const;
|
||||||
|
|
||||||
void bbt_time_add (framepos_t origin, Timecode::BBT_Time& start, const Timecode::BBT_Time& shift);
|
|
||||||
|
|
||||||
static const Tempo& default_tempo() { return _default_tempo; }
|
static const Tempo& default_tempo() { return _default_tempo; }
|
||||||
static const Meter& default_meter() { return _default_meter; }
|
static const Meter& default_meter() { return _default_meter; }
|
||||||
|
|
||||||
const Tempo& tempo_at (framepos_t) const;
|
const Tempo& tempo_at (framepos_t) const;
|
||||||
const Meter& meter_at (framepos_t) const;
|
const Meter& meter_at (framepos_t) const;
|
||||||
|
|
||||||
const TempoSection& tempo_section_at (framepos_t);
|
const TempoSection& tempo_section_at (framepos_t) const;
|
||||||
|
|
||||||
void add_tempo(const Tempo&, Timecode::BBT_Time where);
|
void add_tempo(const Tempo&, Timecode::BBT_Time where);
|
||||||
void add_meter(const Meter&, Timecode::BBT_Time where);
|
void add_meter(const Meter&, Timecode::BBT_Time where);
|
||||||
@ -250,6 +248,9 @@ class TempoMap : public PBD::StatefulDestructible
|
|||||||
Timecode::BBT_Time bbt_add (const Timecode::BBT_Time& a, const Timecode::BBT_Time& b) const;
|
Timecode::BBT_Time bbt_add (const Timecode::BBT_Time& a, const Timecode::BBT_Time& b) const;
|
||||||
Timecode::BBT_Time bbt_subtract (const Timecode::BBT_Time&, const Timecode::BBT_Time&) const;
|
Timecode::BBT_Time bbt_subtract (const Timecode::BBT_Time&, const Timecode::BBT_Time&) const;
|
||||||
|
|
||||||
|
framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b) const;
|
||||||
|
double framewalk_to_beats (framepos_t pos, framecnt_t distance) const;
|
||||||
|
|
||||||
void change_existing_tempo_at (framepos_t, double bpm, double note_type);
|
void change_existing_tempo_at (framepos_t, double bpm, double note_type);
|
||||||
void change_initial_tempo (double bpm, double note_type);
|
void change_initial_tempo (double bpm, double note_type);
|
||||||
|
|
||||||
|
@ -27,25 +27,19 @@ namespace ARDOUR {
|
|||||||
framecnt_t
|
framecnt_t
|
||||||
BeatsFramesConverter::to(double beats) const
|
BeatsFramesConverter::to(double beats) const
|
||||||
{
|
{
|
||||||
// FIXME: assumes tempo never changes after origin
|
Timecode::BBT_Time delta;
|
||||||
const Tempo& tempo = _tempo_map.tempo_at (_origin_b);
|
|
||||||
const double frames_per_beat = tempo.frames_per_beat(
|
|
||||||
_tempo_map.frame_rate(),
|
|
||||||
_tempo_map.meter_at (_origin_b));
|
|
||||||
|
|
||||||
return llrint (beats * frames_per_beat);
|
delta.bars = 0;
|
||||||
|
delta.beats = rint (floor (beats));
|
||||||
|
delta.ticks = rint (floor (Meter::ticks_per_beat * fmod (beats, 1.0)));
|
||||||
|
|
||||||
|
return _tempo_map.framepos_plus_bbt (_origin_b, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
BeatsFramesConverter::from (framecnt_t frames) const
|
BeatsFramesConverter::from (framecnt_t frames) const
|
||||||
{
|
{
|
||||||
// FIXME: assumes tempo never changes after origin
|
return _tempo_map.framewalk_to_beats (_origin_b, frames);
|
||||||
const Tempo& tempo = _tempo_map.tempo_at (_origin_b);
|
|
||||||
const double frames_per_beat = tempo.frames_per_beat(
|
|
||||||
_tempo_map.frame_rate(),
|
|
||||||
_tempo_map.meter_at (_origin_b));
|
|
||||||
|
|
||||||
return frames / frames_per_beat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace ARDOUR */
|
} /* namespace ARDOUR */
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
#include "ardour/control_protocol_manager.h"
|
#include "ardour/control_protocol_manager.h"
|
||||||
#include "ardour/debug.h"
|
#include "ardour/debug.h"
|
||||||
#include "ardour/filesystem_paths.h"
|
#include "ardour/filesystem_paths.h"
|
||||||
|
#include "ardour/midi_region.h"
|
||||||
#include "ardour/mix.h"
|
#include "ardour/mix.h"
|
||||||
#include "ardour/audioplaylist.h"
|
#include "ardour/audioplaylist.h"
|
||||||
#include "ardour/plugin_manager.h"
|
#include "ardour/plugin_manager.h"
|
||||||
@ -247,6 +248,7 @@ ARDOUR::init (bool use_vst, bool try_optimization)
|
|||||||
make_property_quarks ();
|
make_property_quarks ();
|
||||||
SessionObject::make_property_quarks ();
|
SessionObject::make_property_quarks ();
|
||||||
Region::make_property_quarks ();
|
Region::make_property_quarks ();
|
||||||
|
MidiRegion::make_property_quarks ();
|
||||||
AudioRegion::make_property_quarks ();
|
AudioRegion::make_property_quarks ();
|
||||||
RouteGroup::make_property_quarks ();
|
RouteGroup::make_property_quarks ();
|
||||||
Playlist::make_property_quarks ();
|
Playlist::make_property_quarks ();
|
||||||
|
@ -49,7 +49,8 @@ using namespace PBD;
|
|||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
namespace Properties {
|
namespace Properties {
|
||||||
PBD::PropertyDescriptor<void*> midi_data;
|
PBD::PropertyDescriptor<void*> midi_data;
|
||||||
|
PBD::PropertyDescriptor<Evoral::MusicalTime> length_beats;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,18 +59,22 @@ MidiRegion::make_property_quarks ()
|
|||||||
{
|
{
|
||||||
Properties::midi_data.property_id = g_quark_from_static_string (X_("midi-data"));
|
Properties::midi_data.property_id = g_quark_from_static_string (X_("midi-data"));
|
||||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for midi-data = %1\n", Properties::midi_data.property_id));
|
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for midi-data = %1\n", Properties::midi_data.property_id));
|
||||||
|
Properties::length_beats.property_id = g_quark_from_static_string (X_("length-beats"));
|
||||||
|
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for length-beats = %1\n", Properties::length_beats.property_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiRegion::register_properties ()
|
MidiRegion::register_properties ()
|
||||||
{
|
{
|
||||||
/* none yet, but its only a matter of time */
|
add_property (_length_beats);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Basic MidiRegion constructor (many channels) */
|
/* Basic MidiRegion constructor (many channels) */
|
||||||
MidiRegion::MidiRegion (const SourceList& srcs)
|
MidiRegion::MidiRegion (const SourceList& srcs)
|
||||||
: Region (srcs)
|
: Region (srcs)
|
||||||
|
, _length_beats (Properties::length_beats, (Evoral::MusicalTime) 0)
|
||||||
{
|
{
|
||||||
|
update_length_beats ();
|
||||||
register_properties ();
|
register_properties ();
|
||||||
|
|
||||||
midi_source(0)->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this));
|
midi_source(0)->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this));
|
||||||
@ -81,7 +86,9 @@ MidiRegion::MidiRegion (const SourceList& srcs)
|
|||||||
/** Create a new MidiRegion, that is part of an existing one */
|
/** Create a new MidiRegion, that is part of an existing one */
|
||||||
MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, frameoffset_t offset, bool offset_relative)
|
MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, frameoffset_t offset, bool offset_relative)
|
||||||
: Region (other, offset, offset_relative)
|
: Region (other, offset, offset_relative)
|
||||||
|
, _length_beats (Properties::length_beats, (Evoral::MusicalTime) 0)
|
||||||
{
|
{
|
||||||
|
update_length_beats ();
|
||||||
register_properties ();
|
register_properties ();
|
||||||
|
|
||||||
assert(_name.val().find("/") == string::npos);
|
assert(_name.val().find("/") == string::npos);
|
||||||
@ -110,22 +117,43 @@ MidiRegion::clone ()
|
|||||||
plist.add (Properties::whole_file, true);
|
plist.add (Properties::whole_file, true);
|
||||||
plist.add (Properties::start, _start);
|
plist.add (Properties::start, _start);
|
||||||
plist.add (Properties::length, _length);
|
plist.add (Properties::length, _length);
|
||||||
|
plist.add (Properties::length_beats, _length_beats);
|
||||||
plist.add (Properties::layer, 0);
|
plist.add (Properties::layer, 0);
|
||||||
|
|
||||||
return boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (ms, plist, true));
|
return boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (ms, plist, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiRegion::set_length_internal (framecnt_t len)
|
||||||
|
{
|
||||||
|
Region::set_length_internal (len);
|
||||||
|
update_length_beats ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiRegion::update_length_beats ()
|
||||||
|
{
|
||||||
|
cerr << name() << " Updating length beats, currently = " << _length_beats << " w/length = " << _length << endl;
|
||||||
|
BeatsFramesConverter converter (_session.tempo_map(), _position - _start);
|
||||||
|
_length_beats = converter.from (_length);
|
||||||
|
cerr << "\tnew value: " << _length_beats << endl;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
|
MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
|
||||||
{
|
{
|
||||||
BeatsFramesConverter old_converter(_session.tempo_map(), _position - _start);
|
|
||||||
double length_beats = old_converter.from(_length);
|
|
||||||
|
|
||||||
Region::set_position_internal (pos, allow_bbt_recompute);
|
Region::set_position_internal (pos, allow_bbt_recompute);
|
||||||
|
/* zero length regions don't exist - so if _length_beats is zero, this object
|
||||||
BeatsFramesConverter new_converter(_session.tempo_map(), pos - _start);
|
is under construction.
|
||||||
|
*/
|
||||||
set_length(new_converter.to(length_beats), 0);
|
if (_length_beats) {
|
||||||
|
/* leave _length_beats alone, and change _length to reflect the state of things
|
||||||
|
at the new position (tempo map may dictate a different number of frames
|
||||||
|
*/
|
||||||
|
BeatsFramesConverter converter (_session.tempo_map(), _position - _start);
|
||||||
|
cerr << name() << " change frame length to " << converter.to (_length_beats) << endl;
|
||||||
|
Region::set_length_internal (converter.to (_length_beats));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
framecnt_t
|
framecnt_t
|
||||||
@ -212,7 +240,13 @@ MidiRegion::state ()
|
|||||||
int
|
int
|
||||||
MidiRegion::set_state (const XMLNode& node, int version)
|
MidiRegion::set_state (const XMLNode& node, int version)
|
||||||
{
|
{
|
||||||
return Region::set_state (node, version);
|
int ret = Region::set_state (node, version);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
update_length_beats ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -462,7 +462,7 @@ Region::set_length (framecnt_t len, void */*src*/)
|
|||||||
|
|
||||||
|
|
||||||
_last_length = _length;
|
_last_length = _length;
|
||||||
_length = len;
|
set_length_internal (len);
|
||||||
_whole_file = false;
|
_whole_file = false;
|
||||||
first_edit ();
|
first_edit ();
|
||||||
maybe_uncopy ();
|
maybe_uncopy ();
|
||||||
@ -476,6 +476,12 @@ Region::set_length (framecnt_t len, void */*src*/)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Region::set_length_internal (framecnt_t len)
|
||||||
|
{
|
||||||
|
_length = len;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Region::maybe_uncopy ()
|
Region::maybe_uncopy ()
|
||||||
{
|
{
|
||||||
@ -925,7 +931,7 @@ Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/)
|
|||||||
if (!property_changes_suspended()) {
|
if (!property_changes_suspended()) {
|
||||||
_last_length = _length;
|
_last_length = _length;
|
||||||
}
|
}
|
||||||
_length = length;
|
set_length_internal (length);
|
||||||
what_changed.add (Properties::length);
|
what_changed.add (Properties::length);
|
||||||
}
|
}
|
||||||
if (_position != position) {
|
if (_position != position) {
|
||||||
|
@ -1510,10 +1510,10 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TempoSection&
|
const TempoSection&
|
||||||
TempoMap::tempo_section_at (framepos_t frame)
|
TempoMap::tempo_section_at (framepos_t frame) const
|
||||||
{
|
{
|
||||||
Glib::RWLock::ReaderLock lm (lock);
|
Glib::RWLock::ReaderLock lm (lock);
|
||||||
Metrics::iterator i;
|
Metrics::const_iterator i;
|
||||||
TempoSection* prev = 0;
|
TempoSection* prev = 0;
|
||||||
|
|
||||||
for (i = metrics->begin(); i != metrics->end(); ++i) {
|
for (i = metrics->begin(); i != metrics->end(); ++i) {
|
||||||
@ -1904,6 +1904,206 @@ TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add the BBT interval @param increment to @param start and return the result
|
||||||
|
*/
|
||||||
|
framepos_t
|
||||||
|
TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
|
||||||
|
{
|
||||||
|
Metrics::const_iterator i;
|
||||||
|
const MeterSection* meter;
|
||||||
|
const MeterSection* m;
|
||||||
|
const TempoSection* tempo;
|
||||||
|
const TempoSection* t;
|
||||||
|
framecnt_t frames_per_beat;
|
||||||
|
|
||||||
|
meter = &first_meter ();
|
||||||
|
tempo = &first_tempo ();
|
||||||
|
|
||||||
|
assert (meter);
|
||||||
|
assert (tempo);
|
||||||
|
|
||||||
|
/* find the starting metrics for tempo & meter */
|
||||||
|
|
||||||
|
for (i = metrics->begin(); i != metrics->end(); ++i) {
|
||||||
|
|
||||||
|
if ((*i)->frame() > pos) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
|
||||||
|
tempo = t;
|
||||||
|
} else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
|
||||||
|
meter = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We now have:
|
||||||
|
|
||||||
|
meter -> the Meter for "pos"
|
||||||
|
tempo -> the Tempo for "pos"
|
||||||
|
i -> for first new metric after "pos", possibly metrics->end()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* now comes the complicated part. we have to add one beat a time,
|
||||||
|
checking for a new metric on every beat.
|
||||||
|
*/
|
||||||
|
|
||||||
|
frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
|
||||||
|
|
||||||
|
while (op.bars) {
|
||||||
|
|
||||||
|
pos += llrint (frames_per_beat * meter->beats_per_bar());
|
||||||
|
op.bars--;
|
||||||
|
|
||||||
|
/* check if we need to use a new metric section: has adding frames moved us
|
||||||
|
to or after the start of the next metric section? in which case, use it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (i != metrics->end()) {
|
||||||
|
if ((*i)->frame() <= pos) {
|
||||||
|
|
||||||
|
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
|
||||||
|
tempo = t;
|
||||||
|
} else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
|
||||||
|
meter = m;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
while (op.beats) {
|
||||||
|
|
||||||
|
/* given the current meter, have we gone past the end of the bar ? */
|
||||||
|
|
||||||
|
pos += frames_per_beat;
|
||||||
|
op.beats--;
|
||||||
|
|
||||||
|
/* check if we need to use a new metric section: has adding frames moved us
|
||||||
|
to or after the start of the next metric section? in which case, use it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (i != metrics->end()) {
|
||||||
|
if ((*i)->frame() <= pos) {
|
||||||
|
|
||||||
|
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
|
||||||
|
tempo = t;
|
||||||
|
} else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
|
||||||
|
meter = m;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.ticks) {
|
||||||
|
if (op.ticks >= Meter::ticks_per_beat) {
|
||||||
|
pos += frames_per_beat;
|
||||||
|
pos += llrint (frames_per_beat * ((op.ticks % (uint32_t) Meter::ticks_per_beat) / (double) Meter::ticks_per_beat));
|
||||||
|
} else {
|
||||||
|
pos += llrint (frames_per_beat * (op.ticks / (double) Meter::ticks_per_beat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add the BBT interval @param increment to @param start and return the result
|
||||||
|
*/
|
||||||
|
double
|
||||||
|
TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
|
||||||
|
{
|
||||||
|
Metrics::const_iterator i;
|
||||||
|
double beats = 0;
|
||||||
|
const MeterSection* meter;
|
||||||
|
const MeterSection* m;
|
||||||
|
const TempoSection* tempo;
|
||||||
|
const TempoSection* t;
|
||||||
|
double frames_per_beat;
|
||||||
|
|
||||||
|
double ddist = distance;
|
||||||
|
double dpos = pos;
|
||||||
|
|
||||||
|
meter = &first_meter ();
|
||||||
|
tempo = &first_tempo ();
|
||||||
|
|
||||||
|
assert (meter);
|
||||||
|
assert (tempo);
|
||||||
|
|
||||||
|
/* find the starting metrics for tempo & meter */
|
||||||
|
|
||||||
|
for (i = metrics->begin(); i != metrics->end(); ++i) {
|
||||||
|
|
||||||
|
if ((*i)->frame() > pos) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
|
||||||
|
tempo = t;
|
||||||
|
} else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
|
||||||
|
meter = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We now have:
|
||||||
|
|
||||||
|
meter -> the Meter for "pos"
|
||||||
|
tempo -> the Tempo for "pos"
|
||||||
|
i -> for first new metric after "pos", possibly metrics->end()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* now comes the complicated part. we have to add one beat a time,
|
||||||
|
checking for a new metric on every beat.
|
||||||
|
*/
|
||||||
|
|
||||||
|
frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
|
||||||
|
|
||||||
|
while (ddist > 0) {
|
||||||
|
|
||||||
|
/* if we're nearly at the end, but have a fractional beat left,
|
||||||
|
compute the fraction and then its all over
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ddist < frames_per_beat) {
|
||||||
|
beats += Meter::ticks_per_beat * (ddist/frames_per_beat);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* walk one beat */
|
||||||
|
|
||||||
|
ddist -= frames_per_beat;
|
||||||
|
dpos += frames_per_beat;
|
||||||
|
beats += 1.0;
|
||||||
|
|
||||||
|
/* check if we need to use a new metric section: has adding frames moved us
|
||||||
|
to or after the start of the next metric section? in which case, use it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (i != metrics->end()) {
|
||||||
|
if ((*i)->frame() <= (framepos_t) dpos) {
|
||||||
|
|
||||||
|
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
|
||||||
|
tempo = t;
|
||||||
|
} else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
|
||||||
|
meter = m;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return beats;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Compare the time of this with that of another MetricSection.
|
/** Compare the time of this with that of another MetricSection.
|
||||||
* @param with_bbt True to compare using ::start(), false to use ::frame().
|
* @param with_bbt True to compare using ::start(), false to use ::frame().
|
||||||
* @return -1 for less than, 0 for equal, 1 for greater than.
|
* @return -1 for less than, 0 for equal, 1 for greater than.
|
||||||
|
Loading…
Reference in New Issue
Block a user