mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-10 00:34:59 +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/icons'), icon_files))
|
||||
|
||||
env.AlwaysBuild ('version.cc')
|
||||
env.Alias ('version', gtkardour.VersionBuild(['version.cc','version.h'], 'SConscript'))
|
||||
|
||||
#dist
|
||||
|
|
|
|||
|
|
@ -902,12 +902,11 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
|
|||
trackview.session().begin_reversible_command (_("add gain control point"));
|
||||
XMLNode &before = audio_region()->envelope().get_state();
|
||||
|
||||
|
||||
if (!audio_region()->envelope_active()) {
|
||||
XMLNode &before = audio_region()->get_state();
|
||||
XMLNode ®ion_before = audio_region()->get_state();
|
||||
audio_region()->set_envelope_active(true);
|
||||
XMLNode &after = audio_region()->get_state();
|
||||
trackview.session().add_command (new MementoCommand<AudioRegion>(*(audio_region().get()), &before, &after));
|
||||
XMLNode ®ion_after = audio_region()->get_state();
|
||||
trackview.session().add_command (new MementoCommand<AudioRegion>(*(audio_region().get()), ®ion_before, ®ion_after));
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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 prev_ry = 0;
|
||||
double* slope;
|
||||
double box_size;
|
||||
uint32_t cpsize;
|
||||
|
||||
/* hide all existing points, and the line */
|
||||
|
||||
cpsize = 0;
|
||||
|
||||
for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
|
||||
(*i)->hide();
|
||||
++cpsize;
|
||||
}
|
||||
|
||||
line->hide ();
|
||||
|
|
@ -695,6 +700,13 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
|
|||
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 */
|
||||
|
||||
view_index = 0;
|
||||
|
|
@ -738,27 +750,23 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
|
|||
this_rx = (uint32_t) rint (tx);
|
||||
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;
|
||||
}
|
||||
|
||||
/* ok, we should display this point */
|
||||
|
||||
if (view_index >= control_points.size()) {
|
||||
if (view_index >= cpsize) {
|
||||
|
||||
/* make sure we have enough control points */
|
||||
|
||||
ControlPoint* ncp = new ControlPoint (*this);
|
||||
|
||||
if (_height > (guint32) TimeAxisView::Larger) {
|
||||
ncp->set_size (8.0);
|
||||
} else if (_height > (guint32) TimeAxisView::Normal) {
|
||||
ncp->set_size (6.0);
|
||||
} else {
|
||||
ncp->set_size (4.0);
|
||||
}
|
||||
ncp->set_size (box_size);
|
||||
|
||||
control_points.push_back (ncp);
|
||||
++cpsize;
|
||||
}
|
||||
|
||||
ControlPoint::ShapeType shape;
|
||||
|
|
@ -829,6 +837,10 @@ AutomationLine::determine_visible_control_points (ALPoints& points)
|
|||
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) {
|
||||
line_points[view_index].set_x (control_points[view_index]->get_x());
|
||||
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) {
|
||||
|
||||
double translated_y;
|
||||
|
||||
translated_y = (*ai)->value;
|
||||
double translated_y = (*ai)->value;
|
||||
model_to_view_y (translated_y);
|
||||
|
||||
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");
|
||||
node->add_child_nocopy(alist.get_state());
|
||||
return *node;
|
||||
/* function as a proxy for the model */
|
||||
return alist.get_state();
|
||||
}
|
||||
|
||||
int AutomationLine::set_state(const XMLNode &node)
|
||||
int
|
||||
AutomationLine::set_state (const XMLNode &node)
|
||||
{
|
||||
// TODO
|
||||
//alist.set_state(node);
|
||||
return 0;
|
||||
/* function as a proxy for the model */
|
||||
return alist.set_state (node);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,10 @@ Editor::draw_metric_marks (const Metrics& metrics)
|
|||
void
|
||||
Editor::tempo_map_changed (Change ignored)
|
||||
{
|
||||
if (!session) {
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
@ -112,10 +116,10 @@ Editor::tempo_map_changed (Change ignored)
|
|||
previous_beat.ticks = 0;
|
||||
|
||||
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 {
|
||||
next_beat.bars += 1;
|
||||
next_beat.beats = 1;
|
||||
next_beat.bars += 1;
|
||||
next_beat.beats = 1;
|
||||
}
|
||||
next_beat.ticks = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -63,12 +63,10 @@ GainAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkE
|
|||
lines.front()->view_to_model_y (y);
|
||||
|
||||
_session.begin_reversible_command (_("add gain automation event"));
|
||||
|
||||
XMLNode &before = curve.get_state();
|
||||
XMLNode& before = curve.get_state();
|
||||
curve.add (when, y);
|
||||
XMLNode &after = curve.get_state();
|
||||
_session.add_command(new MementoCommand<ARDOUR::Curve>(curve, &before, &after));
|
||||
_session.commit_reversible_command ();
|
||||
XMLNode& after = curve.get_state();
|
||||
_session.commit_reversible_command (new MementoCommand<ARDOUR::Curve>(curve, &before, &after));
|
||||
_session.set_dirty ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,10 +65,10 @@ AudioRegionGainLine::remove_point (ControlPoint& cp)
|
|||
XMLNode &before = get_state();
|
||||
|
||||
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);
|
||||
XMLNode &after = rv.audio_region()->get_state();
|
||||
trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), &before, &after));
|
||||
XMLNode ®ion_after = rv.audio_region()->get_state();
|
||||
trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), ®ion_before, ®ion_after));
|
||||
}
|
||||
|
||||
alist.erase (mr.start, mr.end);
|
||||
|
|
@ -85,6 +85,7 @@ AudioRegionGainLine::end_drag (ControlPoint* cp)
|
|||
rv.audio_region()->set_envelope_active(true);
|
||||
trackview.session().add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), 0, &rv.audio_region()->get_state()));
|
||||
}
|
||||
|
||||
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_audio_track_boolean (string name, void (ARDOUR::AudioTrack::*func)(bool, void*), bool, void *);
|
||||
|
||||
sigc::signal<void> GoingAway;
|
||||
};
|
||||
|
||||
#endif /* __ardour_route_ui__ */
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ class AudioTrack : public Track
|
|||
|
||||
uint32_t n_process_buffers ();
|
||||
|
||||
int _set_state (const XMLNode&, bool call_base);
|
||||
|
||||
private:
|
||||
int set_diskstream (boost::shared_ptr<AudioDiskstream>, void *);
|
||||
int deprecated_use_diskstream_connections ();
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ class AutomationList : public PBD::StatefulDestructible
|
|||
typedef AutomationEventList::iterator iterator;
|
||||
typedef AutomationEventList::const_iterator const_iterator;
|
||||
|
||||
AutomationList(double default_value, bool no_state = false);
|
||||
AutomationList (double default_value);
|
||||
AutomationList (const XMLNode&);
|
||||
~AutomationList();
|
||||
|
||||
AutomationList (const AutomationList&);
|
||||
|
|
@ -151,8 +152,10 @@ class AutomationList : public PBD::StatefulDestructible
|
|||
|
||||
sigc::signal<void,Change> StateChanged;
|
||||
|
||||
XMLNode &get_state(void);
|
||||
XMLNode& get_state(void);
|
||||
int set_state (const XMLNode &s);
|
||||
XMLNode& state (bool full);
|
||||
XMLNode& serialize_events ();
|
||||
|
||||
void set_max_xval (double);
|
||||
double get_max_xval() const { return max_xval; }
|
||||
|
|
@ -204,11 +207,11 @@ class AutomationList : public PBD::StatefulDestructible
|
|||
double min_yval;
|
||||
double max_yval;
|
||||
double default_value;
|
||||
bool no_state;
|
||||
|
||||
iterator rt_insertion_point;
|
||||
double rt_pos;
|
||||
|
||||
void fast_simple_add (double when, double value);
|
||||
void maybe_signal_changed ();
|
||||
void mark_dirty ();
|
||||
void _x_scale (double factor);
|
||||
|
|
@ -235,6 +238,8 @@ class AutomationList : public PBD::StatefulDestructible
|
|||
virtual ControlEvent* point_factory (const ControlEvent&) const;
|
||||
|
||||
AutomationList* cut_copy_clear (double, double, int op);
|
||||
|
||||
int deserialize_events (const XMLNode&);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ class Curve : public AutomationList
|
|||
~Curve ();
|
||||
Curve (const Curve& other);
|
||||
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);
|
||||
void get_vector (double x0, double x1, float *arg, int32_t veclen);
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ class PluginInsert : public Insert
|
|||
nframes_t latency();
|
||||
|
||||
void transport_stopped (nframes_t now);
|
||||
void automation_snapshot (nframes_t now);
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
|||
|
|
@ -67,9 +67,11 @@ class IO : public PBD::StatefulDestructible
|
|||
IO (Session&, string name,
|
||||
int input_min = -1, int input_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_maximum() const { return _input_maximum; }
|
||||
|
|
@ -205,6 +207,14 @@ public:
|
|||
|
||||
/* 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 ();
|
||||
|
||||
bool gain_automation_recording() const {
|
||||
|
|
@ -226,6 +236,7 @@ public:
|
|||
sigc::signal<void> gain_automation_style_changed;
|
||||
|
||||
virtual void transport_stopped (nframes_t now);
|
||||
void automation_snapshot (nframes_t now);
|
||||
|
||||
ARDOUR::Curve& gain_automation_curve () { return _gain_automation_curve; }
|
||||
|
||||
|
|
@ -289,6 +300,9 @@ public:
|
|||
|
||||
GainControllable _gain_control;
|
||||
|
||||
nframes_t last_automation_snapshot;
|
||||
static nframes_t _automation_interval;
|
||||
|
||||
AutoState _gain_automation_state;
|
||||
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,
|
||||
Flag flags = Flag(0), DataType default_type = DataType::AUDIO);
|
||||
|
||||
Route (Session&, const XMLNode&);
|
||||
Route (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
|
||||
virtual ~Route();
|
||||
|
||||
std::string comment() { return _comment; }
|
||||
|
|
@ -233,6 +232,7 @@ class Route : public IO
|
|||
return _mute_control;
|
||||
}
|
||||
|
||||
void automation_snapshot (nframes_t now);
|
||||
void protect_automation ();
|
||||
|
||||
void set_remote_control_id (uint32_t id);
|
||||
|
|
@ -315,6 +315,8 @@ class Route : public IO
|
|||
uint32_t pans_required() const;
|
||||
uint32_t n_process_buffers ();
|
||||
|
||||
virtual int _set_state (const XMLNode&, bool call_base);
|
||||
|
||||
private:
|
||||
void init ();
|
||||
|
||||
|
|
|
|||
|
|
@ -91,11 +91,17 @@ namespace ARDOUR {
|
|||
Play = 0x4
|
||||
};
|
||||
|
||||
std::string auto_state_to_string (AutoState);
|
||||
AutoState string_to_auto_state (std::string);
|
||||
|
||||
enum AutoStyle {
|
||||
Absolute = 0x1,
|
||||
Trim = 0x2
|
||||
};
|
||||
|
||||
std::string auto_style_to_string (AutoStyle);
|
||||
AutoStyle string_to_auto_style (std::string);
|
||||
|
||||
enum AlignStyle {
|
||||
CaptureTime,
|
||||
ExistingMaterial
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode
|
|||
AudioTrack::AudioTrack (Session& sess, const XMLNode& node)
|
||||
: Track (sess, node)
|
||||
{
|
||||
set_state (node);
|
||||
_set_state (node, false);
|
||||
}
|
||||
|
||||
AudioTrack::~AudioTrack ()
|
||||
|
|
@ -187,12 +187,20 @@ AudioTrack::audio_diskstream() const
|
|||
|
||||
int
|
||||
AudioTrack::set_state (const XMLNode& node)
|
||||
{
|
||||
return _set_state (node, true);
|
||||
}
|
||||
|
||||
int
|
||||
AudioTrack::_set_state (const XMLNode& node, bool call_base)
|
||||
{
|
||||
const XMLProperty *prop;
|
||||
XMLNodeConstIterator iter;
|
||||
|
||||
if (Route::set_state (node)) {
|
||||
return -1;
|
||||
if (call_base) {
|
||||
if (Route::set_state (node)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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()) {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,14 +47,13 @@ static void dumpit (const AutomationList& al, string prefix = "")
|
|||
}
|
||||
#endif
|
||||
|
||||
AutomationList::AutomationList (double defval, bool with_state)
|
||||
AutomationList::AutomationList (double defval)
|
||||
{
|
||||
_frozen = false;
|
||||
changed_when_thawed = false;
|
||||
_state = Off;
|
||||
_style = Absolute;
|
||||
_touching = false;
|
||||
no_state = with_state;
|
||||
min_yval = FLT_MIN;
|
||||
max_yval = FLT_MAX;
|
||||
max_xval = 0; // means "no limit"
|
||||
|
|
@ -80,7 +79,6 @@ AutomationList::AutomationList (const AutomationList& other)
|
|||
_touching = other._touching;
|
||||
_dirty = false;
|
||||
rt_insertion_point = events.end();
|
||||
no_state = other.no_state;
|
||||
lookup_cache.left = -1;
|
||||
lookup_cache.range.first = events.end();
|
||||
|
||||
|
|
@ -108,7 +106,6 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
|
|||
_touching = other._touching;
|
||||
_dirty = false;
|
||||
rt_insertion_point = events.end();
|
||||
no_state = other.no_state;
|
||||
lookup_cache.left = -1;
|
||||
lookup_cache.range.first = events.end();
|
||||
|
||||
|
|
@ -125,6 +122,27 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
|
|||
delete section;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -346,12 +364,19 @@ AutomationList::rt_add (double when, double value)
|
|||
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
|
||||
|
||||
void
|
||||
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);
|
||||
|
|
@ -395,11 +420,6 @@ AutomationList::erase (AutomationList::iterator i)
|
|||
Glib::Mutex::Lock lm (lock);
|
||||
events.erase (i);
|
||||
reposition_for_rt_add (0);
|
||||
if (!no_state) {
|
||||
#ifdef STATE_MANAGER
|
||||
save_state (_("removed event"));
|
||||
#endif
|
||||
}
|
||||
mark_dirty ();
|
||||
}
|
||||
maybe_signal_changed ();
|
||||
|
|
@ -1118,66 +1138,179 @@ AutomationList::point_factory (const ControlEvent& other) const
|
|||
XMLNode&
|
||||
AutomationList::get_state ()
|
||||
{
|
||||
stringstream str;
|
||||
XMLNode* node = new XMLNode (X_("events"));
|
||||
iterator xx;
|
||||
return state (true);
|
||||
}
|
||||
|
||||
if (events.empty()) {
|
||||
return *node;
|
||||
XMLNode&
|
||||
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 << ' ';
|
||||
str <<(double) (*xx)->value;
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
AutomationList::set_state (const XMLNode& node)
|
||||
AutomationList::deserialize_events (const XMLNode& node)
|
||||
{
|
||||
if (node.name() != X_("events")) {
|
||||
warning << _("automation list: passed XML node not called \"events\" - ignored.") << endmsg;
|
||||
if (node.children().empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
XMLNode* content_node = node.children().front();
|
||||
|
||||
if (content_node->content().empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeze ();
|
||||
clear ();
|
||||
|
||||
if (!node.content().empty()) {
|
||||
stringstream str (content_node->content());
|
||||
|
||||
stringstream str (node.content());
|
||||
double x;
|
||||
double y;
|
||||
bool ok = true;
|
||||
|
||||
double x;
|
||||
double y;
|
||||
bool ok = true;
|
||||
|
||||
while (str) {
|
||||
str >> x;
|
||||
if (!str) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
str >> y;
|
||||
if (!str) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
add (x, y);
|
||||
while (str) {
|
||||
str >> x;
|
||||
if (!str) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
clear ();
|
||||
error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg;
|
||||
str >> y;
|
||||
if (!str) {
|
||||
ok = false;
|
||||
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 ();
|
||||
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 PBD;
|
||||
|
||||
sigc::signal<void, Curve*> Curve::CurveCreated;
|
||||
|
||||
Curve::Curve (double minv, double maxv, double canv, bool nostate)
|
||||
: AutomationList (canv, nostate)
|
||||
: AutomationList (canv)
|
||||
{
|
||||
min_yval = minv;
|
||||
max_yval = maxv;
|
||||
CurveCreated(this);
|
||||
}
|
||||
|
||||
Curve::Curve (const Curve& other)
|
||||
|
|
@ -55,7 +52,6 @@ Curve::Curve (const Curve& other)
|
|||
{
|
||||
min_yval = other.min_yval;
|
||||
max_yval = other.max_yval;
|
||||
CurveCreated(this);
|
||||
}
|
||||
|
||||
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;
|
||||
max_yval = other.max_yval;
|
||||
CurveCreated(this);
|
||||
}
|
||||
|
||||
Curve::Curve (const XMLNode& node)
|
||||
: AutomationList (node)
|
||||
{
|
||||
}
|
||||
|
||||
Curve::~Curve ()
|
||||
|
|
|
|||
|
|
@ -310,6 +310,23 @@ PluginInsert::connect_and_run (vector<Sample*>& bufs, uint32_t nbufs, nframes_t
|
|||
/* 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
|
||||
PluginInsert::transport_stopped (nframes_t now)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ using namespace std;
|
|||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
nframes_t IO::_automation_interval = 0;
|
||||
const string IO::state_node_name = "IO";
|
||||
bool IO::connecting_legal = false;
|
||||
bool IO::ports_legal = false;
|
||||
|
|
@ -124,6 +125,8 @@ IO::IO (Session& s, string name,
|
|||
apply_gain_automation = false;
|
||||
_ignore_gain_on_deliver = false;
|
||||
|
||||
last_automation_snapshot = 0;
|
||||
|
||||
_gain_automation_state = Off;
|
||||
_gain_automation_style = Absolute;
|
||||
|
||||
|
|
@ -137,6 +140,38 @@ IO::IO (Session& s, string name,
|
|||
_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 ()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
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) {
|
||||
|
||||
if ((*iter)->name() == "Panner") {
|
||||
if (_panner == 0) {
|
||||
_panner = new Panner (_name, _session);
|
||||
}
|
||||
_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 (create_ports (node)) {
|
||||
|
|
@ -1644,6 +1662,8 @@ IO::set_state (const XMLNode& node)
|
|||
pending_state_node = new XMLNode (node);
|
||||
}
|
||||
|
||||
last_automation_snapshot = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2398,6 +2418,7 @@ IO::set_gain_automation_state (AutoState state)
|
|||
|
||||
if (state != _gain_automation_curve.automation_state()) {
|
||||
changed = true;
|
||||
last_automation_snapshot = 0;
|
||||
_gain_automation_curve.set_automation_state (state);
|
||||
|
||||
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
|
||||
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_("type"), EqualPowerStereoPanner::name);
|
||||
|
||||
if (full_state) {
|
||||
XMLNode* autonode = new XMLNode (X_("Automation"));
|
||||
autonode->add_child_nocopy (_automation.get_state ());
|
||||
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);
|
||||
XMLNode* autonode = new XMLNode (X_("Automation"));
|
||||
autonode->add_child_nocopy (_automation.state (full_state));
|
||||
root->add_child_nocopy (*autonode);
|
||||
|
||||
StreamPanner::add_state (*root);
|
||||
|
||||
root->add_child_nocopy (_control.get_state ());
|
||||
|
||||
return *root;
|
||||
|
|
@ -496,7 +488,6 @@ int
|
|||
EqualPowerStereoPanner::set_state (const XMLNode& node)
|
||||
{
|
||||
const XMLProperty* prop;
|
||||
int x;
|
||||
float pos;
|
||||
LocaleGuard lg (X_("POSIX"));
|
||||
|
||||
|
|
@ -508,27 +499,21 @@ EqualPowerStereoPanner::set_state (const XMLNode& node)
|
|||
StreamPanner::set_state (node);
|
||||
|
||||
for (XMLNodeConstIterator iter = node.children().begin(); iter != node.children().end(); ++iter) {
|
||||
|
||||
if ((*iter)->name() == X_("panner")) {
|
||||
|
||||
_control.set_state (**iter);
|
||||
|
||||
} else if ((*iter)->name() == X_("Automation")) {
|
||||
|
||||
_automation.set_state (*((*iter)->children().front()));
|
||||
|
||||
if (_automation.automation_state() != Off) {
|
||||
set_position (_automation.eval (parent.session().transport_frame()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((prop = node.property (X_("automation-state")))) {
|
||||
sscanf (prop->value().c_str(), "0x%x", &x);
|
||||
_automation.set_automation_state ((AutoState) x);
|
||||
|
||||
if (x != Off) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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);
|
||||
|
||||
parameter_automation.clear ();
|
||||
|
|
@ -157,20 +157,6 @@ Redirect::set_automation_state (const XMLNode& node)
|
|||
XMLNode&
|
||||
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);
|
||||
XMLNode* node = new XMLNode (X_("Automation"));
|
||||
string fullpath;
|
||||
|
|
@ -217,20 +203,6 @@ Redirect::state (bool 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();
|
||||
|
||||
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 ();
|
||||
}
|
||||
|
||||
Route::Route (Session& sess, const XMLNode& node)
|
||||
: IO (sess, "route"),
|
||||
Route::Route (Session& sess, const XMLNode& node, DataType default_type)
|
||||
: IO (sess, *node.child ("IO"), default_type),
|
||||
_solo_control (X_("solo"), *this, ToggleControllable::SoloControl),
|
||||
_mute_control (X_("mute"), *this, ToggleControllable::MuteControl)
|
||||
{
|
||||
init ();
|
||||
set_state (node);
|
||||
_set_state (node, false);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1481,6 +1481,12 @@ Route::add_redirect_from_xml (const XMLNode& node)
|
|||
|
||||
int
|
||||
Route::set_state (const XMLNode& node)
|
||||
{
|
||||
return _set_state (node, true);
|
||||
}
|
||||
|
||||
int
|
||||
Route::_set_state (const XMLNode& node, bool call_base)
|
||||
{
|
||||
XMLNodeList nlist;
|
||||
XMLNodeConstIterator niter;
|
||||
|
|
@ -1604,7 +1610,7 @@ Route::set_state (const XMLNode& node)
|
|||
|
||||
child = *niter;
|
||||
|
||||
if (child->name() == IO::state_node_name) {
|
||||
if (child->name() == IO::state_node_name && call_base) {
|
||||
|
||||
IO::set_state (*child);
|
||||
break;
|
||||
|
|
@ -1925,6 +1931,10 @@ Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_f
|
|||
{
|
||||
Glib::RWLock::ReaderLock lm (redirect_lock);
|
||||
|
||||
if (!did_locate) {
|
||||
automation_snapshot (now);
|
||||
}
|
||||
|
||||
for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
|
||||
|
||||
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,
|
||||
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) {
|
||||
silence (nframes, offset);
|
||||
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)
|
||||
: Controllable (name), route (s), type(tp)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1321,6 +1321,8 @@ Session::set_frame_rate (nframes_t frames_per_second)
|
|||
|
||||
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
|
||||
// DestructiveFileSource::setup_standard_crossfades (frames_per_second);
|
||||
|
||||
|
|
@ -3760,14 +3762,8 @@ Session::nbusses () const
|
|||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
Session::add_curve(Curve *curve)
|
||||
{
|
||||
curves[curve->id()] = curve;
|
||||
}
|
||||
|
||||
void
|
||||
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 <ardour/diskstream.h>
|
||||
#include <ardour/playlist.h>
|
||||
#include <ardour/audioplaylist.h>
|
||||
#include <ardour/audio_track.h>
|
||||
#include <ardour/tempo.h>
|
||||
#include <ardour/audiosource.h>
|
||||
#include <ardour/audioregion.h>
|
||||
|
|
@ -53,30 +55,26 @@ Command *Session::memento_command_factory(XMLNode *n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* create command */
|
||||
string obj_T = n->children().front()->name();
|
||||
if (obj_T == "AudioRegion" || obj_T == "Region") {
|
||||
string obj_T = n->property ("type_name")->value();
|
||||
if (obj_T == typeid (AudioRegion).name() || obj_T == typeid (Region).name()) {
|
||||
if (audio_regions.count(id))
|
||||
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))
|
||||
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);
|
||||
} else if (obj_T == "Locations") {
|
||||
} else if (obj_T == typeid (Locations).name()) {
|
||||
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);
|
||||
} 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()))
|
||||
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);
|
||||
} else if (obj_T == "Curve") {
|
||||
if (curves.count(id))
|
||||
return new MementoCommand<Curve>(*curves[id], before, after);
|
||||
} else if (obj_T == "AutomationList") {
|
||||
} else if (obj_T == typeid (Curve).name() || obj_T == typeid (AutomationList).name()) {
|
||||
if (automation_lists.count(id))
|
||||
return new MementoCommand<AutomationList>(*automation_lists[id], before, after);
|
||||
} 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 */
|
||||
error << _("could not reconstitute MementoCommand from XMLNode. id=") << id.to_s() << endmsg;
|
||||
return 0;
|
||||
error << string_compose (_("could not reconstitute MementoCommand from XMLNode. object type = %1 id = %2"), obj_T, id.to_s()) << endmsg;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
// solo
|
||||
|
|
|
|||
|
|
@ -240,7 +240,6 @@ Session::first_stage_init (string fullpath, string snapshot_name)
|
|||
Playlist::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist));
|
||||
Redirect::RedirectCreated.connect (mem_fun (*this, &Session::add_redirect));
|
||||
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));
|
||||
|
||||
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)
|
||||
: Route (sess, "to be renamed", 0, 0, -1, -1, Route::Flag(0), default_type)
|
||||
, _rec_enable_control (*this)
|
||||
: Route (sess, node),
|
||||
_rec_enable_control (*this)
|
||||
{
|
||||
_freeze_record.state = NoFreeze;
|
||||
_declickable = true;
|
||||
|
|
|
|||
|
|
@ -398,3 +398,68 @@ meter_hold_to_float (MeterHold hold)
|
|||
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 &);
|
||||
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_copy (const XMLNode&);
|
||||
XMLNode *child (const char*) const;
|
||||
void add_child_nocopy (XMLNode&);
|
||||
|
||||
const XMLPropertyList & properties() const { return _proplist; };
|
||||
|
|
|
|||
|
|
@ -216,13 +216,38 @@ XMLNode::set_content(const string & c)
|
|||
return _content;
|
||||
}
|
||||
|
||||
const XMLNodeList &
|
||||
XMLNode::children(const string & n) const
|
||||
XMLNode*
|
||||
XMLNode::child (const char *name) const
|
||||
{
|
||||
/* returns first child matching name */
|
||||
|
||||
static XMLNodeList retval;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue