summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Loftis <ben@glw.com>2011-03-29 17:49:49 +0000
committerBen Loftis <ben@glw.com>2011-03-29 17:49:49 +0000
commitcfe3c891dee125b7837ff8d3d88ecbd5a4509450 (patch)
tree762b8aa41ac8a2618d032d61cea29ea2b8600cc0
parent3c1625a71260335e4f1acc48b8676551e55226ff (diff)
significant fixes to realtime (touch/write) automation. no longer decide point visibility based on scale. thin automation on recording. fix bugs in nascent automation pass handling. allow timecode to skip forwards or backwards or even loop. automation is only recording during forward playback though. this is all backported from mixbus branch.
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@9231 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/automation_line.cc36
-rw-r--r--gtk2_ardour/generic_pluginui.cc9
-rw-r--r--libs/ardour/ardour/automation_event.h2
-rw-r--r--libs/ardour/ardour/configuration_vars.h1
-rw-r--r--libs/ardour/automation_event.cc142
-rw-r--r--libs/ardour/io.cc4
6 files changed, 121 insertions, 73 deletions
diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc
index 7fb88d660f..54620cd291 100644
--- a/gtk2_ardour/automation_line.cc
+++ b/gtk2_ardour/automation_line.cc
@@ -564,7 +564,7 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
uint32_t prev_rx = 0;
uint32_t this_ry = 0;
uint32_t prev_ry = 0;
- double* slope;
+ double* slope = NULL;
uint32_t box_size;
uint32_t cpsize;
@@ -587,13 +587,13 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
/* compute derivative/slope for the entire line */
- slope = new double[npoints];
+ //slope = new double[npoints];
- for (n = 0; n < npoints - 1; ++n) {
- double xdelta = points[n+1].x - points[n].x;
- double ydelta = points[n+1].y - points[n].y;
- slope[n] = ydelta/xdelta;
- }
+ //for (n = 0; n < npoints - 1; ++n) {
+ // double xdelta = points[n+1].x - points[n].x;
+ // double ydelta = points[n+1].y - points[n].y;
+ // slope[n] = ydelta/xdelta;
+ //}
box_size = (uint32_t) control_point_box_size ();
@@ -626,14 +626,14 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
continue;
}
- if (pi > 0 && pi < npoints - 1) {
- if (slope[pi] == slope[pi-1]) {
+// if (pi > 0 && pi < npoints - 1) {
+// if (slope[pi] == slope[pi-1]) {
/* no reason to display this point */
- continue;
- }
- }
+// continue;
+// }
+// }
/* need to round here. the ultimate coordinates are integer
pixels, so tiny deltas in the coords will be eliminated
@@ -646,12 +646,12 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
this_rx = (uint32_t) rint (tx);
this_ry = (uint32_t) rint (ty);
- if (view_index && pi != npoints && /* not the first, not the last */
- (((this_rx == prev_rx) && (this_ry == prev_ry)) || /* same point */
- (((this_rx - prev_rx) < (box_size + 2)) && /* not identical, but still too close horizontally */
- (abs ((int)(this_ry - prev_ry)) < (int) (box_size + 2))))) { /* too close vertically */
- continue;
- }
+ // if (view_index && pi != npoints && /* not the first, not the last */
+// (((this_rx == prev_rx) && (this_ry == prev_ry)) || /* same point */
+// (((this_rx - prev_rx) < (box_size + 2)) && /* not identical, but still too close horizontally */
+// (abs ((int)(this_ry - prev_ry)) < (int) (box_size + 2))))) { /* too close vertically */
+// continue;
+// }
/* ok, we should display this point */
diff --git a/gtk2_ardour/generic_pluginui.cc b/gtk2_ardour/generic_pluginui.cc
index 52813aa231..bdaedd5d32 100644
--- a/gtk2_ardour/generic_pluginui.cc
+++ b/gtk2_ardour/generic_pluginui.cc
@@ -589,7 +589,7 @@ GenericPluginUI::build_control_ui (guint32 port_index, PBD::Controllable* mcontr
void
GenericPluginUI::start_touch (GenericPluginUI::ControlUI* cui)
{
- insert->automation_list (cui->port_index).start_touch (insert->session().transport_frame());
+ insert->automation_list ( cui->port_index).start_touch (insert->session().transport_frame() );
}
void
@@ -603,8 +603,13 @@ GenericPluginUI::stop_touch (GenericPluginUI::ControlUI* cui)
when = insert->session().transport_frame();
}
+ double value = cui->adjustment->get_value();
+ if (cui->logarithmic) {
+ value = exp(value);
+ }
+
if (insert->automation_list (cui->port_index).automation_state() == Auto_Touch) {
- insert->automation_list (cui->port_index).stop_touch (mark, when);
+ insert->automation_list (cui->port_index).stop_touch (mark, when, value);
}
}
diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h
index 909a39ef26..45227dc040 100644
--- a/libs/ardour/ardour/automation_event.h
+++ b/libs/ardour/ardour/automation_event.h
@@ -134,7 +134,7 @@ class AutomationList : public PBD::StatefulDestructible
}
void start_touch (double when);
- void stop_touch (bool mark, double when);
+ void stop_touch (bool mark, double when, double value);
bool touching() const { return g_atomic_int_get (&_touching); }
void set_yrange (double min, double max) {
diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h
index 31a2ae9140..8b95ecfd85 100644
--- a/libs/ardour/ardour/configuration_vars.h
+++ b/libs/ardour/ardour/configuration_vars.h
@@ -159,6 +159,7 @@ CONFIG_VARIABLE (bool, use_overlap_equivalency, "use-overlap-equivalency", false
CONFIG_VARIABLE (bool, periodic_safety_backups, "periodic-safety-backups", true)
CONFIG_VARIABLE (uint32_t, periodic_safety_backup_interval, "periodic-safety-backup-interval", 120)
CONFIG_VARIABLE (float, automation_interval, "automation-interval", 50)
+CONFIG_VARIABLE (float, automation_thinning_strength, "automation-thinning-strength", 10)
CONFIG_VARIABLE (bool, sync_all_route_ordering, "sync-all-route-ordering", true)
CONFIG_VARIABLE (bool, only_copy_imported_files, "only-copy-imported-files", false)
CONFIG_VARIABLE (bool, new_plugins_active, "new-plugins-active", true)
diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc
index dd2930a1a6..e17f9fb91b 100644
--- a/libs/ardour/automation_event.cc
+++ b/libs/ardour/automation_event.cc
@@ -248,7 +248,7 @@ AutomationList::start_touch (double when)
}
void
-AutomationList::stop_touch (bool mark, double when)
+AutomationList::stop_touch (bool mark, double when, double value)
{
g_atomic_int_set (&_touching, 0);
@@ -268,6 +268,11 @@ AutomationList::stop_touch (bool mark, double when)
delete ninfo;
}
}
+
+ //if no automation yet
+ if (events.empty()) {
+ default_value = value;
+ }
}
void
@@ -313,12 +318,30 @@ void AutomationList::_x_scale (double factor)
void
AutomationList::write_pass_finished (double when)
{
- merge_nascent (when);
+ //if fader is in Write, we need to put an automation point to mark the last place we rolled.
+ if ( (_state & Auto_Write) ) {
+ if ( nascent.back() && !nascent.back()->events.empty() ) {
+ rt_add( when, nascent.back()->events.back()->value );
+ }
+ }
+
+ merge_nascent (when);
}
void
AutomationList::rt_add (double when, double value)
{
+ //for now, automation only writes during forward motion
+ //if transport goes in reverse, start a new nascent pass and ignore this change
+ float last_when = 0;
+ if (!nascent.back()->events.empty())
+ last_when = nascent.back()->events.back()->when;
+ if ( (when < last_when) ) {
+ Glib::Mutex::Lock lm (lock);
+ nascent.push_back (new NascentInfo (false));
+ return;
+ }
+
/* this is for automation recording */
if ((_state & Auto_Touch) && !touching()) {
@@ -329,10 +352,11 @@ AutomationList::rt_add (double when, double value)
if (lm.locked()) {
assert (!nascent.empty());
- if (!nascent.back()->events.empty()) {
- assert (when > nascent.back()->events.back()->when);
- }
- nascent.back()->events.push_back (point_factory (when, value));
+ if (nascent.back()->events.empty() ){
+ nascent.back()->events.push_back (point_factory (when, value));
+ } else if (when > nascent.back()->events.back()->when) {
+ nascent.back()->events.push_back (point_factory (when, value));
+ }
}
}
@@ -346,14 +370,48 @@ AutomationList::merge_nascent (double when)
return;
}
- for (list<NascentInfo*>::iterator n = nascent.begin(); n != nascent.end(); ++n) {
+ //thin automation data in each nascent packet
+ for (list<NascentInfo*>::iterator n = nascent.begin(); n != nascent.end(); ++n) {
+ ControlEvent *next = NULL;
+ ControlEvent *cur = NULL;
+ ControlEvent *prev = NULL;
+ int counter = 0;
+ AutomationEventList delete_list;
+ for (AutomationEventList::iterator x = (*n)->events.begin(); x != (*n)->events.end(); x++) {
+ next = *x;
+ counter++;
+ if (counter > 2) { //wait for the third iteration so "cur" & "prev" are initialized
+
+ float area = fabs(
+ 0.5 * (
+ prev->when*(cur->value - next->value) +
+ cur->when*(next->value - prev->value) +
+ next->when*(prev->value - cur->value) )
+ );
+
+//printf( "area: %3.16f\n", area);
+ if (area < ( Config->get_automation_thinning_strength() ) )
+ delete_list.push_back(cur);
+ }
+ prev = cur;
+ cur = next;
+ }
+
+ for (AutomationEventList::iterator x = delete_list.begin(); x != delete_list.end(); ++x) {
+ (*n)->events.remove(*x);
+ delete *x;
+ }
+
+ }
+
+ for (list<NascentInfo*>::iterator n = nascent.begin(); n != nascent.end(); ++n) {
NascentInfo* ninfo = *n;
AutomationEventList& nascent_events (ninfo->events);
bool need_adjacent_start_clamp;
bool need_adjacent_end_clamp;
- if (nascent_events.empty()) {
+ if (nascent_events.size() < 2) {
delete ninfo;
continue;
}
@@ -363,27 +421,15 @@ AutomationList::merge_nascent (double when)
}
if (ninfo->end_time < 0.0) {
- ninfo->end_time = when;
+ ninfo->end_time = nascent_events.back()->when;
}
- bool preexisting = !events.empty();
+ bool preexisting = !events.empty();
if (!preexisting) {
events = nascent_events;
- } else if (ninfo->end_time < events.front()->when) {
-
- /* all points in nascent are before the first existing point */
-
- events.insert (events.begin(), nascent_events.begin(), nascent_events.end());
-
- } else if (ninfo->start_time > events.back()->when) {
-
- /* all points in nascent are after the last existing point */
-
- events.insert (events.end(), nascent_events.begin(), nascent_events.end());
-
} else {
/* find the range that overaps with nascent events,
@@ -393,7 +439,7 @@ AutomationList::merge_nascent (double when)
iterator i;
iterator range_begin = events.end();
iterator range_end = events.end();
- double end_value = unlocked_eval (ninfo->end_time);
+ double end_value = unlocked_eval (ninfo->end_time + 1);
double start_value = unlocked_eval (ninfo->start_time - 1);
need_adjacent_end_clamp = true;
@@ -435,25 +481,25 @@ AutomationList::merge_nascent (double when)
}
}
}
-
- assert (range_begin != events.end());
-
- if (range_begin != events.begin()) {
- /* clamp point before */
- if (need_adjacent_start_clamp) {
- events.insert (range_begin, point_factory (ninfo->start_time, start_value));
- }
- }
-
- events.insert (range_begin, nascent_events.begin(), nascent_events.end());
-
- if (range_end != events.end()) {
- /* clamp point after */
- if (need_adjacent_end_clamp) {
- events.insert (range_begin, point_factory (ninfo->end_time, end_value));
- }
- }
-
+
+ //if you write past the end of existing automation,
+ //then treat it as virgin territory
+ if (range_end == events.end()) {
+ need_adjacent_end_clamp = false;
+ }
+
+ /* clamp point before */
+ if (need_adjacent_start_clamp) {
+ events.insert (range_begin, point_factory (ninfo->start_time-1, start_value));
+ }
+
+ events.insert (range_begin, nascent_events.begin(), nascent_events.end());
+
+ /* clamp point after */
+ if (need_adjacent_end_clamp) {
+ events.insert (range_begin, point_factory (ninfo->end_time+1, end_value));
+ }
+
events.erase (range_begin, range_end);
}
@@ -474,7 +520,8 @@ void
AutomationList::fast_simple_add (double when, double value)
{
/* to be used only for loading pre-sorted data from saved state */
- events.insert (events.end(), point_factory (when, value));
+ if ( events.empty() || (when > events.back()->when) )
+ events.insert (events.end(), point_factory (when, value));
}
void
@@ -983,12 +1030,7 @@ AutomationList::shared_eval (double x)
return default_value;
case 1:
- if (x >= events.front()->when) {
- return events.front()->value;
- } else {
- // return default_value;
- return events.front()->value;
- }
+ return events.front()->value;
case 2:
if (x >= events.back()->when) {
@@ -1022,7 +1064,7 @@ AutomationList::shared_eval (double x)
return events.front()->value;
}
- return multipoint_eval (x);
+ return AutomationList::multipoint_eval (x); //switch to plain linear for now.
break;
}
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index f41cf6c691..be03df7926 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -2683,7 +2683,7 @@ IO::end_gain_touch ()
when = _session.transport_frame();
}
- _gain_automation_curve.stop_touch (mark, when);
+ _gain_automation_curve.stop_touch (mark, when, gain());
}
void
@@ -2706,7 +2706,7 @@ IO::end_pan_touch (uint32_t which)
when = _session.transport_frame();
}
- (*_panner)[which]->automation().stop_touch(mark, when);
+ (*_panner)[which]->automation().stop_touch(mark, when, 0);
}
}