Classes derived from AutomationControl now check ::writable() in their ::set_value() methods to ensure that they
do not attempt to overwrite data sent to them while automation playback is underway.
void
Amp::GainControl::set_value (double val)
+{
+ if (writable()) {
+ set_value_unchecked (val);
+ }
+}
+
+void
+Amp::GainControl::set_value_unchecked (double val)
{
AutomationControl::set_value (std::max (std::min (val, (double)_desc.upper), (double)_desc.lower));
_amp->session().set_dirty ();
}
void set_value (double val);
+ void set_value_unchecked (double);
double internal_to_interface (double) const;
double interface_to_internal (double) const;
void start_touch(double when);
void stop_touch(bool mark, double when);
+ /* inherited from PBD::Controllable.
+ * Derived classes MUST call ::writable() to verify
+ * that writing to the parameter is legal at that time.
+ */
void set_value (double);
double get_value () const;
+ /* automation related value setting */
+ virtual bool writable () const;
+ /* Call to ::set_value() with no test for writable() because
+ * this is only used by automation playback. We would like
+ * to make it pure virtual
+ */
+ virtual void set_value_unchecked (double val) {}
+
double lower() const { return _desc.lower; }
double upper() const { return _desc.upper; }
double normal() const { return _desc.normal; }
{}
void set_value (double val);
+ void set_value_unchecked (double);
+ bool writable() const { return true; }
MidiTrack* _route;
};
double lower () const;
void set_value (double);
+ void set_value_unchecked (double);
private:
Pannable* owner;
boost::shared_ptr<AutomationList> list=boost::shared_ptr<AutomationList>());
void set_value (double val);
+ void set_value_unchecked (double);
double get_value (void) const;
void catch_up_with_external_value (double val);
XMLNode& get_state();
void set_value (const Variant& val);
void set_value (double val);
+ void set_value_unchecked (double);
double get_value (void) const;
XMLNode& get_state();
public:
SoloControllable (std::string name, boost::shared_ptr<Route>);
void set_value (double);
+ void set_value_unchecked (double);
double get_value () const;
private:
public:
MuteControllable (std::string name, boost::shared_ptr<Route>);
void set_value (double);
+ void set_value_unchecked (double);
double get_value () const;
/* Pretend to change value, but do not affect actual route mute. */
RecEnableControl (boost::shared_ptr<Track> t);
void set_value (double);
+ void set_value_unchecked (double);
double get_value (void) const;
boost::weak_ptr<Track> track;
#include "ardour/session.h"
#include "pbd/memento_command.h"
+#include "pbd/stacktrace.h"
#include "i18n.h"
{
}
+bool
+AutomationControl::writable() const
+{
+ boost::shared_ptr<AutomationList> al = alist();
+ if (al) {
+ return al->automation_state() != Play;
+ }
+ return true;
+}
+
/** Get the current effective `user' value based on automation state */
double
AutomationControl::get_value() const
void
MidiTrack::MidiControl::set_value(double val)
+{
+ if (writable()) {
+ set_value_unchecked (val);
+ }
+}
+
+void
+MidiTrack::MidiControl::set_value_unchecked(double val)
{
const Evoral::Parameter ¶meter = _list ? _list->parameter() : Control::parameter();
const Evoral::ParameterDescriptor &desc = EventTypeMap::instance().descriptor(parameter);
void
PanControllable::set_value (double v)
{
- boost::shared_ptr<Panner> p = owner->panner();
+ if (writable()) {
+ set_value_unchecked (v);
+ }
+}
+
+void
+PanControllable::set_value_unchecked (double v)
+{
+ boost::shared_ptr<Panner> p = owner->panner();
if (!p) {
/* no panner: just do it */
const float val = c->list()->rt_safe_eval (now, valid);
if (valid) {
- c->set_value(val);
+ /* This is the ONLY place where we are
+ * allowed to call
+ * AutomationControl::set_value_unchecked(). We
+ * know that the control is in
+ * automation playback mode, so no
+ * check on writable() is required
+ * (which must be done in AutomationControl::set_value()
+ *
+ */
+ c->set_value_unchecked(val);
}
}
/** @param val `user' value */
void
PluginInsert::PluginControl::set_value (double user_val)
+{
+ if (writable()) {
+ set_value_unchecked (user_val);
+ }
+}
+
+void
+PluginInsert::PluginControl::set_value_unchecked (double user_val)
{
/* FIXME: probably should be taking out some lock here.. */
void
PluginInsert::PluginPropertyControl::set_value (double user_val)
+{
+ if (writable()) {
+ set_value_unchecked (user_val);
+ }
+}
+
+void
+PluginInsert::PluginPropertyControl::set_value_unchecked (double user_val)
{
/* Old numeric set_value(), coerce to appropriate datatype if possible.
This is lossy, but better than nothing until Ardour's automation system
void
Route::SoloControllable::set_value (double val)
+{
+ if (writable()) {
+ set_value_unchecked (val);
+ }
+}
+
+void
+Route::SoloControllable::set_value_unchecked (double val)
{
const bool bval = ((val >= 0.5) ? true : false);
void
Route::MuteControllable::set_value (double val)
+{
+ if (writable()) {
+ set_value_unchecked (val);
+ }
+}
+
+void
+Route::MuteControllable::set_value_unchecked (double val)
{
const bool bval = ((val >= 0.5) ? true : false);
void
Track::RecEnableControl::set_value (double val)
+{
+ if (writable()) {
+ set_value_unchecked (val);
+ }
+}
+
+void
+Track::RecEnableControl::set_value_unchecked (double val)
{
boost::shared_ptr<Track> t = track.lock ();
if (!t) {