summaryrefslogtreecommitdiff
path: root/libs
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 /libs
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
Diffstat (limited to 'libs')
-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
4 files changed, 96 insertions, 53 deletions
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);
}
}