mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-17 04:06:26 +01:00
Big ol' automation refactor.
Things with automation parameters now inherit from Automatable, which handles serialization, fetching/adding/removing parameters, etc. Use AutomationList everywhere instead of Curve, make Curve a member of AutomationList instead (towards other types of "Curve" needed for CC, among other things). Work towards MIDI CC sending "automation" tracks. git-svn-id: svn://localhost/ardour2/trunk@2069 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
d7afe01c30
commit
d7bd270aa1
68 changed files with 1770 additions and 1216 deletions
|
|
@ -96,6 +96,7 @@ audio_clock.cc
|
||||||
audio_time_axis.cc
|
audio_time_axis.cc
|
||||||
audio_region_editor.cc
|
audio_region_editor.cc
|
||||||
automation_gain_line.cc
|
automation_gain_line.cc
|
||||||
|
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
|
||||||
|
|
@ -142,6 +143,7 @@ export_session_dialog.cc
|
||||||
export_region_dialog.cc
|
export_region_dialog.cc
|
||||||
export_range_markers_dialog.cc
|
export_range_markers_dialog.cc
|
||||||
gain_automation_time_axis.cc
|
gain_automation_time_axis.cc
|
||||||
|
midi_controller_time_axis.cc
|
||||||
gain_meter.cc
|
gain_meter.cc
|
||||||
ghostregion.cc
|
ghostregion.cc
|
||||||
gtk-custom-hruler.c
|
gtk-custom-hruler.c
|
||||||
|
|
|
||||||
|
|
@ -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().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);
|
||||||
|
|
||||||
|
|
@ -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().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;
|
||||||
|
|
@ -953,7 +953,7 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
|
||||||
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<Curve>(audio_region()->envelope(), &before, &after));
|
trackview.session().add_command (new MementoCommand<AutomationList>(audio_region()->envelope(), &before, &after));
|
||||||
trackview.session().commit_reversible_command ();
|
trackview.session().commit_reversible_command ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,16 +83,12 @@ AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
|
||||||
assert(!is_track() || is_audio_track());
|
assert(!is_track() || is_audio_track());
|
||||||
|
|
||||||
subplugin_menu.set_name ("ArdourContextMenu");
|
subplugin_menu.set_name ("ArdourContextMenu");
|
||||||
gain_track = 0;
|
|
||||||
pan_track = 0;
|
|
||||||
waveform_item = 0;
|
waveform_item = 0;
|
||||||
pan_automation_item = 0;
|
|
||||||
gain_automation_item = 0;
|
|
||||||
|
|
||||||
_view = new AudioStreamView (*this);
|
_view = new AudioStreamView (*this);
|
||||||
|
|
||||||
add_gain_automation_child ();
|
create_automation_child (GainAutomation);
|
||||||
add_pan_automation_child ();
|
create_automation_child (PanAutomation);
|
||||||
|
|
||||||
ignore_toggle = false;
|
ignore_toggle = false;
|
||||||
|
|
||||||
|
|
@ -155,81 +151,6 @@ AudioTimeAxisView::hide ()
|
||||||
TimeAxisView::hide ();
|
TimeAxisView::hide ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
AudioTimeAxisView::set_state (const XMLNode& node)
|
|
||||||
{
|
|
||||||
const XMLProperty *prop;
|
|
||||||
|
|
||||||
TimeAxisView::set_state (node);
|
|
||||||
|
|
||||||
if ((prop = node.property ("shown_editor")) != 0) {
|
|
||||||
if (prop->value() == "no") {
|
|
||||||
_marked_for_display = false;
|
|
||||||
} else {
|
|
||||||
_marked_for_display = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_marked_for_display = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
XMLNodeList nlist = node.children();
|
|
||||||
XMLNodeConstIterator niter;
|
|
||||||
XMLNode *child_node;
|
|
||||||
|
|
||||||
|
|
||||||
show_gain_automation = false;
|
|
||||||
show_pan_automation = false;
|
|
||||||
|
|
||||||
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
|
||||||
child_node = *niter;
|
|
||||||
|
|
||||||
if (child_node->name() == "gain") {
|
|
||||||
XMLProperty *prop=child_node->property ("shown");
|
|
||||||
|
|
||||||
if (prop != 0) {
|
|
||||||
if (prop->value() == "yes") {
|
|
||||||
show_gain_automation = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (child_node->name() == "pan") {
|
|
||||||
XMLProperty *prop=child_node->property ("shown");
|
|
||||||
|
|
||||||
if (prop != 0) {
|
|
||||||
if (prop->value() == "yes") {
|
|
||||||
show_pan_automation = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AudioTimeAxisView::build_automation_action_menu ()
|
|
||||||
{
|
|
||||||
using namespace Menu_Helpers;
|
|
||||||
|
|
||||||
RouteTimeAxisView::build_automation_action_menu ();
|
|
||||||
|
|
||||||
MenuList& automation_items = automation_action_menu->items();
|
|
||||||
|
|
||||||
automation_items.push_back (SeparatorElem());
|
|
||||||
|
|
||||||
automation_items.push_back (CheckMenuElem (_("Fader"),
|
|
||||||
mem_fun(*this, &AudioTimeAxisView::toggle_gain_track)));
|
|
||||||
gain_automation_item = static_cast<CheckMenuItem*> (&automation_items.back());
|
|
||||||
gain_automation_item->set_active(show_gain_automation);
|
|
||||||
|
|
||||||
automation_items.push_back (CheckMenuElem (_("Pan"),
|
|
||||||
mem_fun(*this, &AudioTimeAxisView::toggle_pan_track)));
|
|
||||||
pan_automation_item = static_cast<CheckMenuItem*> (&automation_items.back());
|
|
||||||
pan_automation_item->set_active(show_pan_automation);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioTimeAxisView::append_extra_display_menu_items ()
|
AudioTimeAxisView::append_extra_display_menu_items ()
|
||||||
{
|
{
|
||||||
|
|
@ -360,79 +281,45 @@ AudioTimeAxisView::set_waveform_scale (WaveformScale scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioTimeAxisView::add_gain_automation_child ()
|
AudioTimeAxisView::create_automation_child (ParamID param)
|
||||||
{
|
{
|
||||||
XMLProperty* prop;
|
if (param.type() == GainAutomation) {
|
||||||
AutomationLine* line;
|
GainAutomationTimeAxisView* gain_track = new GainAutomationTimeAxisView (_session,
|
||||||
|
|
||||||
gain_track = new GainAutomationTimeAxisView (_session,
|
|
||||||
_route,
|
_route,
|
||||||
editor,
|
editor,
|
||||||
*this,
|
*this,
|
||||||
parent_canvas,
|
parent_canvas,
|
||||||
_("gain"),
|
_route->describe_parameter(param),
|
||||||
_route->gain_automation_curve());
|
_route->gain_automation());
|
||||||
|
|
||||||
line = new AutomationGainLine ("automation gain",
|
AutomationLine* line = new AutomationGainLine ("automation gain",
|
||||||
_session,
|
|
||||||
*gain_track,
|
*gain_track,
|
||||||
*gain_track->canvas_display,
|
*gain_track->canvas_display,
|
||||||
_route->gain_automation_curve());
|
_route->gain_automation());
|
||||||
|
|
||||||
line->set_line_color (Config->canvasvar_AutomationLine.get());
|
line->set_line_color (Config->canvasvar_AutomationLine.get());
|
||||||
|
|
||||||
|
|
||||||
gain_track->add_line (*line);
|
gain_track->add_line (*line);
|
||||||
|
|
||||||
add_child (gain_track);
|
add_automation_child(ParamID(GainAutomation), gain_track);
|
||||||
|
|
||||||
gain_track->Hiding.connect (mem_fun(*this, &AudioTimeAxisView::gain_hidden));
|
} else if (param.type() == PanAutomation) {
|
||||||
|
|
||||||
bool hideit = true;
|
PanAutomationTimeAxisView* pan_track = new PanAutomationTimeAxisView (_session,
|
||||||
|
_route,
|
||||||
|
editor,
|
||||||
|
*this,
|
||||||
|
parent_canvas,
|
||||||
|
_route->describe_parameter(param));
|
||||||
|
|
||||||
XMLNode* node;
|
ensure_xml_node ();
|
||||||
|
|
||||||
if ((node = gain_track->get_state_node()) != 0) {
|
add_automation_child(ParamID(PanAutomation), pan_track);
|
||||||
if ((prop = node->property ("shown")) != 0) {
|
|
||||||
if (prop->value() == "yes") {
|
|
||||||
hideit = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hideit) {
|
|
||||||
gain_track->hide ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AudioTimeAxisView::add_pan_automation_child ()
|
|
||||||
{
|
|
||||||
XMLProperty* prop;
|
|
||||||
|
|
||||||
pan_track = new PanAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, _("pan"));
|
|
||||||
|
|
||||||
update_pans ();
|
update_pans ();
|
||||||
|
|
||||||
add_child (pan_track);
|
} else {
|
||||||
|
error << "AudioTimeAxisView: unknown automation child " << param.to_string() << endmsg;
|
||||||
pan_track->Hiding.connect (mem_fun(*this, &AudioTimeAxisView::pan_hidden));
|
|
||||||
|
|
||||||
ensure_xml_node ();
|
|
||||||
bool hideit = true;
|
|
||||||
|
|
||||||
XMLNode* node;
|
|
||||||
|
|
||||||
if ((node = pan_track->get_state_node()) != 0) {
|
|
||||||
if ((prop = node->property ("shown")) != 0) {
|
|
||||||
if (prop->value() == "yes") {
|
|
||||||
hideit = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hideit) {
|
|
||||||
pan_track->hide ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -441,6 +328,14 @@ AudioTimeAxisView::update_pans ()
|
||||||
{
|
{
|
||||||
Panner::iterator p;
|
Panner::iterator p;
|
||||||
|
|
||||||
|
RouteAutomationNode* ran = automation_track(PanAutomation);
|
||||||
|
if (!ran) {
|
||||||
|
warning << _route << " has no pan automation track" << endmsg;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutomationTimeAxisView* pan_track = ran->track;
|
||||||
|
|
||||||
pan_track->clear_lines ();
|
pan_track->clear_lines ();
|
||||||
|
|
||||||
/* we don't draw lines for "greater than stereo" panning.
|
/* we don't draw lines for "greater than stereo" panning.
|
||||||
|
|
@ -454,7 +349,7 @@ AudioTimeAxisView::update_pans ()
|
||||||
|
|
||||||
AutomationLine* line;
|
AutomationLine* line;
|
||||||
|
|
||||||
line = new AutomationPanLine ("automation pan", _session, *pan_track,
|
line = new AutomationPanLine ("automation pan", *pan_track,
|
||||||
*pan_track->canvas_display,
|
*pan_track->canvas_display,
|
||||||
(*p)->automation());
|
(*p)->automation());
|
||||||
|
|
||||||
|
|
@ -470,79 +365,6 @@ AudioTimeAxisView::update_pans ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
AudioTimeAxisView::toggle_gain_track ()
|
|
||||||
{
|
|
||||||
|
|
||||||
bool showit = gain_automation_item->get_active();
|
|
||||||
|
|
||||||
if (showit != gain_track->marked_for_display()) {
|
|
||||||
if (showit) {
|
|
||||||
gain_track->set_marked_for_display (true);
|
|
||||||
gain_track->canvas_display->show();
|
|
||||||
gain_track->get_state_node()->add_property ("shown", X_("yes"));
|
|
||||||
} else {
|
|
||||||
gain_track->set_marked_for_display (false);
|
|
||||||
gain_track->hide ();
|
|
||||||
gain_track->get_state_node()->add_property ("shown", X_("no"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now trigger a redisplay */
|
|
||||||
|
|
||||||
if (!no_redraw) {
|
|
||||||
_route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AudioTimeAxisView::gain_hidden ()
|
|
||||||
{
|
|
||||||
gain_track->get_state_node()->add_property (X_("shown"), X_("no"));
|
|
||||||
|
|
||||||
if (gain_automation_item && !_hidden) {
|
|
||||||
gain_automation_item->set_active (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
_route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AudioTimeAxisView::toggle_pan_track ()
|
|
||||||
{
|
|
||||||
bool showit = pan_automation_item->get_active();
|
|
||||||
|
|
||||||
if (showit != pan_track->marked_for_display()) {
|
|
||||||
if (showit) {
|
|
||||||
pan_track->set_marked_for_display (true);
|
|
||||||
pan_track->canvas_display->show();
|
|
||||||
pan_track->get_state_node()->add_property ("shown", X_("yes"));
|
|
||||||
} else {
|
|
||||||
pan_track->set_marked_for_display (false);
|
|
||||||
pan_track->hide ();
|
|
||||||
pan_track->get_state_node()->add_property ("shown", X_("no"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now trigger a redisplay */
|
|
||||||
|
|
||||||
if (!no_redraw) {
|
|
||||||
_route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AudioTimeAxisView::pan_hidden ()
|
|
||||||
{
|
|
||||||
pan_track->get_state_node()->add_property ("shown", "no");
|
|
||||||
|
|
||||||
if (pan_automation_item && !_hidden) {
|
|
||||||
pan_automation_item->set_active (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
_route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioTimeAxisView::show_all_automation ()
|
AudioTimeAxisView::show_all_automation ()
|
||||||
{
|
{
|
||||||
|
|
@ -669,12 +491,6 @@ AudioTimeAxisView::update_control_names ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLNode*
|
|
||||||
AudioTimeAxisView::get_child_xml_node (const string & childname)
|
|
||||||
{
|
|
||||||
return RouteUI::get_child_xml_node (childname);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioTimeAxisView::set_layer_display (LayerDisplay d)
|
AudioTimeAxisView::set_layer_display (LayerDisplay d)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -83,8 +83,7 @@ class AudioTimeAxisView : public RouteTimeAxisView
|
||||||
guint32 show_at (double y, int& nth, Gtk::VBox *parent);
|
guint32 show_at (double y, int& nth, Gtk::VBox *parent);
|
||||||
void hide ();
|
void hide ();
|
||||||
|
|
||||||
void set_state (const XMLNode&);
|
void create_automation_child (ARDOUR::ParamID param);
|
||||||
XMLNode* get_child_xml_node (const string & childname);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class AudioStreamView;
|
friend class AudioStreamView;
|
||||||
|
|
@ -92,7 +91,6 @@ class AudioTimeAxisView : public RouteTimeAxisView
|
||||||
|
|
||||||
void route_active_changed ();
|
void route_active_changed ();
|
||||||
|
|
||||||
void build_automation_action_menu ();
|
|
||||||
void append_extra_display_menu_items ();
|
void append_extra_display_menu_items ();
|
||||||
|
|
||||||
void toggle_show_waveforms ();
|
void toggle_show_waveforms ();
|
||||||
|
|
@ -104,26 +102,12 @@ class AudioTimeAxisView : public RouteTimeAxisView
|
||||||
void show_existing_automation ();
|
void show_existing_automation ();
|
||||||
void hide_all_automation ();
|
void hide_all_automation ();
|
||||||
|
|
||||||
void add_gain_automation_child ();
|
|
||||||
void add_pan_automation_child ();
|
|
||||||
void add_parameter_automation_child ();
|
|
||||||
|
|
||||||
void toggle_gain_track ();
|
|
||||||
void toggle_pan_track ();
|
|
||||||
|
|
||||||
void gain_hidden ();
|
void gain_hidden ();
|
||||||
void pan_hidden ();
|
void pan_hidden ();
|
||||||
|
|
||||||
void update_pans ();
|
void update_pans ();
|
||||||
void update_control_names ();
|
void update_control_names ();
|
||||||
|
|
||||||
AutomationTimeAxisView* gain_track;
|
|
||||||
AutomationTimeAxisView* pan_track;
|
|
||||||
|
|
||||||
// Set from XML so context menu automation buttons can be correctly initialized
|
|
||||||
bool show_gain_automation;
|
|
||||||
bool show_pan_automation;
|
|
||||||
|
|
||||||
Gtk::CheckMenuItem* waveform_item;
|
Gtk::CheckMenuItem* waveform_item;
|
||||||
Gtk::RadioMenuItem* traditional_item;
|
Gtk::RadioMenuItem* traditional_item;
|
||||||
Gtk::RadioMenuItem* rectified_item;
|
Gtk::RadioMenuItem* rectified_item;
|
||||||
|
|
|
||||||
|
|
@ -26,16 +26,13 @@
|
||||||
#include "automation_gain_line.h"
|
#include "automation_gain_line.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#include <ardour/session.h>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
AutomationGainLine::AutomationGainLine (const string & name, Session& s, TimeAxisView& tv, ArdourCanvas::Group& parent, Curve& c)
|
AutomationGainLine::AutomationGainLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, AutomationList& l)
|
||||||
|
|
||||||
: AutomationLine (name, tv, parent, c),
|
: AutomationLine (name, tv, parent, l)
|
||||||
session (s)
|
|
||||||
{
|
{
|
||||||
set_verbose_cursor_uses_gain_mapping (true);
|
set_verbose_cursor_uses_gain_mapping (true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,23 +25,15 @@
|
||||||
#include "canvas.h"
|
#include "canvas.h"
|
||||||
#include "automation_line.h"
|
#include "automation_line.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
|
||||||
class Session;
|
|
||||||
}
|
|
||||||
|
|
||||||
class TimeAxisView;
|
class TimeAxisView;
|
||||||
|
|
||||||
class AutomationGainLine : public AutomationLine
|
class AutomationGainLine : public AutomationLine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AutomationGainLine (const string & name, ARDOUR::Session&, TimeAxisView&, ArdourCanvas::Group& parent, ARDOUR::Curve&);
|
AutomationGainLine (const string & name, TimeAxisView&, ArdourCanvas::Group& parent, 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&);
|
||||||
|
|
||||||
private:
|
|
||||||
ARDOUR::Session& session;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
76
gtk2_ardour/automation_midi_cc_line.cc
Normal file
76
gtk2_ardour/automation_midi_cc_line.cc
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2000-2007 Paul Davis
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
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 <sigc++/signal.h>
|
||||||
|
|
||||||
|
#include <ardour/curve.h>
|
||||||
|
|
||||||
|
#include "automation_midi_cc_line.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace ARDOUR;
|
||||||
|
using namespace PBD;
|
||||||
|
|
||||||
|
AutomationMidiCCLine::AutomationMidiCCLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, AutomationList& l)
|
||||||
|
|
||||||
|
: AutomationLine (name, tv, parent, l)
|
||||||
|
{
|
||||||
|
set_verbose_cursor_uses_gain_mapping (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AutomationMidiCCLine::view_to_model_y (double& y)
|
||||||
|
{
|
||||||
|
assert(y >= 0);
|
||||||
|
assert(y <= 1);
|
||||||
|
|
||||||
|
y = (int)(y * 127.0);
|
||||||
|
|
||||||
|
assert(y >= 0);
|
||||||
|
assert(y <= 127);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AutomationMidiCCLine::model_to_view_y (double& y)
|
||||||
|
{
|
||||||
|
assert(y >= 0);
|
||||||
|
assert(y <= 127);
|
||||||
|
|
||||||
|
y = y / 127.0;
|
||||||
|
|
||||||
|
assert(y >= 0);
|
||||||
|
assert(y <= 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
AutomationMidiCCLine::get_verbose_cursor_string (float fraction)
|
||||||
|
{
|
||||||
|
static const size_t MAX_VAL_LEN = 4; // 4 for "127\0"
|
||||||
|
char buf[MAX_VAL_LEN];
|
||||||
|
|
||||||
|
double cc_val = fraction;
|
||||||
|
view_to_model_y(cc_val); // 0..127
|
||||||
|
|
||||||
|
snprintf (buf, MAX_VAL_LEN, "%u", (unsigned)cc_val);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
44
gtk2_ardour/automation_midi_cc_line.h
Normal file
44
gtk2_ardour/automation_midi_cc_line.h
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2000-2007 Paul Davis
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
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_midi_cc_line_h__
|
||||||
|
#define __ardour_gtk_automation_midi_cc_line_h__
|
||||||
|
|
||||||
|
#include <ardour/ardour.h>
|
||||||
|
|
||||||
|
#include "canvas.h"
|
||||||
|
#include "automation_line.h"
|
||||||
|
|
||||||
|
class TimeAxisView;
|
||||||
|
|
||||||
|
class AutomationMidiCCLine : public AutomationLine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AutomationMidiCCLine (const string & name, TimeAxisView&, ArdourCanvas::Group& parent, ARDOUR::AutomationList&);
|
||||||
|
|
||||||
|
void view_to_model_y (double&);
|
||||||
|
void model_to_view_y (double&);
|
||||||
|
|
||||||
|
string get_verbose_cursor_string (float);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __ardour_gtk_automation_midi_cc_line_h__ */
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -27,15 +27,12 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include <ardour/session.h>
|
|
||||||
|
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
AutomationPanLine::AutomationPanLine (const string & name, Session& s, TimeAxisView& tv, ArdourCanvas::Group& parent, Curve& c)
|
AutomationPanLine::AutomationPanLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, AutomationList& l)
|
||||||
|
|
||||||
: AutomationLine (name, tv, parent, c),
|
: AutomationLine (name, tv, parent, l)
|
||||||
session (s)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,22 +25,17 @@
|
||||||
#include "canvas.h"
|
#include "canvas.h"
|
||||||
#include "automation_line.h"
|
#include "automation_line.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
|
||||||
class Session;
|
|
||||||
}
|
|
||||||
|
|
||||||
class TimeAxisView;
|
class TimeAxisView;
|
||||||
|
|
||||||
class AutomationPanLine : public AutomationLine
|
class AutomationPanLine : public AutomationLine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AutomationPanLine (const string & name, ARDOUR::Session&, TimeAxisView&, ArdourCanvas::Group& parent, ARDOUR::Curve&);
|
AutomationPanLine (const string & name, TimeAxisView&, ArdourCanvas::Group& parent, 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&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ARDOUR::Session& session;
|
|
||||||
vector<ArdourCanvas::Item*> lines;
|
vector<ArdourCanvas::Item*> lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,8 @@ CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
|
||||||
|
|
||||||
CrossfadeEditor::Half::Half ()
|
CrossfadeEditor::Half::Half ()
|
||||||
: line (0),
|
: line (0),
|
||||||
normative_curve (0.0, 1.0, 1.0, true),
|
normative_curve (ParamID(GainAutomation), 0.0, 1.0, 1.0), // FIXME: GainAutomation?
|
||||||
gain_curve (0.0, 2.0, 1.0, true)
|
gain_curve (ParamID(GainAutomation), 0.0, 2.0, 1.0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -327,10 +327,10 @@ CrossfadeEditor::audition_state_changed (bool yn)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CrossfadeEditor::set (const ARDOUR::Curve& curve, WhichFade which)
|
CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
|
||||||
{
|
{
|
||||||
double firstx, endx;
|
double firstx, endx;
|
||||||
ARDOUR::Curve::const_iterator the_end;
|
ARDOUR::AutomationList::const_iterator the_end;
|
||||||
|
|
||||||
for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
|
for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
|
||||||
delete *i;
|
delete *i;
|
||||||
|
|
@ -350,7 +350,7 @@ CrossfadeEditor::set (const ARDOUR::Curve& curve, WhichFade which)
|
||||||
firstx = (*curve.const_begin())->when;
|
firstx = (*curve.const_begin())->when;
|
||||||
endx = (*the_end)->when;
|
endx = (*the_end)->when;
|
||||||
|
|
||||||
for (ARDOUR::Curve::const_iterator i = curve.const_begin(); i != curve.const_end(); ++i) {
|
for (ARDOUR::AutomationList::const_iterator i = curve.const_begin(); i != curve.const_end(); ++i) {
|
||||||
|
|
||||||
double xfract = ((*i)->when - firstx) / (endx - firstx);
|
double xfract = ((*i)->when - firstx) / (endx - firstx);
|
||||||
double yfract = ((*i)->value - miny) / (maxy - miny);
|
double yfract = ((*i)->value - miny) / (maxy - miny);
|
||||||
|
|
@ -644,7 +644,7 @@ CrossfadeEditor::redraw ()
|
||||||
size_t npoints = (size_t) effective_width();
|
size_t npoints = (size_t) effective_width();
|
||||||
float vec[npoints];
|
float vec[npoints];
|
||||||
|
|
||||||
fade[current].normative_curve.get_vector (0, 1.0, vec, npoints);
|
fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
|
||||||
|
|
||||||
ArdourCanvas::Points pts;
|
ArdourCanvas::Points pts;
|
||||||
ArdourCanvas::Points spts;
|
ArdourCanvas::Points spts;
|
||||||
|
|
@ -760,13 +760,13 @@ CrossfadeEditor::apply ()
|
||||||
void
|
void
|
||||||
CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
|
CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
|
||||||
{
|
{
|
||||||
ARDOUR::Curve& in (xf->fade_in());
|
ARDOUR::AutomationList& in (xf->fade_in());
|
||||||
ARDOUR::Curve& out (xf->fade_out());
|
ARDOUR::AutomationList& out (xf->fade_out());
|
||||||
|
|
||||||
/* IN */
|
/* IN */
|
||||||
|
|
||||||
|
|
||||||
ARDOUR::Curve::const_iterator the_end = in.const_end();
|
ARDOUR::AutomationList::const_iterator the_end = in.const_end();
|
||||||
--the_end;
|
--the_end;
|
||||||
|
|
||||||
double firstx = (*in.begin())->when;
|
double firstx = (*in.begin())->when;
|
||||||
|
|
@ -813,8 +813,8 @@ CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
|
||||||
{
|
{
|
||||||
_apply_to (xfade);
|
_apply_to (xfade);
|
||||||
xfade->set_active (true);
|
xfade->set_active (true);
|
||||||
xfade->fade_in().solve ();
|
xfade->fade_in().curve().solve ();
|
||||||
xfade->fade_out().solve ();
|
xfade->fade_out().curve().solve ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
namespace ARDOUR
|
namespace ARDOUR
|
||||||
{
|
{
|
||||||
class Session;
|
class Session;
|
||||||
class Curve;
|
class AutomationList;
|
||||||
class Crossfade;
|
class Crossfade;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,8 +105,8 @@ class CrossfadeEditor : public ArdourDialog
|
||||||
ArdourCanvas::Line* line;
|
ArdourCanvas::Line* line;
|
||||||
ArdourCanvas::Polygon* shading;
|
ArdourCanvas::Polygon* shading;
|
||||||
list<Point*> points;
|
list<Point*> points;
|
||||||
ARDOUR::Curve normative_curve; /* 0 - 1.0, linear */
|
ARDOUR::AutomationList normative_curve; /* 0 - 1.0, linear */
|
||||||
ARDOUR::Curve gain_curve; /* 0 - 2.0, gain mapping */
|
ARDOUR::AutomationList gain_curve; /* 0 - 2.0, gain mapping */
|
||||||
vector<ArdourCanvas::WaveView*> waves;
|
vector<ArdourCanvas::WaveView*> waves;
|
||||||
|
|
||||||
Half();
|
Half();
|
||||||
|
|
@ -176,7 +176,7 @@ class CrossfadeEditor : public ArdourDialog
|
||||||
double x_coordinate (double& xfract) const;
|
double x_coordinate (double& xfract) const;
|
||||||
double y_coordinate (double& yfract) const;
|
double y_coordinate (double& yfract) const;
|
||||||
|
|
||||||
void set (const ARDOUR::Curve& alist, WhichFade);
|
void set (const ARDOUR::AutomationList& alist, WhichFade);
|
||||||
|
|
||||||
sigc::connection peaks_ready_connection;
|
sigc::connection peaks_ready_connection;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ CrossfadeView::redraw_curves ()
|
||||||
points = get_canvas_points ("xfade edit redraw", npoints);
|
points = get_canvas_points ("xfade edit redraw", npoints);
|
||||||
vec = new float[npoints];
|
vec = new float[npoints];
|
||||||
|
|
||||||
crossfade->fade_in().get_vector (0, crossfade->length(), vec, npoints);
|
crossfade->fade_in().curve().get_vector (0, crossfade->length(), vec, npoints);
|
||||||
for (int i = 0, pci = 0; i < npoints; ++i) {
|
for (int i = 0, pci = 0; i < npoints; ++i) {
|
||||||
Art::Point &p = (*points)[pci++];
|
Art::Point &p = (*points)[pci++];
|
||||||
p.set_x(i);
|
p.set_x(i);
|
||||||
|
|
@ -197,7 +197,7 @@ CrossfadeView::redraw_curves ()
|
||||||
}
|
}
|
||||||
fade_in->property_points() = *points;
|
fade_in->property_points() = *points;
|
||||||
|
|
||||||
crossfade->fade_out().get_vector (0, crossfade->length(), vec, npoints);
|
crossfade->fade_out().curve().get_vector (0, crossfade->length(), vec, npoints);
|
||||||
for (int i = 0, pci = 0; i < npoints; ++i) {
|
for (int i = 0, pci = 0; i < npoints; ++i) {
|
||||||
Art::Point &p = (*points)[pci++];
|
Art::Point &p = (*points)[pci++];
|
||||||
p.set_x(i);
|
p.set_x(i);
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ curvetest (string filename)
|
||||||
{
|
{
|
||||||
ifstream in (filename.c_str());
|
ifstream in (filename.c_str());
|
||||||
stringstream line;
|
stringstream line;
|
||||||
Curve c (-1.0, +1.0, 0, true);
|
AutomationList al (ParamID(), -1.0, +1.0, 0);
|
||||||
double minx = DBL_MAX;
|
double minx = DBL_MAX;
|
||||||
double maxx = DBL_MIN;
|
double maxx = DBL_MIN;
|
||||||
|
|
||||||
|
|
@ -55,13 +55,13 @@ curvetest (string filename)
|
||||||
maxx = x;
|
maxx = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
c.add (x, y);
|
al.add (x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float foo[1024];
|
float foo[1024];
|
||||||
|
|
||||||
c.get_vector (minx, maxx, foo, 1024);
|
al.curve().get_vector (minx, maxx, foo, 1024);
|
||||||
|
|
||||||
for (int i = 0; i < 1024; ++i) {
|
for (int i = 0; i < 1024; ++i) {
|
||||||
cout << minx + (((double) i / 1024.0) * (maxx - minx)) << ' ' << foo[i] << endl;
|
cout << minx + (((double) i / 1024.0) * (maxx - minx)) << ' ' << foo[i] << endl;
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
#include "region_gain_line.h"
|
#include "region_gain_line.h"
|
||||||
#include "automation_gain_line.h"
|
#include "automation_gain_line.h"
|
||||||
#include "automation_pan_line.h"
|
#include "automation_pan_line.h"
|
||||||
|
#include "automation_midi_cc_line.h"
|
||||||
#include "automation_time_axis.h"
|
#include "automation_time_axis.h"
|
||||||
#include "redirect_automation_line.h"
|
#include "redirect_automation_line.h"
|
||||||
#include "canvas_impl.h"
|
#include "canvas_impl.h"
|
||||||
|
|
@ -592,6 +593,8 @@ Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, C
|
||||||
type = PanAutomationControlPointItem;
|
type = PanAutomationControlPointItem;
|
||||||
} else if (dynamic_cast<RedirectAutomationLine*> (&cp->line) != 0) {
|
} else if (dynamic_cast<RedirectAutomationLine*> (&cp->line) != 0) {
|
||||||
type = RedirectAutomationControlPointItem;
|
type = RedirectAutomationControlPointItem;
|
||||||
|
} else if (dynamic_cast<AutomationMidiCCLine*> (&cp->line) != 0) {
|
||||||
|
type = MidiCCAutomationControlPointItem;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -612,6 +615,8 @@ Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, Automation
|
||||||
type = PanAutomationLineItem;
|
type = PanAutomationLineItem;
|
||||||
} else if (dynamic_cast<RedirectAutomationLine*> (al) != 0) {
|
} else if (dynamic_cast<RedirectAutomationLine*> (al) != 0) {
|
||||||
type = RedirectAutomationLineItem;
|
type = RedirectAutomationLineItem;
|
||||||
|
} else if (dynamic_cast<AutomationMidiCCLine*> (al) != 0) {
|
||||||
|
type = MidiCCAutomationLineItem;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@ enum ItemType {
|
||||||
PanAutomationLineItem,
|
PanAutomationLineItem,
|
||||||
RedirectAutomationControlPointItem,
|
RedirectAutomationControlPointItem,
|
||||||
RedirectAutomationLineItem,
|
RedirectAutomationLineItem,
|
||||||
|
MidiCCAutomationControlPointItem,
|
||||||
|
MidiCCAutomationLineItem,
|
||||||
MeterMarkerItem,
|
MeterMarkerItem,
|
||||||
TempoMarkerItem,
|
TempoMarkerItem,
|
||||||
MeterBarItem,
|
MeterBarItem,
|
||||||
|
|
|
||||||
|
|
@ -350,6 +350,7 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it
|
||||||
case GainAutomationControlPointItem:
|
case GainAutomationControlPointItem:
|
||||||
case PanAutomationControlPointItem:
|
case PanAutomationControlPointItem:
|
||||||
case RedirectAutomationControlPointItem:
|
case RedirectAutomationControlPointItem:
|
||||||
|
case MidiCCAutomationControlPointItem:
|
||||||
commit = set_selected_track_from_click (press, op, true);
|
commit = set_selected_track_from_click (press, op, true);
|
||||||
if (mouse_mode != MouseRange) {
|
if (mouse_mode != MouseRange) {
|
||||||
commit |= set_selected_control_point_from_click (op, false);
|
commit |= set_selected_control_point_from_click (op, false);
|
||||||
|
|
@ -539,6 +540,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
|
||||||
case GainAutomationControlPointItem:
|
case GainAutomationControlPointItem:
|
||||||
case PanAutomationControlPointItem:
|
case PanAutomationControlPointItem:
|
||||||
case RedirectAutomationControlPointItem:
|
case RedirectAutomationControlPointItem:
|
||||||
|
case MidiCCAutomationControlPointItem:
|
||||||
start_control_point_grab (item, event);
|
start_control_point_grab (item, event);
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -546,6 +548,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
|
||||||
case GainAutomationLineItem:
|
case GainAutomationLineItem:
|
||||||
case PanAutomationLineItem:
|
case PanAutomationLineItem:
|
||||||
case RedirectAutomationLineItem:
|
case RedirectAutomationLineItem:
|
||||||
|
case MidiCCAutomationLineItem:
|
||||||
start_line_grab_from_line (item, event);
|
start_line_grab_from_line (item, event);
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -608,6 +611,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
|
||||||
case GainAutomationControlPointItem:
|
case GainAutomationControlPointItem:
|
||||||
case PanAutomationControlPointItem:
|
case PanAutomationControlPointItem:
|
||||||
case RedirectAutomationControlPointItem:
|
case RedirectAutomationControlPointItem:
|
||||||
|
case MidiCCAutomationControlPointItem:
|
||||||
start_control_point_grab (item, event);
|
start_control_point_grab (item, event);
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -622,12 +626,14 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
|
||||||
case GainAutomationControlPointItem:
|
case GainAutomationControlPointItem:
|
||||||
case PanAutomationControlPointItem:
|
case PanAutomationControlPointItem:
|
||||||
case RedirectAutomationControlPointItem:
|
case RedirectAutomationControlPointItem:
|
||||||
|
case MidiCCAutomationControlPointItem:
|
||||||
start_control_point_grab (item, event);
|
start_control_point_grab (item, event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GainAutomationLineItem:
|
case GainAutomationLineItem:
|
||||||
case PanAutomationLineItem:
|
case PanAutomationLineItem:
|
||||||
case RedirectAutomationLineItem:
|
case RedirectAutomationLineItem:
|
||||||
|
case MidiCCAutomationLineItem:
|
||||||
start_line_grab_from_line (item, event);
|
start_line_grab_from_line (item, event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -682,6 +688,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
|
||||||
case GainAutomationControlPointItem:
|
case GainAutomationControlPointItem:
|
||||||
case PanAutomationControlPointItem:
|
case PanAutomationControlPointItem:
|
||||||
case RedirectAutomationControlPointItem:
|
case RedirectAutomationControlPointItem:
|
||||||
|
case MidiCCAutomationControlPointItem:
|
||||||
start_control_point_grab (item, event);
|
start_control_point_grab (item, event);
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -896,6 +903,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
||||||
case GainAutomationControlPointItem:
|
case GainAutomationControlPointItem:
|
||||||
case PanAutomationControlPointItem:
|
case PanAutomationControlPointItem:
|
||||||
case RedirectAutomationControlPointItem:
|
case RedirectAutomationControlPointItem:
|
||||||
|
case MidiCCAutomationControlPointItem:
|
||||||
remove_control_point (item, event);
|
remove_control_point (item, event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -917,6 +925,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
||||||
case GainAutomationLineItem:
|
case GainAutomationLineItem:
|
||||||
case PanAutomationLineItem:
|
case PanAutomationLineItem:
|
||||||
case RedirectAutomationLineItem:
|
case RedirectAutomationLineItem:
|
||||||
|
case MidiCCAutomationLineItem:
|
||||||
case StartSelectionTrimItem:
|
case StartSelectionTrimItem:
|
||||||
case EndSelectionTrimItem:
|
case EndSelectionTrimItem:
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1061,6 +1070,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
|
||||||
case GainAutomationControlPointItem:
|
case GainAutomationControlPointItem:
|
||||||
case PanAutomationControlPointItem:
|
case PanAutomationControlPointItem:
|
||||||
case RedirectAutomationControlPointItem:
|
case RedirectAutomationControlPointItem:
|
||||||
|
case MidiCCAutomationControlPointItem:
|
||||||
if (mouse_mode == MouseGain || mouse_mode == MouseObject) {
|
if (mouse_mode == MouseGain || mouse_mode == MouseObject) {
|
||||||
cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
|
cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
|
||||||
cp->set_visible (true);
|
cp->set_visible (true);
|
||||||
|
|
@ -1096,6 +1106,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
|
||||||
|
|
||||||
case GainAutomationLineItem:
|
case GainAutomationLineItem:
|
||||||
case RedirectAutomationLineItem:
|
case RedirectAutomationLineItem:
|
||||||
|
case MidiCCAutomationLineItem:
|
||||||
case PanAutomationLineItem:
|
case PanAutomationLineItem:
|
||||||
if (mouse_mode == MouseGain || mouse_mode == MouseObject) {
|
if (mouse_mode == MouseGain || mouse_mode == MouseObject) {
|
||||||
{
|
{
|
||||||
|
|
@ -1218,11 +1229,13 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
|
||||||
case GainLineItem:
|
case GainLineItem:
|
||||||
case GainAutomationLineItem:
|
case GainAutomationLineItem:
|
||||||
case RedirectAutomationLineItem:
|
case RedirectAutomationLineItem:
|
||||||
|
case MidiCCAutomationLineItem:
|
||||||
case PanAutomationLineItem:
|
case PanAutomationLineItem:
|
||||||
case GainControlPointItem:
|
case GainControlPointItem:
|
||||||
case GainAutomationControlPointItem:
|
case GainAutomationControlPointItem:
|
||||||
case PanAutomationControlPointItem:
|
case PanAutomationControlPointItem:
|
||||||
case RedirectAutomationControlPointItem:
|
case RedirectAutomationControlPointItem:
|
||||||
|
case MidiCCAutomationControlPointItem:
|
||||||
/* these do not affect the current entered track state */
|
/* these do not affect the current entered track state */
|
||||||
clear_entered_track = false;
|
clear_entered_track = false;
|
||||||
break;
|
break;
|
||||||
|
|
@ -1254,6 +1267,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
|
||||||
case GainAutomationControlPointItem:
|
case GainAutomationControlPointItem:
|
||||||
case PanAutomationControlPointItem:
|
case PanAutomationControlPointItem:
|
||||||
case RedirectAutomationControlPointItem:
|
case RedirectAutomationControlPointItem:
|
||||||
|
case MidiCCAutomationControlPointItem:
|
||||||
cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point"));
|
cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point"));
|
||||||
if (cp->line.npoints() > 1) {
|
if (cp->line.npoints() > 1) {
|
||||||
if (!cp->selected) {
|
if (!cp->selected) {
|
||||||
|
|
@ -1289,6 +1303,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
|
||||||
case GainLineItem:
|
case GainLineItem:
|
||||||
case GainAutomationLineItem:
|
case GainAutomationLineItem:
|
||||||
case RedirectAutomationLineItem:
|
case RedirectAutomationLineItem:
|
||||||
|
case MidiCCAutomationLineItem:
|
||||||
case PanAutomationLineItem:
|
case PanAutomationLineItem:
|
||||||
al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
|
al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
|
||||||
{
|
{
|
||||||
|
|
@ -1432,6 +1447,7 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
|
||||||
case MarkerItem:
|
case MarkerItem:
|
||||||
case GainControlPointItem:
|
case GainControlPointItem:
|
||||||
case RedirectAutomationControlPointItem:
|
case RedirectAutomationControlPointItem:
|
||||||
|
case MidiCCAutomationControlPointItem:
|
||||||
case GainAutomationControlPointItem:
|
case GainAutomationControlPointItem:
|
||||||
case PanAutomationControlPointItem:
|
case PanAutomationControlPointItem:
|
||||||
case TempoMarkerItem:
|
case TempoMarkerItem:
|
||||||
|
|
@ -1442,6 +1458,7 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
|
||||||
case SelectionItem:
|
case SelectionItem:
|
||||||
case GainLineItem:
|
case GainLineItem:
|
||||||
case RedirectAutomationLineItem:
|
case RedirectAutomationLineItem:
|
||||||
|
case MidiCCAutomationLineItem:
|
||||||
case GainAutomationLineItem:
|
case GainAutomationLineItem:
|
||||||
case PanAutomationLineItem:
|
case PanAutomationLineItem:
|
||||||
case FadeInHandleItem:
|
case FadeInHandleItem:
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ardour/curve.h>
|
#include <ardour/automation_event.h>
|
||||||
#include <ardour/route.h>
|
#include <ardour/route.h>
|
||||||
#include <pbd/memento_command.h>
|
#include <pbd/memento_command.h>
|
||||||
|
|
||||||
|
|
@ -33,11 +33,11 @@ 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::Curve& c)
|
ArdourCanvas::Canvas& canvas, const string & n, ARDOUR::AutomationList& l)
|
||||||
|
|
||||||
: AxisView (s),
|
: AxisView (s),
|
||||||
AutomationTimeAxisView (s, r, e, parent, canvas, n, X_("gain"), ""),
|
AutomationTimeAxisView (s, r, e, parent, canvas, n, X_("gain"), ""),
|
||||||
curve (c)
|
list (l)
|
||||||
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -62,10 +62,10 @@ GainAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkE
|
||||||
lines.front()->view_to_model_y (y);
|
lines.front()->view_to_model_y (y);
|
||||||
|
|
||||||
_session.begin_reversible_command (_("add gain automation event"));
|
_session.begin_reversible_command (_("add gain automation event"));
|
||||||
XMLNode& before = curve.get_state();
|
XMLNode& before = list.get_state();
|
||||||
curve.add (when, y);
|
list.add (when, y);
|
||||||
XMLNode& after = curve.get_state();
|
XMLNode& after = list.get_state();
|
||||||
_session.commit_reversible_command (new MementoCommand<ARDOUR::Curve>(curve, &before, &after));
|
_session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(list, &before, &after));
|
||||||
_session.set_dirty ();
|
_session.set_dirty ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,6 +73,6 @@ void
|
||||||
GainAutomationTimeAxisView::set_automation_state (AutoState state)
|
GainAutomationTimeAxisView::set_automation_state (AutoState state)
|
||||||
{
|
{
|
||||||
if (!ignore_state_request) {
|
if (!ignore_state_request) {
|
||||||
route->set_gain_automation_state (state);
|
route->set_parameter_automation_state (ParamID(GainAutomation), state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,7 @@
|
||||||
#include "automation_time_axis.h"
|
#include "automation_time_axis.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
class Redirect;
|
class AutomationList;
|
||||||
class Curve;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class GainAutomationTimeAxisView : public AutomationTimeAxisView
|
class GainAutomationTimeAxisView : public AutomationTimeAxisView
|
||||||
|
|
@ -37,14 +36,14 @@ class GainAutomationTimeAxisView : public AutomationTimeAxisView
|
||||||
TimeAxisView& parent_axis,
|
TimeAxisView& parent_axis,
|
||||||
ArdourCanvas::Canvas& canvas,
|
ArdourCanvas::Canvas& canvas,
|
||||||
const string & name,
|
const string & name,
|
||||||
ARDOUR::Curve&);
|
ARDOUR::AutomationList&);
|
||||||
|
|
||||||
~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::Curve& curve;
|
ARDOUR::AutomationList& list;
|
||||||
|
|
||||||
void automation_changed ();
|
void automation_changed ();
|
||||||
void set_automation_state (ARDOUR::AutoState);
|
void set_automation_state (ARDOUR::AutoState);
|
||||||
|
|
|
||||||
|
|
@ -166,13 +166,17 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
|
||||||
using namespace Menu_Helpers;
|
using namespace Menu_Helpers;
|
||||||
|
|
||||||
gain_astate_menu.items().push_back (MenuElem (_("Manual"),
|
gain_astate_menu.items().push_back (MenuElem (_("Manual"),
|
||||||
bind (mem_fun (*_io, &IO::set_gain_automation_state), (AutoState) Off)));
|
bind (mem_fun (*_io, &IO::set_parameter_automation_state),
|
||||||
|
ParamID(GainAutomation), (AutoState) Off)));
|
||||||
gain_astate_menu.items().push_back (MenuElem (_("Play"),
|
gain_astate_menu.items().push_back (MenuElem (_("Play"),
|
||||||
bind (mem_fun (*_io, &IO::set_gain_automation_state), (AutoState) Play)));
|
bind (mem_fun (*_io, &IO::set_parameter_automation_state),
|
||||||
|
ParamID(GainAutomation), (AutoState) Play)));
|
||||||
gain_astate_menu.items().push_back (MenuElem (_("Write"),
|
gain_astate_menu.items().push_back (MenuElem (_("Write"),
|
||||||
bind (mem_fun (*_io, &IO::set_gain_automation_state), (AutoState) Write)));
|
bind (mem_fun (*_io, &IO::set_parameter_automation_state),
|
||||||
|
ParamID(GainAutomation), (AutoState) Write)));
|
||||||
gain_astate_menu.items().push_back (MenuElem (_("Touch"),
|
gain_astate_menu.items().push_back (MenuElem (_("Touch"),
|
||||||
bind (mem_fun (*_io, &IO::set_gain_automation_state), (AutoState) Touch)));
|
bind (mem_fun (*_io, &IO::set_parameter_automation_state),
|
||||||
|
ParamID(GainAutomation), (AutoState) Touch)));
|
||||||
|
|
||||||
gain_astyle_menu.items().push_back (MenuElem (_("Trim")));
|
gain_astyle_menu.items().push_back (MenuElem (_("Trim")));
|
||||||
gain_astyle_menu.items().push_back (MenuElem (_("Abs")));
|
gain_astyle_menu.items().push_back (MenuElem (_("Abs")));
|
||||||
|
|
@ -183,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_curve().automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed));
|
r->gain_automation().automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed));
|
||||||
r->gain_automation_curve().automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed));
|
r->gain_automation().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 ();
|
||||||
|
|
@ -668,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_state() & Play));
|
static_cast<Gtkmm2ext::SliderController*>(gain_slider)->set_sensitive (!(_io->gain_automation().automation_state() & Play));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -811,14 +815,14 @@ GainMeter::meter_point_clicked ()
|
||||||
gint
|
gint
|
||||||
GainMeter::start_gain_touch (GdkEventButton* ev)
|
GainMeter::start_gain_touch (GdkEventButton* ev)
|
||||||
{
|
{
|
||||||
_io->start_gain_touch ();
|
_io->gain_automation().start_touch ();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gint
|
gint
|
||||||
GainMeter::end_gain_touch (GdkEventButton* ev)
|
GainMeter::end_gain_touch (GdkEventButton* ev)
|
||||||
{
|
{
|
||||||
_io->end_gain_touch ();
|
_io->gain_automation().stop_touch ();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -922,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_curve().automation_style()));
|
gain_automation_style_button.set_label (astyle_string(_io->gain_automation().automation_style()));
|
||||||
break;
|
break;
|
||||||
case Narrow:
|
case Narrow:
|
||||||
gain_automation_style_button.set_label (short_astyle_string(_io->gain_automation_curve().automation_style()));
|
gain_automation_style_button.set_label (short_astyle_string(_io->gain_automation().automation_style()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -940,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_curve().automation_state()));
|
gain_automation_state_button.set_label (astate_string(_io->gain_automation().automation_state()));
|
||||||
break;
|
break;
|
||||||
case Narrow:
|
case Narrow:
|
||||||
gain_automation_state_button.set_label (short_astate_string(_io->gain_automation_curve().automation_state()));
|
gain_automation_state_button.set_label (short_astate_string(_io->gain_automation().automation_state()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
x = (_io->gain_automation_state() != Off);
|
x = (_io->gain_automation().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;
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ LadspaPluginUI::build ()
|
||||||
|
|
||||||
/* Don't show latency control ports */
|
/* Don't show latency control ports */
|
||||||
|
|
||||||
if (plugin->describe_parameter (i) == X_("latency")) {
|
if (plugin->describe_parameter (ParamID(PluginAutomation, i)) == X_("latency")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -324,7 +324,8 @@ LadspaPluginUI::automation_state_changed (ControlUI* cui)
|
||||||
{
|
{
|
||||||
/* update button label */
|
/* update button label */
|
||||||
|
|
||||||
switch (insert->get_port_automation_state (cui->port_index) & (Off|Play|Touch|Write)) {
|
switch (insert->get_parameter_automation_state (ParamID(PluginAutomation, cui->port_index))
|
||||||
|
& (Off|Play|Touch|Write)) {
|
||||||
case Off:
|
case Off:
|
||||||
cui->automate_button.set_label (_("Manual"));
|
cui->automate_button.set_label (_("Manual"));
|
||||||
break;
|
break;
|
||||||
|
|
@ -491,7 +492,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 (port_index).automation_state_changed.connect
|
insert->automation_list (ParamID(PluginAutomation, port_index))->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)) {
|
||||||
|
|
@ -548,13 +549,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 (cui->port_index).start_touch ();
|
insert->automation_list (ParamID(PluginAutomation, cui->port_index))->start_touch ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LadspaPluginUI::stop_touch (LadspaPluginUI::ControlUI* cui)
|
LadspaPluginUI::stop_touch (LadspaPluginUI::ControlUI* cui)
|
||||||
{
|
{
|
||||||
insert->automation_list (cui->port_index).stop_touch ();
|
insert->automation_list (ParamID(PluginAutomation, cui->port_index))->stop_touch ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -585,7 +586,7 @@ LadspaPluginUI::astate_clicked (ControlUI* cui, uint32_t port)
|
||||||
void
|
void
|
||||||
LadspaPluginUI::set_automation_state (AutoState state, ControlUI* cui)
|
LadspaPluginUI::set_automation_state (AutoState state, ControlUI* cui)
|
||||||
{
|
{
|
||||||
insert->set_port_automation_state (cui->port_index, state);
|
insert->set_parameter_automation_state (ParamID(PluginAutomation, cui->port_index), state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -601,7 +602,7 @@ LadspaPluginUI::control_adjustment_changed (ControlUI* cui)
|
||||||
value = exp(value);
|
value = exp(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
insert->set_parameter (cui->port_index, (float) value);
|
insert->set_parameter (ParamID(PluginAutomation, cui->port_index), (float) value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -656,7 +657,7 @@ void
|
||||||
LadspaPluginUI::control_port_toggled (ControlUI* cui)
|
LadspaPluginUI::control_port_toggled (ControlUI* cui)
|
||||||
{
|
{
|
||||||
if (!cui->ignore_change) {
|
if (!cui->ignore_change) {
|
||||||
insert->set_parameter (cui->port_index, cui->button->get_active());
|
insert->set_parameter (ParamID(PluginAutomation, cui->port_index), cui->button->get_active());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -666,7 +667,7 @@ LadspaPluginUI::control_combo_changed (ControlUI* cui)
|
||||||
if (!cui->ignore_change) {
|
if (!cui->ignore_change) {
|
||||||
string value = cui->combo->get_active_text();
|
string value = cui->combo->get_active_text();
|
||||||
std::map<string,float> mapping = *cui->combo_map;
|
std::map<string,float> mapping = *cui->combo_map;
|
||||||
insert->set_parameter (cui->port_index, mapping[value]);
|
insert->set_parameter (ParamID(PluginAutomation, cui->port_index), mapping[value]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
81
gtk2_ardour/midi_controller_time_axis.cc
Normal file
81
gtk2_ardour/midi_controller_time_axis.cc
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2003 Paul Davis
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
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 <ardour/automation_event.h>
|
||||||
|
#include <ardour/route.h>
|
||||||
|
#include <pbd/memento_command.h>
|
||||||
|
|
||||||
|
#include "midi_controller_time_axis.h"
|
||||||
|
#include "automation_line.h"
|
||||||
|
#include "canvas.h"
|
||||||
|
|
||||||
|
#include "i18n.h"
|
||||||
|
|
||||||
|
using namespace ARDOUR;
|
||||||
|
using namespace PBD;
|
||||||
|
using namespace Gtk;
|
||||||
|
|
||||||
|
MidiControllerTimeAxisView::MidiControllerTimeAxisView (Session& s, boost::shared_ptr<Route> r,
|
||||||
|
PublicEditor& e, TimeAxisView& parent,
|
||||||
|
ArdourCanvas::Canvas& canvas, const string & n,
|
||||||
|
ParamID param, ARDOUR::AutomationList& l)
|
||||||
|
|
||||||
|
: AxisView (s),
|
||||||
|
AutomationTimeAxisView (s, r, e, parent, canvas, n, param.to_string(), ""),
|
||||||
|
_list (l),
|
||||||
|
_param (param)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MidiControllerTimeAxisView::~MidiControllerTimeAxisView ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiControllerTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEvent* event, nframes_t when, double y)
|
||||||
|
{
|
||||||
|
double x = 0;
|
||||||
|
|
||||||
|
canvas_display->w2i (x, y);
|
||||||
|
|
||||||
|
/* compute vertical fractional position */
|
||||||
|
|
||||||
|
y = 1.0 - (y / height);
|
||||||
|
|
||||||
|
/* map using line */
|
||||||
|
|
||||||
|
lines.front()->view_to_model_y (y);
|
||||||
|
|
||||||
|
_session.begin_reversible_command (_("add midi controller automation event"));
|
||||||
|
XMLNode& before = _list.get_state();
|
||||||
|
_list.add (when, y);
|
||||||
|
XMLNode& after = _list.get_state();
|
||||||
|
_session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(_list, &before, &after));
|
||||||
|
_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
54
gtk2_ardour/midi_controller_time_axis.h
Normal file
54
gtk2_ardour/midi_controller_time_axis.h
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2000-2007 Paul Davis
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
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_midi_controller_time_axis_h__
|
||||||
|
#define __ardour_gtk_midi_controller_time_axis_h__
|
||||||
|
|
||||||
|
#include "canvas.h"
|
||||||
|
#include "automation_time_axis.h"
|
||||||
|
|
||||||
|
namespace ARDOUR {
|
||||||
|
class AutomationList;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MidiControllerTimeAxisView : public AutomationTimeAxisView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MidiControllerTimeAxisView (ARDOUR::Session&,
|
||||||
|
boost::shared_ptr<ARDOUR::Route>,
|
||||||
|
PublicEditor&,
|
||||||
|
TimeAxisView& parent_axis,
|
||||||
|
ArdourCanvas::Canvas& canvas,
|
||||||
|
const string & name,
|
||||||
|
ARDOUR::ParamID param,
|
||||||
|
ARDOUR::AutomationList&);
|
||||||
|
|
||||||
|
~MidiControllerTimeAxisView();
|
||||||
|
|
||||||
|
void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, nframes_t, double);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ARDOUR::AutomationList& _list;
|
||||||
|
ARDOUR::ParamID _param;
|
||||||
|
|
||||||
|
void automation_changed ();
|
||||||
|
void set_automation_state (ARDOUR::AutoState);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __ardour_gtk_midi_controller_time_axis_h__ */
|
||||||
|
|
@ -48,6 +48,7 @@
|
||||||
#include "ardour_ui.h"
|
#include "ardour_ui.h"
|
||||||
#include "midi_time_axis.h"
|
#include "midi_time_axis.h"
|
||||||
#include "automation_time_axis.h"
|
#include "automation_time_axis.h"
|
||||||
|
#include "automation_midi_cc_line.h"
|
||||||
#include "canvas_impl.h"
|
#include "canvas_impl.h"
|
||||||
#include "crossfade_view.h"
|
#include "crossfade_view.h"
|
||||||
#include "enums.h"
|
#include "enums.h"
|
||||||
|
|
@ -61,6 +62,7 @@
|
||||||
#include "public_editor.h"
|
#include "public_editor.h"
|
||||||
#include "redirect_automation_line.h"
|
#include "redirect_automation_line.h"
|
||||||
#include "redirect_automation_time_axis.h"
|
#include "redirect_automation_time_axis.h"
|
||||||
|
#include "midi_controller_time_axis.h"
|
||||||
#include "region_view.h"
|
#include "region_view.h"
|
||||||
#include "rgb_macros.h"
|
#include "rgb_macros.h"
|
||||||
#include "selection.h"
|
#include "selection.h"
|
||||||
|
|
@ -147,30 +149,67 @@ MidiTimeAxisView::hide ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiTimeAxisView::set_state (const XMLNode& node)
|
MidiTimeAxisView::build_automation_action_menu ()
|
||||||
{
|
{
|
||||||
const XMLProperty *prop;
|
using namespace Menu_Helpers;
|
||||||
|
|
||||||
TimeAxisView::set_state (node);
|
RouteTimeAxisView::build_automation_action_menu ();
|
||||||
|
|
||||||
if ((prop = node.property ("shown_editor")) != 0) {
|
MenuList& automation_items = automation_action_menu->items();
|
||||||
if (prop->value() == "no") {
|
|
||||||
_marked_for_display = false;
|
automation_items.push_back (SeparatorElem());
|
||||||
} else {
|
|
||||||
_marked_for_display = true;
|
automation_items.push_back (MenuElem (_("Controller..."),
|
||||||
}
|
mem_fun(*this, &MidiTimeAxisView::add_controller_track)));
|
||||||
} else {
|
|
||||||
_marked_for_display = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLNodeList nlist = node.children();
|
/** Prompt for a controller with a dialog and add an automation track for it
|
||||||
XMLNodeConstIterator niter;
|
*/
|
||||||
XMLNode *child_node;
|
void
|
||||||
|
MidiTimeAxisView::add_controller_track()
|
||||||
|
{
|
||||||
|
/* TODO: fancy controller selection dialog here... */
|
||||||
|
|
||||||
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
ParamID param(MidiCCAutomation, 7);
|
||||||
child_node = *niter;
|
create_automation_child(param);
|
||||||
|
}
|
||||||
|
|
||||||
// uh... do stuff..
|
void
|
||||||
|
MidiTimeAxisView::create_automation_child (ParamID param)
|
||||||
|
{
|
||||||
|
if (param.type() == MidiCCAutomation) {
|
||||||
|
|
||||||
|
/* FIXME: this all probably leaks */
|
||||||
|
|
||||||
|
ARDOUR::AutomationList* al = _route->automation_list(param);
|
||||||
|
|
||||||
|
if (!al)
|
||||||
|
al = new ARDOUR::AutomationList(param, 0, 127, 64);
|
||||||
|
|
||||||
|
_route->add_automation_parameter(al);
|
||||||
|
|
||||||
|
MidiControllerTimeAxisView* track = new MidiControllerTimeAxisView (_session,
|
||||||
|
_route,
|
||||||
|
editor,
|
||||||
|
*this,
|
||||||
|
parent_canvas,
|
||||||
|
_route->describe_parameter(param),
|
||||||
|
param,
|
||||||
|
*al);
|
||||||
|
|
||||||
|
AutomationMidiCCLine* line = new AutomationMidiCCLine (param.to_string(),
|
||||||
|
*track,
|
||||||
|
*track->canvas_display,
|
||||||
|
*al);
|
||||||
|
|
||||||
|
line->set_line_color (Config->canvasvar_AutomationLine.get());
|
||||||
|
|
||||||
|
track->add_line(*line);
|
||||||
|
|
||||||
|
add_automation_child(param, track);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
error << "MidiTimeAxisView: unknown automation child " << param.to_string() << endmsg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,9 +244,3 @@ MidiTimeAxisView::route_active_changed ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLNode*
|
|
||||||
MidiTimeAxisView::get_child_xml_node (const string & childname)
|
|
||||||
{
|
|
||||||
return RouteUI::get_child_xml_node (childname);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,10 +62,13 @@ class MidiTimeAxisView : public RouteTimeAxisView
|
||||||
guint32 show_at (double y, int& nth, Gtk::VBox *parent);
|
guint32 show_at (double y, int& nth, Gtk::VBox *parent);
|
||||||
void hide ();
|
void hide ();
|
||||||
|
|
||||||
void set_state (const XMLNode&);
|
void add_controller_track ();
|
||||||
XMLNode* get_child_xml_node (const string & childname);
|
void create_automation_child (ARDOUR::ParamID param);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void build_automation_action_menu ();
|
||||||
|
|
||||||
void route_active_changed ();
|
void route_active_changed ();
|
||||||
|
|
||||||
void add_insert_to_subplugin_menu (ARDOUR::Insert *);
|
void add_insert_to_subplugin_menu (ARDOUR::Insert *);
|
||||||
|
|
|
||||||
|
|
@ -435,8 +435,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_curve().automation_style()));
|
((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (gpm.astyle_string(_route->gain_automation().automation_style()));
|
||||||
((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (gpm.astate_string(_route->gain_automation_curve().automation_state()));
|
((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (gpm.astate_string(_route->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 +457,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_curve().automation_style()));
|
((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (gpm.short_astyle_string(_route->gain_automation().automation_style()));
|
||||||
((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (gpm.short_astate_string(_route->gain_automation_curve().automation_state()));
|
((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (gpm.short_astate_string(_route->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);
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,11 @@ PanAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEv
|
||||||
{
|
{
|
||||||
if (lines.empty()) {
|
if (lines.empty()) {
|
||||||
/* no data, possibly caused by no outputs/inputs */
|
/* no data, possibly caused by no outputs/inputs */
|
||||||
|
Gtkmm2ext::PopUp* msg = new Gtkmm2ext::PopUp (Gtk::WIN_POS_MOUSE, 5000, true);
|
||||||
|
|
||||||
|
msg->set_text (_("Pan automation track has no lines, unable to add point\n(is track pannable?)"));
|
||||||
|
msg->touch ();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,10 @@ class LadspaPluginUI : public PlugUIBase, public Gtk::VBox
|
||||||
static const int32_t initial_output_rows = 1;
|
static const int32_t initial_output_rows = 1;
|
||||||
static const int32_t initial_output_cols = 4;
|
static const int32_t initial_output_cols = 4;
|
||||||
|
|
||||||
|
/* TODO: pull this out of PluginUI and make it generic.
|
||||||
|
* Sticking this in the track controls of an automation track would
|
||||||
|
* make a handy touch controller for anything.
|
||||||
|
*/
|
||||||
struct ControlUI : public Gtk::HBox {
|
struct ControlUI : public Gtk::HBox {
|
||||||
|
|
||||||
uint32_t port_index;
|
uint32_t port_index;
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ using namespace std;
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
RedirectAutomationLine::RedirectAutomationLine (const string & name, Insert& i, uint32_t port, Session& s,
|
RedirectAutomationLine::RedirectAutomationLine (const string & name, Insert& i, ParamID param, Session& s,
|
||||||
|
|
||||||
TimeAxisView& tv, ArdourCanvas::Group& parent,
|
TimeAxisView& tv, ArdourCanvas::Group& parent,
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ RedirectAutomationLine::RedirectAutomationLine (const string & name, Insert& i,
|
||||||
: AutomationLine (name, tv, parent, l),
|
: AutomationLine (name, tv, parent, l),
|
||||||
session (s),
|
session (s),
|
||||||
_insert (i),
|
_insert (i),
|
||||||
_port (port)
|
_param (param)
|
||||||
{
|
{
|
||||||
set_verbose_cursor_uses_gain_mapping (false);
|
set_verbose_cursor_uses_gain_mapping (false);
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ RedirectAutomationLine::RedirectAutomationLine (const string & name, Insert& i,
|
||||||
/*NOTREACHED*/
|
/*NOTREACHED*/
|
||||||
}
|
}
|
||||||
|
|
||||||
pi->plugin()->get_parameter_descriptor (_port, desc);
|
pi->plugin()->get_parameter_descriptor (_param, desc);
|
||||||
|
|
||||||
upper = desc.upper;
|
upper = desc.upper;
|
||||||
lower = desc.lower;
|
lower = desc.lower;
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,10 @@ class TimeAxisView;
|
||||||
class RedirectAutomationLine : public AutomationLine
|
class RedirectAutomationLine : public AutomationLine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RedirectAutomationLine (const string & name, ARDOUR::Insert&, uint32_t port, ARDOUR::Session&, TimeAxisView&,
|
RedirectAutomationLine (const string & name, ARDOUR::Insert&, ARDOUR::ParamID param, ARDOUR::Session&, TimeAxisView&,
|
||||||
ArdourCanvas::Group& parent, ARDOUR::AutomationList&);
|
ArdourCanvas::Group& parent, ARDOUR::AutomationList&);
|
||||||
|
|
||||||
uint32_t port() const { return _port; }
|
ARDOUR::ParamID param() const { return _param; }
|
||||||
ARDOUR::Insert& insert() const { return _insert; }
|
ARDOUR::Insert& insert() const { return _insert; }
|
||||||
|
|
||||||
string get_verbose_cursor_string (float);
|
string get_verbose_cursor_string (float);
|
||||||
|
|
@ -45,7 +45,7 @@ class RedirectAutomationLine : public AutomationLine
|
||||||
private:
|
private:
|
||||||
ARDOUR::Session& session;
|
ARDOUR::Session& session;
|
||||||
ARDOUR::Insert& _insert;
|
ARDOUR::Insert& _insert;
|
||||||
uint32_t _port;
|
ARDOUR::ParamID _param;
|
||||||
float upper;
|
float upper;
|
||||||
float lower;
|
float lower;
|
||||||
float range;
|
float range;
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,12 @@ using namespace Gtk;
|
||||||
|
|
||||||
RedirectAutomationTimeAxisView::RedirectAutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r,
|
RedirectAutomationTimeAxisView::RedirectAutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r,
|
||||||
PublicEditor& e, TimeAxisView& parent, Canvas& canvas, std::string n,
|
PublicEditor& e, TimeAxisView& parent, Canvas& canvas, std::string n,
|
||||||
uint32_t prt, Insert& i, string state_name)
|
ParamID p, Insert& i, string state_name)
|
||||||
|
|
||||||
: AxisView (s),
|
: AxisView (s),
|
||||||
AutomationTimeAxisView (s, r, e, parent, canvas, n, state_name, i.name()),
|
AutomationTimeAxisView (s, r, e, parent, canvas, n, state_name, i.name()),
|
||||||
insert (i),
|
insert (i),
|
||||||
port (prt)
|
param (p)
|
||||||
|
|
||||||
{
|
{
|
||||||
char buf[32];
|
char buf[32];
|
||||||
|
|
@ -53,7 +53,7 @@ RedirectAutomationTimeAxisView::RedirectAutomationTimeAxisView (Session& s, boos
|
||||||
|
|
||||||
kids = xml_node->children ();
|
kids = xml_node->children ();
|
||||||
|
|
||||||
snprintf (buf, sizeof(buf), "Port_%" PRIu32, port);
|
snprintf (buf, sizeof(buf), "Port_%" PRIu32, param.id());
|
||||||
|
|
||||||
for (iter = kids.begin(); iter != kids.end(); ++iter) {
|
for (iter = kids.begin(); iter != kids.end(); ++iter) {
|
||||||
if ((*iter)->name() == buf) {
|
if ((*iter)->name() == buf) {
|
||||||
|
|
@ -91,17 +91,17 @@ RedirectAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item,
|
||||||
/* map to model space */
|
/* map to model space */
|
||||||
|
|
||||||
if (!lines.empty()) {
|
if (!lines.empty()) {
|
||||||
AutomationList& alist (insert.automation_list(port));
|
AutomationList* alist (insert.automation_list(param, true));
|
||||||
string description = _("add automation event to ");
|
string description = _("add automation event to ");
|
||||||
description += insert.describe_parameter (port);
|
description += insert.describe_parameter (param);
|
||||||
|
|
||||||
lines.front()->view_to_model_y (y);
|
lines.front()->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();
|
||||||
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, &before, &after));
|
||||||
_session.commit_reversible_command ();
|
_session.commit_reversible_command ();
|
||||||
_session.set_dirty ();
|
_session.set_dirty ();
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +146,7 @@ RedirectAutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
|
||||||
XMLNodeConstIterator i;
|
XMLNodeConstIterator i;
|
||||||
XMLNode * port_node = 0;
|
XMLNode * port_node = 0;
|
||||||
|
|
||||||
snprintf (buf, sizeof(buf), "Port_%" PRIu32, port);
|
snprintf (buf, sizeof(buf), "Port_%" PRIu32, param.id());
|
||||||
|
|
||||||
for (i = nlist.begin(); i != nlist.end(); ++i) {
|
for (i = nlist.begin(); i != nlist.end(); ++i) {
|
||||||
if ((*i)->name() == buf) {
|
if ((*i)->name() == buf) {
|
||||||
|
|
@ -168,6 +168,6 @@ void
|
||||||
RedirectAutomationTimeAxisView::set_automation_state (AutoState state)
|
RedirectAutomationTimeAxisView::set_automation_state (AutoState state)
|
||||||
{
|
{
|
||||||
if (!ignore_state_request) {
|
if (!ignore_state_request) {
|
||||||
insert.automation_list (port).set_automation_state (state);
|
insert.automation_list (param, true)->set_automation_state (state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "canvas.h"
|
#include "canvas.h"
|
||||||
#include "automation_time_axis.h"
|
#include "automation_time_axis.h"
|
||||||
|
#include <ardour/param_id.h>
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
class Redirect;
|
class Redirect;
|
||||||
|
|
@ -38,7 +39,7 @@ class RedirectAutomationTimeAxisView : public AutomationTimeAxisView
|
||||||
TimeAxisView& parent,
|
TimeAxisView& parent,
|
||||||
ArdourCanvas::Canvas& canvas,
|
ArdourCanvas::Canvas& canvas,
|
||||||
std::string name,
|
std::string name,
|
||||||
uint32_t port,
|
ARDOUR::ParamID param,
|
||||||
ARDOUR::Insert& i,
|
ARDOUR::Insert& i,
|
||||||
std::string state_name);
|
std::string state_name);
|
||||||
|
|
||||||
|
|
@ -52,7 +53,7 @@ class RedirectAutomationTimeAxisView : public AutomationTimeAxisView
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ARDOUR::Insert& insert;
|
ARDOUR::Insert& insert;
|
||||||
uint32_t port;
|
ARDOUR::ParamID param;
|
||||||
|
|
||||||
XMLNode *xml_node;
|
XMLNode *xml_node;
|
||||||
void ensure_xml_node();
|
void ensure_xml_node();
|
||||||
|
|
|
||||||
|
|
@ -1050,7 +1050,7 @@ RedirectBox::edit_insert (boost::shared_ptr<Insert> insert)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((send = boost::dynamic_pointer_cast<Send> (send)) == 0) {
|
if ((send = boost::dynamic_pointer_cast<Send> (send)) != 0) {
|
||||||
|
|
||||||
if (!_session.engine().connected()) {
|
if (!_session.engine().connected()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,8 @@ 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, Curve& c)
|
AudioRegionGainLine::AudioRegionGainLine (const string & name, Session& s, AudioRegionView& r, ArdourCanvas::Group& parent, AutomationList& l)
|
||||||
: AutomationLine (name, r.get_time_axis_view(), parent, c),
|
: AutomationLine (name, r.get_time_axis_view(), parent, l),
|
||||||
session (s),
|
session (s),
|
||||||
rv (r)
|
rv (r)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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::Curve&);
|
AudioRegionGainLine (const string & name, ARDOUR::Session&, AudioRegionView&, ArdourCanvas::Group& parent, 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&);
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <sigc++/bind.h>
|
#include <sigc++/bind.h>
|
||||||
|
|
||||||
|
|
@ -50,6 +51,7 @@
|
||||||
#include <ardour/session.h>
|
#include <ardour/session.h>
|
||||||
#include <ardour/session_playlist.h>
|
#include <ardour/session_playlist.h>
|
||||||
#include <ardour/utils.h>
|
#include <ardour/utils.h>
|
||||||
|
#include <ardour/param_id.h>
|
||||||
|
|
||||||
#include "ardour_ui.h"
|
#include "ardour_ui.h"
|
||||||
#include "route_time_axis.h"
|
#include "route_time_axis.h"
|
||||||
|
|
@ -80,6 +82,7 @@ using namespace ARDOUR;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
using namespace Gtk;
|
using namespace Gtk;
|
||||||
using namespace Editing;
|
using namespace Editing;
|
||||||
|
using namespace sigc;
|
||||||
|
|
||||||
|
|
||||||
RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr<Route> rt, Canvas& canvas)
|
RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr<Route> rt, Canvas& canvas)
|
||||||
|
|
@ -252,6 +255,58 @@ RouteTimeAxisView::playlist_modified ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RouteTimeAxisView::set_state (const XMLNode& node)
|
||||||
|
{
|
||||||
|
const XMLProperty *prop;
|
||||||
|
|
||||||
|
TimeAxisView::set_state (node);
|
||||||
|
|
||||||
|
if ((prop = node.property ("shown_editor")) != 0) {
|
||||||
|
if (prop->value() == "no") {
|
||||||
|
_marked_for_display = false;
|
||||||
|
} else {
|
||||||
|
_marked_for_display = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_marked_for_display = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLNodeList nlist = node.children();
|
||||||
|
XMLNodeConstIterator niter;
|
||||||
|
XMLNode *child_node;
|
||||||
|
|
||||||
|
_show_automation.clear();
|
||||||
|
|
||||||
|
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
||||||
|
child_node = *niter;
|
||||||
|
|
||||||
|
ParamID param(child_node->name());
|
||||||
|
|
||||||
|
if (param) {
|
||||||
|
|
||||||
|
cerr << "RTAV::set_state parameter: " << param.to_string() << endl;
|
||||||
|
|
||||||
|
XMLProperty* prop = child_node->property ("shown");
|
||||||
|
|
||||||
|
if (_automation_tracks.find(param) == _automation_tracks.end())
|
||||||
|
create_automation_child(param);
|
||||||
|
|
||||||
|
if (prop != 0 && prop->value() == "yes")
|
||||||
|
_show_automation.insert(ParamID(GainAutomation));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cerr << "RTAV: no parameter " << child_node->name() << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLNode*
|
||||||
|
RouteTimeAxisView::get_child_xml_node (const string & childname)
|
||||||
|
{
|
||||||
|
return RouteUI::get_child_xml_node (childname);
|
||||||
|
}
|
||||||
|
|
||||||
gint
|
gint
|
||||||
RouteTimeAxisView::edit_click (GdkEventButton *ev)
|
RouteTimeAxisView::edit_click (GdkEventButton *ev)
|
||||||
{
|
{
|
||||||
|
|
@ -386,6 +441,24 @@ RouteTimeAxisView::build_automation_action_menu ()
|
||||||
mem_fun(*this, &RouteTimeAxisView::hide_all_automation)));
|
mem_fun(*this, &RouteTimeAxisView::hide_all_automation)));
|
||||||
|
|
||||||
automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu));
|
automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu));
|
||||||
|
|
||||||
|
map<ARDOUR::ParamID, RouteAutomationNode*>::iterator i;
|
||||||
|
for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
|
||||||
|
|
||||||
|
automation_items.push_back (SeparatorElem());
|
||||||
|
|
||||||
|
if ( ! i->second->menu_item) {
|
||||||
|
automation_items.push_back(CheckMenuElem (_route->describe_parameter(i->second->param),
|
||||||
|
bind (mem_fun(*this, &RouteTimeAxisView::toggle_automation_track), i->second->param)));
|
||||||
|
|
||||||
|
i->second->menu_item = static_cast<Gtk::CheckMenuItem*>(&automation_items.back());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
automation_items.push_back (*i->second->menu_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
i->second->menu_item->set_active(show_automation(i->second->param));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1092,6 +1165,33 @@ RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>&
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RouteTimeAxisView::show_automation(ParamID param)
|
||||||
|
{
|
||||||
|
return (_show_automation.find(param) != _show_automation.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retuns NULL if track for \a param doesn't exist.
|
||||||
|
*/
|
||||||
|
RouteTimeAxisView::RouteAutomationNode*
|
||||||
|
RouteTimeAxisView::automation_track(ParamID param)
|
||||||
|
{
|
||||||
|
map<ARDOUR::ParamID, RouteAutomationNode*>::iterator i = _automation_tracks.find(param);
|
||||||
|
|
||||||
|
if (i != _automation_tracks.end())
|
||||||
|
return i->second;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Shorthand for GainAutomation, etc.
|
||||||
|
*/
|
||||||
|
RouteTimeAxisView::RouteAutomationNode*
|
||||||
|
RouteTimeAxisView::automation_track(AutomationType type)
|
||||||
|
{
|
||||||
|
return automation_track(ParamID(type));
|
||||||
|
}
|
||||||
|
|
||||||
RouteGroup*
|
RouteGroup*
|
||||||
RouteTimeAxisView::edit_group() const
|
RouteTimeAxisView::edit_group() const
|
||||||
{
|
{
|
||||||
|
|
@ -1379,11 +1479,71 @@ RouteTimeAxisView::color_handler ()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RouteTimeAxisView::toggle_automation_track (ParamID param)
|
||||||
|
{
|
||||||
|
RouteAutomationNode* node = automation_track(param);
|
||||||
|
|
||||||
|
if (!node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool showit = node->menu_item->get_active();
|
||||||
|
|
||||||
|
if (showit != node->track->marked_for_display()) {
|
||||||
|
if (showit) {
|
||||||
|
node->track->set_marked_for_display (true);
|
||||||
|
node->track->canvas_display->show();
|
||||||
|
node->track->get_state_node()->add_property ("shown", X_("yes"));
|
||||||
|
} else {
|
||||||
|
node->track->set_marked_for_display (false);
|
||||||
|
node->track->hide ();
|
||||||
|
node->track->get_state_node()->add_property ("shown", X_("no"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now trigger a redisplay */
|
||||||
|
|
||||||
|
if (!no_redraw) {
|
||||||
|
_route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RouteTimeAxisView::automation_track_hidden (ParamID param)
|
||||||
|
{
|
||||||
|
RouteAutomationNode* ran = automation_track(param);
|
||||||
|
if (!ran)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_show_automation.erase(param);
|
||||||
|
ran->track->get_state_node()->add_property (X_("shown"), X_("no"));
|
||||||
|
|
||||||
|
if (ran->menu_item && !_hidden) {
|
||||||
|
ran->menu_item->set_active (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
RouteTimeAxisView::show_all_automation ()
|
RouteTimeAxisView::show_all_automation ()
|
||||||
{
|
{
|
||||||
no_redraw = true;
|
no_redraw = true;
|
||||||
|
|
||||||
|
/* Show our automation */
|
||||||
|
|
||||||
|
map<ARDOUR::ParamID, RouteAutomationNode*>::iterator i;
|
||||||
|
for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
|
||||||
|
i->second->track->set_marked_for_display (true);
|
||||||
|
i->second->track->canvas_display->show();
|
||||||
|
i->second->track->get_state_node()->add_property ("shown", X_("yes"));
|
||||||
|
i->second->menu_item->set_active(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Show insert automation */
|
||||||
|
|
||||||
for (list<InsertAutomationInfo*>::iterator i = insert_automation.begin(); i != insert_automation.end(); ++i) {
|
for (list<InsertAutomationInfo*>::iterator i = insert_automation.begin(); i != insert_automation.end(); ++i) {
|
||||||
for (vector<InsertAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
|
for (vector<InsertAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
|
||||||
if ((*ii)->view == 0) {
|
if ((*ii)->view == 0) {
|
||||||
|
|
@ -1396,6 +1556,9 @@ RouteTimeAxisView::show_all_automation ()
|
||||||
|
|
||||||
no_redraw = false;
|
no_redraw = false;
|
||||||
|
|
||||||
|
|
||||||
|
/* Redraw */
|
||||||
|
|
||||||
_route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
|
_route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1404,6 +1567,22 @@ RouteTimeAxisView::show_existing_automation ()
|
||||||
{
|
{
|
||||||
no_redraw = true;
|
no_redraw = true;
|
||||||
|
|
||||||
|
/* Show our automation */
|
||||||
|
|
||||||
|
map<ARDOUR::ParamID, RouteAutomationNode*>::iterator i;
|
||||||
|
for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
|
||||||
|
// FIXME: only shown if /first/ line has points
|
||||||
|
if (!i->second->track->lines.empty() && i->second->track->lines[0]->npoints() > 0) {
|
||||||
|
i->second->track->set_marked_for_display (true);
|
||||||
|
i->second->track->canvas_display->show();
|
||||||
|
i->second->track->get_state_node()->add_property ("shown", X_("yes"));
|
||||||
|
i->second->menu_item->set_active(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Show insert automation */
|
||||||
|
|
||||||
for (list<InsertAutomationInfo*>::iterator i = insert_automation.begin(); i != insert_automation.end(); ++i) {
|
for (list<InsertAutomationInfo*>::iterator i = insert_automation.begin(); i != insert_automation.end(); ++i) {
|
||||||
for (vector<InsertAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
|
for (vector<InsertAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
|
||||||
if ((*ii)->view != 0) {
|
if ((*ii)->view != 0) {
|
||||||
|
|
@ -1477,7 +1656,7 @@ RouteTimeAxisView::remove_ran (InsertAutomationNode* ran)
|
||||||
}
|
}
|
||||||
|
|
||||||
RouteTimeAxisView::InsertAutomationNode*
|
RouteTimeAxisView::InsertAutomationNode*
|
||||||
RouteTimeAxisView::find_insert_automation_node (boost::shared_ptr<Insert> insert, uint32_t what)
|
RouteTimeAxisView::find_insert_automation_node (boost::shared_ptr<Insert> insert, ParamID what)
|
||||||
{
|
{
|
||||||
for (list<InsertAutomationInfo*>::iterator i = insert_automation.begin(); i != insert_automation.end(); ++i) {
|
for (list<InsertAutomationInfo*>::iterator i = insert_automation.begin(); i != insert_automation.end(); ++i) {
|
||||||
|
|
||||||
|
|
@ -1514,7 +1693,7 @@ legalize_for_xml_node (string str)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
RouteTimeAxisView::add_insert_automation_curve (boost::shared_ptr<Insert> insert, uint32_t what)
|
RouteTimeAxisView::add_insert_automation_curve (boost::shared_ptr<Insert> insert, ParamID what)
|
||||||
{
|
{
|
||||||
RedirectAutomationLine* ral;
|
RedirectAutomationLine* ral;
|
||||||
string name;
|
string name;
|
||||||
|
|
@ -1538,13 +1717,13 @@ RouteTimeAxisView::add_insert_automation_curve (boost::shared_ptr<Insert> insert
|
||||||
/* 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 */
|
||||||
|
|
||||||
char state_name[256];
|
char state_name[256];
|
||||||
snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (insert->name()).c_str(), what);
|
snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (insert->name()).c_str(), what.id());
|
||||||
|
|
||||||
ran->view = new RedirectAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, name, what, *insert, state_name);
|
ran->view = new RedirectAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, name, what, *insert, state_name);
|
||||||
|
|
||||||
ral = new RedirectAutomationLine (name,
|
ral = new RedirectAutomationLine (name,
|
||||||
*insert, what, _session, *ran->view,
|
*insert, what, _session, *ran->view,
|
||||||
*ran->view->canvas_display, insert->automation_list (what));
|
*ran->view->canvas_display, *insert->automation_list (what, true));
|
||||||
|
|
||||||
ral->set_line_color (Config->canvasvar_RedirectAutomationLine.get());
|
ral->set_line_color (Config->canvasvar_RedirectAutomationLine.get());
|
||||||
ral->queue_reset ();
|
ral->queue_reset ();
|
||||||
|
|
@ -1583,12 +1762,12 @@ RouteTimeAxisView::insert_automation_track_hidden (RouteTimeAxisView::InsertAuto
|
||||||
void
|
void
|
||||||
RouteTimeAxisView::add_existing_insert_automation_curves (boost::shared_ptr<Insert> insert)
|
RouteTimeAxisView::add_existing_insert_automation_curves (boost::shared_ptr<Insert> insert)
|
||||||
{
|
{
|
||||||
set<uint32_t> s;
|
set<ParamID> s;
|
||||||
RedirectAutomationLine *ral;
|
RedirectAutomationLine *ral;
|
||||||
|
|
||||||
insert->what_has_visible_automation (s);
|
insert->what_has_visible_automation (s);
|
||||||
|
|
||||||
for (set<uint32_t>::iterator i = s.begin(); i != s.end(); ++i) {
|
for (set<ParamID>::iterator i = s.begin(); i != s.end(); ++i) {
|
||||||
|
|
||||||
if ((ral = find_insert_automation_curve (insert, *i)) != 0) {
|
if ((ral = find_insert_automation_curve (insert, *i)) != 0) {
|
||||||
ral->queue_reset ();
|
ral->queue_reset ();
|
||||||
|
|
@ -1598,6 +1777,39 @@ RouteTimeAxisView::add_existing_insert_automation_curves (boost::shared_ptr<Inse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RouteTimeAxisView::add_automation_child(ParamID param, AutomationTimeAxisView* track)
|
||||||
|
{
|
||||||
|
using namespace Menu_Helpers;
|
||||||
|
|
||||||
|
XMLProperty* prop;
|
||||||
|
|
||||||
|
add_child (track);
|
||||||
|
|
||||||
|
track->Hiding.connect (bind (mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
|
||||||
|
|
||||||
|
bool hideit = true;
|
||||||
|
|
||||||
|
XMLNode* node;
|
||||||
|
|
||||||
|
if ((node = track->get_state_node()) != 0) {
|
||||||
|
if ((prop = node->property ("shown")) != 0) {
|
||||||
|
if (prop->value() == "yes") {
|
||||||
|
hideit = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hideit) {
|
||||||
|
track->hide ();
|
||||||
|
} else {
|
||||||
|
_show_automation.insert(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
_automation_tracks.insert(std::make_pair(param, new RouteAutomationNode(param, NULL, track)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
RouteTimeAxisView::add_insert_to_subplugin_menu (boost::shared_ptr<Insert> insert)
|
RouteTimeAxisView::add_insert_to_subplugin_menu (boost::shared_ptr<Insert> insert)
|
||||||
{
|
{
|
||||||
|
|
@ -1605,8 +1817,8 @@ RouteTimeAxisView::add_insert_to_subplugin_menu (boost::shared_ptr<Insert> inser
|
||||||
InsertAutomationInfo *rai;
|
InsertAutomationInfo *rai;
|
||||||
list<InsertAutomationInfo*>::iterator x;
|
list<InsertAutomationInfo*>::iterator x;
|
||||||
|
|
||||||
const std::set<uint32_t>& automatable = insert->what_can_be_automated ();
|
const std::set<ParamID>& automatable = insert->what_can_be_automated ();
|
||||||
std::set<uint32_t> has_visible_automation;
|
std::set<ParamID> has_visible_automation;
|
||||||
|
|
||||||
insert->what_has_visible_automation(has_visible_automation);
|
insert->what_has_visible_automation(has_visible_automation);
|
||||||
|
|
||||||
|
|
@ -1641,7 +1853,7 @@ RouteTimeAxisView::add_insert_to_subplugin_menu (boost::shared_ptr<Insert> inser
|
||||||
|
|
||||||
items.clear ();
|
items.clear ();
|
||||||
|
|
||||||
for (std::set<uint32_t>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
|
for (std::set<ParamID>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
|
||||||
|
|
||||||
InsertAutomationNode* ran;
|
InsertAutomationNode* ran;
|
||||||
CheckMenuItem* mitem;
|
CheckMenuItem* mitem;
|
||||||
|
|
@ -1755,7 +1967,7 @@ RouteTimeAxisView::inserts_changed ()
|
||||||
}
|
}
|
||||||
|
|
||||||
RedirectAutomationLine *
|
RedirectAutomationLine *
|
||||||
RouteTimeAxisView::find_insert_automation_curve (boost::shared_ptr<Insert> insert, uint32_t what)
|
RouteTimeAxisView::find_insert_automation_curve (boost::shared_ptr<Insert> insert, ParamID what)
|
||||||
{
|
{
|
||||||
InsertAutomationNode* ran;
|
InsertAutomationNode* ran;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ public:
|
||||||
void set_selected_regionviews (RegionSelection&);
|
void set_selected_regionviews (RegionSelection&);
|
||||||
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 *>&);
|
||||||
void get_inverted_selectables (Selection&, list<Selectable*>&);
|
void get_inverted_selectables (Selection&, list<Selectable*>&);
|
||||||
|
bool show_automation(ARDOUR::ParamID param);
|
||||||
|
|
||||||
boost::shared_ptr<ARDOUR::Region> find_next_region (nframes_t pos, ARDOUR::RegionPoint, int32_t dir);
|
boost::shared_ptr<ARDOUR::Region> find_next_region (nframes_t pos, ARDOUR::RegionPoint, int32_t dir);
|
||||||
|
|
||||||
|
|
@ -95,6 +96,8 @@ public:
|
||||||
|
|
||||||
void build_playlist_menu (Gtk::Menu *);
|
void build_playlist_menu (Gtk::Menu *);
|
||||||
|
|
||||||
|
virtual void create_automation_child (ARDOUR::ParamID param) = 0;
|
||||||
|
|
||||||
string name() const;
|
string name() const;
|
||||||
StreamView* view() const { return _view; }
|
StreamView* view() const { return _view; }
|
||||||
ARDOUR::RouteGroup* edit_group() const;
|
ARDOUR::RouteGroup* edit_group() const;
|
||||||
|
|
@ -103,13 +106,22 @@ public:
|
||||||
protected:
|
protected:
|
||||||
friend class StreamView;
|
friend class StreamView;
|
||||||
|
|
||||||
|
struct RouteAutomationNode {
|
||||||
|
ARDOUR::ParamID param;
|
||||||
|
Gtk::CheckMenuItem* menu_item;
|
||||||
|
AutomationTimeAxisView* track;
|
||||||
|
|
||||||
|
RouteAutomationNode (ARDOUR::ParamID par, Gtk::CheckMenuItem* mi, AutomationTimeAxisView* tr)
|
||||||
|
: param (par), menu_item (mi), track (tr) {}
|
||||||
|
};
|
||||||
|
|
||||||
struct InsertAutomationNode {
|
struct InsertAutomationNode {
|
||||||
uint32_t what;
|
ARDOUR::ParamID what;
|
||||||
Gtk::CheckMenuItem* menu_item;
|
Gtk::CheckMenuItem* menu_item;
|
||||||
AutomationTimeAxisView* view;
|
AutomationTimeAxisView* view;
|
||||||
RouteTimeAxisView& parent;
|
RouteTimeAxisView& parent;
|
||||||
|
|
||||||
InsertAutomationNode (uint32_t w, Gtk::CheckMenuItem* mitem, RouteTimeAxisView& p)
|
InsertAutomationNode (ARDOUR::ParamID w, Gtk::CheckMenuItem* mitem, RouteTimeAxisView& p)
|
||||||
: what (w), menu_item (mitem), view (0), parent (p) {}
|
: what (w), menu_item (mitem), view (0), parent (p) {}
|
||||||
|
|
||||||
~InsertAutomationNode ();
|
~InsertAutomationNode ();
|
||||||
|
|
@ -144,15 +156,22 @@ protected:
|
||||||
void insert_automation_track_hidden (InsertAutomationNode*,
|
void insert_automation_track_hidden (InsertAutomationNode*,
|
||||||
boost::shared_ptr<ARDOUR::Insert>);
|
boost::shared_ptr<ARDOUR::Insert>);
|
||||||
|
|
||||||
|
void automation_track_hidden (ARDOUR::ParamID param);
|
||||||
|
|
||||||
|
RouteAutomationNode* automation_track(ARDOUR::ParamID param);
|
||||||
|
RouteAutomationNode* automation_track(ARDOUR::AutomationType type);
|
||||||
|
|
||||||
InsertAutomationNode*
|
InsertAutomationNode*
|
||||||
find_insert_automation_node (boost::shared_ptr<ARDOUR::Insert> i, uint32_t);
|
find_insert_automation_node (boost::shared_ptr<ARDOUR::Insert> i, ARDOUR::ParamID);
|
||||||
|
|
||||||
RedirectAutomationLine*
|
RedirectAutomationLine*
|
||||||
find_insert_automation_curve (boost::shared_ptr<ARDOUR::Insert> i, uint32_t);
|
find_insert_automation_curve (boost::shared_ptr<ARDOUR::Insert> i, ARDOUR::ParamID);
|
||||||
|
|
||||||
void add_insert_automation_curve (boost::shared_ptr<ARDOUR::Insert> r, uint32_t);
|
void add_insert_automation_curve (boost::shared_ptr<ARDOUR::Insert> r, ARDOUR::ParamID);
|
||||||
void add_existing_insert_automation_curves (boost::shared_ptr<ARDOUR::Insert>);
|
void add_existing_insert_automation_curves (boost::shared_ptr<ARDOUR::Insert>);
|
||||||
|
|
||||||
|
void add_automation_child(ARDOUR::ParamID param, AutomationTimeAxisView* track);
|
||||||
|
|
||||||
void reset_insert_automation_curves ();
|
void reset_insert_automation_curves ();
|
||||||
|
|
||||||
void take_name_changed (void *src);
|
void take_name_changed (void *src);
|
||||||
|
|
@ -186,6 +205,7 @@ protected:
|
||||||
void rename_current_playlist ();
|
void rename_current_playlist ();
|
||||||
|
|
||||||
void automation_click ();
|
void automation_click ();
|
||||||
|
void toggle_automation_track (ARDOUR::ParamID param);
|
||||||
virtual void show_all_automation ();
|
virtual void show_all_automation ();
|
||||||
virtual void show_existing_automation ();
|
virtual void show_existing_automation ();
|
||||||
virtual void hide_all_automation ();
|
virtual void hide_all_automation ();
|
||||||
|
|
@ -204,7 +224,6 @@ protected:
|
||||||
void region_view_added (RegionView*);
|
void region_view_added (RegionView*);
|
||||||
void add_ghost_to_insert (RegionView*, AutomationTimeAxisView*);
|
void add_ghost_to_insert (RegionView*, AutomationTimeAxisView*);
|
||||||
|
|
||||||
|
|
||||||
StreamView* _view;
|
StreamView* _view;
|
||||||
ArdourCanvas::Canvas& parent_canvas;
|
ArdourCanvas::Canvas& parent_canvas;
|
||||||
bool no_redraw;
|
bool no_redraw;
|
||||||
|
|
@ -241,9 +260,18 @@ protected:
|
||||||
list<InsertAutomationInfo*> insert_automation;
|
list<InsertAutomationInfo*> insert_automation;
|
||||||
vector<RedirectAutomationLine*> insert_automation_curves;
|
vector<RedirectAutomationLine*> insert_automation_curves;
|
||||||
|
|
||||||
|
// Set from XML so context menu automation buttons can be correctly initialized
|
||||||
|
set<ARDOUR::ParamID> _show_automation;
|
||||||
|
|
||||||
|
map<ARDOUR::ParamID, RouteAutomationNode*> _automation_tracks;
|
||||||
|
|
||||||
sigc::connection modified_connection;
|
sigc::connection modified_connection;
|
||||||
|
|
||||||
void post_construct ();
|
void post_construct ();
|
||||||
|
|
||||||
|
void set_state (const XMLNode&);
|
||||||
|
|
||||||
|
XMLNode* get_child_xml_node (const string & childname);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __ardour_route_time_axis_h__ */
|
#endif /* __ardour_route_time_axis_h__ */
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
||||||
Curve& fade_in() { return _fade_in; }
|
AutomationList& fade_in() { return _fade_in; }
|
||||||
Curve& fade_out() { return _fade_out; }
|
AutomationList& fade_out() { return _fade_out; }
|
||||||
Curve& envelope() { return _envelope; }
|
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 Curve _fade_in;
|
mutable AutomationList _fade_in;
|
||||||
FadeShape _fade_in_shape;
|
FadeShape _fade_in_shape;
|
||||||
mutable Curve _fade_out;
|
mutable AutomationList _fade_out;
|
||||||
FadeShape _fade_out_shape;
|
FadeShape _fade_out_shape;
|
||||||
mutable Curve _envelope;
|
mutable 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;
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <ardour/session_object.h>
|
#include <ardour/session_object.h>
|
||||||
#include <ardour/automation_event.h>
|
#include <ardour/automation_event.h>
|
||||||
|
#include <ardour/param_id.h>
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
|
@ -36,28 +37,46 @@ public:
|
||||||
|
|
||||||
virtual ~Automatable() {}
|
virtual ~Automatable() {}
|
||||||
|
|
||||||
virtual AutomationList& automation_list(uint32_t n);
|
// shorthand for gain, pan, etc
|
||||||
|
inline AutomationList* automation_list(AutomationType type, bool create_if_missing=false) {
|
||||||
|
return automation_list(ParamID(type), create_if_missing);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual AutomationList* automation_list(ParamID id, bool create_if_missing=false);
|
||||||
|
virtual const AutomationList* automation_list(ParamID id) const;
|
||||||
|
|
||||||
|
virtual void add_automation_parameter(AutomationList* al);
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
virtual string describe_parameter(uint32_t which);
|
virtual string describe_parameter(ParamID param);
|
||||||
virtual float default_parameter_value(uint32_t which) { return 1.0f; }
|
virtual float default_parameter_value(ParamID param) { return 1.0f; }
|
||||||
|
|
||||||
void what_has_automation(std::set<uint32_t>&) const;
|
virtual void clear_automation();
|
||||||
void what_has_visible_automation(std::set<uint32_t>&) const;
|
|
||||||
const std::set<uint32_t>& what_can_be_automated() const { return _can_automate_list; }
|
|
||||||
|
|
||||||
void mark_automation_visible(uint32_t, bool);
|
AutoState get_parameter_automation_state (ParamID param);
|
||||||
|
virtual void set_parameter_automation_state (ParamID param, AutoState);
|
||||||
|
|
||||||
|
AutoStyle get_parameter_automation_style (ParamID param);
|
||||||
|
void set_parameter_automation_style (ParamID param, AutoStyle);
|
||||||
|
|
||||||
|
void protect_automation ();
|
||||||
|
|
||||||
|
void what_has_automation(std::set<ParamID>&) const;
|
||||||
|
void what_has_visible_automation(std::set<ParamID>&) const;
|
||||||
|
const std::set<ParamID>& what_can_be_automated() const { return _can_automate_list; }
|
||||||
|
|
||||||
|
void mark_automation_visible(ParamID, bool);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void can_automate(uint32_t);
|
void can_automate(ParamID);
|
||||||
|
|
||||||
virtual void automation_list_creation_callback(uint32_t, AutomationList&) {}
|
virtual void automation_list_creation_callback(ParamID, AutomationList&) {}
|
||||||
|
|
||||||
int set_automation_state(const XMLNode&);
|
int set_automation_state(const XMLNode&, ParamID default_param);
|
||||||
XMLNode& get_automation_state();
|
XMLNode& get_automation_state();
|
||||||
|
|
||||||
int load_automation (const std::string& path);
|
int load_automation (const std::string& path);
|
||||||
|
|
@ -65,10 +84,9 @@ protected:
|
||||||
|
|
||||||
mutable Glib::Mutex _automation_lock;
|
mutable Glib::Mutex _automation_lock;
|
||||||
|
|
||||||
// FIXME: map with int keys is a bit silly. this could be O(1)
|
std::map<ParamID,AutomationList*> _parameter_automation;
|
||||||
std::map<uint32_t,AutomationList*> _parameter_automation;
|
std::set<ParamID> _visible_parameter_automation;
|
||||||
std::set<uint32_t> _visible_parameter_automation;
|
std::set<ParamID> _can_automate_list;
|
||||||
std::set<uint32_t> _can_automate_list;
|
|
||||||
|
|
||||||
nframes_t _last_automation_snapshot;
|
nframes_t _last_automation_snapshot;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -32,35 +32,39 @@
|
||||||
#include <pbd/statefuldestructible.h>
|
#include <pbd/statefuldestructible.h>
|
||||||
|
|
||||||
#include <ardour/ardour.h>
|
#include <ardour/ardour.h>
|
||||||
|
#include <ardour/param_id.h>
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
class Curve;
|
||||||
|
|
||||||
struct ControlEvent {
|
struct ControlEvent {
|
||||||
double when;
|
|
||||||
double value;
|
|
||||||
|
|
||||||
ControlEvent (double w, double v)
|
ControlEvent (double w, double v)
|
||||||
: when (w), value (v) { }
|
: when (w), value (v) {
|
||||||
|
coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
ControlEvent (const ControlEvent& other)
|
ControlEvent (const ControlEvent& other)
|
||||||
: when (other.when), value (other.value) {}
|
: when (other.when), value (other.value) {
|
||||||
|
coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
|
||||||
virtual ~ControlEvent() {}
|
}
|
||||||
|
|
||||||
// bool operator==(const ControlEvent& other) {
|
|
||||||
// return value == other.value && when == other.when;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
double when;
|
||||||
|
double value;
|
||||||
|
double coeff[4]; ///< Used by Curve
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class AutomationList : public PBD::StatefulDestructible
|
class AutomationList : public PBD::StatefulDestructible
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::list<ControlEvent*> AutomationEventList;
|
typedef std::list<ControlEvent*> EventList;
|
||||||
typedef AutomationEventList::iterator iterator;
|
typedef EventList::iterator iterator;
|
||||||
typedef AutomationEventList::const_iterator const_iterator;
|
typedef EventList::const_iterator const_iterator;
|
||||||
|
|
||||||
AutomationList (double default_value);
|
AutomationList (ParamID id, double min_val, double max_val, double default_val);
|
||||||
AutomationList (const XMLNode&);
|
AutomationList (const XMLNode&, ParamID id);
|
||||||
~AutomationList();
|
~AutomationList();
|
||||||
|
|
||||||
AutomationList (const AutomationList&);
|
AutomationList (const AutomationList&);
|
||||||
|
|
@ -68,14 +72,17 @@ class AutomationList : public PBD::StatefulDestructible
|
||||||
AutomationList& operator= (const AutomationList&);
|
AutomationList& operator= (const AutomationList&);
|
||||||
bool operator== (const AutomationList&);
|
bool operator== (const AutomationList&);
|
||||||
|
|
||||||
|
ParamID param_id() const { return _param_id; }
|
||||||
|
void set_param_id(ParamID id) { _param_id = id; }
|
||||||
|
|
||||||
void freeze();
|
void freeze();
|
||||||
void thaw ();
|
void thaw ();
|
||||||
|
|
||||||
AutomationEventList::size_type size() const { return events.size(); }
|
EventList::size_type size() const { return _events.size(); }
|
||||||
bool empty() const { return events.empty(); }
|
bool empty() const { return _events.empty(); }
|
||||||
|
|
||||||
void reset_default (double val) {
|
void reset_default (double val) {
|
||||||
default_value = val;
|
_default_value = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear ();
|
void clear ();
|
||||||
|
|
@ -126,29 +133,29 @@ class AutomationList : public PBD::StatefulDestructible
|
||||||
bool touching() const { return _touching; }
|
bool touching() const { return _touching; }
|
||||||
|
|
||||||
void set_yrange (double min, double max) {
|
void set_yrange (double min, double max) {
|
||||||
min_yval = min;
|
_min_yval = min;
|
||||||
max_yval = max;
|
_max_yval = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
double get_max_y() const { return max_yval; }
|
double get_max_y() const { return _max_yval; }
|
||||||
double get_min_y() const { return min_yval; }
|
double get_min_y() const { return _min_yval; }
|
||||||
|
|
||||||
void truncate_end (double length);
|
void truncate_end (double length);
|
||||||
void truncate_start (double length);
|
void truncate_start (double length);
|
||||||
|
|
||||||
iterator begin() { return events.begin(); }
|
iterator begin() { return _events.begin(); }
|
||||||
iterator end() { return events.end(); }
|
iterator end() { return _events.end(); }
|
||||||
|
|
||||||
ControlEvent* back() { return events.back(); }
|
ControlEvent* back() { return _events.back(); }
|
||||||
ControlEvent* front() { return events.front(); }
|
ControlEvent* front() { return _events.front(); }
|
||||||
|
|
||||||
const_iterator const_begin() const { return events.begin(); }
|
const_iterator const_begin() const { return _events.begin(); }
|
||||||
const_iterator const_end() const { return events.end(); }
|
const_iterator const_end() const { return _events.end(); }
|
||||||
|
|
||||||
std::pair<AutomationList::iterator,AutomationList::iterator> control_points_adjacent (double when);
|
std::pair<AutomationList::iterator,AutomationList::iterator> control_points_adjacent (double when);
|
||||||
|
|
||||||
template<class T> void apply_to_points (T& obj, void (T::*method)(const AutomationList&)) {
|
template<class T> void apply_to_points (T& obj, void (T::*method)(const AutomationList&)) {
|
||||||
Glib::Mutex::Lock lm (lock);
|
Glib::Mutex::Lock lm (_lock);
|
||||||
(obj.*method)(*this);
|
(obj.*method)(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,16 +167,16 @@ class AutomationList : public PBD::StatefulDestructible
|
||||||
XMLNode& serialize_events ();
|
XMLNode& serialize_events ();
|
||||||
|
|
||||||
void set_max_xval (double);
|
void set_max_xval (double);
|
||||||
double get_max_xval() const { return max_xval; }
|
double get_max_xval() const { return _max_xval; }
|
||||||
|
|
||||||
double eval (double where) {
|
double eval (double where) {
|
||||||
Glib::Mutex::Lock lm (lock);
|
Glib::Mutex::Lock lm (_lock);
|
||||||
return unlocked_eval (where);
|
return unlocked_eval (where);
|
||||||
}
|
}
|
||||||
|
|
||||||
double rt_safe_eval (double where, bool& ok) {
|
double rt_safe_eval (double where, bool& ok) {
|
||||||
|
|
||||||
Glib::Mutex::Lock lm (lock, Glib::TRY_LOCK);
|
Glib::Mutex::Lock lm (_lock, Glib::TRY_LOCK);
|
||||||
|
|
||||||
if ((ok = lm.locked())) {
|
if ((ok = lm.locked())) {
|
||||||
return unlocked_eval (where);
|
return unlocked_eval (where);
|
||||||
|
|
@ -184,64 +191,65 @@ class AutomationList : public PBD::StatefulDestructible
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LookupCache {
|
||||||
|
double left; /* leftmost x coordinate used when finding "range" */
|
||||||
|
std::pair<AutomationList::const_iterator,AutomationList::const_iterator> range;
|
||||||
|
};
|
||||||
|
|
||||||
static sigc::signal<void, AutomationList*> AutomationListCreated;
|
static sigc::signal<void, AutomationList*> AutomationListCreated;
|
||||||
|
|
||||||
|
const EventList& events() const { return _events; }
|
||||||
|
double default_value() const { return _default_value; }
|
||||||
|
|
||||||
|
// teeny const violations for Curve
|
||||||
|
mutable sigc::signal<void> Dirty;
|
||||||
|
Glib::Mutex& lock() const { return _lock; }
|
||||||
|
LookupCache& lookup_cache() const { return _lookup_cache; }
|
||||||
|
|
||||||
|
/** Called by locked entry point and various private
|
||||||
|
* locations where we already hold the lock.
|
||||||
|
*
|
||||||
|
* FIXME: Should this be private? Curve needs it..
|
||||||
|
*/
|
||||||
|
double unlocked_eval (double x) const;
|
||||||
|
|
||||||
|
Curve& curve() { return *_curve; }
|
||||||
|
const Curve& curve() const { return *_curve; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
AutomationEventList events;
|
/** Called by unlocked_eval() to handle cases of 3 or more control points.
|
||||||
mutable Glib::Mutex lock;
|
*/
|
||||||
int8_t _frozen;
|
virtual double multipoint_eval (double x) const;
|
||||||
bool changed_when_thawed;
|
|
||||||
bool _dirty;
|
|
||||||
|
|
||||||
struct LookupCache {
|
AutomationList* cut_copy_clear (double, double, int op);
|
||||||
double left; /* leftmost x coordinate used when finding "range" */
|
|
||||||
std::pair<AutomationList::iterator,AutomationList::iterator> range;
|
|
||||||
};
|
|
||||||
|
|
||||||
mutable LookupCache lookup_cache;
|
int deserialize_events (const XMLNode&);
|
||||||
|
|
||||||
AutoState _state;
|
|
||||||
AutoStyle _style;
|
|
||||||
bool _touching;
|
|
||||||
bool _new_touch;
|
|
||||||
double max_xval;
|
|
||||||
double min_yval;
|
|
||||||
double max_yval;
|
|
||||||
double default_value;
|
|
||||||
bool sort_pending;
|
|
||||||
|
|
||||||
iterator rt_insertion_point;
|
|
||||||
double rt_pos;
|
|
||||||
|
|
||||||
void maybe_signal_changed ();
|
void maybe_signal_changed ();
|
||||||
void mark_dirty ();
|
void mark_dirty ();
|
||||||
void _x_scale (double factor);
|
void _x_scale (double factor);
|
||||||
|
|
||||||
/* called by type-specific unlocked_eval() to handle
|
mutable LookupCache _lookup_cache;
|
||||||
common case of 0, 1 or 2 control points.
|
|
||||||
*/
|
|
||||||
|
|
||||||
double shared_eval (double x);
|
ParamID _param_id;
|
||||||
|
EventList _events;
|
||||||
|
mutable Glib::Mutex _lock;
|
||||||
|
int8_t _frozen;
|
||||||
|
bool _changed_when_thawed;
|
||||||
|
AutoState _state;
|
||||||
|
AutoStyle _style;
|
||||||
|
bool _touching;
|
||||||
|
bool _new_touch;
|
||||||
|
double _max_xval;
|
||||||
|
double _min_yval;
|
||||||
|
double _max_yval;
|
||||||
|
double _default_value;
|
||||||
|
bool _sort_pending;
|
||||||
|
iterator _rt_insertion_point;
|
||||||
|
double _rt_pos;
|
||||||
|
|
||||||
/* called by shared_eval() to handle any case of
|
Curve* _curve;
|
||||||
3 or more control points.
|
|
||||||
*/
|
|
||||||
|
|
||||||
virtual double multipoint_eval (double x);
|
|
||||||
|
|
||||||
/* called by locked entry point and various private
|
|
||||||
locations where we already hold the lock.
|
|
||||||
*/
|
|
||||||
|
|
||||||
virtual double unlocked_eval (double where);
|
|
||||||
|
|
||||||
virtual ControlEvent* point_factory (double,double) const;
|
|
||||||
virtual ControlEvent* point_factory (const ControlEvent&) const;
|
|
||||||
|
|
||||||
AutomationList* cut_copy_clear (double, double, int op);
|
|
||||||
|
|
||||||
int deserialize_events (const XMLNode&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -124,8 +124,8 @@ class Crossfade : public ARDOUR::AudioRegion
|
||||||
bool can_follow_overlap() const;
|
bool can_follow_overlap() const;
|
||||||
void set_follow_overlap (bool yn);
|
void set_follow_overlap (bool yn);
|
||||||
|
|
||||||
Curve& fade_in() { return _fade_in; }
|
AutomationList& fade_in() { return _fade_in; }
|
||||||
Curve& fade_out() { return _fade_out; }
|
AutomationList& fade_out() { return _fade_out; }
|
||||||
|
|
||||||
nframes_t set_length (nframes_t);
|
nframes_t set_length (nframes_t);
|
||||||
|
|
||||||
|
|
@ -157,8 +157,8 @@ class Crossfade : public ARDOUR::AudioRegion
|
||||||
int32_t layer_relation;
|
int32_t layer_relation;
|
||||||
|
|
||||||
|
|
||||||
mutable Curve _fade_in;
|
mutable AutomationList _fade_in;
|
||||||
mutable Curve _fade_out;
|
mutable AutomationList _fade_out;
|
||||||
|
|
||||||
static Sample* crossfade_buffer_out;
|
static Sample* crossfade_buffer_out;
|
||||||
static Sample* crossfade_buffer_in;
|
static Sample* crossfade_buffer_in;
|
||||||
|
|
|
||||||
|
|
@ -30,50 +30,30 @@
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
struct CurvePoint : public ControlEvent
|
class Curve
|
||||||
{
|
|
||||||
double coeff[4];
|
|
||||||
|
|
||||||
CurvePoint (double w, double v)
|
|
||||||
: ControlEvent (w, v) {
|
|
||||||
|
|
||||||
coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
~CurvePoint() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Curve : public AutomationList
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Curve (double min_yval, double max_yval, double defaultvalue, bool nostate = false);
|
Curve (const AutomationList& al);
|
||||||
~Curve ();
|
~Curve ();
|
||||||
Curve (const Curve& other);
|
Curve (const Curve& other);
|
||||||
Curve (const Curve& other, double start, double end);
|
//Curve (const Curve& other, double start, double end);
|
||||||
Curve (const XMLNode&);
|
/*Curve (const XMLNode&, ParamID id);*/
|
||||||
|
|
||||||
bool rt_safe_get_vector (double x0, double x1, float *arg, int32_t veclen);
|
bool rt_safe_get_vector (double x0, double x1, float *arg, int32_t veclen);
|
||||||
void get_vector (double x0, double x1, float *arg, int32_t veclen);
|
void get_vector (double x0, double x1, float *arg, int32_t veclen);
|
||||||
|
|
||||||
AutomationEventList::iterator closest_control_point_before (double xval);
|
|
||||||
AutomationEventList::iterator closest_control_point_after (double xval);
|
|
||||||
|
|
||||||
void solve ();
|
void solve ();
|
||||||
|
|
||||||
static sigc::signal<void, Curve*> CurveCreated;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
ControlEvent* point_factory (double,double) const;
|
|
||||||
ControlEvent* point_factory (const ControlEvent&) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AutomationList::iterator last_bound;
|
|
||||||
|
|
||||||
double unlocked_eval (double where);
|
double unlocked_eval (double where);
|
||||||
double multipoint_eval (double x);
|
double multipoint_eval (double x);
|
||||||
|
|
||||||
void _get_vector (double x0, double x1, float *arg, int32_t veclen);
|
void _get_vector (double x0, double x1, float *arg, int32_t veclen);
|
||||||
|
|
||||||
|
const AutomationList& _list;
|
||||||
|
|
||||||
|
void on_list_dirty() { _dirty = true; }
|
||||||
|
bool _dirty;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ARDOUR
|
} // namespace ARDOUR
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
struct Gain : public Curve {
|
struct Gain : public AutomationList {
|
||||||
|
|
||||||
Gain();
|
Gain();
|
||||||
Gain (const Gain&);
|
Gain (const Gain&);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
#include <pbd/controllable.h>
|
#include <pbd/controllable.h>
|
||||||
|
|
||||||
#include <ardour/ardour.h>
|
#include <ardour/ardour.h>
|
||||||
#include <ardour/session_object.h>
|
#include <ardour/automatable.h>
|
||||||
#include <ardour/utils.h>
|
#include <ardour/utils.h>
|
||||||
#include <ardour/curve.h>
|
#include <ardour/curve.h>
|
||||||
#include <ardour/types.h>
|
#include <ardour/types.h>
|
||||||
|
|
@ -64,9 +64,8 @@ class BufferSet;
|
||||||
* 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
|
||||||
* varied combinations of types (eg MIDI and audio) possible.
|
* varied combinations of types (eg MIDI and audio) possible.
|
||||||
*/
|
*/
|
||||||
class IO : public SessionObject
|
class IO : public Automatable
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const string state_node_name;
|
static const string state_node_name;
|
||||||
|
|
||||||
|
|
@ -228,21 +227,14 @@ class IO : public SessionObject
|
||||||
|
|
||||||
void clear_automation ();
|
void clear_automation ();
|
||||||
|
|
||||||
virtual void set_gain_automation_state (AutoState);
|
void set_parameter_automation_state (ParamID, AutoState);
|
||||||
AutoState gain_automation_state() const { return _gain_automation_curve.automation_state(); }
|
|
||||||
//sigc::signal<void> gain_automation_state_changed;
|
|
||||||
|
|
||||||
virtual void set_gain_automation_style (AutoStyle);
|
|
||||||
AutoStyle gain_automation_style () const { return _gain_automation_curve.automation_style(); }
|
|
||||||
//sigc::signal<void> gain_automation_style_changed;
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
ARDOUR::Curve& gain_automation_curve () { return _gain_automation_curve; }
|
// FIXME: these will probably become unsafe in the near future
|
||||||
|
ARDOUR::AutomationList& gain_automation() { return *automation_list(GainAutomation); }
|
||||||
void start_gain_touch ();
|
const ARDOUR::AutomationList& gain_automation() const { return *automation_list(GainAutomation); }
|
||||||
void end_gain_touch ();
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
@ -299,16 +291,12 @@ class IO : public SessionObject
|
||||||
nframes_t last_automation_snapshot;
|
nframes_t last_automation_snapshot;
|
||||||
static nframes_t _automation_interval;
|
static nframes_t _automation_interval;
|
||||||
|
|
||||||
AutoState _gain_automation_state;
|
/*AutoState _gain_automation_state;
|
||||||
AutoStyle _gain_automation_style;
|
AutoStyle _gain_automation_style;*/
|
||||||
|
|
||||||
bool apply_gain_automation;
|
bool apply_gain_automation;
|
||||||
Curve _gain_automation_curve;
|
//Curve _gain_automation_curve;
|
||||||
|
|
||||||
Glib::Mutex automation_lock;
|
|
||||||
|
|
||||||
virtual int set_automation_state (const XMLNode&);
|
|
||||||
virtual XMLNode& get_automation_state ();
|
|
||||||
virtual int load_automation (std::string path);
|
virtual int load_automation (std::string path);
|
||||||
|
|
||||||
/* AudioTrack::deprecated_use_diskstream_connections() needs these */
|
/* AudioTrack::deprecated_use_diskstream_connections() needs these */
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ class LadspaPlugin : public ARDOUR::Plugin
|
||||||
void set_parameter (uint32_t port, float val);
|
void set_parameter (uint32_t port, float val);
|
||||||
float get_parameter (uint32_t port) const;
|
float get_parameter (uint32_t port) const;
|
||||||
int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const;
|
int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const;
|
||||||
std::set<uint32_t> automatable() const;
|
std::set<ParamID> automatable() const;
|
||||||
uint32_t nth_parameter (uint32_t port, bool& ok) const;
|
uint32_t nth_parameter (uint32_t port, bool& ok) const;
|
||||||
void activate () {
|
void activate () {
|
||||||
if (descriptor->activate) {
|
if (descriptor->activate) {
|
||||||
|
|
@ -85,7 +85,7 @@ class LadspaPlugin : public ARDOUR::Plugin
|
||||||
int connect_and_run (BufferSet& bufs, uint32_t& in, uint32_t& out, nframes_t nframes, nframes_t offset);
|
int connect_and_run (BufferSet& bufs, uint32_t& in, uint32_t& out, nframes_t nframes, nframes_t offset);
|
||||||
void store_state (ARDOUR::PluginState&);
|
void store_state (ARDOUR::PluginState&);
|
||||||
void restore_state (ARDOUR::PluginState&);
|
void restore_state (ARDOUR::PluginState&);
|
||||||
string describe_parameter (uint32_t);
|
string describe_parameter (ParamID);
|
||||||
string state_node_name() const { return "ladspa"; }
|
string state_node_name() const { return "ladspa"; }
|
||||||
void print_parameter (uint32_t, char*, uint32_t len) const;
|
void print_parameter (uint32_t, char*, uint32_t len) const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,8 +81,9 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful
|
||||||
/* 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 */
|
||||||
|
|
||||||
virtual Curve& automation() = 0;
|
virtual 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 */
|
||||||
|
|
@ -149,7 +150,8 @@ class BaseStereoPanner : public StreamPanner
|
||||||
void set_automation_state (AutoState);
|
void set_automation_state (AutoState);
|
||||||
void set_automation_style (AutoStyle);
|
void set_automation_style (AutoStyle);
|
||||||
|
|
||||||
Curve& automation() { return _automation; }
|
/* TODO: StreamPanner is-a Automatable? */
|
||||||
|
AutomationList& automation() { return _automation; }
|
||||||
|
|
||||||
/* old school automation loading */
|
/* old school automation loading */
|
||||||
|
|
||||||
|
|
@ -163,7 +165,7 @@ class BaseStereoPanner : public StreamPanner
|
||||||
float left_interp;
|
float left_interp;
|
||||||
float right_interp;
|
float right_interp;
|
||||||
|
|
||||||
Curve _automation;
|
AutomationList _automation;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EqualPowerStereoPanner : public BaseStereoPanner
|
class EqualPowerStereoPanner : public BaseStereoPanner
|
||||||
|
|
@ -204,7 +206,9 @@ class Multi2dPanner : public StreamPanner
|
||||||
must surely be more than 1 automation curve.
|
must surely be more than 1 automation curve.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Curve& automation() { return _automation; }
|
/* TODO: StreamPanner is-a Automatable? */
|
||||||
|
|
||||||
|
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,
|
||||||
|
|
@ -222,7 +226,7 @@ class Multi2dPanner : public StreamPanner
|
||||||
int load (istream&, string path, uint32_t&);
|
int load (istream&, string path, uint32_t&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Curve _automation;
|
AutomationList _automation;
|
||||||
void update ();
|
void update ();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
137
libs/ardour/ardour/param_id.h
Normal file
137
libs/ardour/ardour/param_id.h
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2007 Paul Davis
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by 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_param_id_h__
|
||||||
|
#define __ardour_param_id_h__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <pbd/compose.h>
|
||||||
|
#include <pbd/error.h>
|
||||||
|
#include <ardour/types.h>
|
||||||
|
|
||||||
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
|
||||||
|
/** ID of an automatable parameter.
|
||||||
|
*
|
||||||
|
* A given automatable object has a number of automatable parameters. This is
|
||||||
|
* the unique ID for those parameters. Anything automatable (AutomationList,
|
||||||
|
* Curve) must have an ID unique with respect to it's Automatable parent.
|
||||||
|
*
|
||||||
|
* A parameter ID has two parts, a type and an int (only used by some types).
|
||||||
|
*
|
||||||
|
* This is a bit more ugly than it could be, due to using the existing/legacy
|
||||||
|
* ARDOUR::AutomationType: GainAutomation, PanAutomation, SoloAutomation,
|
||||||
|
* and MuteAutomation use only the type(), but PluginAutomation and
|
||||||
|
* MidiCCAutomation use the id() as port number and CC number, respectively.
|
||||||
|
*
|
||||||
|
* Future types may use a string or URI or whatever, as long as these are
|
||||||
|
* comparable anything may be added. ints are best as these should be fast to
|
||||||
|
* copy and compare with one another.
|
||||||
|
*/
|
||||||
|
class ParamID
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline ParamID(AutomationType type = NullAutomation, uint32_t id=0) : _type(type), _id(id) {}
|
||||||
|
|
||||||
|
/** Construct an ParamID from a string returned from ParamID::to_string
|
||||||
|
* (AutomationList automation-id property)
|
||||||
|
*/
|
||||||
|
ParamID(const std::string& str) : _type(NullAutomation), _id(0) {
|
||||||
|
if (str == "gain") {
|
||||||
|
_type = GainAutomation;
|
||||||
|
} else if (str == "pan") {
|
||||||
|
_type = PanAutomation;
|
||||||
|
} else if (str == "solo") {
|
||||||
|
_type = SoloAutomation;
|
||||||
|
} else if (str == "mute") {
|
||||||
|
_type = MuteAutomation;
|
||||||
|
} else if (str == "fadein") {
|
||||||
|
_type = FadeInAutomation;
|
||||||
|
} else if (str == "fadeout") {
|
||||||
|
_type = FadeOutAutomation;
|
||||||
|
} else if (str == "envelope") {
|
||||||
|
_type = EnvelopeAutomation;
|
||||||
|
} else if (str.length() > 10 && str.substr(0, 10) == "parameter-") {
|
||||||
|
_type = PluginAutomation;
|
||||||
|
_id = atoi(str.c_str()+10);
|
||||||
|
PBD::info << "Parameter: " << str << " -> " << _id << endl;
|
||||||
|
} else if (str.length() > 7 && str.substr(0, 7) == "midicc-") {
|
||||||
|
_type = MidiCCAutomation;
|
||||||
|
_id = atoi(str.c_str()+7);
|
||||||
|
PBD::info << "MIDI CC: " << str << " -> " << _id << endl;
|
||||||
|
} else {
|
||||||
|
PBD::warning << "Unknown ParamID '" << str << "'" << endmsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline AutomationType type() const { return _type; }
|
||||||
|
inline uint32_t id() const { return _id; }
|
||||||
|
|
||||||
|
inline bool operator==(const ParamID& id) const
|
||||||
|
{ return (_type == id._type && _id == id._id); }
|
||||||
|
|
||||||
|
/** Arbitrary but fixed ordering, so we're comparable (usable in std::map) */
|
||||||
|
inline bool operator<(const ParamID& id) const {
|
||||||
|
// FIXME: branch a performance problem? #ifdef DEBUG?
|
||||||
|
if (_type == NullAutomation)
|
||||||
|
PBD::warning << "Uninitialized ParamID compared." << endmsg;
|
||||||
|
return (_type < id._type || _id < id._id);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline operator bool() const { return (_type != 0); }
|
||||||
|
|
||||||
|
/** Unique string representation, suitable as an XML property value.
|
||||||
|
* e.g. <AutomationList automation-id="whatthisreturns">
|
||||||
|
*/
|
||||||
|
inline std::string to_string() const {
|
||||||
|
if (_type == GainAutomation) {
|
||||||
|
return "gain";
|
||||||
|
} else if (_type == PanAutomation) {
|
||||||
|
return "pan";
|
||||||
|
} else if (_type == SoloAutomation) {
|
||||||
|
return "solo";
|
||||||
|
} else if (_type == MuteAutomation) {
|
||||||
|
return "mute";
|
||||||
|
} else if (_type == FadeInAutomation) {
|
||||||
|
return "fadein";
|
||||||
|
} else if (_type == FadeOutAutomation) {
|
||||||
|
return "fadeout";
|
||||||
|
} else if (_type == EnvelopeAutomation) {
|
||||||
|
return "envelope";
|
||||||
|
} else if (_type == PluginAutomation) {
|
||||||
|
return string_compose("parameter-%1", _id);
|
||||||
|
} else if (_type == MidiCCAutomation) {
|
||||||
|
return string_compose("midicc-%1", _id);
|
||||||
|
} else {
|
||||||
|
PBD::warning << "Uninitialized ParamID to_string() called." << endmsg;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// default copy constructor is ok
|
||||||
|
AutomationType _type;
|
||||||
|
uint32_t _id;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ARDOUR
|
||||||
|
|
||||||
|
#endif // __ardour_param_id_h__
|
||||||
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include <ardour/chan_count.h>
|
#include <ardour/chan_count.h>
|
||||||
#include <ardour/plugin_state.h>
|
#include <ardour/plugin_state.h>
|
||||||
#include <ardour/cycles.h>
|
#include <ardour/cycles.h>
|
||||||
|
#include <ardour/param_id.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
@ -121,10 +122,10 @@ class Plugin : public PBD::StatefulDestructible
|
||||||
|
|
||||||
virtual int connect_and_run (BufferSet& bufs, uint32_t& in, uint32_t& out, nframes_t nframes, nframes_t offset) = 0;
|
virtual int connect_and_run (BufferSet& bufs, uint32_t& in, uint32_t& out, nframes_t nframes, nframes_t offset) = 0;
|
||||||
|
|
||||||
virtual std::set<uint32_t> automatable() const = 0;
|
virtual std::set<ParamID> automatable() const = 0;
|
||||||
virtual void store_state (ARDOUR::PluginState&) = 0;
|
virtual void store_state (ARDOUR::PluginState&) = 0;
|
||||||
virtual void restore_state (ARDOUR::PluginState&) = 0;
|
virtual void restore_state (ARDOUR::PluginState&) = 0;
|
||||||
virtual string describe_parameter (uint32_t) = 0;
|
virtual string describe_parameter (ParamID) = 0;
|
||||||
virtual string state_node_name() const = 0;
|
virtual string state_node_name() const = 0;
|
||||||
virtual void print_parameter (uint32_t, char*, uint32_t len) const = 0;
|
virtual void print_parameter (uint32_t, char*, uint32_t len) const = 0;
|
||||||
|
|
||||||
|
|
@ -139,7 +140,7 @@ class Plugin : public PBD::StatefulDestructible
|
||||||
|
|
||||||
virtual bool has_editor() const = 0;
|
virtual bool has_editor() const = 0;
|
||||||
|
|
||||||
sigc::signal<void,uint32_t,float> ParameterChanged;
|
sigc::signal<void,ParamID,float> ParameterChanged;
|
||||||
|
|
||||||
PBD::Controllable *get_nth_control (uint32_t);
|
PBD::Controllable *get_nth_control (uint32_t);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,13 +76,9 @@ class PluginInsert : public Insert
|
||||||
|
|
||||||
bool is_generator() const;
|
bool is_generator() const;
|
||||||
|
|
||||||
void set_parameter (uint32_t port, float val);
|
void set_parameter (ParamID param, float val);
|
||||||
|
|
||||||
AutoState get_port_automation_state (uint32_t port);
|
float default_parameter_value (ParamID param);
|
||||||
void set_port_automation_state (uint32_t port, AutoState);
|
|
||||||
void protect_automation ();
|
|
||||||
|
|
||||||
float default_parameter_value (uint32_t which);
|
|
||||||
|
|
||||||
boost::shared_ptr<Plugin> plugin(uint32_t num=0) const {
|
boost::shared_ptr<Plugin> plugin(uint32_t num=0) const {
|
||||||
if (num < _plugins.size()) {
|
if (num < _plugins.size()) {
|
||||||
|
|
@ -94,7 +90,7 @@ class PluginInsert : public Insert
|
||||||
|
|
||||||
PluginType type ();
|
PluginType type ();
|
||||||
|
|
||||||
string describe_parameter (uint32_t);
|
string describe_parameter (ParamID param);
|
||||||
|
|
||||||
nframes_t latency();
|
nframes_t latency();
|
||||||
|
|
||||||
|
|
@ -103,7 +99,7 @@ class PluginInsert : public Insert
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void parameter_changed (uint32_t, float);
|
void parameter_changed (ParamID, float);
|
||||||
|
|
||||||
std::vector<boost::shared_ptr<Plugin> > _plugins;
|
std::vector<boost::shared_ptr<Plugin> > _plugins;
|
||||||
|
|
||||||
|
|
@ -112,8 +108,8 @@ class PluginInsert : public Insert
|
||||||
|
|
||||||
void init ();
|
void init ();
|
||||||
void set_automatable ();
|
void set_automatable ();
|
||||||
void auto_state_changed (uint32_t which);
|
void auto_state_changed (ParamID which);
|
||||||
void automation_list_creation_callback (uint32_t, AutomationList&);
|
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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,12 +93,20 @@ namespace ARDOUR {
|
||||||
OverlapType coverage (nframes_t start_a, nframes_t end_a,
|
OverlapType coverage (nframes_t start_a, nframes_t end_a,
|
||||||
nframes_t start_b, nframes_t end_b);
|
nframes_t start_b, nframes_t end_b);
|
||||||
|
|
||||||
|
/** See param_id.h
|
||||||
|
* XXX: I don't think/hope these hex values matter anymore.
|
||||||
|
*/
|
||||||
enum AutomationType {
|
enum AutomationType {
|
||||||
|
NullAutomation = 0x0,
|
||||||
GainAutomation = 0x1,
|
GainAutomation = 0x1,
|
||||||
PanAutomation = 0x2,
|
PanAutomation = 0x2,
|
||||||
PluginAutomation = 0x4,
|
PluginAutomation = 0x4,
|
||||||
SoloAutomation = 0x8,
|
SoloAutomation = 0x8,
|
||||||
MuteAutomation = 0x10
|
MuteAutomation = 0x10,
|
||||||
|
MidiCCAutomation = 0x20,
|
||||||
|
FadeInAutomation = 0x40,
|
||||||
|
FadeOutAutomation = 0x80,
|
||||||
|
EnvelopeAutomation = 0x100
|
||||||
};
|
};
|
||||||
|
|
||||||
enum AutoState {
|
enum AutoState {
|
||||||
|
|
|
||||||
|
|
@ -599,10 +599,10 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
|
||||||
/* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
|
/* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
|
||||||
|
|
||||||
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_curve.automation_playback()) {
|
if (am.locked() && gain_automation().automation_playback()) {
|
||||||
apply_gain_automation = _gain_automation_curve.rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
|
apply_gain_automation = gain_automation().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 (_gain_automation_curve.automation_state() == Play) {
|
if (IO::gain_automation().automation_state() == Play) {
|
||||||
|
|
||||||
_gain_automation_curve.get_vector (start, start + nframes, gain_automation, nframes);
|
IO::gain_automation().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();
|
||||||
|
|
|
||||||
|
|
@ -73,9 +73,9 @@ 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 (0.0, 2.0, 1.0, false),
|
_fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0),
|
||||||
_fade_out (0.0, 2.0, 1.0, false),
|
_fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0),
|
||||||
_envelope (0.0, 2.0, 1.0, false)
|
_envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
}
|
}
|
||||||
|
|
@ -83,9 +83,9 @@ AudioRegion::AudioRegion (nframes_t start, nframes_t length, string name)
|
||||||
/** 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 (0.0, 2.0, 1.0, false),
|
_fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0),
|
||||||
_fade_out (0.0, 2.0, 1.0, false),
|
_fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0),
|
||||||
_envelope (0.0, 2.0, 1.0, false)
|
_envelope (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 (0.0, 2.0, 1.0, false)
|
, _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0)
|
||||||
, _fade_out (0.0, 2.0, 1.0, false)
|
, _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)
|
||||||
, _envelope (0.0, 2.0, 1.0, false)
|
, _envelope (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 (0.0, 2.0, 1.0, false)
|
, _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0)
|
||||||
, _fade_out (0.0, 2.0, 1.0, false)
|
, _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)
|
||||||
, _envelope (0.0, 2.0, 1.0, false)
|
, _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
}
|
}
|
||||||
|
|
@ -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 (0.0, 2.0, 1.0, false)
|
, _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0)
|
||||||
, _fade_out (0.0, 2.0, 1.0, false)
|
, _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)
|
||||||
, _envelope (0.0, 2.0, 1.0, false)
|
, _envelope (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) {
|
||||||
|
|
@ -200,10 +200,10 @@ 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 (0.0, 2.0, 1.0, false),
|
, _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0)
|
||||||
_fade_out (0.0, 2.0, 1.0, false),
|
, _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)
|
||||||
_envelope (0.0, 2.0, 1.0, false)
|
, _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
|
||||||
{
|
{
|
||||||
set_default_fades ();
|
set_default_fades ();
|
||||||
_scale_amplitude = 1.0;
|
_scale_amplitude = 1.0;
|
||||||
|
|
@ -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.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];
|
||||||
|
|
@ -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.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.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) {
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ Automatable::old_set_automation_state (const XMLNode& node)
|
||||||
if (sstr.fail()) {
|
if (sstr.fail()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mark_automation_visible (what, true);
|
mark_automation_visible (ParamID(PluginAutomation, what), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,7 +88,7 @@ Automatable::load_automation (const string& path)
|
||||||
}
|
}
|
||||||
|
|
||||||
Glib::Mutex::Lock lm (_automation_lock);
|
Glib::Mutex::Lock lm (_automation_lock);
|
||||||
set<uint32_t> tosave;
|
set<ParamID> tosave;
|
||||||
_parameter_automation.clear ();
|
_parameter_automation.clear ();
|
||||||
|
|
||||||
while (in) {
|
while (in) {
|
||||||
|
|
@ -100,9 +100,10 @@ Automatable::load_automation (const string& path)
|
||||||
in >> when; if (!in) goto bad;
|
in >> when; if (!in) goto bad;
|
||||||
in >> value; if (!in) goto bad;
|
in >> value; if (!in) goto bad;
|
||||||
|
|
||||||
AutomationList& al = automation_list (port);
|
/* FIXME: this is legacy and only used for plugin inserts? I think? */
|
||||||
al.add (when, value);
|
AutomationList* al = automation_list (ParamID(PluginAutomation, port), true);
|
||||||
tosave.insert (port);
|
al->add (when, value);
|
||||||
|
tosave.insert (ParamID(PluginAutomation, port));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -113,12 +114,27 @@ Automatable::load_automation (const string& path)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Automatable::add_automation_parameter(AutomationList* al)
|
||||||
|
{
|
||||||
|
_parameter_automation[al->param_id()] = al;
|
||||||
|
|
||||||
|
/* let derived classes do whatever they need with this */
|
||||||
|
automation_list_creation_callback (al->param_id(), *al);
|
||||||
|
|
||||||
|
cerr << _name << ": added (visible, can_automate) parameter " << al->param_id().to_string() << ", # params = "
|
||||||
|
<< _parameter_automation.size() << endl;
|
||||||
|
|
||||||
|
// FIXME: sane default behaviour?
|
||||||
|
_visible_parameter_automation.insert(al->param_id());
|
||||||
|
_can_automate_list.insert(al->param_id());
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Automatable::what_has_automation (set<uint32_t>& s) const
|
Automatable::what_has_automation (set<ParamID>& s) const
|
||||||
{
|
{
|
||||||
Glib::Mutex::Lock lm (_automation_lock);
|
Glib::Mutex::Lock lm (_automation_lock);
|
||||||
map<uint32_t,AutomationList*>::const_iterator li;
|
map<ParamID,AutomationList*>::const_iterator li;
|
||||||
|
|
||||||
for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
|
for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
|
||||||
s.insert ((*li).first);
|
s.insert ((*li).first);
|
||||||
|
|
@ -126,49 +142,79 @@ Automatable::what_has_automation (set<uint32_t>& s) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Automatable::what_has_visible_automation (set<uint32_t>& s) const
|
Automatable::what_has_visible_automation (set<ParamID>& s) const
|
||||||
{
|
{
|
||||||
Glib::Mutex::Lock lm (_automation_lock);
|
Glib::Mutex::Lock lm (_automation_lock);
|
||||||
set<uint32_t>::const_iterator li;
|
set<ParamID>::const_iterator li;
|
||||||
|
|
||||||
for (li = _visible_parameter_automation.begin(); li != _visible_parameter_automation.end(); ++li) {
|
for (li = _visible_parameter_automation.begin(); li != _visible_parameter_automation.end(); ++li) {
|
||||||
s.insert (*li);
|
s.insert (*li);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AutomationList&
|
|
||||||
Automatable::automation_list (uint32_t parameter)
|
/** Returns NULL if we don't have an AutomationList for \a parameter.
|
||||||
|
*/
|
||||||
|
AutomationList*
|
||||||
|
Automatable::automation_list (ParamID parameter, bool create_if_missing)
|
||||||
{
|
{
|
||||||
AutomationList* al = _parameter_automation[parameter];
|
std::map<ParamID,AutomationList*>::iterator i = _parameter_automation.find(parameter);
|
||||||
|
|
||||||
if (al == 0) {
|
if (i != _parameter_automation.end()) {
|
||||||
al = _parameter_automation[parameter] = new AutomationList (default_parameter_value (parameter));
|
return i->second;
|
||||||
/* let derived classes do whatever they need with this */
|
|
||||||
automation_list_creation_callback (parameter, *al);
|
} else if (create_if_missing) {
|
||||||
|
AutomationList* al = new AutomationList (parameter, FLT_MIN, FLT_MAX, default_parameter_value (parameter));
|
||||||
|
add_automation_parameter(al);
|
||||||
|
return al;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return *al;
|
const AutomationList*
|
||||||
|
Automatable::automation_list (ParamID parameter) const
|
||||||
|
{
|
||||||
|
std::map<ParamID,AutomationList*>::const_iterator i = _parameter_automation.find(parameter);
|
||||||
|
|
||||||
|
if (i != _parameter_automation.end()) {
|
||||||
|
return i->second;
|
||||||
|
} else {
|
||||||
|
warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
string
|
string
|
||||||
Automatable::describe_parameter (uint32_t which)
|
Automatable::describe_parameter (ParamID param)
|
||||||
{
|
{
|
||||||
/* derived classes will override this */
|
/* derived classes like PluginInsert should override this */
|
||||||
return "";
|
|
||||||
|
if (param == ParamID(GainAutomation))
|
||||||
|
return _("Fader");
|
||||||
|
else if (param == ParamID(PanAutomation))
|
||||||
|
return _("Pan");
|
||||||
|
else if (param.type() == MidiCCAutomation)
|
||||||
|
return string_compose("MIDI CC %1", param.id());
|
||||||
|
else
|
||||||
|
return param.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Automatable::can_automate (uint32_t what)
|
Automatable::can_automate (ParamID what)
|
||||||
{
|
{
|
||||||
_can_automate_list.insert (what);
|
_can_automate_list.insert (what);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Automatable::mark_automation_visible (uint32_t what, bool yn)
|
Automatable::mark_automation_visible (ParamID what, bool yn)
|
||||||
{
|
{
|
||||||
if (yn) {
|
if (yn) {
|
||||||
_visible_parameter_automation.insert (what);
|
_visible_parameter_automation.insert (what);
|
||||||
} else {
|
} else {
|
||||||
set<uint32_t>::iterator i;
|
set<ParamID>::iterator i;
|
||||||
|
|
||||||
if ((i = _visible_parameter_automation.find (what)) != _visible_parameter_automation.end()) {
|
if ((i = _visible_parameter_automation.find (what)) != _visible_parameter_automation.end()) {
|
||||||
_visible_parameter_automation.erase (i);
|
_visible_parameter_automation.erase (i);
|
||||||
|
|
@ -179,7 +225,7 @@ Automatable::mark_automation_visible (uint32_t 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<uint32_t,AutomationList*>::const_iterator li;
|
map<ParamID,AutomationList*>::const_iterator li;
|
||||||
AutomationList::TimeComparator cmp;
|
AutomationList::TimeComparator cmp;
|
||||||
|
|
||||||
next_event.when = max_frames;
|
next_event.when = max_frames;
|
||||||
|
|
@ -207,36 +253,50 @@ Automatable::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_e
|
||||||
return next_event.when != max_frames;
|
return next_event.when != max_frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \a legacy_param is used for loading legacy sessions where an object (IO, Panner)
|
||||||
|
* had a single automation parameter, with it's type implicit. Derived objects should
|
||||||
|
* pass that type and it will be used for the untyped AutomationList found.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
Automatable::set_automation_state (const XMLNode& node)
|
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 ();
|
_parameter_automation.clear ();
|
||||||
|
_visible_parameter_automation.clear ();
|
||||||
|
|
||||||
XMLNodeList nlist = node.children();
|
XMLNodeList nlist = node.children();
|
||||||
XMLNodeIterator niter;
|
XMLNodeIterator niter;
|
||||||
|
|
||||||
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
||||||
uint32_t param;
|
|
||||||
|
|
||||||
if (sscanf ((*niter)->name().c_str(), "parameter-%" PRIu32, ¶m) != 1) {
|
/*if (sscanf ((*niter)->name().c_str(), "parameter-%" PRIu32, ¶m) != 1) {
|
||||||
error << string_compose (_("%2: badly formatted node name in XML automation state, ignored"), _name) << endmsg;
|
error << string_compose (_("%2: badly formatted node name in XML automation state, ignored"), _name) << endmsg;
|
||||||
continue;
|
continue;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if ((*niter)->name() == "AutomationList") {
|
||||||
|
|
||||||
|
const XMLProperty* id_prop = (*niter)->property("automation-id");
|
||||||
|
|
||||||
|
ParamID param = (id_prop ? ParamID(id_prop->value()) : legacy_param);
|
||||||
|
|
||||||
|
AutomationList* al = new AutomationList(**niter, param);
|
||||||
|
|
||||||
|
if (!id_prop) {
|
||||||
|
warning << "AutomationList node without automation-id property, "
|
||||||
|
<< "using default: " << legacy_param.to_string() << endmsg;
|
||||||
|
al->set_param_id(legacy_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
AutomationList& al = automation_list (param);
|
add_automation_parameter(al);
|
||||||
if (al.set_state (*(*niter)->children().front())) {
|
|
||||||
goto bad;
|
} else {
|
||||||
|
error << "Expected AutomationList node, got '" << (*niter)->name() << endmsg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bad:
|
|
||||||
error << string_compose(_("%1: cannot load automation data from XML"), _name) << endmsg;
|
|
||||||
_parameter_automation.clear ();
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLNode&
|
XMLNode&
|
||||||
|
|
@ -244,24 +304,108 @@ 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"));
|
||||||
string fullpath;
|
|
||||||
|
cerr << "'" << _name << "'->get_automation_state, # params = " << _parameter_automation.size() << endl;
|
||||||
|
|
||||||
if (_parameter_automation.empty()) {
|
if (_parameter_automation.empty()) {
|
||||||
return *node;
|
return *node;
|
||||||
}
|
}
|
||||||
|
|
||||||
map<uint32_t,AutomationList*>::iterator li;
|
map<ParamID,AutomationList*>::iterator li;
|
||||||
|
|
||||||
for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
|
for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
|
||||||
|
node->add_child_nocopy (li->second->get_state ());
|
||||||
XMLNode* child;
|
|
||||||
|
|
||||||
char buf[64];
|
|
||||||
stringstream str;
|
|
||||||
snprintf (buf, sizeof (buf), "parameter-%" PRIu32, li->first);
|
|
||||||
child = new XMLNode (buf);
|
|
||||||
child->add_child_nocopy (li->second->get_state ());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return *node;
|
return *node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Automatable::clear_automation ()
|
||||||
|
{
|
||||||
|
Glib::Mutex::Lock lm (_automation_lock);
|
||||||
|
|
||||||
|
map<ParamID,AutomationList*>::iterator li;
|
||||||
|
|
||||||
|
for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li)
|
||||||
|
li->second->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Automatable::set_parameter_automation_state (ParamID param, AutoState s)
|
||||||
|
{
|
||||||
|
Glib::Mutex::Lock lm (_automation_lock);
|
||||||
|
|
||||||
|
AutomationList* al = automation_list (param, true);
|
||||||
|
|
||||||
|
if (s != al->automation_state()) {
|
||||||
|
al->set_automation_state (s);
|
||||||
|
_session.set_dirty ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoState
|
||||||
|
Automatable::get_parameter_automation_state (ParamID param)
|
||||||
|
{
|
||||||
|
Glib::Mutex::Lock lm (_automation_lock);
|
||||||
|
|
||||||
|
AutomationList* al = automation_list(param);
|
||||||
|
|
||||||
|
if (al) {
|
||||||
|
return al->automation_state();
|
||||||
|
} else {
|
||||||
|
return Off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Automatable::set_parameter_automation_style (ParamID param, AutoStyle s)
|
||||||
|
{
|
||||||
|
Glib::Mutex::Lock lm (_automation_lock);
|
||||||
|
|
||||||
|
AutomationList* al = automation_list (param, true);
|
||||||
|
|
||||||
|
if (s != al->automation_style()) {
|
||||||
|
al->set_automation_style (s);
|
||||||
|
_session.set_dirty ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoStyle
|
||||||
|
Automatable::get_parameter_automation_style (ParamID param)
|
||||||
|
{
|
||||||
|
Glib::Mutex::Lock lm (_automation_lock);
|
||||||
|
|
||||||
|
AutomationList* al = automation_list(param);
|
||||||
|
|
||||||
|
if (al) {
|
||||||
|
return al->automation_style();
|
||||||
|
} else {
|
||||||
|
return Absolute; // whatever
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Automatable::protect_automation ()
|
||||||
|
{
|
||||||
|
set<ParamID> automated_params;
|
||||||
|
|
||||||
|
what_has_automation (automated_params);
|
||||||
|
|
||||||
|
for (set<ParamID>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
|
||||||
|
|
||||||
|
AutomationList* al = automation_list (*i);
|
||||||
|
|
||||||
|
switch (al->automation_state()) {
|
||||||
|
case Write:
|
||||||
|
al->set_automation_state (Off);
|
||||||
|
break;
|
||||||
|
case Touch:
|
||||||
|
al->set_automation_state (Play);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -78,8 +78,8 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<Audio
|
||||||
nframes_t position,
|
nframes_t position,
|
||||||
AnchorPoint ap)
|
AnchorPoint ap)
|
||||||
: AudioRegion (position, length, "foobar"),
|
: AudioRegion (position, length, "foobar"),
|
||||||
_fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
|
_fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
|
||||||
_fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
|
_fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
|
||||||
|
|
||||||
{
|
{
|
||||||
_in = in;
|
_in = in;
|
||||||
|
|
@ -96,8 +96,8 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<Audio
|
||||||
|
|
||||||
Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioRegion> b, CrossfadeModel model, bool act)
|
Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioRegion> b, CrossfadeModel model, bool act)
|
||||||
: AudioRegion (0, 0, "foobar"),
|
: AudioRegion (0, 0, "foobar"),
|
||||||
_fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
|
_fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
|
||||||
_fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
|
_fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
|
||||||
{
|
{
|
||||||
_in_update = false;
|
_in_update = false;
|
||||||
_fixed = false;
|
_fixed = false;
|
||||||
|
|
@ -115,8 +115,8 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioR
|
||||||
|
|
||||||
Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
|
Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
|
||||||
: AudioRegion (0, 0, "foobar"),
|
: AudioRegion (0, 0, "foobar"),
|
||||||
_fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
|
_fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
|
||||||
_fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
|
_fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
|
||||||
|
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Region> r;
|
boost::shared_ptr<Region> r;
|
||||||
|
|
@ -300,8 +300,8 @@ Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
|
||||||
float* fiv = new float[to_write];
|
float* fiv = new float[to_write];
|
||||||
float* fov = new float[to_write];
|
float* fov = new float[to_write];
|
||||||
|
|
||||||
_fade_in.get_vector (offset, offset+to_write, fiv, to_write);
|
_fade_in.curve().get_vector (offset, offset+to_write, fiv, to_write);
|
||||||
_fade_out.get_vector (offset, offset+to_write, fov, to_write);
|
_fade_out.curve().get_vector (offset, offset+to_write, fov, to_write);
|
||||||
|
|
||||||
/* note: although we have not explicitly taken into account the return values
|
/* note: although we have not explicitly taken into account the return values
|
||||||
from _out->read_at() or _in->read_at(), the length() function does this
|
from _out->read_at() or _in->read_at(), the length() function does this
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include <sigc++/bind.h>
|
#include <sigc++/bind.h>
|
||||||
|
|
||||||
#include "ardour/curve.h"
|
#include "ardour/curve.h"
|
||||||
|
#include "ardour/automation_event.h"
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
|
|
@ -39,31 +40,35 @@ using namespace ARDOUR;
|
||||||
using namespace sigc;
|
using namespace sigc;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
Curve::Curve (double minv, double maxv, double canv, bool nostate)
|
Curve::Curve (const AutomationList& al)
|
||||||
: AutomationList (canv)
|
: _list (al)
|
||||||
|
, _dirty (true)
|
||||||
{
|
{
|
||||||
min_yval = minv;
|
_list.Dirty.connect(mem_fun(*this, &Curve::on_list_dirty));
|
||||||
max_yval = maxv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Curve::Curve (const Curve& other)
|
Curve::Curve (const Curve& other)
|
||||||
: AutomationList (other)
|
: _list (other._list)
|
||||||
|
, _dirty (true)
|
||||||
{
|
{
|
||||||
min_yval = other.min_yval;
|
_list.Dirty.connect(mem_fun(*this, &Curve::on_list_dirty));
|
||||||
max_yval = other.max_yval;
|
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
Curve::Curve (const Curve& other, double start, double end)
|
Curve::Curve (const Curve& other, double start, double end)
|
||||||
: AutomationList (other, start, end)
|
: _list (other._list)
|
||||||
{
|
{
|
||||||
min_yval = other.min_yval;
|
_min_yval = other._min_yval;
|
||||||
max_yval = other.max_yval;
|
_max_yval = other._max_yval;
|
||||||
}
|
}
|
||||||
|
|
||||||
Curve::Curve (const XMLNode& node)
|
/** \a id is used for legacy sessions where the type is not present
|
||||||
: AutomationList (node)
|
* in or below the <AutomationList> node. It is used if \a id is non-null.
|
||||||
|
*/
|
||||||
|
Curve::Curve (const XMLNode& node, ParamID id)
|
||||||
|
: AutomationList (node, id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
Curve::~Curve ()
|
Curve::~Curve ()
|
||||||
{
|
{
|
||||||
|
|
@ -78,7 +83,7 @@ Curve::solve ()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((npoints = events.size()) > 2) {
|
if ((npoints = _list.events().size()) > 2) {
|
||||||
|
|
||||||
/* Compute coefficients needed to efficiently compute a constrained spline
|
/* Compute coefficients needed to efficiently compute a constrained spline
|
||||||
curve. See "Constrained Cubic Spline Interpolation" by CJC Kruger
|
curve. See "Constrained Cubic Spline Interpolation" by CJC Kruger
|
||||||
|
|
@ -88,9 +93,9 @@ Curve::solve ()
|
||||||
double x[npoints];
|
double x[npoints];
|
||||||
double y[npoints];
|
double y[npoints];
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
AutomationEventList::iterator xx;
|
AutomationList::EventList::const_iterator xx;
|
||||||
|
|
||||||
for (i = 0, xx = events.begin(); xx != events.end(); ++xx, ++i) {
|
for (i = 0, xx = _list.events().begin(); xx != _list.events().end(); ++xx, ++i) {
|
||||||
x[i] = (double) (*xx)->when;
|
x[i] = (double) (*xx)->when;
|
||||||
y[i] = (double) (*xx)->value;
|
y[i] = (double) (*xx)->value;
|
||||||
}
|
}
|
||||||
|
|
@ -108,16 +113,7 @@ Curve::solve ()
|
||||||
|
|
||||||
double fplast = 0;
|
double fplast = 0;
|
||||||
|
|
||||||
for (i = 0, xx = events.begin(); xx != events.end(); ++xx, ++i) {
|
for (i = 0, xx = _list.events().begin(); xx != _list.events().end(); ++xx, ++i) {
|
||||||
|
|
||||||
CurvePoint* cp = dynamic_cast<CurvePoint*>(*xx);
|
|
||||||
|
|
||||||
if (cp == 0) {
|
|
||||||
fatal << _("programming error: ")
|
|
||||||
<< X_("non-CurvePoint event found in event list for a Curve")
|
|
||||||
<< endmsg;
|
|
||||||
/*NOTREACHED*/
|
|
||||||
}
|
|
||||||
|
|
||||||
double xdelta; /* gcc is wrong about possible uninitialized use */
|
double xdelta; /* gcc is wrong about possible uninitialized use */
|
||||||
double xdelta2; /* ditto */
|
double xdelta2; /* ditto */
|
||||||
|
|
@ -192,10 +188,10 @@ Curve::solve ()
|
||||||
|
|
||||||
/* store */
|
/* store */
|
||||||
|
|
||||||
cp->coeff[0] = y[i-1] - (b * x[i-1]) - (c * xim12) - (d * xim13);
|
(*xx)->coeff[0] = y[i-1] - (b * x[i-1]) - (c * xim12) - (d * xim13);
|
||||||
cp->coeff[1] = b;
|
(*xx)->coeff[1] = b;
|
||||||
cp->coeff[2] = c;
|
(*xx)->coeff[2] = c;
|
||||||
cp->coeff[3] = d;
|
(*xx)->coeff[3] = d;
|
||||||
|
|
||||||
fplast = fpi;
|
fplast = fpi;
|
||||||
}
|
}
|
||||||
|
|
@ -208,7 +204,7 @@ Curve::solve ()
|
||||||
bool
|
bool
|
||||||
Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen)
|
Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen)
|
||||||
{
|
{
|
||||||
Glib::Mutex::Lock lm (lock, Glib::TRY_LOCK);
|
Glib::Mutex::Lock lm(_list.lock(), Glib::TRY_LOCK);
|
||||||
|
|
||||||
if (!lm.locked()) {
|
if (!lm.locked()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -221,7 +217,7 @@ Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen)
|
||||||
void
|
void
|
||||||
Curve::get_vector (double x0, double x1, float *vec, int32_t veclen)
|
Curve::get_vector (double x0, double x1, float *vec, int32_t veclen)
|
||||||
{
|
{
|
||||||
Glib::Mutex::Lock lm (lock);
|
Glib::Mutex::Lock lm(_list.lock());
|
||||||
_get_vector (x0, x1, vec, veclen);
|
_get_vector (x0, x1, vec, veclen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,22 +229,22 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
|
||||||
int32_t original_veclen;
|
int32_t original_veclen;
|
||||||
int32_t npoints;
|
int32_t npoints;
|
||||||
|
|
||||||
if ((npoints = events.size()) == 0) {
|
if ((npoints = _list.events().size()) == 0) {
|
||||||
for (i = 0; i < veclen; ++i) {
|
for (i = 0; i < veclen; ++i) {
|
||||||
vec[i] = default_value;
|
vec[i] = _list.default_value();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* events is now known not to be empty */
|
/* events is now known not to be empty */
|
||||||
|
|
||||||
max_x = events.back()->when;
|
max_x = _list.events().back()->when;
|
||||||
min_x = events.front()->when;
|
min_x = _list.events().front()->when;
|
||||||
|
|
||||||
lx = max (min_x, x0);
|
lx = max (min_x, x0);
|
||||||
|
|
||||||
if (x1 < 0) {
|
if (x1 < 0) {
|
||||||
x1 = events.back()->when;
|
x1 = _list.events().back()->when;
|
||||||
}
|
}
|
||||||
|
|
||||||
hx = min (max_x, x1);
|
hx = min (max_x, x1);
|
||||||
|
|
@ -267,7 +263,7 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
|
||||||
subveclen = min (subveclen, veclen);
|
subveclen = min (subveclen, veclen);
|
||||||
|
|
||||||
for (i = 0; i < subveclen; ++i) {
|
for (i = 0; i < subveclen; ++i) {
|
||||||
vec[i] = events.front()->value;
|
vec[i] = _list.events().front()->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
veclen -= subveclen;
|
veclen -= subveclen;
|
||||||
|
|
@ -286,7 +282,7 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
|
||||||
|
|
||||||
subveclen = min (subveclen, veclen);
|
subveclen = min (subveclen, veclen);
|
||||||
|
|
||||||
val = events.back()->value;
|
val = _list.events().back()->value;
|
||||||
|
|
||||||
i = veclen - subveclen;
|
i = veclen - subveclen;
|
||||||
|
|
||||||
|
|
@ -304,7 +300,7 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
|
||||||
if (npoints == 1 ) {
|
if (npoints == 1 ) {
|
||||||
|
|
||||||
for (i = 0; i < veclen; ++i) {
|
for (i = 0; i < veclen; ++i) {
|
||||||
vec[i] = events.front()->value;
|
vec[i] = _list.events().front()->value;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -325,11 +321,11 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
|
||||||
dx = 0; // not used
|
dx = 0; // not used
|
||||||
}
|
}
|
||||||
|
|
||||||
double slope = (events.back()->value - events.front()->value)/
|
double slope = (_list.events().back()->value - _list.events().front()->value)/
|
||||||
(events.back()->when - events.front()->when);
|
(_list.events().back()->when - _list.events().front()->when);
|
||||||
double yfrac = dx*slope;
|
double yfrac = dx*slope;
|
||||||
|
|
||||||
vec[0] = events.front()->value + slope * (lx - events.front()->when);
|
vec[0] = _list.events().front()->value + slope * (lx - _list.events().front()->when);
|
||||||
|
|
||||||
for (i = 1; i < veclen; ++i) {
|
for (i = 1; i < veclen; ++i) {
|
||||||
vec[i] = vec[i-1] + yfrac;
|
vec[i] = vec[i-1] + yfrac;
|
||||||
|
|
@ -357,27 +353,31 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
|
||||||
double
|
double
|
||||||
Curve::unlocked_eval (double x)
|
Curve::unlocked_eval (double x)
|
||||||
{
|
{
|
||||||
|
// I don't see the point of this...
|
||||||
|
|
||||||
if (_dirty) {
|
if (_dirty) {
|
||||||
solve ();
|
solve ();
|
||||||
}
|
}
|
||||||
|
|
||||||
return shared_eval (x);
|
return _list.unlocked_eval (x);
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
Curve::multipoint_eval (double x)
|
Curve::multipoint_eval (double x)
|
||||||
{
|
{
|
||||||
pair<AutomationEventList::iterator,AutomationEventList::iterator> range;
|
pair<AutomationList::EventList::const_iterator,AutomationList::EventList::const_iterator> range;
|
||||||
|
|
||||||
|
AutomationList::LookupCache& lookup_cache = _list.lookup_cache();
|
||||||
|
|
||||||
if ((lookup_cache.left < 0) ||
|
if ((lookup_cache.left < 0) ||
|
||||||
((lookup_cache.left > x) ||
|
((lookup_cache.left > x) ||
|
||||||
(lookup_cache.range.first == events.end()) ||
|
(lookup_cache.range.first == _list.events().end()) ||
|
||||||
((*lookup_cache.range.second)->when < x))) {
|
((*lookup_cache.range.second)->when < x))) {
|
||||||
|
|
||||||
TimeComparator cmp;
|
AutomationList::TimeComparator cmp;
|
||||||
ControlEvent cp (x, 0.0);
|
ControlEvent cp (x, 0.0);
|
||||||
|
|
||||||
lookup_cache.range = equal_range (events.begin(), events.end(), &cp, cmp);
|
lookup_cache.range = equal_range (_list.events().begin(), _list.events().end(), &cp, cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
range = lookup_cache.range;
|
range = lookup_cache.range;
|
||||||
|
|
@ -399,21 +399,21 @@ Curve::multipoint_eval (double x)
|
||||||
|
|
||||||
lookup_cache.left = x;
|
lookup_cache.left = x;
|
||||||
|
|
||||||
if (range.first == events.begin()) {
|
if (range.first == _list.events().begin()) {
|
||||||
/* we're before the first point */
|
/* we're before the first point */
|
||||||
// return default_value;
|
// return default_value;
|
||||||
events.front()->value;
|
_list.events().front()->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (range.second == events.end()) {
|
if (range.second == _list.events().end()) {
|
||||||
/* we're after the last point */
|
/* we're after the last point */
|
||||||
return events.back()->value;
|
return _list.events().back()->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
double x2 = x * x;
|
double x2 = x * x;
|
||||||
CurvePoint* cp = dynamic_cast<CurvePoint*> (*range.second);
|
ControlEvent* ev = *range.second;
|
||||||
|
|
||||||
return cp->coeff[0] + (cp->coeff[1] * x) + (cp->coeff[2] * x2) + (cp->coeff[3] * x2 * x);
|
return ev->coeff[0] + (ev->coeff[1] * x) + (ev->coeff[2] * x2) + (ev->coeff[3] * x2 * x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* x is a control point in the data */
|
/* x is a control point in the data */
|
||||||
|
|
@ -422,18 +422,6 @@ Curve::multipoint_eval (double x)
|
||||||
return (*range.first)->value;
|
return (*range.first)->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlEvent*
|
|
||||||
Curve::point_factory (double when, double val) const
|
|
||||||
{
|
|
||||||
return new CurvePoint (when, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
ControlEvent*
|
|
||||||
Curve::point_factory (const ControlEvent& other) const
|
|
||||||
{
|
|
||||||
return new CurvePoint (other.when, other.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,10 @@ setup_enum_writer ()
|
||||||
REGISTER_ENUM (PluginAutomation);
|
REGISTER_ENUM (PluginAutomation);
|
||||||
REGISTER_ENUM (SoloAutomation);
|
REGISTER_ENUM (SoloAutomation);
|
||||||
REGISTER_ENUM (MuteAutomation);
|
REGISTER_ENUM (MuteAutomation);
|
||||||
|
REGISTER_ENUM (MidiCCAutomation);
|
||||||
|
REGISTER_ENUM (FadeInAutomation);
|
||||||
|
REGISTER_ENUM (FadeOutAutomation);
|
||||||
|
REGISTER_ENUM (EnvelopeAutomation);
|
||||||
REGISTER_BITS (_AutomationType);
|
REGISTER_BITS (_AutomationType);
|
||||||
|
|
||||||
REGISTER_ENUM (Off);
|
REGISTER_ENUM (Off);
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,12 @@
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
|
|
||||||
Gain::Gain ()
|
Gain::Gain ()
|
||||||
: Curve (0.0, 2.0, 1.0f) /* XXX yuck; clamps gain to -inf .. +6db */
|
: AutomationList (ParamID(GainAutomation), 0.0, 2.0, 1.0f) /* XXX yuck; clamps gain to -inf .. +6db */
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Gain::Gain (const Gain& other)
|
Gain::Gain (const Gain& other)
|
||||||
: Curve (other)
|
: AutomationList (other)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ Gain&
|
||||||
Gain::operator= (const Gain& other)
|
Gain::operator= (const Gain& other)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
Curve::operator= (other);
|
AutomationList::operator= (other);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ Insert::state (bool full_state)
|
||||||
|
|
||||||
XMLNode& automation = Automatable::get_automation_state();
|
XMLNode& automation = Automatable::get_automation_state();
|
||||||
|
|
||||||
for (set<uint32_t>::iterator x = _visible_parameter_automation.begin(); x != _visible_parameter_automation.end(); ++x) {
|
for (set<ParamID>::iterator x = _visible_parameter_automation.begin(); x != _visible_parameter_automation.end(); ++x) {
|
||||||
if (x != _visible_parameter_automation.begin()) {
|
if (x != _visible_parameter_automation.begin()) {
|
||||||
sstr << ' ';
|
sstr << ' ';
|
||||||
}
|
}
|
||||||
|
|
@ -196,7 +196,7 @@ Insert::set_state (const XMLNode& node)
|
||||||
if ((prop = (*niter)->property ("path")) != 0) {
|
if ((prop = (*niter)->property ("path")) != 0) {
|
||||||
old_set_automation_state (*(*niter));
|
old_set_automation_state (*(*niter));
|
||||||
} else {
|
} else {
|
||||||
set_automation_state (*(*niter));
|
set_automation_state (*(*niter), ParamID(PluginAutomation));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((prop = (*niter)->property ("visible")) != 0) {
|
if ((prop = (*niter)->property ("visible")) != 0) {
|
||||||
|
|
@ -211,7 +211,8 @@ Insert::set_state (const XMLNode& node)
|
||||||
if (sstr.fail()) {
|
if (sstr.fail()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mark_automation_visible (what, true);
|
// FIXME: other automation types?
|
||||||
|
mark_automation_visible (ParamID(PluginAutomation, what), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,11 +101,10 @@ static double direct_gain_to_control (gain_t gain) {
|
||||||
IO::IO (Session& s, const string& name,
|
IO::IO (Session& s, const string& name,
|
||||||
int input_min, int input_max, int output_min, int output_max,
|
int input_min, int input_max, int output_min, int output_max,
|
||||||
DataType default_type)
|
DataType default_type)
|
||||||
: SessionObject(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),
|
_gain_control (X_("gaincontrol"), *this),
|
||||||
_gain_automation_curve (0.0, 2.0, 1.0),
|
|
||||||
_input_minimum (ChanCount::ZERO),
|
_input_minimum (ChanCount::ZERO),
|
||||||
_input_maximum (ChanCount::INFINITE),
|
_input_maximum (ChanCount::INFINITE),
|
||||||
_output_minimum (ChanCount::ZERO),
|
_output_minimum (ChanCount::ZERO),
|
||||||
|
|
@ -136,12 +135,14 @@ 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));
|
||||||
|
|
||||||
apply_gain_automation = false;
|
apply_gain_automation = false;
|
||||||
|
|
||||||
last_automation_snapshot = 0;
|
last_automation_snapshot = 0;
|
||||||
|
|
||||||
_gain_automation_state = Off;
|
/*_gain_automation_state = Off;
|
||||||
_gain_automation_style = Absolute;
|
_gain_automation_style = Absolute;*/
|
||||||
|
|
||||||
{
|
{
|
||||||
// IO::Meter is emitted from another thread so the
|
// IO::Meter is emitted from another thread so the
|
||||||
|
|
@ -157,11 +158,10 @@ IO::IO (Session& s, const string& name,
|
||||||
}
|
}
|
||||||
|
|
||||||
IO::IO (Session& s, const XMLNode& node, DataType dt)
|
IO::IO (Session& s, const XMLNode& node, DataType dt)
|
||||||
: SessionObject(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),
|
_gain_control (X_("gaincontrol"), *this)
|
||||||
_gain_automation_curve (0, 0, 0) // all reset in set_state()
|
|
||||||
{
|
{
|
||||||
_meter = new PeakMeter (_session);
|
_meter = new PeakMeter (_session);
|
||||||
|
|
||||||
|
|
@ -1129,7 +1129,7 @@ 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_curve.automation_playback()) {
|
if (gain_automation().automation_playback()) {
|
||||||
return _effective_gain;
|
return _effective_gain;
|
||||||
} else {
|
} else {
|
||||||
return _desired_gain;
|
return _desired_gain;
|
||||||
|
|
@ -1289,17 +1289,8 @@ IO::state (bool full_state)
|
||||||
|
|
||||||
/* automation */
|
/* automation */
|
||||||
|
|
||||||
if (full_state) {
|
if (full_state)
|
||||||
|
node->add_child_nocopy (get_automation_state());
|
||||||
XMLNode* autonode = new XMLNode (X_("Automation"));
|
|
||||||
autonode->add_child_nocopy (get_automation_state());
|
|
||||||
node->add_child_nocopy (*autonode);
|
|
||||||
|
|
||||||
snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
|
|
||||||
} else {
|
|
||||||
/* never store anything except Off for automation state in a template */
|
|
||||||
snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
|
|
||||||
}
|
|
||||||
|
|
||||||
return *node;
|
return *node;
|
||||||
}
|
}
|
||||||
|
|
@ -1363,7 +1354,7 @@ IO::set_state (const XMLNode& node)
|
||||||
|
|
||||||
if ((*iter)->name() == X_("Automation")) {
|
if ((*iter)->name() == X_("Automation")) {
|
||||||
|
|
||||||
set_automation_state (*(*iter)->children().front());
|
set_automation_state (*(*iter), ParamID(GainAutomation));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*iter)->name() == X_("controllable")) {
|
if ((*iter)->name() == X_("controllable")) {
|
||||||
|
|
@ -1410,18 +1401,6 @@ IO::set_state (const XMLNode& node)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
IO::set_automation_state (const XMLNode& node)
|
|
||||||
{
|
|
||||||
return _gain_automation_curve.set_state (node);
|
|
||||||
}
|
|
||||||
|
|
||||||
XMLNode&
|
|
||||||
IO::get_automation_state ()
|
|
||||||
{
|
|
||||||
return (_gain_automation_curve.get_state ());
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
IO::load_automation (string path)
|
IO::load_automation (string path)
|
||||||
{
|
{
|
||||||
|
|
@ -1479,7 +1458,7 @@ IO::load_automation (string path)
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'g':
|
case 'g':
|
||||||
_gain_automation_curve.fast_simple_add (when, value);
|
gain_automation().fast_simple_add (when, value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
|
|
@ -2198,41 +2177,43 @@ IO::meter ()
|
||||||
void
|
void
|
||||||
IO::clear_automation ()
|
IO::clear_automation ()
|
||||||
{
|
{
|
||||||
Glib::Mutex::Lock lm (automation_lock);
|
Automatable::clear_automation (); // clears gain automation
|
||||||
_gain_automation_curve.clear ();
|
|
||||||
_panner->clear_automation ();
|
_panner->clear_automation ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IO::set_gain_automation_state (AutoState state)
|
IO::set_parameter_automation_state (ParamID param, AutoState state)
|
||||||
{
|
{
|
||||||
|
// XXX: would be nice to get rid of this special hack
|
||||||
|
|
||||||
|
if (param.type() == GainAutomation) {
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
Glib::Mutex::Lock lm (automation_lock);
|
Glib::Mutex::Lock lm (_automation_lock);
|
||||||
|
|
||||||
if (state != _gain_automation_curve.automation_state()) {
|
ARDOUR::AutomationList& gain_auto = gain_automation();
|
||||||
|
|
||||||
|
if (state != gain_auto.automation_state()) {
|
||||||
changed = true;
|
changed = true;
|
||||||
last_automation_snapshot = 0;
|
last_automation_snapshot = 0;
|
||||||
_gain_automation_curve.set_automation_state (state);
|
gain_auto.set_automation_state (state);
|
||||||
|
|
||||||
if (state != Off) {
|
if (state != Off) {
|
||||||
set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
|
// FIXME: shouldn't this use Curve?
|
||||||
|
set_gain (gain_auto.eval (_session.transport_frame()), this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
_session.set_dirty ();
|
_session.set_dirty ();
|
||||||
//gain_automation_state_changed (); /* EMIT SIGNAL */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
} else {
|
||||||
IO::set_gain_automation_style (AutoStyle style)
|
Automatable::set_parameter_automation_state(param, state);
|
||||||
{
|
}
|
||||||
Glib::Mutex::Lock lm (automation_lock);
|
|
||||||
_gain_automation_curve.set_automation_style (style);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -2263,26 +2244,16 @@ IO::set_gain (gain_t val, void *src)
|
||||||
gain_changed (src);
|
gain_changed (src);
|
||||||
_gain_control.Changed (); /* EMIT SIGNAL */
|
_gain_control.Changed (); /* EMIT SIGNAL */
|
||||||
|
|
||||||
if (_session.transport_stopped() && src != 0 && src != this && _gain_automation_curve.automation_write()) {
|
ARDOUR::AutomationList& gain_auto = gain_automation();
|
||||||
_gain_automation_curve.add (_session.transport_frame(), val);
|
|
||||||
|
if (_session.transport_stopped() && src != 0 && src != this && gain_auto.automation_write()) {
|
||||||
|
gain_auto.add (_session.transport_frame(), val);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_session.set_dirty();
|
_session.set_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
IO::start_gain_touch ()
|
|
||||||
{
|
|
||||||
_gain_automation_curve.start_touch ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
IO::end_gain_touch ()
|
|
||||||
{
|
|
||||||
_gain_automation_curve.stop_touch ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
IO::start_pan_touch (uint32_t which)
|
IO::start_pan_touch (uint32_t which)
|
||||||
{
|
{
|
||||||
|
|
@ -2305,8 +2276,10 @@ IO::automation_snapshot (nframes_t now)
|
||||||
{
|
{
|
||||||
if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
|
if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
|
||||||
|
|
||||||
if (_gain_automation_curve.automation_write()) {
|
ARDOUR::AutomationList& gain_auto = gain_automation();
|
||||||
_gain_automation_curve.rt_add (now, gain());
|
|
||||||
|
if (gain_auto.automation_write()) {
|
||||||
|
gain_auto.rt_add (now, gain());
|
||||||
}
|
}
|
||||||
|
|
||||||
_panner->snapshot (now);
|
_panner->snapshot (now);
|
||||||
|
|
@ -2318,15 +2291,18 @@ IO::automation_snapshot (nframes_t now)
|
||||||
void
|
void
|
||||||
IO::transport_stopped (nframes_t frame)
|
IO::transport_stopped (nframes_t frame)
|
||||||
{
|
{
|
||||||
_gain_automation_curve.reposition_for_rt_add (frame);
|
ARDOUR::AutomationList& gain_auto = gain_automation();
|
||||||
|
|
||||||
if (_gain_automation_curve.automation_state() != Off) {
|
gain_auto.reposition_for_rt_add (frame);
|
||||||
|
|
||||||
|
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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
set_gain (_gain_automation_curve.eval (frame), 0);
|
// FIXME: shouldn't this use Curve?
|
||||||
|
set_gain (gain_auto.eval (frame), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
_panner->transport_stopped (frame);
|
_panner->transport_stopped (frame);
|
||||||
|
|
|
||||||
|
|
@ -318,7 +318,7 @@ LadspaPlugin::set_parameter (uint32_t which, float val)
|
||||||
{
|
{
|
||||||
if (which < descriptor->PortCount) {
|
if (which < descriptor->PortCount) {
|
||||||
shadow_data[which] = (LADSPA_Data) val;
|
shadow_data[which] = (LADSPA_Data) val;
|
||||||
ParameterChanged (which, val); /* EMIT SIGNAL */
|
ParameterChanged (ParamID(PluginAutomation, which), val); /* EMIT SIGNAL */
|
||||||
|
|
||||||
if (which < parameter_count() && controls[which]) {
|
if (which < parameter_count() && controls[which]) {
|
||||||
controls[which]->Changed ();
|
controls[which]->Changed ();
|
||||||
|
|
@ -493,10 +493,10 @@ LadspaPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& des
|
||||||
|
|
||||||
|
|
||||||
string
|
string
|
||||||
LadspaPlugin::describe_parameter (uint32_t which)
|
LadspaPlugin::describe_parameter (ParamID which)
|
||||||
{
|
{
|
||||||
if (which < parameter_count()) {
|
if (which.type() == PluginAutomation && which.id() < parameter_count()) {
|
||||||
return port_names()[which];
|
return port_names()[which.id()];
|
||||||
} else {
|
} else {
|
||||||
return "??";
|
return "??";
|
||||||
}
|
}
|
||||||
|
|
@ -512,16 +512,16 @@ LadspaPlugin::latency () const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set<uint32_t>
|
set<ParamID>
|
||||||
LadspaPlugin::automatable () const
|
LadspaPlugin::automatable () const
|
||||||
{
|
{
|
||||||
set<uint32_t> ret;
|
set<ParamID> ret;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < parameter_count(); ++i){
|
for (uint32_t i = 0; i < parameter_count(); ++i){
|
||||||
if (LADSPA_IS_PORT_INPUT(port_descriptor (i)) &&
|
if (LADSPA_IS_PORT_INPUT(port_descriptor (i)) &&
|
||||||
LADSPA_IS_PORT_CONTROL(port_descriptor (i))){
|
LADSPA_IS_PORT_CONTROL(port_descriptor (i))){
|
||||||
|
|
||||||
ret.insert (ret.end(), i);
|
ret.insert (ret.end(), ParamID(PluginAutomation, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ StreamPanner::add_state (XMLNode& node)
|
||||||
/*---------------------------------------------------------------------- */
|
/*---------------------------------------------------------------------- */
|
||||||
|
|
||||||
BaseStereoPanner::BaseStereoPanner (Panner& p)
|
BaseStereoPanner::BaseStereoPanner (Panner& p)
|
||||||
: StreamPanner (p), _automation (0.0, 1.0, 0.5)
|
: StreamPanner (p), _automation (ParamID(PanAutomation), 0.0, 1.0, 0.5)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,7 +438,7 @@ EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& ob
|
||||||
|
|
||||||
/* fetch positional data */
|
/* fetch positional data */
|
||||||
|
|
||||||
if (!_automation.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);
|
||||||
|
|
@ -565,7 +565,7 @@ EqualPowerStereoPanner::set_state (const XMLNode& node)
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
Multi2dPanner::Multi2dPanner (Panner& p)
|
Multi2dPanner::Multi2dPanner (Panner& p)
|
||||||
: StreamPanner (p), _automation (0.0, 1.0, 0.5) // XXX useless
|
: StreamPanner (p), _automation (ParamID(PanAutomation), 0.0, 1.0, 0.5) // XXX useless
|
||||||
{
|
{
|
||||||
update ();
|
update ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ Plugin::get_nth_control (uint32_t n)
|
||||||
|
|
||||||
get_parameter_descriptor (n, desc);
|
get_parameter_descriptor (n, desc);
|
||||||
|
|
||||||
controls[n] = new PortControllable (describe_parameter (n), *this, n,
|
controls[n] = new PortControllable (describe_parameter (ParamID(PluginAutomation, n)), *this, n,
|
||||||
desc.lower, desc.upper, desc.toggled, desc.logarithmic);
|
desc.lower, desc.upper, desc.toggled, desc.logarithmic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -152,18 +152,21 @@ PluginInsert::~PluginInsert ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PluginInsert::automation_list_creation_callback (uint32_t which, AutomationList& alist)
|
PluginInsert::automation_list_creation_callback (ParamID which, AutomationList& alist)
|
||||||
{
|
{
|
||||||
alist.automation_state_changed.connect (sigc::bind (mem_fun (*this, &PluginInsert::auto_state_changed), (which)));
|
alist.automation_state_changed.connect (sigc::bind (mem_fun (*this, &PluginInsert::auto_state_changed), (which)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PluginInsert::auto_state_changed (uint32_t which)
|
PluginInsert::auto_state_changed (ParamID which)
|
||||||
{
|
{
|
||||||
AutomationList& alist (automation_list (which));
|
if (which.type() != PluginAutomation)
|
||||||
|
return;
|
||||||
|
|
||||||
if (alist.automation_state() != Off) {
|
AutomationList* alist = automation_list (which);
|
||||||
_plugins[0]->set_parameter (which, alist.eval (_session.transport_frame()));
|
|
||||||
|
if (alist && alist->automation_state() != Off) {
|
||||||
|
_plugins[0]->set_parameter (which.id(), alist->eval (_session.transport_frame()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,18 +213,21 @@ PluginInsert::is_generator() const
|
||||||
void
|
void
|
||||||
PluginInsert::set_automatable ()
|
PluginInsert::set_automatable ()
|
||||||
{
|
{
|
||||||
set<uint32_t> a;
|
set<ParamID> a;
|
||||||
|
|
||||||
a = _plugins.front()->automatable ();
|
a = _plugins.front()->automatable ();
|
||||||
|
|
||||||
for (set<uint32_t>::iterator i = a.begin(); i != a.end(); ++i) {
|
for (set<ParamID>::iterator i = a.begin(); i != a.end(); ++i) {
|
||||||
can_automate (*i);
|
can_automate (*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PluginInsert::parameter_changed (uint32_t which, float val)
|
PluginInsert::parameter_changed (ParamID which, float val)
|
||||||
{
|
{
|
||||||
|
if (which.type() != PluginAutomation)
|
||||||
|
return;
|
||||||
|
|
||||||
vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin();
|
vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin();
|
||||||
|
|
||||||
/* don't set the first plugin, just all the slaves */
|
/* don't set the first plugin, just all the slaves */
|
||||||
|
|
@ -270,14 +276,14 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
|
||||||
|
|
||||||
if (with_auto) {
|
if (with_auto) {
|
||||||
|
|
||||||
map<uint32_t,AutomationList*>::iterator li;
|
map<ParamID,AutomationList*>::iterator li;
|
||||||
uint32_t n;
|
uint32_t n;
|
||||||
|
|
||||||
for (n = 0, li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li, ++n) {
|
for (n = 0, li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li, ++n) {
|
||||||
|
|
||||||
AutomationList& alist (*((*li).second));
|
AutomationList& alist (*((*li).second));
|
||||||
|
|
||||||
if (alist.automation_playback()) {
|
if (alist.param_id().type() == PluginAutomation && alist.automation_playback()) {
|
||||||
bool valid;
|
bool valid;
|
||||||
|
|
||||||
float val = alist.rt_safe_eval (now, valid);
|
float val = alist.rt_safe_eval (now, valid);
|
||||||
|
|
@ -301,12 +307,13 @@ 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<uint32_t,AutomationList*>::iterator li;
|
map<ParamID,AutomationList*>::iterator li;
|
||||||
|
|
||||||
for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) {
|
for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) {
|
||||||
|
|
||||||
AutomationList *alist = ((*li).second);
|
AutomationList *alist = ((*li).second);
|
||||||
if (alist != 0 && alist->automation_write ()) {
|
if (alist != 0 && alist->param_id().type() == PluginAutomation
|
||||||
|
&& alist->automation_write ()) {
|
||||||
|
|
||||||
float val = _plugins[0]->get_parameter ((*li).first);
|
float val = _plugins[0]->get_parameter ((*li).first);
|
||||||
alist->rt_add (now, val);
|
alist->rt_add (now, val);
|
||||||
|
|
@ -318,13 +325,13 @@ PluginInsert::automation_snapshot (nframes_t now)
|
||||||
void
|
void
|
||||||
PluginInsert::transport_stopped (nframes_t now)
|
PluginInsert::transport_stopped (nframes_t now)
|
||||||
{
|
{
|
||||||
map<uint32_t,AutomationList*>::iterator li;
|
map<ParamID,AutomationList*>::iterator li;
|
||||||
|
|
||||||
for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) {
|
for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) {
|
||||||
AutomationList& alist (*(li->second));
|
AutomationList& alist (*(li->second));
|
||||||
alist.reposition_for_rt_add (now);
|
alist.reposition_for_rt_add (now);
|
||||||
|
|
||||||
if (alist.automation_state() != Off) {
|
if (alist.param_id().type() == PluginAutomation && alist.automation_state() != Off) {
|
||||||
_plugins[0]->set_parameter (li->first, alist.eval (now));
|
_plugins[0]->set_parameter (li->first, alist.eval (now));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -374,14 +381,17 @@ PluginInsert::run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PluginInsert::set_parameter (uint32_t port, float val)
|
PluginInsert::set_parameter (ParamID param, float val)
|
||||||
{
|
{
|
||||||
|
if (param.type() != PluginAutomation)
|
||||||
|
return;
|
||||||
|
|
||||||
/* the others will be set from the event triggered by this */
|
/* the others will be set from the event triggered by this */
|
||||||
|
|
||||||
_plugins[0]->set_parameter (port, val);
|
_plugins[0]->set_parameter (param.id(), val);
|
||||||
|
|
||||||
if (automation_list (port).automation_write()) {
|
if (automation_list (param) && automation_list (param)->automation_write()) {
|
||||||
automation_list (port).add (_session.audible_frame(), val);
|
automation_list (param)->add (_session.audible_frame(), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
_session.set_dirty();
|
_session.set_dirty();
|
||||||
|
|
@ -432,63 +442,18 @@ PluginInsert::automation_run (BufferSet& bufs, nframes_t nframes, nframes_t offs
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
PluginInsert::default_parameter_value (uint32_t port)
|
PluginInsert::default_parameter_value (ParamID param)
|
||||||
{
|
{
|
||||||
|
if (param.type() != PluginAutomation)
|
||||||
|
return 1.0;
|
||||||
|
|
||||||
if (_plugins.empty()) {
|
if (_plugins.empty()) {
|
||||||
fatal << _("programming error: ") << X_("PluginInsert::default_parameter_value() called with no plugin")
|
fatal << _("programming error: ") << X_("PluginInsert::default_parameter_value() called with no plugin")
|
||||||
<< endmsg;
|
<< endmsg;
|
||||||
/*NOTREACHED*/
|
/*NOTREACHED*/
|
||||||
}
|
}
|
||||||
|
|
||||||
return _plugins[0]->default_value (port);
|
return _plugins[0]->default_value (param.id());
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PluginInsert::set_port_automation_state (uint32_t port, AutoState s)
|
|
||||||
{
|
|
||||||
if (port < _plugins[0]->parameter_count()) {
|
|
||||||
|
|
||||||
AutomationList& al = automation_list (port);
|
|
||||||
|
|
||||||
if (s != al.automation_state()) {
|
|
||||||
al.set_automation_state (s);
|
|
||||||
_session.set_dirty ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoState
|
|
||||||
PluginInsert::get_port_automation_state (uint32_t port)
|
|
||||||
{
|
|
||||||
if (port < _plugins[0]->parameter_count()) {
|
|
||||||
return automation_list (port).automation_state();
|
|
||||||
} else {
|
|
||||||
return Off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PluginInsert::protect_automation ()
|
|
||||||
{
|
|
||||||
set<uint32_t> automated_params;
|
|
||||||
|
|
||||||
what_has_automation (automated_params);
|
|
||||||
|
|
||||||
for (set<uint32_t>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
|
|
||||||
|
|
||||||
AutomationList& al = automation_list (*i);
|
|
||||||
|
|
||||||
switch (al.automation_state()) {
|
|
||||||
case Write:
|
|
||||||
al.set_automation_state (Off);
|
|
||||||
break;
|
|
||||||
case Touch:
|
|
||||||
al.set_automation_state (Play);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<Plugin>
|
boost::shared_ptr<Plugin>
|
||||||
|
|
@ -684,16 +649,18 @@ PluginInsert::state (bool full)
|
||||||
|
|
||||||
/* add port automation state */
|
/* add port automation state */
|
||||||
XMLNode *autonode = new XMLNode(port_automation_node_name);
|
XMLNode *autonode = new XMLNode(port_automation_node_name);
|
||||||
set<uint32_t> automatable = _plugins[0]->automatable();
|
set<ParamID> automatable = _plugins[0]->automatable();
|
||||||
|
|
||||||
for (set<uint32_t>::iterator x = automatable.begin(); x != automatable.end(); ++x) {
|
for (set<ParamID>::iterator x = automatable.begin(); x != automatable.end(); ++x) {
|
||||||
|
|
||||||
XMLNode* child = new XMLNode("port");
|
/*XMLNode* child = new XMLNode("port");
|
||||||
snprintf(buf, sizeof(buf), "%" PRIu32, *x);
|
snprintf(buf, sizeof(buf), "%" PRIu32, *x);
|
||||||
child->add_property("number", string(buf));
|
child->add_property("number", string(buf));
|
||||||
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
node.add_child_nocopy (*autonode);
|
node.add_child_nocopy (*autonode);
|
||||||
|
|
@ -824,7 +791,7 @@ PluginInsert::set_state(const XMLNode& node)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!child->children().empty()) {
|
if (!child->children().empty()) {
|
||||||
automation_list (port_id).set_state (*child->children().front());
|
automation_list (ParamID(PluginAutomation, port_id), true)->set_state (*child->children().front());
|
||||||
} else {
|
} else {
|
||||||
if ((cprop = child->property("auto")) != 0) {
|
if ((cprop = child->property("auto")) != 0) {
|
||||||
|
|
||||||
|
|
@ -832,13 +799,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 (port_id).set_automation_state (AutoState (x));
|
automation_list (ParamID(PluginAutomation, port_id), true)->set_automation_state (AutoState (x));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* missing */
|
/* missing */
|
||||||
|
|
||||||
automation_list (port_id).set_automation_state (Off);
|
automation_list (ParamID(PluginAutomation, port_id), true)->set_automation_state (Off);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -860,9 +827,12 @@ PluginInsert::set_state(const XMLNode& node)
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
PluginInsert::describe_parameter (uint32_t what)
|
PluginInsert::describe_parameter (ParamID param)
|
||||||
{
|
{
|
||||||
return _plugins[0]->describe_parameter (what);
|
if (param.type() != PluginAutomation)
|
||||||
|
return Automatable::describe_parameter(param);
|
||||||
|
|
||||||
|
return _plugins[0]->describe_parameter (param);
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDOUR::nframes_t
|
ARDOUR::nframes_t
|
||||||
|
|
|
||||||
|
|
@ -2380,12 +2380,14 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nfra
|
||||||
apply_gain_automation = false;
|
apply_gain_automation = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
Glib::Mutex::Lock am (automation_lock, Glib::TRY_LOCK);
|
Glib::Mutex::Lock am (_automation_lock, Glib::TRY_LOCK);
|
||||||
|
|
||||||
if (am.locked() && _session.transport_rolling()) {
|
if (am.locked() && _session.transport_rolling()) {
|
||||||
|
|
||||||
if (_gain_automation_curve.automation_playback()) {
|
ARDOUR::AutomationList& gain_auto = gain_automation();
|
||||||
apply_gain_automation = _gain_automation_curve.rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
|
|
||||||
|
if (gain_auto.automation_playback()) {
|
||||||
|
apply_gain_automation = gain_auto.curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2562,33 +2564,10 @@ Route::set_block_size (nframes_t nframes)
|
||||||
void
|
void
|
||||||
Route::protect_automation ()
|
Route::protect_automation ()
|
||||||
{
|
{
|
||||||
switch (gain_automation_state()) {
|
Automatable::protect_automation();
|
||||||
case Write:
|
|
||||||
set_gain_automation_state (Off);
|
|
||||||
case Touch:
|
|
||||||
set_gain_automation_state (Play);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (panner().automation_state ()) {
|
for (InsertList::iterator i = _inserts.begin(); i != _inserts.end(); ++i)
|
||||||
case Write:
|
(*i)->protect_automation();
|
||||||
panner().set_automation_state (Off);
|
|
||||||
break;
|
|
||||||
case Touch:
|
|
||||||
panner().set_automation_state (Play);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (InsertList::iterator i = _inserts.begin(); i != _inserts.end(); ++i) {
|
|
||||||
boost::shared_ptr<PluginInsert> pi;
|
|
||||||
if ((pi = boost::dynamic_pointer_cast<PluginInsert> (*i)) != 0) {
|
|
||||||
pi->protect_automation ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ Send::set_state(const XMLNode& node)
|
||||||
if ((*niter)->name() == "Redirect") {
|
if ((*niter)->name() == "Redirect") {
|
||||||
insert_node = *niter;
|
insert_node = *niter;
|
||||||
} else if ((*niter)->name() == X_("Automation")) {
|
} else if ((*niter)->name() == X_("Automation")) {
|
||||||
_io->set_automation_state (*(*niter));
|
_io->set_automation_state (*(*niter), ParamID(GainAutomation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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_state();
|
ARDOUR::AutoState gain_state = rs.route().gain_automation().automation_state();
|
||||||
if ( gain_state == Touch || gain_state == Play )
|
if ( gain_state == Touch || gain_state == Play )
|
||||||
{
|
{
|
||||||
notify_gain_changed( &rs );
|
notify_gain_changed( &rs );
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue