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 Temporal;
#define TIME_TO_SAMPLES(x) (_distance_measure (x, Temporal::AudioTime))
#define SAMPLES_TO_TIME(x) (_distance_measure (x, alist->time_domain()))
#define SAMPLES_TO_TIME(x) (get_origin().distance (x))
/** @param converter A TimeConverter whose origin_b is the start time of the AutomationList in session samples.
* This will not be deleted by AutomationLine.
@ -89,8 +88,7 @@ AutomationLine::AutomationLine (const string& name,
TimeAxisView& tv,
ArdourCanvas::Item& parent,
boost::shared_ptr<AutomationList> al,
const ParameterDescriptor& desc,
Temporal::DistanceMeasure const & m)
const ParameterDescriptor& desc)
: trackview (tv)
, _name (name)
, alist (al)
@ -99,7 +97,6 @@ AutomationLine::AutomationLine (const string& name,
, _maximum_time (timepos_t::max (al->time_domain()))
, _fill (false)
, _desc (desc)
, _distance_measure (m)
{
_visible = Line;
@ -139,6 +136,15 @@ AutomationLine::~AutomationLine ()
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
AutomationLine::event_handler (GdkEvent* event)
{
@ -762,6 +768,14 @@ AutomationLine::end_drag (bool with_push, uint32_t final_index)
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
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_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))) {
/* convert from view coordinates, via pixels->samples->timepos_t
const timepos_t absolute_time = model_time + get_origin();
/* 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;
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) */
model_to_view_coord_y (view_y);
@ -1346,13 +1387,13 @@ AutomationLine::get_point_x_range () const
samplepos_t
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
AutomationLine::session_position (AutomationList::const_iterator p) const
{
return (*p)->when + _offset + _distance_measure.origin();
return (*p)->when + _offset + get_origin();
}
void
@ -1365,9 +1406,3 @@ AutomationLine::set_offset (timecnt_t const & off)
_offset = off;
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/memento_command.h"
#include "temporal/time_converter.h"
#include "ardour/automation_list.h"
#include "ardour/parameter_descriptor.h"
#include "ardour/types.h"
@ -71,11 +69,13 @@ public:
TimeAxisView& tv,
ArdourCanvas::Item& parent,
boost::shared_ptr<ARDOUR::AutomationList> al,
const ARDOUR::ParameterDescriptor& desc,
Temporal::DistanceMeasure const &);
const ARDOUR::ParameterDescriptor& desc);
virtual ~AutomationLine ();
virtual Temporal::timepos_t get_origin () const;
void queue_reset ();
void reset ();
void clear ();
@ -164,9 +164,6 @@ public:
samplepos_t session_sample_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:
std::string _name;
@ -245,7 +242,6 @@ private:
bool _fill;
const ARDOUR::ParameterDescriptor _desc;
Temporal::DistanceMeasure _distance_measure;
friend class AudioRegionGainLine;
};

View File

@ -305,8 +305,7 @@ AutomationTimeAxisView::AutomationTimeAxisView (
*this,
*_canvas_display,
_control->alist(),
_control->desc(),
Temporal::DistanceMeasure (timepos_t()) /* default distance measure, origin at absolute zero */
_control->desc()
)
);
@ -868,8 +867,7 @@ AutomationTimeAxisView::paste_one (timepos_t const & pos, unsigned paste_count,
}
/* convert position to model's unit and position */
Temporal::DistanceMeasure const & dm (_line->distance_measure());
Temporal::timepos_t model_pos = dm (_line->distance_measure().origin().distance (tpos), line()->the_list()->time_domain());
Temporal::timepos_t model_pos (_line->get_origin().distance (tpos));
XMLNode &before = alist->get_state();
alist->paste (**p, model_pos);
@ -1143,9 +1141,8 @@ AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& sel
XMLNode &before = alist->get_state();
/* 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.distance_measure().origin());
timepos_t end = selection.time.front().end().earlier (line.distance_measure().origin());
timepos_t start = selection.time.front().start().earlier (line.get_origin());
timepos_t end = selection.time.front().end().earlier (line.get_origin());
switch (op) {
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
AudioRegionGainLine *argl = dynamic_cast<AudioRegionGainLine*> ((*i).get());
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.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 */
ControlPoint* p = i->line->nth (j);
#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 = 0;;

View File

@ -38,7 +38,7 @@ MidiAutomationLine::MidiAutomationLine (
boost::shared_ptr<ARDOUR::AutomationList> list,
boost::shared_ptr<ARDOUR::MidiRegion> region,
Evoral::Parameter parameter)
: AutomationLine (name, tav, parent, list, parameter, Temporal::DistanceMeasure (Temporal::timepos_t()))
: AutomationLine (name, tav, parent, list, parameter)
, _region (region)
, _parameter (parameter)
{
@ -51,6 +51,17 @@ MidiAutomationLine::memento_command_binder ()
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
MidiAutomationLine::get_verbose_cursor_string (double fraction) const
{

View File

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

View File

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

View File

@ -44,7 +44,7 @@ using namespace ARDOUR;
using namespace PBD;
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)
{
// 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;
}
timepos_t
AudioRegionGainLine::get_origin() const
{
return rv.region()->position();
}
void
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::position);
if (what_changed.contains (ARDOUR::Properties::position)) {
set_distance_measure_origin (rv.region()->position());
}
if (what_changed.contains (interesting_stuff)) {
reset ();
}

View File

@ -42,6 +42,8 @@ class AudioRegionGainLine : public AutomationLine
public:
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 end_drag (bool with_push, uint32_t final_index);

View File

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

View File

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