Further automation refactoring - bring in the concept of Controllable, work towards

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
This commit is contained in:
David Robillard 2007-06-29 04:02:58 +00:00
parent f8697ed223
commit 24ccaac67e
80 changed files with 1202 additions and 811 deletions

View file

@ -101,6 +101,7 @@ automation_midi_cc_line.cc
automation_line.cc automation_line.cc
automation_pan_line.cc automation_pan_line.cc
automation_time_axis.cc automation_time_axis.cc
automation_controller.cc
midi_time_axis.cc midi_time_axis.cc
midi_streamview.cc midi_streamview.cc
axis_view.cc axis_view.cc

View file

@ -10,14 +10,14 @@
; (gtk_accel_path "<Actions>/Editor/Autoconnect" "") ; (gtk_accel_path "<Actions>/Editor/Autoconnect" "")
; (gtk_accel_path "<Actions>/Editor/Edit" "") ; (gtk_accel_path "<Actions>/Editor/Edit" "")
(gtk_accel_path "<Actions>/Editor/playhead-to-previous-region-end" "<Control>comma") (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>/options/MeterFalloffFaster" "")
(gtk_accel_path "<Actions>/Transport/ToggleRollForgetCapture" "<Control>space") (gtk_accel_path "<Actions>/Transport/ToggleRollForgetCapture" "<Control>space")
(gtk_accel_path "<Actions>/Transport/Record" "<Shift>r") (gtk_accel_path "<Actions>/Transport/Record" "<Shift>r")
; (gtk_accel_path "<Actions>/RegionList/SortByRegionLength" "") ; (gtk_accel_path "<Actions>/RegionList/SortByRegionLength" "")
; (gtk_accel_path "<Actions>/options/MeterFalloffSlowest" "") ; (gtk_accel_path "<Actions>/options/MeterFalloffSlowest" "")
; (gtk_accel_path "<Actions>/Editor/playhead-to-previous-region-sync" "") ; (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>/RegionList/SortByRegionPosition" "")
; (gtk_accel_path "<Actions>/Editor/ZoomFocus" "") ; (gtk_accel_path "<Actions>/Editor/ZoomFocus" "")
; (gtk_accel_path "<Actions>/options/MeterFalloffSlow" "") ; (gtk_accel_path "<Actions>/options/MeterFalloffSlow" "")
@ -28,7 +28,7 @@
; (gtk_accel_path "<Actions>/Zoom/zoom-focus-playhead" "") ; (gtk_accel_path "<Actions>/Zoom/zoom-focus-playhead" "")
; (gtk_accel_path "<Actions>/Editor/center-edit-cursor" "") ; (gtk_accel_path "<Actions>/Editor/center-edit-cursor" "")
; (gtk_accel_path "<Actions>/Editor/Monitoring" "") ; (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>/options/LatchedRecordEnable" "")
; (gtk_accel_path "<Actions>/Transport/TogglePunchIn" "") ; (gtk_accel_path "<Actions>/Transport/TogglePunchIn" "")
; (gtk_accel_path "<Actions>/ShuttleActions/SetShuttleUnitsPercentage" "") ; (gtk_accel_path "<Actions>/ShuttleActions/SetShuttleUnitsPercentage" "")
@ -96,9 +96,9 @@
; (gtk_accel_path "<Actions>/Zoom/zoom-focus-edit" "") ; (gtk_accel_path "<Actions>/Zoom/zoom-focus-edit" "")
(gtk_accel_path "<Actions>/Editor/playhead-to-previous-region-start" "comma") (gtk_accel_path "<Actions>/Editor/playhead-to-previous-region-start" "comma")
; (gtk_accel_path "<Actions>/Editor/EditCursorMovementOptions" "") ; (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>/Editor/addExternalAudioAsTapeTrack" "")
; (gtk_accel_path "<Actions>/redirectmenu/paste" "") ; (gtk_accel_path "<Actions>/processormenu/paste" "")
; (gtk_accel_path "<Actions>/Editor/Smpte25" "") ; (gtk_accel_path "<Actions>/Editor/Smpte25" "")
; (gtk_accel_path "<Actions>/options/RegionEquivalentsOverlap" "") ; (gtk_accel_path "<Actions>/options/RegionEquivalentsOverlap" "")
; (gtk_accel_path "<Actions>/Main/MeteringFallOffRate" "") ; (gtk_accel_path "<Actions>/Main/MeteringFallOffRate" "")
@ -123,7 +123,7 @@
(gtk_accel_path "<Actions>/Editor/align-regions-sync-relative" "a") (gtk_accel_path "<Actions>/Editor/align-regions-sync-relative" "a")
; (gtk_accel_path "<Actions>/Editor/EditSelectRegionOptions" "") ; (gtk_accel_path "<Actions>/Editor/EditSelectRegionOptions" "")
(gtk_accel_path "<Actions>/Editor/crop" "c") (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/ToggleGeneric MIDISurfaceSubMenu" "")
; (gtk_accel_path "<Actions>/Editor/MeterFalloff" "") ; (gtk_accel_path "<Actions>/Editor/MeterFalloff" "")
; (gtk_accel_path "<Actions>/RegionList/rlRemove" "") ; (gtk_accel_path "<Actions>/RegionList/rlRemove" "")
@ -136,7 +136,7 @@
(gtk_accel_path "<Actions>/Editor/align-regions-sync" "<Mod2>a") (gtk_accel_path "<Actions>/Editor/align-regions-sync" "<Mod2>a")
; (gtk_accel_path "<Actions>/Main/Windows" "") ; (gtk_accel_path "<Actions>/Main/Windows" "")
; (gtk_accel_path "<Actions>/Main/CleanupUnused" "") ; (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>/options/SoloViaBus" "")
(gtk_accel_path "<Actions>/MouseMode/set-mouse-mode-zoom" "z") (gtk_accel_path "<Actions>/MouseMode/set-mouse-mode-zoom" "z")
; (gtk_accel_path "<Actions>/RegionList/rlAudition" "") ; (gtk_accel_path "<Actions>/RegionList/rlAudition" "")
@ -202,7 +202,7 @@
(gtk_accel_path "<Actions>/Editor/temporal-zoom-in" "minus") (gtk_accel_path "<Actions>/Editor/temporal-zoom-in" "minus")
; (gtk_accel_path "<Actions>/JACK/Latency" "") ; (gtk_accel_path "<Actions>/JACK/Latency" "")
(gtk_accel_path "<Actions>/Editor/edit-cursor-to-range-end" "F2") (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>/RegionList/rlShowAuto" "")
(gtk_accel_path "<Actions>/Editor/select-all-before-playhead" "<Control>p") (gtk_accel_path "<Actions>/Editor/select-all-before-playhead" "<Control>p")
; (gtk_accel_path "<Actions>/Editor/addExistingAudioFiles" "") ; (gtk_accel_path "<Actions>/Editor/addExistingAudioFiles" "")
@ -231,7 +231,7 @@
(gtk_accel_path "<Actions>/Common/goto-mixer" "<Alt>m") (gtk_accel_path "<Actions>/Common/goto-mixer" "<Alt>m")
; (gtk_accel_path "<Actions>/Editor/addExternalAudioToTrack" "") ; (gtk_accel_path "<Actions>/Editor/addExternalAudioToTrack" "")
; (gtk_accel_path "<Actions>/RegionList/SortBySourceFileCreationDate" "") ; (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/extend-range-to-start-of-region" "leftanglebracket")
; (gtk_accel_path "<Actions>/Editor/PullupMinus1" "") ; (gtk_accel_path "<Actions>/Editor/PullupMinus1" "")
; (gtk_accel_path "<Actions>/Editor/snap-normal" "") ; (gtk_accel_path "<Actions>/Editor/snap-normal" "")
@ -239,7 +239,7 @@
(gtk_accel_path "<Actions>/Common/ToggleBigClock" "<Alt>b") (gtk_accel_path "<Actions>/Common/ToggleBigClock" "<Alt>b")
; (gtk_accel_path "<Actions>/Snap/snap-to-asixteenthbeat" "") ; (gtk_accel_path "<Actions>/Snap/snap-to-asixteenthbeat" "")
(gtk_accel_path "<Actions>/Editor/select-all-in-punch-range" "<Control>d") (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>/Editor/duplicate-region" "d")
; (gtk_accel_path "<Actions>/JACK/JACKLatency2048" "") ; (gtk_accel_path "<Actions>/JACK/JACKLatency2048" "")
; (gtk_accel_path "<Actions>/Editor/ToggleWaveformsWhileRecording" "") ; (gtk_accel_path "<Actions>/Editor/ToggleWaveformsWhileRecording" "")
@ -248,8 +248,8 @@
; (gtk_accel_path "<Actions>/options/FileHeaderFormatWAVE" "") ; (gtk_accel_path "<Actions>/options/FileHeaderFormatWAVE" "")
(gtk_accel_path "<Actions>/Transport/GotoZero" "KP_Insert") (gtk_accel_path "<Actions>/Transport/GotoZero" "KP_Insert")
(gtk_accel_path "<Actions>/Transport/GotoEnd" "End") (gtk_accel_path "<Actions>/Transport/GotoEnd" "End")
; (gtk_accel_path "<Actions>/redirectmenu/cut" "") ; (gtk_accel_path "<Actions>/processormenu/cut" "")
; (gtk_accel_path "<Actions>/redirectmenu/newinsert" "") ; (gtk_accel_path "<Actions>/processormenu/newinsert" "")
; (gtk_accel_path "<Actions>/options/UseMMC" "") ; (gtk_accel_path "<Actions>/options/UseMMC" "")
; (gtk_accel_path "<Actions>/options/MeterFalloffOff" "") ; (gtk_accel_path "<Actions>/options/MeterFalloffOff" "")
(gtk_accel_path "<Actions>/MouseMode/set-mouse-mode-object" "o") (gtk_accel_path "<Actions>/MouseMode/set-mouse-mode-object" "o")
@ -296,7 +296,7 @@
; (gtk_accel_path "<Actions>/Editor/toggle-xfades-active" "") ; (gtk_accel_path "<Actions>/Editor/toggle-xfades-active" "")
; (gtk_accel_path "<Actions>/Snap/snap-to-bar" "") ; (gtk_accel_path "<Actions>/Snap/snap-to-bar" "")
; (gtk_accel_path "<Actions>/Editor/LayerLaterHigher" "") ; (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>/Editor/editor-copy" "<Control>c")
; (gtk_accel_path "<Actions>/Snap/snap-to-quarters" "") ; (gtk_accel_path "<Actions>/Snap/snap-to-quarters" "")
(gtk_accel_path "<Actions>/Editor/temporal-zoom-out" "equal") (gtk_accel_path "<Actions>/Editor/temporal-zoom-out" "equal")
@ -306,13 +306,13 @@
; (gtk_accel_path "<Actions>/options/OutputAutoConnectManual" "") ; (gtk_accel_path "<Actions>/options/OutputAutoConnectManual" "")
; (gtk_accel_path "<Actions>/Snap/snap-to-region-sync" "") ; (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>/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/ToggleGeneric MIDISurfaceFeedback" "")
; (gtk_accel_path "<Actions>/Editor/PullupPlus4Minus1" "") ; (gtk_accel_path "<Actions>/Editor/PullupPlus4Minus1" "")
; (gtk_accel_path "<Actions>/JACK/JACKLatency512" "") ; (gtk_accel_path "<Actions>/JACK/JACKLatency512" "")
(gtk_accel_path "<Actions>/Editor/edit-cursor-to-next-region-end" "<Control>bracketright") (gtk_accel_path "<Actions>/Editor/edit-cursor-to-next-region-end" "<Control>bracketright")
; (gtk_accel_path "<Actions>/Main/Recent" "") ; (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/InputAutoConnectManual" "")
; (gtk_accel_path "<Actions>/options/MeterHoldLong" "") ; (gtk_accel_path "<Actions>/options/MeterHoldLong" "")
; (gtk_accel_path "<Actions>/Snap/snap-to-seconds" "") ; (gtk_accel_path "<Actions>/Snap/snap-to-seconds" "")

View file

@ -374,7 +374,7 @@
</menu> </menu>
</menubar> </menubar>
<popup name='redirectmenu'> <popup name='processormenu'>
<menuitem action='newplugin'/> <menuitem action='newplugin'/>
<menuitem action='newinsert'/> <menuitem action='newinsert'/>
<menuitem action='newsend'/> <menuitem action='newsend'/>

View file

@ -171,11 +171,11 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfd)
setup_fade_handle_positions (); setup_fade_handle_positions ();
string foo = _region->name(); string line_name = _region->name();
foo += ':'; line_name += ':';
foo += "gain"; 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)) { if (!(_flags & EnvelopeVisible)) {
gain_line->hide (); gain_line->hide ();
@ -489,7 +489,7 @@ AudioRegionView::reset_fade_shapes ()
void void
AudioRegionView::reset_fade_in_shape () 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 void
@ -534,7 +534,7 @@ AudioRegionView::reset_fade_in_shape_width (nframes_t width)
fade_in_shape->show(); fade_in_shape->show();
float curve[npoints]; 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); points = get_canvas_points ("fade in shape", npoints+3);
@ -573,7 +573,7 @@ AudioRegionView::reset_fade_in_shape_width (nframes_t width)
void void
AudioRegionView::reset_fade_out_shape () 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 void
@ -620,7 +620,7 @@ AudioRegionView::reset_fade_out_shape_width (nframes_t width)
fade_out_shape->show(); fade_out_shape->show();
float curve[npoints]; 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) { if (_height > NAME_HIGHLIGHT_THRESH) {
h = _height - NAME_HIGHLIGHT_SIZE; 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); gain_line->view_to_model_y (y);
trackview.session().begin_reversible_command (_("add gain control point")); 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()) { if (!audio_region()->envelope_active()) {
XMLNode &region_before = audio_region()->get_state(); 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)); 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(); XMLNode &after = audio_region()->envelope()->get_state();
trackview.session().add_command (new MementoCommand<AutomationList>(audio_region()->envelope(), &before, &after)); trackview.session().add_command (new MementoCommand<AutomationList>(*audio_region()->envelope().get(), &before, &after));
trackview.session().commit_reversible_command (); trackview.session().commit_reversible_command ();
} }
@ -961,7 +961,7 @@ void
AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
{ {
ControlPoint *cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point")); ControlPoint *cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"));
audio_region()->envelope().erase (cp->model); audio_region()->envelope()->erase (cp->model);
} }
void void

View file

@ -284,18 +284,25 @@ void
AudioTimeAxisView::create_automation_child (ParamID param) AudioTimeAxisView::create_automation_child (ParamID param)
{ {
if (param.type() == GainAutomation) { 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, GainAutomationTimeAxisView* gain_track = new GainAutomationTimeAxisView (_session,
_route, _route,
editor, editor,
*this, *this,
parent_canvas, parent_canvas,
_route->describe_parameter(param), _route->describe_parameter(param),
_route->gain_automation()); c);
AutomationLine* line = new AutomationGainLine ("automation gain", AutomationLine* line = new AutomationGainLine ("automation gain",
*gain_track, *gain_track,
*gain_track->canvas_display, *gain_track->canvas_display,
_route->gain_automation()); c->list());
line->set_line_color (Config->canvasvar_AutomationLine.get()); line->set_line_color (Config->canvasvar_AutomationLine.get());

View file

@ -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();
}

View file

@ -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__ */

View file

@ -30,7 +30,7 @@ using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; 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) : AutomationLine (name, tv, parent, l)
{ {

View file

@ -30,7 +30,7 @@ class TimeAxisView;
class AutomationGainLine : public AutomationLine class AutomationGainLine : public AutomationLine
{ {
public: 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 view_to_model_y (double&);
void model_to_view_y (double&); void model_to_view_y (double&);

View file

@ -57,7 +57,7 @@ using namespace Gnome; // for Canvas
ControlPoint::ControlPoint (AutomationLine& al) ControlPoint::ControlPoint (AutomationLine& al)
: line (al) : line (al)
{ {
model = al.the_list().end(); model = al.the_list()->end();
view_index = 0; view_index = 0;
can_slide = true; can_slide = true;
_x = 0; _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), : trackview (tv),
_name (name), _name (name),
alist (al), alist (al),
@ -245,10 +245,9 @@ AutomationLine::AutomationLine (const string & name, TimeAxisView& tv, ArdourCan
line->signal_event().connect (mem_fun (*this, &AutomationLine::event_handler)); line->signal_event().connect (mem_fun (*this, &AutomationLine::event_handler));
alist.StateChanged.connect (mem_fun(*this, &AutomationLine::list_changed)); alist->StateChanged.connect (mem_fun(*this, &AutomationLine::list_changed));
trackview.session().register_with_memento_command_factory(alist.id(), this);
trackview.session().register_with_memento_command_factory(alist->id(), this);
} }
AutomationLine::~AutomationLine () AutomationLine::~AutomationLine ()
@ -612,7 +611,7 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
view_index = 0; 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 tx = points[pi].x;
double ty = points[pi].y; 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()->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_x = x;
drag_distance = 0; drag_distance = 0;
@ -872,7 +871,7 @@ AutomationLine::end_drag (ControlPoint* cp)
return; return;
} }
alist.freeze (); alist->freeze ();
if (cp) { if (cp) {
sync_model_with_view_point (*cp, did_push, drag_distance); 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); sync_model_with_view_line (line_drag_cp1, line_drag_cp2);
} }
alist.thaw (); alist->thaw ();
update_pending = false; 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()->commit_reversible_command ();
trackview.editor.current_session()->set_dirty (); trackview.editor.current_session()->set_dirty ();
} }
@ -919,14 +918,14 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int
/* interpolate */ /* interpolate */
if (y_delta || x_delta) { 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 */ /* change the primary point */
update_pending = true; update_pending = true;
alist.modify (cp.model, mr.xval, mr.yval); alist->modify (cp.model, mr.xval, mr.yval);
/* change later points */ /* 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 */ /* all later points move by the same distance along the x-axis as the main point */
if (delta) { if (delta) {
alist.modify (i, (*i)->when + distance, (*i)->value + delta); alist->modify (i, (*i)->when + distance, (*i)->value + delta);
} }
++i; ++i;
@ -954,7 +953,7 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int
as the main point moved. 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 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; 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 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; return true;
} }
@ -1030,11 +1029,12 @@ AutomationLine::remove_point (ControlPoint& cp)
model_representation (cp, mr); model_representation (cp, mr);
trackview.editor.current_session()->begin_reversible_command (_("remove control point")); 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()->commit_reversible_command ();
trackview.editor.current_session()->set_dirty (); trackview.editor.current_session()->set_dirty ();
} }
@ -1229,7 +1229,7 @@ AutomationLine::reset ()
return; return;
} }
alist.apply_to_points (*this, &AutomationLine::reset_callback); alist->apply_to_points (*this, &AutomationLine::reset_callback);
} }
void void
@ -1237,7 +1237,7 @@ AutomationLine::clear ()
{ {
/* parent must create command */ /* parent must create command */
XMLNode &before = get_state(); 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()->add_command (new MementoCommand<AutomationLine>(*this, &before, &get_state()));
trackview.editor.current_session()->commit_reversible_command (); trackview.editor.current_session()->commit_reversible_command ();
trackview.editor.current_session()->set_dirty (); trackview.editor.current_session()->set_dirty ();
@ -1251,7 +1251,7 @@ AutomationLine::change_model (AutomationList::iterator i, double x, double y)
void void
AutomationLine::change_model_range (AutomationList::iterator start, AutomationList::iterator end, double xdelta, float ydelta) 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 void
@ -1281,12 +1281,12 @@ XMLNode &
AutomationLine::get_state (void) AutomationLine::get_state (void)
{ {
/* function as a proxy for the model */ /* function as a proxy for the model */
return alist.get_state(); return alist->get_state();
} }
int int
AutomationLine::set_state (const XMLNode &node) AutomationLine::set_state (const XMLNode &node)
{ {
/* function as a proxy for the model */ /* function as a proxy for the model */
return alist.set_state (node); return alist->set_state (node);
} }

View file

@ -98,7 +98,7 @@ class ControlPoint
class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoingAway class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoingAway
{ {
public: public:
AutomationLine (const string & name, TimeAxisView&, ArdourCanvas::Group&, ARDOUR::AutomationList&); AutomationLine (const string & name, TimeAxisView&, ArdourCanvas::Group&, boost::shared_ptr<ARDOUR::AutomationList>);
virtual ~AutomationLine (); virtual ~AutomationLine ();
void queue_reset (); 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 view_to_model_y (double&) = 0;
virtual void model_to_view_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 show_all_control_points ();
void hide_all_but_selected_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 _y_position;
guint32 _height; guint32 _height;
uint32_t _line_color; uint32_t _line_color;
ARDOUR::AutomationList& alist; boost::shared_ptr<ARDOUR::AutomationList> alist;
bool _visible : 1; bool _visible : 1;
bool _vc_uses_gain_mapping : 1; bool _vc_uses_gain_mapping : 1;

View file

@ -27,7 +27,7 @@ using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; 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) : AutomationLine (name, tv, parent, l)
{ {

View file

@ -30,7 +30,7 @@ class TimeAxisView;
class AutomationMidiCCLine : public AutomationLine class AutomationMidiCCLine : public AutomationLine
{ {
public: 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 view_to_model_y (double&);
void model_to_view_y (double&); void model_to_view_y (double&);

View file

@ -30,7 +30,7 @@
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; 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) : AutomationLine (name, tv, parent, l)
{ {

View file

@ -30,7 +30,7 @@ class TimeAxisView;
class AutomationPanLine : public AutomationLine class AutomationPanLine : public AutomationLine
{ {
public: 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 view_to_model_y (double&);
void model_to_view_y (double&); void model_to_view_y (double&);

View file

@ -17,8 +17,11 @@
*/ */
#include <utility>
#include <ardour/route.h> #include <ardour/route.h>
#include <ardour/automation_control.h>
#include <pbd/memento_command.h> #include <pbd/memento_command.h>
#include <gtkmm2ext/barcontroller.h>
#include "ardour_ui.h" #include "ardour_ui.h"
#include "automation_time_axis.h" #include "automation_time_axis.h"
@ -38,6 +41,7 @@
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
using namespace Gtk; using namespace Gtk;
using namespace Gtkmm2ext;
using namespace Editing; using namespace Editing;
Pango::FontDescription AutomationTimeAxisView::name_font; Pango::FontDescription AutomationTimeAxisView::name_font;
@ -217,6 +221,17 @@ AutomationTimeAxisView::auto_clicked ()
automation_menu->popup (1, gtk_get_current_event_time()); 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 void
AutomationTimeAxisView::automation_state_changed () AutomationTimeAxisView::automation_state_changed ()
@ -228,7 +243,7 @@ AutomationTimeAxisView::automation_state_changed ()
if (lines.empty()) { if (lines.empty()) {
state = Off; state = Off;
} else { } else {
state = lines.front()->the_list().automation_state (); state = lines.front().first->the_list()->automation_state ();
} }
switch (state & (Off|Play|Touch|Write)) { switch (state & (Off|Play|Touch|Write)) {
@ -292,8 +307,8 @@ void
AutomationTimeAxisView::clear_clicked () AutomationTimeAxisView::clear_clicked ()
{ {
_session.begin_reversible_command (_("clear automation")); _session.begin_reversible_command (_("clear automation"));
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->clear (); i->first->clear ();
} }
_session.commit_reversible_command (); _session.commit_reversible_command ();
} }
@ -304,7 +319,7 @@ AutomationTimeAxisView::set_height (TrackHeight ht)
uint32_t h = height_to_pixels (ht); uint32_t h = height_to_pixels (ht);
bool changed = (height != (uint32_t) h); 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 (); TimeAxisView* state_parent = get_parent_with_state ();
XMLNode* xml_node = state_parent->get_child_xml_node (_state_name); XMLNode* xml_node = state_parent->get_child_xml_node (_state_name);
@ -312,8 +327,8 @@ AutomationTimeAxisView::set_height (TrackHeight ht)
TimeAxisView::set_height (ht); TimeAxisView::set_height (ht);
base_rect->property_y2() = h; base_rect->property_y2() = h;
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->set_y_position_and_height (0, h); i->first->set_y_position_and_height (0, h);
} }
for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
@ -347,12 +362,20 @@ AutomationTimeAxisView::set_height (TrackHeight ht)
break; 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; first_call_to_set_height = false;
unsigned control_cnt = 0;
switch (ht) { switch (ht) {
case Largest: case Largest:
case Large: case Large:
case Larger: 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: case Normal:
controls_table.remove (name_hbox); controls_table.remove (name_hbox);
@ -400,7 +423,7 @@ AutomationTimeAxisView::set_height (TrackHeight ht)
hide_button.hide(); hide_button.hide();
break; break;
} }
} //}
if (changed) { if (changed) {
/* only emit the signal if the height really 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()); TimeAxisView::set_samples_per_unit (editor.get_current_zoom());
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->reset (); i->first->reset ();
} }
} }
@ -486,8 +509,8 @@ AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
{ {
bool ret = false; bool ret = false;
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
ret = cut_copy_clear_one ((**i), selection, op); ret = cut_copy_clear_one (*i->first, selection, op);
} }
return ret; return ret;
@ -497,28 +520,28 @@ bool
AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op) AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
{ {
AutomationList* what_we_got = 0; AutomationList* what_we_got = 0;
AutomationList& alist (line.the_list()); boost::shared_ptr<AutomationList> alist (line.the_list());
bool ret = false; bool ret = false;
XMLNode &before = alist.get_state(); XMLNode &before = alist->get_state();
switch (op) { switch (op) {
case Cut: 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); 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; ret = true;
} }
break; break;
case Copy: 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); editor.get_cut_buffer().add (what_we_got);
} }
break; break;
case Clear: case Clear:
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) {
_session.add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state())); _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
delete what_we_got; delete what_we_got;
what_we_got = 0; what_we_got = 0;
ret = true; ret = true;
@ -540,17 +563,17 @@ AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& sel
void void
AutomationTimeAxisView::reset_objects (PointSelection& selection) AutomationTimeAxisView::reset_objects (PointSelection& selection)
{ {
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
reset_objects_one ((**i), selection); reset_objects_one (*i->first, selection);
} }
} }
void void
AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection) 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) { for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
@ -558,7 +581,7 @@ AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection&
continue; 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; bool ret = false;
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
ret = cut_copy_clear_objects_one ((**i), selection, op); ret = cut_copy_clear_objects_one (*i->first, selection, op);
} }
return ret; return ret;
@ -578,10 +601,10 @@ bool
AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op) AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
{ {
AutomationList* what_we_got = 0; AutomationList* what_we_got = 0;
AutomationList& alist (line.the_list()); boost::shared_ptr<AutomationList> alist(line.the_list());
bool ret = false; bool ret = false;
XMLNode &before = alist.get_state(); XMLNode &before = alist->get_state();
for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) { 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) { switch (op) {
case Cut: 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); 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; ret = true;
} }
break; break;
case Copy: 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); editor.get_cut_buffer().add (what_we_got);
} }
break; break;
case Clear: case Clear:
if ((what_we_got = alist.cut ((*i).start, (*i).end)) != 0) { if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
_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()));
delete what_we_got; delete what_we_got;
what_we_got = 0; what_we_got = 0;
ret = true; ret = true;
@ -632,8 +655,8 @@ AutomationTimeAxisView::paste (nframes_t pos, float times, Selection& selection,
{ {
bool ret = true; bool ret = true;
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
ret = paste_one (**i, pos, times, selection, nth); ret = paste_one (*i->first, pos, times, selection, nth);
} }
return ret; return ret;
@ -643,7 +666,7 @@ bool
AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth) AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth)
{ {
AutomationSelection::iterator p; 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); 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; (*x)->value = foo;
} }
XMLNode &before = alist.get_state(); XMLNode &before = alist->get_state();
alist.paste (copy, pos, times); alist->paste (copy, pos, times);
_session.add_command (new MementoCommand<AutomationList>(alist, &before, &alist.get_state())); _session.add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
return true; return true;
} }
@ -725,8 +748,8 @@ AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double
botfrac = 1.0 - ((bot - y_position) / height); botfrac = 1.0 - ((bot - y_position) / height);
} }
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->get_selectables (start, end, botfrac, topfrac, results); i->first->get_selectables (start, end, botfrac, topfrac, results);
} }
} }
} }
@ -734,25 +757,24 @@ AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double
void void
AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result) AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
{ {
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->get_inverted_selectables (sel, result); i->first->get_inverted_selectables (sel, result);
} }
} }
void void
AutomationTimeAxisView::set_selected_points (PointSelection& points) AutomationTimeAxisView::set_selected_points (PointSelection& points)
{ {
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->set_selected_points (points); i->first->set_selected_points (points);
} }
} }
void void
AutomationTimeAxisView::clear_lines () AutomationTimeAxisView::clear_lines ()
{ {
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i)
delete *i; delete i->first;
}
lines.clear (); lines.clear ();
automation_connection.disconnect (); automation_connection.disconnect ();
@ -765,33 +787,38 @@ AutomationTimeAxisView::add_line (AutomationLine& line)
if (lines.empty()) { if (lines.empty()) {
/* first line is the Model for automation state */ /* 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)); (mem_fun(*this, &AutomationTimeAxisView::automation_state_changed));
get = true; 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); line.set_y_position_and_height (0, height);
if (get) { if (get) {
/* pick up the current state */ /* pick up the current state */
automation_state_changed (); automation_state_changed ();
} }
line.show();
} }
void void
AutomationTimeAxisView::show_all_control_points () AutomationTimeAxisView::show_all_control_points ()
{ {
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->show_all_control_points (); i->first->show_all_control_points ();
} }
} }
void void
AutomationTimeAxisView::hide_all_but_selected_control_points () AutomationTimeAxisView::hide_all_but_selected_control_points ()
{ {
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) { for (Lines::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->hide_all_but_selected_control_points (); i->first->hide_all_but_selected_control_points ();
} }
} }
@ -808,36 +835,23 @@ AutomationTimeAxisView::exited ()
} }
void void
AutomationTimeAxisView::set_colors () { AutomationTimeAxisView::set_colors ()
{
for (list<GhostRegion*>::iterator i=ghosts.begin(); i != ghosts.end(); i++ ) { for (list<GhostRegion*>::iterator i=ghosts.begin(); i != ghosts.end(); i++ ) {
(*i)->set_colors(); (*i)->set_colors();
} }
for( vector<AutomationLine *>::iterator i=lines.begin(); i != lines.end(); i++ ) { for (Lines::iterator i=lines.begin(); i != lines.end(); i++ ) {
(*i)->set_colors(); i->first->set_colors();
} }
} }
void void
AutomationTimeAxisView::color_handler () AutomationTimeAxisView::color_handler ()
{ {
//case cGhostTrackWave:
//case cGhostTrackWaveClip:
//case cGhostTrackZeroLine:
//case cControlPoint:
//case cControlPointFill:
//case cControlPointOutline:
//case cAutomationLine:
set_colors (); set_colors ();
} }
void void
AutomationTimeAxisView::set_state (const XMLNode& node) AutomationTimeAxisView::set_state (const XMLNode& node)
{ {

View file

@ -23,6 +23,7 @@
#include <vector> #include <vector>
#include <list> #include <list>
#include <string> #include <string>
#include <utility>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
@ -31,6 +32,7 @@
#include "canvas.h" #include "canvas.h"
#include "time_axis_view.h" #include "time_axis_view.h"
#include "simplerect.h" #include "simplerect.h"
#include "automation_controller.h"
using std::vector; using std::vector;
using std::list; using std::list;
@ -50,6 +52,8 @@ class GhostRegion;
class Selection; class Selection;
class Selectable; class Selectable;
/** TODO: All the derived types of this can probably be merged into this cleanly.
*/
class AutomationTimeAxisView : public TimeAxisView { class AutomationTimeAxisView : public TimeAxisView {
public: public:
AutomationTimeAxisView (ARDOUR::Session&, AutomationTimeAxisView (ARDOUR::Session&,
@ -72,7 +76,8 @@ class AutomationTimeAxisView : public TimeAxisView {
virtual void clear_lines (); virtual void clear_lines ();
virtual void add_line (AutomationLine&); 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 set_selected_points (PointSelection&);
void get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable *>&); 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 _name;
string _state_name; string _state_name;
bool in_destructor; bool in_destructor;
bool ignore_toggle;
bool first_call_to_set_height; 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); bool paste_one (AutomationLine&, nframes_t, float times, Selection&, size_t nth);
void reset_objects_one (AutomationLine&, PointSelection&); void reset_objects_one (AutomationLine&, PointSelection&);
virtual void set_automation_state (ARDOUR::AutoState) = 0; void set_automation_state (ARDOUR::AutoState);
bool ignore_state_request; bool ignore_state_request;
void automation_state_changed (); void automation_state_changed ();

View file

@ -1163,7 +1163,7 @@ Editor::connect_to_session (Session *t)
RouteTimeAxisView *rtv; RouteTimeAxisView *rtv;
if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) { if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
if (rtv->route()->master()) { if (rtv->route()->is_master()) {
route_list_display.get_selection()->unselect (i); route_list_display.get_selection()->unselect (i);
} }
} }

View file

@ -1676,7 +1676,7 @@ Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event)
AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data); 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 void
@ -1755,13 +1755,13 @@ Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* even
continue; continue;
} }
AutomationList& alist = tmp->audio_region()->fade_in(); boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
XMLNode &before = alist.get_state(); XMLNode &before = alist->get_state();
tmp->audio_region()->set_fade_in_length (fade_length); tmp->audio_region()->set_fade_in_length (fade_length);
XMLNode &after = alist.get_state(); XMLNode &after = alist->get_state();
session->add_command(new MementoCommand<AutomationList>(alist, &before, &after)); session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
} }
commit_reversible_command (); 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); 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 void
@ -1871,13 +1871,13 @@ Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* eve
continue; continue;
} }
AutomationList& alist = tmp->audio_region()->fade_out(); boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
XMLNode &before = alist.get_state(); XMLNode &before = alist->get_state();
tmp->audio_region()->set_fade_out_length (fade_length); tmp->audio_region()->set_fade_out_length (fade_length);
XMLNode &after = alist.get_state(); XMLNode &after = alist->get_state();
session->add_command(new MementoCommand<AutomationList>(alist, &before, &after)); session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
} }
commit_reversible_command (); commit_reversible_command ();

View file

@ -3392,11 +3392,11 @@ Editor::reset_region_gain_envelopes ()
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i); AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
if (arv) { if (arv) {
AutomationList& alist (arv->audio_region()->envelope()); boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
XMLNode& before (alist.get_state()); XMLNode& before (alist->get_state());
arv->audio_region()->set_default_envelope (); 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; return;
} }
AutomationList& alist = tmp->audio_region()->fade_in(); boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
XMLNode &before = alist.get_state(); XMLNode &before = alist->get_state();
tmp->audio_region()->set_fade_in_shape (shape); tmp->audio_region()->set_fade_in_shape (shape);
XMLNode &after = alist.get_state(); XMLNode &after = alist->get_state();
session->add_command(new MementoCommand<AutomationList>(alist, &before, &after)); session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
} }
commit_reversible_command (); commit_reversible_command ();
@ -3509,13 +3509,13 @@ Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
return; return;
} }
AutomationList& alist = tmp->audio_region()->fade_out(); boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
XMLNode &before = alist.get_state(); XMLNode &before = alist->get_state();
tmp->audio_region()->set_fade_out_shape (shape); tmp->audio_region()->set_fade_out_shape (shape);
XMLNode &after = alist.get_state(); XMLNode &after = alist->get_state();
session->add_command(new MementoCommand<AutomationList>(alist, &before, &after)); session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
} }
commit_reversible_command (); commit_reversible_command ();

View file

@ -56,7 +56,7 @@ Editor::handle_new_route (Session::RouteList& routes)
for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
boost::shared_ptr<Route> route = (*x); boost::shared_ptr<Route> route = (*x);
if (route->hidden()) { if (route->is_hidden()) {
continue; continue;
} }

View file

@ -1089,7 +1089,7 @@ ExportDialog::fill_lists ()
boost::shared_ptr<Route> route = (*ri); boost::shared_ptr<Route> route = (*ri);
if (route->hidden()) { if (route->is_hidden()) {
continue; continue;
} }

View file

@ -33,12 +33,12 @@ using namespace Gtk;
GainAutomationTimeAxisView::GainAutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r, GainAutomationTimeAxisView::GainAutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r,
PublicEditor& e, TimeAxisView& parent, 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), : AxisView (s),
AutomationTimeAxisView (s, r, e, parent, canvas, n, X_("gain"), ""), 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 */ /* 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")); _session.begin_reversible_command (_("add gain automation event"));
XMLNode& before = list.get_state(); XMLNode& before = _control->list()->get_state();
list.add (when, y); _control->list()->add (when, y);
XMLNode& after = list.get_state(); XMLNode& after = _control->list()->get_state();
_session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(list, &before, &after)); _session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->list(), &before, &after));
_session.set_dirty (); _session.set_dirty ();
} }
void
GainAutomationTimeAxisView::set_automation_state (AutoState state)
{
if (!ignore_state_request) {
route->set_parameter_automation_state (ParamID(GainAutomation), state);
}
}

View file

@ -25,6 +25,7 @@
namespace ARDOUR { namespace ARDOUR {
class AutomationList; class AutomationList;
class AutomationControl;
} }
class GainAutomationTimeAxisView : public AutomationTimeAxisView class GainAutomationTimeAxisView : public AutomationTimeAxisView
@ -36,17 +37,16 @@ class GainAutomationTimeAxisView : public AutomationTimeAxisView
TimeAxisView& parent_axis, TimeAxisView& parent_axis,
ArdourCanvas::Canvas& canvas, ArdourCanvas::Canvas& canvas,
const string & name, const string & name,
ARDOUR::AutomationList&); boost::shared_ptr<ARDOUR::AutomationControl> control);
~GainAutomationTimeAxisView(); ~GainAutomationTimeAxisView();
void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, nframes_t, double); void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, nframes_t, double);
private: private:
ARDOUR::AutomationList& list; boost::shared_ptr<ARDOUR::AutomationControl> _control;
void automation_changed (); void automation_changed ();
void set_automation_state (ARDOUR::AutoState);
}; };
#endif /* __ardour_gtk_gain_automation_time_axis_h__ */ #endif /* __ardour_gtk_gain_automation_time_axis_h__ */

View file

@ -91,7 +91,7 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
gain_slider = manage (new VSliderController (slider, gain_slider = manage (new VSliderController (slider,
&gain_adjustment, &gain_adjustment,
_io->gain_control(), *_io->gain_control().get(),
false)); false));
gain_slider->signal_button_press_event().connect (mem_fun(*this, &GainMeter::start_gain_touch)); gain_slider->signal_button_press_event().connect (mem_fun(*this, &GainMeter::start_gain_touch));
@ -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_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); 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_control()->list()->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_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed));
fader_vbox->pack_start (gain_automation_state_button, false, false, 0); fader_vbox->pack_start (gain_automation_state_button, false, false, 0);
gain_automation_state_changed (); 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 (gain_display_box, Gtk::PACK_SHRINK);
pack_start (hbox, 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)); 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)); 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)); Config->ParameterChanged.connect (mem_fun (*this, &GainMeter::parameter_changed));
gain_changed (0); gain_changed ();
show_gain (); show_gain ();
update_gain_sensitive (); update_gain_sensitive ();
@ -606,7 +606,7 @@ GainMeter::gain_activated ()
f = min (f, 6.0f); 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()) { if (gain_display.has_focus()) {
PublicEditor::instance().reset_focus(); PublicEditor::instance().reset_focus();
@ -634,7 +634,7 @@ void
GainMeter::gain_adjusted () GainMeter::gain_adjusted ()
{ {
if (!ignore_toggle) { 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 (); show_gain ();
} }
@ -652,7 +652,7 @@ GainMeter::effective_gain_display ()
} }
void void
GainMeter::gain_changed (void *src) GainMeter::gain_changed ()
{ {
Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &GainMeter::effective_gain_display)); Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &GainMeter::effective_gain_display));
} }
@ -672,7 +672,7 @@ GainMeter::set_fader_name (const char * name)
void void
GainMeter::update_gain_sensitive () 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 gint
GainMeter::start_gain_touch (GdkEventButton* ev) GainMeter::start_gain_touch (GdkEventButton* ev)
{ {
_io->gain_automation().start_touch (); _io->gain_control()->list()->start_touch ();
return FALSE; return FALSE;
} }
gint gint
GainMeter::end_gain_touch (GdkEventButton* ev) GainMeter::end_gain_touch (GdkEventButton* ev)
{ {
_io->gain_automation().stop_touch (); _io->gain_control()->list()->stop_touch ();
return FALSE; return FALSE;
} }
@ -926,10 +926,10 @@ GainMeter::gain_automation_style_changed ()
// Route* _route = dynamic_cast<Route*>(&_io); // Route* _route = dynamic_cast<Route*>(&_io);
switch (_width) { switch (_width) {
case Wide: 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; break;
case Narrow: 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; break;
} }
} }
@ -944,14 +944,14 @@ GainMeter::gain_automation_state_changed ()
switch (_width) { switch (_width) {
case Wide: 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; break;
case Narrow: 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; break;
} }
x = (_io->gain_automation().automation_state() != Off); x = (_io->gain_control()->list()->automation_state() != Off);
if (gain_automation_state_button.get_active() != x) { if (gain_automation_state_button.get_active() != x) {
ignore_toggle = true; ignore_toggle = true;

View file

@ -149,7 +149,7 @@ class GainMeter : public Gtk::VBox
Gtk::HBox meter_packer; Gtk::HBox meter_packer;
void gain_adjusted (); void gain_adjusted ();
void gain_changed (void *); void gain_changed ();
void meter_point_clicked (); void meter_point_clicked ();
void gain_unit_changed (); void gain_unit_changed ();

View file

@ -496,7 +496,7 @@ LadspaPluginUI::build_control_ui (guint32 port_index, PBD::Controllable* mcontro
automation_state_changed (control_ui); automation_state_changed (control_ui);
plugin->ParameterChanged.connect (bind (mem_fun(*this, &LadspaPluginUI::parameter_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)); (bind (mem_fun(*this, &LadspaPluginUI::automation_state_changed), control_ui));
} else if (plugin->parameter_is_output (port_index)) { } else if (plugin->parameter_is_output (port_index)) {
@ -553,13 +553,13 @@ LadspaPluginUI::build_control_ui (guint32 port_index, PBD::Controllable* mcontro
void void
LadspaPluginUI::start_touch (LadspaPluginUI::ControlUI* cui) 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 void
LadspaPluginUI::stop_touch (LadspaPluginUI::ControlUI* cui) 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 void

View file

@ -20,6 +20,7 @@
#include <ardour/automation_event.h> #include <ardour/automation_event.h>
#include <ardour/route.h> #include <ardour/route.h>
#include <pbd/memento_command.h> #include <pbd/memento_command.h>
#include <pbd/controllable.h>
#include "midi_controller_time_axis.h" #include "midi_controller_time_axis.h"
#include "automation_line.h" #include "automation_line.h"
@ -34,12 +35,10 @@ using namespace Gtk;
MidiControllerTimeAxisView::MidiControllerTimeAxisView (Session& s, boost::shared_ptr<Route> r, MidiControllerTimeAxisView::MidiControllerTimeAxisView (Session& s, boost::shared_ptr<Route> r,
PublicEditor& e, TimeAxisView& parent, PublicEditor& e, TimeAxisView& parent,
ArdourCanvas::Canvas& canvas, const string & n, ArdourCanvas::Canvas& canvas, const string & n,
ParamID param, ARDOUR::AutomationList& l) boost::shared_ptr<AutomationControl> c)
: AxisView (s), : AxisView (s),
AutomationTimeAxisView (s, r, e, parent, canvas, n, param.to_string(), ""), AutomationTimeAxisView (s, r, e, parent, canvas, n, c->list()->param_id().to_string(), ""),
_list (l), _control (c)
_param (param)
{ {
} }
@ -60,22 +59,13 @@ MidiControllerTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkE
/* map using line */ /* 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")); _session.begin_reversible_command (_("add midi controller automation event"));
XMLNode& before = _list.get_state(); XMLNode& before = _control->list()->get_state();
_list.add (when, y); _control->list()->add (when, y);
XMLNode& after = _list.get_state(); XMLNode& after = _control->list()->get_state();
_session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(_list, &before, &after)); _session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->list().get(), &before, &after));
_session.set_dirty (); _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);
}
}

View file

@ -36,19 +36,16 @@ class MidiControllerTimeAxisView : public AutomationTimeAxisView
TimeAxisView& parent_axis, TimeAxisView& parent_axis,
ArdourCanvas::Canvas& canvas, ArdourCanvas::Canvas& canvas,
const string & name, const string & name,
ARDOUR::ParamID param, boost::shared_ptr<ARDOUR::AutomationControl> c);
ARDOUR::AutomationList&);
~MidiControllerTimeAxisView(); ~MidiControllerTimeAxisView();
void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, nframes_t, double); void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, nframes_t, double);
private: private:
ARDOUR::AutomationList& _list; boost::shared_ptr<ARDOUR::AutomationControl> _control;
ARDOUR::ParamID _param;
void automation_changed (); void automation_changed ();
void set_automation_state (ARDOUR::AutoState);
}; };
#endif /* __ardour_gtk_midi_controller_time_axis_h__ */ #endif /* __ardour_gtk_midi_controller_time_axis_h__ */

View file

@ -185,12 +185,13 @@ MidiTimeAxisView::create_automation_child (ParamID param)
/* FIXME: this all probably leaks */ /* FIXME: this all probably leaks */
ARDOUR::AutomationList* al = _route->automation_list(param); boost::shared_ptr<AutomationControl> c =_route->control(param);
if (!al) if (!c) {
al = new ARDOUR::AutomationList(param, 0, 127, 64); boost::shared_ptr<AutomationList> al(new ARDOUR::AutomationList(param, 0, 127, 64));
c = boost::shared_ptr<AutomationControl>(new AutomationControl(_session, al));
_route->add_automation_parameter(al); _route->add_control(c);
}
MidiControllerTimeAxisView* track = new MidiControllerTimeAxisView (_session, MidiControllerTimeAxisView* track = new MidiControllerTimeAxisView (_session,
_route, _route,
@ -198,13 +199,12 @@ MidiTimeAxisView::create_automation_child (ParamID param)
*this, *this,
parent_canvas, parent_canvas,
_route->describe_parameter(param), _route->describe_parameter(param),
param, c);
*al);
AutomationMidiCCLine* line = new AutomationMidiCCLine (param.to_string(), AutomationMidiCCLine* line = new AutomationMidiCCLine (param.to_string(),
*track, *track,
*track->canvas_display, *track->canvas_display,
*al); c->list());
line->set_line_color (Config->canvasvar_AutomationLine.get()); line->set_line_color (Config->canvasvar_AutomationLine.get());

View 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 (output_button, Gtk::PACK_SHRINK);
global_vpacker.pack_start (comment_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) { if (scrollbar_height == 0) {
HScrollbar scrollbar; HScrollbar scrollbar;
@ -403,6 +403,8 @@ MixerStrip::set_width (Width w, void* owner)
pre_processor_box.set_width (w); pre_processor_box.set_width (w);
post_processor_box.set_width (w); post_processor_box.set_width (w);
boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->list();
_width_owner = owner; _width_owner = owner;
if (_width == w) { 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*)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_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(_route->gain_automation().automation_state())); ((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_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())); ((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); 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*)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_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(_route->gain_automation().automation_state())); ((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_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())); ((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); 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()) { if (!_route->panner().empty()) {
StreamPanner* sp = _route->panner().front(); StreamPanner* sp = _route->panner().front();
panstate_connection = sp->automation().automation_state_changed.connect (mem_fun(panners, &PannerUI::pan_automation_state_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)); panstyle_connection = sp->automation()->automation_style_changed.connect (mem_fun(panners, &PannerUI::pan_automation_style_changed));
} }
panners.pan_changed (this); panners.pan_changed (this);

View file

@ -267,7 +267,7 @@ Mixer_UI::add_strip (Session::RouteList& routes)
for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
boost::shared_ptr<Route> route = (*x); boost::shared_ptr<Route> route = (*x);
if (route->hidden()) { if (route->is_hidden()) {
return; return;
} }
@ -473,7 +473,7 @@ Mixer_UI::set_all_strips_visibility (bool yn)
continue; continue;
} }
if (strip->route()->master() || strip->route()->control()) { if (strip->route()->is_master() || strip->route()->is_control()) {
continue; continue;
} }
@ -501,7 +501,7 @@ Mixer_UI::set_all_audio_visibility (int tracks, bool yn)
continue; continue;
} }
if (strip->route()->master() || strip->route()->control()) { if (strip->route()->is_master() || strip->route()->is_control()) {
continue; continue;
} }
@ -605,7 +605,7 @@ Mixer_UI::redisplay_track_list ()
if (strip->packed()) { 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); out_packer.reorder_child (*strip, -1);
} else { } else {
strip_packer.reorder_child (*strip, -1); /* put at end */ strip_packer.reorder_child (*strip, -1); /* put at end */
@ -613,7 +613,7 @@ Mixer_UI::redisplay_track_list ()
} else { } else {
if (strip->route()->master() || strip->route()->control()) { if (strip->route()->is_master() || strip->route()->is_control()) {
out_packer.pack_start (*strip, false, false); out_packer.pack_start (*strip, false, false);
} else { } else {
strip_packer.pack_start (*strip, false, false); strip_packer.pack_start (*strip, false, false);
@ -624,7 +624,7 @@ Mixer_UI::redisplay_track_list ()
} else { } else {
if (strip->route()->master() || strip->route()->control()) { if (strip->route()->is_master() || strip->route()->is_control()) {
/* do nothing, these cannot be hidden */ /* do nothing, these cannot be hidden */
} else { } else {
if (strip->packed()) { if (strip->packed()) {
@ -702,7 +702,7 @@ Mixer_UI::track_display_button_press (GdkEventButton* ev)
MixerStrip* strip = (*iter)[track_columns.strip]; MixerStrip* strip = (*iter)[track_columns.strip];
if (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]; bool visible = (*iter)[track_columns.visible];
(*iter)[track_columns.visible] = !visible; (*iter)[track_columns.visible] = !visible;
} }

View file

@ -88,15 +88,15 @@ PanAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEv
/* map using line */ /* 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")); _session.begin_reversible_command (_("add pan automation event"));
XMLNode &before = alist.get_state(); XMLNode &before = alist->get_state();
alist.add (when, y); alist->add (when, y);
XMLNode &after = alist.get_state(); XMLNode &after = alist->get_state();
_session.add_command(new MementoCommand<AutomationList>(alist, &before, &after)); _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
_session.commit_reversible_command (); _session.commit_reversible_command ();
_session.set_dirty (); _session.set_dirty ();
} }
@ -147,11 +147,3 @@ PanAutomationTimeAxisView::set_height (TimeAxisView::TrackHeight th)
multiline_selector.hide(); multiline_selector.hide();
} }
} }
void
PanAutomationTimeAxisView::set_automation_state (AutoState state)
{
if (!ignore_state_request) {
route->panner().set_automation_state (state);
}
}

View file

@ -52,7 +52,6 @@ class PanAutomationTimeAxisView : public AutomationTimeAxisView
private: private:
void automation_changed (); void automation_changed ();
void set_automation_state (ARDOUR::AutoState);
}; };
#endif /* __ardour_gtk_pan_automation_time_axis_h__ */ #endif /* __ardour_gtk_pan_automation_time_axis_h__ */

View file

@ -34,8 +34,8 @@ null_label_callback (char* buf, unsigned int bufsize)
} }
PannerBar::PannerBar (Gtk::Adjustment& adj, PBD::Controllable& c) PannerBar::PannerBar (Gtk::Adjustment& adj, boost::shared_ptr<PBD::Controllable> c)
: BarController (adj, c, sigc::ptr_fun (null_label_callback)) : BarController (adj, *c.get(), sigc::ptr_fun (null_label_callback))
{ {
set_style (BarController::Line); set_style (BarController::Line);
} }

View file

@ -21,11 +21,12 @@
#define __gtk_ardour_panner_h__ #define __gtk_ardour_panner_h__
#include <gtkmm2ext/barcontroller.h> #include <gtkmm2ext/barcontroller.h>
#include <boost/shared_ptr.hpp>
class PannerBar : public Gtkmm2ext::BarController class PannerBar : public Gtkmm2ext::BarController
{ {
public: public:
PannerBar (Gtk::Adjustment& adj, PBD::Controllable&); PannerBar (Gtk::Adjustment& adj, boost::shared_ptr<PBD::Controllable>);
~PannerBar (); ~PannerBar ();
protected: protected:

View file

@ -573,9 +573,9 @@ PannerUI::update_pan_bars (bool only_if_aplay)
float xpos, val; float xpos, val;
if (only_if_aplay) { 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; continue;
} }
} }
@ -707,7 +707,7 @@ PannerUI::pan_automation_state_changed ()
return; 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) { if (pan_automation_state_button.get_active() != x) {
ignore_toggle = true; ignore_toggle = true;

View file

@ -32,12 +32,11 @@ using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
ProcessorAutomationLine::ProcessorAutomationLine (const string & name, Processor& proc, ParamID param, ProcessorAutomationLine::ProcessorAutomationLine (const string & name, Processor& proc,
TimeAxisView& tv, ArdourCanvas::Group& parent, AutomationList& l) TimeAxisView& tv, ArdourCanvas::Group& parent, boost::shared_ptr<AutomationList> l)
: AutomationLine (name, tv, parent, l), : AutomationLine (name, tv, parent, l),
_processor(proc), _processor(proc)
_param(param)
{ {
set_verbose_cursor_uses_gain_mapping (false); set_verbose_cursor_uses_gain_mapping (false);
@ -49,7 +48,7 @@ ProcessorAutomationLine::ProcessorAutomationLine (const string & name, Processor
/*NOTREACHED*/ /*NOTREACHED*/
} }
pi->plugin()->get_parameter_descriptor (_param, desc); pi->plugin()->get_parameter_descriptor (l->param_id(), desc);
_upper = desc.upper; _upper = desc.upper;
_lower = desc.lower; _lower = desc.lower;

View file

@ -33,17 +33,15 @@ class TimeAxisView;
class ProcessorAutomationLine : public AutomationLine class ProcessorAutomationLine : public AutomationLine
{ {
public: public:
ProcessorAutomationLine (const string & name, ARDOUR::Processor&, ARDOUR::ParamID param, ProcessorAutomationLine (const string & name, ARDOUR::Processor&,
TimeAxisView&, ArdourCanvas::Group& parent, ARDOUR::AutomationList&); TimeAxisView&, ArdourCanvas::Group& parent, boost::shared_ptr<ARDOUR::AutomationList>);
ARDOUR::ParamID param() const { return _param; }
ARDOUR::Processor& processor() const { return _processor; } ARDOUR::Processor& processor() const { return _processor; }
string get_verbose_cursor_string (float); string get_verbose_cursor_string (float);
private: private:
ARDOUR::Processor& _processor; ARDOUR::Processor& _processor;
ARDOUR::ParamID _param;
float _upper; float _upper;
float _lower; float _lower;

View file

@ -91,11 +91,11 @@ ProcessorAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item,
/* map to model space */ /* map to model space */
if (!lines.empty()) { 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 "); string description = _("add automation event to ");
description += _processor.describe_parameter (_param); 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); _session.begin_reversible_command (description);
XMLNode &before = alist->get_state(); XMLNode &before = alist->get_state();
@ -168,7 +168,33 @@ void
ProcessorAutomationTimeAxisView::set_automation_state (AutoState state) ProcessorAutomationTimeAxisView::set_automation_state (AutoState state)
{ {
if (!ignore_state_request) { 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();
}

View file

@ -46,6 +46,7 @@ class ProcessorAutomationTimeAxisView : public AutomationTimeAxisView
~ProcessorAutomationTimeAxisView(); ~ProcessorAutomationTimeAxisView();
void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, nframes_t, double); 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); guint32 show_at (double y, int& nth, Gtk::VBox *parent);
void hide (); void hide ();

View file

@ -347,7 +347,7 @@ ProcessorBox::processor_button_release_event (GdkEventButton *ev)
Menu * Menu *
ProcessorBox::build_processor_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"); processor_menu->set_name ("ArdourContextMenu");
show_all_children(); show_all_children();
@ -1184,7 +1184,7 @@ ProcessorBox::enter_box (GdkEventCrossing *ev, ProcessorBox* rb)
void void
ProcessorBox::register_actions () 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; Glib::RefPtr<Action> act;
/* new stuff */ /* new stuff */

View file

@ -38,7 +38,7 @@ using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; 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), : AutomationLine (name, r.get_time_axis_view(), parent, l),
session (s), session (s),
rv (r) rv (r)
@ -81,7 +81,7 @@ AudioRegionGainLine::remove_point (ControlPoint& cp)
model_representation (cp, mr); model_representation (cp, mr);
trackview.editor.current_session()->begin_reversible_command (_("remove control point")); 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()) { if (!rv.audio_region()->envelope_active()) {
XMLNode &region_before = rv.audio_region()->get_state(); XMLNode &region_before = rv.audio_region()->get_state();
@ -90,9 +90,9 @@ AudioRegionGainLine::remove_point (ControlPoint& cp)
trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), &region_before, &region_after)); 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()->commit_reversible_command ();
trackview.editor.current_session()->set_dirty (); trackview.editor.current_session()->set_dirty ();
} }

View file

@ -35,7 +35,7 @@ class AudioRegionView;
class AudioRegionGainLine : public AutomationLine class AudioRegionGainLine : public AutomationLine
{ {
public: 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 view_to_model_y (double&);
void model_to_view_y (double&); void model_to_view_y (double&);

View file

@ -178,7 +178,7 @@ RouteParams_UI::add_routes (Session::RouteList& routes)
for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
boost::shared_ptr<Route> route = (*x); boost::shared_ptr<Route> route = (*x);
if (route->hidden()) { if (route->is_hidden()) {
return; return;
} }

View file

@ -1570,7 +1570,7 @@ RouteTimeAxisView::show_existing_automation ()
map<ARDOUR::ParamID, RouteAutomationNode*>::iterator i; map<ARDOUR::ParamID, RouteAutomationNode*>::iterator i;
for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) { for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
// FIXME: only shown if /first/ line has points // 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->set_marked_for_display (true);
i->second->track->canvas_display->show(); i->second->track->canvas_display->show();
i->second->track->get_state_node()->add_property ("shown", X_("yes")); 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 */ /* 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]; char state_name[256];
snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id()); 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); ran->view = new ProcessorAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, name, what, *processor, state_name);
ral = new ProcessorAutomationLine (name, ral = new ProcessorAutomationLine (name,
*processor, what, *ran->view, *processor, *ran->view, *ran->view->canvas_display,
*ran->view->canvas_display, *processor->automation_list (what, true)); processor->control (what, true)->list());
ral->set_line_color (Config->canvasvar_ProcessorAutomationLine.get()); ral->set_line_color (Config->canvasvar_ProcessorAutomationLine.get());
ral->queue_reset (); 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 = find_processor_automation_node (processor, what)) != 0) {
if (ran->view) { if (ran->view) {
return dynamic_cast<ProcessorAutomationLine*> (ran->view->lines.front()); return dynamic_cast<ProcessorAutomationLine*> (ran->view->lines.front().first);
} }
} }

View 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)); _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); 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); solo_button->set_self_managed (true);
mute_button->set_name ("MuteButton"); 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)); _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_name ("RecordEnableButton");
rec_enable_button->set_self_managed (true); rec_enable_button->set_self_managed (true);

View file

@ -31,7 +31,6 @@
#include <pbd/file_utils.h> #include <pbd/file_utils.h>
#include <gtkmm2ext/utils.h> #include <gtkmm2ext/utils.h>
//#include <ardour/ardour.h>
#include <ardour/filesystem_paths.h> #include <ardour/filesystem_paths.h>

View file

@ -77,6 +77,7 @@ gdither.cc
globals.cc globals.cc
import.cc import.cc
automatable.cc automatable.cc
automation_control.cc
processor.cc processor.cc
io_processor.cc io_processor.cc
plugin_insert.cc plugin_insert.cc

View file

@ -67,9 +67,9 @@ class AudioRegion : public Region
bool fade_in_active () const { return _flags & Region::FadeIn; } bool fade_in_active () const { return _flags & Region::FadeIn; }
bool fade_out_active () const { return _flags & Region::FadeOut; } bool fade_out_active () const { return _flags & Region::FadeOut; }
AutomationList& fade_in() { return _fade_in; } boost::shared_ptr<AutomationList> fade_in() { return _fade_in; }
AutomationList& fade_out() { return _fade_out; } boost::shared_ptr<AutomationList> fade_out() { return _fade_out; }
AutomationList& envelope() { return _envelope; } boost::shared_ptr<AutomationList> envelope() { return _envelope; }
virtual nframes_t read_peaks (PeakData *buf, nframes_t npeaks, virtual nframes_t read_peaks (PeakData *buf, nframes_t npeaks,
nframes_t offset, nframes_t cnt, nframes_t offset, nframes_t cnt,
@ -162,11 +162,11 @@ class AudioRegion : public Region
void source_offset_changed (); void source_offset_changed ();
void listen_to_my_curves (); void listen_to_my_curves ();
mutable AutomationList _fade_in; boost::shared_ptr<AutomationList> _fade_in;
FadeShape _fade_in_shape; FadeShape _fade_in_shape;
mutable AutomationList _fade_out; boost::shared_ptr<AutomationList> _fade_out;
FadeShape _fade_out_shape; FadeShape _fade_out_shape;
mutable AutomationList _envelope; boost::shared_ptr<AutomationList> _envelope;
gain_t _scale_amplitude; gain_t _scale_amplitude;
uint32_t _fade_in_disabled; uint32_t _fade_in_disabled;
uint32_t _fade_out_disabled; uint32_t _fade_out_disabled;

View file

@ -22,13 +22,16 @@
#include <set> #include <set>
#include <map> #include <map>
#include <boost/shared_ptr.hpp>
#include <ardour/session_object.h> #include <ardour/session_object.h>
#include <ardour/automation_event.h> #include <ardour/automation_event.h>
#include <ardour/automation_control.h>
#include <ardour/param_id.h> #include <ardour/param_id.h>
namespace ARDOUR { namespace ARDOUR {
class Session; class Session;
class AutomationControl;
class Automatable : public SessionObject class Automatable : public SessionObject
{ {
@ -38,16 +41,17 @@ public:
virtual ~Automatable() {} virtual ~Automatable() {}
// shorthand for gain, pan, etc // shorthand for gain, pan, etc
inline AutomationList* automation_list(AutomationType type, bool create_if_missing=false) { inline boost::shared_ptr<AutomationControl>
return automation_list(ParamID(type), create_if_missing); 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 boost::shared_ptr<AutomationControl> control(ParamID id, bool create_if_missing=false);
virtual const AutomationList* automation_list(ParamID id) const; 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; virtual bool find_next_event(nframes_t start, nframes_t end, ControlEvent& ev) const;
@ -74,7 +78,7 @@ protected:
void can_automate(ParamID); 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); int set_automation_state(const XMLNode&, ParamID default_param);
XMLNode& get_automation_state(); XMLNode& get_automation_state();
@ -84,8 +88,10 @@ protected:
mutable Glib::Mutex _automation_lock; mutable Glib::Mutex _automation_lock;
std::map<ParamID,AutomationList*> _parameter_automation; typedef std::map<ParamID,boost::shared_ptr<AutomationControl> > Controls;
std::set<ParamID> _visible_parameter_automation;
Controls _controls;
std::set<ParamID> _visible_controls;
std::set<ParamID> _can_automate_list; std::set<ParamID> _can_automate_list;
nframes_t _last_automation_snapshot; nframes_t _last_automation_snapshot;

View file

@ -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__ */

View file

@ -42,6 +42,7 @@
#include <ardour/port_set.h> #include <ardour/port_set.h>
#include <ardour/chan_count.h> #include <ardour/chan_count.h>
#include <ardour/latent.h> #include <ardour/latent.h>
#include <ardour/automation_control.h>
using std::string; using std::string;
using std::vector; using std::vector;
@ -60,6 +61,7 @@ class AudioPort;
class MidiPort; class MidiPort;
class BufferSet; class BufferSet;
/** A collection of input and output ports with connections. /** A collection of input and output ports with connections.
* *
* An IO can contain ports of varying types, making routes/inserts/etc with * 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, void just_meter_input (nframes_t start_frame, nframes_t end_frame,
nframes_t nframes, nframes_t offset); 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; } gain_t gain () const { return _desired_gain; }
virtual gain_t effective_gain () const; 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*> input_changed;
sigc::signal<void,IOChange,void*> output_changed; sigc::signal<void,IOChange,void*> output_changed;
sigc::signal<void,void*> gain_changed;
virtual XMLNode& state (bool full); virtual XMLNode& state (bool full);
XMLNode& get_state (void); XMLNode& get_state (void);
int set_state (const XMLNode&); int set_state (const XMLNode&);
@ -206,10 +204,6 @@ class IO : public Automatable, public Latent
static sigc::signal<void,ChanCount> MoreChannels; static sigc::signal<void,ChanCount> MoreChannels;
static sigc::signal<int> PortsCreated; static sigc::signal<int> PortsCreated;
PBD::Controllable& gain_control() {
return _gain_control;
}
static void update_meters(); static void update_meters();
private: private:
@ -222,12 +216,23 @@ class IO : public Automatable, public Latent
/* automation */ /* automation */
static void set_automation_interval (nframes_t frames) { struct GainControl : public AutomationControl {
_automation_interval = frames; GainControl (std::string name, IO& i, boost::shared_ptr<AutomationList> al)
} : AutomationControl (i._session, al, name)
, _io (i)
{}
static nframes_t automation_interval() { void set_value (float val);
return _automation_interval; float get_value (void) const;
IO& _io;
};
boost::shared_ptr<GainControl> gain_control() {
return _gain_control;
}
boost::shared_ptr<const GainControl> gain_control() const {
return _gain_control;
} }
void clear_automation (); void clear_automation ();
@ -237,10 +242,6 @@ class IO : public Automatable, public Latent
virtual void transport_stopped (nframes_t now); // interface: matches Insert virtual void transport_stopped (nframes_t now); // interface: matches Insert
void automation_snapshot (nframes_t now); // interface: matches Automatable 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 start_pan_touch (uint32_t which);
void end_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 virtual uint32_t pans_required() const
{ return _inputs.count().n_audio(); } { return _inputs.count().n_audio(); }
struct GainControllable : public PBD::Controllable { boost::shared_ptr<GainControl> _gain_control;
GainControllable (std::string name, IO& i) : Controllable (name), io (i) {}
void set_value (float val); virtual void set_gain (gain_t g, void *src);
float get_value (void) const; void inc_gain (gain_t delta, void *src);
IO& io;
};
GainControllable _gain_control;
nframes_t last_automation_snapshot;
static nframes_t _automation_interval;
/*AutoState _gain_automation_state;
AutoStyle _gain_automation_style;*/
bool apply_gain_automation; bool apply_gain_automation;
//Curve _gain_automation_curve;
virtual int load_automation (std::string path); virtual int load_automation (std::string path);

View file

@ -76,14 +76,14 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful
virtual void set_automation_state (AutoState) = 0; virtual void set_automation_state (AutoState) = 0;
virtual void set_automation_style (AutoStyle) = 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 /* XXX this is wrong. for multi-dimensional panners, there
must surely be more than 1 automation curve. must surely be more than 1 automation curve.
*/ */
/* TODO: Panner is-a Automation solves this */ /* 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> Changed; /* for position */
sigc::signal<void> StateChanged; /* for mute */ sigc::signal<void> StateChanged; /* for mute */
@ -125,7 +125,7 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful
bool can_send_feedback() const; bool can_send_feedback() const;
}; };
PanControllable _control; boost::shared_ptr<PanControllable> _control;
void add_state (XMLNode&); void add_state (XMLNode&);
virtual void update () = 0; virtual void update () = 0;
@ -151,7 +151,7 @@ class BaseStereoPanner : public StreamPanner
void set_automation_style (AutoStyle); void set_automation_style (AutoStyle);
/* TODO: StreamPanner is-a Automatable? */ /* TODO: StreamPanner is-a Automatable? */
AutomationList& automation() { return _automation; } boost::shared_ptr<AutomationList> automation() { return _automation; }
/* old school automation loading */ /* old school automation loading */
@ -165,7 +165,7 @@ class BaseStereoPanner : public StreamPanner
float left_interp; float left_interp;
float right_interp; float right_interp;
AutomationList _automation; boost::shared_ptr<AutomationList> _automation;
}; };
class EqualPowerStereoPanner : public BaseStereoPanner class EqualPowerStereoPanner : public BaseStereoPanner
@ -208,7 +208,7 @@ class Multi2dPanner : public StreamPanner
/* TODO: StreamPanner is-a Automatable? */ /* 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 (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes);
void distribute_automated (AudioBuffer& src, BufferSet& obufs, void distribute_automated (AudioBuffer& src, BufferSet& obufs,
@ -226,7 +226,7 @@ class Multi2dPanner : public StreamPanner
int load (istream&, string path, uint32_t&); int load (istream&, string path, uint32_t&);
private: private:
AutomationList _automation; boost::shared_ptr<AutomationList> _automation;
void update (); void update ();
}; };

View file

@ -109,7 +109,6 @@ class PluginInsert : public Processor
void init (); void init ();
void set_automatable (); void set_automatable ();
void auto_state_changed (ParamID which); void auto_state_changed (ParamID which);
void automation_list_creation_callback (ParamID, AutomationList&);
int32_t count_for_configuration (ChanCount in, ChanCount out) const; int32_t count_for_configuration (ChanCount in, ChanCount out) const;

View 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); } 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 bool can_support_input_configuration (ChanCount in) const { return true; }
virtual ChanCount output_for_input_configuration (ChanCount in) const { return in; } virtual ChanCount output_for_input_configuration (ChanCount in) const { return in; }
virtual ChanCount output_streams() const { return _configured_input; } virtual ChanCount output_streams() const { return _configured_input; }

View file

@ -81,9 +81,9 @@ class Route : public IO
long order_key (const char* name) const; long order_key (const char* name) const;
void set_order_key (const char* name, long n); void set_order_key (const char* name, long n);
bool hidden() const { return _flags & Hidden; } bool is_hidden() const { return _flags & Hidden; }
bool master() const { return _flags & MasterOut; } bool is_master() const { return _flags & MasterOut; }
bool control() const { return _flags & ControlOut; } bool is_control() const { return _flags & ControlOut; }
/* these are the core of the API of a Route. see the protected sections as well */ /* 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; ToggleType type;
}; };
PBD::Controllable& solo_control() { boost::shared_ptr<PBD::Controllable> solo_control() {
return _solo_control; return _solo_control;
} }
PBD::Controllable& mute_control() { boost::shared_ptr<PBD::Controllable> mute_control() {
return _mute_control; return _mute_control;
} }
@ -306,8 +306,8 @@ class Route : public IO
std::string _comment; std::string _comment;
bool _have_internal_generator; bool _have_internal_generator;
ToggleControllable _solo_control; boost::shared_ptr<ToggleControllable> _solo_control;
ToggleControllable _mute_control; boost::shared_ptr<ToggleControllable> _mute_control;
nframes_t check_initial_delay (nframes_t, nframes_t&, nframes_t&); nframes_t check_initial_delay (nframes_t, nframes_t&, nframes_t&);

View file

@ -653,6 +653,8 @@ class Session : public PBD::StatefulDestructible
void add_curve(Curve*); void add_curve(Curve*);
void add_automation_list(AutomationList*); void add_automation_list(AutomationList*);
nframes_t automation_interval () const { return _automation_interval; }
/* fade curves */ /* fade curves */
float get_default_fade_length () const { return default_fade_msecs; } float get_default_fade_length () const { return default_fade_msecs; }
@ -917,9 +919,9 @@ class Session : public PBD::StatefulDestructible
/* Controllables */ /* 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*); void remove_controllable (PBD::Controllable*);
protected: protected:
@ -1648,6 +1650,8 @@ class Session : public PBD::StatefulDestructible
void allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, bool force); void allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, bool force);
uint32_t _npan_buffers; uint32_t _npan_buffers;
nframes_t _automation_interval;
/* VST support */ /* VST support */
long _vst_callback (VSTPlugin*, long _vst_callback (VSTPlugin*,
@ -1672,7 +1676,7 @@ class Session : public PBD::StatefulDestructible
LayerModel layer_model; LayerModel layer_model;
CrossfadeModel xfade_model; CrossfadeModel xfade_model;
typedef std::set<PBD::Controllable*> Controllables; typedef std::set<boost::shared_ptr<PBD::Controllable> > Controllables;
Glib::Mutex controllables_lock; Glib::Mutex controllables_lock;
Controllables controllables; Controllables controllables;

View file

@ -83,7 +83,7 @@ class Track : public Route
XMLNode& get_template(); XMLNode& get_template();
virtual int set_state(const XMLNode& node) = 0; 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; bool record_enabled() const;
void set_record_enable (bool yn, void *src); void set_record_enable (bool yn, void *src);
@ -141,8 +141,9 @@ class Track : public Route
XMLNode* pending_state; XMLNode* pending_state;
sigc::connection recenable_connection; sigc::connection recenable_connection;
sigc::connection ic_connection; sigc::connection ic_connection;
RecEnableControllable _rec_enable_control;
bool _destructive; bool _destructive;
boost::shared_ptr<RecEnableControllable> _rec_enable_control;
}; };
}; /* namespace ARDOUR*/ }; /* namespace ARDOUR*/

View file

@ -278,8 +278,8 @@ AudioTrack::_set_state (const XMLNode& node, bool call_base)
child = *niter; child = *niter;
if (child->name() == X_("recenable")) { if (child->name() == X_("recenable")) {
_rec_enable_control.set_state (*child); _rec_enable_control->set_state (*child);
_session.add_controllable (&_rec_enable_control); _session.add_controllable (_rec_enable_control);
} }
} }
@ -334,7 +334,7 @@ AudioTrack::state(bool full_state)
_diskstream->id().print (buf, sizeof (buf)); _diskstream->id().print (buf, sizeof (buf));
root.add_property ("diskstream-id", 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; 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()) { if (!diskstream->record_enabled() && _session.transport_rolling()) {
Glib::Mutex::Lock am (_automation_lock, Glib::TRY_LOCK); Glib::Mutex::Lock am (_automation_lock, Glib::TRY_LOCK);
if (am.locked() && gain_automation().automation_playback()) { if (am.locked() && gain_control()->list()->automation_playback()) {
apply_gain_automation = gain_automation().curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes); 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) { for (BufferSet::audio_iterator bi = buffers.audio_begin(); bi != buffers.audio_end(); ++bi) {
Sample *b = bi->data(); Sample *b = bi->data();

View file

@ -72,20 +72,20 @@ AudioRegion::init ()
/* constructor for use by derived types only */ /* constructor for use by derived types only */
AudioRegion::AudioRegion (nframes_t start, nframes_t length, string name) AudioRegion::AudioRegion (nframes_t start, nframes_t length, string name)
: Region (start, length, name, DataType::AUDIO), : Region (start, length, name, DataType::AUDIO)
_fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0), , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
_fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0), , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
_envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0) , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
{ {
init (); init ();
} }
/** Basic AudioRegion constructor (one channel) */ /** Basic AudioRegion constructor (one channel) */
AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length) 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)), : 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_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
_fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0), , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
_envelope (ParamID(EnvelopeAutomation), 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); boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
if (afs) { if (afs) {
@ -98,9 +98,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
/* Basic AudioRegion constructor (one channel) */ /* 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) 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) : Region (src, start, length, name, DataType::AUDIO, layer, flags)
, _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0) , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
, _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0) , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
, _envelope (ParamID(EnvelopeAutomation), 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); boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
if (afs) { if (afs) {
@ -113,9 +113,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
/* Basic AudioRegion constructor (many channels) */ /* Basic AudioRegion constructor (many channels) */
AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags) 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) : Region (srcs, start, length, name, DataType::AUDIO, layer, flags)
, _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0) , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
, _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0) , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
, _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0) , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
{ {
init (); 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 */ /** 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) 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), : Region (other, offset, length, name, layer, flags)
_fade_in (other->_fade_in), , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
_fade_out (other->_fade_out), , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
_envelope (other->_envelope, (double) offset, (double) offset + length) , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
{ {
/* return to default fades if the existing ones are too long */ /* return to default fades if the existing ones are too long */
_fade_in_disabled = 0; _fade_in_disabled = 0;
@ -134,7 +134,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
if (_flags & LeftOfSplit) { if (_flags & LeftOfSplit) {
if (_fade_in.back()->when >= _length) { if (_fade_in->back()->when >= _length) {
set_default_fade_in (); set_default_fade_in ();
} else { } else {
_fade_in_disabled = other->_fade_in_disabled; _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 (_flags & RightOfSplit) {
if (_fade_out.back()->when >= _length) { if (_fade_out->back()->when >= _length) {
set_default_fade_out (); set_default_fade_out ();
} else { } else {
_fade_out_disabled = other->_fade_out_disabled; _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) AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
: Region (other), : Region (other)
_fade_in (other->_fade_in), , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
_fade_out (other->_fade_out), , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
_envelope (other->_envelope) , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
{ {
_scale_amplitude = other->_scale_amplitude; _scale_amplitude = other->_scale_amplitude;
_envelope = other->_envelope; _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) AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node)
: Region (src, node) : Region (src, node)
, _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0) , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
, _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0) , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
, _envelope (ParamID(EnvelopeAutomation), 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); boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
if (afs) { if (afs) {
@ -201,9 +201,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node) AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
: Region (srcs, node) : Region (srcs, node)
, _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0) , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0))
, _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0) , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0))
, _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0) , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0))
{ {
set_default_fades (); set_default_fades ();
_scale_amplitude = 1.0; _scale_amplitude = 1.0;
@ -224,9 +224,9 @@ AudioRegion::~AudioRegion ()
void void
AudioRegion::listen_to_my_curves () AudioRegion::listen_to_my_curves ()
{ {
_envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed)); _envelope->StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
_fade_in.StateChanged.connect (mem_fun (*this, &AudioRegion::fade_in_changed)); _fade_in->StateChanged.connect (mem_fun (*this, &AudioRegion::fade_in_changed));
_fade_out.StateChanged.connect (mem_fun (*this, &AudioRegion::fade_out_changed)); _fade_out->StateChanged.connect (mem_fun (*this, &AudioRegion::fade_out_changed));
} }
bool bool
@ -395,7 +395,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
if (_flags & FadeIn) { 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 */ /* 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); 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) { for (nframes_t n = 0; n < limit; ++n) {
mixdown_buffer[n] *= gain_buffer[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_start = max(internal_offset, _length-fade_out_length);
nframes_t fade_interval_end = min(internal_offset + to_read, _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 curve_offset = fade_interval_start - (_length-fade_out_length);
nframes_t fade_offset = fade_interval_start - internal_offset; 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) { for (nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
mixdown_buffer[m] *= gain_buffer[n]; mixdown_buffer[m] *= gain_buffer[n];
@ -459,7 +459,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
/* Regular gain curves */ /* Regular gain curves */
if (envelope_active()) { 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) { if (_scale_amplitude != 1.0f) {
for (nframes_t n = 0; n < to_read; ++n) { for (nframes_t n = 0; n < to_read; ++n) {
@ -521,7 +521,7 @@ AudioRegion::state (bool full)
if ((_flags & DefaultFadeIn)) { if ((_flags & DefaultFadeIn)) {
child->add_property (X_("default"), X_("yes")); child->add_property (X_("default"), X_("yes"));
} else { } 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")); child->add_property (X_("active"), _fade_in_disabled ? X_("no") : X_("yes"));
@ -531,7 +531,7 @@ AudioRegion::state (bool full)
if ((_flags & DefaultFadeOut)) { if ((_flags & DefaultFadeOut)) {
child->add_property (X_("default"), X_("yes")); child->add_property (X_("default"), X_("yes"));
} else { } 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")); 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 // 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. // so, if they are both at 1.0f, that means the default region.
if (_envelope.size() == 2 && if (_envelope->size() == 2 &&
_envelope.front()->value == 1.0f && _envelope->front()->value == 1.0f &&
_envelope.back()->value==1.0f) { _envelope->back()->value==1.0f) {
if (_envelope.front()->when == 0 && _envelope.back()->when == _length) { if (_envelope->front()->when == 0 && _envelope->back()->when == _length) {
default_env = true; default_env = true;
} }
} }
@ -556,7 +556,7 @@ AudioRegion::state (bool full)
if (default_env) { if (default_env) {
child->add_property ("default", "yes"); child->add_property ("default", "yes");
} else { } else {
child->add_child_nocopy (_envelope.get_state ()); child->add_child_nocopy (_envelope->get_state ());
} }
} else { } else {
@ -617,28 +617,28 @@ AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool sen
if (child->name() == "Envelope") { 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 (); set_default_envelope ();
} }
_envelope.set_max_xval (_length); _envelope->set_max_xval (_length);
_envelope.truncate_end (_length); _envelope->truncate_end (_length);
} else if (child->name() == "FadeIn") { } 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 (); set_default_fade_in ();
} }
} else if (child->name() == "FadeOut") { } 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 (); set_default_fade_out ();
} }
} }
@ -665,70 +665,70 @@ AudioRegion::set_state (const XMLNode& node)
void void
AudioRegion::set_fade_in_shape (FadeShape shape) 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 void
AudioRegion::set_fade_out_shape (FadeShape shape) 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 void
AudioRegion::set_fade_in (FadeShape shape, nframes_t len) AudioRegion::set_fade_in (FadeShape shape, nframes_t len)
{ {
_fade_in.freeze (); _fade_in->freeze ();
_fade_in.clear (); _fade_in->clear ();
switch (shape) { switch (shape) {
case Linear: case Linear:
_fade_in.fast_simple_add (0.0, 0.0); _fade_in->fast_simple_add (0.0, 0.0);
_fade_in.fast_simple_add (len, 1.0); _fade_in->fast_simple_add (len, 1.0);
break; break;
case Fast: case Fast:
_fade_in.fast_simple_add (0, 0); _fade_in->fast_simple_add (0, 0);
_fade_in.fast_simple_add (len * 0.389401, 0.0333333); _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.629032, 0.0861111);
_fade_in.fast_simple_add (len * 0.829493, 0.233333); _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.9447, 0.483333);
_fade_in.fast_simple_add (len * 0.976959, 0.697222); _fade_in->fast_simple_add (len * 0.976959, 0.697222);
_fade_in.fast_simple_add (len, 1); _fade_in->fast_simple_add (len, 1);
break; break;
case Slow: case Slow:
_fade_in.fast_simple_add (0, 0); _fade_in->fast_simple_add (0, 0);
_fade_in.fast_simple_add (len * 0.0207373, 0.197222); _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.0645161, 0.525);
_fade_in.fast_simple_add (len * 0.152074, 0.802778); _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.276498, 0.919444);
_fade_in.fast_simple_add (len * 0.481567, 0.980556); _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 * 0.767281, 1);
_fade_in.fast_simple_add (len, 1); _fade_in->fast_simple_add (len, 1);
break; break;
case LogA: case LogA:
_fade_in.fast_simple_add (0, 0); _fade_in->fast_simple_add (0, 0);
_fade_in.fast_simple_add (len * 0.0737327, 0.308333); _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.246544, 0.658333);
_fade_in.fast_simple_add (len * 0.470046, 0.886111); _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.652074, 0.972222);
_fade_in.fast_simple_add (len * 0.771889, 0.988889); _fade_in->fast_simple_add (len * 0.771889, 0.988889);
_fade_in.fast_simple_add (len, 1); _fade_in->fast_simple_add (len, 1);
break; break;
case LogB: case LogB:
_fade_in.fast_simple_add (0, 0); _fade_in->fast_simple_add (0, 0);
_fade_in.fast_simple_add (len * 0.304147, 0.0694444); _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.529954, 0.152778);
_fade_in.fast_simple_add (len * 0.725806, 0.333333); _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.847926, 0.558333);
_fade_in.fast_simple_add (len * 0.919355, 0.730556); _fade_in->fast_simple_add (len * 0.919355, 0.730556);
_fade_in.fast_simple_add (len, 1); _fade_in->fast_simple_add (len, 1);
break; break;
} }
_fade_in.thaw (); _fade_in->thaw ();
_fade_in_shape = shape; _fade_in_shape = shape;
send_change (FadeInChanged); send_change (FadeInChanged);
@ -737,56 +737,56 @@ AudioRegion::set_fade_in (FadeShape shape, nframes_t len)
void void
AudioRegion::set_fade_out (FadeShape shape, nframes_t len) AudioRegion::set_fade_out (FadeShape shape, nframes_t len)
{ {
_fade_out.freeze (); _fade_out->freeze ();
_fade_out.clear (); _fade_out->clear ();
switch (shape) { switch (shape) {
case Fast: case Fast:
_fade_out.fast_simple_add (len * 0, 1); _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.023041, 0.697222);
_fade_out.fast_simple_add (len * 0.0553, 0.483333); _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.170507, 0.233333);
_fade_out.fast_simple_add (len * 0.370968, 0.0861111); _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 * 0.610599, 0.0333333);
_fade_out.fast_simple_add (len * 1, 0); _fade_out->fast_simple_add (len * 1, 0);
break; break;
case LogA: case LogA:
_fade_out.fast_simple_add (len * 0, 1); _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.228111, 0.988889);
_fade_out.fast_simple_add (len * 0.347926, 0.972222); _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.529954, 0.886111);
_fade_out.fast_simple_add (len * 0.753456, 0.658333); _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 * 0.9262673, 0.308333);
_fade_out.fast_simple_add (len * 1, 0); _fade_out->fast_simple_add (len * 1, 0);
break; break;
case Slow: case Slow:
_fade_out.fast_simple_add (len * 0, 1); _fade_out->fast_simple_add (len * 0, 1);
_fade_out.fast_simple_add (len * 0.305556, 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.548611, 0.991736);
_fade_out.fast_simple_add (len * 0.759259, 0.931129); _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.918981, 0.68595);
_fade_out.fast_simple_add (len * 0.976852, 0.22865); _fade_out->fast_simple_add (len * 0.976852, 0.22865);
_fade_out.fast_simple_add (len * 1, 0); _fade_out->fast_simple_add (len * 1, 0);
break; break;
case LogB: case LogB:
_fade_out.fast_simple_add (len * 0, 1); _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.080645, 0.730556);
_fade_out.fast_simple_add (len * 0.277778, 0.289256); _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.470046, 0.152778);
_fade_out.fast_simple_add (len * 0.695853, 0.0694444); _fade_out->fast_simple_add (len * 0.695853, 0.0694444);
_fade_out.fast_simple_add (len * 1, 0); _fade_out->fast_simple_add (len * 1, 0);
break; break;
case Linear: case Linear:
_fade_out.fast_simple_add (len * 0, 1); _fade_out->fast_simple_add (len * 0, 1);
_fade_out.fast_simple_add (len * 1, 0); _fade_out->fast_simple_add (len * 1, 0);
break; break;
} }
_fade_out.thaw (); _fade_out->thaw ();
_fade_out_shape = shape; _fade_out_shape = shape;
send_change (FadeOutChanged); send_change (FadeOutChanged);
@ -795,7 +795,7 @@ AudioRegion::set_fade_out (FadeShape shape, nframes_t len)
void void
AudioRegion::set_fade_in_length (nframes_t len) AudioRegion::set_fade_in_length (nframes_t len)
{ {
bool changed = _fade_in.extend_to (len); bool changed = _fade_in->extend_to (len);
if (changed) { if (changed) {
_flags = Flag (_flags & ~DefaultFadeIn); _flags = Flag (_flags & ~DefaultFadeIn);
@ -806,7 +806,7 @@ AudioRegion::set_fade_in_length (nframes_t len)
void void
AudioRegion::set_fade_out_length (nframes_t len) AudioRegion::set_fade_out_length (nframes_t len)
{ {
bool changed = _fade_out.extend_to (len); bool changed = _fade_out->extend_to (len);
if (changed) { if (changed) {
_flags = Flag (_flags & ~DefaultFadeOut); _flags = Flag (_flags & ~DefaultFadeOut);
@ -848,13 +848,13 @@ AudioRegion::set_fade_out_active (bool yn)
bool bool
AudioRegion::fade_in_is_default () const 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 bool
AudioRegion::fade_out_is_default () const 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 void
@ -881,11 +881,11 @@ AudioRegion::set_default_fades ()
void void
AudioRegion::set_default_envelope () AudioRegion::set_default_envelope ()
{ {
_envelope.freeze (); _envelope->freeze ();
_envelope.clear (); _envelope->clear ();
_envelope.fast_simple_add (0, 1.0f); _envelope->fast_simple_add (0, 1.0f);
_envelope.fast_simple_add (_length, 1.0f); _envelope->fast_simple_add (_length, 1.0f);
_envelope.thaw (); _envelope->thaw ();
} }
void void
@ -895,18 +895,18 @@ AudioRegion::recompute_at_end ()
based on the the existing curve. based on the the existing curve.
*/ */
_envelope.freeze (); _envelope->freeze ();
_envelope.truncate_end (_length); _envelope->truncate_end (_length);
_envelope.set_max_xval (_length); _envelope->set_max_xval (_length);
_envelope.thaw (); _envelope->thaw ();
if (_fade_in.back()->when > _length) { if (_fade_in->back()->when > _length) {
_fade_in.extend_to (_length); _fade_in->extend_to (_length);
send_change (FadeInChanged); send_change (FadeInChanged);
} }
if (_fade_out.back()->when > _length) { if (_fade_out->back()->when > _length) {
_fade_out.extend_to (_length); _fade_out->extend_to (_length);
send_change (FadeOutChanged); send_change (FadeOutChanged);
} }
} }
@ -916,15 +916,15 @@ AudioRegion::recompute_at_start ()
{ {
/* as above, but the shift was from the front */ /* as above, but the shift was from the front */
_envelope.truncate_start (_length); _envelope->truncate_start (_length);
if (_fade_in.back()->when > _length) { if (_fade_in->back()->when > _length) {
_fade_in.extend_to (_length); _fade_in->extend_to (_length);
send_change (FadeInChanged); send_change (FadeInChanged);
} }
if (_fade_out.back()->when > _length) { if (_fade_out->back()->when > _length) {
_fade_out.extend_to (_length); _fade_out->extend_to (_length);
send_change (FadeOutChanged); send_change (FadeOutChanged);
} }
} }

View file

@ -54,7 +54,7 @@ Automatable::old_set_automation_state (const XMLNode& node)
uint32_t what; uint32_t what;
stringstream sstr; stringstream sstr;
_visible_parameter_automation.clear (); _visible_controls.clear ();
sstr << prop->value(); sstr << prop->value();
while (1) { while (1) {
@ -66,6 +66,8 @@ Automatable::old_set_automation_state (const XMLNode& node)
} }
} }
_last_automation_snapshot = 0;
return 0; return 0;
} }
@ -89,7 +91,9 @@ Automatable::load_automation (const string& path)
Glib::Mutex::Lock lm (_automation_lock); Glib::Mutex::Lock lm (_automation_lock);
set<ParamID> tosave; set<ParamID> tosave;
_parameter_automation.clear (); _controls.clear ();
_last_automation_snapshot = 0;
while (in) { while (in) {
double when; double when;
@ -101,8 +105,8 @@ Automatable::load_automation (const string& path)
in >> value; if (!in) goto bad; in >> value; if (!in) goto bad;
/* FIXME: this is legacy and only used for plugin inserts? I think? */ /* FIXME: this is legacy and only used for plugin inserts? I think? */
AutomationList* al = automation_list (ParamID(PluginAutomation, port), true); boost::shared_ptr<AutomationControl> c = control (ParamID(PluginAutomation, port), true);
al->add (when, value); c->list()->add (when, value);
tosave.insert (ParamID(PluginAutomation, port)); tosave.insert (ParamID(PluginAutomation, port));
} }
@ -110,32 +114,35 @@ Automatable::load_automation (const string& path)
bad: bad:
error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg; error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg;
_parameter_automation.clear (); _controls.clear ();
return -1; return -1;
} }
void void
Automatable::add_automation_parameter(AutomationList* al) Automatable::add_control(boost::shared_ptr<AutomationControl> ac)
{ {
_parameter_automation[al->param_id()] = al; ParamID param = ac->list()->param_id();
/* let derived classes do whatever they need with this */ _controls[param] = ac;
automation_list_creation_callback (al->param_id(), *al);
cerr << _name << ": added parameter " << al->param_id().to_string() << endl; cerr << _name << ": added parameter " << param.to_string() << endl;
// FIXME: sane default behaviour? // FIXME: sane default behaviour?
_visible_parameter_automation.insert(al->param_id()); _visible_controls.insert(param);
_can_automate_list.insert(al->param_id()); _can_automate_list.insert(param);
// Sync everything (derived classes) up to initial values
auto_state_changed(param);
} }
void void
Automatable::what_has_automation (set<ParamID>& s) const Automatable::what_has_automation (set<ParamID>& s) const
{ {
Glib::Mutex::Lock lm (_automation_lock); 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); s.insert ((*li).first);
} }
} }
@ -146,42 +153,45 @@ Automatable::what_has_visible_automation (set<ParamID>& s) const
Glib::Mutex::Lock lm (_automation_lock); Glib::Mutex::Lock lm (_automation_lock);
set<ParamID>::const_iterator li; 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); s.insert (*li);
} }
} }
/** Returns NULL if we don't have an AutomationList for \a parameter. /** Returns NULL if we don't have an AutomationList for \a parameter.
*/ */
AutomationList* boost::shared_ptr<AutomationControl>
Automatable::automation_list (ParamID parameter, bool create_if_missing) 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; return i->second;
} else if (create_if_missing) { } else if (create_if_missing) {
AutomationList* al = new AutomationList (parameter, FLT_MIN, FLT_MAX, default_parameter_value (parameter)); assert(parameter.type() != GainAutomation);
add_automation_parameter(al); boost::shared_ptr<AutomationList> al (new AutomationList (
return al; parameter, FLT_MIN, FLT_MAX, default_parameter_value (parameter)));
boost::shared_ptr<AutomationControl> ac (new AutomationControl(_session, al));
add_control(ac);
return ac;
} else { } else {
//warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg; //warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg;
return NULL; return boost::shared_ptr<AutomationControl>();
} }
} }
const AutomationList* boost::shared_ptr<const AutomationControl>
Automatable::automation_list (ParamID parameter) const 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; return i->second;
} else { } else {
//warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg; //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)) else if (param == ParamID(PanAutomation))
return _("Pan"); return _("Pan");
else if (param.type() == MidiCCAutomation) else if (param.type() == MidiCCAutomation)
return string_compose("MIDI CC %1", param.id()); return string_compose("CC %1", param.id());
else else
return param.to_string(); return param.to_string();
} }
@ -211,12 +221,12 @@ void
Automatable::mark_automation_visible (ParamID what, bool yn) Automatable::mark_automation_visible (ParamID what, bool yn)
{ {
if (yn) { if (yn) {
_visible_parameter_automation.insert (what); _visible_controls.insert (what);
} else { } else {
set<ParamID>::iterator i; set<ParamID>::iterator i;
if ((i = _visible_parameter_automation.find (what)) != _visible_parameter_automation.end()) { if ((i = _visible_controls.find (what)) != _visible_controls.end()) {
_visible_parameter_automation.erase (i); _visible_controls.erase (i);
} }
} }
} }
@ -224,24 +234,24 @@ Automatable::mark_automation_visible (ParamID what, bool yn)
bool bool
Automatable::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_event) const 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; AutomationList::TimeComparator cmp;
next_event.when = max_frames; 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; AutomationList::const_iterator i;
const AutomationList& alist (*((*li).second)); boost::shared_ptr<const AutomationList> alist (li->second->list());
ControlEvent cp (now, 0.0f); 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) { if ((*i)->when > now) {
break; break;
} }
} }
if (i != alist.const_end() && (*i)->when < end) { if (i != alist->const_end() && (*i)->when < end) {
if ((*i)->when < next_event.when) { if ((*i)->when < next_event.when) {
next_event.when = (*i)->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); Glib::Mutex::Lock lm (_automation_lock);
_parameter_automation.clear (); /* Don't clear controls, since some may be special derived Controllable classes */
_visible_parameter_automation.clear ();
_visible_controls.clear ();
XMLNodeList nlist = node.children(); XMLNodeList nlist = node.children();
XMLNodeIterator niter; 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); 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) { if (!id_prop) {
warning << "AutomationList node without automation-id property, " 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); 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 { } else {
error << "Expected AutomationList node, got '" << (*niter)->name() << endmsg; error << "Expected AutomationList node, got '" << (*niter)->name() << endmsg;
} }
} }
_last_automation_snapshot = 0;
return 0; return 0;
} }
@ -304,16 +321,12 @@ Automatable::get_automation_state ()
Glib::Mutex::Lock lm (_automation_lock); Glib::Mutex::Lock lm (_automation_lock);
XMLNode* node = new XMLNode (X_("Automation")); XMLNode* node = new XMLNode (X_("Automation"));
cerr << "'" << _name << "'->get_automation_state, # params = " << _parameter_automation.size() << endl; if (_controls.empty()) {
if (_parameter_automation.empty()) {
return *node; return *node;
} }
map<ParamID,AutomationList*>::iterator li; for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) {
node->add_child_nocopy (li->second->list()->get_state ());
for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
node->add_child_nocopy (li->second->get_state ());
} }
return *node; return *node;
@ -324,10 +337,8 @@ Automatable::clear_automation ()
{ {
Glib::Mutex::Lock lm (_automation_lock); Glib::Mutex::Lock lm (_automation_lock);
map<ParamID,AutomationList*>::iterator li; for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li)
li->second->list()->clear();
for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li)
li->second->clear();
} }
void void
@ -335,10 +346,10 @@ Automatable::set_parameter_automation_state (ParamID param, AutoState s)
{ {
Glib::Mutex::Lock lm (_automation_lock); 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()) { if (s != c->list()->automation_state()) {
al->set_automation_state (s); c->list()->set_automation_state (s);
_session.set_dirty (); _session.set_dirty ();
} }
} }
@ -348,10 +359,10 @@ Automatable::get_parameter_automation_state (ParamID param)
{ {
Glib::Mutex::Lock lm (_automation_lock); Glib::Mutex::Lock lm (_automation_lock);
AutomationList* al = automation_list(param); boost::shared_ptr<AutomationControl> c = control(param);
if (al) { if (c) {
return al->automation_state(); return c->list()->automation_state();
} else { } else {
return Off; return Off;
} }
@ -362,10 +373,10 @@ Automatable::set_parameter_automation_style (ParamID param, AutoStyle s)
{ {
Glib::Mutex::Lock lm (_automation_lock); 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()) { if (s != c->list()->automation_style()) {
al->set_automation_style (s); c->list()->set_automation_style (s);
_session.set_dirty (); _session.set_dirty ();
} }
} }
@ -375,10 +386,10 @@ Automatable::get_parameter_automation_style (ParamID param)
{ {
Glib::Mutex::Lock lm (_automation_lock); Glib::Mutex::Lock lm (_automation_lock);
AutomationList* al = automation_list(param); boost::shared_ptr<AutomationControl> c = control(param);
if (al) { if (c) {
return al->automation_style(); return c->list()->automation_style();
} else { } else {
return Absolute; // whatever return Absolute; // whatever
} }
@ -393,14 +404,14 @@ Automatable::protect_automation ()
for (set<ParamID>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) { 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: case Write:
al->set_automation_state (Off); c->list()->set_automation_state (Off);
break; break;
case Touch: case Touch:
al->set_automation_state (Play); c->list()->set_automation_state (Play);
break; break;
default: default:
break; 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;
}
}

View file

@ -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 */
}

View file

@ -1195,8 +1195,6 @@ AutomationList::get_state ()
XMLNode& XMLNode&
AutomationList::state (bool full) AutomationList::state (bool full)
{ {
cerr << _param_id.to_string() << "->state()" << endl;
XMLNode* root = new XMLNode (X_("AutomationList")); XMLNode* root = new XMLNode (X_("AutomationList"));
char buf[64]; char buf[64];
LocaleGuard lg (X_("POSIX")); LocaleGuard lg (X_("POSIX"));
@ -1208,11 +1206,11 @@ AutomationList::state (bool full)
snprintf (buf, sizeof (buf), "%.12g", _default_value); snprintf (buf, sizeof (buf), "%.12g", _default_value);
root->add_property ("default", buf); root->add_property ("default", buf);
snprintf (buf, sizeof (buf), "%.12g", _min_yval); 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); 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); snprintf (buf, sizeof (buf), "%.12g", _max_xval);
root->add_property ("_max_xval", buf); root->add_property ("max_xval", buf);
if (full) { if (full) {
root->add_property ("state", auto_state_to_string (_state)); root->add_property ("state", auto_state_to_string (_state));
@ -1390,19 +1388,19 @@ AutomationList::set_state (const XMLNode& node)
_state = Off; _state = Off;
} }
if ((prop = node.property (X_("_min_yval"))) != 0) { if ((prop = node.property (X_("min_yval"))) != 0) {
_min_yval = atof (prop->value ()); _min_yval = atof (prop->value ());
} else { } else {
_min_yval = FLT_MIN; _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 ()); _max_yval = atof (prop->value ());
} else { } else {
_max_yval = FLT_MAX; _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 ()); _max_xval = atof (prop->value ());
} else { } else {
_max_xval = 0; // means "no limit ; _max_xval = 0; // means "no limit ;

View file

@ -62,8 +62,6 @@ using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
nframes_t IO::_automation_interval = 0;
const string IO::state_node_name = "IO"; const string IO::state_node_name = "IO";
bool IO::connecting_legal = false; bool IO::connecting_legal = false;
bool IO::ports_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. others can be imagined.
*/ */
#if 0
static gain_t direct_control_to_gain (double fract) { 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 ... */ /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
/* this maxes at +6dB */ /* 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); 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 /** @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). * 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), : Automatable (s, name),
_output_buffers (new BufferSet()), _output_buffers (new BufferSet()),
_default_type (default_type), _default_type (default_type),
_gain_control (X_("gaincontrol"), *this),
_input_minimum (ChanCount::ZERO), _input_minimum (ChanCount::ZERO),
_input_maximum (ChanCount::INFINITE), _input_maximum (ChanCount::INFINITE),
_output_minimum (ChanCount::ZERO), _output_minimum (ChanCount::ZERO),
@ -135,15 +133,16 @@ IO::IO (Session& s, const string& name,
_phase_invert = false; _phase_invert = false;
deferred_state = 0; 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));
_gain_control = boost::shared_ptr<GainControl>(
new GainControl(X_("gaincontrol"), *this, gl));
add_control(_gain_control);
apply_gain_automation = false; apply_gain_automation = false;
last_automation_snapshot = 0;
/*_gain_automation_state = Off;
_gain_automation_style = Absolute;*/
{ {
// IO::Meter is emitted from another thread so the // IO::Meter is emitted from another thread so the
// Meter signal must be protected. // 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 // Connect to our own MoreChannels signal to connect output buffers
IO::MoreChannels.connect (mem_fun (*this, &IO::attach_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) IO::IO (Session& s, const XMLNode& node, DataType dt)
: Automatable (s, "unnamed io"), : Automatable (s, "unnamed io"),
_output_buffers (new BufferSet()), _output_buffers (new BufferSet()),
_default_type (dt), _default_type (dt)
_gain_control (X_("gaincontrol"), *this)
{ {
_meter = new PeakMeter (_session); _meter = new PeakMeter (_session);
@ -175,6 +173,14 @@ IO::IO (Session& s, const XMLNode& node, DataType dt)
apply_gain_automation = false; 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); 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 // Connect to our own MoreChannels signal to connect output buffers
IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers)); IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
_session.add_controllable (&_gain_control); _session.add_controllable (_gain_control);
} }
IO::~IO () IO::~IO ()
@ -1129,8 +1135,8 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
gain_t gain_t
IO::effective_gain () const IO::effective_gain () const
{ {
if (gain_automation().automation_playback()) { if (_gain_control->list()->automation_playback()) {
return _effective_gain; return _gain_control->get_value();
} else { } else {
return _desired_gain; return _desired_gain;
} }
@ -1272,7 +1278,7 @@ IO::state (bool full_state)
} }
node->add_child_nocopy (_panner->state (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()); snprintf (buf, sizeof(buf), "%2.12f", gain());
node->add_property ("gain", buf); node->add_property ("gain", buf);
@ -1359,7 +1365,7 @@ IO::set_state (const XMLNode& node)
if ((*iter)->name() == X_("controllable")) { if ((*iter)->name() == X_("controllable")) {
if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") { 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); pending_state_node = new XMLNode (node);
} }
last_automation_snapshot = 0;
return 0; return 0;
} }
@ -1458,7 +1462,7 @@ IO::load_automation (string path)
switch (type) { switch (type) {
case 'g': case 'g':
gain_automation().fast_simple_add (when, value); _gain_control->list()->fast_simple_add (when, value);
break; break;
case 's': case 's':
@ -2131,15 +2135,22 @@ IO::output_bundle_configuration_changed ()
} }
void 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 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 void
@ -2193,16 +2204,16 @@ IO::set_parameter_automation_state (ParamID param, AutoState state)
{ {
Glib::Mutex::Lock lm (_automation_lock); 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; changed = true;
last_automation_snapshot = 0; _last_automation_snapshot = 0;
gain_auto.set_automation_state (state); gain_auto->set_automation_state (state);
if (state != Off) { if (state != Off) {
// FIXME: shouldn't this use Curve? // 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) IO::set_gain (gain_t val, void *src)
{ {
// max gain at about +6dB (10.0 ^ ( 6 dB * 0.05)) // 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); Glib::Mutex::Lock dm (declick_lock);
@ -2237,17 +2256,11 @@ IO::set_gain (gain_t val, void *src)
} }
if (_session.transport_stopped()) { if (_session.transport_stopped()) {
_effective_gain = val;
_gain = val; _gain = val;
} }
gain_changed (src); if (_session.transport_stopped() && src != 0 && src != this && _gain_control->list()->automation_write()) {
_gain_control.Changed (); /* EMIT SIGNAL */ _gain_control->list()->add (_session.transport_frame(), val);
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);
} }
@ -2258,7 +2271,7 @@ void
IO::start_pan_touch (uint32_t which) IO::start_pan_touch (uint32_t which)
{ {
if (which < _panner->size()) { 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) IO::end_pan_touch (uint32_t which)
{ {
if (which < _panner->size()) { 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 void
IO::automation_snapshot (nframes_t now) IO::automation_snapshot (nframes_t now)
{ {
if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) { Automatable::automation_snapshot (now);
ARDOUR::AutomationList& gain_auto = gain_automation();
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); _panner->snapshot (now);
last_automation_snapshot = now;
} }
} }
void void
IO::transport_stopped (nframes_t frame) IO::transport_stopped (nframes_t frame)
{ {
ARDOUR::AutomationList& gain_auto = gain_automation(); _gain_control->list()->reposition_for_rt_add (frame);
gain_auto.reposition_for_rt_add (frame); if (_gain_control->list()->automation_state() != Off) {
if (gain_auto.automation_state() != Off) {
/* the src=0 condition is a special signal to not propagate /* the src=0 condition is a special signal to not propagate
automation gain changes into the mix group when locating. automation gain changes into the mix group when locating.
*/ */
// FIXME: shouldn't this use Curve? // 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); _panner->transport_stopped (frame);

View 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 // XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
// Write into playback buffer here, and whatnot? // 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(); dst.clear();
assert(dst.size() == 0); 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) { if (end <= start) {
cerr << "MDS: Reverse? Skipping" << endl;
return; return;
} }

View file

@ -193,8 +193,8 @@ MidiTrack::_set_state (const XMLNode& node, bool call_base)
child = *niter; child = *niter;
if (child->name() == X_("recenable")) { if (child->name() == X_("recenable")) {
_rec_enable_control.set_state (*child); _rec_enable_control->set_state (*child);
_session.add_controllable (&_rec_enable_control); _session.add_controllable (_rec_enable_control);
} }
} }
@ -249,7 +249,7 @@ MidiTrack::state(bool full_state)
_diskstream->id().print (buf, sizeof(buf)); _diskstream->id().print (buf, sizeof(buf));
root.add_property ("diskstream-id", 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; return root;
} }
@ -427,6 +427,15 @@ MidiTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
int dret; int dret;
boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream(); 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()) { if (n_outputs().n_total() == 0 && _processors.empty()) {
return 0; return 0;
} }

View file

@ -71,11 +71,11 @@ static double direct_pan_to_control (pan_t val) {
StreamPanner::StreamPanner (Panner& p) StreamPanner::StreamPanner (Panner& p)
: parent (p), : parent (p),
_control (X_("panner"), *this) _control (new PanControllable(X_("panner"), *this))
{ {
_muted = false; _muted = false;
parent.session().add_controllable (&_control); parent.session().add_controllable (_control);
x = 0.5; x = 0.5;
y = 0.5; y = 0.5;
@ -132,7 +132,7 @@ StreamPanner::set_position (float xpos, bool link_call)
x = xpos; x = xpos;
update (); update ();
Changed (); Changed ();
_control.Changed (); _control->Changed ();
} }
} }
@ -190,7 +190,7 @@ StreamPanner::add_state (XMLNode& node)
/*---------------------------------------------------------------------- */ /*---------------------------------------------------------------------- */
BaseStereoPanner::BaseStereoPanner (Panner& p) 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 void
BaseStereoPanner::snapshot (nframes_t now) BaseStereoPanner::snapshot (nframes_t now)
{ {
if (_automation.automation_state() == Write || _automation.automation_state() == Touch) { if (_automation->automation_state() == Write || _automation->automation_state() == Touch) {
_automation.rt_add (now, x); _automation->rt_add (now, x);
} }
} }
void void
BaseStereoPanner::transport_stopped (nframes_t frame) BaseStereoPanner::transport_stopped (nframes_t frame)
{ {
_automation.reposition_for_rt_add (frame); _automation->reposition_for_rt_add (frame);
if (_automation.automation_state() != Off) { if (_automation->automation_state() != Off) {
set_position (_automation.eval (frame)); set_position (_automation->eval (frame));
} }
} }
void void
BaseStereoPanner::set_automation_style (AutoStyle style) BaseStereoPanner::set_automation_style (AutoStyle style)
{ {
_automation.set_automation_style (style); _automation->set_automation_style (style);
} }
void void
BaseStereoPanner::set_automation_state (AutoState state) 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) { 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]; char line[128];
LocaleGuard lg (X_("POSIX")); LocaleGuard lg (X_("POSIX"));
_automation.clear (); _automation->clear ();
while (in.getline (line, sizeof (line), '\n')) { while (in.getline (line, sizeof (line), '\n')) {
nframes_t when; nframes_t when;
@ -258,12 +258,12 @@ BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt)
continue; continue;
} }
_automation.fast_simple_add (when, value); _automation->fast_simple_add (when, value);
} }
/* now that we are done loading */ /* now that we are done loading */
_automation.StateChanged (); _automation->StateChanged ();
return 0; return 0;
} }
@ -438,7 +438,7 @@ EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& ob
/* fetch positional data */ /* 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 */ /* fallback */
if (!_muted) { if (!_muted) {
distribute (srcbuf, obufs, 1.0, nframes); distribute (srcbuf, obufs, 1.0, nframes);
@ -518,12 +518,12 @@ EqualPowerStereoPanner::state (bool full_state)
root->add_property (X_("type"), EqualPowerStereoPanner::name); root->add_property (X_("type"), EqualPowerStereoPanner::name);
XMLNode* autonode = new XMLNode (X_("Automation")); 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); root->add_child_nocopy (*autonode);
StreamPanner::add_state (*root); StreamPanner::add_state (*root);
root->add_child_nocopy (_control.get_state ()); root->add_child_nocopy (_control->get_state ());
return *root; return *root;
} }
@ -546,15 +546,15 @@ EqualPowerStereoPanner::set_state (const XMLNode& node)
if ((*iter)->name() == X_("controllable")) { if ((*iter)->name() == X_("controllable")) {
if ((prop = (*iter)->property("name")) != 0 && prop->value() == "panner") { if ((prop = (*iter)->property("name")) != 0 && prop->value() == "panner") {
_control.set_state (**iter); _control->set_state (**iter);
} }
} else if ((*iter)->name() == X_("Automation")) { } else if ((*iter)->name() == X_("Automation")) {
_automation.set_state (*((*iter)->children().front())); _automation->set_state (*((*iter)->children().front()));
if (_automation.automation_state() != Off) { if (_automation->automation_state() != Off) {
set_position (_automation.eval (parent.session().transport_frame())); set_position (_automation->eval (parent.session().transport_frame()));
} }
} }
} }
@ -565,7 +565,7 @@ EqualPowerStereoPanner::set_state (const XMLNode& node)
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
Multi2dPanner::Multi2dPanner (Panner& p) 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 (); update ();
} }
@ -930,10 +930,10 @@ Panner::reset (uint32_t nouts, uint32_t npans)
if (changed || ((left == 0.5) && (right == 0.5))) { if (changed || ((left == 0.5) && (right == 0.5))) {
front()->set_position (0.0); front()->set_position (0.0);
front()->automation().reset_default (0.0); front()->automation()->reset_default (0.0);
back()->set_position (1.0); back()->set_position (1.0);
back()->automation().reset_default (1.0); back()->automation()->reset_default (1.0);
changed = true; changed = true;
} }
@ -990,7 +990,7 @@ AutoState
Panner::automation_state () const Panner::automation_state () const
{ {
if (!empty()) { if (!empty()) {
return front()->automation().automation_state (); return front()->automation()->automation_state ();
} else { } else {
return Off; return Off;
} }
@ -1000,7 +1000,7 @@ AutoStyle
Panner::automation_style () const Panner::automation_style () const
{ {
if (!empty()) { if (!empty()) {
return front()->automation().automation_style (); return front()->automation()->automation_style ();
} else { } else {
return Absolute; return Absolute;
} }
@ -1026,7 +1026,7 @@ void
Panner::clear_automation () Panner::clear_automation ()
{ {
for (vector<StreamPanner*>::iterator i = begin(); i != end(); ++i) { for (vector<StreamPanner*>::iterator i = begin(); i != end(); ++i) {
(*i)->automation().clear (); (*i)->automation()->clear ();
} }
_session.set_dirty (); _session.set_dirty ();
} }
@ -1181,7 +1181,7 @@ bool
Panner::touching () const Panner::touching () const
{ {
for (vector<StreamPanner*>::const_iterator i = begin(); i != end(); ++i) { for (vector<StreamPanner*>::const_iterator i = begin(); i != end(); ++i) {
if ((*i)->automation().touching ()) { if ((*i)->automation()->touching ()) {
return true; return true;
} }
} }

View file

@ -142,8 +142,6 @@ void
PluginInsert::init () PluginInsert::init ()
{ {
set_automatable (); set_automatable ();
set<uint32_t>::iterator s;
} }
PluginInsert::~PluginInsert () PluginInsert::~PluginInsert ()
@ -151,22 +149,16 @@ PluginInsert::~PluginInsert ()
GoingAway (); /* EMIT SIGNAL */ 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 void
PluginInsert::auto_state_changed (ParamID which) PluginInsert::auto_state_changed (ParamID which)
{ {
if (which.type() != PluginAutomation) if (which.type() != PluginAutomation)
return; return;
AutomationList* alist = automation_list (which); boost::shared_ptr<AutomationControl> c = control (which);
if (alist && alist->automation_state() != Off) { if (c && c->list()->automation_state() != Off) {
_plugins[0]->set_parameter (which.id(), alist->eval (_session.transport_frame())); _plugins[0]->set_parameter (which.id(), c->list()->eval (_session.transport_frame()));
} }
} }
@ -213,12 +205,23 @@ PluginInsert::is_generator() const
void void
PluginInsert::set_automatable () PluginInsert::set_automatable ()
{ {
set<ParamID> a; set<ParamID> a = _plugins.front()->automatable ();
a = _plugins.front()->automatable (); Plugin::ParameterDescriptor desc;
for (set<ParamID>::iterator i = a.begin(); i != a.end(); ++i) { for (set<ParamID>::iterator i = a.begin(); i != a.end(); ++i) {
if (i->type() == PluginAutomation) {
can_automate (*i); 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) { if (with_auto) {
map<ParamID,AutomationList*>::iterator li; uint32_t n = 0;
uint32_t n;
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; bool valid;
float val = alist.rt_safe_eval (now, valid); float val = c->list()->rt_safe_eval (now, valid);
if (valid) { if (valid) {
/* set the first plugin, the others will be set via signals */ /* 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 void
PluginInsert::automation_snapshot (nframes_t now) PluginInsert::automation_snapshot (nframes_t now)
{ {
map<ParamID,AutomationList*>::iterator li; for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) {
for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) { boost::shared_ptr<AutomationControl> c = li->second;
AutomationList *alist = ((*li).second); if (c->list() != 0 && c->list()->param_id().type() == PluginAutomation
if (alist != 0 && alist->param_id().type() == PluginAutomation && c->list()->automation_write ()) {
&& alist->automation_write ()) {
float val = _plugins[0]->get_parameter ((*li).first); float val = _plugins[0]->get_parameter (c->list()->param_id());
alist->rt_add (now, val); c->list()->rt_add (now, val);
_last_automation_snapshot = now; _last_automation_snapshot = now;
} }
} }
@ -325,14 +326,14 @@ PluginInsert::automation_snapshot (nframes_t now)
void void
PluginInsert::transport_stopped (nframes_t now) PluginInsert::transport_stopped (nframes_t now)
{ {
map<ParamID,AutomationList*>::iterator li; for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) {
for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) { boost::shared_ptr<AutomationControl> c = li->second;
AutomationList& alist (*(li->second));
alist.reposition_for_rt_add (now);
if (alist.param_id().type() == PluginAutomation && alist.automation_state() != Off) { c->list()->reposition_for_rt_add (now);
_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); _plugins[0]->set_parameter (param.id(), val);
if (automation_list (param) && automation_list (param)->automation_write()) { boost::shared_ptr<AutomationControl> c = control (param);
automation_list (param)->add (_session.audible_frame(), val);
if (c && c->list()->automation_write()) {
c->list()->add (_session.audible_frame(), val);
} }
_session.set_dirty(); _session.set_dirty();
@ -660,7 +663,7 @@ PluginInsert::state (bool full)
child->add_child_nocopy (automation_list (*x).state (full)); child->add_child_nocopy (automation_list (*x).state (full));
autonode->add_child_nocopy (*child); 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); node.add_child_nocopy (*autonode);
@ -791,7 +794,7 @@ PluginInsert::set_state(const XMLNode& node)
} }
if (!child->children().empty()) { 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 { } else {
if ((cprop = child->property("auto")) != 0) { if ((cprop = child->property("auto")) != 0) {
@ -799,13 +802,13 @@ PluginInsert::set_state(const XMLNode& node)
int x; int x;
sscanf (cprop->value().c_str(), "0x%x", &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 { } else {
/* missing */ /* missing */
automation_list (ParamID(PluginAutomation, port_id), true)->set_automation_state (Off); control (ParamID(PluginAutomation, port_id), true)->list()->set_automation_state (Off);
} }
} }

View file

@ -157,8 +157,8 @@ Processor::state (bool full_state)
XMLNode& automation = Automatable::get_automation_state(); XMLNode& automation = Automatable::get_automation_state();
for (set<ParamID>::iterator x = _visible_parameter_automation.begin(); x != _visible_parameter_automation.end(); ++x) { for (set<ParamID>::iterator x = _visible_controls.begin(); x != _visible_controls.end(); ++x) {
if (x != _visible_parameter_automation.begin()) { if (x != _visible_controls.begin()) {
sstr << ' '; sstr << ' ';
} }
sstr << *x; sstr << *x;
@ -202,7 +202,7 @@ Processor::set_state (const XMLNode& node)
uint32_t what; uint32_t what;
stringstream sstr; stringstream sstr;
_visible_parameter_automation.clear (); _visible_controls.clear ();
sstr << prop->value(); sstr << prop->value();
while (1) { while (1) {

View 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) 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), : IO (sess, name, input_min, input_max, output_min, output_max, default_type),
_flags (flg), _flags (flg),
_solo_control (X_("solo"), *this, ToggleControllable::SoloControl), _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl)),
_mute_control (X_("mute"), *this, ToggleControllable::MuteControl) _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl))
{ {
init (); init ();
} }
Route::Route (Session& sess, const XMLNode& node, DataType default_type) Route::Route (Session& sess, const XMLNode& node, DataType default_type)
: IO (sess, *node.child ("IO"), default_type), : IO (sess, *node.child ("IO"), default_type),
_solo_control (X_("solo"), *this, ToggleControllable::SoloControl), _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl)),
_mute_control (X_("mute"), *this, ToggleControllable::MuteControl) _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl))
{ {
init (); init ();
_set_state (node, false); _set_state (node, false);
@ -177,7 +177,6 @@ Route::set_gain (gain_t val, void *src)
if (_mix_group->is_relative()) { if (_mix_group->is_relative()) {
gain_t usable_gain = gain(); gain_t usable_gain = gain();
if (usable_gain < 0.000001f) { if (usable_gain < 0.000001f) {
usable_gain = 0.000001f; usable_gain = 0.000001f;
@ -190,20 +189,21 @@ Route::set_gain (gain_t val, void *src)
delta -= usable_gain; delta -= usable_gain;
if (delta == 0.0f) return; if (delta == 0.0f)
return;
gain_t factor = delta / usable_gain; gain_t factor = delta / usable_gain;
if (factor > 0.0f) { if (factor > 0.0f) {
factor = _mix_group->get_max_factor(factor); factor = _mix_group->get_max_factor(factor);
if (factor == 0.0f) { if (factor == 0.0f) {
gain_changed (src); _gain_control->Changed(); /* EMIT SIGNAL */
return; return;
} }
} else { } else {
factor = _mix_group->get_min_factor(factor); factor = _mix_group->get_min_factor(factor);
if (factor == 0.0f) { if (factor == 0.0f) {
gain_changed (src); _gain_control->Changed(); /* EMIT SIGNAL */
return; return;
} }
} }
@ -726,7 +726,7 @@ Route::set_solo (bool yn, void *src)
if (_soloed != yn) { if (_soloed != yn) {
_soloed = yn; _soloed = yn;
solo_changed (src); /* EMIT SIGNAL */ 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; _muted = yn;
mute_changed (src); /* EMIT SIGNAL */ mute_changed (src); /* EMIT SIGNAL */
_mute_control.Changed (); /* EMIT SIGNAL */ _mute_control->Changed (); /* EMIT SIGNAL */
Glib::Mutex::Lock lm (declick_lock); Glib::Mutex::Lock lm (declick_lock);
desired_mute_gain = (yn?0.0f:1.0f); 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_property ("order-keys", order_string);
node->add_child_nocopy (IO::state (full_state)); node->add_child_nocopy (IO::state (full_state));
node->add_child_nocopy (_solo_control.get_state ()); node->add_child_nocopy (_solo_control->get_state ());
node->add_child_nocopy (_mute_control.get_state ()); node->add_child_nocopy (_mute_control->get_state ());
XMLNode* remote_control_node = new XMLNode (X_("remote_control")); XMLNode* remote_control_node = new XMLNode (X_("remote_control"));
snprintf (buf, sizeof (buf), "%d", _remote_control_id); 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) { } else if (child->name() == X_("controllable") && (prop = child->property("name")) != 0) {
if (prop->value() == "solo") { if (prop->value() == "solo") {
_solo_control.set_state (*child); _solo_control->set_state (*child);
_session.add_controllable (&_solo_control); _session.add_controllable (_solo_control);
} }
else if (prop->value() == "mute") { else if (prop->value() == "mute") {
_mute_control.set_state (*child); _mute_control->set_state (*child);
_session.add_controllable (&_mute_control); _session.add_controllable (_mute_control);
} }
} }
else if (child->name() == X_("remote_control")) { else if (child->name() == X_("remote_control")) {
@ -2038,7 +2038,7 @@ Route::set_control_outs (const vector<string>& ports)
_control_outs = 0; _control_outs = 0;
} }
if (control() || master()) { if (is_control() || is_master()) {
/* no control outs for these two special busses */ /* no control outs for these two special busses */
return 0; 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()) { if (am.locked() && _session.transport_rolling()) {
ARDOUR::AutomationList& gain_auto = gain_automation(); if (_gain_control->list()->automation_playback()) {
apply_gain_automation = _gain_control->list()->curve().rt_safe_get_vector (
if (gain_auto.automation_playback()) { start_frame, end_frame, _session.gain_automation_buffer(), nframes);
apply_gain_automation = gain_auto.curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
} }
} }
} }

View file

@ -122,7 +122,8 @@ Session::Session (AudioEngine &eng,
routes (new RouteList), routes (new RouteList),
auditioner ((Auditioner*) 0), auditioner ((Auditioner*) 0),
_click_io ((IO*) 0), _click_io ((IO*) 0),
main_outs (0) main_outs (0),
_automation_interval (0)
{ {
if (!eng.connected()) { if (!eng.connected()) {
throw failed_constructor(); throw failed_constructor();
@ -221,7 +222,8 @@ Session::Session (AudioEngine &eng,
_send_smpte_update (false), _send_smpte_update (false),
diskstreams (new DiskstreamList), diskstreams (new DiskstreamList),
routes (new RouteList), routes (new RouteList),
main_outs (0) main_outs (0),
_automation_interval (0)
{ {
if (!eng.connected()) { if (!eng.connected()) {
@ -1267,7 +1269,7 @@ Session::set_frame_rate (nframes_t frames_per_second)
sync_time_vars(); 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 // XXX we need some equivalent to this, somehow
// SndFileSource::setup_standard_crossfades (frames_per_second); // 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) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (dynamic_cast<MidiTrack*>((*i).get()) != 0) { if (dynamic_cast<MidiTrack*>((*i).get()) != 0) {
if (!(*i)->hidden()) { if (!(*i)->is_hidden()) {
n++; n++;
channels_used += (*i)->n_inputs().n_midi(); 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) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (dynamic_cast<AudioTrack*>((*i).get()) != 0) { if (dynamic_cast<AudioTrack*>((*i).get()) != 0) {
if (!(*i)->hidden()) { if (!(*i)->is_hidden()) {
n++; n++;
channels_used += (*i)->n_inputs().n_audio(); 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) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (dynamic_cast<AudioTrack*>((*i).get()) == 0) { if (dynamic_cast<AudioTrack*>((*i).get()) == 0) {
if (!(*i)->hidden() && (*i)->name() != _("master")) { if (!(*i)->is_hidden() && (*i)->name() != _("master")) {
bus_id++; 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)->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)); (*x)->processors_changed.connect (bind (mem_fun (*this, &Session::update_latency_compensation), false, false));
if ((*x)->master()) { if ((*x)->is_master()) {
_master_out = (*x); _master_out = (*x);
} }
if ((*x)->control()) { if ((*x)->is_control()) {
_control_out = (*x); _control_out = (*x);
} }
} }
@ -3436,7 +3438,7 @@ Session::set_all_solo (bool yn)
shared_ptr<RouteList> r = routes.reader (); shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (!(*i)->hidden()) { if (!(*i)->is_hidden()) {
(*i)->set_solo (yn, this); (*i)->set_solo (yn, this);
} }
} }
@ -3450,7 +3452,7 @@ Session::set_all_mute (bool yn)
shared_ptr<RouteList> r = routes.reader (); shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (!(*i)->hidden()) { if (!(*i)->is_hidden()) {
(*i)->set_mute (yn, this); (*i)->set_mute (yn, this);
} }
} }

View file

@ -101,7 +101,7 @@ Session::no_roll (nframes_t nframes, nframes_t offset)
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((*i)->hidden()) { if ((*i)->is_hidden()) {
continue; continue;
} }
@ -140,7 +140,7 @@ Session::process_routes (nframes_t nframes, nframes_t offset)
int ret; int ret;
if ((*i)->hidden()) { if ((*i)->is_hidden()) {
continue; continue;
} }
@ -186,7 +186,7 @@ Session::silent_process_routes (nframes_t nframes, nframes_t offset)
int ret; int ret;
if ((*i)->hidden()) { if ((*i)->is_hidden()) {
continue; continue;
} }
@ -819,7 +819,7 @@ Session::process_audition (nframes_t nframes)
boost::shared_ptr<RouteList> r = routes.reader (); boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (!(*i)->hidden()) { if (!(*i)->is_hidden()) {
(*i)->silence (nframes, 0); (*i)->silence (nframes, 0);
} }
} }

View file

@ -939,7 +939,7 @@ Session::state(bool full_state)
public_order.sort (cmp); public_order.sort (cmp);
for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) { for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
if (!(*i)->hidden()) { if (!(*i)->is_hidden()) {
if (full_state) { if (full_state) {
child->add_child_nocopy ((*i)->get_state()); child->add_child_nocopy ((*i)->get_state());
} else { } else {
@ -2055,7 +2055,7 @@ Session::get_global_route_boolean (bool (Route::*method)(void) const)
boost::shared_ptr<RouteList> r = routes.reader (); boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (!(*i)->hidden()) { if (!(*i)->is_hidden()) {
RouteBooleanState v; RouteBooleanState v;
v.first =* i; v.first =* i;
@ -2076,7 +2076,7 @@ Session::get_global_route_metering ()
boost::shared_ptr<RouteList> r = routes.reader (); boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (!(*i)->hidden()) { if (!(*i)->is_hidden()) {
RouteMeterState v; RouteMeterState v;
v.first =* i; v.first =* i;
@ -2622,7 +2622,7 @@ Session::set_deletion_in_progress ()
} }
void 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 adds a controllable to the list managed by the Session.
this is a subset of those managed by the Controllable class this is a subset of those managed by the Controllable class
@ -2634,6 +2634,8 @@ Session::add_controllable (Controllable* c)
controllables.insert (c); controllables.insert (c);
} }
struct null_deleter { void operator()(void const *) const {} };
void void
Session::remove_controllable (Controllable* c) Session::remove_controllable (Controllable* c)
{ {
@ -2643,14 +2645,15 @@ Session::remove_controllable (Controllable* c)
Glib::Mutex::Lock lm (controllables_lock); 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()) { if (x != controllables.end()) {
controllables.erase (x); controllables.erase (x);
} }
} }
Controllable* boost::shared_ptr<Controllable>
Session::controllable_by_id (const PBD::ID& id) Session::controllable_by_id (const PBD::ID& id)
{ {
Glib::Mutex::Lock lm (controllables_lock); 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 void

View file

@ -363,7 +363,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
boost::shared_ptr<RouteList> r = routes.reader (); boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (!(*i)->hidden()) { if (!(*i)->is_hidden()) {
(*i)->set_pending_declick (0); (*i)->set_pending_declick (0);
} }
} }
@ -1262,7 +1262,7 @@ Session::update_latency_compensation (bool with_stop, bool abort)
update_jack = true; update_jack = true;
} }
if (!(*i)->hidden() && ((*i)->active())) { if (!(*i)->is_hidden() && ((*i)->active())) {
_worst_track_latency = max (_worst_track_latency, track_latency); _worst_track_latency = max (_worst_track_latency, track_latency);
} }
} }

View file

@ -40,7 +40,7 @@ using namespace PBD;
Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, DataType default_type) Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, DataType default_type)
: Route (sess, name, 1, -1, -1, -1, flag, default_type) : Route (sess, name, 1, -1, -1, -1, flag, default_type)
, _rec_enable_control (*this) , _rec_enable_control (new RecEnableControllable(*this))
{ {
_declickable = true; _declickable = true;
_freeze_record.state = NoFreeze; _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) Track::Track (Session& sess, const XMLNode& node, DataType default_type)
: Route (sess, node) : Route (sess, node)
, _rec_enable_control (*this) , _rec_enable_control (new RecEnableControllable(*this))
{ {
_freeze_record.state = NoFreeze; _freeze_record.state = NoFreeze;
_declickable = true; _declickable = true;
@ -188,7 +188,7 @@ Track::set_record_enable (bool yn, void *src)
set_meter_point (_saved_meter_point, this); set_meter_point (_saved_meter_point, this);
} }
_rec_enable_control.Changed (); _rec_enable_control->Changed ();
} }

View file

@ -349,6 +349,7 @@ BarController::expose (GdkEventExpose* event)
char buf[64]; char buf[64];
buf[0] = '\0'; buf[0] = '\0';
if (label_callback)
label_callback (buf, 64); label_callback (buf, 64);
if (buf[0] != '\0') { if (buf[0] != '\0') {

View file

@ -32,7 +32,10 @@ namespace Gtkmm2ext {
class BarController : public Gtk::Frame class BarController : public Gtk::Frame
{ {
public: 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 () {} virtual ~BarController () {}
enum Style { enum Style {
@ -40,6 +43,7 @@ class BarController : public Gtk::Frame
RightToLeft, RightToLeft,
Line, Line,
CenterOut, CenterOut,
TopToBottom, TopToBottom,
BottomToTop BottomToTop
}; };
@ -64,7 +68,7 @@ class BarController : public Gtk::Frame
Gtk::Adjustment& adjustment; Gtk::Adjustment& adjustment;
BindingProxy binding_proxy; BindingProxy binding_proxy;
Gtk::DrawingArea darea; Gtk::DrawingArea darea;
sigc::slot<void,char*,unsigned int> label_callback; LabelCallback label_callback;
Glib::RefPtr<Pango::Layout> layout; Glib::RefPtr<Pango::Layout> layout;
Style _style; Style _style;
bool grabbed; bool grabbed;

View file

@ -228,9 +228,9 @@ MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes()
Route & route = **it; Route & route = **it;
if ( if (
route.active() route.active()
&& !route.master() && !route.is_master()
&& !route.hidden() && !route.is_hidden()
&& !route.control() && !route.is_control()
&& remote_ids.find( route.remote_control_id() ) == remote_ids.end() && 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 // TODO handle plugin automation polling
void MackieControlProtocol::update_automation( RouteSignal & rs ) 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 ) if ( gain_state == Touch || gain_state == Play )
{ {
notify_gain_changed( &rs ); notify_gain_changed( &rs );

View file

@ -20,6 +20,7 @@
#include <ardour/route.h> #include <ardour/route.h>
#include <ardour/track.h> #include <ardour/track.h>
#include <ardour/panner.h> #include <ardour/panner.h>
#include <ardour/types.h>
#include "mackie_control_protocol.h" #include "mackie_control_protocol.h"
@ -30,13 +31,13 @@ using namespace Mackie;
void RouteSignal::connect() void RouteSignal::connect()
{ {
if ( _strip.has_solo() ) 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() ) 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() ) 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 ) ); _name_changed_connection = _route.NameChanged.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_name_changed ), this ) );
@ -48,7 +49,7 @@ void RouteSignal::connect()
try try
{ {
_record_enable_changed_connection = _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 ) ) .connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_record_enable_changed ), this ) )
; ;
} }