void reposition_for_rt_add (double when);
void rt_add (double when, double value);
void add (double when, double value);
+ /* this should be private but old-school automation loading needs it in IO/Redirect */
+ void fast_simple_add (double when, double value);
void reset_range (double start, double end);
void erase_range (double start, double end);
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);
virtual int set_automation_state (const XMLNode&);
virtual XMLNode& get_automation_state ();
+ virtual int load_automation (std::string path);
/* AudioTrack::deprecated_use_diskstream_connections() needs these */
Panner & get_parent() { return parent; }
+ /* old school automation loading */
+
+ virtual int load (istream&, string path, uint32_t&) = 0;
+
protected:
friend class Panner;
Panner& parent;
Curve& automation() { return _automation; }
+ /* old school automation loading */
+
+ int load (istream&, string path, uint32_t&);
+
protected:
float left;
float right;
XMLNode& get_state (void);
int set_state (const XMLNode&);
+ /* old school automation loading */
+
+ int load (istream&, string path, uint32_t&);
+
private:
Curve _automation;
void update ();
void set_position (float x, StreamPanner& orig);
void set_position (float x, float y, StreamPanner& orig);
void set_position (float x, float y, float z, StreamPanner& orig);
-
+
+ /* old school automation */
+
+ int load ();
+
private:
Session& _session;
LinkDirection _link_direction;
static float current_automation_version_number;
+
+ /* old school automation handling */
+
+ std::string automation_path;
+ void set_name (std::string);
};
} // namespace ARDOUR
int set_automation_state (const XMLNode&);
XMLNode& get_automation_state ();
-
+
private:
bool _active;
Placement _placement;
uint32_t _sort_key;
void* _gui; /* generic, we don't know or care what this is */
+
+ int old_set_automation_state (const XMLNode&);
+ int load_automation (std::string path);
};
} // namespace ARDOUR
IO::panners_became_legal ()
{
_panner->reset (_noutputs, pans_required());
+ _panner->load (); // automation
panner_legal_c.disconnect ();
return 0;
}
_gain = _desired_gain;
}
+ if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
+ /* old school automation handling */
+ }
+
for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
if ((*iter)->name() == "Panner") {
return (_gain_automation_curve.get_state ());
}
+int
+IO::load_automation (string path)
+{
+ string fullpath;
+ ifstream in;
+ char line[128];
+ uint32_t linecnt = 0;
+ float version;
+ LocaleGuard lg (X_("POSIX"));
+
+ fullpath = _session.automation_dir();
+ fullpath += path;
+
+ in.open (fullpath.c_str());
+
+ if (!in) {
+ fullpath = _session.automation_dir();
+ fullpath += _session.snap_name();
+ fullpath += '-';
+ fullpath += path;
+
+ in.open (fullpath.c_str());
+
+ if (!in) {
+ error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
+ return -1;
+ }
+ }
+
+ clear_automation ();
+
+ while (in.getline (line, sizeof(line), '\n')) {
+ char type;
+ jack_nframes_t when;
+ double value;
+
+ if (++linecnt == 1) {
+ if (memcmp (line, "version", 7) == 0) {
+ if (sscanf (line, "version %f", &version) != 1) {
+ error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
+ return -1;
+ }
+ } else {
+ error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
+ return -1;
+ }
+
+ continue;
+ }
+
+ if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
+ warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
+ continue;
+ }
+
+ switch (type) {
+ case 'g':
+ _gain_automation_curve.fast_simple_add (when, value);
+ break;
+
+ case 's':
+ break;
+
+ case 'm':
+ break;
+
+ case 'p':
+ /* older (pre-1.0) versions of ardour used this */
+ break;
+
+ default:
+ warning << _("dubious automation event found (and ignored)") << endmsg;
+ }
+ }
+
+ return 0;
+}
+
int
IO::connecting_became_legal ()
{
}
}
+int
+BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt)
+{
+ char line[128];
+ LocaleGuard lg (X_("POSIX"));
+
+ _automation.clear ();
+
+ while (in.getline (line, sizeof (line), '\n')) {
+ jack_nframes_t when;
+ double value;
+
+ ++linecnt;
+
+ if (strcmp (line, "end") == 0) {
+ break;
+ }
+
+ if (sscanf (line, "%" PRIu32 " %lf", &when, &value) != 2) {
+ warning << string_compose(_("badly formatted pan automation event record at line %1 of %2 (ignored) [%3]"), linecnt, path, line) << endmsg;
+ continue;
+ }
+
+ _automation.fast_simple_add (when, value);
+ }
+
+ /* now that we are done loading */
+
+ _automation.StateChanged (Change (0));
+
+ return 0;
+}
+
void
BaseStereoPanner::distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes)
{
return new Multi2dPanner (p);
}
+int
+Multi2dPanner::load (istream& in, string path, uint32_t& linecnt)
+{
+ return 0;
+}
+
XMLNode&
Multi2dPanner::get_state (void)
{
Panner::Panner (string name, Session& s)
: _session (s)
{
+ set_name (name);
+
_linked = false;
_link_direction = SameDirection;
_bypassed = false;
}
}
+ /* don't try to do old-school automation loading if it wasn't marked as existing */
+
+ if ((prop = node.property (X_("automation")))) {
+
+ /* automation path is relative */
+
+ automation_path = _session.automation_dir();
+ automation_path += prop->value ();
+ }
+
return 0;
}
}
}
}
+
+/* old school automation handling */
+
+void
+Panner::set_name (string str)
+{
+ automation_path = _session.automation_dir();
+ automation_path += _session.snap_name();
+ automation_path += "-pan-";
+ automation_path += legalize_for_path (str);
+ automation_path += ".automation";
+}
+
+int
+Panner::load ()
+{
+ char line[128];
+ uint32_t linecnt = 0;
+ float version;
+ iterator sp;
+ LocaleGuard lg (X_("POSIX"));
+
+ if (automation_path.length() == 0) {
+ return 0;
+ }
+
+ if (access (automation_path.c_str(), F_OK)) {
+ return 0;
+ }
+
+ ifstream in (automation_path.c_str());
+
+ if (!in) {
+ error << string_compose (_("cannot open pan automation file %1 (%2)"),
+ automation_path, strerror (errno))
+ << endmsg;
+ return -1;
+ }
+
+ sp = begin();
+
+ while (in.getline (line, sizeof(line), '\n')) {
+
+ if (++linecnt == 1) {
+ if (memcmp (line, X_("version"), 7) == 0) {
+ if (sscanf (line, "version %f", &version) != 1) {
+ error << string_compose(_("badly formed version number in pan automation event file \"%1\""), automation_path) << endmsg;
+ return -1;
+ }
+ } else {
+ error << string_compose(_("no version information in pan automation event file \"%1\" (first line = %2)"),
+ automation_path, line) << endmsg;
+ return -1;
+ }
+
+ continue;
+ }
+
+ if (strlen (line) == 0 || line[0] == '#') {
+ continue;
+ }
+
+ if (strcmp (line, "begin") == 0) {
+
+ if (sp == end()) {
+ error << string_compose (_("too many panner states found in pan automation file %1"),
+ automation_path)
+ << endmsg;
+ return -1;
+ }
+
+ if ((*sp)->load (in, automation_path, linecnt)) {
+ return -1;
+ }
+
+ ++sp;
+ }
+ }
+
+ return 0;
+}
} else if ((*niter)->name() == X_("Automation")) {
+
XMLProperty *prop;
if ((prop = (*niter)->property ("path")) != 0) {
- warning << string_compose (_("old automation data found for %1, ignored"), _name) << endmsg;
+ old_set_automation_state (*(*niter));
} else {
set_automation_state (*(*niter));
}
return 0;
}
+int
+Redirect::old_set_automation_state (const XMLNode& node)
+{
+ const XMLProperty *prop;
+
+ if ((prop = node.property ("path")) != 0) {
+ load_automation (prop->value());
+ } else {
+ warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg;
+ }
+
+ if ((prop = node.property ("visible")) != 0) {
+ uint32_t what;
+ stringstream sstr;
+
+ visible_parameter_automation.clear ();
+
+ sstr << prop->value();
+ while (1) {
+ sstr >> what;
+ if (sstr.fail()) {
+ break;
+ }
+ mark_automation_visible (what, true);
+ }
+ }
+
+ return 0;
+}
+
+int
+Redirect::load_automation (string path)
+{
+ string fullpath;
+
+ if (path[0] == '/') { // legacy
+ fullpath = path;
+ } else {
+ fullpath = _session.automation_dir();
+ fullpath += path;
+ }
+ ifstream in (fullpath.c_str());
+
+ if (!in) {
+ warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg;
+ return 1;
+ }
+
+ Glib::Mutex::Lock lm (_automation_lock);
+ set<uint32_t> tosave;
+ parameter_automation.clear ();
+
+ while (in) {
+ double when;
+ double value;
+ uint32_t port;
+
+ in >> port; if (!in) break;
+ in >> when; if (!in) goto bad;
+ in >> value; if (!in) goto bad;
+
+ AutomationList& al = automation_list (port);
+ al.add (when, value);
+ tosave.insert (port);
+ }
+
+ return 0;
+
+ bad:
+ error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg;
+ parameter_automation.clear ();
+ return -1;
+}
+
+
void
Redirect::what_has_automation (set<uint32_t>& s) const
{
return -1;
}
- if ((prop = node.property ("flags")) != 0) {
+ if ((prop = node.property (X_("flags"))) != 0) {
int x;
sscanf (prop->value().c_str(), "0x%x", &x);
_flags = Flag (x);
_flags = Flag (0);
}
- if ((prop = node.property ("default-type")) != 0) {
+ if ((prop = node.property (X_("default-type"))) != 0) {
_default_type = DataType(prop->value());
assert(_default_type != DataType::NIL);
}
- if ((prop = node.property ("phase-invert")) != 0) {
+ if ((prop = node.property (X_("phase-invert"))) != 0) {
set_phase_invert(prop->value()=="yes"?true:false, this);
}
- if ((prop = node.property ("active")) != 0) {
+ if ((prop = node.property (X_("active"))) != 0) {
set_active (prop->value() == "yes");
}
- if ((prop = node.property ("muted")) != 0) {
+ if ((prop = node.property (X_("muted"))) != 0) {
bool yn = prop->value()=="yes"?true:false;
/* force reset of mute status */
mute_gain = desired_mute_gain;
}
- if ((prop = node.property ("soloed")) != 0) {
+ if ((prop = node.property (X_("soloed"))) != 0) {
bool yn = prop->value()=="yes"?true:false;
/* force reset of solo status */
solo_gain = desired_solo_gain;
}
- if ((prop = node.property ("mute-affects-pre-fader")) != 0) {
+ if ((prop = node.property (X_("mute-affects-pre-fader"))) != 0) {
_mute_affects_pre_fader = (prop->value()=="yes")?true:false;
}
- if ((prop = node.property ("mute-affects-post-fader")) != 0) {
+ if ((prop = node.property (X_("mute-affects-post-fader"))) != 0) {
_mute_affects_post_fader = (prop->value()=="yes")?true:false;
}
- if ((prop = node.property ("mute-affects-control-outs")) != 0) {
+ if ((prop = node.property (X_("mute-affects-control-outs"))) != 0) {
_mute_affects_control_outs = (prop->value()=="yes")?true:false;
}
- if ((prop = node.property ("mute-affects-main-outs")) != 0) {
+ if ((prop = node.property (X_("mute-affects-main-outs"))) != 0) {
_mute_affects_main_outs = (prop->value()=="yes")?true:false;
}
- if ((prop = node.property ("edit-group")) != 0) {
+ if ((prop = node.property (X_("edit-group"))) != 0) {
RouteGroup* edit_group = _session.edit_group_by_name(prop->value());
if(edit_group == 0) {
error << string_compose(_("Route %1: unknown edit group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg;
}
}
- if ((prop = node.property ("order-keys")) != 0) {
+ if ((prop = node.property (X_("order-keys"))) != 0) {
long n;
delete deferred_state;
}
- deferred_state = new XMLNode("deferred state");
+ deferred_state = new XMLNode(X_("deferred state"));
/* set parent class properties before anything else */
child = *niter;
- if (child->name() == "Send") {
+ if (child->name() == X_("Send")) {
if (!IO::ports_legal) {
add_redirect_from_xml (*child);
}
- } else if (child->name() == "Insert") {
+ } else if (child->name() == X_("Insert")) {
if (!IO::ports_legal) {
add_redirect_from_xml (*child);
}
- } else if (child->name() == "ControlOuts") {
+ } else if (child->name() == X_("Automation")) {
+
+ if ((prop = child->property (X_("path"))) != 0) {
+ load_automation (prop->value());
+ }
+
+ } else if (child->name() == X_("ControlOuts")) {
string coutname = _name;
coutname += _("[control]");
_control_outs = new IO (_session, coutname);
_control_outs->set_state (**(child->children().begin()));
- } else if (child->name() == "Comment") {
+ } else if (child->name() == X_("Comment")) {
/* XXX this is a terrible API design in libxml++ */
XMLNode *cmt = *(child->children().begin());
_comment = cmt->content();
- } else if (child->name() == "extra") {
+ } else if (child->name() == X_("extra")) {
_extra_xml = new XMLNode (*child);
- } else if (child->name() == "solo") {
+ } else if (child->name() == X_("solo")) {
_solo_control.set_state (*child);
_session.add_controllable (&_solo_control);
- } else if (child->name() == "mute") {
+ } else if (child->name() == X_("mute")) {
_mute_control.set_state (*child);
_session.add_controllable (&_mute_control);
}
}
- if ((prop = node.property ("mix-group")) != 0) {
+ if ((prop = node.property (X_("mix-group"))) != 0) {
RouteGroup* mix_group = _session.mix_group_by_name(prop->value());
if (mix_group == 0) {
error << string_compose(_("Route %1: unknown mix group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg;
nframes_t
SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
{
- nframes_t where;
-
- where = sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE);
-
- if (where != frame_pos) {
+ if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
char errbuf[256];
sf_error_str (0, errbuf, sizeof (errbuf) - 1);
- error << string_compose (_("%1: cannot seek to %2, now at %3 (libsndfile error: %4"), _path, frame_pos, where, errbuf) << endmsg;
+ error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
return 0;
}