GUI changes to *try* to adapt to a world without explicit beats<->samples converter objects (i.e. use AutomationLine::get_origin() instead

This commit is contained in:
Paul Davis 2021-02-16 15:58:37 -07:00
parent 0877500437
commit 0162d3f9d6
11 changed files with 104 additions and 45 deletions

View File

@ -79,8 +79,7 @@ using namespace PBD;
using namespace Editing; using namespace Editing;
using namespace Temporal; using namespace Temporal;
#define TIME_TO_SAMPLES(x) (_distance_measure (x, Temporal::AudioTime)) #define SAMPLES_TO_TIME(x) (get_origin().distance (x))
#define SAMPLES_TO_TIME(x) (_distance_measure (x, alist->time_domain()))
/** @param converter A TimeConverter whose origin_b is the start time of the AutomationList in session samples. /** @param converter A TimeConverter whose origin_b is the start time of the AutomationList in session samples.
* This will not be deleted by AutomationLine. * This will not be deleted by AutomationLine.
@ -89,8 +88,7 @@ AutomationLine::AutomationLine (const string& name,
TimeAxisView& tv, TimeAxisView& tv,
ArdourCanvas::Item& parent, ArdourCanvas::Item& parent,
boost::shared_ptr<AutomationList> al, boost::shared_ptr<AutomationList> al,
const ParameterDescriptor& desc, const ParameterDescriptor& desc)
Temporal::DistanceMeasure const & m)
: trackview (tv) : trackview (tv)
, _name (name) , _name (name)
, alist (al) , alist (al)
@ -99,7 +97,6 @@ AutomationLine::AutomationLine (const string& name,
, _maximum_time (timepos_t::max (al->time_domain())) , _maximum_time (timepos_t::max (al->time_domain()))
, _fill (false) , _fill (false)
, _desc (desc) , _desc (desc)
, _distance_measure (m)
{ {
_visible = Line; _visible = Line;
@ -139,6 +136,15 @@ AutomationLine::~AutomationLine ()
control_points.clear (); control_points.clear ();
} }
timepos_t
AutomationLine::get_origin() const
{
/* this is the default for all non-derived AutomationLine classes: the
origin is zero, in whatever time domain the list we represent uses.
*/
return timepos_t (the_list()->time_domain());
}
bool bool
AutomationLine::event_handler (GdkEvent* event) AutomationLine::event_handler (GdkEvent* event)
{ {
@ -762,6 +768,14 @@ AutomationLine::end_drag (bool with_push, uint32_t final_index)
contiguous_points.clear (); contiguous_points.clear ();
} }
/**
*
* get model coordinates synced with (possibly changed) view coordinates.
*
* For example, we call this in ::end_drag(), when we have probably moved a
* point in the view, and now want to "push" that change back into the
* corresponding model point.
*/
bool bool
AutomationLine::sync_model_with_view_point (ControlPoint& cp) AutomationLine::sync_model_with_view_point (ControlPoint& cp)
{ {
@ -773,22 +787,49 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp)
double view_x = cp.get_x(); double view_x = cp.get_x();
double view_y = 1.0 - cp.get_y() / (double)_height; double view_y = 1.0 - cp.get_y() / (double)_height;
/* if xval has not changed, set it directly from the model to avoid rounding errors */ timepos_t model_time = (*cp.model())->when;
timepos_t model_x = (*cp.model())->when; /* convert to absolute time by taking the origin of the line into
* account.
*/
if (view_x != trackview.editor().time_to_pixel_unrounded (model_x.earlier (_offset))) { const timepos_t absolute_time = model_time + get_origin();
/* convert from view coordinates, via pixels->samples->timepos_t
/* convert the absolute time of the model event into unrounded pixels,
* taking _offset into account.
*/
const double model_x = trackview.editor().time_to_pixel_unrounded (absolute_time.earlier (_offset));
if (view_x != model_x) {
/* convert the current position in the view (units: pixels)
* into samples, then use that to create a timecnt_t that
* measures the distance from the origin for this line.
*/ */
const timecnt_t p = timecnt_t (trackview.editor().pixel_to_sample (view_x), timepos_t()); /* samples */
model_x = SAMPLES_TO_TIME (p + _offset); /* correct time domain for list */ const timecnt_t view_samples (trackview.editor().pixel_to_sample (view_x)); /* implicit zero origin */
/* adjust to measure distance from origin (this preserves time domain) */
const timecnt_t distance_from_origin = get_origin().distance (timepos_t (view_samples));
/* now convert to relevant time domain, and use _offset.
*/
if (model_time.time_domain() == Temporal::AudioTime) {
model_time = timepos_t (distance_from_origin.samples()) + _offset;
} else {
model_time = timepos_t (distance_from_origin.beats()) + _offset;
}
} else {
model_time = model_time.earlier (_offset);
} }
update_pending = true; update_pending = true;
view_to_model_coord_y (view_y); view_to_model_coord_y (view_y);
alist->modify (cp.model(), model_x, view_y); alist->modify (cp.model(), model_time, view_y);
/* convert back from model to view y for clamping position (for integer/boolean/etc) */ /* convert back from model to view y for clamping position (for integer/boolean/etc) */
model_to_view_coord_y (view_y); model_to_view_coord_y (view_y);
@ -1346,13 +1387,13 @@ AutomationLine::get_point_x_range () const
samplepos_t samplepos_t
AutomationLine::session_sample_position (AutomationList::const_iterator p) const AutomationLine::session_sample_position (AutomationList::const_iterator p) const
{ {
return (*p)->when.samples() + _offset.samples() + _distance_measure.origin().samples(); return (*p)->when.samples() + _offset.samples() + get_origin().samples();
} }
timepos_t timepos_t
AutomationLine::session_position (AutomationList::const_iterator p) const AutomationLine::session_position (AutomationList::const_iterator p) const
{ {
return (*p)->when + _offset + _distance_measure.origin(); return (*p)->when + _offset + get_origin();
} }
void void
@ -1365,9 +1406,3 @@ AutomationLine::set_offset (timecnt_t const & off)
_offset = off; _offset = off;
reset (); reset ();
} }
void
AutomationLine::set_distance_measure_origin (timepos_t const & pos)
{
_distance_measure.set_origin (pos);
}

View File

@ -37,8 +37,6 @@
#include "pbd/statefuldestructible.h" #include "pbd/statefuldestructible.h"
#include "pbd/memento_command.h" #include "pbd/memento_command.h"
#include "temporal/time_converter.h"
#include "ardour/automation_list.h" #include "ardour/automation_list.h"
#include "ardour/parameter_descriptor.h" #include "ardour/parameter_descriptor.h"
#include "ardour/types.h" #include "ardour/types.h"
@ -71,11 +69,13 @@ public:
TimeAxisView& tv, TimeAxisView& tv,
ArdourCanvas::Item& parent, ArdourCanvas::Item& parent,
boost::shared_ptr<ARDOUR::AutomationList> al, boost::shared_ptr<ARDOUR::AutomationList> al,
const ARDOUR::ParameterDescriptor& desc, const ARDOUR::ParameterDescriptor& desc);
Temporal::DistanceMeasure const &);
virtual ~AutomationLine (); virtual ~AutomationLine ();
virtual Temporal::timepos_t get_origin () const;
void queue_reset (); void queue_reset ();
void reset (); void reset ();
void clear (); void clear ();
@ -164,9 +164,6 @@ public:
samplepos_t session_sample_position (ARDOUR::AutomationList::const_iterator) const; samplepos_t session_sample_position (ARDOUR::AutomationList::const_iterator) const;
Temporal::timepos_t session_position (ARDOUR::AutomationList::const_iterator) const; Temporal::timepos_t session_position (ARDOUR::AutomationList::const_iterator) const;
Temporal::DistanceMeasure const & distance_measure () const { return _distance_measure; }
void set_distance_measure_origin (Temporal::timepos_t const &);
protected: protected:
std::string _name; std::string _name;
@ -245,7 +242,6 @@ private:
bool _fill; bool _fill;
const ARDOUR::ParameterDescriptor _desc; const ARDOUR::ParameterDescriptor _desc;
Temporal::DistanceMeasure _distance_measure;
friend class AudioRegionGainLine; friend class AudioRegionGainLine;
}; };

View File

@ -305,8 +305,7 @@ AutomationTimeAxisView::AutomationTimeAxisView (
*this, *this,
*_canvas_display, *_canvas_display,
_control->alist(), _control->alist(),
_control->desc(), _control->desc()
Temporal::DistanceMeasure (timepos_t()) /* default distance measure, origin at absolute zero */
) )
); );
@ -868,8 +867,7 @@ AutomationTimeAxisView::paste_one (timepos_t const & pos, unsigned paste_count,
} }
/* convert position to model's unit and position */ /* convert position to model's unit and position */
Temporal::DistanceMeasure const & dm (_line->distance_measure()); Temporal::timepos_t model_pos (_line->get_origin().distance (tpos));
Temporal::timepos_t model_pos = dm (_line->distance_measure().origin().distance (tpos), line()->the_list()->time_domain());
XMLNode &before = alist->get_state(); XMLNode &before = alist->get_state();
alist->paste (**p, model_pos); alist->paste (**p, model_pos);
@ -1143,9 +1141,8 @@ AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& sel
XMLNode &before = alist->get_state(); XMLNode &before = alist->get_state();
/* convert time selection to automation list model coordinates */ /* convert time selection to automation list model coordinates */
/* convert time selection to automation list model coordinates */ timepos_t start = selection.time.front().start().earlier (line.get_origin());
timepos_t start = selection.time.front().start().earlier (line.distance_measure().origin()); timepos_t end = selection.time.front().end().earlier (line.get_origin());
timepos_t end = selection.time.front().end().earlier (line.distance_measure().origin());
switch (op) { switch (op) {
case Delete: case Delete:

View File

@ -6537,7 +6537,7 @@ AutomationRangeDrag::setup (list<boost::shared_ptr<AutomationLine> > const & lin
//TODO: if we implement automation regions, this check can probably be removed //TODO: if we implement automation regions, this check can probably be removed
AudioRegionGainLine *argl = dynamic_cast<AudioRegionGainLine*> ((*i).get()); AudioRegionGainLine *argl = dynamic_cast<AudioRegionGainLine*> ((*i).get());
if (!argl) { if (!argl) {
//in automation lanes, the EFFECTIVE range should be considered 0->max_samplepos (even if there is no line) //in automation lanes, the EFFECTIVE range should be considered 0->max_position (even if there is no line)
r.first = Temporal::timepos_t ((*i)->the_list()->time_domain()); r.first = Temporal::timepos_t ((*i)->the_list()->time_domain());
r.second = Temporal::timepos_t::max ((*i)->the_list()->time_domain()); r.second = Temporal::timepos_t::max ((*i)->the_list()->time_domain());
} }
@ -6702,6 +6702,23 @@ AutomationRangeDrag::motion (GdkEvent*, bool first_move)
/* here's a control point on this line */ /* here's a control point on this line */
ControlPoint* p = i->line->nth (j); ControlPoint* p = i->line->nth (j);
#warning NUTEMPO figure out what this code is/was doing and replace it #warning NUTEMPO figure out what this code is/was doing and replace it
/*
convert is <double,samplepos_t> ... double meant beats
so origin_b is the origin in samplepos_t (since a=double b=samplepos_t)
so ->to() returns samples
so to (p->model->when) is the beat time (as dobule)
we convert to samples
then add the originin samples
BUT ... mostly used IdentityConverter, except MIDI
where the time_converter() is a source-relative converter
source-relative uses the the source_position() as the origin
*/
//double const w = i->line->time_converter().to ((*p->model())->when) + i->line->time_converter().origin_b (); //double const w = i->line->time_converter().to ((*p->model())->when) + i->line->time_converter().origin_b ();
double const w = 0;; double const w = 0;;

View File

@ -38,7 +38,7 @@ MidiAutomationLine::MidiAutomationLine (
boost::shared_ptr<ARDOUR::AutomationList> list, boost::shared_ptr<ARDOUR::AutomationList> list,
boost::shared_ptr<ARDOUR::MidiRegion> region, boost::shared_ptr<ARDOUR::MidiRegion> region,
Evoral::Parameter parameter) Evoral::Parameter parameter)
: AutomationLine (name, tav, parent, list, parameter, Temporal::DistanceMeasure (Temporal::timepos_t())) : AutomationLine (name, tav, parent, list, parameter)
, _region (region) , _region (region)
, _parameter (parameter) , _parameter (parameter)
{ {
@ -51,6 +51,17 @@ MidiAutomationLine::memento_command_binder ()
return new ARDOUR::MidiAutomationListBinder (_region->midi_source(), _parameter); return new ARDOUR::MidiAutomationListBinder (_region->midi_source(), _parameter);
} }
Temporal::timepos_t
MidiAutomationLine::get_origin() const
{
/* Events in the automation list are relative to the start of the
source, not the start of the region, so we need to use the
position-of-the-start-of-the-source, rather than just the
position-of-the-region.
*/
return _region->source_position();
}
string string
MidiAutomationLine::get_verbose_cursor_string (double fraction) const MidiAutomationLine::get_verbose_cursor_string (double fraction) const
{ {

View File

@ -38,6 +38,7 @@ public:
MementoCommandBinder<ARDOUR::AutomationList>* memento_command_binder (); MementoCommandBinder<ARDOUR::AutomationList>* memento_command_binder ();
virtual std::string get_verbose_cursor_string (double) const; virtual std::string get_verbose_cursor_string (double) const;
Temporal::timepos_t get_origin() const;
private: private:
boost::shared_ptr<ARDOUR::MidiRegion> _region; boost::shared_ptr<ARDOUR::MidiRegion> _region;

View File

@ -26,7 +26,6 @@
#include "evoral/midi_util.h" #include "evoral/midi_util.h"
#include "evoral/Note.h" #include "evoral/Note.h"
#include "ardour/beats_samples_converter.h"
#include "ardour/midi_model.h" #include "ardour/midi_model.h"
#include "ardour/midi_region.h" #include "ardour/midi_region.h"
#include "ardour/midi_source.h" #include "ardour/midi_source.h"

View File

@ -44,7 +44,7 @@ using namespace ARDOUR;
using namespace PBD; using namespace PBD;
AudioRegionGainLine::AudioRegionGainLine (const string & name, AudioRegionView& r, ArdourCanvas::Container& parent, boost::shared_ptr<AutomationList> l) AudioRegionGainLine::AudioRegionGainLine (const string & name, AudioRegionView& r, ArdourCanvas::Container& parent, boost::shared_ptr<AutomationList> l)
: AutomationLine (name, r.get_time_axis_view(), parent, l, l->parameter(), Temporal::DistanceMeasure (r.region()->position())) : AutomationLine (name, r.get_time_axis_view(), parent, l, l->parameter())
, rv (r) , rv (r)
{ {
// If this isn't true something is horribly wrong, and we'll get catastrophic gain values // If this isn't true something is horribly wrong, and we'll get catastrophic gain values
@ -57,6 +57,13 @@ AudioRegionGainLine::AudioRegionGainLine (const string & name, AudioRegionView&
terminal_points_can_slide = false; terminal_points_can_slide = false;
} }
timepos_t
AudioRegionGainLine::get_origin() const
{
return rv.region()->position();
}
void void
AudioRegionGainLine::start_drag_single (ControlPoint* cp, double x, float fraction) AudioRegionGainLine::start_drag_single (ControlPoint* cp, double x, float fraction)
{ {
@ -110,10 +117,6 @@ AudioRegionGainLine::region_changed (const PropertyChange& what_changed)
interesting_stuff.add (ARDOUR::Properties::start); interesting_stuff.add (ARDOUR::Properties::start);
interesting_stuff.add (ARDOUR::Properties::position); interesting_stuff.add (ARDOUR::Properties::position);
if (what_changed.contains (ARDOUR::Properties::position)) {
set_distance_measure_origin (rv.region()->position());
}
if (what_changed.contains (interesting_stuff)) { if (what_changed.contains (interesting_stuff)) {
reset (); reset ();
} }

View File

@ -42,6 +42,8 @@ class AudioRegionGainLine : public AutomationLine
public: public:
AudioRegionGainLine (const std::string & name, AudioRegionView&, ArdourCanvas::Container& parent, boost::shared_ptr<ARDOUR::AutomationList>); AudioRegionGainLine (const std::string & name, AudioRegionView&, ArdourCanvas::Container& parent, boost::shared_ptr<ARDOUR::AutomationList>);
Temporal::timepos_t get_origin() const;
void start_drag_single (ControlPoint*, double, float); void start_drag_single (ControlPoint*, double, float);
void end_drag (bool with_push, uint32_t final_index); void end_drag (bool with_push, uint32_t final_index);

View File

@ -32,7 +32,6 @@
#include <sigc++/signal.h> #include <sigc++/signal.h>
#include "ardour/region.h" #include "ardour/region.h"
#include "ardour/beats_samples_converter.h"
#include "canvas/fwd.h" #include "canvas/fwd.h"

View File

@ -21,7 +21,6 @@
#ifndef __ardour_tempo_lines_h__ #ifndef __ardour_tempo_lines_h__
#define __ardour_tempo_lines_h__ #define __ardour_tempo_lines_h__
#include "ardour/beats_samples_converter.h"
#include "ardour/tempo.h" #include "ardour/tempo.h"
#include "canvas/line_set.h" #include "canvas/line_set.h"