Use ARDOUR::user_config_directory in ARDOUR::user_template_directory
[ardour.git] / libs / ardour / io.cc
index a9284d779c6883173aab106566e21c0260e0b1d5..3069123f165ae18a1f9d9e5c54b8c2520994036b 100644 (file)
@@ -34,7 +34,7 @@
 #include <ardour/port.h>
 #include <ardour/audio_port.h>
 #include <ardour/midi_port.h>
-#include <ardour/connection.h>
+#include <ardour/bundle.h>
 #include <ardour/session.h>
 #include <ardour/cycle_timer.h>
 #include <ardour/panner.h>
@@ -98,12 +98,11 @@ static double direct_gain_to_control (gain_t gain) {
 /** @param default_type The type of port that will be created by ensure_io
  * and friends if no type is explicitly requested (to avoid breakage).
  */
-IO::IO (Session& s, string name,
+IO::IO (Session& s, const string& name,
        int input_min, int input_max, int output_min, int output_max,
        DataType default_type)
-       : _session (s),
+       : SessionObject(s, name),
       _output_buffers(new BufferSet()),
-         _name (name),
          _default_type(default_type),
          _gain_control (X_("gaincontrol"), *this),
          _gain_automation_curve (0.0, 2.0, 1.0),
@@ -130,8 +129,8 @@ IO::IO (Session& s, string name,
 
        _gain = 1.0;
        _desired_gain = 1.0;
-       _input_connection = 0;
-       _output_connection = 0;
+       _input_bundle = 0;
+       _output_bundle = 0;
        pending_state_node = 0;
        no_panner_reset = false;
        _phase_invert = false;
@@ -158,13 +157,12 @@ IO::IO (Session& s, string name,
 }
 
 IO::IO (Session& s, const XMLNode& node, DataType dt)
-       : _session (s),
+       : SessionObject(s, "unnamed io"),
       _output_buffers(new BufferSet()),
          _default_type (dt),
          _gain_control (X_("gaincontrol"), *this),
          _gain_automation_curve (0, 0, 0) // all reset in set_state()
 {
-       // FIXME: hack
        _meter = new PeakMeter (_session);
 
        _panner = 0;
@@ -172,8 +170,8 @@ IO::IO (Session& s, const XMLNode& node, DataType dt)
        no_panner_reset = false;
        _desired_gain = 1.0;
        _gain = 1.0;
-       _input_connection = 0;
-       _output_connection = 0;
+       _input_bundle = 0;
+       _output_bundle = 0;
 
        apply_gain_automation = false;
 
@@ -249,35 +247,48 @@ IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
 
                }
 
-               Amp::run(bufs, nframes, _gain, dg, _phase_invert);
+               if (dg != _gain || dg != 1.0)
+                       Amp::run(bufs, nframes, _gain, dg, _phase_invert);
        }
        
        // Use the panner to distribute audio to output port buffers
        if (_panner && !_panner->empty() && !_panner->bypassed()) {
-               _panner->distribute(bufs, output_buffers(), start_frame, end_frame, nframes, offset);
+               _panner->distribute (bufs, output_buffers(), start_frame, end_frame, nframes, offset);
        } else {
                const DataType type = DataType::AUDIO;
-
+               
                // Copy any audio 1:1 to outputs
-               assert(bufs.count().get(DataType::AUDIO) == output_buffers().count().get(DataType::AUDIO));
+               
                BufferSet::iterator o = output_buffers().begin(type);
-               for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
+               BufferSet::iterator i = bufs.begin(type);
+               BufferSet::iterator prev = i;
+               
+               while (i != bufs.end(type) && o != output_buffers().end (type)) {
                        o->read_from(*i, nframes, offset);
+                       prev = i;
+                       ++i;
+                       ++o;
                }
-       }
 
+               /* extra outputs get a copy of the last buffer */
+
+               while (o != output_buffers().end(type)) {
+                       o->read_from(*prev, nframes, offset);
+                       ++o;
+               }
+       }
 
        /* ********** MIDI ********** */
 
        // No MIDI, we're done here
-       if (bufs.count().get(DataType::MIDI) == 0) {
+       if (bufs.count().n_midi() == 0) {
                return;
        }
 
        const DataType type = DataType::MIDI;
 
        // Copy any MIDI 1:1 to outputs
-       assert(bufs.count().get(DataType::MIDI) == output_buffers().count().get(DataType::MIDI));
+       assert(bufs.count().n_midi() == output_buffers().count().n_midi());
        BufferSet::iterator o = output_buffers().begin(type);
        for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
                o->read_from(*i, nframes, offset);
@@ -312,24 +323,24 @@ IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
 
        collect_input (bufs, nframes, offset);
 
-       _meter->run(bufs, nframes);
+       _meter->run(bufs, start_frame, end_frame, nframes, offset);
 }
 
 void
-IO::drop_input_connection ()
+IO::drop_input_bundle ()
 {
-       _input_connection = 0;
-       input_connection_configuration_connection.disconnect();
-       input_connection_connection_connection.disconnect();
+       _input_bundle = 0;
+       input_bundle_configuration_connection.disconnect();
+       input_bundle_connection_connection.disconnect();
        _session.set_dirty ();
 }
 
 void
-IO::drop_output_connection ()
+IO::drop_output_bundle ()
 {
-       _output_connection = 0;
-       output_connection_configuration_connection.disconnect();
-       output_connection_connection_connection.disconnect();
+       _output_bundle = 0;
+       output_bundle_configuration_connection.disconnect();
+       output_bundle_connection_connection.disconnect();
        _session.set_dirty ();
 }
 
@@ -359,7 +370,7 @@ IO::disconnect_input (Port* our_port, string other_port, void* src)
                                return -1;
                        }
 
-                       drop_input_connection();
+                       drop_input_bundle ();
                }
        }
 
@@ -394,7 +405,7 @@ IO::connect_input (Port* our_port, string other_port, void* src)
                                return -1;
                        }
                        
-                       drop_input_connection ();
+                       drop_input_bundle ();
                }
        }
 
@@ -429,7 +440,7 @@ IO::disconnect_output (Port* our_port, string other_port, void* src)
                                return -1;
                        }
 
-                       drop_output_connection ();
+                       drop_output_bundle ();
                }
        }
 
@@ -464,7 +475,7 @@ IO::connect_output (Port* our_port, string other_port, void* src)
                                return -1;
                        }
 
-                       drop_output_connection ();
+                       drop_output_bundle ();
                }
        }
 
@@ -480,7 +491,7 @@ IO::set_input (Port* other_port, void* src)
           to the specified source.
        */
 
-       if (_input_minimum.get_total() > 1) {
+       if (_input_minimum.n_total() > 1) {
                /* sorry, you can't do this */
                return -1;
        }
@@ -525,7 +536,7 @@ IO::remove_output_port (Port* port, void* src)
                                } 
 
                                _session.engine().unregister_port (*port);
-                               drop_output_connection ();
+                               drop_output_bundle ();
                                
                                setup_peak_meters ();
                                reset_panner ();
@@ -583,7 +594,7 @@ IO::add_output_port (string destination, void* src, DataType type)
                        }
                        
                        _outputs.add (our_port);
-                       drop_output_connection ();
+                       drop_output_bundle ();
                        setup_peak_meters ();
                        reset_panner ();
                }
@@ -629,7 +640,7 @@ IO::remove_input_port (Port* port, void* src)
                                } 
 
                                _session.engine().unregister_port (*port);
-                               drop_input_connection ();
+                               drop_input_bundle ();
                                
                                setup_peak_meters ();
                                reset_panner ();
@@ -687,7 +698,7 @@ IO::add_input_port (string source, void* src, DataType type)
                        }
 
                        _inputs.add (our_port);
-                       drop_input_connection ();
+                       drop_input_bundle ();
                        setup_peak_meters ();
                        reset_panner ();
                }
@@ -722,7 +733,7 @@ IO::disconnect_inputs (void* src)
                                _session.engine().disconnect (*i);
                        }
 
-                       drop_input_connection ();
+                       drop_input_bundle ();
                }
        }
        
@@ -744,7 +755,7 @@ IO::disconnect_outputs (void* src)
                                _session.engine().disconnect (*i);
                        }
 
-                       drop_output_connection ();
+                       drop_output_bundle ();
                }
        }
 
@@ -808,7 +819,7 @@ IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
        }
        
        if (changed) {
-               drop_input_connection ();
+               drop_input_bundle ();
                setup_peak_meters ();
                reset_panner ();
                MoreChannels (n_inputs()); /* EMIT SIGNAL */
@@ -975,12 +986,12 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
        }
 
        if (out_changed) {
-               drop_output_connection ();
+               drop_output_bundle ();
                output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
        }
        
        if (in_changed) {
-               drop_input_connection ();
+               drop_input_bundle ();
                input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
        }
 
@@ -1071,7 +1082,7 @@ IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
        }
        
        if (changed) {
-               drop_output_connection ();
+               drop_output_bundle ();
                MoreChannels (n_outputs()); /* EMIT SIGNAL */
                _session.set_dirty ();
        }
@@ -1118,7 +1129,7 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
 gain_t
 IO::effective_gain () const
 {
-       if (gain_automation_playback()) {
+       if (_gain_automation_curve.automation_playback()) {
                return _effective_gain;
        } else {
                return _desired_gain;
@@ -1130,7 +1141,7 @@ IO::reset_panner ()
 {
        if (panners_legal) {
                if (!no_panner_reset) {
-                       _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
+                       _panner->reset (n_outputs().n_audio(), pans_required());
                }
        } else {
                panner_legal_c.disconnect ();
@@ -1141,7 +1152,7 @@ IO::reset_panner ()
 int
 IO::panners_became_legal ()
 {
-       _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
+       _panner->reset (n_outputs().n_audio(), pans_required());
        _panner->load (); // automation
        panner_legal_c.disconnect ();
        return 0;
@@ -1184,13 +1195,13 @@ IO::state (bool full_state)
 
        str = "";
 
-       if (_input_connection) {
-               node->add_property ("input-connection", _input_connection->name());
+       if (_input_bundle) {
+               node->add_property ("input-connection", _input_bundle->name());
                need_ins = false;
        }
 
-       if (_output_connection) {
-               node->add_property ("output-connection", _output_connection->name());
+       if (_output_bundle) {
+               node->add_property ("output-connection", _output_bundle->name());
                need_outs = false;
        }
 
@@ -1444,7 +1455,7 @@ IO::load_automation (string path)
 
        while (in.getline (line, sizeof(line), '\n')) {
                char type;
-               jack_nframes_t when;
+               nframes_t when;
                double value;
 
                if (++linecnt == 1) {
@@ -1541,24 +1552,27 @@ IO::create_ports (const XMLNode& node)
        int num_inputs = 0;
        int num_outputs = 0;
 
+       /* XXX: we could change *-connection to *-bundle, but it seems a bit silly to
+        * break the session file format.
+        */
        if ((prop = node.property ("input-connection")) != 0) {
 
-               Connection* c = _session.connection_by_name (prop->value());
+               Bundle* c = _session.bundle_by_name (prop->value());
                
                if (c == 0) {
-                       error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
+                       error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
 
-                       if ((c = _session.connection_by_name (_("in 1"))) == 0) {
-                               error << _("No input connections available as a replacement")
+                       if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
+                               error << _("No input bundles available as a replacement")
                                      << endmsg;
                                return -1;
                        }  else {
-                               info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
+                               info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
                                     << endmsg;
                        }
                } 
 
-               num_inputs = c->nports();
+               num_inputs = c->nchannels();
 
        } else if ((prop = node.property ("inputs")) != 0) {
 
@@ -1566,22 +1580,22 @@ IO::create_ports (const XMLNode& node)
        }
        
        if ((prop = node.property ("output-connection")) != 0) {
-               Connection* c = _session.connection_by_name (prop->value());
+               Bundle* c = _session.bundle_by_name (prop->value());
 
                if (c == 0) {
-                       error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
+                       error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
 
-                       if ((c = _session.connection_by_name (_("out 1"))) == 0) {
-                               error << _("No output connections available as a replacement")
+                       if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
+                               error << _("No output bundles available as a replacement")
                                      << endmsg;
                                return -1;
                        }  else {
-                               info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
+                               info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
                                     << endmsg;
                        }
                } 
 
-               num_outputs = c->nports ();
+               num_outputs = c->nchannels ();
                
        } else if ((prop = node.property ("outputs")) != 0) {
                num_outputs = count (prop->value().begin(), prop->value().end(), '{');
@@ -1610,22 +1624,22 @@ IO::make_connections (const XMLNode& node)
        const XMLProperty* prop;
 
        if ((prop = node.property ("input-connection")) != 0) {
-               Connection* c = _session.connection_by_name (prop->value());
+               Bundle* c = _session.bundle_by_name (prop->value());
                
                if (c == 0) {
                        error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
 
-                       if ((c = _session.connection_by_name (_("in 1"))) == 0) {
+                       if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
                                error << _("No input connections available as a replacement")
                                      << endmsg;
                                return -1;
                        } else {
-                               info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
+                               info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
                                     << endmsg;
                        }
                } 
 
-               use_input_connection (*c, this);
+               use_input_bundle (*c, this);
 
        } else if ((prop = node.property ("inputs")) != 0) {
                if (set_inputs (prop->value())) {
@@ -1634,23 +1648,23 @@ IO::make_connections (const XMLNode& node)
                }
        }
        
-       if ((prop = node.property ("output-connection")) != 0) {
-               Connection* c = _session.connection_by_name (prop->value());
+       if ((prop = node.property ("output-bundle")) != 0) {
+               Bundle* c = _session.bundle_by_name (prop->value());
                
                if (c == 0) {
-                       error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
+                       error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
 
-                       if ((c = _session.connection_by_name (_("out 1"))) == 0) {
-                               error << _("No output connections available as a replacement")
+                       if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
+                               error << _("No output bundles available as a replacement")
                                      << endmsg;
                                return -1;
                        }  else {
-                               info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
+                               info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
                                     << endmsg;
                        }
                } 
 
-               use_output_connection (*c, this);
+               use_output_bundle (*c, this);
                
        } else if ((prop = node.property ("outputs")) != 0) {
                if (set_outputs (prop->value())) {
@@ -1811,14 +1825,15 @@ IO::parse_gain_string (const string& str, vector<string>& ports)
        return ports.size();
 }
 
-int
-IO::set_name (string name, void* src)
+bool
+IO::set_name (const string& str)
 {
-       if (name == _name) {
-               return 0;
+       if (str == _name) {
+               return true;
        }
-
+       
        /* replace all colons in the name. i wish we didn't have to do this */
+       string name = str;
 
        if (replace_all (name, ":", "-")) {
                warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
@@ -1836,10 +1851,7 @@ IO::set_name (string name, void* src)
                i->set_name (current_name);
        }
 
-       _name = name;
-        name_changed (src); /* EMIT SIGNAL */
-
-        return 0;
+       return SessionObject::set_name(name);
 }
 
 void
@@ -1915,7 +1927,7 @@ IO::input_latency () const
 }
 
 int
-IO::use_input_connection (Connection& c, void* src)
+IO::use_input_bundle (Bundle& c, void* src)
 {
        uint32_t limit;
 
@@ -1923,11 +1935,11 @@ IO::use_input_connection (Connection& c, void* src)
                BLOCK_PROCESS_CALLBACK ();
                Glib::Mutex::Lock lm2 (io_lock);
                
-               limit = c.nports();
+               limit = c.nchannels();
                
-               drop_input_connection ();
+               drop_input_bundle ();
                
-               // FIXME connections only work for audio-only
+               // FIXME bundles only work for audio-only
                if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
                        return -1;
                }
@@ -1937,9 +1949,9 @@ IO::use_input_connection (Connection& c, void* src)
                */
                
                for (uint32_t n = 0; n < limit; ++n) {
-                       const Connection::PortList& pl = c.port_connections (n);
+                       const Bundle::PortList& pl = c.channel_ports (n);
                        
-                       for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
+                       for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
                                
                                if (!_inputs.port(n)->connected_to ((*i))) {
                                        
@@ -1967,9 +1979,9 @@ IO::use_input_connection (Connection& c, void* src)
                /* second pass: connect all requested ports where necessary */
                
                for (uint32_t n = 0; n < limit; ++n) {
-                       const Connection::PortList& pl = c.port_connections (n);
+                       const Bundle::PortList& pl = c.channel_ports (n);
                        
-                       for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
+                       for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
                                
                                if (!_inputs.port(n)->connected_to ((*i))) {
                                        
@@ -1981,12 +1993,12 @@ IO::use_input_connection (Connection& c, void* src)
                        }
                }
                
-               _input_connection = &c;
+               _input_bundle = &c;
                
-               input_connection_configuration_connection = c.ConfigurationChanged.connect
-                       (mem_fun (*this, &IO::input_connection_configuration_changed));
-               input_connection_connection_connection = c.ConnectionsChanged.connect
-                       (mem_fun (*this, &IO::input_connection_connection_changed));
+               input_bundle_configuration_connection = c.ConfigurationChanged.connect
+                       (mem_fun (*this, &IO::input_bundle_configuration_changed));
+               input_bundle_connection_connection = c.PortsChanged.connect
+                       (mem_fun (*this, &IO::input_bundle_connection_changed));
        }
 
        input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
@@ -1994,7 +2006,7 @@ IO::use_input_connection (Connection& c, void* src)
 }
 
 int
-IO::use_output_connection (Connection& c, void* src)
+IO::use_output_bundle (Bundle& c, void* src)
 {
        uint32_t limit; 
 
@@ -2002,9 +2014,9 @@ IO::use_output_connection (Connection& c, void* src)
                BLOCK_PROCESS_CALLBACK ();
                Glib::Mutex::Lock lm2 (io_lock);
 
-               limit = c.nports();
+               limit = c.nchannels();
                        
-               drop_output_connection ();
+               drop_output_bundle ();
 
                // FIXME: audio-only
                if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
@@ -2017,9 +2029,9 @@ IO::use_output_connection (Connection& c, void* src)
                        
                for (uint32_t n = 0; n < limit; ++n) {
 
-                       const Connection::PortList& pl = c.port_connections (n);
+                       const Bundle::PortList& pl = c.channel_ports (n);
                                
-                       for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
+                       for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
                                        
                                if (!_outputs.port(n)->connected_to ((*i))) {
 
@@ -2047,9 +2059,9 @@ IO::use_output_connection (Connection& c, void* src)
 
                for (uint32_t n = 0; n < limit; ++n) {
 
-                       const Connection::PortList& pl = c.port_connections (n);
+                       const Bundle::PortList& pl = c.channel_ports (n);
                                
-                       for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
+                       for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
                                        
                                if (!_outputs.port(n)->connected_to ((*i))) {
                                                
@@ -2060,12 +2072,12 @@ IO::use_output_connection (Connection& c, void* src)
                        }
                }
 
-               _output_connection = &c;
+               _output_bundle = &c;
 
-               output_connection_configuration_connection = c.ConfigurationChanged.connect
-                       (mem_fun (*this, &IO::output_connection_configuration_changed));
-               output_connection_connection_connection = c.ConnectionsChanged.connect
-                       (mem_fun (*this, &IO::output_connection_connection_changed));
+               output_bundle_configuration_connection = c.ConfigurationChanged.connect
+                       (mem_fun (*this, &IO::output_bundle_configuration_changed));
+               output_bundle_connection_connection = c.PortsChanged.connect
+                       (mem_fun (*this, &IO::output_bundle_connection_changed));
        }
 
        output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
@@ -2116,27 +2128,27 @@ IO::reset_panners ()
 }
 
 void
-IO::input_connection_connection_changed (int ignored)
+IO::input_bundle_connection_changed (int ignored)
 {
-       use_input_connection (*_input_connection, this);
+       use_input_bundle (*_input_bundle, this);
 }
 
 void
-IO::input_connection_configuration_changed ()
+IO::input_bundle_configuration_changed ()
 {
-       use_input_connection (*_input_connection, this);
+       use_input_bundle (*_input_bundle, this);
 }
 
 void
-IO::output_connection_connection_changed (int ignored)
+IO::output_bundle_connection_changed (int ignored)
 {
-       use_output_connection (*_output_connection, this);
+       use_output_bundle (*_output_bundle, this);
 }
 
 void
-IO::output_connection_configuration_changed ()
+IO::output_bundle_configuration_changed ()
 {
-       use_output_connection (*_output_connection, this);
+       use_output_bundle (*_output_bundle, this);
 }
 
 void
@@ -2154,7 +2166,8 @@ IO::GainControllable::get_value (void) const
 void
 IO::setup_peak_meters()
 {
-       _meter->setup(std::max(_inputs.count(), _outputs.count()));
+       ChanCount max_streams = std::max(_inputs.count(), _outputs.count());
+       _meter->configure_io(max_streams, max_streams);
 }
 
 /**
@@ -2211,28 +2224,17 @@ IO::set_gain_automation_state (AutoState state)
 
        if (changed) {
                _session.set_dirty ();
-               gain_automation_state_changed (); /* EMIT SIGNAL */
+               //gain_automation_state_changed (); /* EMIT SIGNAL */
        }
 }
 
 void
 IO::set_gain_automation_style (AutoStyle style)
 {
-       bool changed = false;
-
-       {
-               Glib::Mutex::Lock lm (automation_lock);
-
-               if (style != _gain_automation_curve.automation_style()) {
-                       changed = true;
-                       _gain_automation_curve.set_automation_style (style);
-               }
-       }
-
-       if (changed) {
-               gain_automation_style_changed (); /* EMIT SIGNAL */
-       }
+       Glib::Mutex::Lock lm (automation_lock);
+       _gain_automation_curve.set_automation_style (style);
 }
+
 void
 IO::inc_gain (gain_t factor, void *src)
 {
@@ -2261,7 +2263,7 @@ IO::set_gain (gain_t val, void *src)
        gain_changed (src);
        _gain_control.Changed (); /* EMIT SIGNAL */
        
-       if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
+       if (_session.transport_stopped() && src != 0 && src != this && _gain_automation_curve.automation_write()) {
                _gain_automation_curve.add (_session.transport_frame(), val);
                
        }
@@ -2303,7 +2305,7 @@ IO::automation_snapshot (nframes_t now)
 {
        if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
 
-               if (gain_automation_recording()) {
+               if (_gain_automation_curve.automation_write()) {
                        _gain_automation_curve.rt_add (now, gain());
                }
                
@@ -2420,7 +2422,17 @@ IO::set_phase_invert (bool yn, void *src)
 {
        if (_phase_invert != yn) {
                _phase_invert = yn;
+               //  phase_invert_changed (src); /* EMIT SIGNAL */
        }
-       //  phase_invert_changed (src); /* EMIT SIGNAL */
 }
 
+void
+IO::set_denormal_protection (bool yn, void *src)
+{
+       if (_denormal_protection != yn) {
+               _denormal_protection = yn;
+               //  denormal_protection_changed (src); /* EMIT SIGNAL */
+       }
+}
+
+