Further automation refactoring - bring in the concept of Controllable, work towards
authorDavid Robillard <d@drobilla.net>
Fri, 29 Jun 2007 04:02:58 +0000 (04:02 +0000)
committerDavid Robillard <d@drobilla.net>
Fri, 29 Jun 2007 04:02:58 +0000 (04:02 +0000)
making automation + GUI + play/write/touch generic and easily reusable.
Added bar controller to automation track controls (mostly relevant for MIDI CC, but added for gain and pan too Just Because).
Fixed glaring "redirect" list errors.
Fix plugin controls/automation loading.

git-svn-id: svn://localhost/ardour2/trunk@2080 d708f5d6-7413-0410-9779-e7cbd77b26cf

80 files changed:
gtk2_ardour/SConscript
gtk2_ardour/ardour.bindings.in
gtk2_ardour/ardour.menus
gtk2_ardour/audio_region_view.cc
gtk2_ardour/audio_time_axis.cc
gtk2_ardour/automation_controller.cc [new file with mode: 0644]
gtk2_ardour/automation_controller.h [new file with mode: 0644]
gtk2_ardour/automation_gain_line.cc
gtk2_ardour/automation_gain_line.h
gtk2_ardour/automation_line.cc
gtk2_ardour/automation_line.h
gtk2_ardour/automation_midi_cc_line.cc
gtk2_ardour/automation_midi_cc_line.h
gtk2_ardour/automation_pan_line.cc
gtk2_ardour/automation_pan_line.h
gtk2_ardour/automation_time_axis.cc
gtk2_ardour/automation_time_axis.h
gtk2_ardour/editor.cc
gtk2_ardour/editor_mouse.cc
gtk2_ardour/editor_ops.cc
gtk2_ardour/editor_route_list.cc
gtk2_ardour/export_dialog.cc
gtk2_ardour/gain_automation_time_axis.cc
gtk2_ardour/gain_automation_time_axis.h
gtk2_ardour/gain_meter.cc
gtk2_ardour/gain_meter.h
gtk2_ardour/ladspa_pluginui.cc
gtk2_ardour/midi_controller_time_axis.cc
gtk2_ardour/midi_controller_time_axis.h
gtk2_ardour/midi_time_axis.cc
gtk2_ardour/mixer_strip.cc
gtk2_ardour/mixer_ui.cc
gtk2_ardour/pan_automation_time_axis.cc
gtk2_ardour/pan_automation_time_axis.h
gtk2_ardour/panner.cc
gtk2_ardour/panner.h
gtk2_ardour/panner_ui.cc
gtk2_ardour/processor_automation_line.cc
gtk2_ardour/processor_automation_line.h
gtk2_ardour/processor_automation_time_axis.cc
gtk2_ardour/processor_automation_time_axis.h
gtk2_ardour/processor_box.cc
gtk2_ardour/region_gain_line.cc
gtk2_ardour/region_gain_line.h
gtk2_ardour/route_params_ui.cc
gtk2_ardour/route_time_axis.cc
gtk2_ardour/route_ui.cc
gtk2_ardour/utils.cc
libs/ardour/SConscript
libs/ardour/ardour/audioregion.h
libs/ardour/ardour/automatable.h
libs/ardour/ardour/automation_control.h [new file with mode: 0644]
libs/ardour/ardour/io.h
libs/ardour/ardour/panner.h
libs/ardour/ardour/plugin_insert.h
libs/ardour/ardour/processor.h
libs/ardour/ardour/route.h
libs/ardour/ardour/session.h
libs/ardour/ardour/track.h
libs/ardour/audio_track.cc
libs/ardour/audioregion.cc
libs/ardour/automatable.cc
libs/ardour/automation_control.cc [new file with mode: 0644]
libs/ardour/automation_event.cc
libs/ardour/io.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_track.cc
libs/ardour/panner.cc
libs/ardour/plugin_insert.cc
libs/ardour/processor.cc
libs/ardour/route.cc
libs/ardour/session.cc
libs/ardour/session_process.cc
libs/ardour/session_state.cc
libs/ardour/session_transport.cc
libs/ardour/track.cc
libs/gtkmm2ext/barcontroller.cc
libs/gtkmm2ext/gtkmm2ext/barcontroller.h
libs/surfaces/mackie/mackie_control_protocol.cc
libs/surfaces/mackie/route_signal.cc

index 384e312e622b06cdb77d028476473ac5a49d9836..91245a5584161e5182db0c4dc6be70b847f355eb 100644 (file)
@@ -101,6 +101,7 @@ automation_midi_cc_line.cc
 automation_line.cc
 automation_pan_line.cc
 automation_time_axis.cc
+automation_controller.cc
 midi_time_axis.cc
 midi_streamview.cc
 axis_view.cc
index 2bdbe718831c9b5585b73b447c2d932a628f42c8..bbe72c05788ba3a2038d3d8b1feff7462c6901ad 100644 (file)
 ; (gtk_accel_path "<Actions>/Editor/Autoconnect" "")
 ; (gtk_accel_path "<Actions>/Editor/Edit" "")
 (gtk_accel_path "<Actions>/Editor/playhead-to-previous-region-end" "<Control>comma")
-; (gtk_accel_path "<Actions>/redirectmenu/copy" "")
+; (gtk_accel_path "<Actions>/processormenu/copy" "")
 ; (gtk_accel_path "<Actions>/options/MeterFalloffFaster" "")
 (gtk_accel_path "<Actions>/Transport/ToggleRollForgetCapture" "<Control>space")
 (gtk_accel_path "<Actions>/Transport/Record" "<Shift>r")
 ; (gtk_accel_path "<Actions>/RegionList/SortByRegionLength" "")
 ; (gtk_accel_path "<Actions>/options/MeterFalloffSlowest" "")
 ; (gtk_accel_path "<Actions>/Editor/playhead-to-previous-region-sync" "")
-; (gtk_accel_path "<Actions>/redirectmenu/deactivate_all" "")
+; (gtk_accel_path "<Actions>/processormenu/deactivate_all" "")
 ; (gtk_accel_path "<Actions>/RegionList/SortByRegionPosition" "")
 ; (gtk_accel_path "<Actions>/Editor/ZoomFocus" "")
 ; (gtk_accel_path "<Actions>/options/MeterFalloffSlow" "")
@@ -28,7 +28,7 @@
 ; (gtk_accel_path "<Actions>/Zoom/zoom-focus-playhead" "")
 ; (gtk_accel_path "<Actions>/Editor/center-edit-cursor" "")
 ; (gtk_accel_path "<Actions>/Editor/Monitoring" "")
-; (gtk_accel_path "<Actions>/redirectmenu/deactivate" "")
+; (gtk_accel_path "<Actions>/processormenu/deactivate" "")
 ; (gtk_accel_path "<Actions>/options/LatchedRecordEnable" "")
 ; (gtk_accel_path "<Actions>/Transport/TogglePunchIn" "")
 ; (gtk_accel_path "<Actions>/ShuttleActions/SetShuttleUnitsPercentage" "")
@@ -96,9 +96,9 @@
 ; (gtk_accel_path "<Actions>/Zoom/zoom-focus-edit" "")
 (gtk_accel_path "<Actions>/Editor/playhead-to-previous-region-start" "comma")
 ; (gtk_accel_path "<Actions>/Editor/EditCursorMovementOptions" "")
-; (gtk_accel_path "<Actions>/redirectmenu/activate_all" "")
+; (gtk_accel_path "<Actions>/processormenu/activate_all" "")
 ; (gtk_accel_path "<Actions>/Editor/addExternalAudioAsTapeTrack" "")
-; (gtk_accel_path "<Actions>/redirectmenu/paste" "")
+; (gtk_accel_path "<Actions>/processormenu/paste" "")
 ; (gtk_accel_path "<Actions>/Editor/Smpte25" "")
 ; (gtk_accel_path "<Actions>/options/RegionEquivalentsOverlap" "")
 ; (gtk_accel_path "<Actions>/Main/MeteringFallOffRate" "")
 (gtk_accel_path "<Actions>/Editor/align-regions-sync-relative" "a")
 ; (gtk_accel_path "<Actions>/Editor/EditSelectRegionOptions" "")
 (gtk_accel_path "<Actions>/Editor/crop" "c")
-; (gtk_accel_path "<Actions>/redirectmenu/newsend" "")
+; (gtk_accel_path "<Actions>/processormenu/newsend" "")
 ; (gtk_accel_path "<Actions>/Editor/ToggleGeneric MIDISurfaceSubMenu" "")
 ; (gtk_accel_path "<Actions>/Editor/MeterFalloff" "")
 ; (gtk_accel_path "<Actions>/RegionList/rlRemove" "")
 (gtk_accel_path "<Actions>/Editor/align-regions-sync" "<Mod2>a")
 ; (gtk_accel_path "<Actions>/Main/Windows" "")
 ; (gtk_accel_path "<Actions>/Main/CleanupUnused" "")
-; (gtk_accel_path "<Actions>/redirectmenu/deselectall" "")
+; (gtk_accel_path "<Actions>/processormenu/deselectall" "")
 ; (gtk_accel_path "<Actions>/options/SoloViaBus" "")
 (gtk_accel_path "<Actions>/MouseMode/set-mouse-mode-zoom" "z")
 ; (gtk_accel_path "<Actions>/RegionList/rlAudition" "")
 (gtk_accel_path "<Actions>/Editor/temporal-zoom-in" "minus")
 ; (gtk_accel_path "<Actions>/JACK/Latency" "")
 (gtk_accel_path "<Actions>/Editor/edit-cursor-to-range-end" "F2")
-; (gtk_accel_path "<Actions>/redirectmenu/rename" "")
+; (gtk_accel_path "<Actions>/processormenu/rename" "")
 ; (gtk_accel_path "<Actions>/RegionList/rlShowAuto" "")
 (gtk_accel_path "<Actions>/Editor/select-all-before-playhead" "<Control>p")
 ; (gtk_accel_path "<Actions>/Editor/addExistingAudioFiles" "")
 (gtk_accel_path "<Actions>/Common/goto-mixer" "<Alt>m")
 ; (gtk_accel_path "<Actions>/Editor/addExternalAudioToTrack" "")
 ; (gtk_accel_path "<Actions>/RegionList/SortBySourceFileCreationDate" "")
-; (gtk_accel_path "<Actions>/redirectmenu/activate" "")
+; (gtk_accel_path "<Actions>/processormenu/activate" "")
 (gtk_accel_path "<Actions>/Editor/extend-range-to-start-of-region" "leftanglebracket")
 ; (gtk_accel_path "<Actions>/Editor/PullupMinus1" "")
 ; (gtk_accel_path "<Actions>/Editor/snap-normal" "")
 (gtk_accel_path "<Actions>/Common/ToggleBigClock" "<Alt>b")
 ; (gtk_accel_path "<Actions>/Snap/snap-to-asixteenthbeat" "")
 (gtk_accel_path "<Actions>/Editor/select-all-in-punch-range" "<Control>d")
-; (gtk_accel_path "<Actions>/redirectmenu/edit" "")
+; (gtk_accel_path "<Actions>/processormenu/edit" "")
 (gtk_accel_path "<Actions>/Editor/duplicate-region" "d")
 ; (gtk_accel_path "<Actions>/JACK/JACKLatency2048" "")
 ; (gtk_accel_path "<Actions>/Editor/ToggleWaveformsWhileRecording" "")
 ; (gtk_accel_path "<Actions>/options/FileHeaderFormatWAVE" "")
 (gtk_accel_path "<Actions>/Transport/GotoZero" "KP_Insert")
 (gtk_accel_path "<Actions>/Transport/GotoEnd" "End")
-; (gtk_accel_path "<Actions>/redirectmenu/cut" "")
-; (gtk_accel_path "<Actions>/redirectmenu/newinsert" "")
+; (gtk_accel_path "<Actions>/processormenu/cut" "")
+; (gtk_accel_path "<Actions>/processormenu/newinsert" "")
 ; (gtk_accel_path "<Actions>/options/UseMMC" "")
 ; (gtk_accel_path "<Actions>/options/MeterFalloffOff" "")
 (gtk_accel_path "<Actions>/MouseMode/set-mouse-mode-object" "o")
 ; (gtk_accel_path "<Actions>/Editor/toggle-xfades-active" "")
 ; (gtk_accel_path "<Actions>/Snap/snap-to-bar" "")
 ; (gtk_accel_path "<Actions>/Editor/LayerLaterHigher" "")
-; (gtk_accel_path "<Actions>/redirectmenu/selectall" "")
+; (gtk_accel_path "<Actions>/processormenu/selectall" "")
 (gtk_accel_path "<Actions>/Editor/editor-copy" "<Control>c")
 ; (gtk_accel_path "<Actions>/Snap/snap-to-quarters" "")
 (gtk_accel_path "<Actions>/Editor/temporal-zoom-out" "equal")
 ; (gtk_accel_path "<Actions>/options/OutputAutoConnectManual" "")
 ; (gtk_accel_path "<Actions>/Snap/snap-to-region-sync" "")
 (gtk_accel_path "<Actions>/Editor/edit-cursor-to-previous-region-sync" "apostrophe")
-; (gtk_accel_path "<Actions>/redirectmenu/clear" "")
+; (gtk_accel_path "<Actions>/processormenu/clear" "")
 ; (gtk_accel_path "<Actions>/Editor/ToggleGeneric MIDISurfaceFeedback" "")
 ; (gtk_accel_path "<Actions>/Editor/PullupPlus4Minus1" "")
 ; (gtk_accel_path "<Actions>/JACK/JACKLatency512" "")
 (gtk_accel_path "<Actions>/Editor/edit-cursor-to-next-region-end" "<Control>bracketright")
 ; (gtk_accel_path "<Actions>/Main/Recent" "")
-; (gtk_accel_path "<Actions>/redirectmenu/newplugin" "")
+; (gtk_accel_path "<Actions>/processormenu/newplugin" "")
 ; (gtk_accel_path "<Actions>/options/InputAutoConnectManual" "")
 ; (gtk_accel_path "<Actions>/options/MeterHoldLong" "")
 ; (gtk_accel_path "<Actions>/Snap/snap-to-seconds" "")
index 13b8cbf738897cb67a20f963522b46f9aa0170df..27dea430d8c8c50f49eb095fe43a54cea8fc179b 100644 (file)
        </menu>
      </menubar>
 
-     <popup name='redirectmenu'>
+     <popup name='processormenu'>
         <menuitem action='newplugin'/>
         <menuitem action='newinsert'/>
         <menuitem action='newsend'/>
index 058295949f8de94495d5b264040eb9193c540410..40349877a1e7bd62a249c1f07cc119ea231cb5ae 100644 (file)
@@ -171,11 +171,11 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfd)
 
        setup_fade_handle_positions ();
 
-       string foo = _region->name();
-       foo += ':';
-       foo += "gain";
+       string line_name = _region->name();
+       line_name += ':';
+       line_name += "gain";
 
-       gain_line = new AudioRegionGainLine (foo, trackview.session(), *this, *group, audio_region()->envelope());
+       gain_line = new AudioRegionGainLine (line_name, trackview.session(), *this, *group, audio_region()->envelope());
 
        if (!(_flags & EnvelopeVisible)) {
                gain_line->hide ();
@@ -489,7 +489,7 @@ AudioRegionView::reset_fade_shapes ()
 void
 AudioRegionView::reset_fade_in_shape ()
 {
-       reset_fade_in_shape_width ((nframes_t) audio_region()->fade_in().back()->when);
+       reset_fade_in_shape_width ((nframes_t) audio_region()->fade_in()->back()->when);
 }
        
 void
@@ -534,7 +534,7 @@ AudioRegionView::reset_fade_in_shape_width (nframes_t width)
        fade_in_shape->show();
 
        float curve[npoints];
-       audio_region()->fade_in().curve().get_vector (0, audio_region()->fade_in().back()->when, curve, npoints);
+       audio_region()->fade_in()->curve().get_vector (0, audio_region()->fade_in()->back()->when, curve, npoints);
 
        points = get_canvas_points ("fade in shape", npoints+3);
 
@@ -573,7 +573,7 @@ AudioRegionView::reset_fade_in_shape_width (nframes_t width)
 void
 AudioRegionView::reset_fade_out_shape ()
 {
-       reset_fade_out_shape_width ((nframes_t) audio_region()->fade_out().back()->when);
+       reset_fade_out_shape_width ((nframes_t) audio_region()->fade_out()->back()->when);
 }
 
 void
@@ -620,7 +620,7 @@ AudioRegionView::reset_fade_out_shape_width (nframes_t width)
        fade_out_shape->show();
 
        float curve[npoints];
-       audio_region()->fade_out().curve().get_vector (0, audio_region()->fade_out().back()->when, curve, npoints);
+       audio_region()->fade_out()->curve().get_vector (0, audio_region()->fade_out()->back()->when, curve, npoints);
 
        if (_height > NAME_HIGHLIGHT_THRESH) {
                h = _height - NAME_HIGHLIGHT_SIZE;
@@ -941,7 +941,7 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
        gain_line->view_to_model_y (y);
 
        trackview.session().begin_reversible_command (_("add gain control point"));
-       XMLNode &before = audio_region()->envelope().get_state();
+       XMLNode &before = audio_region()->envelope()->get_state();
 
        if (!audio_region()->envelope_active()) {
                XMLNode &region_before = audio_region()->get_state();
@@ -950,10 +950,10 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
                trackview.session().add_command (new MementoCommand<AudioRegion>(*(audio_region().get()), &region_before, &region_after));
        }
 
-       audio_region()->envelope().add (fx, y);
+       audio_region()->envelope()->add (fx, y);
        
-       XMLNode &after = audio_region()->envelope().get_state();
-       trackview.session().add_command (new MementoCommand<AutomationList>(audio_region()->envelope(), &before, &after));
+       XMLNode &after = audio_region()->envelope()->get_state();
+       trackview.session().add_command (new MementoCommand<AutomationList>(*audio_region()->envelope().get(), &before, &after));
        trackview.session().commit_reversible_command ();
 }
 
@@ -961,7 +961,7 @@ void
 AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
 {
         ControlPoint *cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"));
-       audio_region()->envelope().erase (cp->model);
+       audio_region()->envelope()->erase (cp->model);
 }
 
 void
index 416a86c1a5a14e676201671d493dc19e1e837a42..3d62915171fc2add7a22200031e1d2ffc4480996 100644 (file)
@@ -284,18 +284,25 @@ void
 AudioTimeAxisView::create_automation_child (ParamID param)
 {
        if (param.type() == GainAutomation) {
+
+               boost::shared_ptr<AutomationControl> c = _route->gain_control();
+               if (!c) {
+                       error << "Route has no gain automation, unable to add automation track view." << endmsg;
+                       return;
+               }
+
                GainAutomationTimeAxisView* gain_track = new GainAutomationTimeAxisView (_session,
                                _route,
                                editor,
                                *this,
                                parent_canvas,
                                _route->describe_parameter(param),
-                               _route->gain_automation());
+                               c);
 
                AutomationLine* line = new AutomationGainLine ("automation gain",
                                *gain_track,
                                *gain_track->canvas_display,
-                               _route->gain_automation());
+                               c->list());
 
                line->set_line_color (Config->canvasvar_AutomationLine.get());
 
@@ -304,7 +311,7 @@ AudioTimeAxisView::create_automation_child (ParamID param)
                add_automation_child(ParamID(GainAutomation), gain_track);
 
        } else if (param.type() == PanAutomation) {
-
+               
                PanAutomationTimeAxisView* pan_track = new PanAutomationTimeAxisView (_session,
                                 _route,
                                 editor,
diff --git a/gtk2_ardour/automation_controller.cc b/gtk2_ardour/automation_controller.cc
new file mode 100644 (file)
index 0000000..a72aa0b
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+    Copyright (C) 2007 Paul Davis 
+       Author: Dave Robillard
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <pbd/error.h>
+#include "automation_controller.h"
+#include "ardour/automation_event.h"
+#include "ardour/automation_control.h"
+#include "ardour_ui.h"
+#include "utils.h"
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace Gtk;
+
+
+AutomationController::AutomationController(boost::shared_ptr<AutomationControl> ac, Adjustment* adj)
+       : BarController(*adj, *ac)
+       , _ignore_change(false)
+       , _controllable(ac)
+       , _adjustment(adj)
+{
+       set_name (X_("PluginSlider")); // FIXME: get yer own name!
+       set_style (BarController::LeftToRight);
+       set_use_parent (true);
+       
+       label_callback = sigc::mem_fun(this, &AutomationController::update_label);
+       
+       StartGesture.connect (mem_fun(*this, &AutomationController::start_touch));
+       StopGesture.connect (mem_fun(*this, &AutomationController::end_touch));
+       
+       _adjustment->signal_value_changed().connect (
+                       mem_fun(*this, &AutomationController::value_adjusted));
+               
+       _screen_update_connection = ARDOUR_UI::RapidScreenUpdate.connect (
+                       mem_fun (*this, &AutomationController::display_effective_value));
+}
+
+AutomationController::~AutomationController()
+{
+}
+
+boost::shared_ptr<AutomationController>
+AutomationController::create(Session& s, boost::shared_ptr<AutomationList> al, boost::shared_ptr<AutomationControl> ac)
+{
+       Gtk::Adjustment* adjustment = manage(new Gtk::Adjustment(al->default_value(), al->get_min_y(), al->get_max_y()));
+       if (!ac) {
+               PBD::warning << "Creating AutomationController for " << al->param_id().to_string() << endmsg;
+               ac = boost::shared_ptr<AutomationControl>(new AutomationControl(s, al));
+       }
+       return boost::shared_ptr<AutomationController>(new AutomationController(ac, adjustment));
+}
+
+void
+AutomationController::update_label(char* label, int label_len)
+{
+       //cerr << "Controller label: " << label << endl;
+}
+
+void
+AutomationController::display_effective_value()
+{
+       if ( ! _controllable->list()->automation_playback())
+               return;
+
+       float value = _controllable->get_value();
+       
+       if (_adjustment->get_value() != value) {
+               _ignore_change = true; 
+               _adjustment->set_value (value);
+               _ignore_change = false;
+       }
+}
+
+void
+AutomationController::value_adjusted()
+{
+       if (!_ignore_change) {
+               _controllable->set_value(_adjustment->get_value());
+       }
+}
+
+void
+AutomationController::start_touch()
+{
+       _controllable->list()->start_touch();
+}
+
+void
+AutomationController::end_touch()
+{
+       _controllable->list()->stop_touch();
+}
diff --git a/gtk2_ardour/automation_controller.h b/gtk2_ardour/automation_controller.h
new file mode 100644 (file)
index 0000000..042f4a3
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+    Copyright (C) 2007 Paul Davis 
+       Author: Dave Robillard
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_gtk_automation_controller_h__
+#define __ardour_gtk_automation_controller_h__
+
+#include <boost/shared_ptr.hpp>
+#include <gtkmm.h>
+#include <gtkmm2ext/barcontroller.h>
+
+namespace ARDOUR {
+       class Session;
+       class AutomationList;
+       class AutomationControl;
+}
+
+
+class AutomationController : public Gtkmm2ext::BarController {
+public:
+       static boost::shared_ptr<AutomationController> create(
+                       ARDOUR::Session& s,
+                       boost::shared_ptr<ARDOUR::AutomationList> al,
+                       boost::shared_ptr<ARDOUR::AutomationControl> ac);
+
+       ~AutomationController();
+       
+       boost::shared_ptr<ARDOUR::AutomationControl> controllable() { return _controllable; }
+       
+       void update_label(char* label, int label_len);
+       void display_effective_value();
+       void value_adjusted();
+
+private:
+       AutomationController(boost::shared_ptr<ARDOUR::AutomationControl> ac, Gtk::Adjustment* adj);
+       void start_touch();
+       void end_touch();
+
+       bool                                         _ignore_change;
+       boost::shared_ptr<ARDOUR::AutomationControl> _controllable;
+       Gtk::Adjustment*                             _adjustment;
+       sigc::connection                             _screen_update_connection;
+};
+
+
+#endif /* __ardour_gtk_automation_controller_h__ */
index 84488dc2b50742930bde00195405efbda91cc57c..0480016ca2c5e0c59f8c5077af7483ff4b4bd304 100644 (file)
@@ -30,7 +30,7 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-AutomationGainLine::AutomationGainLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, AutomationList& l)
+AutomationGainLine::AutomationGainLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, boost::shared_ptr<AutomationList> l)
 
        : AutomationLine (name, tv, parent, l)
 {
index fe8c9274f2b1c91007da531ba067bb6af3b67556..a5ddafdd57e79bdb9d3b46fa1a3dcc4445741fe8 100644 (file)
@@ -30,7 +30,7 @@ class TimeAxisView;
 class AutomationGainLine : public AutomationLine
 {
   public:
-       AutomationGainLine (const string & name, TimeAxisView&, ArdourCanvas::Group& parent, ARDOUR::AutomationList&);
+       AutomationGainLine (const string & name, TimeAxisView&, ArdourCanvas::Group& parent, boost::shared_ptr<ARDOUR::AutomationList>);
        
        void view_to_model_y (double&);
        void model_to_view_y (double&);
index 683a76793547f84fd62f3873071453a87d71fc89..f6b54cd12806551f677dfe9535e3737462cfacd7 100644 (file)
@@ -57,7 +57,7 @@ using namespace Gnome; // for Canvas
 ControlPoint::ControlPoint (AutomationLine& al)
        : line (al)
 {
-       model = al.the_list().end();
+       model = al.the_list()->end();
        view_index = 0;
        can_slide = true;
        _x = 0;
@@ -220,7 +220,7 @@ ControlPoint::move_to (double x, double y, ShapeType shape)
 
 /*****/
 
-AutomationLine::AutomationLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, AutomationList& al)
+AutomationLine::AutomationLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, boost::shared_ptr<AutomationList> al)
        : trackview (tv),
          _name (name),
          alist (al),
@@ -245,10 +245,9 @@ AutomationLine::AutomationLine (const string & name, TimeAxisView& tv, ArdourCan
 
        line->signal_event().connect (mem_fun (*this, &AutomationLine::event_handler));
 
-       alist.StateChanged.connect (mem_fun(*this, &AutomationLine::list_changed));
-
-        trackview.session().register_with_memento_command_factory(alist.id(), this);
+       alist->StateChanged.connect (mem_fun(*this, &AutomationLine::list_changed));
 
+       trackview.session().register_with_memento_command_factory(alist->id(), this);
 }
 
 AutomationLine::~AutomationLine ()
@@ -612,7 +611,7 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
 
        view_index = 0;
 
-       for (model = alist.begin(), pi = 0; pi < npoints; ++model, ++pi) {
+       for (model = alist->begin(), pi = 0; pi < npoints; ++model, ++pi) {
 
                double tx = points[pi].x;
                double ty = points[pi].y;
@@ -808,7 +807,7 @@ AutomationLine::start_drag (ControlPoint* cp, nframes_t x, float fraction)
        }
 
        trackview.editor.current_session()->begin_reversible_command (str);
-       trackview.editor.current_session()->add_command (new MementoCommand<AutomationList>(alist, &get_state(), 0));
+       trackview.editor.current_session()->add_command (new MementoCommand<AutomationList>(*alist.get(), &get_state(), 0));
        
        drag_x = x;
        drag_distance = 0;
@@ -872,7 +871,7 @@ AutomationLine::end_drag (ControlPoint* cp)
                return;
        }
 
-       alist.freeze ();
+       alist->freeze ();
 
        if (cp) {
                sync_model_with_view_point (*cp, did_push, drag_distance);
@@ -880,11 +879,11 @@ AutomationLine::end_drag (ControlPoint* cp)
                sync_model_with_view_line (line_drag_cp1, line_drag_cp2);
        }
        
-       alist.thaw ();
+       alist->thaw ();
 
        update_pending = false;
 
-       trackview.editor.current_session()->add_command (new MementoCommand<AutomationList>(alist, 0, &alist.get_state()));
+       trackview.editor.current_session()->add_command (new MementoCommand<AutomationList>(*alist.get(), 0, &alist->get_state()));
        trackview.editor.current_session()->commit_reversible_command ();
        trackview.editor.current_session()->set_dirty ();
 }
@@ -919,14 +918,14 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int
                /* interpolate */
                
                if (y_delta || x_delta) {
-                       alist.modify (i, (*i)->when + x_delta, mr.ymin + y_delta);
+                       alist->modify (i, (*i)->when + x_delta, mr.ymin + y_delta);
                }
        }
 
        /* change the primary point */
 
        update_pending = true;
-       alist.modify (cp.model, mr.xval, mr.yval);
+       alist->modify (cp.model, mr.xval, mr.yval);
 
 
        /* change later points */
@@ -942,7 +941,7 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int
                /* all later points move by the same distance along the x-axis as the main point */
                
                if (delta) {
-                       alist.modify (i, (*i)->when + distance, (*i)->value + delta);
+                       alist->modify (i, (*i)->when + distance, (*i)->value + delta);
                }
                
                ++i;
@@ -954,7 +953,7 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int
                   as the main point moved.
                */
 
-               alist.slide (mr.end, drag_distance);
+               alist->slide (mr.end, drag_distance);
        }
 
 }
@@ -998,7 +997,7 @@ AutomationLine::is_last_point (ControlPoint& cp)
 
        // If the list is not empty, and the point is the last point in the list
 
-       if (!alist.empty() && mr.end == alist.end()) {
+       if (!alist->empty() && mr.end == alist->end()) {
                return true;
        }
        
@@ -1014,7 +1013,7 @@ AutomationLine::is_first_point (ControlPoint& cp)
 
        // If the list is not empty, and the point is the first point in the list
 
-       if (!alist.empty() && mr.start == alist.begin()) {
+       if (!alist->empty() && mr.start == alist->begin()) {
                return true;
        }
        
@@ -1030,11 +1029,12 @@ AutomationLine::remove_point (ControlPoint& cp)
        model_representation (cp, mr);
 
        trackview.editor.current_session()->begin_reversible_command (_("remove control point"));
-        XMLNode &before = alist.get_state();
+        XMLNode &before = alist->get_state();
 
-       alist.erase (mr.start, mr.end);
+       alist->erase (mr.start, mr.end);
 
-       trackview.editor.current_session()->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
+       trackview.editor.current_session()->add_command(new MementoCommand<AutomationList>(
+                       *alist.get(), &before, &alist->get_state()));
        trackview.editor.current_session()->commit_reversible_command ();
        trackview.editor.current_session()->set_dirty ();
 }
@@ -1229,7 +1229,7 @@ AutomationLine::reset ()
                return;
        }
 
-       alist.apply_to_points (*this, &AutomationLine::reset_callback);
+       alist->apply_to_points (*this, &AutomationLine::reset_callback);
 }
 
 void
@@ -1237,7 +1237,7 @@ AutomationLine::clear ()
 {
        /* parent must create command */
         XMLNode &before = get_state();
-       alist.clear();
+       alist->clear();
        trackview.editor.current_session()->add_command (new MementoCommand<AutomationLine>(*this, &before, &get_state()));
        trackview.editor.current_session()->commit_reversible_command ();
        trackview.editor.current_session()->set_dirty ();
@@ -1251,7 +1251,7 @@ AutomationLine::change_model (AutomationList::iterator i, double x, double y)
 void
 AutomationLine::change_model_range (AutomationList::iterator start, AutomationList::iterator end, double xdelta, float ydelta)
 {
-       alist.move_range (start, end, xdelta, ydelta);
+       alist->move_range (start, end, xdelta, ydelta);
 }
 
 void
@@ -1281,12 +1281,12 @@ XMLNode &
 AutomationLine::get_state (void)
 {
        /* function as a proxy for the model */
-       return alist.get_state();
+       return alist->get_state();
 }
 
 int 
 AutomationLine::set_state (const XMLNode &node)
 {
        /* function as a proxy for the model */
-       return alist.set_state (node);
+       return alist->set_state (node);
 }
index 41034dbf6e2b8a99f639a348b96f58282536c84b..a915966d97259aac46b6db9c2ac47e661cf2dc5f 100644 (file)
@@ -98,7 +98,7 @@ class ControlPoint
 class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoingAway
 {
   public:
-       AutomationLine (const string & name, TimeAxisView&, ArdourCanvas::Group&, ARDOUR::AutomationList&);
+       AutomationLine (const string & name, TimeAxisView&, ArdourCanvas::Group&, boost::shared_ptr<ARDOUR::AutomationList>);
        virtual ~AutomationLine ();
 
        void queue_reset ();
@@ -150,7 +150,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoin
        virtual void view_to_model_y (double&) = 0;
        virtual void model_to_view_y (double&) = 0;
 
-       ARDOUR::AutomationList& the_list() const { return alist; }
+       boost::shared_ptr<ARDOUR::AutomationList> the_list() const { return alist; }
 
        void show_all_control_points ();
        void hide_all_but_selected_control_points ();
@@ -168,7 +168,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoin
        guint32 _y_position;
        guint32 _height;
        uint32_t _line_color;
-       ARDOUR::AutomationList& alist;
+       boost::shared_ptr<ARDOUR::AutomationList> alist;
 
        bool    _visible  : 1;
        bool    _vc_uses_gain_mapping : 1;
index 4a074ddbe9a28bddf9f21521f6b35e62060c5c4d..9bfef278e136b394b400bb0b615ecfc1894c1eba 100644 (file)
@@ -27,7 +27,7 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-AutomationMidiCCLine::AutomationMidiCCLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, AutomationList& l)
+AutomationMidiCCLine::AutomationMidiCCLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, boost::shared_ptr<AutomationList> l)
 
        : AutomationLine (name, tv, parent, l)
 {
index 6ac078a9117d1edf0765bd1626f3705cf5c78fc9..82a5e0f816874ee9f385d6000693e43269107c7f 100644 (file)
@@ -30,7 +30,7 @@ class TimeAxisView;
 class AutomationMidiCCLine : public AutomationLine
 {
   public:
-       AutomationMidiCCLine (const string & name, TimeAxisView&, ArdourCanvas::Group& parent, ARDOUR::AutomationList&);
+       AutomationMidiCCLine (const string & name, TimeAxisView&, ArdourCanvas::Group& parent, boost::shared_ptr<ARDOUR::AutomationList>);
        
        void view_to_model_y (double&);
        void model_to_view_y (double&);
index 0e36f4ef885d1f9d4031b770579acc6908bc67ad..02c9fe2c49ec31b50e4e1e6fd725f9e701ce5ed6 100644 (file)
@@ -30,7 +30,7 @@
 using namespace ARDOUR;
 using namespace PBD;
 
-AutomationPanLine::AutomationPanLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, AutomationList& l)
+AutomationPanLine::AutomationPanLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, boost::shared_ptr<AutomationList> l)
 
        : AutomationLine (name, tv, parent, l)
 {
index 6374c535e0ebdb307274eb91bdb0e1168a1759a2..d77efdd8e34752a5c226574eba64e2931aace71b 100644 (file)
@@ -30,7 +30,7 @@ class TimeAxisView;
 class AutomationPanLine : public AutomationLine
 {
   public:
-       AutomationPanLine (const string & name, TimeAxisView&, ArdourCanvas::Group& parent, ARDOUR::AutomationList&);
+       AutomationPanLine (const string & name, TimeAxisView&, ArdourCanvas::Group& parent, boost::shared_ptr<ARDOUR::AutomationList>);
        
        void view_to_model_y (double&);
        void model_to_view_y (double&);
index 04ac1ee0763835d54c0c2415b29bb49073d7df8f..ffb66e22709e2b2036d7b7e32407de9dbe949664 100644 (file)
 
 */
 
+#include <utility>
 #include <ardour/route.h>
+#include <ardour/automation_control.h>
 #include <pbd/memento_command.h>
+#include <gtkmm2ext/barcontroller.h>
 
 #include "ardour_ui.h"
 #include "automation_time_axis.h"
@@ -38,6 +41,7 @@
 using namespace ARDOUR;
 using namespace PBD;
 using namespace Gtk;
+using namespace Gtkmm2ext;
 using namespace Editing;
 
 Pango::FontDescription AutomationTimeAxisView::name_font;
@@ -69,7 +73,7 @@ AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptr<Ro
        auto_play_item = 0;
        ignore_state_request = false;
        first_call_to_set_height = true;
-
+       
        base_rect = new SimpleRect(*canvas_display);
        base_rect->property_x1() = 0.0;
        base_rect->property_y1() = 0.0;
@@ -217,6 +221,17 @@ AutomationTimeAxisView::auto_clicked ()
        automation_menu->popup (1, gtk_get_current_event_time());
 }
 
+void
+AutomationTimeAxisView::set_automation_state (AutoState state)
+{
+       if (!ignore_state_request) {
+               for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+                       route->set_parameter_automation_state (
+                                       i->second->controllable()->list()->param_id(),
+                                       state);
+               }
+       }
+}
 
 void
 AutomationTimeAxisView::automation_state_changed ()
@@ -228,7 +243,7 @@ AutomationTimeAxisView::automation_state_changed ()
        if (lines.empty()) {
                state = Off;
        } else {
-               state = lines.front()->the_list().automation_state ();
+               state = lines.front().first->the_list()->automation_state ();
        }
 
        switch (state & (Off|Play|Touch|Write)) {
@@ -292,8 +307,8 @@ void
 AutomationTimeAxisView::clear_clicked ()
 {
        _session.begin_reversible_command (_("clear automation"));
-       for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-               (*i)->clear ();
+       for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+               i->first->clear ();
        }
        _session.commit_reversible_command ();
 }
@@ -304,7 +319,7 @@ AutomationTimeAxisView::set_height (TrackHeight ht)
        uint32_t h = height_to_pixels (ht);
        bool changed = (height != (uint32_t) h);
 
-       bool changed_between_small_and_normal = ( (ht == Small || ht == Smaller) ^ (height_style == Small || height_style == Smaller) );
+       //bool changed_between_small_and_normal = ( (ht == Small || ht == Smaller) ^ (height_style == Small || height_style == Smaller) );
 
        TimeAxisView* state_parent = get_parent_with_state ();
        XMLNode* xml_node = state_parent->get_child_xml_node (_state_name);
@@ -312,8 +327,8 @@ AutomationTimeAxisView::set_height (TrackHeight ht)
        TimeAxisView::set_height (ht);
        base_rect->property_y2() = h;
 
-       for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-               (*i)->set_y_position_and_height (0, h);
+       for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+               i->first->set_y_position_and_height (0, h);
        }
 
        for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
@@ -347,12 +362,20 @@ AutomationTimeAxisView::set_height (TrackHeight ht)
                break;
        }
 
-       if (changed_between_small_and_normal || first_call_to_set_height) {
+       //if (changed_between_small_and_normal || first_call_to_set_height) {
                first_call_to_set_height = false;
+               unsigned control_cnt = 0;
                switch (ht) {
                        case Largest:
                        case Large:
                        case Larger:
+
+                               for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+                                       i->second->show ();
+                                       controls_table.attach (*i->second.get(), 0, 8, 2 + control_cnt, 3 + control_cnt, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
+                                       ++control_cnt;
+                               }
+
                        case Normal:
 
                                controls_table.remove (name_hbox);
@@ -400,7 +423,7 @@ AutomationTimeAxisView::set_height (TrackHeight ht)
                                hide_button.hide();
                                break;
                }
-       }
+       //}
 
        if (changed) {
                /* only emit the signal if the height really changed */
@@ -413,8 +436,8 @@ AutomationTimeAxisView::set_samples_per_unit (double spu)
 {
        TimeAxisView::set_samples_per_unit (editor.get_current_zoom());
 
-       for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-               (*i)->reset ();
+       for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+               i->first->reset ();
        }
 }
  
@@ -486,8 +509,8 @@ AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
 {
        bool ret = false;
 
-       for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-               ret = cut_copy_clear_one ((**i), selection, op);
+       for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+               ret = cut_copy_clear_one (*i->first, selection, op);
        }
 
        return ret;
@@ -497,28 +520,28 @@ bool
 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
 {
        AutomationList* what_we_got = 0;
-       AutomationList& alist (line.the_list());
+       boost::shared_ptr<AutomationList> alist (line.the_list());
        bool ret = false;
 
-        XMLNode &before = alist.get_state();
+       XMLNode &before = alist->get_state();
 
        switch (op) {
        case Cut:
-               if ((what_we_got = alist.cut (selection.time.front().start, selection.time.front().end)) != 0) {
+               if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
                        editor.get_cut_buffer().add (what_we_got);
-                       _session.add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
+                       _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
                        ret = true;
                }
                break;
        case Copy:
-               if ((what_we_got = alist.copy (selection.time.front().start, selection.time.front().end)) != 0) {
+               if ((what_we_got = alist->copy (selection.time.front().start, selection.time.front().end)) != 0) {
                        editor.get_cut_buffer().add (what_we_got);
                }
                break;
 
        case Clear:
-               if ((what_we_got = alist.cut (selection.time.front().start, selection.time.front().end)) != 0) {
-                       _session.add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
+               if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
+                       _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
                        delete what_we_got;
                        what_we_got = 0;
                        ret = true;
@@ -540,17 +563,17 @@ AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& sel
 void
 AutomationTimeAxisView::reset_objects (PointSelection& selection)
 {
-       for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-               reset_objects_one ((**i), selection);
+       for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+               reset_objects_one (*i->first, selection);
        }
 }
 
 void
 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
 {
-       AutomationList& alist (line.the_list());
+       boost::shared_ptr<AutomationList> alist(line.the_list());
 
-       _session.add_command (new MementoCommand<AutomationList>(alist, &alist.get_state(), 0));
+       _session.add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
 
        for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
 
@@ -558,7 +581,7 @@ AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection&
                        continue;
                }
                
-               alist.reset_range ((*i).start, (*i).end);
+               alist->reset_range ((*i).start, (*i).end);
        }
 }
 
@@ -567,8 +590,8 @@ AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCo
 {
        bool ret = false;
 
-       for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-               ret = cut_copy_clear_objects_one ((**i), selection, op);
+       for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+               ret = cut_copy_clear_objects_one (*i->first, selection, op);
        }
 
        return ret;
@@ -578,10 +601,10 @@ bool
 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
 {
        AutomationList* what_we_got = 0;
-       AutomationList& alist (line.the_list());
+       boost::shared_ptr<AutomationList> alist(line.the_list());
        bool ret = false;
 
-        XMLNode &before = alist.get_state();
+       XMLNode &before = alist->get_state();
 
        for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
 
@@ -591,21 +614,21 @@ AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointS
 
                switch (op) {
                case Cut:
-                       if ((what_we_got = alist.cut ((*i).start, (*i).end)) != 0) {
+                       if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
                                editor.get_cut_buffer().add (what_we_got);
-                               _session.add_command (new MementoCommand<AutomationList>(alist, new XMLNode (before), &alist.get_state()));
+                               _session.add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
                                ret = true;
                        }
                        break;
                case Copy:
-                       if ((what_we_got = alist.copy ((*i).start, (*i).end)) != 0) {
+                       if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
                                editor.get_cut_buffer().add (what_we_got);
                        }
                        break;
                        
                case Clear:
-                       if ((what_we_got = alist.cut ((*i).start, (*i).end)) != 0) {
-                               _session.add_command (new MementoCommand<AutomationList>(alist, new XMLNode (before), &alist.get_state()));
+                       if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
+                               _session.add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
                                delete what_we_got;
                                what_we_got = 0;
                                ret = true;
@@ -632,8 +655,8 @@ AutomationTimeAxisView::paste (nframes_t pos, float times, Selection& selection,
 {
        bool ret = true;
 
-       for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-               ret = paste_one (**i, pos, times, selection, nth);
+       for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+               ret = paste_one (*i->first, pos, times, selection, nth);
        }
 
        return ret;
@@ -643,7 +666,7 @@ bool
 AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth)
 {
        AutomationSelection::iterator p;
-       AutomationList& alist (line.the_list());
+       boost::shared_ptr<AutomationList> alist(line.the_list());
        
        for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth);
 
@@ -664,9 +687,9 @@ AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float ti
                (*x)->value = foo;
        }
 
-        XMLNode &before = alist.get_state();
-       alist.paste (copy, pos, times);
-       _session.add_command (new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
+       XMLNode &before = alist->get_state();
+       alist->paste (copy, pos, times);
+       _session.add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
 
        return true;
 }
@@ -725,8 +748,8 @@ AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double
                        botfrac = 1.0 - ((bot - y_position) / height);
                }
 
-               for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-                       (*i)->get_selectables (start, end, botfrac, topfrac, results);
+               for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+                       i->first->get_selectables (start, end, botfrac, topfrac, results);
                }
        }
 }
@@ -734,25 +757,24 @@ AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double
 void
 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
 {
-       for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-               (*i)->get_inverted_selectables (sel, result);
+       for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+               i->first->get_inverted_selectables (sel, result);
        }
 }
 
 void
 AutomationTimeAxisView::set_selected_points (PointSelection& points)
 {
-       for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-               (*i)->set_selected_points (points);
+       for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+               i->first->set_selected_points (points);
        }
 }
 
 void
 AutomationTimeAxisView::clear_lines ()
 {
-       for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-               delete *i;
-       }
+       for (Lines::iterator i = lines.begin(); i != lines.end(); ++i)
+               delete i->first;
 
        lines.clear ();
        automation_connection.disconnect ();
@@ -765,33 +787,38 @@ AutomationTimeAxisView::add_line (AutomationLine& line)
 
        if (lines.empty()) {
                /* first line is the Model for automation state */
-               automation_connection = line.the_list().automation_state_changed.connect
+               automation_connection = line.the_list()->automation_state_changed.connect
                        (mem_fun(*this, &AutomationTimeAxisView::automation_state_changed));
                get = true;
        }
 
-       lines.push_back (&line);
+       lines.push_back (std::make_pair(&line,
+                       AutomationController::create(_session, line.the_list(),
+                               route->control(line.the_list()->param_id()))));
+
        line.set_y_position_and_height (0, height);
 
        if (get) {
                /* pick up the current state */
                automation_state_changed ();
        }
+
+       line.show();
 }
 
 void
 AutomationTimeAxisView::show_all_control_points ()
 {
-       for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-               (*i)->show_all_control_points ();
+       for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+               i->first->show_all_control_points ();
        }
 }
 
 void
 AutomationTimeAxisView::hide_all_but_selected_control_points ()
 {
-       for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
-               (*i)->hide_all_but_selected_control_points ();
+       for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
+               i->first->hide_all_but_selected_control_points ();
        }
 }
 
@@ -808,36 +835,23 @@ AutomationTimeAxisView::exited ()
 }
 
 void
-AutomationTimeAxisView::set_colors () {
-
-    for( list<GhostRegion *>::iterator i=ghosts.begin(); i != ghosts.end(); i++ ) {
-       (*i)->set_colors();
+AutomationTimeAxisView::set_colors ()
+{
+    for (list<GhostRegion*>::iterator i=ghosts.begin(); i != ghosts.end(); i++ ) {
+               (*i)->set_colors();
     }
     
-    for( vector<AutomationLine *>::iterator i=lines.begin(); i != lines.end(); i++ ) {
-       (*i)->set_colors();
+    for (Lines::iterator i=lines.begin(); i != lines.end(); i++ ) {
+               i->first->set_colors();
     }
-
 }
 
 void
 AutomationTimeAxisView::color_handler () 
 {
-    
-       //case cGhostTrackWave:
-       //case cGhostTrackWaveClip:
-       //case cGhostTrackZeroLine:
-
-       //case cControlPoint:
-       //case cControlPointFill:
-       //case cControlPointOutline:
-       //case cAutomationLine:
        set_colors ();
-
 }
 
-
-
 void
 AutomationTimeAxisView::set_state (const XMLNode& node)
 {
index e302e14ebb537bac60cd31bb50772e2b9361da06..b88c21d68dc6be3a6538611d999f652a0e361ad8 100644 (file)
@@ -23,6 +23,7 @@
 #include <vector>
 #include <list>
 #include <string>
+#include <utility>
 
 #include <boost/shared_ptr.hpp>
 
@@ -31,6 +32,7 @@
 #include "canvas.h"
 #include "time_axis_view.h"
 #include "simplerect.h"
+#include "automation_controller.h"
 
 using std::vector;
 using std::list;
@@ -50,6 +52,8 @@ class GhostRegion;
 class Selection;
 class Selectable;
 
+/** TODO: All the derived types of this can probably be merged into this cleanly.
+ */
 class AutomationTimeAxisView : public TimeAxisView {
   public:
        AutomationTimeAxisView (ARDOUR::Session&,
@@ -72,7 +76,8 @@ class AutomationTimeAxisView : public TimeAxisView {
        virtual void clear_lines ();
        virtual void add_line (AutomationLine&);
 
-       vector<AutomationLine*> lines;
+       typedef vector<std::pair<AutomationLine*,boost::shared_ptr<AutomationController> > > Lines;
+       Lines lines;
 
        void set_selected_points (PointSelection&);
        void get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable *>&);
@@ -102,6 +107,7 @@ class AutomationTimeAxisView : public TimeAxisView {
        string _name;
        string _state_name;
        bool    in_destructor;
+       bool    ignore_toggle;
 
        bool    first_call_to_set_height;
 
@@ -132,7 +138,7 @@ class AutomationTimeAxisView : public TimeAxisView {
        bool paste_one (AutomationLine&, nframes_t, float times, Selection&, size_t nth);
        void reset_objects_one (AutomationLine&, PointSelection&);
 
-       virtual void set_automation_state (ARDOUR::AutoState) = 0;
+       void set_automation_state (ARDOUR::AutoState);
        bool ignore_state_request;
 
        void automation_state_changed ();
index 61250c1289126010153f80a1969669c58326f7e5..520db57eb44bf36e3ba137c2f90f7b72e5fe466b 100644 (file)
@@ -1163,7 +1163,7 @@ Editor::connect_to_session (Session *t)
                        RouteTimeAxisView *rtv;
                        
                        if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
-                               if (rtv->route()->master()) {
+                               if (rtv->route()->is_master()) {
                                        route_list_display.get_selection()->unselect (i);
                                }
                        }
index f6f4d3bf0ba8340f84a744cf953f362f63f2f435..bcbb806b79eb944d988447db7d9e951d28b15915 100644 (file)
@@ -1676,7 +1676,7 @@ Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event)
 
        AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
 
-       drag_info.pointer_frame_offset = drag_info.grab_frame - ((nframes_t) arv->audio_region()->fade_in().back()->when + arv->region()->position());  
+       drag_info.pointer_frame_offset = drag_info.grab_frame - ((nframes_t) arv->audio_region()->fade_in()->back()->when + arv->region()->position()); 
 }
 
 void
@@ -1755,13 +1755,13 @@ Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* even
                        continue;
                }
        
-               AutomationList& alist = tmp->audio_region()->fade_in();
-               XMLNode &before = alist.get_state();
+               boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
+               XMLNode &before = alist->get_state();
 
                tmp->audio_region()->set_fade_in_length (fade_length);
                
-               XMLNode &after = alist.get_state();
-               session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
+               XMLNode &after = alist->get_state();
+               session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
        }
 
        commit_reversible_command ();
@@ -1783,7 +1783,7 @@ Editor::start_fade_out_grab (ArdourCanvas::Item* item, GdkEvent* event)
 
        AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
 
-       drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region()->length() - (nframes_t) arv->audio_region()->fade_out().back()->when + arv->region()->position());       
+       drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region()->length() - (nframes_t) arv->audio_region()->fade_out()->back()->when + arv->region()->position());      
 }
 
 void
@@ -1871,13 +1871,13 @@ Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* eve
                        continue;
                }
        
-               AutomationList& alist = tmp->audio_region()->fade_out();
-               XMLNode &before = alist.get_state();
+               boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
+               XMLNode &before = alist->get_state();
                
                tmp->audio_region()->set_fade_out_length (fade_length);
 
-               XMLNode &after = alist.get_state();
-               session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
+               XMLNode &after = alist->get_state();
+               session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
        }
 
        commit_reversible_command ();
index 843e0e3addbd279f5eeb42c739ce33b5023a82e3..ccfcdbd6c55e81cc276d1049edecfdcdc44bb8c1 100644 (file)
@@ -3392,11 +3392,11 @@ Editor::reset_region_gain_envelopes ()
        for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
                if (arv) {
-                       AutomationList& alist (arv->audio_region()->envelope());
-                       XMLNode& before (alist.get_state());
+                       boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
+                       XMLNode& before (alist->get_state());
 
                        arv->audio_region()->set_default_envelope ();
-                       session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
+                       session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
                }
        }
 
@@ -3485,13 +3485,13 @@ Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
                        return;
                }
 
-               AutomationList& alist = tmp->audio_region()->fade_in();
-               XMLNode &before = alist.get_state();
+               boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
+               XMLNode &before = alist->get_state();
 
                tmp->audio_region()->set_fade_in_shape (shape);
                
-               XMLNode &after = alist.get_state();
-               session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
+               XMLNode &after = alist->get_state();
+               session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
        }
 
        commit_reversible_command ();
@@ -3509,13 +3509,13 @@ Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
                        return;
                }
 
-               AutomationList& alist = tmp->audio_region()->fade_out();
-               XMLNode &before = alist.get_state();
+               boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
+               XMLNode &before = alist->get_state();
 
                tmp->audio_region()->set_fade_out_shape (shape);
                
-               XMLNode &after = alist.get_state();
-               session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
+               XMLNode &after = alist->get_state();
+               session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
        }
 
        commit_reversible_command ();
index 04ef8b46b07845c49efae61c51bc39754fa7cb76..e11738f65b3c0eae0cf5c126f0c300ec06f87917 100644 (file)
@@ -56,7 +56,7 @@ Editor::handle_new_route (Session::RouteList& routes)
        for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
                boost::shared_ptr<Route> route = (*x);
 
-               if (route->hidden()) {
+               if (route->is_hidden()) {
                        continue;
                }
                
index 2d73887d3a996f0e23c218d54346b521942aaf2b..2cf96fe02a8d1b20e53624f8ad4f400d43f1fd94 100644 (file)
@@ -1089,7 +1089,7 @@ ExportDialog::fill_lists ()
                
                boost::shared_ptr<Route> route = (*ri);
                
-               if (route->hidden()) {
+               if (route->is_hidden()) {
                        continue;
                }
 
index 509c941555dde530bfe9f4ed56901c607dc98556..0daec3b2502c167a79cb0d20a799712f6d638ae2 100644 (file)
@@ -33,12 +33,12 @@ using namespace Gtk;
 
 GainAutomationTimeAxisView::GainAutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r, 
                                                        PublicEditor& e, TimeAxisView& parent, 
-                                                       ArdourCanvas::Canvas& canvas, const string & n, ARDOUR::AutomationList& l)
+                                                       ArdourCanvas::Canvas& canvas, const string & n,
+                                                       boost::shared_ptr<ARDOUR::AutomationControl> c)
 
        : AxisView (s),
          AutomationTimeAxisView (s, r, e, parent, canvas, n, X_("gain"), ""),
-         list (l)
-       
+         _control (c)
 {
 }
 
@@ -59,20 +59,13 @@ GainAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkE
 
        /* map using line */
 
-       lines.front()->view_to_model_y (y);
+       lines.front().first->view_to_model_y (y);
 
        _session.begin_reversible_command (_("add gain automation event"));
-       XMLNode& before = list.get_state();
-       list.add (when, y);
-       XMLNode& after = list.get_state();
-       _session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(list, &before, &after));
+       XMLNode& before = _control->list()->get_state();
+       _control->list()->add (when, y);
+       XMLNode& after = _control->list()->get_state();
+       _session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->list(), &before, &after));
        _session.set_dirty ();
 }
 
-void
-GainAutomationTimeAxisView::set_automation_state (AutoState state)
-{
-       if (!ignore_state_request) {
-               route->set_parameter_automation_state (ParamID(GainAutomation), state);
-       }
-}
index 3f07be4ace4fc94b3825724523535bb276e73c08..f4132acb20b675f6feab2ac2238723d0ae35d555 100644 (file)
@@ -25,6 +25,7 @@
 
 namespace ARDOUR {
        class AutomationList;
+       class AutomationControl;
 }
 
 class GainAutomationTimeAxisView : public AutomationTimeAxisView
@@ -36,17 +37,16 @@ class GainAutomationTimeAxisView : public AutomationTimeAxisView
                                    TimeAxisView& parent_axis,
                                    ArdourCanvas::Canvas& canvas,
                                    const string & name,
-                                   ARDOUR::AutomationList&);
+                                       boost::shared_ptr<ARDOUR::AutomationControl> control);
        
        ~GainAutomationTimeAxisView();
 
        void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, nframes_t, double);
        
    private:
-       ARDOUR::AutomationList& list;
+       boost::shared_ptr<ARDOUR::AutomationControl> _control;
 
        void automation_changed ();
-       void set_automation_state (ARDOUR::AutoState);
 };
 
 #endif /* __ardour_gtk_gain_automation_time_axis_h__ */
index a4eea61bfa40b9cdf06ee06f85e2b9adc601e159..d3650667744997ca811f40b620c49649c972ba1b 100644 (file)
@@ -91,7 +91,7 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
 
        gain_slider = manage (new VSliderController (slider,
                                                     &gain_adjustment,
-                                                    _io->gain_control(),
+                                                    *_io->gain_control().get(),
                                                     false));
 
        gain_slider->signal_button_press_event().connect (mem_fun(*this, &GainMeter::start_gain_touch));
@@ -154,12 +154,12 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
 
        if ((r = dynamic_cast<Route*> (_io.get())) != 0) {
 
-               /* 
+               /* 
                   if we have a route (ie. we're not the click), 
                   pack some route-dependent stuff.
                */
 
-               gain_display_box.pack_end (peak_display, true, true);
+               gain_display_box.pack_end (peak_display, true, true);
 
                hbox.pack_end (meter_packer, true, true);
 
@@ -187,8 +187,8 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
                gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &GainMeter::gain_automation_style_button_event), false);
                gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeter::gain_automation_state_button_event), false);
                
-               r->gain_automation().automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed));
-               r->gain_automation().automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed));
+               r->gain_control()->list()->automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed));
+               r->gain_control()->list()->automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed));
                fader_vbox->pack_start (gain_automation_state_button, false, false, 0);
 
                gain_automation_state_changed ();
@@ -199,7 +199,7 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
        pack_start (gain_display_box, Gtk::PACK_SHRINK);
        pack_start (hbox, Gtk::PACK_SHRINK);
 
-       _io->gain_changed.connect (mem_fun(*this, &GainMeter::gain_changed));
+       _io->gain_control()->Changed.connect (mem_fun(*this, &GainMeter::gain_changed));
 
        meter_metric_area.signal_expose_event().connect (mem_fun(*this, &GainMeter::meter_metrics_expose));
        gain_adjustment.signal_value_changed().connect (mem_fun(*this, &GainMeter::gain_adjusted));
@@ -208,7 +208,7 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
 
        Config->ParameterChanged.connect (mem_fun (*this, &GainMeter::parameter_changed));
 
-       gain_changed (0);
+       gain_changed ();
        show_gain ();
 
        update_gain_sensitive ();
@@ -606,7 +606,7 @@ GainMeter::gain_activated ()
 
                f = min (f, 6.0f);
 
-               _io->set_gain (dB_to_coefficient(f), this);
+               _io->gain_control()->set_value (dB_to_coefficient(f));
 
                if (gain_display.has_focus()) {
                        PublicEditor::instance().reset_focus();
@@ -634,7 +634,7 @@ void
 GainMeter::gain_adjusted ()
 {
        if (!ignore_toggle) {
-               _io->set_gain (slider_position_to_gain (gain_adjustment.get_value()), this);
+               _io->gain_control()->set_value (slider_position_to_gain (gain_adjustment.get_value()));
        }
        show_gain ();
 }
@@ -652,7 +652,7 @@ GainMeter::effective_gain_display ()
 }
 
 void
-GainMeter::gain_changed (void *src)
+GainMeter::gain_changed ()
 {
        Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &GainMeter::effective_gain_display));
 }
@@ -672,7 +672,7 @@ GainMeter::set_fader_name (const char * name)
 void
 GainMeter::update_gain_sensitive ()
 {
-       static_cast<Gtkmm2ext::SliderController*>(gain_slider)->set_sensitive (!(_io->gain_automation().automation_state() & Play));
+       static_cast<Gtkmm2ext::SliderController*>(gain_slider)->set_sensitive (!(_io->gain_control()->list()->automation_state() & Play));
 }
 
 
@@ -815,14 +815,14 @@ GainMeter::meter_point_clicked ()
 gint
 GainMeter::start_gain_touch (GdkEventButton* ev)
 {
-       _io->gain_automation().start_touch ();
+       _io->gain_control()->list()->start_touch ();
        return FALSE;
 }
 
 gint
 GainMeter::end_gain_touch (GdkEventButton* ev)
 {
-       _io->gain_automation().stop_touch ();
+       _io->gain_control()->list()->stop_touch ();
        return FALSE;
 }
 
@@ -926,10 +926,10 @@ GainMeter::gain_automation_style_changed ()
   // Route* _route = dynamic_cast<Route*>(&_io);
        switch (_width) {
        case Wide:
-               gain_automation_style_button.set_label (astyle_string(_io->gain_automation().automation_style()));
+               gain_automation_style_button.set_label (astyle_string(_io->gain_control()->list()->automation_style()));
                break;
        case Narrow:
-               gain_automation_style_button.set_label  (short_astyle_string(_io->gain_automation().automation_style()));
+               gain_automation_style_button.set_label  (short_astyle_string(_io->gain_control()->list()->automation_style()));
                break;
        }
 }
@@ -944,14 +944,14 @@ GainMeter::gain_automation_state_changed ()
 
        switch (_width) {
        case Wide:
-               gain_automation_state_button.set_label (astate_string(_io->gain_automation().automation_state()));
+               gain_automation_state_button.set_label (astate_string(_io->gain_control()->list()->automation_state()));
                break;
        case Narrow:
-               gain_automation_state_button.set_label (short_astate_string(_io->gain_automation().automation_state()));
+               gain_automation_state_button.set_label (short_astate_string(_io->gain_control()->list()->automation_state()));
                break;
        }
 
-       x = (_io->gain_automation().automation_state() != Off);
+       x = (_io->gain_control()->list()->automation_state() != Off);
        
        if (gain_automation_state_button.get_active() != x) {
                ignore_toggle = true;
index 447271ed5538a723b1825fcd39264d6e203d0f84..3839221e7368fec67fb23e026c1523490c45d974 100644 (file)
@@ -149,7 +149,7 @@ class GainMeter : public Gtk::VBox
        Gtk::HBox   meter_packer;
 
        void gain_adjusted ();
-       void gain_changed (void *);
+       void gain_changed ();
        
        void meter_point_clicked ();
        void gain_unit_changed ();
index 721e50753ad1547f6a713d1302adfd45f3c3c676..eacc8f024b8a5b609d54bebd5a61537b0103d6f6 100644 (file)
@@ -496,7 +496,7 @@ LadspaPluginUI::build_control_ui (guint32 port_index, PBD::Controllable* mcontro
                automation_state_changed (control_ui);
 
                plugin->ParameterChanged.connect (bind (mem_fun(*this, &LadspaPluginUI::parameter_changed), control_ui));
-               insert->automation_list (ParamID(PluginAutomation, port_index))->automation_state_changed.connect 
+               insert->control (ParamID(PluginAutomation, port_index))->list()->automation_state_changed.connect 
                        (bind (mem_fun(*this, &LadspaPluginUI::automation_state_changed), control_ui));
 
        } else if (plugin->parameter_is_output (port_index)) {
@@ -553,13 +553,13 @@ LadspaPluginUI::build_control_ui (guint32 port_index, PBD::Controllable* mcontro
 void
 LadspaPluginUI::start_touch (LadspaPluginUI::ControlUI* cui)
 {
-       insert->automation_list (ParamID(PluginAutomation, cui->port_index))->start_touch ();
+       insert->control (ParamID(PluginAutomation, cui->port_index))->list()->start_touch ();
 }
 
 void
 LadspaPluginUI::stop_touch (LadspaPluginUI::ControlUI* cui)
 {
-       insert->automation_list (ParamID(PluginAutomation, cui->port_index))->stop_touch ();
+       insert->control (ParamID(PluginAutomation, cui->port_index))->list()->stop_touch ();
 }
 
 void
index a3dcb0f508523896454330b24492927c78831ed7..d25b5e398a762c04b045724c3e7f749ab4961afd 100644 (file)
@@ -20,6 +20,7 @@
 #include <ardour/automation_event.h>
 #include <ardour/route.h>
 #include <pbd/memento_command.h>
+#include <pbd/controllable.h>
 
 #include "midi_controller_time_axis.h"
 #include "automation_line.h"
@@ -34,12 +35,10 @@ using namespace Gtk;
 MidiControllerTimeAxisView::MidiControllerTimeAxisView (Session& s, boost::shared_ptr<Route> r, 
                                                        PublicEditor& e, TimeAxisView& parent, 
                                                        ArdourCanvas::Canvas& canvas, const string & n,
-                                                       ParamID param, ARDOUR::AutomationList& l)
-
+                                                       boost::shared_ptr<AutomationControl> c)
        : AxisView (s),
-         AutomationTimeAxisView (s, r, e, parent, canvas, n, param.to_string(), ""),
-         _list (l),
-         _param (param)
+         AutomationTimeAxisView (s, r, e, parent, canvas, n, c->list()->param_id().to_string(), ""),
+         _control (c)
 {
 }
 
@@ -60,22 +59,13 @@ MidiControllerTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkE
 
        /* map using line */
 
-       lines.front()->view_to_model_y (y);
+       lines.front().first->view_to_model_y (y);
 
        _session.begin_reversible_command (_("add midi controller automation event"));
-       XMLNode& before = _list.get_state();
-       _list.add (when, y);
-       XMLNode& after = _list.get_state();
-       _session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(_list, &before, &after));
+       XMLNode& before = _control->list()->get_state();
+       _control->list()->add (when, y);
+       XMLNode& after = _control->list()->get_state();
+       _session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->list().get(), &before, &after));
        _session.set_dirty ();
 }
 
-void
-MidiControllerTimeAxisView::set_automation_state (AutoState state)
-{
-       if (!ignore_state_request) {
-               cerr << "FIXME: set midi controller automation state" << endl;
-               //route->set_midi_controller_state (state);
-       }
-}
-
index 78f3c12c1a4b372c59fe42318cff976063bbf4c2..db14a77ca9c97bec9c49354c3a8118c4c25f07d5 100644 (file)
@@ -36,19 +36,16 @@ class MidiControllerTimeAxisView : public AutomationTimeAxisView
                                    TimeAxisView& parent_axis,
                                    ArdourCanvas::Canvas& canvas,
                                    const string & name,
-                                       ARDOUR::ParamID param,
-                                   ARDOUR::AutomationList&);
+                                       boost::shared_ptr<ARDOUR::AutomationControl> c);
        
        ~MidiControllerTimeAxisView();
 
        void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, nframes_t, double);
        
    private:
-       ARDOUR::AutomationList& _list;
-       ARDOUR::ParamID _param;
+       boost::shared_ptr<ARDOUR::AutomationControl> _control;
 
        void automation_changed ();
-       void set_automation_state (ARDOUR::AutoState);
 };
 
 #endif /* __ardour_gtk_midi_controller_time_axis_h__ */
index 52c9a29f1277ff491604ac578a3f55fb508959b6..8fe5823c782098fbc79ff0b10a0ee206543d59d4 100644 (file)
@@ -185,12 +185,13 @@ MidiTimeAxisView::create_automation_child (ParamID param)
        
                /* FIXME: this all probably leaks */
 
-               ARDOUR::AutomationList* al = _route->automation_list(param);
+               boost::shared_ptr<AutomationControl> c =_route->control(param);
 
-               if (!al)
-                       al = new ARDOUR::AutomationList(param, 0, 127, 64);
-
-               _route->add_automation_parameter(al);
+               if (!c) {
+                       boost::shared_ptr<AutomationList> al(new ARDOUR::AutomationList(param, 0, 127, 64));
+                       c = boost::shared_ptr<AutomationControl>(new AutomationControl(_session, al));
+                       _route->add_control(c);
+               }
 
                MidiControllerTimeAxisView* track = new MidiControllerTimeAxisView (_session,
                                _route,
@@ -198,13 +199,12 @@ MidiTimeAxisView::create_automation_child (ParamID param)
                                *this,
                                parent_canvas,
                                _route->describe_parameter(param),
-                               param,
-                               *al);
+                               c);
 
                AutomationMidiCCLine* line = new AutomationMidiCCLine (param.to_string(),
                                *track,
                                *track->canvas_display,
-                               *al);
+                               c->list());
 
                line->set_line_color (Config->canvasvar_AutomationLine.get());
 
index 40571d3e91f939ecd64dc4724c9d084fa1f1bfb4..54c396599371984a2ccc871c73c11df74046ab62 100644 (file)
@@ -261,7 +261,7 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
        global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
        global_vpacker.pack_start (comment_button, Gtk::PACK_SHRINK);
 
-       if (route()->master() || route()->control()) {
+       if (route()->is_master() || route()->is_control()) {
                
                if (scrollbar_height == 0) {
                        HScrollbar scrollbar;
@@ -403,6 +403,8 @@ MixerStrip::set_width (Width w, void* owner)
        pre_processor_box.set_width (w);
        post_processor_box.set_width (w);
 
+       boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->list();
+
        _width_owner = owner;
 
        if (_width == w) {
@@ -435,8 +437,8 @@ MixerStrip::set_width (Width w, void* owner)
                       ((Gtk::Label*)comment_button.get_child())->set_text (_("*comments*"));
                }
 
-               ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (gpm.astyle_string(_route->gain_automation().automation_style()));
-               ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (gpm.astate_string(_route->gain_automation().automation_state()));
+               ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (gpm.astyle_string(gain_automation->automation_style()));
+               ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (gpm.astate_string(gain_automation->automation_state()));
                ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (panners.astyle_string(_route->panner().automation_style()));
                ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (panners.astate_string(_route->panner().automation_state()));
                Gtkmm2ext::set_size_request_to_display_given_text (name_button, "long", 2, 2);
@@ -457,8 +459,8 @@ MixerStrip::set_width (Width w, void* owner)
                       ((Gtk::Label*)comment_button.get_child())->set_text (_("*Cmt*"));
                }
 
-               ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (gpm.short_astyle_string(_route->gain_automation().automation_style()));
-               ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (gpm.short_astate_string(_route->gain_automation().automation_state()));
+               ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (gpm.short_astyle_string(gain_automation->automation_style()));
+               ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (gpm.short_astate_string(gain_automation->automation_state()));
                ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (panners.short_astyle_string(_route->panner().automation_style()));
                ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (panners.short_astate_string(_route->panner().automation_state()));
                Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
@@ -699,8 +701,8 @@ MixerStrip::connect_to_pan ()
        if (!_route->panner().empty()) {
                StreamPanner* sp = _route->panner().front();
 
-               panstate_connection = sp->automation().automation_state_changed.connect (mem_fun(panners, &PannerUI::pan_automation_state_changed));
-               panstyle_connection = sp->automation().automation_style_changed.connect (mem_fun(panners, &PannerUI::pan_automation_style_changed));
+               panstate_connection = sp->automation()->automation_state_changed.connect (mem_fun(panners, &PannerUI::pan_automation_state_changed));
+               panstyle_connection = sp->automation()->automation_style_changed.connect (mem_fun(panners, &PannerUI::pan_automation_style_changed));
        }
 
        panners.pan_changed (this);
index 665420fdbdc9a762630bcad63860abeb51a17be0..11f9b6357d71d273fccbaf216c557152a8f17954 100644 (file)
@@ -267,7 +267,7 @@ Mixer_UI::add_strip (Session::RouteList& routes)
        for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
                boost::shared_ptr<Route> route = (*x);
 
-               if (route->hidden()) {
+               if (route->is_hidden()) {
                        return;
                }
                
@@ -473,7 +473,7 @@ Mixer_UI::set_all_strips_visibility (bool yn)
                        continue;
                }
                
-               if (strip->route()->master() || strip->route()->control()) {
+               if (strip->route()->is_master() || strip->route()->is_control()) {
                        continue;
                }
 
@@ -501,7 +501,7 @@ Mixer_UI::set_all_audio_visibility (int tracks, bool yn)
                        continue;
                }
 
-               if (strip->route()->master() || strip->route()->control()) {
+               if (strip->route()->is_master() || strip->route()->is_control()) {
                        continue;
                }
 
@@ -605,7 +605,7 @@ Mixer_UI::redisplay_track_list ()
 
                        if (strip->packed()) {
 
-                               if (strip->route()->master() || strip->route()->control()) {
+                               if (strip->route()->is_master() || strip->route()->is_control()) {
                                        out_packer.reorder_child (*strip, -1);
                                } else {
                                        strip_packer.reorder_child (*strip, -1); /* put at end */
@@ -613,7 +613,7 @@ Mixer_UI::redisplay_track_list ()
 
                        } else {
 
-                               if (strip->route()->master() || strip->route()->control()) {
+                               if (strip->route()->is_master() || strip->route()->is_control()) {
                                        out_packer.pack_start (*strip, false, false);
                                } else {
                                        strip_packer.pack_start (*strip, false, false);
@@ -624,7 +624,7 @@ Mixer_UI::redisplay_track_list ()
 
                } else {
 
-                       if (strip->route()->master() || strip->route()->control()) {
+                       if (strip->route()->is_master() || strip->route()->is_control()) {
                                /* do nothing, these cannot be hidden */
                        } else {
                                if (strip->packed()) {
@@ -702,7 +702,7 @@ Mixer_UI::track_display_button_press (GdkEventButton* ev)
                        MixerStrip* strip = (*iter)[track_columns.strip];
                        if (strip) {
 
-                               if (!strip->route()->master() && !strip->route()->control()) {
+                               if (!strip->route()->is_master() && !strip->route()->is_control()) {
                                        bool visible = (*iter)[track_columns.visible];
                                        (*iter)[track_columns.visible] = !visible;
                                }
index 1199982b5d3f9e49e1caecd0262026260dd33140..49eed5d2216bf7bc8011e8feacec7d129d3adfb5 100644 (file)
@@ -88,15 +88,15 @@ PanAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEv
 
        /* map using line */
 
-       lines.front()->view_to_model_y (y);
+       lines.front().first->view_to_model_y (y);
 
-       AutomationList& alist (lines[line_index]->the_list());
+       boost::shared_ptr<AutomationList> alist (lines[line_index].first->the_list());
 
        _session.begin_reversible_command (_("add pan automation event"));
-       XMLNode &before = alist.get_state();
-       alist.add (when, y);
-       XMLNode &after = alist.get_state();
-        _session.add_command(new MementoCommand<AutomationList>(alist, &before, &after));
+       XMLNode &before = alist->get_state();
+       alist->add (when, y);
+       XMLNode &after = alist->get_state();
+       _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
        _session.commit_reversible_command ();
        _session.set_dirty ();
 }
@@ -147,11 +147,3 @@ PanAutomationTimeAxisView::set_height (TimeAxisView::TrackHeight th)
                        multiline_selector.hide();
        }
 }
-
-void
-PanAutomationTimeAxisView::set_automation_state (AutoState state)
-{
-       if (!ignore_state_request) {
-               route->panner().set_automation_state (state);
-       }
-}
index d4a22ebc296f434884a768e01c42702029a4d1c5..fdffa875caf5356314d3e6c00d576a99984b3ab6 100644 (file)
@@ -52,7 +52,6 @@ class PanAutomationTimeAxisView : public AutomationTimeAxisView
 
        private:
                void automation_changed ();
-               void set_automation_state (ARDOUR::AutoState);
 };
 
 #endif /* __ardour_gtk_pan_automation_time_axis_h__ */
index 23fae953a16042e4aa8cefad8c453cf833250e18..2607cdf2b85e3ac3f346acd05aead4f04fd0594e 100644 (file)
@@ -34,8 +34,8 @@ null_label_callback (char* buf, unsigned int bufsize)
 }
 
 
-PannerBar::PannerBar (Gtk::Adjustment& adj, PBD::Controllable& c)
-       : BarController (adj, c, sigc::ptr_fun (null_label_callback))
+PannerBar::PannerBar (Gtk::Adjustment& adj, boost::shared_ptr<PBD::Controllable> c)
+       : BarController (adj, *c.get(), sigc::ptr_fun (null_label_callback))
 {
        set_style (BarController::Line);
 }
index 6813f3d0320b84853dd54dce17c159f475ebe46c..21f984aa7c023f223bc53e6cef64498e773114bb 100644 (file)
 #define __gtk_ardour_panner_h__
 
 #include <gtkmm2ext/barcontroller.h>
+#include <boost/shared_ptr.hpp>
 
 class PannerBar : public Gtkmm2ext::BarController
 {
   public:
-       PannerBar (Gtk::Adjustment& adj, PBD::Controllable&);
+       PannerBar (Gtk::Adjustment& adj, boost::shared_ptr<PBD::Controllable>);
        ~PannerBar ();
 
   protected:
index 42ccba992e2db2f1111685631faadaf7b4d48d33..0e12a418e7047c9bfa32e604dac6400ee20035d1 100644 (file)
@@ -573,9 +573,9 @@ PannerUI::update_pan_bars (bool only_if_aplay)
                float xpos, val;
 
                if (only_if_aplay) {
-                       AutomationList& alist (_io->panner()[n]->automation());
+                       boost::shared_ptr<AutomationList> alist (_io->panner()[n]->automation());
                        
-                       if (!alist.automation_playback()) {
+                       if (!alist->automation_playback()) {
                                continue;
                        }
                }
@@ -707,7 +707,7 @@ PannerUI::pan_automation_state_changed ()
                return;
        }
 
-       x = (_io->panner().front()->automation().automation_state() != Off);
+       x = (_io->panner().front()->automation()->automation_state() != Off);
 
        if (pan_automation_state_button.get_active() != x) {
        ignore_toggle = true;
index 8b83b736f07be881c385f1f811f842de272cfc7c..86eb7c7a7d189b9f21f34fb2bd65b34dde4acc70 100644 (file)
@@ -32,12 +32,11 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-ProcessorAutomationLine::ProcessorAutomationLine (const string & name, Processor& proc, ParamID param, 
-                                               TimeAxisView& tv, ArdourCanvas::Group& parent, AutomationList& l)
+ProcessorAutomationLine::ProcessorAutomationLine (const string & name, Processor& proc, 
+                                               TimeAxisView& tv, ArdourCanvas::Group& parent, boost::shared_ptr<AutomationList> l)
   
        : AutomationLine (name, tv, parent, l),
-       _processor(proc),
-       _param(param)
+       _processor(proc)
 {
        set_verbose_cursor_uses_gain_mapping (false);
 
@@ -49,7 +48,7 @@ ProcessorAutomationLine::ProcessorAutomationLine (const string & name, Processor
                /*NOTREACHED*/
        }
 
-       pi->plugin()->get_parameter_descriptor (_param, desc);
+       pi->plugin()->get_parameter_descriptor (l->param_id(), desc);
 
        _upper = desc.upper;
        _lower = desc.lower;
index 3a0a95786b774f553a247ada23aa078a4cb610c9..422f2b7f6f387c7981c5029899b77700557f2dc5 100644 (file)
@@ -33,17 +33,15 @@ class TimeAxisView;
 class ProcessorAutomationLine : public AutomationLine
 {
   public:
-       ProcessorAutomationLine (const string & name, ARDOUR::Processor&, ARDOUR::ParamID param,
-                       TimeAxisView&, ArdourCanvas::Group& parent, ARDOUR::AutomationList&);
+       ProcessorAutomationLine (const string & name, ARDOUR::Processor&,
+                       TimeAxisView&, ArdourCanvas::Group& parent, boost::shared_ptr<ARDOUR::AutomationList>);
        
-       ARDOUR::ParamID    param()     const { return _param; }
        ARDOUR::Processor& processor() const { return _processor; }
 
        string get_verbose_cursor_string (float);
 
   private:
        ARDOUR::Processor& _processor;
-       ARDOUR::ParamID    _param;
 
        float _upper;
        float _lower;
index 37c996d17e5da9127af152c4bd70e03cae671b0f..4940f1fc108f1c7e06fb507798c2ea7552a2314b 100644 (file)
@@ -91,11 +91,11 @@ ProcessorAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item,
        /* map to model space */
 
        if (!lines.empty()) {
-               AutomationList* alist (_processor.automation_list(_param, true));
+               boost::shared_ptr<AutomationList> alist (_processor.control(_param, true)->list());
                string description = _("add automation event to ");
                description += _processor.describe_parameter (_param);
 
-               lines.front()->view_to_model_y (y);
+               lines.front().first->view_to_model_y (y);
                
                _session.begin_reversible_command (description);
                XMLNode &before = alist->get_state();
@@ -168,7 +168,33 @@ void
 ProcessorAutomationTimeAxisView::set_automation_state (AutoState state)
 {
        if (!ignore_state_request) {
-               _processor.automation_list (_param, true)->set_automation_state (state);
+               _processor.control (_param, true)->list()->set_automation_state (state);
        }
 }
 
+void
+ProcessorAutomationTimeAxisView::add_line (AutomationLine& line)
+{
+       bool get = false;
+
+       if (lines.empty()) {
+               /* first line is the Model for automation state */
+               automation_connection = line.the_list()->automation_state_changed.connect
+                       (mem_fun(*this, &ProcessorAutomationTimeAxisView::automation_state_changed));
+               get = true;
+       }
+
+       lines.push_back (std::make_pair(&line,
+                       AutomationController::create(_session, line.the_list(),
+                               _processor.control(line.the_list()->param_id()))));
+
+       line.set_y_position_and_height (0, height);
+
+       if (get) {
+               /* pick up the current state */
+               automation_state_changed ();
+       }
+
+       line.show();
+}
+
index ec8caaf98f0e7786c21d0f853e855d1b120bdb34..980acdc441f00c8f0fe4b0fa50340a875f4251dd 100644 (file)
@@ -46,6 +46,7 @@ class ProcessorAutomationTimeAxisView : public AutomationTimeAxisView
        ~ProcessorAutomationTimeAxisView();
        
        void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, nframes_t, double);
+       void add_line (AutomationLine&);
 
        guint32 show_at (double y, int& nth, Gtk::VBox *parent);
        void hide ();
index 51257e18c0e20c4d198cdd08ece45c4387c5666a..756067e1e22660486c336b97712c3d43119e1f05 100644 (file)
@@ -347,7 +347,7 @@ ProcessorBox::processor_button_release_event (GdkEventButton *ev)
 Menu *
 ProcessorBox::build_processor_menu ()
 {
-       processor_menu = dynamic_cast<Gtk::Menu*>(ActionManager::get_widget("/redirectmenu") );
+       processor_menu = dynamic_cast<Gtk::Menu*>(ActionManager::get_widget("/processormenu") );
        processor_menu->set_name ("ArdourContextMenu");
 
        show_all_children();
@@ -1184,7 +1184,7 @@ ProcessorBox::enter_box (GdkEventCrossing *ev, ProcessorBox* rb)
 void
 ProcessorBox::register_actions ()
 {
-       Glib::RefPtr<Gtk::ActionGroup> popup_act_grp = Gtk::ActionGroup::create(X_("redirectmenu"));
+       Glib::RefPtr<Gtk::ActionGroup> popup_act_grp = Gtk::ActionGroup::create(X_("processormenu"));
        Glib::RefPtr<Action> act;
 
        /* new stuff */
index 25ba903ca8d2dba2c0f7fa53ba94b3235a410066..629981312131418fcbc78f979d734efc2534c34a 100644 (file)
@@ -38,7 +38,7 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-AudioRegionGainLine::AudioRegionGainLine (const string & name, Session& s, AudioRegionView& r, ArdourCanvas::Group& parent, AutomationList& l)
+AudioRegionGainLine::AudioRegionGainLine (const string & name, Session& s, AudioRegionView& r, ArdourCanvas::Group& parent, boost::shared_ptr<AutomationList> l)
   : AutomationLine (name, r.get_time_axis_view(), parent, l),
          session (s),
          rv (r)
@@ -67,8 +67,8 @@ AudioRegionGainLine::start_drag (ControlPoint* cp, nframes_t x, float fraction)
 {
        AutomationLine::start_drag (cp, x, fraction);
        if (!rv.audio_region()->envelope_active()) {
-                trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), &rv.audio_region()->get_state(), 0));
-                rv.audio_region()->set_envelope_active(false);
+               trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), &rv.audio_region()->get_state(), 0));
+               rv.audio_region()->set_envelope_active(false);
        } 
 }
 
@@ -81,18 +81,18 @@ AudioRegionGainLine::remove_point (ControlPoint& cp)
        model_representation (cp, mr);
 
        trackview.editor.current_session()->begin_reversible_command (_("remove control point"));
-        XMLNode &before = alist.get_state();
+       XMLNode &before = alist->get_state();
 
        if (!rv.audio_region()->envelope_active()) {
-                XMLNode &region_before = rv.audio_region()->get_state();
+               XMLNode &region_before = rv.audio_region()->get_state();
                rv.audio_region()->set_envelope_active(true);
-                XMLNode &region_after = rv.audio_region()->get_state();
-                trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), &region_before, &region_after));
+               XMLNode &region_after = rv.audio_region()->get_state();
+               trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), &region_before, &region_after));
        } 
        
-       alist.erase (mr.start, mr.end);
+       alist->erase (mr.start, mr.end);
 
-       trackview.editor.current_session()->add_command (new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
+       trackview.editor.current_session()->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
        trackview.editor.current_session()->commit_reversible_command ();
        trackview.editor.current_session()->set_dirty ();
 }
index 259615aa39fe8155b33b221a8adb1ae42f177a9a..fe03c0f76f9c66db6426c2175ba70bac43cc28e5 100644 (file)
@@ -35,7 +35,7 @@ class AudioRegionView;
 class AudioRegionGainLine : public AutomationLine
 {
   public:
-  AudioRegionGainLine (const string & name, ARDOUR::Session&, AudioRegionView&, ArdourCanvas::Group& parent, ARDOUR::AutomationList&);
+  AudioRegionGainLine (const string & name, ARDOUR::Session&, AudioRegionView&, ArdourCanvas::Group& parent, boost::shared_ptr<ARDOUR::AutomationList>);
        
        void view_to_model_y (double&);
        void model_to_view_y (double&);
index fb63ae8bd664f2e75d914da2dbc7323f9fec8cf1..cbddd098bb3abe80d584889638ccc7287da12dcb 100644 (file)
@@ -178,7 +178,7 @@ RouteParams_UI::add_routes (Session::RouteList& routes)
        for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
                boost::shared_ptr<Route> route = (*x);
 
-               if (route->hidden()) {
+               if (route->is_hidden()) {
                        return;
                }
                
index 3b89517fcecfd45453238db2c91e18133810dec6..dff66302131bf1edb74022b807a98346f8bdec67 100644 (file)
@@ -1570,7 +1570,7 @@ RouteTimeAxisView::show_existing_automation ()
        map<ARDOUR::ParamID, RouteAutomationNode*>::iterator i;
        for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
                // FIXME: only shown if /first/ line has points
-               if (!i->second->track->lines.empty() && i->second->track->lines[0]->npoints() > 0) {
+               if (!i->second->track->lines.empty() && i->second->track->lines[0].first->npoints() > 0) {
                        i->second->track->set_marked_for_display (true);
                        i->second->track->canvas_display->show();
                        i->second->track->get_state_node()->add_property ("shown", X_("yes"));
@@ -1714,14 +1714,16 @@ RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor>
 
        /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */
 
+       /* FIXME: ew */
+
        char state_name[256];
        snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id());
 
        ran->view = new ProcessorAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, name, what, *processor, state_name);
 
        ral = new ProcessorAutomationLine (name, 
-                                         *processor, what, *ran->view,
-                                         *ran->view->canvas_display, *processor->automation_list (what, true));
+                                         *processor, *ran->view, *ran->view->canvas_display,
+                                         processor->control (what, true)->list());
        
        ral->set_line_color (Config->canvasvar_ProcessorAutomationLine.get());
        ral->queue_reset ();
@@ -1974,7 +1976,7 @@ RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor>
 
        if ((ran = find_processor_automation_node (processor, what)) != 0) {
                if (ran->view) {
-                       return dynamic_cast<ProcessorAutomationLine*> (ran->view->lines.front());
+                       return dynamic_cast<ProcessorAutomationLine*> (ran->view->lines.front().first);
                } 
        }
 
index 95042af6ea62dffb113d0d7db500a95a84ad68d5..76c4b7b5b3ae12d03fc82c9498facb5229792d35 100644 (file)
@@ -80,10 +80,10 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co
 
        _route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed));
 
-       mute_button = manage (new BindableToggleButton (_route->mute_control(), m_name ));
+       mute_button = manage (new BindableToggleButton (*_route->mute_control().get(), m_name ));
        mute_button->set_self_managed (true);
 
-       solo_button = manage (new BindableToggleButton (_route->solo_control(), s_name ));
+       solo_button = manage (new BindableToggleButton (*_route->solo_control().get(), s_name ));
        solo_button->set_self_managed (true);
 
        mute_button->set_name ("MuteButton");
@@ -104,7 +104,7 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co
 
                _session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed));
 
-               rec_enable_button = manage (new BindableToggleButton (t->rec_enable_control(), r_name ));
+               rec_enable_button = manage (new BindableToggleButton (*t->rec_enable_control().get(), r_name ));
                rec_enable_button->set_name ("RecordEnableButton");
                rec_enable_button->set_self_managed (true);
 
index e47be6a54b0fc58f0e2481b76405deccab8cc810..c20b56f6f4c1d8f7ee384a80f6a5f2226b6bf588 100644 (file)
@@ -31,7 +31,6 @@
 #include <pbd/file_utils.h>
 
 #include <gtkmm2ext/utils.h>
-//#include <ardour/ardour.h>
 
 #include <ardour/filesystem_paths.h>
 
index dd76aadcba9715e54583367bd7fc805a80834147..f93c19649f791efa947b4c4c907c44d7a945db71 100644 (file)
@@ -77,6 +77,7 @@ gdither.cc
 globals.cc
 import.cc
 automatable.cc
+automation_control.cc
 processor.cc
 io_processor.cc
 plugin_insert.cc
index db763876b0dce727de6a7933ae61d5547d513e96..52a07679afdfb8db74e386da637761239fee1617 100644 (file)
@@ -67,9 +67,9 @@ class AudioRegion : public Region
        bool fade_in_active ()  const { return _flags & Region::FadeIn; }
        bool fade_out_active () const { return _flags & Region::FadeOut; }
 
-       AutomationList& fade_in()  { return _fade_in; }
-       AutomationList& fade_out() { return _fade_out; }
-       AutomationList& envelope() { return _envelope; }
+       boost::shared_ptr<AutomationList> fade_in()  { return _fade_in; }
+       boost::shared_ptr<AutomationList> fade_out() { return _fade_out; }
+       boost::shared_ptr<AutomationList> envelope() { return _envelope; }
 
        virtual nframes_t read_peaks (PeakData *buf, nframes_t npeaks,
                                      nframes_t offset, nframes_t cnt,
@@ -162,14 +162,14 @@ class AudioRegion : public Region
        void source_offset_changed ();
        void listen_to_my_curves ();
 
-       mutable AutomationList _fade_in;
-       FadeShape              _fade_in_shape;
-       mutable AutomationList _fade_out;
-       FadeShape              _fade_out_shape;
-       mutable AutomationList _envelope;
-       gain_t                 _scale_amplitude;
-       uint32_t               _fade_in_disabled;
-       uint32_t               _fade_out_disabled;
+       boost::shared_ptr<AutomationList> _fade_in;
+       FadeShape                         _fade_in_shape;
+       boost::shared_ptr<AutomationList> _fade_out;
+       FadeShape                         _fade_out_shape;
+       boost::shared_ptr<AutomationList> _envelope;
+       gain_t                            _scale_amplitude;
+       uint32_t                          _fade_in_disabled;
+       uint32_t                          _fade_out_disabled;
 
   protected:
        /* default constructor for derived (compound) types */
index f6d6d86ed065936c9231669775c208ba4b7f2efa..a1161db80d35de2c1110b1f970c69091cd008295 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2000,2007 Paul Davis 
+    Copyright (C) 2000, 2007 Paul Davis 
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 
 #include <set>
 #include <map>
+#include <boost/shared_ptr.hpp>
 #include <ardour/session_object.h>
 #include <ardour/automation_event.h>
+#include <ardour/automation_control.h>
 #include <ardour/param_id.h>
 
 namespace ARDOUR {
 
 class Session;
+class AutomationControl;
 
 class Automatable : public SessionObject
 {
@@ -38,16 +41,17 @@ public:
        virtual ~Automatable() {}
 
        // shorthand for gain, pan, etc
-       inline AutomationList* automation_list(AutomationType type, bool create_if_missing=false) {
-               return automation_list(ParamID(type), create_if_missing);
+       inline boost::shared_ptr<AutomationControl>
+       control(AutomationType type, bool create_if_missing=false) {
+               return control(ParamID(type), create_if_missing);
        }
 
-       virtual AutomationList* automation_list(ParamID id, bool create_if_missing=false);
-       virtual const AutomationList* automation_list(ParamID id) const;
+       virtual boost::shared_ptr<AutomationControl> control(ParamID id, bool create_if_missing=false);
+       virtual boost::shared_ptr<const AutomationControl> control(ParamID id) const;
 
-       virtual void add_automation_parameter(AutomationList* al);
+       virtual void add_control(boost::shared_ptr<AutomationControl>);
 
-       virtual void automation_snapshot(nframes_t now) {};
+       virtual void automation_snapshot(nframes_t now);
 
        virtual bool find_next_event(nframes_t start, nframes_t end, ControlEvent& ev) const;
        
@@ -74,7 +78,7 @@ protected:
 
        void can_automate(ParamID);
 
-       virtual void automation_list_creation_callback(ParamID, AutomationList&) {}
+       virtual void auto_state_changed (ParamID which) {}
 
        int set_automation_state(const XMLNode&, ParamID default_param);
        XMLNode& get_automation_state();
@@ -83,9 +87,11 @@ protected:
        int old_set_automation_state(const XMLNode&);
 
        mutable Glib::Mutex _automation_lock;
-
-       std::map<ParamID,AutomationList*> _parameter_automation;
-       std::set<ParamID> _visible_parameter_automation;
+       
+       typedef std::map<ParamID,boost::shared_ptr<AutomationControl> > Controls;
+       
+       Controls          _controls;
+       std::set<ParamID> _visible_controls;
        std::set<ParamID> _can_automate_list;
        
        nframes_t _last_automation_snapshot;
diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h
new file mode 100644 (file)
index 0000000..d9e7a23
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+    Copyright (C) 2007 Paul Davis
+       Author: Dave Robillard
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_automation_control_h__
+#define __ardour_automation_control_h__
+
+#include <boost/shared_ptr.hpp>
+#include <pbd/controllable.h>
+
+namespace ARDOUR {
+
+class AutomationList;
+class Session;
+
+
+/** A PBD:Controllable with associated automation data (AutomationList)
+ */
+class AutomationControl : public PBD::Controllable
+{
+public:
+       AutomationControl(ARDOUR::Session&, boost::shared_ptr<ARDOUR::AutomationList>,
+                       std::string name="unnamed controllable");
+
+       void set_value(float val);
+       float get_value() const;
+       float user_value() const;
+
+       void set_list(boost::shared_ptr<ARDOUR::AutomationList>);
+
+       boost::shared_ptr<ARDOUR::AutomationList>       list()       { return _list; }
+       boost::shared_ptr<const ARDOUR::AutomationList> list() const { return _list; }
+
+protected:
+       ARDOUR::Session&                          _session;
+       boost::shared_ptr<ARDOUR::AutomationList> _list;
+       float                                     _user_value;
+};
+
+
+} // namespace ARDOUR
+
+#endif /* __ardour_automation_control_h__ */
index fc49f0699fa10f17987e7e8753ebc8a2315c341d..60e1fc25f1be89e05ea19551845a92ac19ee2cbe 100644 (file)
@@ -42,6 +42,7 @@
 #include <ardour/port_set.h>
 #include <ardour/chan_count.h>
 #include <ardour/latent.h>
+#include <ardour/automation_control.h>
 
 using std::string;
 using std::vector;
@@ -60,6 +61,7 @@ class AudioPort;
 class MidiPort;
 class BufferSet;
 
+
 /** A collection of input and output ports with connections.
  *
  * An IO can contain ports of varying types, making routes/inserts/etc with
@@ -103,8 +105,6 @@ class IO : public Automatable, public Latent
        void just_meter_input (nframes_t start_frame, nframes_t end_frame, 
                               nframes_t nframes, nframes_t offset);
 
-       virtual void   set_gain (gain_t g, void *src);
-       void           inc_gain (gain_t delta, void *src);
        gain_t         gain () const { return _desired_gain; }
        virtual gain_t effective_gain () const;
        
@@ -182,8 +182,6 @@ class IO : public Automatable, public Latent
        sigc::signal<void,IOChange,void*> input_changed;
        sigc::signal<void,IOChange,void*> output_changed;
 
-       sigc::signal<void,void*> gain_changed;
-
        virtual XMLNode& state (bool full);
        XMLNode& get_state (void);
        int set_state (const XMLNode&);
@@ -206,10 +204,6 @@ class IO : public Automatable, public Latent
        static sigc::signal<void,ChanCount> MoreChannels;
        static sigc::signal<int>            PortsCreated;
 
-       PBD::Controllable& gain_control() {
-               return _gain_control;
-       }
-       
     static void update_meters();
 
   private: 
@@ -221,13 +215,24 @@ class IO : public Automatable, public Latent
   public:
 
        /* automation */
+       
+       struct GainControl : public AutomationControl {
+           GainControl (std::string name, IO& i, boost::shared_ptr<AutomationList> al)
+                       : AutomationControl (i._session, al, name)
+                       , _io (i)
+               {}
+        
+           void set_value (float val);
+           float get_value (void) const;
+   
+           IO& _io;
+       };
 
-       static void set_automation_interval (nframes_t frames) {
-               _automation_interval = frames;
+       boost::shared_ptr<GainControl> gain_control() {
+               return _gain_control;
        }
-
-       static nframes_t automation_interval() { 
-               return _automation_interval;
+       boost::shared_ptr<const GainControl> gain_control() const {
+               return _gain_control;
        }
 
        void clear_automation ();
@@ -237,10 +242,6 @@ class IO : public Automatable, public Latent
        virtual void transport_stopped (nframes_t now); // interface: matches Insert
        void automation_snapshot (nframes_t now); // interface: matches Automatable
 
-       // FIXME: these will probably become unsafe in the near future
-       ARDOUR::AutomationList&       gain_automation()       { return *automation_list(GainAutomation); }
-       const ARDOUR::AutomationList& gain_automation() const { return *automation_list(GainAutomation); }
-
        void start_pan_touch (uint32_t which);
        void end_pan_touch (uint32_t which);
 
@@ -282,25 +283,12 @@ class IO : public Automatable, public Latent
        virtual uint32_t pans_required() const
                { return _inputs.count().n_audio(); }
 
-       struct GainControllable : public PBD::Controllable {
-           GainControllable (std::string name, IO& i) : Controllable (name), io (i) {}
-        
-           void set_value (float val);
-           float get_value (void) const;
-   
-           IO& io;
-       };
-
-       GainControllable _gain_control;
+       boost::shared_ptr<GainControl> _gain_control;
 
-       nframes_t last_automation_snapshot;
-       static nframes_t _automation_interval;
-
-       /*AutoState      _gain_automation_state;
-       AutoStyle      _gain_automation_style;*/
+       virtual void   set_gain (gain_t g, void *src);
+       void           inc_gain (gain_t delta, void *src);
 
        bool apply_gain_automation;
-       //Curve     _gain_automation_curve;
        
        virtual int load_automation (std::string path);
 
index af3cda94e2647b2b582849bd04ec2ee80d4f3a71..89f56e03c554b37c9e2f7e4720412155b29ff19b 100644 (file)
@@ -76,14 +76,14 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful
        virtual void set_automation_state (AutoState) = 0;
        virtual void set_automation_style (AutoStyle) = 0;
        
-       PBD::Controllable& control()  { return _control; }
+       boost::shared_ptr<PBD::Controllable> control()  { return _control; }
        
        /* XXX this is wrong. for multi-dimensional panners, there
           must surely be more than 1 automation curve.
        */
        /* TODO: Panner is-a Automation solves this */
 
-       virtual AutomationList& automation() = 0;
+       virtual boost::shared_ptr<AutomationList> automation() = 0;
 
        sigc::signal<void> Changed;      /* for position */
        sigc::signal<void> StateChanged; /* for mute */
@@ -125,7 +125,7 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful
            bool can_send_feedback() const;
        };
 
-       PanControllable  _control;
+       boost::shared_ptr<PanControllable> _control;
 
        void add_state (XMLNode&);
        virtual void update () = 0;
@@ -151,7 +151,7 @@ class BaseStereoPanner : public StreamPanner
        void set_automation_style (AutoStyle);
 
        /* TODO: StreamPanner is-a Automatable? */
-       AutomationList& automation() { return _automation; }
+       boost::shared_ptr<AutomationList> automation() { return _automation; }
 
        /* old school automation loading */
 
@@ -165,7 +165,7 @@ class BaseStereoPanner : public StreamPanner
        float left_interp;
        float right_interp;
 
-       AutomationList _automation;
+       boost::shared_ptr<AutomationList> _automation;
 };
 
 class EqualPowerStereoPanner : public BaseStereoPanner
@@ -208,7 +208,7 @@ class Multi2dPanner : public StreamPanner
        
        /* TODO: StreamPanner is-a Automatable? */
 
-       AutomationList& automation() { return _automation; }
+       boost::shared_ptr<AutomationList> automation() { return _automation; }
 
        void distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes);
        void distribute_automated (AudioBuffer& src, BufferSet& obufs,
@@ -226,7 +226,7 @@ class Multi2dPanner : public StreamPanner
        int load (istream&, string path, uint32_t&);
 
   private:
-       AutomationList _automation;
+       boost::shared_ptr<AutomationList> _automation;
        void update ();
 };
 
index e3b1b62b199a39fc946da467d67c941dcddf7cc9..90c83057df47ab9ce9a3c8ebbdf2c21b235b9908 100644 (file)
@@ -109,7 +109,6 @@ class PluginInsert : public Processor
        void init ();
        void set_automatable ();
        void auto_state_changed (ParamID which);
-       void automation_list_creation_callback (ParamID, AutomationList&);
 
        int32_t count_for_configuration (ChanCount in, ChanCount out) const;
 
index 3985306d0109f7ba577ef0b0f0e8b290123d9038..371572610a9c24b45837905b39001867649c247d 100644 (file)
@@ -80,7 +80,7 @@ class Processor : public Automatable, public Latent
        
        virtual bool configure_io (ChanCount in, ChanCount out) { _configured_input = in; return (_configured = true); }
 
-       /* Act as a pass through, if not overridden */
+       /* Derived classes should override these, or processor appears as a pass-through */
        virtual bool      can_support_input_configuration (ChanCount in) const { return true; }
        virtual ChanCount output_for_input_configuration (ChanCount in) const { return in; }
        virtual ChanCount output_streams() const { return _configured_input; }
index b8c9431e4276d36df8ebc545e332ffee7b630bab..1fd6eff0f8917e34c4a04ba00691e57de2ce6f6e 100644 (file)
@@ -81,9 +81,9 @@ class Route : public IO
        long order_key (const char* name) const;
        void set_order_key (const char* name, long n);
 
-       bool hidden() const { return _flags & Hidden; }
-       bool master() const { return _flags & MasterOut; }
-       bool control() const { return _flags & ControlOut; }
+       bool is_hidden() const { return _flags & Hidden; }
+       bool is_master() const { return _flags & MasterOut; }
+       bool is_control() const { return _flags & ControlOut; }
 
        /* these are the core of the API of a Route. see the protected sections as well */
 
@@ -243,11 +243,11 @@ class Route : public IO
            ToggleType type;
        };
 
-       PBD::Controllable& solo_control() {
+       boost::shared_ptr<PBD::Controllable> solo_control() {
                return _solo_control;
        }
 
-       PBD::Controllable& mute_control() {
+       boost::shared_ptr<PBD::Controllable> mute_control() {
                return _mute_control;
        }
        
@@ -306,8 +306,8 @@ class Route : public IO
        std::string         _comment;
        bool                _have_internal_generator;
 
-       ToggleControllable _solo_control;
-       ToggleControllable _mute_control;
+       boost::shared_ptr<ToggleControllable> _solo_control;
+       boost::shared_ptr<ToggleControllable> _mute_control;
        
        nframes_t check_initial_delay (nframes_t, nframes_t&, nframes_t&);
        
index 3a4a21cb8ae103d472c61177360748f517b1ded3..2c4c60a9119cf22d805c66fce79fd0936b4d816c 100644 (file)
@@ -649,9 +649,11 @@ class Session : public PBD::StatefulDestructible
        sigc::signal<void> NamedSelectionAdded;
        sigc::signal<void> NamedSelectionRemoved;
 
-        /* Curves and AutomationLists (TODO when they go away) */
-        void add_curve(Curve*);
-        void add_automation_list(AutomationList*);
+       /* Curves and AutomationLists (TODO when they go away) */
+       void add_curve(Curve*);
+       void add_automation_list(AutomationList*);
+       
+       nframes_t automation_interval () const { return _automation_interval; }
 
        /* fade curves */
 
@@ -780,9 +782,9 @@ class Session : public PBD::StatefulDestructible
 
        std::map<PBD::ID, PBD::StatefulThingWithGoingAway*> registry;
 
-        // these commands are implemented in libs/ardour/session_command.cc
+       // these commands are implemented in libs/ardour/session_command.cc
        Command* memento_command_factory(XMLNode* n);
-        void register_with_memento_command_factory(PBD::ID, PBD::StatefulThingWithGoingAway*);
+       void register_with_memento_command_factory(PBD::ID, PBD::StatefulThingWithGoingAway*);
 
        Command* global_state_command_factory (const XMLNode& n);
 
@@ -917,9 +919,9 @@ class Session : public PBD::StatefulDestructible
 
        /* Controllables */
 
-       PBD::Controllable* controllable_by_id (const PBD::ID&);
+       boost::shared_ptr<PBD::Controllable> controllable_by_id (const PBD::ID&);
 
-       void add_controllable (PBD::Controllable*);
+       void add_controllable (boost::shared_ptr<PBD::Controllable>);
        void remove_controllable (PBD::Controllable*);
 
   protected:
@@ -1648,6 +1650,8 @@ class Session : public PBD::StatefulDestructible
        void allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, bool force);
        uint32_t _npan_buffers;
 
+       nframes_t _automation_interval;
+
        /* VST support */
 
        long _vst_callback (VSTPlugin*,
@@ -1672,7 +1676,7 @@ class Session : public PBD::StatefulDestructible
        LayerModel layer_model;
        CrossfadeModel xfade_model;
 
-       typedef std::set<PBD::Controllable*> Controllables;
+       typedef std::set<boost::shared_ptr<PBD::Controllable> > Controllables;
        Glib::Mutex controllables_lock;
        Controllables controllables;
 
index 06ce39889642b70ee7e64ca2bcf53d2442dbbaeb..4d5545c0dc4c935a501007c9e866a994e559c899 100644 (file)
@@ -83,7 +83,7 @@ class Track : public Route
        XMLNode&    get_template();
        virtual int set_state(const XMLNode& node) = 0;
 
-       PBD::Controllable& rec_enable_control() { return _rec_enable_control; }
+       boost::shared_ptr<PBD::Controllable> rec_enable_control() { return _rec_enable_control; }
 
        bool record_enabled() const;
        void set_record_enable (bool yn, void *src);
@@ -141,8 +141,9 @@ class Track : public Route
        XMLNode*              pending_state;
        sigc::connection      recenable_connection;
        sigc::connection      ic_connection;
-       RecEnableControllable _rec_enable_control;
        bool                  _destructive;
+       
+       boost::shared_ptr<RecEnableControllable> _rec_enable_control;
 };
 
 }; /* namespace ARDOUR*/
index 9f13aee465c8ba2d9e24d29474291a37c10ae972..4df8ffea492b5f8c365231686e8a2b14528ad57d 100644 (file)
@@ -278,8 +278,8 @@ AudioTrack::_set_state (const XMLNode& node, bool call_base)
                child = *niter;
 
                if (child->name() == X_("recenable")) {
-                       _rec_enable_control.set_state (*child);
-                       _session.add_controllable (&_rec_enable_control);
+                       _rec_enable_control->set_state (*child);
+                       _session.add_controllable (_rec_enable_control);
                }
        }
 
@@ -334,7 +334,7 @@ AudioTrack::state(bool full_state)
        _diskstream->id().print (buf, sizeof (buf));
        root.add_property ("diskstream-id", buf);
 
-       root.add_child_nocopy (_rec_enable_control.get_state());
+       root.add_child_nocopy (_rec_enable_control->get_state());
 
        return root;
 }
@@ -601,8 +601,8 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
                if (!diskstream->record_enabled() && _session.transport_rolling()) {
                        Glib::Mutex::Lock am (_automation_lock, Glib::TRY_LOCK);
                        
-                       if (am.locked() && gain_automation().automation_playback()) {
-                               apply_gain_automation = gain_automation().curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
+                       if (am.locked() && gain_control()->list()->automation_playback()) {
+                               apply_gain_automation = gain_control()->list()->curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
                        }
                }
 
@@ -696,9 +696,9 @@ AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes
                }
        }
        
-       if (IO::gain_automation().automation_state() == Play) {
+       if (gain_control()->list()->automation_state() == Play) {
                
-               IO::gain_automation().curve().get_vector (start, start + nframes, gain_automation, nframes);
+               gain_control()->list()->curve().get_vector (start, start + nframes, gain_automation, nframes);
 
                for (BufferSet::audio_iterator bi = buffers.audio_begin(); bi != buffers.audio_end(); ++bi) {
                        Sample *b = bi->data();
index a7a5fca9127c8e4e7b77646d08979d787f45daa6..359c729368e25131a145468225e7e348570d9377 100644 (file)
@@ -72,20 +72,20 @@ AudioRegion::init ()
 
 /* constructor for use by derived types only */
 AudioRegion::AudioRegion (nframes_t start, nframes_t length, string name)
-       : Region (start, length, name, DataType::AUDIO),
-         _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0),
-         _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0),
-         _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
+       : Region (start, length, name, DataType::AUDIO)
+       , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
+       , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
+       , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
 {
        init ();
 }
 
 /** Basic AudioRegion constructor (one channel) */
 AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length)
-       : Region (src, start, length, PBD::basename_nosuffix(src->name()), DataType::AUDIO, 0,  Region::Flag(Region::DefaultFlags|Region::External)),
-         _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0),
-         _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0),
-         _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
+       : Region (src, start, length, PBD::basename_nosuffix(src->name()), DataType::AUDIO, 0,  Region::Flag(Region::DefaultFlags|Region::External))
+       , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
+       , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
+       , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
 {
        boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
        if (afs) {
@@ -98,9 +98,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
 /* Basic AudioRegion constructor (one channel) */
 AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
        : Region (src, start, length, name, DataType::AUDIO, layer, flags)
-       , _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0)
-       , _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)
-       , _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
+       , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
+       , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
+       , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
 {
        boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
        if (afs) {
@@ -113,9 +113,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
 /* Basic AudioRegion constructor (many channels) */
 AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
        : Region (srcs, start, length, name, DataType::AUDIO, layer, flags)
-       , _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0)
-       , _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)
-       , _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
+       , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
+       , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
+       , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
 {
        init ();
 }
@@ -123,10 +123,10 @@ AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, c
 
 /** Create a new AudioRegion, that is part of an existing one */
 AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
-       : Region (other, offset, length, name, layer, flags),
-         _fade_in (other->_fade_in),
-         _fade_out (other->_fade_out),
-         _envelope (other->_envelope, (double) offset, (double) offset + length) 
+       : Region (other, offset, length, name, layer, flags)
+       , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
+       , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
+       , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
 {
        /* return to default fades if the existing ones are too long */
        _fade_in_disabled = 0;
@@ -134,7 +134,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
 
 
        if (_flags & LeftOfSplit) {
-               if (_fade_in.back()->when >= _length) {
+               if (_fade_in->back()->when >= _length) {
                        set_default_fade_in ();
                } else {
                        _fade_in_disabled = other->_fade_in_disabled;
@@ -144,7 +144,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
        }
 
        if (_flags & RightOfSplit) {
-               if (_fade_out.back()->when >= _length) {
+               if (_fade_out->back()->when >= _length) {
                        set_default_fade_out ();
                } else {
                        _fade_out_disabled = other->_fade_out_disabled;
@@ -161,10 +161,10 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
 }
 
 AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
-       : Region (other),
-         _fade_in (other->_fade_in),
-         _fade_out (other->_fade_out),
-         _envelope (other->_envelope) 
+       : Region (other)
+       , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
+       , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
+       , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
 {
        _scale_amplitude = other->_scale_amplitude;
        _envelope = other->_envelope;
@@ -179,9 +179,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
 
 AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node)
        : Region (src, node)
-       , _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0)
-       , _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)
-       , _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
+       , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
+       , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
+       , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
 {
        boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
        if (afs) {
@@ -201,9 +201,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
 
 AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
        : Region (srcs, node)
-       , _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0)
-       , _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)
-       , _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
+       , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
+       , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
+       , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
 {
        set_default_fades ();
        _scale_amplitude = 1.0;
@@ -224,9 +224,9 @@ AudioRegion::~AudioRegion ()
 void
 AudioRegion::listen_to_my_curves ()
 {
-       _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
-       _fade_in.StateChanged.connect (mem_fun (*this, &AudioRegion::fade_in_changed));
-       _fade_out.StateChanged.connect (mem_fun (*this, &AudioRegion::fade_out_changed));
+       _envelope->StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+       _fade_in->StateChanged.connect (mem_fun (*this, &AudioRegion::fade_in_changed));
+       _fade_out->StateChanged.connect (mem_fun (*this, &AudioRegion::fade_out_changed));
 }
 
 bool
@@ -395,7 +395,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
 
        if (_flags & FadeIn) {
 
-               nframes_t fade_in_length = (nframes_t) _fade_in.back()->when;
+               nframes_t fade_in_length = (nframes_t) _fade_in->back()->when;
                
                /* see if this read is within the fade in */
 
@@ -405,7 +405,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
 
                        limit = min (to_read, fade_in_length - internal_offset);
 
-                       _fade_in.curve().get_vector (internal_offset, internal_offset+limit, gain_buffer, limit);
+                       _fade_in->curve().get_vector (internal_offset, internal_offset+limit, gain_buffer, limit);
 
                        for (nframes_t n = 0; n < limit; ++n) {
                                mixdown_buffer[n] *= gain_buffer[n];
@@ -436,7 +436,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
                */
 
        
-               nframes_t fade_out_length = (nframes_t) _fade_out.back()->when;
+               nframes_t fade_out_length = (nframes_t) _fade_out->back()->when;
                nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length);
                nframes_t fade_interval_end   = min(internal_offset + to_read, _length);
 
@@ -447,7 +447,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
                        nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
                        nframes_t fade_offset = fade_interval_start - internal_offset;
                                                                       
-                       _fade_out.curve().get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
+                       _fade_out->curve().get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
 
                        for (nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
                                mixdown_buffer[m] *= gain_buffer[n];
@@ -459,7 +459,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
        /* Regular gain curves */
 
        if (envelope_active())  {
-               _envelope.curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
+               _envelope->curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
                
                if (_scale_amplitude != 1.0f) {
                        for (nframes_t n = 0; n < to_read; ++n) {
@@ -521,7 +521,7 @@ AudioRegion::state (bool full)
                if ((_flags & DefaultFadeIn)) {
                        child->add_property (X_("default"), X_("yes"));
                } else {
-                       child->add_child_nocopy (_fade_in.get_state ());
+                       child->add_child_nocopy (_fade_in->get_state ());
                }
 
                child->add_property (X_("active"), _fade_in_disabled ? X_("no") : X_("yes"));
@@ -531,7 +531,7 @@ AudioRegion::state (bool full)
                if ((_flags & DefaultFadeOut)) {
                        child->add_property (X_("default"), X_("yes"));
                } else {
-                       child->add_child_nocopy (_fade_out.get_state ());
+                       child->add_child_nocopy (_fade_out->get_state ());
                }
                
                child->add_property (X_("active"), _fade_out_disabled ? X_("no") : X_("yes"));
@@ -545,10 +545,10 @@ AudioRegion::state (bool full)
                // If there are only two points, the points are in the start of the region and the end of the region
                // so, if they are both at 1.0f, that means the default region.
 
-               if (_envelope.size() == 2 &&
-                   _envelope.front()->value == 1.0f &&
-                   _envelope.back()->value==1.0f) {
-                       if (_envelope.front()->when == 0 && _envelope.back()->when == _length) {
+               if (_envelope->size() == 2 &&
+                   _envelope->front()->value == 1.0f &&
+                   _envelope->back()->value==1.0f) {
+                       if (_envelope->front()->when == 0 && _envelope->back()->when == _length) {
                                default_env = true;
                        }
                } 
@@ -556,7 +556,7 @@ AudioRegion::state (bool full)
                if (default_env) {
                        child->add_property ("default", "yes");
                } else {
-                       child->add_child_nocopy (_envelope.get_state ());
+                       child->add_child_nocopy (_envelope->get_state ());
                }
 
        } else {
@@ -617,28 +617,28 @@ AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool sen
                
                if (child->name() == "Envelope") {
                        
-                       _envelope.clear ();
+                       _envelope->clear ();
 
-                       if ((prop = child->property ("default")) != 0 || _envelope.set_state (*child)) {
+                       if ((prop = child->property ("default")) != 0 || _envelope->set_state (*child)) {
                                set_default_envelope ();
                        }
 
-                       _envelope.set_max_xval (_length);
-                       _envelope.truncate_end (_length);
+                       _envelope->set_max_xval (_length);
+                       _envelope->truncate_end (_length);
 
                } else if (child->name() == "FadeIn") {
                        
-                       _fade_in.clear ();
+                       _fade_in->clear ();
                        
-                       if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_in.set_state (*child)) {
+                       if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_in->set_state (*child)) {
                                set_default_fade_in ();
                        } 
 
                } else if (child->name() == "FadeOut") {
                        
-                       _fade_out.clear ();
+                       _fade_out->clear ();
 
-                       if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_out.set_state (*child)) {
+                       if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_out->set_state (*child)) {
                                set_default_fade_out ();
                        } 
                } 
@@ -665,70 +665,70 @@ AudioRegion::set_state (const XMLNode& node)
 void
 AudioRegion::set_fade_in_shape (FadeShape shape)
 {
-       set_fade_in (shape, (nframes_t) _fade_in.back()->when);
+       set_fade_in (shape, (nframes_t) _fade_in->back()->when);
 }
 
 void
 AudioRegion::set_fade_out_shape (FadeShape shape)
 {
-       set_fade_out (shape, (nframes_t) _fade_out.back()->when);
+       set_fade_out (shape, (nframes_t) _fade_out->back()->when);
 }
 
 void
 AudioRegion::set_fade_in (FadeShape shape, nframes_t len)
 {
-       _fade_in.freeze ();
-       _fade_in.clear ();
+       _fade_in->freeze ();
+       _fade_in->clear ();
 
        switch (shape) {
        case Linear:
-               _fade_in.fast_simple_add (0.0, 0.0);
-               _fade_in.fast_simple_add (len, 1.0);
+               _fade_in->fast_simple_add (0.0, 0.0);
+               _fade_in->fast_simple_add (len, 1.0);
                break;
 
        case Fast:
-               _fade_in.fast_simple_add (0, 0);
-               _fade_in.fast_simple_add (len * 0.389401, 0.0333333);
-               _fade_in.fast_simple_add (len * 0.629032, 0.0861111);
-               _fade_in.fast_simple_add (len * 0.829493, 0.233333);
-               _fade_in.fast_simple_add (len * 0.9447, 0.483333);
-               _fade_in.fast_simple_add (len * 0.976959, 0.697222);
-               _fade_in.fast_simple_add (len, 1);
+               _fade_in->fast_simple_add (0, 0);
+               _fade_in->fast_simple_add (len * 0.389401, 0.0333333);
+               _fade_in->fast_simple_add (len * 0.629032, 0.0861111);
+               _fade_in->fast_simple_add (len * 0.829493, 0.233333);
+               _fade_in->fast_simple_add (len * 0.9447, 0.483333);
+               _fade_in->fast_simple_add (len * 0.976959, 0.697222);
+               _fade_in->fast_simple_add (len, 1);
                break;
 
        case Slow:
-               _fade_in.fast_simple_add (0, 0);
-               _fade_in.fast_simple_add (len * 0.0207373, 0.197222);
-               _fade_in.fast_simple_add (len * 0.0645161, 0.525);
-               _fade_in.fast_simple_add (len * 0.152074, 0.802778);
-               _fade_in.fast_simple_add (len * 0.276498, 0.919444);
-               _fade_in.fast_simple_add (len * 0.481567, 0.980556);
-               _fade_in.fast_simple_add (len * 0.767281, 1);
-               _fade_in.fast_simple_add (len, 1);
+               _fade_in->fast_simple_add (0, 0);
+               _fade_in->fast_simple_add (len * 0.0207373, 0.197222);
+               _fade_in->fast_simple_add (len * 0.0645161, 0.525);
+               _fade_in->fast_simple_add (len * 0.152074, 0.802778);
+               _fade_in->fast_simple_add (len * 0.276498, 0.919444);
+               _fade_in->fast_simple_add (len * 0.481567, 0.980556);
+               _fade_in->fast_simple_add (len * 0.767281, 1);
+               _fade_in->fast_simple_add (len, 1);
                break;
 
        case LogA:
-               _fade_in.fast_simple_add (0, 0);
-               _fade_in.fast_simple_add (len * 0.0737327, 0.308333);
-               _fade_in.fast_simple_add (len * 0.246544, 0.658333);
-               _fade_in.fast_simple_add (len * 0.470046, 0.886111);
-               _fade_in.fast_simple_add (len * 0.652074, 0.972222);
-               _fade_in.fast_simple_add (len * 0.771889, 0.988889);
-               _fade_in.fast_simple_add (len, 1);
+               _fade_in->fast_simple_add (0, 0);
+               _fade_in->fast_simple_add (len * 0.0737327, 0.308333);
+               _fade_in->fast_simple_add (len * 0.246544, 0.658333);
+               _fade_in->fast_simple_add (len * 0.470046, 0.886111);
+               _fade_in->fast_simple_add (len * 0.652074, 0.972222);
+               _fade_in->fast_simple_add (len * 0.771889, 0.988889);
+               _fade_in->fast_simple_add (len, 1);
                break;
 
        case LogB:
-               _fade_in.fast_simple_add (0, 0);
-               _fade_in.fast_simple_add (len * 0.304147, 0.0694444);
-               _fade_in.fast_simple_add (len * 0.529954, 0.152778);
-               _fade_in.fast_simple_add (len * 0.725806, 0.333333);
-               _fade_in.fast_simple_add (len * 0.847926, 0.558333);
-               _fade_in.fast_simple_add (len * 0.919355, 0.730556);
-               _fade_in.fast_simple_add (len, 1);
+               _fade_in->fast_simple_add (0, 0);
+               _fade_in->fast_simple_add (len * 0.304147, 0.0694444);
+               _fade_in->fast_simple_add (len * 0.529954, 0.152778);
+               _fade_in->fast_simple_add (len * 0.725806, 0.333333);
+               _fade_in->fast_simple_add (len * 0.847926, 0.558333);
+               _fade_in->fast_simple_add (len * 0.919355, 0.730556);
+               _fade_in->fast_simple_add (len, 1);
                break;
        }
 
-       _fade_in.thaw ();
+       _fade_in->thaw ();
        _fade_in_shape = shape;
 
        send_change (FadeInChanged);
@@ -737,56 +737,56 @@ AudioRegion::set_fade_in (FadeShape shape, nframes_t len)
 void
 AudioRegion::set_fade_out (FadeShape shape, nframes_t len)
 {
-       _fade_out.freeze ();
-       _fade_out.clear ();
+       _fade_out->freeze ();
+       _fade_out->clear ();
 
        switch (shape) {
        case Fast:
-               _fade_out.fast_simple_add (len * 0, 1);
-               _fade_out.fast_simple_add (len * 0.023041, 0.697222);
-               _fade_out.fast_simple_add (len * 0.0553,   0.483333);
-               _fade_out.fast_simple_add (len * 0.170507, 0.233333);
-               _fade_out.fast_simple_add (len * 0.370968, 0.0861111);
-               _fade_out.fast_simple_add (len * 0.610599, 0.0333333);
-               _fade_out.fast_simple_add (len * 1, 0);
+               _fade_out->fast_simple_add (len * 0, 1);
+               _fade_out->fast_simple_add (len * 0.023041, 0.697222);
+               _fade_out->fast_simple_add (len * 0.0553,   0.483333);
+               _fade_out->fast_simple_add (len * 0.170507, 0.233333);
+               _fade_out->fast_simple_add (len * 0.370968, 0.0861111);
+               _fade_out->fast_simple_add (len * 0.610599, 0.0333333);
+               _fade_out->fast_simple_add (len * 1, 0);
                break;
 
        case LogA:
-               _fade_out.fast_simple_add (len * 0, 1);
-               _fade_out.fast_simple_add (len * 0.228111, 0.988889);
-               _fade_out.fast_simple_add (len * 0.347926, 0.972222);
-               _fade_out.fast_simple_add (len * 0.529954, 0.886111);
-               _fade_out.fast_simple_add (len * 0.753456, 0.658333);
-               _fade_out.fast_simple_add (len * 0.9262673, 0.308333);
-               _fade_out.fast_simple_add (len * 1, 0);
+               _fade_out->fast_simple_add (len * 0, 1);
+               _fade_out->fast_simple_add (len * 0.228111, 0.988889);
+               _fade_out->fast_simple_add (len * 0.347926, 0.972222);
+               _fade_out->fast_simple_add (len * 0.529954, 0.886111);
+               _fade_out->fast_simple_add (len * 0.753456, 0.658333);
+               _fade_out->fast_simple_add (len * 0.9262673, 0.308333);
+               _fade_out->fast_simple_add (len * 1, 0);
                break;
 
        case Slow:
-               _fade_out.fast_simple_add (len * 0, 1);
-               _fade_out.fast_simple_add (len * 0.305556, 1);
-               _fade_out.fast_simple_add (len * 0.548611, 0.991736);
-               _fade_out.fast_simple_add (len * 0.759259, 0.931129);
-               _fade_out.fast_simple_add (len * 0.918981, 0.68595);
-               _fade_out.fast_simple_add (len * 0.976852, 0.22865);
-               _fade_out.fast_simple_add (len * 1, 0);
+               _fade_out->fast_simple_add (len * 0, 1);
+               _fade_out->fast_simple_add (len * 0.305556, 1);
+               _fade_out->fast_simple_add (len * 0.548611, 0.991736);
+               _fade_out->fast_simple_add (len * 0.759259, 0.931129);
+               _fade_out->fast_simple_add (len * 0.918981, 0.68595);
+               _fade_out->fast_simple_add (len * 0.976852, 0.22865);
+               _fade_out->fast_simple_add (len * 1, 0);
                break;
 
        case LogB:
-               _fade_out.fast_simple_add (len * 0, 1);
-               _fade_out.fast_simple_add (len * 0.080645, 0.730556);
-               _fade_out.fast_simple_add (len * 0.277778, 0.289256);
-               _fade_out.fast_simple_add (len * 0.470046, 0.152778);
-               _fade_out.fast_simple_add (len * 0.695853, 0.0694444);
-               _fade_out.fast_simple_add (len * 1, 0);
+               _fade_out->fast_simple_add (len * 0, 1);
+               _fade_out->fast_simple_add (len * 0.080645, 0.730556);
+               _fade_out->fast_simple_add (len * 0.277778, 0.289256);
+               _fade_out->fast_simple_add (len * 0.470046, 0.152778);
+               _fade_out->fast_simple_add (len * 0.695853, 0.0694444);
+               _fade_out->fast_simple_add (len * 1, 0);
                break;
 
        case Linear:
-               _fade_out.fast_simple_add (len * 0, 1);
-               _fade_out.fast_simple_add (len * 1, 0);
+               _fade_out->fast_simple_add (len * 0, 1);
+               _fade_out->fast_simple_add (len * 1, 0);
                break;
        }
 
-       _fade_out.thaw ();
+       _fade_out->thaw ();
        _fade_out_shape = shape;
 
        send_change (FadeOutChanged);
@@ -795,7 +795,7 @@ AudioRegion::set_fade_out (FadeShape shape, nframes_t len)
 void
 AudioRegion::set_fade_in_length (nframes_t len)
 {
-       bool changed = _fade_in.extend_to (len);
+       bool changed = _fade_in->extend_to (len);
 
        if (changed) {
                _flags = Flag (_flags & ~DefaultFadeIn);
@@ -806,7 +806,7 @@ AudioRegion::set_fade_in_length (nframes_t len)
 void
 AudioRegion::set_fade_out_length (nframes_t len)
 {
-       bool changed =  _fade_out.extend_to (len);
+       bool changed =  _fade_out->extend_to (len);
 
        if (changed) {
                _flags = Flag (_flags & ~DefaultFadeOut);
@@ -848,13 +848,13 @@ AudioRegion::set_fade_out_active (bool yn)
 bool
 AudioRegion::fade_in_is_default () const
 {
-       return _fade_in_shape == Linear && _fade_in.back()->when == 64;
+       return _fade_in_shape == Linear && _fade_in->back()->when == 64;
 }
 
 bool
 AudioRegion::fade_out_is_default () const
 {
-       return _fade_out_shape == Linear && _fade_out.back()->when == 64;
+       return _fade_out_shape == Linear && _fade_out->back()->when == 64;
 }
 
 void
@@ -881,11 +881,11 @@ AudioRegion::set_default_fades ()
 void
 AudioRegion::set_default_envelope ()
 {
-       _envelope.freeze ();
-       _envelope.clear ();
-       _envelope.fast_simple_add (0, 1.0f);
-       _envelope.fast_simple_add (_length, 1.0f);
-       _envelope.thaw ();
+       _envelope->freeze ();
+       _envelope->clear ();
+       _envelope->fast_simple_add (0, 1.0f);
+       _envelope->fast_simple_add (_length, 1.0f);
+       _envelope->thaw ();
 }
 
 void
@@ -895,18 +895,18 @@ AudioRegion::recompute_at_end ()
           based on the the existing curve.
        */
        
-       _envelope.freeze ();
-       _envelope.truncate_end (_length);
-       _envelope.set_max_xval (_length);
-       _envelope.thaw ();
+       _envelope->freeze ();
+       _envelope->truncate_end (_length);
+       _envelope->set_max_xval (_length);
+       _envelope->thaw ();
 
-       if (_fade_in.back()->when > _length) {
-               _fade_in.extend_to (_length);
+       if (_fade_in->back()->when > _length) {
+               _fade_in->extend_to (_length);
                send_change (FadeInChanged);
        }
 
-       if (_fade_out.back()->when > _length) {
-               _fade_out.extend_to (_length);
+       if (_fade_out->back()->when > _length) {
+               _fade_out->extend_to (_length);
                send_change (FadeOutChanged);
        }
 }      
@@ -916,15 +916,15 @@ AudioRegion::recompute_at_start ()
 {
        /* as above, but the shift was from the front */
 
-       _envelope.truncate_start (_length);
+       _envelope->truncate_start (_length);
 
-       if (_fade_in.back()->when > _length) {
-               _fade_in.extend_to (_length);
+       if (_fade_in->back()->when > _length) {
+               _fade_in->extend_to (_length);
                send_change (FadeInChanged);
        }
 
-       if (_fade_out.back()->when > _length) {
-               _fade_out.extend_to (_length);
+       if (_fade_out->back()->when > _length) {
+               _fade_out->extend_to (_length);
                send_change (FadeOutChanged);
        }
 }
index 9f3ba6deb6f2b0e75b297901d3d2fa4e8cb676c7..d7c570ecdf46b1d30a3430448a9462ee2e591550 100644 (file)
@@ -54,7 +54,7 @@ Automatable::old_set_automation_state (const XMLNode& node)
                uint32_t what;
                stringstream sstr;
                
-               _visible_parameter_automation.clear ();
+               _visible_controls.clear ();
                
                sstr << prop->value();
                while (1) {
@@ -65,6 +65,8 @@ Automatable::old_set_automation_state (const XMLNode& node)
                        mark_automation_visible (ParamID(PluginAutomation, what), true);
                }
        }
+       
+       _last_automation_snapshot = 0;
 
        return 0;
 }
@@ -89,7 +91,9 @@ Automatable::load_automation (const string& path)
 
        Glib::Mutex::Lock lm (_automation_lock);
        set<ParamID> tosave;
-       _parameter_automation.clear ();
+       _controls.clear ();
+       
+       _last_automation_snapshot = 0;
 
        while (in) {
                double when;
@@ -101,8 +105,8 @@ Automatable::load_automation (const string& path)
                in >> value; if (!in) goto bad;
                
                /* FIXME: this is legacy and only used for plugin inserts?  I think? */
-               AutomationList* al = automation_list (ParamID(PluginAutomation, port), true);
-               al->add (when, value);
+               boost::shared_ptr<AutomationControl> c = control (ParamID(PluginAutomation, port), true);
+               c->list()->add (when, value);
                tosave.insert (ParamID(PluginAutomation, port));
        }
        
@@ -110,32 +114,35 @@ Automatable::load_automation (const string& path)
 
   bad:
        error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg;
-       _parameter_automation.clear ();
+       _controls.clear ();
        return -1;
 }
 
 void
-Automatable::add_automation_parameter(AutomationList* al)
+Automatable::add_control(boost::shared_ptr<AutomationControl> ac)
 {
-       _parameter_automation[al->param_id()] = al;
-       
-       /* let derived classes do whatever they need with this */
-       automation_list_creation_callback (al->param_id(), *al);
+       ParamID param = ac->list()->param_id();
 
-       cerr << _name << ": added parameter " << al->param_id().to_string() << endl;
+       _controls[param] = ac;
+       
+       cerr << _name << ": added parameter " << param.to_string() << endl;
 
        // FIXME: sane default behaviour?
-       _visible_parameter_automation.insert(al->param_id());
-       _can_automate_list.insert(al->param_id());
+       _visible_controls.insert(param);
+       _can_automate_list.insert(param);
+
+       // Sync everything (derived classes) up to initial values
+       auto_state_changed(param);
 }
 
 void
 Automatable::what_has_automation (set<ParamID>& s) const
 {
        Glib::Mutex::Lock lm (_automation_lock);
-       map<ParamID,AutomationList*>::const_iterator li;
+       Controls::const_iterator li;
        
-       for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
+       // FIXME: correct semantics?
+       for (li = _controls.begin(); li != _controls.end(); ++li) {
                s.insert  ((*li).first);
        }
 }
@@ -146,42 +153,45 @@ Automatable::what_has_visible_automation (set<ParamID>& s) const
        Glib::Mutex::Lock lm (_automation_lock);
        set<ParamID>::const_iterator li;
        
-       for (li = _visible_parameter_automation.begin(); li != _visible_parameter_automation.end(); ++li) {
+       for (li = _visible_controls.begin(); li != _visible_controls.end(); ++li) {
                s.insert  (*li);
        }
 }
 
 /** Returns NULL if we don't have an AutomationList for \a parameter.
  */
-AutomationList*
-Automatable::automation_list (ParamID parameter, bool create_if_missing)
+boost::shared_ptr<AutomationControl>
+Automatable::control (ParamID parameter, bool create_if_missing)
 {
-       std::map<ParamID,AutomationList*>::iterator i = _parameter_automation.find(parameter);
+       Controls::iterator i = _controls.find(parameter);
 
-       if (i != _parameter_automation.end()) {
+       if (i != _controls.end()) {
                return i->second;
 
        } else if (create_if_missing) {
-               AutomationList* al = new AutomationList (parameter, FLT_MIN, FLT_MAX, default_parameter_value (parameter));
-               add_automation_parameter(al);
-               return al;
+               assert(parameter.type() != GainAutomation);
+               boost::shared_ptr<AutomationList> al (new AutomationList (
+                                       parameter, FLT_MIN, FLT_MAX, default_parameter_value (parameter)));
+               boost::shared_ptr<AutomationControl> ac (new AutomationControl(_session, al));
+               add_control(ac);
+               return ac;
 
        } else {
                //warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg;
-               return NULL;
+               return boost::shared_ptr<AutomationControl>();
        }
 }
 
-const AutomationList*
-Automatable::automation_list (ParamID parameter) const
+boost::shared_ptr<const AutomationControl>
+Automatable::control (ParamID parameter) const
 {
-       std::map<ParamID,AutomationList*>::const_iterator i = _parameter_automation.find(parameter);
+       Controls::const_iterator i = _controls.find(parameter);
 
-       if (i != _parameter_automation.end()) {
+       if (i != _controls.end()) {
                return i->second;
        } else {
                //warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg;
-               return NULL;
+               return boost::shared_ptr<AutomationControl>();
        }
 }
 
@@ -196,7 +206,7 @@ Automatable::describe_parameter (ParamID param)
        else if (param == ParamID(PanAutomation))
                return _("Pan");
        else if (param.type() == MidiCCAutomation)
-               return string_compose("MIDI CC %1", param.id());
+               return string_compose("CC %1", param.id());
        else
                return param.to_string();
 }
@@ -211,12 +221,12 @@ void
 Automatable::mark_automation_visible (ParamID what, bool yn)
 {
        if (yn) {
-               _visible_parameter_automation.insert (what);
+               _visible_controls.insert (what);
        } else {
                set<ParamID>::iterator i;
 
-               if ((i = _visible_parameter_automation.find (what)) != _visible_parameter_automation.end()) {
-                       _visible_parameter_automation.erase (i);
+               if ((i = _visible_controls.find (what)) != _visible_controls.end()) {
+                       _visible_controls.erase (i);
                }
        }
 }
@@ -224,24 +234,24 @@ Automatable::mark_automation_visible (ParamID what, bool yn)
 bool
 Automatable::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_event) const
 {
-       map<ParamID,AutomationList*>::const_iterator li;        
+       Controls::const_iterator li;    
        AutomationList::TimeComparator cmp;
 
        next_event.when = max_frames;
        
-       for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
+       for (li = _controls.begin(); li != _controls.end(); ++li) {
                
                AutomationList::const_iterator i;
-               const AutomationList& alist (*((*li).second));
+               boost::shared_ptr<const AutomationList> alist (li->second->list());
                ControlEvent cp (now, 0.0f);
                
-               for (i = lower_bound (alist.const_begin(), alist.const_end(), &cp, cmp); i != alist.const_end() && (*i)->when < end; ++i) {
+               for (i = lower_bound (alist->const_begin(), alist->const_end(), &cp, cmp); i != alist->const_end() && (*i)->when < end; ++i) {
                        if ((*i)->when > now) {
                                break; 
                        }
                }
                
-               if (i != alist.const_end() && (*i)->when < end) {
+               if (i != alist->const_end() && (*i)->when < end) {
                        
                        if ((*i)->when < next_event.when) {
                                next_event.when = (*i)->when;
@@ -261,8 +271,9 @@ Automatable::set_automation_state (const XMLNode& node, ParamID legacy_param)
 {      
        Glib::Mutex::Lock lm (_automation_lock);
 
-       _parameter_automation.clear ();
-       _visible_parameter_automation.clear ();
+       /* Don't clear controls, since some may be special derived Controllable classes */
+
+       _visible_controls.clear ();
 
        XMLNodeList nlist = node.children();
        XMLNodeIterator niter;
@@ -280,7 +291,7 @@ Automatable::set_automation_state (const XMLNode& node, ParamID legacy_param)
 
                        ParamID param = (id_prop ? ParamID(id_prop->value()) : legacy_param);
                        
-                       AutomationList* al = new AutomationList(**niter, param);
+                       boost::shared_ptr<AutomationList> al (new AutomationList(**niter, param));
                        
                        if (!id_prop) {
                                warning << "AutomationList node without automation-id property, "
@@ -288,13 +299,19 @@ Automatable::set_automation_state (const XMLNode& node, ParamID legacy_param)
                                al->set_param_id(legacy_param);
                        }
 
-                       add_automation_parameter(al);
+                       boost::shared_ptr<AutomationControl> existing = control(param);
+                       if (existing)
+                               existing->set_list(al);
+                       else
+                               add_control(boost::shared_ptr<AutomationControl>(new AutomationControl(_session, al)));
 
                } else {
                        error << "Expected AutomationList node, got '" << (*niter)->name() << endmsg;
                }
        }
 
+       _last_automation_snapshot = 0;
+
        return 0;
 }
 
@@ -304,16 +321,12 @@ Automatable::get_automation_state ()
        Glib::Mutex::Lock lm (_automation_lock);
        XMLNode* node = new XMLNode (X_("Automation"));
        
-       cerr << "'" << _name << "'->get_automation_state, # params = " << _parameter_automation.size() << endl;
-
-       if (_parameter_automation.empty()) {
+       if (_controls.empty()) {
                return *node;
        }
 
-       map<ParamID,AutomationList*>::iterator li;
-       
-       for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
-               node->add_child_nocopy (li->second->get_state ());
+       for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) {
+               node->add_child_nocopy (li->second->list()->get_state ());
        }
 
        return *node;
@@ -324,10 +337,8 @@ Automatable::clear_automation ()
 {
        Glib::Mutex::Lock lm (_automation_lock);
 
-       map<ParamID,AutomationList*>::iterator li;
-
-       for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li)
-               li->second->clear();
+       for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li)
+               li->second->list()->clear();
 }
        
 void
@@ -335,10 +346,10 @@ Automatable::set_parameter_automation_state (ParamID param, AutoState s)
 {
        Glib::Mutex::Lock lm (_automation_lock);
        
-       AutomationList* al = automation_list (param, true);
+       boost::shared_ptr<AutomationControl> c = control (param, true);
 
-       if (s != al->automation_state()) {
-               al->set_automation_state (s);
+       if (s != c->list()->automation_state()) {
+               c->list()->set_automation_state (s);
                _session.set_dirty ();
        }
 }
@@ -348,10 +359,10 @@ Automatable::get_parameter_automation_state (ParamID param)
 {
        Glib::Mutex::Lock lm (_automation_lock);
 
-       AutomationList* al = automation_list(param);
+       boost::shared_ptr<AutomationControl> c = control(param);
 
-       if (al) {
-               return al->automation_state();
+       if (c) {
+               return c->list()->automation_state();
        } else {
                return Off;
        }
@@ -362,10 +373,10 @@ Automatable::set_parameter_automation_style (ParamID param, AutoStyle s)
 {
        Glib::Mutex::Lock lm (_automation_lock);
        
-       AutomationList* al = automation_list (param, true);
+       boost::shared_ptr<AutomationControl> c = control(param, true);
 
-       if (s != al->automation_style()) {
-               al->set_automation_style (s);
+       if (s != c->list()->automation_style()) {
+               c->list()->set_automation_style (s);
                _session.set_dirty ();
        }
 }
@@ -375,10 +386,10 @@ Automatable::get_parameter_automation_style (ParamID param)
 {
        Glib::Mutex::Lock lm (_automation_lock);
 
-       AutomationList* al = automation_list(param);
+       boost::shared_ptr<AutomationControl> c = control(param);
 
-       if (al) {
-               return al->automation_style();
+       if (c) {
+               return c->list()->automation_style();
        } else {
                return Absolute; // whatever
        }
@@ -393,14 +404,14 @@ Automatable::protect_automation ()
 
        for (set<ParamID>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
 
-               AutomationList* al = automation_list (*i);
+               boost::shared_ptr<AutomationControl> c = control(*i);
 
-               switch (al->automation_state()) {
+               switch (c->list()->automation_state()) {
                case Write:
-                       al->set_automation_state (Off);
+                       c->list()->set_automation_state (Off);
                        break;
                case Touch:
-                       al->set_automation_state (Play);
+                       c->list()->set_automation_state (Play);
                        break;
                default:
                        break;
@@ -408,3 +419,18 @@ Automatable::protect_automation ()
        }
 }
 
+void
+Automatable::automation_snapshot (nframes_t now)
+{
+       if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) {
+
+               for (Controls::iterator i = _controls.begin(); i != _controls.end(); ++i) {
+                       if (i->second->list()->automation_write()) {
+                               i->second->list()->rt_add (now, i->second->user_value());
+                       }
+               }
+               
+               _last_automation_snapshot = now;
+       }
+}
+
diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc
new file mode 100644 (file)
index 0000000..8f8e40a
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+    Copyright (C) 2007 Paul Davis 
+       Author: Dave Robillard
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include <ardour/automation_control.h>
+#include <ardour/session.h>
+#include <ardour/automatable.h>
+
+using namespace std;
+using namespace ARDOUR;
+using namespace PBD;
+
+
+AutomationControl::AutomationControl(Session& session, boost::shared_ptr<AutomationList> list, string name)
+       : Controllable((name == "unnamed controllable") ? list->param_id().to_string() : name)
+       , _session(session)
+       , _list(list)
+       , _user_value(list->default_value())
+{
+       cerr << "Created AutomationControl " << name << "(" << list->param_id().to_string() << ")" << endl;
+}
+
+
+/** Get the currently effective value (ie the one that corresponds to current output)
+ */
+float
+AutomationControl::get_value() const
+{
+       if (_list->automation_playback())
+               return _list->eval(_session.transport_frame());
+       else
+               return _user_value;
+}
+
+
+void
+AutomationControl::set_value(float value)
+{
+       _user_value = value;
+       
+       if (_session.transport_stopped() && _list->automation_write())
+               _list->add(_session.transport_frame(), value);
+
+       Changed(); /* EMIT SIGNAL */
+}
+
+
+/** Get the latest user-set value, which may not equal get_value() when automation
+ * is playing back, etc.
+ *
+ * Automation write/touch works by periodically sampling this value and adding it
+ * to the AutomationList.
+ */
+float
+AutomationControl::user_value() const
+{
+       return _user_value;
+}
+       
+
+void
+AutomationControl::set_list(boost::shared_ptr<ARDOUR::AutomationList> list)
+{
+       _list = list;
+       _user_value = list->default_value();
+       Changed();  /* EMIT SIGNAL */
+}
+
index b620054558a50e2a19cb7ec6bb5eca0ee58e4704..9c1a6126f6f9031169c95fe57bd87aaf02f9be34 100644 (file)
@@ -1195,8 +1195,6 @@ AutomationList::get_state ()
 XMLNode&
 AutomationList::state (bool full)
 {
-       cerr << _param_id.to_string() << "->state()" << endl;
-
        XMLNode* root = new XMLNode (X_("AutomationList"));
        char buf[64];
        LocaleGuard lg (X_("POSIX"));
@@ -1208,11 +1206,11 @@ AutomationList::state (bool full)
        snprintf (buf, sizeof (buf), "%.12g", _default_value);
        root->add_property ("default", buf);
        snprintf (buf, sizeof (buf), "%.12g", _min_yval);
-       root->add_property ("_min_yval", buf);
+       root->add_property ("min_yval", buf);
        snprintf (buf, sizeof (buf), "%.12g", _max_yval);
-       root->add_property ("_max_yval", buf);
+       root->add_property ("max_yval", buf);
        snprintf (buf, sizeof (buf), "%.12g", _max_xval);
-       root->add_property ("_max_xval", buf);
+       root->add_property ("max_xval", buf);
 
        if (full) {
                root->add_property ("state", auto_state_to_string (_state));
@@ -1390,19 +1388,19 @@ AutomationList::set_state (const XMLNode& node)
                _state = Off;
        }
 
-       if ((prop = node.property (X_("_min_yval"))) != 0) {
+       if ((prop = node.property (X_("min_yval"))) != 0) {
                _min_yval = atof (prop->value ());
        } else {
                _min_yval = FLT_MIN;
        }
 
-       if ((prop = node.property (X_("_max_yval"))) != 0) {
+       if ((prop = node.property (X_("max_yval"))) != 0) {
                _max_yval = atof (prop->value ());
        } else {
                _max_yval = FLT_MAX;
        }
 
-       if ((prop = node.property (X_("_max_xval"))) != 0) {
+       if ((prop = node.property (X_("max_xval"))) != 0) {
                _max_xval = atof (prop->value ());
        } else {
                _max_xval = 0; // means "no limit ;
index b61a654b2503588139e72c998944f900e9afbd58..f04af47f8c3a1d735f4fabd87ddc292e29ca167a 100644 (file)
@@ -62,8 +62,6 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-nframes_t    IO::_automation_interval = 0;
-
 const string                 IO::state_node_name = "IO";
 bool                         IO::connecting_legal = false;
 bool                         IO::ports_legal = false;
@@ -81,6 +79,7 @@ Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
    others can be imagined. 
 */
 
+#if 0
 static gain_t direct_control_to_gain (double fract) { 
        /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
        /* this maxes at +6dB */
@@ -93,7 +92,7 @@ static double direct_gain_to_control (gain_t gain) {
        
        return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
 }
-
+#endif
 
 /** @param default_type The type of port that will be created by ensure_io
  * and friends if no type is explicitly requested (to avoid breakage).
@@ -104,7 +103,6 @@ IO::IO (Session& s, const string& name,
        : Automatable (s, name),
       _output_buffers (new BufferSet()),
          _default_type (default_type),
-         _gain_control (X_("gaincontrol"), *this),
          _input_minimum (ChanCount::ZERO),
          _input_maximum (ChanCount::INFINITE),
          _output_minimum (ChanCount::ZERO),
@@ -135,15 +133,16 @@ IO::IO (Session& s, const string& name,
        _phase_invert = false;
        deferred_state = 0;
 
-       add_automation_parameter(new AutomationList(ParamID(GainAutomation), 0.0, 2.0, 1.0));
+       boost::shared_ptr<AutomationList> gl(
+                       new AutomationList(ParamID(GainAutomation), 0.0, 2.0, 1.0));
 
-       apply_gain_automation = false;
-       
-       last_automation_snapshot = 0;
+       _gain_control = boost::shared_ptr<GainControl>(
+                       new GainControl(X_("gaincontrol"), *this, gl));
 
-       /*_gain_automation_state = Off;
-       _gain_automation_style = Absolute;*/
+       add_control(_gain_control);
 
+       apply_gain_automation = false;
+       
        {
                // IO::Meter is emitted from another thread so the
                // Meter signal must be protected.
@@ -154,14 +153,13 @@ IO::IO (Session& s, const string& name,
        // Connect to our own MoreChannels signal to connect output buffers
        IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
 
-       _session.add_controllable (&_gain_control);
+       _session.add_controllable (_gain_control);
 }
 
 IO::IO (Session& s, const XMLNode& node, DataType dt)
        : Automatable (s, "unnamed io"),
       _output_buffers (new BufferSet()),
-         _default_type (dt),
-         _gain_control (X_("gaincontrol"), *this)
+         _default_type (dt)
 {
        _meter = new PeakMeter (_session);
 
@@ -174,6 +172,14 @@ IO::IO (Session& s, const XMLNode& node, DataType dt)
        _output_bundle = 0;
 
        apply_gain_automation = false;
+       
+       boost::shared_ptr<AutomationList> gl(
+                       new AutomationList(ParamID(GainAutomation), 0.0, 2.0, 1.0));
+
+       _gain_control = boost::shared_ptr<GainControl>(
+                       new GainControl(X_("gaincontrol"), *this, gl));
+
+       add_control(_gain_control);
 
        set_state (node);
 
@@ -187,7 +193,7 @@ IO::IO (Session& s, const XMLNode& node, DataType dt)
        // Connect to our own MoreChannels signal to connect output buffers
        IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
 
-       _session.add_controllable (&_gain_control);
+       _session.add_controllable (_gain_control);
 }
 
 IO::~IO ()
@@ -1129,8 +1135,8 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
 gain_t
 IO::effective_gain () const
 {
-       if (gain_automation().automation_playback()) {
-               return _effective_gain;
+       if (_gain_control->list()->automation_playback()) {
+               return _gain_control->get_value();
        } else {
                return _desired_gain;
        }
@@ -1272,7 +1278,7 @@ IO::state (bool full_state)
        }
 
        node->add_child_nocopy (_panner->state (full_state));
-       node->add_child_nocopy (_gain_control.get_state ());
+       node->add_child_nocopy (_gain_control->get_state ());
 
        snprintf (buf, sizeof(buf), "%2.12f", gain());
        node->add_property ("gain", buf);
@@ -1359,7 +1365,7 @@ IO::set_state (const XMLNode& node)
 
                if ((*iter)->name() == X_("controllable")) {
                        if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
-                               _gain_control.set_state (**iter);
+                               _gain_control->set_state (**iter);
                        }
                }
        }
@@ -1396,8 +1402,6 @@ IO::set_state (const XMLNode& node)
                pending_state_node = new XMLNode (node);
        }
 
-       last_automation_snapshot = 0;
-
        return 0;
 }
 
@@ -1458,7 +1462,7 @@ IO::load_automation (string path)
 
                switch (type) {
                case 'g':
-                       gain_automation().fast_simple_add (when, value);
+                       _gain_control->list()->fast_simple_add (when, value);
                        break;
 
                case 's':
@@ -2131,15 +2135,22 @@ IO::output_bundle_configuration_changed ()
 }
 
 void
-IO::GainControllable::set_value (float val)
+IO::GainControl::set_value (float val)
 {
-       io.set_gain (direct_control_to_gain (val), this);
+       // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
+       if (val > 1.99526231f)
+               val = 1.99526231f;
+
+       _user_value = val;
+       _io.set_gain (val, this);
+       
+       Changed(); /* EMIT SIGNAL */
 }
 
 float
-IO::GainControllable::get_value (void) const
+IO::GainControl::get_value (void) const
 {
-       return direct_gain_to_control (io.effective_gain());
+       return AutomationControl::get_value();
 }
 
 void
@@ -2193,16 +2204,16 @@ IO::set_parameter_automation_state (ParamID param, AutoState state)
                { 
                        Glib::Mutex::Lock lm (_automation_lock);
 
-                       ARDOUR::AutomationList& gain_auto = gain_automation();
+                       boost::shared_ptr<AutomationList> gain_auto = _gain_control->list();
 
-                       if (state != gain_auto.automation_state()) {
+                       if (state != gain_auto->automation_state()) {
                                changed = true;
-                               last_automation_snapshot = 0;
-                               gain_auto.set_automation_state (state);
+                               _last_automation_snapshot = 0;
+                               gain_auto->set_automation_state (state);
 
                                if (state != Off) {
                                        // FIXME: shouldn't this use Curve?
-                                       set_gain (gain_auto.eval (_session.transport_frame()), this);
+                                       set_gain (gain_auto->eval (_session.transport_frame()), this);
                                }
                        }
                }
@@ -2229,7 +2240,15 @@ void
 IO::set_gain (gain_t val, void *src)
 {
        // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
-       if (val>1.99526231f) val=1.99526231f;
+       if (val > 1.99526231f)
+               val = 1.99526231f;
+
+       if (src != _gain_control.get()) {
+               _gain_control->set_value(val);
+               // bit twisty, this will come back and call us again
+               // (this keeps control in sync with reality)
+               return;
+       }
 
        {
                Glib::Mutex::Lock dm (declick_lock);
@@ -2237,17 +2256,11 @@ IO::set_gain (gain_t val, void *src)
        }
 
        if (_session.transport_stopped()) {
-               _effective_gain = val;
                _gain = val;
        }
-
-       gain_changed (src);
-       _gain_control.Changed (); /* EMIT SIGNAL */
        
-       ARDOUR::AutomationList& gain_auto = gain_automation();
-
-       if (_session.transport_stopped() && src != 0 && src != this && gain_auto.automation_write()) {
-               gain_auto.add (_session.transport_frame(), val);
+       if (_session.transport_stopped() && src != 0 && src != this && _gain_control->list()->automation_write()) {
+               _gain_control->list()->add (_session.transport_frame(), val);
                
        }
 
@@ -2258,7 +2271,7 @@ void
 IO::start_pan_touch (uint32_t which)
 {
        if (which < _panner->size()) {
-               (*_panner)[which]->automation().start_touch();
+               (*_panner)[which]->automation()->start_touch();
        }
 }
 
@@ -2266,7 +2279,7 @@ void
 IO::end_pan_touch (uint32_t which)
 {
        if (which < _panner->size()) {
-               (*_panner)[which]->automation().stop_touch();
+               (*_panner)[which]->automation()->stop_touch();
        }
 
 }
@@ -2274,35 +2287,26 @@ IO::end_pan_touch (uint32_t which)
 void
 IO::automation_snapshot (nframes_t now)
 {
-       if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
-
-               ARDOUR::AutomationList& gain_auto = gain_automation();
+       Automatable::automation_snapshot (now);
 
-               if (gain_auto.automation_write()) {
-                       gain_auto.rt_add (now, gain());
-               }
-               
+       if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) {
                _panner->snapshot (now);
-
-               last_automation_snapshot = now;
        }
 }
 
 void
 IO::transport_stopped (nframes_t frame)
 {
-       ARDOUR::AutomationList& gain_auto = gain_automation();
-
-       gain_auto.reposition_for_rt_add (frame);
+       _gain_control->list()->reposition_for_rt_add (frame);
 
-       if (gain_auto.automation_state() != Off) {
+       if (_gain_control->list()->automation_state() != Off) {
                
                /* the src=0 condition is a special signal to not propagate 
                   automation gain changes into the mix group when locating.
                */
 
                // FIXME: shouldn't this use Curve?
-               set_gain (gain_auto.eval (frame), 0);
+               set_gain (_gain_control->list()->eval (frame), 0);
        }
 
        _panner->transport_stopped (frame);
index 9114f689b2296d367bf75fc40b8d8a0b5cdeba6a..6386714c16ce719159f8f21065c422ca789e1e30 100644 (file)
@@ -596,7 +596,7 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_t
 
                // XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
                // Write into playback buffer here, and whatnot?
-               cerr << "MDS FIXME: collect playback" << endl;
+               //cerr << "MDS FIXME: collect playback" << endl;
 
        }
 
@@ -1498,9 +1498,8 @@ MidiDiskstream::get_playback(MidiBuffer& dst, nframes_t start, nframes_t end)
        dst.clear();
        assert(dst.size() == 0);
        
-       // I think this happens with reverse varispeed?  maybe?
+       // Reverse.  ... We just don't do reverse, ok?  Back off.
        if (end <= start) {
-               cerr << "MDS: Reverse?  Skipping" << endl;
                return;
        }
 
index 71a2735606dd068b4c1c4a761ae523fef3890862..a10161bc7256c72874ce4b2c1ce2cb5b0a018576 100644 (file)
@@ -193,8 +193,8 @@ MidiTrack::_set_state (const XMLNode& node, bool call_base)
                child = *niter;
 
                if (child->name() == X_("recenable")) {
-                       _rec_enable_control.set_state (*child);
-                       _session.add_controllable (&_rec_enable_control);
+                       _rec_enable_control->set_state (*child);
+                       _session.add_controllable (_rec_enable_control);
                }
        }
 
@@ -249,7 +249,7 @@ MidiTrack::state(bool full_state)
        _diskstream->id().print (buf, sizeof(buf));
        root.add_property ("diskstream-id", buf);
        
-       root.add_child_nocopy (_rec_enable_control.get_state());
+       root.add_child_nocopy (_rec_enable_control->get_state());
 
        return root;
 }
@@ -426,6 +426,15 @@ MidiTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
 {
        int dret;
        boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
+       
+       {
+               Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+               if (lm.locked()) {
+                       // automation snapshot can also be called from the non-rt context
+                       // and it uses the redirect list, so we take the lock out here
+                       automation_snapshot (start_frame);
+               }
+       }
 
        if (n_outputs().n_total() == 0 && _processors.empty()) {
                return 0;
index d5a238e253687a8873f3405b6a57915e4179e7c2..fa05ff44512c56f105d356e780f89aef8df947cf 100644 (file)
@@ -71,11 +71,11 @@ static double direct_pan_to_control (pan_t val) {
 
 StreamPanner::StreamPanner (Panner& p)
        : parent (p),
-         _control (X_("panner"), *this)
+         _control (new PanControllable(X_("panner"), *this))
 {
        _muted = false;
 
-       parent.session().add_controllable (&_control);
+       parent.session().add_controllable (_control);
 
        x = 0.5;
        y = 0.5;
@@ -132,7 +132,7 @@ StreamPanner::set_position (float xpos, bool link_call)
                x = xpos;
                update ();
                Changed ();
-               _control.Changed ();
+               _control->Changed ();
        }
 }
 
@@ -190,7 +190,7 @@ StreamPanner::add_state (XMLNode& node)
 /*---------------------------------------------------------------------- */
 
 BaseStereoPanner::BaseStereoPanner (Panner& p)
-       : StreamPanner (p), _automation (ParamID(PanAutomation), 0.0, 1.0, 0.5)
+       : StreamPanner (p), _automation (new AutomationList(ParamID(PanAutomation), 0.0, 1.0, 0.5))
 {
 }
 
@@ -201,36 +201,36 @@ BaseStereoPanner::~BaseStereoPanner ()
 void
 BaseStereoPanner::snapshot (nframes_t now)
 {
-       if (_automation.automation_state() == Write || _automation.automation_state() == Touch) {
-               _automation.rt_add (now, x);
+       if (_automation->automation_state() == Write || _automation->automation_state() == Touch) {
+               _automation->rt_add (now, x);
        }
 }
 
 void
 BaseStereoPanner::transport_stopped (nframes_t frame)
 {
-       _automation.reposition_for_rt_add (frame);
+       _automation->reposition_for_rt_add (frame);
 
-       if (_automation.automation_state() != Off) {
-               set_position (_automation.eval (frame));
+       if (_automation->automation_state() != Off) {
+               set_position (_automation->eval (frame));
        }
 }
 
 void
 BaseStereoPanner::set_automation_style (AutoStyle style)
 {
-       _automation.set_automation_style (style);
+       _automation->set_automation_style (style);
 }
 
 void
 BaseStereoPanner::set_automation_state (AutoState state)
 {
-       if (state != _automation.automation_state()) {
+       if (state != _automation->automation_state()) {
 
-               _automation.set_automation_state (state);
+               _automation->set_automation_state (state);
                
                if (state != Off) {
-                       set_position (_automation.eval (parent.session().transport_frame()));
+                       set_position (_automation->eval (parent.session().transport_frame()));
                }
        }
 }
@@ -241,7 +241,7 @@ BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt)
        char line[128];
        LocaleGuard lg (X_("POSIX"));
        
-       _automation.clear ();
+       _automation->clear ();
 
        while (in.getline (line, sizeof (line), '\n')) {
                nframes_t when;
@@ -258,12 +258,12 @@ BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt)
                        continue;
                }
 
-               _automation.fast_simple_add (when, value);
+               _automation->fast_simple_add (when, value);
        }
 
        /* now that we are done loading */
 
-       _automation.StateChanged ();
+       _automation->StateChanged ();
 
        return 0;
 }
@@ -438,7 +438,7 @@ EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& ob
 
        /* fetch positional data */
 
-       if (!_automation.curve().rt_safe_get_vector (start, end, buffers[0], nframes)) {
+       if (!_automation->curve().rt_safe_get_vector (start, end, buffers[0], nframes)) {
                /* fallback */
                if (!_muted) {
                        distribute (srcbuf, obufs, 1.0, nframes);
@@ -518,12 +518,12 @@ EqualPowerStereoPanner::state (bool full_state)
        root->add_property (X_("type"), EqualPowerStereoPanner::name);
 
        XMLNode* autonode = new XMLNode (X_("Automation"));
-       autonode->add_child_nocopy (_automation.state (full_state));
+       autonode->add_child_nocopy (_automation->state (full_state));
        root->add_child_nocopy (*autonode);
 
        StreamPanner::add_state (*root);
 
-       root->add_child_nocopy (_control.get_state ());
+       root->add_child_nocopy (_control->get_state ());
 
        return *root;
 }
@@ -546,15 +546,15 @@ EqualPowerStereoPanner::set_state (const XMLNode& node)
 
                if ((*iter)->name() == X_("controllable")) {
                        if ((prop = (*iter)->property("name")) != 0 && prop->value() == "panner") {
-                               _control.set_state (**iter);
+                               _control->set_state (**iter);
                        }
 
                } else if ((*iter)->name() == X_("Automation")) {
 
-                       _automation.set_state (*((*iter)->children().front()));
+                       _automation->set_state (*((*iter)->children().front()));
 
-                       if (_automation.automation_state() != Off) {
-                               set_position (_automation.eval (parent.session().transport_frame()));
+                       if (_automation->automation_state() != Off) {
+                               set_position (_automation->eval (parent.session().transport_frame()));
                        }
                }
        }
@@ -565,7 +565,7 @@ EqualPowerStereoPanner::set_state (const XMLNode& node)
 /*----------------------------------------------------------------------*/
 
 Multi2dPanner::Multi2dPanner (Panner& p)
-       : StreamPanner (p), _automation (ParamID(PanAutomation), 0.0, 1.0, 0.5) // XXX useless
+       : StreamPanner (p), _automation (new AutomationList(ParamID(PanAutomation), 0.0, 1.0, 0.5)) // XXX useless
 {
        update ();
 }
@@ -930,10 +930,10 @@ Panner::reset (uint32_t nouts, uint32_t npans)
                if (changed || ((left == 0.5) && (right == 0.5))) {
                
                        front()->set_position (0.0);
-                       front()->automation().reset_default (0.0);
+                       front()->automation()->reset_default (0.0);
                        
                        back()->set_position (1.0);
-                       back()->automation().reset_default (1.0);
+                       back()->automation()->reset_default (1.0);
                        
                        changed = true;
                }
@@ -990,7 +990,7 @@ AutoState
 Panner::automation_state () const
 {
        if (!empty()) {
-               return front()->automation().automation_state ();
+               return front()->automation()->automation_state ();
        } else {
                return Off;
        }
@@ -1000,7 +1000,7 @@ AutoStyle
 Panner::automation_style () const
 {
        if (!empty()) {
-               return front()->automation().automation_style ();
+               return front()->automation()->automation_style ();
        } else {
                return Absolute;
        }
@@ -1026,7 +1026,7 @@ void
 Panner::clear_automation ()
 {
        for (vector<StreamPanner*>::iterator i = begin(); i != end(); ++i) {
-               (*i)->automation().clear ();
+               (*i)->automation()->clear ();
        }
        _session.set_dirty ();
 }      
@@ -1181,7 +1181,7 @@ bool
 Panner::touching () const
 {
        for (vector<StreamPanner*>::const_iterator i = begin(); i != end(); ++i) {
-               if ((*i)->automation().touching ()) {
+               if ((*i)->automation()->touching ()) {
                        return true;
                }
        }
index a842277845def26b7c3f84d5c836420f87c75506..08a8343fbb36b1870e137abf2d36518f8797857c 100644 (file)
@@ -142,8 +142,6 @@ void
 PluginInsert::init ()
 {
        set_automatable ();
-
-       set<uint32_t>::iterator s;
 }
 
 PluginInsert::~PluginInsert ()
@@ -151,22 +149,16 @@ PluginInsert::~PluginInsert ()
        GoingAway (); /* EMIT SIGNAL */
 }
 
-void
-PluginInsert::automation_list_creation_callback (ParamID which, AutomationList& alist)
-{
-  alist.automation_state_changed.connect (sigc::bind (mem_fun (*this, &PluginInsert::auto_state_changed), (which)));
-}
-
 void
 PluginInsert::auto_state_changed (ParamID which)
 {
        if (which.type() != PluginAutomation)
                return;
 
-       AutomationList* alist = automation_list (which);
+       boost::shared_ptr<AutomationControl> c = control (which);
 
-       if (alist && alist->automation_state() != Off) {
-               _plugins[0]->set_parameter (which.id(), alist->eval (_session.transport_frame()));
+       if (c && c->list()->automation_state() != Off) {
+               _plugins[0]->set_parameter (which.id(), c->list()->eval (_session.transport_frame()));
        }
 }
 
@@ -213,12 +205,23 @@ PluginInsert::is_generator() const
 void
 PluginInsert::set_automatable ()
 {
-       set<ParamID> a;
-       
-       a = _plugins.front()->automatable ();
+       set<ParamID> a = _plugins.front()->automatable ();
+
+       Plugin::ParameterDescriptor desc;
 
        for (set<ParamID>::iterator i = a.begin(); i != a.end(); ++i) {
-               can_automate (*i);
+               if (i->type() == PluginAutomation) {
+                       can_automate (*i);
+                       _plugins.front()->get_parameter_descriptor(i->id(), desc);
+                       boost::shared_ptr<AutomationList> list(new AutomationList(
+                                       *i,
+                                       (desc.min_unbound ? FLT_MIN : desc.lower),
+                                       (desc.max_unbound ? FLT_MAX : desc.upper),
+                                       _plugins.front()->default_value(i->id())));
+
+                       add_control(boost::shared_ptr<AutomationControl>(
+                                       new AutomationControl(_session, list)));
+               }
        }
 }
 
@@ -276,21 +279,20 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
 
        if (with_auto) {
 
-               map<ParamID,AutomationList*>::iterator li;
-               uint32_t n;
+               uint32_t n = 0;
                
-               for (n = 0, li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li, ++n) {
+               for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li, ++n) {
                        
-                       AutomationList& alist (*((*li).second));
+                       boost::shared_ptr<AutomationControl> c = li->second;
 
-                       if (alist.param_id().type() == PluginAutomation && alist.automation_playback()) {
+                       if (c->list()->param_id().type() == PluginAutomation && c->list()->automation_playback()) {
                                bool valid;
 
-                               float val = alist.rt_safe_eval (now, valid);                            
+                               float val = c->list()->rt_safe_eval (now, valid);                               
 
                                if (valid) {
                                        /* set the first plugin, the others will be set via signals */
-                                       _plugins[0]->set_parameter ((*li).first, val);
+                                       _plugins[0]->set_parameter (c->list()->param_id(), val);
                                }
 
                        } 
@@ -307,16 +309,15 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
 void
 PluginInsert::automation_snapshot (nframes_t now)
 {
-       map<ParamID,AutomationList*>::iterator li;
-       
-       for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) {
+       for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) {
                
-               AutomationList *alist = ((*li).second);
-               if (alist != 0 && alist->param_id().type() == PluginAutomation
-                               && alist->automation_write ()) {
+               boost::shared_ptr<AutomationControl> c = li->second;
+               
+               if (c->list() != 0 && c->list()->param_id().type() == PluginAutomation
+                               && c->list()->automation_write ()) {
                        
-                       float val = _plugins[0]->get_parameter ((*li).first);
-                       alist->rt_add (now, val);
+                       float val = _plugins[0]->get_parameter (c->list()->param_id());
+                       c->list()->rt_add (now, val);
                        _last_automation_snapshot = now;
                }
        }
@@ -325,14 +326,14 @@ PluginInsert::automation_snapshot (nframes_t now)
 void
 PluginInsert::transport_stopped (nframes_t now)
 {
-       map<ParamID,AutomationList*>::iterator li;
-
-       for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) {
-               AutomationList& alist (*(li->second));
-               alist.reposition_for_rt_add (now);
+       for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) {
+               
+               boost::shared_ptr<AutomationControl> c = li->second;
+               
+               c->list()->reposition_for_rt_add (now);
 
-               if (alist.param_id().type() == PluginAutomation && alist.automation_state() != Off) {
-                       _plugins[0]->set_parameter (li->first, alist.eval (now));
+               if (c->list()->param_id().type() == PluginAutomation && c->list()->automation_state() != Off) {
+                       _plugins[0]->set_parameter (li->first, c->list()->eval (now));
                }
        }
 }
@@ -390,8 +391,10 @@ PluginInsert::set_parameter (ParamID param, float val)
 
        _plugins[0]->set_parameter (param.id(), val);
        
-       if (automation_list (param) && automation_list (param)->automation_write()) {
-               automation_list (param)->add (_session.audible_frame(), val);
+       boost::shared_ptr<AutomationControl> c = control (param);
+       
+       if (c && c->list()->automation_write()) {
+               c->list()->add (_session.audible_frame(), val);
        }
 
        _session.set_dirty();
@@ -660,7 +663,7 @@ PluginInsert::state (bool full)
                child->add_child_nocopy (automation_list (*x).state (full));
                autonode->add_child_nocopy (*child);
                */
-               autonode->add_child_nocopy (automation_list (*x)->state (full));
+               autonode->add_child_nocopy (control(*x)->list()->state (full));
        }
 
        node.add_child_nocopy (*autonode);
@@ -791,7 +794,7 @@ PluginInsert::set_state(const XMLNode& node)
                        }
 
                        if (!child->children().empty()) {
-                               automation_list (ParamID(PluginAutomation, port_id), true)->set_state (*child->children().front());
+                               control (ParamID(PluginAutomation, port_id), true)->list()->set_state (*child->children().front());
                        } else {
                                if ((cprop = child->property("auto")) != 0) {
                                        
@@ -799,13 +802,13 @@ PluginInsert::set_state(const XMLNode& node)
 
                                        int x;
                                        sscanf (cprop->value().c_str(), "0x%x", &x);
-                                       automation_list (ParamID(PluginAutomation, port_id), true)->set_automation_state (AutoState (x));
+                                       control (ParamID(PluginAutomation, port_id), true)->list()->set_automation_state (AutoState (x));
 
                                } else {
                                        
                                        /* missing */
                                        
-                                       automation_list (ParamID(PluginAutomation, port_id), true)->set_automation_state (Off);
+                                       control (ParamID(PluginAutomation, port_id), true)->list()->set_automation_state (Off);
                                }
                        }
 
index b192eb85c1fee556dc622f7f281dbd954dd6a9ab..76c780f2dbba9efffb7fe2f47772dccbe47c509d 100644 (file)
@@ -157,8 +157,8 @@ Processor::state (bool full_state)
 
                XMLNode& automation = Automatable::get_automation_state(); 
                
-               for (set<ParamID>::iterator x = _visible_parameter_automation.begin(); x != _visible_parameter_automation.end(); ++x) {
-                       if (x != _visible_parameter_automation.begin()) {
+               for (set<ParamID>::iterator x = _visible_controls.begin(); x != _visible_controls.end(); ++x) {
+                       if (x != _visible_controls.begin()) {
                                sstr << ' ';
                        }
                        sstr << *x;
@@ -202,7 +202,7 @@ Processor::set_state (const XMLNode& node)
                                uint32_t what;
                                stringstream sstr;
 
-                               _visible_parameter_automation.clear ();
+                               _visible_controls.clear ();
                                
                                sstr << prop->value();
                                while (1) {
index 507d33761954ec375ac6bbac636a41bfc935e3cd..e8e469b44633ab6c136f810770480ad6e0991999 100644 (file)
@@ -58,16 +58,16 @@ uint32_t Route::order_key_cnt = 0;
 Route::Route (Session& sess, string name, int input_min, int input_max, int output_min, int output_max, Flag flg, DataType default_type)
        : IO (sess, name, input_min, input_max, output_min, output_max, default_type),
          _flags (flg),
-         _solo_control (X_("solo"), *this, ToggleControllable::SoloControl),
-         _mute_control (X_("mute"), *this, ToggleControllable::MuteControl)
+         _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl)),
+         _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl))
 {
        init ();
 }
 
 Route::Route (Session& sess, const XMLNode& node, DataType default_type)
        : IO (sess, *node.child ("IO"), default_type),
-         _solo_control (X_("solo"), *this, ToggleControllable::SoloControl),
-         _mute_control (X_("mute"), *this, ToggleControllable::MuteControl)
+         _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl)),
+         _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl))
 {
        init ();
        _set_state (node, false);
@@ -177,33 +177,33 @@ Route::set_gain (gain_t val, void *src)
                
                if (_mix_group->is_relative()) {
                        
-                       
-                       gain_t usable_gain  = gain();
+                       gain_t usable_gain = gain();
                        if (usable_gain < 0.000001f) {
-                               usable_gain=0.000001f;
+                               usable_gain = 0.000001f;
                        }
                                                
                        gain_t delta = val;
                        if (delta < 0.000001f) {
-                               delta=0.000001f;
+                               delta = 0.000001f;
                        }
 
                        delta -= usable_gain;
 
-                       if (delta == 0.0f) return;
+                       if (delta == 0.0f)
+                               return;
 
                        gain_t factor = delta / usable_gain;
 
                        if (factor > 0.0f) {
                                factor = _mix_group->get_max_factor(factor);
                                if (factor == 0.0f) {
-                                       gain_changed (src);
+                                       _gain_control->Changed(); /* EMIT SIGNAL */
                                        return;
                                }
                        } else {
                                factor = _mix_group->get_min_factor(factor);
                                if (factor == 0.0f) {
-                                       gain_changed (src);
+                                       _gain_control->Changed(); /* EMIT SIGNAL */
                                        return;
                                }
                        }
@@ -726,7 +726,7 @@ Route::set_solo (bool yn, void *src)
        if (_soloed != yn) {
                _soloed = yn;
                solo_changed (src); /* EMIT SIGNAL */
-               _solo_control.Changed (); /* EMIT SIGNAL */
+               _solo_control->Changed (); /* EMIT SIGNAL */
        }
 }
 
@@ -763,7 +763,7 @@ Route::set_mute (bool yn, void *src)
                _muted = yn;
                mute_changed (src); /* EMIT SIGNAL */
                
-               _mute_control.Changed (); /* EMIT SIGNAL */
+               _mute_control->Changed (); /* EMIT SIGNAL */
                
                Glib::Mutex::Lock lm (declick_lock);
                desired_mute_gain = (yn?0.0f:1.0f);
@@ -1491,8 +1491,8 @@ Route::state(bool full_state)
        node->add_property ("order-keys", order_string);
 
        node->add_child_nocopy (IO::state (full_state));
-       node->add_child_nocopy (_solo_control.get_state ());
-       node->add_child_nocopy (_mute_control.get_state ());
+       node->add_child_nocopy (_solo_control->get_state ());
+       node->add_child_nocopy (_mute_control->get_state ());
 
        XMLNode* remote_control_node = new XMLNode (X_("remote_control"));
        snprintf (buf, sizeof (buf), "%d", _remote_control_id);
@@ -1853,12 +1853,12 @@ Route::_set_state (const XMLNode& node, bool call_base)
                } else if (child->name() == X_("controllable") && (prop = child->property("name")) != 0) {
                        
                        if (prop->value() == "solo") {
-                               _solo_control.set_state (*child);
-                               _session.add_controllable (&_solo_control);
+                               _solo_control->set_state (*child);
+                               _session.add_controllable (_solo_control);
                        }
                        else if (prop->value() == "mute") {
-                               _mute_control.set_state (*child);
-                               _session.add_controllable (&_mute_control);
+                               _mute_control->set_state (*child);
+                               _session.add_controllable (_mute_control);
                        }
                }
                else if (child->name() == X_("remote_control")) {
@@ -2038,7 +2038,7 @@ Route::set_control_outs (const vector<string>& ports)
                _control_outs = 0;
        }
 
-       if (control() || master()) {
+       if (is_control() || is_master()) {
                /* no control outs for these two special busses */
                return 0;
        }
@@ -2393,10 +2393,9 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nfra
                
                if (am.locked() && _session.transport_rolling()) {
                        
-                       ARDOUR::AutomationList& gain_auto = gain_automation();
-                       
-                       if (gain_auto.automation_playback()) {
-                               apply_gain_automation = gain_auto.curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
+                       if (_gain_control->list()->automation_playback()) {
+                               apply_gain_automation = _gain_control->list()->curve().rt_safe_get_vector (
+                                               start_frame, end_frame, _session.gain_automation_buffer(), nframes);
                        }
                }
        }
index c40dd6fd7a175cadca5e947b80fcb0d3c366215a..d5c2817f54ceec00910ae13b326ff0354483bbf7 100644 (file)
@@ -122,7 +122,8 @@ Session::Session (AudioEngine &eng,
          routes (new RouteList),
          auditioner ((Auditioner*) 0),
          _click_io ((IO*) 0),
-         main_outs (0)
+         main_outs (0),
+         _automation_interval (0)
 {
        if (!eng.connected()) {
                throw failed_constructor();
@@ -221,7 +222,8 @@ Session::Session (AudioEngine &eng,
          _send_smpte_update (false),
          diskstreams (new DiskstreamList),
          routes (new RouteList),
-         main_outs (0)
+         main_outs (0),
+         _automation_interval (0)
 
 {
        if (!eng.connected()) {
@@ -1267,7 +1269,7 @@ Session::set_frame_rate (nframes_t frames_per_second)
 
        sync_time_vars();
 
-       Route::set_automation_interval ((nframes_t) ceil ((double) frames_per_second * 0.25));
+       _automation_interval = ((nframes_t) ceil ((double) frames_per_second * 0.25));
 
        // XXX we need some equivalent to this, somehow
        // SndFileSource::setup_standard_crossfades (frames_per_second);
@@ -1504,7 +1506,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
 
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                        if (dynamic_cast<MidiTrack*>((*i).get()) != 0) {
-                               if (!(*i)->hidden()) {
+                               if (!(*i)->is_hidden()) {
                                        n++;
                                        channels_used += (*i)->n_inputs().n_midi();
                                }
@@ -1585,7 +1587,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
 
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                        if (dynamic_cast<AudioTrack*>((*i).get()) != 0) {
-                               if (!(*i)->hidden()) {
+                               if (!(*i)->is_hidden()) {
                                        n++;
                                        channels_used += (*i)->n_inputs().n_audio();
                                }
@@ -1775,7 +1777,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
 
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                        if (dynamic_cast<AudioTrack*>((*i).get()) == 0) {
-                               if (!(*i)->hidden() && (*i)->name() != _("master")) {
+                               if (!(*i)->is_hidden() && (*i)->name() != _("master")) {
                                        bus_id++;
                                }
                        }
@@ -1892,11 +1894,11 @@ Session::add_routes (RouteList& new_routes, bool save)
                (*x)->output_changed.connect (mem_fun (*this, &Session::set_worst_io_latencies_x));
                (*x)->processors_changed.connect (bind (mem_fun (*this, &Session::update_latency_compensation), false, false));
                
-               if ((*x)->master()) {
+               if ((*x)->is_master()) {
                        _master_out = (*x);
                }
                
-               if ((*x)->control()) {
+               if ((*x)->is_control()) {
                        _control_out = (*x);
                } 
        }
@@ -3436,7 +3438,7 @@ Session::set_all_solo (bool yn)
        shared_ptr<RouteList> r = routes.reader ();
        
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if (!(*i)->hidden()) {
+               if (!(*i)->is_hidden()) {
                        (*i)->set_solo (yn, this);
                }
        }
@@ -3450,7 +3452,7 @@ Session::set_all_mute (bool yn)
        shared_ptr<RouteList> r = routes.reader ();
        
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if (!(*i)->hidden()) {
+               if (!(*i)->is_hidden()) {
                        (*i)->set_mute (yn, this);
                }
        }
index dc71a40ca218ea0e32c42cf4291ccf4422306014..44b63e08756bee087038e7777b382db7ddd2eb51 100644 (file)
@@ -101,7 +101,7 @@ Session::no_roll (nframes_t nframes, nframes_t offset)
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                
-               if ((*i)->hidden()) {
+               if ((*i)->is_hidden()) {
                        continue;
                }
                
@@ -140,7 +140,7 @@ Session::process_routes (nframes_t nframes, nframes_t offset)
 
                int ret;
 
-               if ((*i)->hidden()) {
+               if ((*i)->is_hidden()) {
                        continue;
                }
 
@@ -186,7 +186,7 @@ Session::silent_process_routes (nframes_t nframes, nframes_t offset)
 
                int ret;
 
-               if ((*i)->hidden()) {
+               if ((*i)->is_hidden()) {
                        continue;
                }
 
@@ -819,7 +819,7 @@ Session::process_audition (nframes_t nframes)
        boost::shared_ptr<RouteList> r = routes.reader ();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if (!(*i)->hidden()) {
+               if (!(*i)->is_hidden()) {
                        (*i)->silence (nframes, 0);
                }
        }
index 65c48a22967960e180023277e1cd0fa74b1a9a1b..2924210e0c450105935eb0c10d873dbe2e427818 100644 (file)
@@ -939,7 +939,7 @@ Session::state(bool full_state)
                public_order.sort (cmp);
                
                for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
-                       if (!(*i)->hidden()) {
+                       if (!(*i)->is_hidden()) {
                                if (full_state) {
                                        child->add_child_nocopy ((*i)->get_state());
                                } else {
@@ -2055,7 +2055,7 @@ Session::get_global_route_boolean (bool (Route::*method)(void) const)
        boost::shared_ptr<RouteList> r = routes.reader ();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if (!(*i)->hidden()) {
+               if (!(*i)->is_hidden()) {
                        RouteBooleanState v;
                        
                        v.first =* i;
@@ -2076,7 +2076,7 @@ Session::get_global_route_metering ()
        boost::shared_ptr<RouteList> r = routes.reader ();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if (!(*i)->hidden()) {
+               if (!(*i)->is_hidden()) {
                        RouteMeterState v;
                        
                        v.first =* i;
@@ -2622,7 +2622,7 @@ Session::set_deletion_in_progress ()
 }
 
 void
-Session::add_controllable (Controllable* c)
+Session::add_controllable (boost::shared_ptr<Controllable> c)
 {
        /* this adds a controllable to the list managed by the Session.
           this is a subset of those managed by the Controllable class
@@ -2633,6 +2633,8 @@ Session::add_controllable (Controllable* c)
        Glib::Mutex::Lock lm (controllables_lock);
        controllables.insert (c);
 }
+       
+struct null_deleter { void operator()(void const *) const {} };
 
 void
 Session::remove_controllable (Controllable* c)
@@ -2643,14 +2645,15 @@ Session::remove_controllable (Controllable* c)
 
        Glib::Mutex::Lock lm (controllables_lock);
 
-       Controllables::iterator x = controllables.find (c);
+       Controllables::iterator x = controllables.find(
+                boost::shared_ptr<Controllable>(c, null_deleter()));
 
        if (x != controllables.end()) {
                controllables.erase (x);
        }
 }      
 
-Controllable*
+boost::shared_ptr<Controllable>
 Session::controllable_by_id (const PBD::ID& id)
 {
        Glib::Mutex::Lock lm (controllables_lock);
@@ -2661,7 +2664,7 @@ Session::controllable_by_id (const PBD::ID& id)
                }
        }
 
-       return 0;
+       return boost::shared_ptr<Controllable>();
 }
 
 void 
index 52f6346789b3de1db2b42fd6bb4ca149e9dbbbf3..c122989b68ee6875cfc18792e249b08b18ed44f9 100644 (file)
@@ -363,7 +363,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
        boost::shared_ptr<RouteList> r = routes.reader ();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if (!(*i)->hidden()) {
+               if (!(*i)->is_hidden()) {
                        (*i)->set_pending_declick (0);
                }
        }
@@ -1262,7 +1262,7 @@ Session::update_latency_compensation (bool with_stop, bool abort)
                        update_jack = true;
                }
 
-               if (!(*i)->hidden() && ((*i)->active())) {
+               if (!(*i)->is_hidden() && ((*i)->active())) {
                        _worst_track_latency = max (_worst_track_latency, track_latency);
                }
        } 
index dd6d7a2067bebfc102af3eb0a253c0ad7de349dd..052105cc855148d3c9dd18ad01d6fedee17a3354 100644 (file)
@@ -40,7 +40,7 @@ using namespace PBD;
 
 Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, DataType default_type)
        : Route (sess, name, 1, -1, -1, -1, flag, default_type)
-       , _rec_enable_control (*this)
+       , _rec_enable_control (new RecEnableControllable(*this))
 {
        _declickable = true;
        _freeze_record.state = NoFreeze;
@@ -50,7 +50,7 @@ Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, Data
 
 Track::Track (Session& sess, const XMLNode& node, DataType default_type)
        : Route (sess, node)
-       , _rec_enable_control (*this)
+       , _rec_enable_control (new RecEnableControllable(*this))
 {
        _freeze_record.state = NoFreeze;
        _declickable = true;
@@ -188,7 +188,7 @@ Track::set_record_enable (bool yn, void *src)
                set_meter_point (_saved_meter_point, this);
        }
 
-       _rec_enable_control.Changed ();
+       _rec_enable_control->Changed ();
 }
 
 
index c3c15b4281bf47ff229da0b90f3b6f3be3a054cb..142d22417185efb8bb9080ac8bb03174e23a7d30 100644 (file)
@@ -349,7 +349,8 @@ BarController::expose (GdkEventExpose* event)
                char buf[64];
                buf[0] = '\0';
 
-               label_callback (buf, 64);
+               if (label_callback)
+                       label_callback (buf, 64);
 
                if (buf[0] != '\0') {
 
index c91f4c8a06a495973f499b33a760ac08f95a4a90..ba2e1f3f7b6b504a48c054ba620cd98c8441b7c7 100644 (file)
@@ -32,7 +32,10 @@ namespace Gtkmm2ext {
 class BarController : public Gtk::Frame
 {
   public:
-       BarController (Gtk::Adjustment& adj, PBD::Controllable&, sigc::slot<void,char*,unsigned int>);
+       typedef sigc::slot<void,char*,unsigned int> LabelCallback;
+
+       BarController (Gtk::Adjustment& adj, PBD::Controllable&, LabelCallback lc = LabelCallback());
+
        virtual ~BarController () {}
        
        enum Style {
@@ -40,6 +43,7 @@ class BarController : public Gtk::Frame
                RightToLeft,
                Line,
                CenterOut,
+               
                TopToBottom,
                BottomToTop
        };
@@ -64,7 +68,7 @@ class BarController : public Gtk::Frame
        Gtk::Adjustment&    adjustment;
        BindingProxy        binding_proxy;
        Gtk::DrawingArea    darea;
-       sigc::slot<void,char*,unsigned int> label_callback;
+       LabelCallback       label_callback;
        Glib::RefPtr<Pango::Layout> layout;
        Style              _style;
        bool                grabbed;
index 16b35397cfd4bcc0996cff57f0ea675873a02ea0..5ef28d4549b6e7685dcee77c58ad96d901bb9fd0 100644 (file)
@@ -228,9 +228,9 @@ MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes()
                Route & route = **it;
                if (
                                route.active()
-                               && !route.master()
-                               && !route.hidden()
-                               && !route.control()
+                               && !route.is_master()
+                               && !route.is_hidden()
+                               && !route.is_control()
                                && remote_ids.find( route.remote_control_id() ) == remote_ids.end()
                )
                {
@@ -1019,7 +1019,7 @@ void MackieControlProtocol::notify_panner_changed( RouteSignal * route_signal )
 // TODO handle plugin automation polling
 void MackieControlProtocol::update_automation( RouteSignal & rs )
 {
-       ARDOUR::AutoState gain_state = rs.route().gain_automation().automation_state();
+       ARDOUR::AutoState gain_state = rs.route().gain_control()->list()->automation_state();
        if ( gain_state == Touch || gain_state == Play )
        {
                notify_gain_changed( &rs );
index 85c234436af75d783e66a8832f95734531a67cff..b01b5e0cf5f99ce59cae0a9464573291b5a641b6 100644 (file)
@@ -20,6 +20,7 @@
 #include <ardour/route.h>
 #include <ardour/track.h>
 #include <ardour/panner.h>
+#include <ardour/types.h>
 
 #include "mackie_control_protocol.h"
 
@@ -30,13 +31,13 @@ using namespace Mackie;
 void RouteSignal::connect()
 {
        if ( _strip.has_solo() )
-               _solo_changed_connection = _route.solo_control().Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_solo_changed ), this ) );
+               _solo_changed_connection = _route.solo_control()->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_solo_changed ), this ) );
        
        if ( _strip.has_mute() )
-               _mute_changed_connection = _route.mute_control().Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_mute_changed ), this ) );
+               _mute_changed_connection = _route.mute_control()->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_mute_changed ), this ) );
        
        if ( _strip.has_gain() )
-               _gain_changed_connection = _route.gain_control().Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_gain_changed ), this ) );
+               _gain_changed_connection = _route.control(ARDOUR::GainAutomation)->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_gain_changed ), this ) );
                
        _name_changed_connection = _route.NameChanged.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_name_changed ), this ) );
        
@@ -48,7 +49,7 @@ void RouteSignal::connect()
        try
        {
                _record_enable_changed_connection =
-                       dynamic_cast<ARDOUR::Track&>( _route ).rec_enable_control().Changed
+                       dynamic_cast<ARDOUR::Track&>( _route ).rec_enable_control()->Changed
                                .connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_record_enable_changed ), this ) )
                ;
        }