mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-10 16:46:35 +01:00
massive changes in automation state handling, not entirely complete; some bug fixes for automation line drawing
git-svn-id: svn://localhost/ardour2/trunk@1034 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
74df5d49c8
commit
71c94e6943
29 changed files with 543 additions and 229 deletions
|
|
@ -305,7 +305,6 @@ env.Alias('install', env.Install(os.path.join(install_prefix, 'share/ardour2'),
|
||||||
env.Alias('install', env.Install(os.path.join(install_prefix, 'share/ardour2/pixmaps'), pixmap_files))
|
env.Alias('install', env.Install(os.path.join(install_prefix, 'share/ardour2/pixmaps'), pixmap_files))
|
||||||
env.Alias('install', env.Install(os.path.join(install_prefix, 'share/ardour2/icons'), icon_files))
|
env.Alias('install', env.Install(os.path.join(install_prefix, 'share/ardour2/icons'), icon_files))
|
||||||
|
|
||||||
env.AlwaysBuild ('version.cc')
|
|
||||||
env.Alias ('version', gtkardour.VersionBuild(['version.cc','version.h'], 'SConscript'))
|
env.Alias ('version', gtkardour.VersionBuild(['version.cc','version.h'], 'SConscript'))
|
||||||
|
|
||||||
#dist
|
#dist
|
||||||
|
|
|
||||||
|
|
@ -902,12 +902,11 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
|
||||||
trackview.session().begin_reversible_command (_("add gain control point"));
|
trackview.session().begin_reversible_command (_("add gain control point"));
|
||||||
XMLNode &before = audio_region()->envelope().get_state();
|
XMLNode &before = audio_region()->envelope().get_state();
|
||||||
|
|
||||||
|
|
||||||
if (!audio_region()->envelope_active()) {
|
if (!audio_region()->envelope_active()) {
|
||||||
XMLNode &before = audio_region()->get_state();
|
XMLNode ®ion_before = audio_region()->get_state();
|
||||||
audio_region()->set_envelope_active(true);
|
audio_region()->set_envelope_active(true);
|
||||||
XMLNode &after = audio_region()->get_state();
|
XMLNode ®ion_after = audio_region()->get_state();
|
||||||
trackview.session().add_command (new MementoCommand<AudioRegion>(*(audio_region().get()), &before, &after));
|
trackview.session().add_command (new MementoCommand<AudioRegion>(*(audio_region().get()), ®ion_before, ®ion_after));
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_region()->envelope().add (fx, y);
|
audio_region()->envelope().add (fx, y);
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ AutomationLine::AutomationLine (const string & name, TimeAxisView& tv, ArdourCan
|
||||||
|
|
||||||
alist.StateChanged.connect (mem_fun(*this, &AutomationLine::list_changed));
|
alist.StateChanged.connect (mem_fun(*this, &AutomationLine::list_changed));
|
||||||
|
|
||||||
trackview.session().register_with_memento_command_factory(_id, this);
|
trackview.session().register_with_memento_command_factory(alist.id(), this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -670,11 +670,16 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
|
||||||
uint32_t this_ry = 0;
|
uint32_t this_ry = 0;
|
||||||
uint32_t prev_ry = 0;
|
uint32_t prev_ry = 0;
|
||||||
double* slope;
|
double* slope;
|
||||||
|
double box_size;
|
||||||
|
uint32_t cpsize;
|
||||||
|
|
||||||
/* hide all existing points, and the line */
|
/* hide all existing points, and the line */
|
||||||
|
|
||||||
|
cpsize = 0;
|
||||||
|
|
||||||
for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
|
for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
|
||||||
(*i)->hide();
|
(*i)->hide();
|
||||||
|
++cpsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
line->hide ();
|
line->hide ();
|
||||||
|
|
@ -695,6 +700,13 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
|
||||||
slope[n] = ydelta/xdelta;
|
slope[n] = ydelta/xdelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_height > (guint32) TimeAxisView::Larger) {
|
||||||
|
box_size = 8.0;
|
||||||
|
} else if (_height > (guint32) TimeAxisView::Normal) {
|
||||||
|
box_size = 6.0;
|
||||||
|
} else {
|
||||||
|
box_size = 4.0;
|
||||||
|
}
|
||||||
/* read all points and decide which ones to show as control points */
|
/* read all points and decide which ones to show as control points */
|
||||||
|
|
||||||
view_index = 0;
|
view_index = 0;
|
||||||
|
|
@ -738,27 +750,23 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
|
||||||
this_rx = (uint32_t) rint (tx);
|
this_rx = (uint32_t) rint (tx);
|
||||||
this_ry = (unsigned long) rint (ty);
|
this_ry = (unsigned long) rint (ty);
|
||||||
|
|
||||||
if (view_index && pi != npoints && (this_rx == prev_rx) && (this_ry == prev_ry)) {
|
if (view_index && pi != npoints && (this_rx == prev_rx) && (this_ry == prev_ry) ||
|
||||||
|
((this_rx - prev_rx) < (box_size + 2))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ok, we should display this point */
|
/* ok, we should display this point */
|
||||||
|
|
||||||
if (view_index >= control_points.size()) {
|
if (view_index >= cpsize) {
|
||||||
|
|
||||||
/* make sure we have enough control points */
|
/* make sure we have enough control points */
|
||||||
|
|
||||||
ControlPoint* ncp = new ControlPoint (*this);
|
ControlPoint* ncp = new ControlPoint (*this);
|
||||||
|
|
||||||
if (_height > (guint32) TimeAxisView::Larger) {
|
ncp->set_size (box_size);
|
||||||
ncp->set_size (8.0);
|
|
||||||
} else if (_height > (guint32) TimeAxisView::Normal) {
|
|
||||||
ncp->set_size (6.0);
|
|
||||||
} else {
|
|
||||||
ncp->set_size (4.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
control_points.push_back (ncp);
|
control_points.push_back (ncp);
|
||||||
|
++cpsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlPoint::ShapeType shape;
|
ControlPoint::ShapeType shape;
|
||||||
|
|
@ -829,6 +837,10 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
|
||||||
line_points.push_back (Art::Point (0,0));
|
line_points.push_back (Art::Point (0,0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (line_points.size() > npoints) {
|
||||||
|
line_points.pop_back ();
|
||||||
|
}
|
||||||
|
|
||||||
for (view_index = 0; view_index < npoints; ++view_index) {
|
for (view_index = 0; view_index < npoints; ++view_index) {
|
||||||
line_points[view_index].set_x (control_points[view_index]->get_x());
|
line_points[view_index].set_x (control_points[view_index]->get_x());
|
||||||
line_points[view_index].set_y (control_points[view_index]->get_y());
|
line_points[view_index].set_y (control_points[view_index]->get_y());
|
||||||
|
|
@ -1193,9 +1205,7 @@ AutomationLine::reset_callback (const AutomationList& events)
|
||||||
|
|
||||||
for (ai = events.const_begin(); ai != events.const_end(); ++ai) {
|
for (ai = events.const_begin(); ai != events.const_end(); ++ai) {
|
||||||
|
|
||||||
double translated_y;
|
double translated_y = (*ai)->value;
|
||||||
|
|
||||||
translated_y = (*ai)->value;
|
|
||||||
model_to_view_y (translated_y);
|
model_to_view_y (translated_y);
|
||||||
|
|
||||||
tmp_points.push_back (ALPoint (trackview.editor.frame_to_unit ((*ai)->when),
|
tmp_points.push_back (ALPoint (trackview.editor.frame_to_unit ((*ai)->when),
|
||||||
|
|
@ -1263,16 +1273,16 @@ AutomationLine::hide_all_but_selected_control_points ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLNode &AutomationLine::get_state(void)
|
XMLNode &
|
||||||
|
AutomationLine::get_state (void)
|
||||||
{
|
{
|
||||||
XMLNode *node = new XMLNode("AutomationLine");
|
/* function as a proxy for the model */
|
||||||
node->add_child_nocopy(alist.get_state());
|
return alist.get_state();
|
||||||
return *node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int AutomationLine::set_state(const XMLNode &node)
|
int
|
||||||
|
AutomationLine::set_state (const XMLNode &node)
|
||||||
{
|
{
|
||||||
// TODO
|
/* function as a proxy for the model */
|
||||||
//alist.set_state(node);
|
return alist.set_state (node);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,10 @@ Editor::draw_metric_marks (const Metrics& metrics)
|
||||||
void
|
void
|
||||||
Editor::tempo_map_changed (Change ignored)
|
Editor::tempo_map_changed (Change ignored)
|
||||||
{
|
{
|
||||||
|
if (!session) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::tempo_map_changed), ignored));
|
ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::tempo_map_changed), ignored));
|
||||||
|
|
||||||
BBT_Time previous_beat, next_beat; // the beats previous to the leftmost frame and after the rightmost frame
|
BBT_Time previous_beat, next_beat; // the beats previous to the leftmost frame and after the rightmost frame
|
||||||
|
|
@ -112,13 +116,13 @@ Editor::tempo_map_changed (Change ignored)
|
||||||
previous_beat.ticks = 0;
|
previous_beat.ticks = 0;
|
||||||
|
|
||||||
if (session->tempo_map().meter_at(leftmost_frame + current_page_frames()).beats_per_bar () > next_beat.beats + 1) {
|
if (session->tempo_map().meter_at(leftmost_frame + current_page_frames()).beats_per_bar () > next_beat.beats + 1) {
|
||||||
next_beat.beats += 1;
|
next_beat.beats += 1;
|
||||||
} else {
|
} else {
|
||||||
next_beat.bars += 1;
|
next_beat.bars += 1;
|
||||||
next_beat.beats = 1;
|
next_beat.beats = 1;
|
||||||
}
|
}
|
||||||
next_beat.ticks = 0;
|
next_beat.ticks = 0;
|
||||||
|
|
||||||
if (current_bbt_points) {
|
if (current_bbt_points) {
|
||||||
delete current_bbt_points;
|
delete current_bbt_points;
|
||||||
current_bbt_points = 0;
|
current_bbt_points = 0;
|
||||||
|
|
|
||||||
|
|
@ -63,12 +63,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 = curve.get_state();
|
|
||||||
curve.add (when, y);
|
curve.add (when, y);
|
||||||
XMLNode &after = curve.get_state();
|
XMLNode& after = curve.get_state();
|
||||||
_session.add_command(new MementoCommand<ARDOUR::Curve>(curve, &before, &after));
|
_session.commit_reversible_command (new MementoCommand<ARDOUR::Curve>(curve, &before, &after));
|
||||||
_session.commit_reversible_command ();
|
|
||||||
_session.set_dirty ();
|
_session.set_dirty ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ AudioRegionGainLine::start_drag (ControlPoint* cp, float fraction)
|
||||||
if (!rv.audio_region()->envelope_active()) {
|
if (!rv.audio_region()->envelope_active()) {
|
||||||
trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), &rv.audio_region()->get_state(), 0));
|
trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), &rv.audio_region()->get_state(), 0));
|
||||||
rv.audio_region()->set_envelope_active(false);
|
rv.audio_region()->set_envelope_active(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is an extended copy from AutomationList
|
// This is an extended copy from AutomationList
|
||||||
|
|
@ -65,12 +65,12 @@ AudioRegionGainLine::remove_point (ControlPoint& cp)
|
||||||
XMLNode &before = get_state();
|
XMLNode &before = get_state();
|
||||||
|
|
||||||
if (!rv.audio_region()->envelope_active()) {
|
if (!rv.audio_region()->envelope_active()) {
|
||||||
XMLNode &before = rv.audio_region()->get_state();
|
XMLNode ®ion_before = rv.audio_region()->get_state();
|
||||||
rv.audio_region()->set_envelope_active(true);
|
rv.audio_region()->set_envelope_active(true);
|
||||||
XMLNode &after = rv.audio_region()->get_state();
|
XMLNode ®ion_after = rv.audio_region()->get_state();
|
||||||
trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), &before, &after));
|
trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), ®ion_before, ®ion_after));
|
||||||
}
|
}
|
||||||
|
|
||||||
alist.erase (mr.start, mr.end);
|
alist.erase (mr.start, mr.end);
|
||||||
|
|
||||||
trackview.editor.current_session()->add_command (new MementoCommand<AudioRegionGainLine>(*this, &before, &get_state()));
|
trackview.editor.current_session()->add_command (new MementoCommand<AudioRegionGainLine>(*this, &before, &get_state()));
|
||||||
|
|
@ -84,7 +84,8 @@ AudioRegionGainLine::end_drag (ControlPoint* cp)
|
||||||
if (!rv.audio_region()->envelope_active()) {
|
if (!rv.audio_region()->envelope_active()) {
|
||||||
rv.audio_region()->set_envelope_active(true);
|
rv.audio_region()->set_envelope_active(true);
|
||||||
trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), 0, &rv.audio_region()->get_state()));
|
trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), 0, &rv.audio_region()->get_state()));
|
||||||
}
|
}
|
||||||
|
|
||||||
AutomationLine::end_drag(cp);
|
AutomationLine::end_drag(cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -153,8 +153,6 @@ class RouteUI : public virtual AxisView
|
||||||
|
|
||||||
void reversibly_apply_route_boolean (string name, void (ARDOUR::Route::*func)(bool, void*), bool, void *);
|
void reversibly_apply_route_boolean (string name, void (ARDOUR::Route::*func)(bool, void*), bool, void *);
|
||||||
void reversibly_apply_audio_track_boolean (string name, void (ARDOUR::AudioTrack::*func)(bool, void*), bool, void *);
|
void reversibly_apply_audio_track_boolean (string name, void (ARDOUR::AudioTrack::*func)(bool, void*), bool, void *);
|
||||||
|
|
||||||
sigc::signal<void> GoingAway;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __ardour_route_ui__ */
|
#endif /* __ardour_route_ui__ */
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@ class AudioTrack : public Track
|
||||||
bool meter);
|
bool meter);
|
||||||
|
|
||||||
uint32_t n_process_buffers ();
|
uint32_t n_process_buffers ();
|
||||||
|
|
||||||
|
int _set_state (const XMLNode&, bool call_base);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int set_diskstream (boost::shared_ptr<AudioDiskstream>, void *);
|
int set_diskstream (boost::shared_ptr<AudioDiskstream>, void *);
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,8 @@ class AutomationList : public PBD::StatefulDestructible
|
||||||
typedef AutomationEventList::iterator iterator;
|
typedef AutomationEventList::iterator iterator;
|
||||||
typedef AutomationEventList::const_iterator const_iterator;
|
typedef AutomationEventList::const_iterator const_iterator;
|
||||||
|
|
||||||
AutomationList(double default_value, bool no_state = false);
|
AutomationList (double default_value);
|
||||||
|
AutomationList (const XMLNode&);
|
||||||
~AutomationList();
|
~AutomationList();
|
||||||
|
|
||||||
AutomationList (const AutomationList&);
|
AutomationList (const AutomationList&);
|
||||||
|
|
@ -151,8 +152,10 @@ class AutomationList : public PBD::StatefulDestructible
|
||||||
|
|
||||||
sigc::signal<void,Change> StateChanged;
|
sigc::signal<void,Change> StateChanged;
|
||||||
|
|
||||||
XMLNode &get_state(void);
|
XMLNode& get_state(void);
|
||||||
int set_state (const XMLNode &s);
|
int set_state (const XMLNode &s);
|
||||||
|
XMLNode& state (bool full);
|
||||||
|
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; }
|
||||||
|
|
@ -204,11 +207,11 @@ class AutomationList : public PBD::StatefulDestructible
|
||||||
double min_yval;
|
double min_yval;
|
||||||
double max_yval;
|
double max_yval;
|
||||||
double default_value;
|
double default_value;
|
||||||
bool no_state;
|
|
||||||
|
|
||||||
iterator rt_insertion_point;
|
iterator rt_insertion_point;
|
||||||
double rt_pos;
|
double rt_pos;
|
||||||
|
|
||||||
|
void fast_simple_add (double when, double value);
|
||||||
void maybe_signal_changed ();
|
void maybe_signal_changed ();
|
||||||
void mark_dirty ();
|
void mark_dirty ();
|
||||||
void _x_scale (double factor);
|
void _x_scale (double factor);
|
||||||
|
|
@ -235,6 +238,8 @@ class AutomationList : public PBD::StatefulDestructible
|
||||||
virtual ControlEvent* point_factory (const ControlEvent&) const;
|
virtual ControlEvent* point_factory (const ControlEvent&) const;
|
||||||
|
|
||||||
AutomationList* cut_copy_clear (double, double, int op);
|
AutomationList* cut_copy_clear (double, double, int op);
|
||||||
|
|
||||||
|
int deserialize_events (const XMLNode&);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ class Curve : public AutomationList
|
||||||
~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&);
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,7 @@ class PluginInsert : public Insert
|
||||||
nframes_t latency();
|
nframes_t latency();
|
||||||
|
|
||||||
void transport_stopped (nframes_t now);
|
void transport_stopped (nframes_t now);
|
||||||
|
void automation_snapshot (nframes_t now);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,9 +67,11 @@ class IO : public PBD::StatefulDestructible
|
||||||
IO (Session&, string name,
|
IO (Session&, string name,
|
||||||
int input_min = -1, int input_max = -1,
|
int input_min = -1, int input_max = -1,
|
||||||
int output_min = -1, int output_max = -1,
|
int output_min = -1, int output_max = -1,
|
||||||
DataType default_type = DataType::AUDIO);
|
DataType default_type = DataType::AUDIO);
|
||||||
|
|
||||||
virtual ~IO();
|
IO (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
|
||||||
|
|
||||||
|
virtual ~IO();
|
||||||
|
|
||||||
int input_minimum() const { return _input_minimum; }
|
int input_minimum() const { return _input_minimum; }
|
||||||
int input_maximum() const { return _input_maximum; }
|
int input_maximum() const { return _input_maximum; }
|
||||||
|
|
@ -205,6 +207,14 @@ public:
|
||||||
|
|
||||||
/* automation */
|
/* automation */
|
||||||
|
|
||||||
|
static void set_automation_interval (jack_nframes_t frames) {
|
||||||
|
_automation_interval = frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jack_nframes_t automation_interval() {
|
||||||
|
return _automation_interval;
|
||||||
|
}
|
||||||
|
|
||||||
void clear_automation ();
|
void clear_automation ();
|
||||||
|
|
||||||
bool gain_automation_recording() const {
|
bool gain_automation_recording() const {
|
||||||
|
|
@ -226,6 +236,7 @@ public:
|
||||||
sigc::signal<void> gain_automation_style_changed;
|
sigc::signal<void> gain_automation_style_changed;
|
||||||
|
|
||||||
virtual void transport_stopped (nframes_t now);
|
virtual void transport_stopped (nframes_t now);
|
||||||
|
void automation_snapshot (nframes_t now);
|
||||||
|
|
||||||
ARDOUR::Curve& gain_automation_curve () { return _gain_automation_curve; }
|
ARDOUR::Curve& gain_automation_curve () { return _gain_automation_curve; }
|
||||||
|
|
||||||
|
|
@ -289,6 +300,9 @@ public:
|
||||||
|
|
||||||
GainControllable _gain_control;
|
GainControllable _gain_control;
|
||||||
|
|
||||||
|
nframes_t last_automation_snapshot;
|
||||||
|
static nframes_t _automation_interval;
|
||||||
|
|
||||||
AutoState _gain_automation_state;
|
AutoState _gain_automation_state;
|
||||||
AutoStyle _gain_automation_style;
|
AutoStyle _gain_automation_style;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,7 @@ class Route : public IO
|
||||||
|
|
||||||
Route (Session&, std::string name, int input_min, int input_max, int output_min, int output_max,
|
Route (Session&, std::string name, int input_min, int input_max, int output_min, int output_max,
|
||||||
Flag flags = Flag(0), DataType default_type = DataType::AUDIO);
|
Flag flags = Flag(0), DataType default_type = DataType::AUDIO);
|
||||||
|
Route (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
|
||||||
Route (Session&, const XMLNode&);
|
|
||||||
virtual ~Route();
|
virtual ~Route();
|
||||||
|
|
||||||
std::string comment() { return _comment; }
|
std::string comment() { return _comment; }
|
||||||
|
|
@ -233,6 +232,7 @@ class Route : public IO
|
||||||
return _mute_control;
|
return _mute_control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void automation_snapshot (nframes_t now);
|
||||||
void protect_automation ();
|
void protect_automation ();
|
||||||
|
|
||||||
void set_remote_control_id (uint32_t id);
|
void set_remote_control_id (uint32_t id);
|
||||||
|
|
@ -315,6 +315,8 @@ class Route : public IO
|
||||||
uint32_t pans_required() const;
|
uint32_t pans_required() const;
|
||||||
uint32_t n_process_buffers ();
|
uint32_t n_process_buffers ();
|
||||||
|
|
||||||
|
virtual int _set_state (const XMLNode&, bool call_base);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init ();
|
void init ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,11 +91,17 @@ namespace ARDOUR {
|
||||||
Play = 0x4
|
Play = 0x4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::string auto_state_to_string (AutoState);
|
||||||
|
AutoState string_to_auto_state (std::string);
|
||||||
|
|
||||||
enum AutoStyle {
|
enum AutoStyle {
|
||||||
Absolute = 0x1,
|
Absolute = 0x1,
|
||||||
Trim = 0x2
|
Trim = 0x2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::string auto_style_to_string (AutoStyle);
|
||||||
|
AutoStyle string_to_auto_style (std::string);
|
||||||
|
|
||||||
enum AlignStyle {
|
enum AlignStyle {
|
||||||
CaptureTime,
|
CaptureTime,
|
||||||
ExistingMaterial
|
ExistingMaterial
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode
|
||||||
AudioTrack::AudioTrack (Session& sess, const XMLNode& node)
|
AudioTrack::AudioTrack (Session& sess, const XMLNode& node)
|
||||||
: Track (sess, node)
|
: Track (sess, node)
|
||||||
{
|
{
|
||||||
set_state (node);
|
_set_state (node, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioTrack::~AudioTrack ()
|
AudioTrack::~AudioTrack ()
|
||||||
|
|
@ -187,12 +187,20 @@ AudioTrack::audio_diskstream() const
|
||||||
|
|
||||||
int
|
int
|
||||||
AudioTrack::set_state (const XMLNode& node)
|
AudioTrack::set_state (const XMLNode& node)
|
||||||
|
{
|
||||||
|
return _set_state (node, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
AudioTrack::_set_state (const XMLNode& node, bool call_base)
|
||||||
{
|
{
|
||||||
const XMLProperty *prop;
|
const XMLProperty *prop;
|
||||||
XMLNodeConstIterator iter;
|
XMLNodeConstIterator iter;
|
||||||
|
|
||||||
if (Route::set_state (node)) {
|
if (call_base) {
|
||||||
return -1;
|
if (Route::set_state (node)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((prop = node.property (X_("mode"))) != 0) {
|
if ((prop = node.property (X_("mode"))) != 0) {
|
||||||
|
|
@ -507,6 +515,16 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
|
||||||
nframes_t transport_frame;
|
nframes_t transport_frame;
|
||||||
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
|
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
|
||||||
|
|
||||||
|
{
|
||||||
|
Glib::RWLock::ReaderLock lm (redirect_lock, Glib::TRY_LOCK);
|
||||||
|
if (lm.locked()) {
|
||||||
|
// automation snapshot can also be called from the non-rt context
|
||||||
|
// and it uses the redirect list, so we take the lock out here
|
||||||
|
automation_snapshot (start_frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (n_outputs() == 0 && _redirects.empty()) {
|
if (n_outputs() == 0 && _redirects.empty()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,14 +47,13 @@ static void dumpit (const AutomationList& al, string prefix = "")
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AutomationList::AutomationList (double defval, bool with_state)
|
AutomationList::AutomationList (double defval)
|
||||||
{
|
{
|
||||||
_frozen = false;
|
_frozen = false;
|
||||||
changed_when_thawed = false;
|
changed_when_thawed = false;
|
||||||
_state = Off;
|
_state = Off;
|
||||||
_style = Absolute;
|
_style = Absolute;
|
||||||
_touching = false;
|
_touching = false;
|
||||||
no_state = with_state;
|
|
||||||
min_yval = FLT_MIN;
|
min_yval = FLT_MIN;
|
||||||
max_yval = FLT_MAX;
|
max_yval = FLT_MAX;
|
||||||
max_xval = 0; // means "no limit"
|
max_xval = 0; // means "no limit"
|
||||||
|
|
@ -80,7 +79,6 @@ AutomationList::AutomationList (const AutomationList& other)
|
||||||
_touching = other._touching;
|
_touching = other._touching;
|
||||||
_dirty = false;
|
_dirty = false;
|
||||||
rt_insertion_point = events.end();
|
rt_insertion_point = events.end();
|
||||||
no_state = other.no_state;
|
|
||||||
lookup_cache.left = -1;
|
lookup_cache.left = -1;
|
||||||
lookup_cache.range.first = events.end();
|
lookup_cache.range.first = events.end();
|
||||||
|
|
||||||
|
|
@ -108,7 +106,6 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
|
||||||
_touching = other._touching;
|
_touching = other._touching;
|
||||||
_dirty = false;
|
_dirty = false;
|
||||||
rt_insertion_point = events.end();
|
rt_insertion_point = events.end();
|
||||||
no_state = other.no_state;
|
|
||||||
lookup_cache.left = -1;
|
lookup_cache.left = -1;
|
||||||
lookup_cache.range.first = events.end();
|
lookup_cache.range.first = events.end();
|
||||||
|
|
||||||
|
|
@ -125,13 +122,34 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
|
||||||
delete section;
|
delete section;
|
||||||
|
|
||||||
mark_dirty ();
|
mark_dirty ();
|
||||||
|
|
||||||
|
AutomationListCreated(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
AutomationList::AutomationList (const XMLNode& node)
|
||||||
|
{
|
||||||
|
_frozen = false;
|
||||||
|
changed_when_thawed = false;
|
||||||
|
_touching = false;
|
||||||
|
min_yval = FLT_MIN;
|
||||||
|
max_yval = FLT_MAX;
|
||||||
|
max_xval = 0; // means "no limit"
|
||||||
|
_dirty = false;
|
||||||
|
_state = Off;
|
||||||
|
_style = Absolute;
|
||||||
|
rt_insertion_point = events.end();
|
||||||
|
lookup_cache.left = -1;
|
||||||
|
lookup_cache.range.first = events.end();
|
||||||
|
|
||||||
|
set_state (node);
|
||||||
|
|
||||||
AutomationListCreated(this);
|
AutomationListCreated(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
AutomationList::~AutomationList()
|
AutomationList::~AutomationList()
|
||||||
{
|
{
|
||||||
GoingAway ();
|
GoingAway ();
|
||||||
|
|
||||||
for (AutomationEventList::iterator x = events.begin(); x != events.end(); ++x) {
|
for (AutomationEventList::iterator x = events.begin(); x != events.end(); ++x) {
|
||||||
delete (*x);
|
delete (*x);
|
||||||
}
|
}
|
||||||
|
|
@ -346,12 +364,19 @@ AutomationList::rt_add (double when, double value)
|
||||||
maybe_signal_changed ();
|
maybe_signal_changed ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AutomationList::fast_simple_add (double when, double value)
|
||||||
|
{
|
||||||
|
/* to be used only for loading pre-sorted data from saved state */
|
||||||
|
events.insert (events.end(), point_factory (when, value));
|
||||||
|
}
|
||||||
|
|
||||||
#undef last_rt_insertion_point
|
#undef last_rt_insertion_point
|
||||||
|
|
||||||
void
|
void
|
||||||
AutomationList::add (double when, double value)
|
AutomationList::add (double when, double value)
|
||||||
{
|
{
|
||||||
/* this is for graphical editing and loading data from storage */
|
/* this is for graphical editing */
|
||||||
|
|
||||||
{
|
{
|
||||||
Glib::Mutex::Lock lm (lock);
|
Glib::Mutex::Lock lm (lock);
|
||||||
|
|
@ -395,11 +420,6 @@ AutomationList::erase (AutomationList::iterator i)
|
||||||
Glib::Mutex::Lock lm (lock);
|
Glib::Mutex::Lock lm (lock);
|
||||||
events.erase (i);
|
events.erase (i);
|
||||||
reposition_for_rt_add (0);
|
reposition_for_rt_add (0);
|
||||||
if (!no_state) {
|
|
||||||
#ifdef STATE_MANAGER
|
|
||||||
save_state (_("removed event"));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
mark_dirty ();
|
mark_dirty ();
|
||||||
}
|
}
|
||||||
maybe_signal_changed ();
|
maybe_signal_changed ();
|
||||||
|
|
@ -1118,66 +1138,179 @@ AutomationList::point_factory (const ControlEvent& other) const
|
||||||
XMLNode&
|
XMLNode&
|
||||||
AutomationList::get_state ()
|
AutomationList::get_state ()
|
||||||
{
|
{
|
||||||
stringstream str;
|
return state (true);
|
||||||
XMLNode* node = new XMLNode (X_("events"));
|
}
|
||||||
iterator xx;
|
|
||||||
|
|
||||||
if (events.empty()) {
|
XMLNode&
|
||||||
return *node;
|
AutomationList::state (bool full)
|
||||||
|
{
|
||||||
|
XMLNode* root = new XMLNode (X_("AutomationList"));
|
||||||
|
char buf[64];
|
||||||
|
LocaleGuard lg (X_("POSIX"));
|
||||||
|
|
||||||
|
root->add_property ("id", _id.to_s());
|
||||||
|
|
||||||
|
snprintf (buf, sizeof (buf), "%.12g", default_value);
|
||||||
|
root->add_property ("default", buf);
|
||||||
|
snprintf (buf, sizeof (buf), "%.12g", min_yval);
|
||||||
|
root->add_property ("min_yval", buf);
|
||||||
|
snprintf (buf, sizeof (buf), "%.12g", max_yval);
|
||||||
|
root->add_property ("max_yval", buf);
|
||||||
|
snprintf (buf, sizeof (buf), "%.12g", max_xval);
|
||||||
|
root->add_property ("max_xval", buf);
|
||||||
|
|
||||||
|
if (full) {
|
||||||
|
root->add_property ("state", auto_state_to_string (_state));
|
||||||
|
} else {
|
||||||
|
/* never save anything but Off for automation state to a template */
|
||||||
|
root->add_property ("state", auto_state_to_string (Off));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (xx = events.begin(); xx != events.end(); ++xx) {
|
root->add_property ("style", auto_style_to_string (_style));
|
||||||
|
|
||||||
|
if (!events.empty()) {
|
||||||
|
root->add_child_nocopy (serialize_events());
|
||||||
|
}
|
||||||
|
|
||||||
|
return *root;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLNode&
|
||||||
|
AutomationList::serialize_events ()
|
||||||
|
{
|
||||||
|
XMLNode* node = new XMLNode (X_("events"));
|
||||||
|
stringstream str;
|
||||||
|
|
||||||
|
for (iterator xx = events.begin(); xx != events.end(); ++xx) {
|
||||||
str << (double) (*xx)->when;
|
str << (double) (*xx)->when;
|
||||||
str << ' ';
|
str << ' ';
|
||||||
str <<(double) (*xx)->value;
|
str <<(double) (*xx)->value;
|
||||||
str << '\n';
|
str << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
node->add_content (str.str());
|
/* XML is a bit wierd */
|
||||||
|
|
||||||
|
XMLNode* content_node = new XMLNode (X_("foo")); /* it gets renamed by libxml when we set content */
|
||||||
|
content_node->set_content (str.str());
|
||||||
|
|
||||||
|
node->add_child_nocopy (*content_node);
|
||||||
|
|
||||||
return *node;
|
return *node;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
AutomationList::set_state (const XMLNode& node)
|
AutomationList::deserialize_events (const XMLNode& node)
|
||||||
{
|
{
|
||||||
if (node.name() != X_("events")) {
|
if (node.children().empty()) {
|
||||||
warning << _("automation list: passed XML node not called \"events\" - ignored.") << endmsg;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLNode* content_node = node.children().front();
|
||||||
|
|
||||||
|
if (content_node->content().empty()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeze ();
|
freeze ();
|
||||||
clear ();
|
clear ();
|
||||||
|
|
||||||
if (!node.content().empty()) {
|
stringstream str (content_node->content());
|
||||||
|
|
||||||
stringstream str (node.content());
|
double x;
|
||||||
|
double y;
|
||||||
double x;
|
bool ok = true;
|
||||||
double y;
|
|
||||||
bool ok = true;
|
while (str) {
|
||||||
|
str >> x;
|
||||||
while (str) {
|
if (!str) {
|
||||||
str >> x;
|
break;
|
||||||
if (!str) {
|
|
||||||
ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str >> y;
|
|
||||||
if (!str) {
|
|
||||||
ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
add (x, y);
|
|
||||||
}
|
}
|
||||||
|
str >> y;
|
||||||
if (!ok) {
|
if (!str) {
|
||||||
clear ();
|
ok = false;
|
||||||
error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg;
|
break;
|
||||||
}
|
}
|
||||||
|
fast_simple_add (x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
clear ();
|
||||||
|
error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg;
|
||||||
|
} else {
|
||||||
|
mark_dirty ();
|
||||||
|
reposition_for_rt_add (0);
|
||||||
|
maybe_signal_changed ();
|
||||||
}
|
}
|
||||||
|
|
||||||
thaw ();
|
thaw ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
AutomationList::set_state (const XMLNode& node)
|
||||||
|
{
|
||||||
|
XMLNodeList nlist = node.children();
|
||||||
|
XMLNodeIterator niter;
|
||||||
|
const XMLProperty* prop;
|
||||||
|
|
||||||
|
if (node.name() == X_("events")) {
|
||||||
|
/* partial state setting*/
|
||||||
|
return deserialize_events (node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.name() != X_("AutomationList") ) {
|
||||||
|
error << string_compose (_("AutomationList: passed XML node called %1, not \"AutomationList\" - ignored"), node.name()) << endmsg;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prop = node.property ("id")) != 0) {
|
||||||
|
_id = prop->value ();
|
||||||
|
/* update session AL list */
|
||||||
|
AutomationListCreated(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prop = node.property (X_("default"))) != 0){
|
||||||
|
default_value = atof (prop->value());
|
||||||
|
} else {
|
||||||
|
default_value = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prop = node.property (X_("style"))) != 0) {
|
||||||
|
_style = string_to_auto_style (prop->value());
|
||||||
|
} else {
|
||||||
|
_style = Absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prop = node.property (X_("state"))) != 0) {
|
||||||
|
_state = string_to_auto_state (prop->value());
|
||||||
|
} else {
|
||||||
|
_state = Off;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prop = node.property (X_("min_yval"))) != 0) {
|
||||||
|
min_yval = atof (prop->value ());
|
||||||
|
} else {
|
||||||
|
min_yval = FLT_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prop = node.property (X_("max_yval"))) != 0) {
|
||||||
|
max_yval = atof (prop->value ());
|
||||||
|
} else {
|
||||||
|
max_yval = FLT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prop = node.property (X_("max_xval"))) != 0) {
|
||||||
|
max_xval = atof (prop->value ());
|
||||||
|
} else {
|
||||||
|
max_xval = 0; // means "no limit ;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
||||||
|
if ((*niter)->name() == X_("events")) {
|
||||||
|
deserialize_events (*(*niter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,14 +40,11 @@ using namespace ARDOUR;
|
||||||
using namespace sigc;
|
using namespace sigc;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
sigc::signal<void, Curve*> Curve::CurveCreated;
|
|
||||||
|
|
||||||
Curve::Curve (double minv, double maxv, double canv, bool nostate)
|
Curve::Curve (double minv, double maxv, double canv, bool nostate)
|
||||||
: AutomationList (canv, nostate)
|
: AutomationList (canv)
|
||||||
{
|
{
|
||||||
min_yval = minv;
|
min_yval = minv;
|
||||||
max_yval = maxv;
|
max_yval = maxv;
|
||||||
CurveCreated(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Curve::Curve (const Curve& other)
|
Curve::Curve (const Curve& other)
|
||||||
|
|
@ -55,7 +52,6 @@ Curve::Curve (const Curve& other)
|
||||||
{
|
{
|
||||||
min_yval = other.min_yval;
|
min_yval = other.min_yval;
|
||||||
max_yval = other.max_yval;
|
max_yval = other.max_yval;
|
||||||
CurveCreated(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Curve::Curve (const Curve& other, double start, double end)
|
Curve::Curve (const Curve& other, double start, double end)
|
||||||
|
|
@ -63,7 +59,11 @@ Curve::Curve (const Curve& other, double start, double end)
|
||||||
{
|
{
|
||||||
min_yval = other.min_yval;
|
min_yval = other.min_yval;
|
||||||
max_yval = other.max_yval;
|
max_yval = other.max_yval;
|
||||||
CurveCreated(this);
|
}
|
||||||
|
|
||||||
|
Curve::Curve (const XMLNode& node)
|
||||||
|
: AutomationList (node)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Curve::~Curve ()
|
Curve::~Curve ()
|
||||||
|
|
|
||||||
|
|
@ -310,6 +310,23 @@ PluginInsert::connect_and_run (vector<Sample*>& bufs, uint32_t nbufs, nframes_t
|
||||||
/* leave remaining channel buffers alone */
|
/* leave remaining channel buffers alone */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PluginInsert::automation_snapshot (nframes_t now)
|
||||||
|
{
|
||||||
|
map<uint32_t,AutomationList*>::iterator li;
|
||||||
|
|
||||||
|
for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
|
||||||
|
|
||||||
|
AutomationList *alist = ((*li).second);
|
||||||
|
if (alist != 0 && alist->automation_write ()) {
|
||||||
|
|
||||||
|
float val = _plugins[0]->get_parameter ((*li).first);
|
||||||
|
alist->rt_add (now, val);
|
||||||
|
last_automation_snapshot = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PluginInsert::transport_stopped (nframes_t now)
|
PluginInsert::transport_stopped (nframes_t now)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ using namespace std;
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
|
nframes_t IO::_automation_interval = 0;
|
||||||
const string IO::state_node_name = "IO";
|
const string IO::state_node_name = "IO";
|
||||||
bool IO::connecting_legal = false;
|
bool IO::connecting_legal = false;
|
||||||
bool IO::ports_legal = false;
|
bool IO::ports_legal = false;
|
||||||
|
|
@ -124,6 +125,8 @@ IO::IO (Session& s, string name,
|
||||||
apply_gain_automation = false;
|
apply_gain_automation = false;
|
||||||
_ignore_gain_on_deliver = false;
|
_ignore_gain_on_deliver = false;
|
||||||
|
|
||||||
|
last_automation_snapshot = 0;
|
||||||
|
|
||||||
_gain_automation_state = Off;
|
_gain_automation_state = Off;
|
||||||
_gain_automation_style = Absolute;
|
_gain_automation_style = Absolute;
|
||||||
|
|
||||||
|
|
@ -137,6 +140,38 @@ IO::IO (Session& s, string name,
|
||||||
_session.add_controllable (&_gain_control);
|
_session.add_controllable (&_gain_control);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IO::IO (Session& s, const XMLNode& node, DataType dt)
|
||||||
|
: _session (s),
|
||||||
|
_default_type (dt),
|
||||||
|
_gain_control (X_("gaincontrol"), *this),
|
||||||
|
_gain_automation_curve (0, 0, 0) // all reset in set_state()
|
||||||
|
{
|
||||||
|
_panner = 0;
|
||||||
|
deferred_state = 0;
|
||||||
|
no_panner_reset = false;
|
||||||
|
_desired_gain = 1.0;
|
||||||
|
_gain = 1.0;
|
||||||
|
_input_connection = 0;
|
||||||
|
_output_connection = 0;
|
||||||
|
_ninputs = 0;
|
||||||
|
_noutputs = 0;
|
||||||
|
|
||||||
|
apply_gain_automation = false;
|
||||||
|
_ignore_gain_on_deliver = false;
|
||||||
|
|
||||||
|
set_state (node);
|
||||||
|
|
||||||
|
{
|
||||||
|
// IO::Meter is emitted from another thread so the
|
||||||
|
// Meter signal must be protected.
|
||||||
|
Glib::Mutex::Lock guard (m_meter_signal_lock);
|
||||||
|
m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
|
||||||
|
}
|
||||||
|
|
||||||
|
_session.add_controllable (&_gain_control);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
IO::~IO ()
|
IO::~IO ()
|
||||||
{
|
{
|
||||||
Glib::Mutex::Lock guard (m_meter_signal_lock);
|
Glib::Mutex::Lock guard (m_meter_signal_lock);
|
||||||
|
|
@ -1535,15 +1570,9 @@ IO::state (bool full_state)
|
||||||
snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
|
snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
|
||||||
}
|
}
|
||||||
|
|
||||||
node->add_property ("automation-state", buf);
|
|
||||||
snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
|
|
||||||
node->add_property ("automation-style", buf);
|
|
||||||
|
|
||||||
return *node;
|
return *node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
IO::set_state (const XMLNode& node)
|
IO::set_state (const XMLNode& node)
|
||||||
{
|
{
|
||||||
|
|
@ -1585,6 +1614,9 @@ IO::set_state (const XMLNode& node)
|
||||||
for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
|
for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
|
||||||
|
|
||||||
if ((*iter)->name() == "Panner") {
|
if ((*iter)->name() == "Panner") {
|
||||||
|
if (_panner == 0) {
|
||||||
|
_panner = new Panner (_name, _session);
|
||||||
|
}
|
||||||
_panner->set_state (**iter);
|
_panner->set_state (**iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1598,20 +1630,6 @@ IO::set_state (const XMLNode& node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((prop = node.property ("automation-state")) != 0) {
|
|
||||||
|
|
||||||
long int x;
|
|
||||||
x = strtol (prop->value().c_str(), 0, 16);
|
|
||||||
set_gain_automation_state (AutoState (x));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((prop = node.property ("automation-style")) != 0) {
|
|
||||||
|
|
||||||
long int x;
|
|
||||||
x = strtol (prop->value().c_str(), 0, 16);
|
|
||||||
set_gain_automation_style (AutoStyle (x));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ports_legal) {
|
if (ports_legal) {
|
||||||
|
|
||||||
if (create_ports (node)) {
|
if (create_ports (node)) {
|
||||||
|
|
@ -1644,6 +1662,8 @@ IO::set_state (const XMLNode& node)
|
||||||
pending_state_node = new XMLNode (node);
|
pending_state_node = new XMLNode (node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last_automation_snapshot = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2398,6 +2418,7 @@ IO::set_gain_automation_state (AutoState state)
|
||||||
|
|
||||||
if (state != _gain_automation_curve.automation_state()) {
|
if (state != _gain_automation_curve.automation_state()) {
|
||||||
changed = true;
|
changed = true;
|
||||||
|
last_automation_snapshot = 0;
|
||||||
_gain_automation_curve.set_automation_state (state);
|
_gain_automation_curve.set_automation_state (state);
|
||||||
|
|
||||||
if (state != Off) {
|
if (state != Off) {
|
||||||
|
|
@ -2495,6 +2516,21 @@ IO::end_pan_touch (uint32_t which)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IO::automation_snapshot (nframes_t now)
|
||||||
|
{
|
||||||
|
if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
|
||||||
|
|
||||||
|
if (gain_automation_recording()) {
|
||||||
|
_gain_automation_curve.rt_add (now, gain());
|
||||||
|
}
|
||||||
|
|
||||||
|
_panner->snapshot (now);
|
||||||
|
|
||||||
|
last_automation_snapshot = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IO::transport_stopped (nframes_t frame)
|
IO::transport_stopped (nframes_t frame)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -473,20 +473,12 @@ EqualPowerStereoPanner::state (bool full_state)
|
||||||
root->add_property (X_("x"), buf);
|
root->add_property (X_("x"), buf);
|
||||||
root->add_property (X_("type"), EqualPowerStereoPanner::name);
|
root->add_property (X_("type"), EqualPowerStereoPanner::name);
|
||||||
|
|
||||||
if (full_state) {
|
XMLNode* autonode = new XMLNode (X_("Automation"));
|
||||||
XMLNode* autonode = new XMLNode (X_("Automation"));
|
autonode->add_child_nocopy (_automation.state (full_state));
|
||||||
autonode->add_child_nocopy (_automation.get_state ());
|
root->add_child_nocopy (*autonode);
|
||||||
root->add_child_nocopy (*autonode);
|
|
||||||
} else {
|
|
||||||
/* never store automation states other than off in a template */
|
|
||||||
snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
|
|
||||||
}
|
|
||||||
|
|
||||||
root->add_property (X_("automation-state"), buf);
|
|
||||||
snprintf (buf, sizeof (buf), "0x%x", _automation.automation_style());
|
|
||||||
root->add_property (X_("automation-style"), buf);
|
|
||||||
|
|
||||||
StreamPanner::add_state (*root);
|
StreamPanner::add_state (*root);
|
||||||
|
|
||||||
root->add_child_nocopy (_control.get_state ());
|
root->add_child_nocopy (_control.get_state ());
|
||||||
|
|
||||||
return *root;
|
return *root;
|
||||||
|
|
@ -496,7 +488,6 @@ int
|
||||||
EqualPowerStereoPanner::set_state (const XMLNode& node)
|
EqualPowerStereoPanner::set_state (const XMLNode& node)
|
||||||
{
|
{
|
||||||
const XMLProperty* prop;
|
const XMLProperty* prop;
|
||||||
int x;
|
|
||||||
float pos;
|
float pos;
|
||||||
LocaleGuard lg (X_("POSIX"));
|
LocaleGuard lg (X_("POSIX"));
|
||||||
|
|
||||||
|
|
@ -508,27 +499,21 @@ EqualPowerStereoPanner::set_state (const XMLNode& node)
|
||||||
StreamPanner::set_state (node);
|
StreamPanner::set_state (node);
|
||||||
|
|
||||||
for (XMLNodeConstIterator iter = node.children().begin(); iter != node.children().end(); ++iter) {
|
for (XMLNodeConstIterator iter = node.children().begin(); iter != node.children().end(); ++iter) {
|
||||||
|
|
||||||
if ((*iter)->name() == X_("panner")) {
|
if ((*iter)->name() == X_("panner")) {
|
||||||
|
|
||||||
_control.set_state (**iter);
|
_control.set_state (**iter);
|
||||||
|
|
||||||
} else if ((*iter)->name() == X_("Automation")) {
|
} else if ((*iter)->name() == X_("Automation")) {
|
||||||
|
|
||||||
_automation.set_state (*((*iter)->children().front()));
|
_automation.set_state (*((*iter)->children().front()));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((prop = node.property (X_("automation-state")))) {
|
|
||||||
sscanf (prop->value().c_str(), "0x%x", &x);
|
|
||||||
_automation.set_automation_state ((AutoState) x);
|
|
||||||
|
|
||||||
if (x != Off) {
|
if (_automation.automation_state() != Off) {
|
||||||
set_position (_automation.eval (parent.session().transport_frame()));
|
set_position (_automation.eval (parent.session().transport_frame()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((prop = node.property (X_("automation-style")))) {
|
|
||||||
sscanf (prop->value().c_str(), "0x%x", &x);
|
|
||||||
_automation.set_automation_style ((AutoStyle) x);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,23 +108,23 @@ Redirect::set_placement (const string& str, void *src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* NODE STRUCTURE
|
||||||
|
|
||||||
|
<Automation [optionally with visible="...." ]>
|
||||||
|
<parameter-N>
|
||||||
|
<AutomationList id=N>
|
||||||
|
<events>
|
||||||
|
X1 Y1
|
||||||
|
X2 Y2
|
||||||
|
....
|
||||||
|
</events>
|
||||||
|
</parameter-N>
|
||||||
|
<Automation>
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
Redirect::set_automation_state (const XMLNode& node)
|
Redirect::set_automation_state (const XMLNode& node)
|
||||||
{
|
{
|
||||||
/* NODE STRUCTURE
|
|
||||||
|
|
||||||
<Automation [optionally with visible="...." ]>
|
|
||||||
<parameter-N>
|
|
||||||
<events>
|
|
||||||
X1 Y1
|
|
||||||
X2 Y2
|
|
||||||
....
|
|
||||||
</events>
|
|
||||||
</parameter-N>
|
|
||||||
<Automation>
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
Glib::Mutex::Lock lm (_automation_lock);
|
Glib::Mutex::Lock lm (_automation_lock);
|
||||||
|
|
||||||
parameter_automation.clear ();
|
parameter_automation.clear ();
|
||||||
|
|
@ -157,20 +157,6 @@ Redirect::set_automation_state (const XMLNode& node)
|
||||||
XMLNode&
|
XMLNode&
|
||||||
Redirect::get_automation_state ()
|
Redirect::get_automation_state ()
|
||||||
{
|
{
|
||||||
/* NODE STRUCTURE
|
|
||||||
|
|
||||||
<Automation [optionally with visible="...." ]>
|
|
||||||
<parameter-N>
|
|
||||||
<events>
|
|
||||||
X1 Y1
|
|
||||||
X2 Y2
|
|
||||||
....
|
|
||||||
</events>
|
|
||||||
</parameter-N>
|
|
||||||
<Automation>
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
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;
|
string fullpath;
|
||||||
|
|
@ -217,20 +203,6 @@ Redirect::state (bool full_state)
|
||||||
|
|
||||||
if (full_state) {
|
if (full_state) {
|
||||||
|
|
||||||
/* NODE STRUCTURE
|
|
||||||
|
|
||||||
<Automation [optionally with visible="...." ]>
|
|
||||||
<parameter-N>
|
|
||||||
<events>
|
|
||||||
X1 Y1
|
|
||||||
X2 Y2
|
|
||||||
....
|
|
||||||
</events>
|
|
||||||
</parameter-N>
|
|
||||||
<Automation>
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
XMLNode& automation = get_automation_state();
|
XMLNode& automation = get_automation_state();
|
||||||
|
|
||||||
for (set<uint32_t>::iterator x = visible_parameter_automation.begin(); x != visible_parameter_automation.end(); ++x) {
|
for (set<uint32_t>::iterator x = visible_parameter_automation.begin(); x != visible_parameter_automation.end(); ++x) {
|
||||||
|
|
|
||||||
|
|
@ -61,13 +61,13 @@ Route::Route (Session& sess, string name, int input_min, int input_max, int outp
|
||||||
init ();
|
init ();
|
||||||
}
|
}
|
||||||
|
|
||||||
Route::Route (Session& sess, const XMLNode& node)
|
Route::Route (Session& sess, const XMLNode& node, DataType default_type)
|
||||||
: IO (sess, "route"),
|
: IO (sess, *node.child ("IO"), default_type),
|
||||||
_solo_control (X_("solo"), *this, ToggleControllable::SoloControl),
|
_solo_control (X_("solo"), *this, ToggleControllable::SoloControl),
|
||||||
_mute_control (X_("mute"), *this, ToggleControllable::MuteControl)
|
_mute_control (X_("mute"), *this, ToggleControllable::MuteControl)
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
set_state (node);
|
_set_state (node, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1481,6 +1481,12 @@ Route::add_redirect_from_xml (const XMLNode& node)
|
||||||
|
|
||||||
int
|
int
|
||||||
Route::set_state (const XMLNode& node)
|
Route::set_state (const XMLNode& node)
|
||||||
|
{
|
||||||
|
return _set_state (node, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Route::_set_state (const XMLNode& node, bool call_base)
|
||||||
{
|
{
|
||||||
XMLNodeList nlist;
|
XMLNodeList nlist;
|
||||||
XMLNodeConstIterator niter;
|
XMLNodeConstIterator niter;
|
||||||
|
|
@ -1604,7 +1610,7 @@ Route::set_state (const XMLNode& node)
|
||||||
|
|
||||||
child = *niter;
|
child = *niter;
|
||||||
|
|
||||||
if (child->name() == IO::state_node_name) {
|
if (child->name() == IO::state_node_name && call_base) {
|
||||||
|
|
||||||
IO::set_state (*child);
|
IO::set_state (*child);
|
||||||
break;
|
break;
|
||||||
|
|
@ -1925,6 +1931,10 @@ Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_f
|
||||||
{
|
{
|
||||||
Glib::RWLock::ReaderLock lm (redirect_lock);
|
Glib::RWLock::ReaderLock lm (redirect_lock);
|
||||||
|
|
||||||
|
if (!did_locate) {
|
||||||
|
automation_snapshot (now);
|
||||||
|
}
|
||||||
|
|
||||||
for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
|
for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
|
||||||
|
|
||||||
if (Config->get_plugins_stop_with_transport() && can_flush_redirects) {
|
if (Config->get_plugins_stop_with_transport() && can_flush_redirects) {
|
||||||
|
|
@ -2024,6 +2034,15 @@ int
|
||||||
Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset, int declick,
|
Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset, int declick,
|
||||||
bool can_record, bool rec_monitors_input)
|
bool can_record, bool rec_monitors_input)
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
Glib::RWLock::ReaderLock lm (redirect_lock, Glib::TRY_LOCK);
|
||||||
|
if (lm.locked()) {
|
||||||
|
// automation snapshot can also be called from the non-rt context
|
||||||
|
// and it uses the redirect list, so we take the lock out here
|
||||||
|
automation_snapshot (_session.transport_frame());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((n_outputs() == 0 && _redirects.empty()) || n_inputs() == 0 || !_active) {
|
if ((n_outputs() == 0 && _redirects.empty()) || n_inputs() == 0 || !_active) {
|
||||||
silence (nframes, offset);
|
silence (nframes, offset);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -2160,6 +2179,16 @@ Route::set_latency_delay (nframes_t longest_session_latency)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Route::automation_snapshot (nframes_t now)
|
||||||
|
{
|
||||||
|
IO::automation_snapshot (now);
|
||||||
|
|
||||||
|
for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
|
||||||
|
(*i)->automation_snapshot (now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Route::ToggleControllable::ToggleControllable (std::string name, Route& s, ToggleType tp)
|
Route::ToggleControllable::ToggleControllable (std::string name, Route& s, ToggleType tp)
|
||||||
: Controllable (name), route (s), type(tp)
|
: Controllable (name), route (s), type(tp)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1321,6 +1321,8 @@ Session::set_frame_rate (nframes_t frames_per_second)
|
||||||
|
|
||||||
sync_time_vars();
|
sync_time_vars();
|
||||||
|
|
||||||
|
Route::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * 0.25));
|
||||||
|
|
||||||
// XXX we need some equivalent to this, somehow
|
// XXX we need some equivalent to this, somehow
|
||||||
// DestructiveFileSource::setup_standard_crossfades (frames_per_second);
|
// DestructiveFileSource::setup_standard_crossfades (frames_per_second);
|
||||||
|
|
||||||
|
|
@ -3760,14 +3762,8 @@ Session::nbusses () const
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Session::add_curve(Curve *curve)
|
|
||||||
{
|
|
||||||
curves[curve->id()] = curve;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Session::add_automation_list(AutomationList *al)
|
Session::add_automation_list(AutomationList *al)
|
||||||
{
|
{
|
||||||
automation_lists[al->id()] = al;
|
automation_lists[al->id()] = al;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
#include <pbd/memento_command.h>
|
#include <pbd/memento_command.h>
|
||||||
#include <ardour/diskstream.h>
|
#include <ardour/diskstream.h>
|
||||||
#include <ardour/playlist.h>
|
#include <ardour/playlist.h>
|
||||||
|
#include <ardour/audioplaylist.h>
|
||||||
|
#include <ardour/audio_track.h>
|
||||||
#include <ardour/tempo.h>
|
#include <ardour/tempo.h>
|
||||||
#include <ardour/audiosource.h>
|
#include <ardour/audiosource.h>
|
||||||
#include <ardour/audioregion.h>
|
#include <ardour/audioregion.h>
|
||||||
|
|
@ -53,30 +55,26 @@ Command *Session::memento_command_factory(XMLNode *n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* create command */
|
/* create command */
|
||||||
string obj_T = n->children().front()->name();
|
string obj_T = n->property ("type_name")->value();
|
||||||
if (obj_T == "AudioRegion" || obj_T == "Region") {
|
if (obj_T == typeid (AudioRegion).name() || obj_T == typeid (Region).name()) {
|
||||||
if (audio_regions.count(id))
|
if (audio_regions.count(id))
|
||||||
return new MementoCommand<AudioRegion>(*audio_regions[id], before, after);
|
return new MementoCommand<AudioRegion>(*audio_regions[id], before, after);
|
||||||
} else if (obj_T == "AudioSource") {
|
} else if (obj_T == typeid (AudioSource).name()) {
|
||||||
if (audio_sources.count(id))
|
if (audio_sources.count(id))
|
||||||
return new MementoCommand<AudioSource>(*audio_sources[id], before, after);
|
return new MementoCommand<AudioSource>(*audio_sources[id], before, after);
|
||||||
} else if (obj_T == "Location") {
|
} else if (obj_T == typeid (Location).name()) {
|
||||||
return new MementoCommand<Location>(*_locations.get_location_by_id(id), before, after);
|
return new MementoCommand<Location>(*_locations.get_location_by_id(id), before, after);
|
||||||
} else if (obj_T == "Locations") {
|
} else if (obj_T == typeid (Locations).name()) {
|
||||||
return new MementoCommand<Locations>(_locations, before, after);
|
return new MementoCommand<Locations>(_locations, before, after);
|
||||||
} else if (obj_T == "TempoMap") {
|
} else if (obj_T == typeid (TempoMap).name()) {
|
||||||
return new MementoCommand<TempoMap>(*_tempo_map, before, after);
|
return new MementoCommand<TempoMap>(*_tempo_map, before, after);
|
||||||
} else if (obj_T == "Playlist" || obj_T == "AudioPlaylist") {
|
} else if (obj_T == typeid (Playlist).name() || obj_T == typeid (AudioPlaylist).name()) {
|
||||||
if (Playlist *pl = playlist_by_name(child->property("name")->value()))
|
if (Playlist *pl = playlist_by_name(child->property("name")->value()))
|
||||||
return new MementoCommand<Playlist>(*pl, before, after);
|
return new MementoCommand<Playlist>(*pl, before, after);
|
||||||
} else if (obj_T == "Route") { // includes AudioTrack
|
} else if (obj_T == typeid (Route).name() || obj_T == typeid (AudioTrack).name()) {
|
||||||
return new MementoCommand<Route>(*route_by_id(id), before, after);
|
return new MementoCommand<Route>(*route_by_id(id), before, after);
|
||||||
} else if (obj_T == "Curve") {
|
} else if (obj_T == typeid (Curve).name() || obj_T == typeid (AutomationList).name()) {
|
||||||
if (curves.count(id))
|
|
||||||
return new MementoCommand<Curve>(*curves[id], before, after);
|
|
||||||
} else if (obj_T == "AutomationList") {
|
|
||||||
if (automation_lists.count(id))
|
if (automation_lists.count(id))
|
||||||
return new MementoCommand<AutomationList>(*automation_lists[id], before, after);
|
return new MementoCommand<AutomationList>(*automation_lists[id], before, after);
|
||||||
} else if (registry.count(id)) { // For Editor and AutomationLine which are off-limits here
|
} else if (registry.count(id)) { // For Editor and AutomationLine which are off-limits here
|
||||||
|
|
@ -84,8 +82,8 @@ Command *Session::memento_command_factory(XMLNode *n)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we failed */
|
/* we failed */
|
||||||
error << _("could not reconstitute MementoCommand from XMLNode. id=") << id.to_s() << endmsg;
|
error << string_compose (_("could not reconstitute MementoCommand from XMLNode. object type = %1 id = %2"), obj_T, id.to_s()) << endmsg;
|
||||||
return 0;
|
return 0 ;
|
||||||
}
|
}
|
||||||
|
|
||||||
// solo
|
// solo
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,6 @@ Session::first_stage_init (string fullpath, string snapshot_name)
|
||||||
Playlist::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist));
|
Playlist::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist));
|
||||||
Redirect::RedirectCreated.connect (mem_fun (*this, &Session::add_redirect));
|
Redirect::RedirectCreated.connect (mem_fun (*this, &Session::add_redirect));
|
||||||
NamedSelection::NamedSelectionCreated.connect (mem_fun (*this, &Session::add_named_selection));
|
NamedSelection::NamedSelectionCreated.connect (mem_fun (*this, &Session::add_named_selection));
|
||||||
Curve::CurveCreated.connect (mem_fun (*this, &Session::add_curve));
|
|
||||||
AutomationList::AutomationListCreated.connect (mem_fun (*this, &Session::add_automation_list));
|
AutomationList::AutomationListCreated.connect (mem_fun (*this, &Session::add_automation_list));
|
||||||
|
|
||||||
Controllable::Destroyed.connect (mem_fun (*this, &Session::remove_controllable));
|
Controllable::Destroyed.connect (mem_fun (*this, &Session::remove_controllable));
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,8 @@ Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, Data
|
||||||
}
|
}
|
||||||
|
|
||||||
Track::Track (Session& sess, const XMLNode& node, DataType default_type)
|
Track::Track (Session& sess, const XMLNode& node, DataType default_type)
|
||||||
: Route (sess, "to be renamed", 0, 0, -1, -1, Route::Flag(0), default_type)
|
: Route (sess, node),
|
||||||
, _rec_enable_control (*this)
|
_rec_enable_control (*this)
|
||||||
{
|
{
|
||||||
_freeze_record.state = NoFreeze;
|
_freeze_record.state = NoFreeze;
|
||||||
_declickable = true;
|
_declickable = true;
|
||||||
|
|
|
||||||
|
|
@ -398,3 +398,68 @@ meter_hold_to_float (MeterHold hold)
|
||||||
return 200.0f;
|
return 200.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AutoState
|
||||||
|
ARDOUR::string_to_auto_state (std::string str)
|
||||||
|
{
|
||||||
|
if (str == X_("Off")) {
|
||||||
|
return Off;
|
||||||
|
} else if (str == X_("Play")) {
|
||||||
|
return Play;
|
||||||
|
} else if (str == X_("Write")) {
|
||||||
|
return Write;
|
||||||
|
} else if (str == X_("Touch")) {
|
||||||
|
return Touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
fatal << string_compose (_("programming error: %1 %2"), "illegal AutoState string: ", str) << endmsg;
|
||||||
|
/*NOTREACHED*/
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
ARDOUR::auto_state_to_string (AutoState as)
|
||||||
|
{
|
||||||
|
/* to be used only for XML serialization, no i18n done */
|
||||||
|
|
||||||
|
switch (as) {
|
||||||
|
case Off:
|
||||||
|
return X_("Off");
|
||||||
|
break;
|
||||||
|
case Play:
|
||||||
|
return X_("Play");
|
||||||
|
break;
|
||||||
|
case Write:
|
||||||
|
return X_("Write");
|
||||||
|
break;
|
||||||
|
case Touch:
|
||||||
|
return X_("Touch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoStyle
|
||||||
|
ARDOUR::string_to_auto_style (std::string str)
|
||||||
|
{
|
||||||
|
if (str == X_("Absolute")) {
|
||||||
|
return Absolute;
|
||||||
|
} else if (str == X_("Trim")) {
|
||||||
|
return Trim;
|
||||||
|
}
|
||||||
|
|
||||||
|
fatal << string_compose (_("programming error: %1 %2"), "illegal AutoStyle string: ", str) << endmsg;
|
||||||
|
/*NOTREACHED*/
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
ARDOUR::auto_style_to_string (AutoStyle as)
|
||||||
|
{
|
||||||
|
/* to be used only for XML serialization, no i18n done */
|
||||||
|
|
||||||
|
switch (as) {
|
||||||
|
case Absolute:
|
||||||
|
return X_("Absolute");
|
||||||
|
break;
|
||||||
|
case Trim:
|
||||||
|
return X_("Trim");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,9 +87,10 @@ public:
|
||||||
const string & set_content (const string &);
|
const string & set_content (const string &);
|
||||||
XMLNode *add_content(const string & = string());
|
XMLNode *add_content(const string & = string());
|
||||||
|
|
||||||
const XMLNodeList & children (const string & = string()) const;
|
const XMLNodeList & children (const string& str = string()) const;
|
||||||
XMLNode *add_child (const char *);
|
XMLNode *add_child (const char *);
|
||||||
XMLNode *add_child_copy (const XMLNode&);
|
XMLNode *add_child_copy (const XMLNode&);
|
||||||
|
XMLNode *child (const char*) const;
|
||||||
void add_child_nocopy (XMLNode&);
|
void add_child_nocopy (XMLNode&);
|
||||||
|
|
||||||
const XMLPropertyList & properties() const { return _proplist; };
|
const XMLPropertyList & properties() const { return _proplist; };
|
||||||
|
|
|
||||||
|
|
@ -216,13 +216,38 @@ XMLNode::set_content(const string & c)
|
||||||
return _content;
|
return _content;
|
||||||
}
|
}
|
||||||
|
|
||||||
const XMLNodeList &
|
XMLNode*
|
||||||
XMLNode::children(const string & n) const
|
XMLNode::child (const char *name) const
|
||||||
{
|
{
|
||||||
|
/* returns first child matching name */
|
||||||
|
|
||||||
static XMLNodeList retval;
|
static XMLNodeList retval;
|
||||||
XMLNodeConstIterator cur;
|
XMLNodeConstIterator cur;
|
||||||
|
|
||||||
if (n.length() == 0) {
|
if (name == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval.erase(retval.begin(), retval.end());
|
||||||
|
|
||||||
|
for (cur = _children.begin(); cur != _children.end(); ++cur) {
|
||||||
|
if ((*cur)->name() == name) {
|
||||||
|
return *cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const XMLNodeList &
|
||||||
|
XMLNode::children(const string& n) const
|
||||||
|
{
|
||||||
|
/* returns all children matching name */
|
||||||
|
|
||||||
|
static XMLNodeList retval;
|
||||||
|
XMLNodeConstIterator cur;
|
||||||
|
|
||||||
|
if (n.empty()) {
|
||||||
return _children;
|
return _children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue