#include "ardour/amp.h"
#include "ardour/audio_buffer.h"
+#include "ardour/audio_port.h"
#include "ardour/audioengine.h"
#include "ardour/buffer.h"
#include "ardour/buffer_set.h"
#include "ardour/internal_return.h"
#include "ardour/internal_send.h"
#include "ardour/meter.h"
+#include "ardour/midi_buffer.h"
+#include "ardour/midi_port.h"
#include "ardour/monitor_processor.h"
#include "ardour/pannable.h"
#include "ardour/panner_shell.h"
, _flags (flg)
, _pending_declick (true)
, _meter_point (MeterPostFader)
+ , _meter_type (MeterPeak)
, _self_solo (false)
, _soloed_by_others_upstream (0)
, _soloed_by_others_downstream (0)
they will be added to _processors by setup_invisible_processors ()
*/
- _meter.reset (new PeakMeter (_session));
+ _meter.reset (new PeakMeter (_session, _name));
_meter->set_display_to_user (false);
_meter->activate ();
_monitor_control->activate ();
}
- if (is_master() || is_monitor() || is_hidden()) {
+ if (is_master() || is_monitor() || is_auditioner()) {
_mute_master->set_solo_ignore (true);
}
}
if (id < 1) {
- error << _("Remote Control ID's start at one, not zero") << endmsg;
return;
}
}
void
-Route::set_remote_control_id_from_order_key (RouteSortOrderKey key, uint32_t rid)
+Route::set_remote_control_id_from_order_key (RouteSortOrderKey /*key*/, uint32_t rid)
{
- if (is_master() || is_monitor() || is_hidden()) {
+ if (is_master() || is_monitor() || is_auditioner()) {
/* hard-coded remote IDs, or no remote ID */
return;
}
on a transition between monitoring states we get a de-clicking gain
change in the _main_outs delivery.
*/
- _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
+ _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
/* -------------------------------------------------------------------------------------------
GLOBAL DECLICK (for transport changes etc.)
}
void
-Route::passthru (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+Route::monitor_run (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
{
- BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+ assert (is_monitor());
+ BufferSet& bufs (_session.get_scratch_buffers (n_process_buffers()));
+ passthru (bufs, start_frame, end_frame, nframes, declick);
+}
+void
+Route::passthru (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+{
_silent = false;
- assert (bufs.available() >= input_streams());
-
- if (_input->n_ports() == ChanCount::ZERO) {
- silence_unlocked (nframes);
- }
-
- bufs.set_count (input_streams());
-
if (is_monitor() && _session.listening() && !_session.is_auditioning()) {
/* control/monitor bus ignores input ports when something is
feeding the listen "stream". data will "arrive" into the
route from the intreturn processor element.
*/
- bufs.silence (nframes, 0);
- } else {
-
- for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-
- BufferSet::iterator o = bufs.begin(*t);
- PortSet& ports (_input->ports());
-
- for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) {
- o->read_from (i->get_buffer(nframes), nframes);
- }
- }
+ bufs.silence (nframes, 0);
}
write_out_of_band_data (bufs, start_frame, end_frame, nframes);
void
Route::set_solo_isolated (bool yn, void *src)
{
- if (is_master() || is_monitor() || is_hidden()) {
+ if (is_master() || is_monitor() || is_auditioner()) {
return;
}
boost::shared_ptr<RouteList> routes = _session.get_routes ();
for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
- if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_hidden()) {
+ if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
continue;
}
node->add_property("denormal-protection", _denormal_protection?"yes":"no");
node->add_property("meter-point", enum_2_string (_meter_point));
+ node->add_property("meter-type", enum_2_string (_meter_type));
+
if (_route_group) {
node->add_property("route-group", _route_group->name());
}
boost::shared_ptr<InternalSend> is;
if ((is = boost::dynamic_pointer_cast<InternalSend> (*i)) != 0) {
- if (is->role() == Delivery::Aux || is->role() == Delivery::Listen) {
+ if (is->role() == Delivery::Listen) {
continue;
}
}
_flags = Flag (0);
}
- if (is_master() || is_monitor() || is_hidden()) {
+ if (is_master() || is_monitor() || is_auditioner()) {
_mute_master->set_solo_ignore (true);
}
}
}
+ if ((prop = node.property (X_("meter-type"))) != 0) {
+ _meter_type = MeterType (string_2_enum (prop->value (), _meter_type));
+ }
+
set_processor_state (processor_state);
// this looks up the internal instrument in processors
_flags = Flag (0);
}
+ if (is_master() || is_monitor() || is_auditioner()) {
+ _mute_master->set_solo_ignore (true);
+ }
+
if ((prop = node.property (X_("phase-invert"))) != 0) {
boost::dynamic_bitset<> p (_input->n_ports().n_audio ());
if (string_is_affirmative (prop->value ())) {
continue;
}
- if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
- /* This processor could not be configured. Turn it into a UnknownProcessor */
- processor.reset (new UnknownProcessor (_session, **niter));
+ if (boost::dynamic_pointer_cast<PluginInsert>(processor)) {
+#ifndef NO_PLUGIN_STATE
+ if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
+ /* This processor could not be configured. Turn it into a UnknownProcessor */
+ processor.reset (new UnknownProcessor (_session, **niter));
+ }
+#else
+ /* plugin, with NO_PLUGIN_STATE defined
+ * =>::set_state() not allowed. Do not
+ * display a message here - things will
+ * get too verbose.
+ */
+#endif
+ } else {
+ if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
+ /* This processor could not be configured. Turn it into a UnknownProcessor */
+ processor.reset (new UnknownProcessor (_session, **niter));
+ }
}
/* we have to note the monitor send here, otherwise a new one will be created
/** Called from the (non-realtime) butler thread when the transport is stopped */
void
-Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors)
+Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool /*did_locate*/, bool can_flush_processors)
{
framepos_t now = _session.transport_frame();
contains ConfigurationChanged
*/
need_to_queue_solo_change = false;
+ configure_processors (0);
+ io_changed (); /* EMIT SIGNAL */
}
if (!_output->connected() && _soloed_by_others_downstream) {
Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
+
if (!lm.locked()) {
return 0;
}
silence_unlocked (nframes);
return 0;
}
+
if (session_state_changing) {
if (_session.transport_speed() != 0.0f) {
/* we're rolling but some state is changing (e.g. our diskstream contents)
*/
}
+ BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+ fill_buffers_with_input (bufs, _input, nframes);
+
+ if (_meter_point == MeterInput) {
+ _meter->run (bufs, start_frame, end_frame, nframes, true);
+ }
+
_amp->apply_gain_automation (false);
- passthru (start_frame, end_frame, nframes, 0);
+ passthru (bufs, start_frame, end_frame, nframes, 0);
return 0;
}
_silent = false;
- passthru (start_frame, end_frame, nframes, declick);
+ BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+ fill_buffers_with_input (bufs, _input, nframes);
+
+ if (_meter_point == MeterInput) {
+ _meter->run (bufs, start_frame, end_frame, nframes, true);
+ }
+
+ passthru (bufs, start_frame, end_frame, nframes, declick);
return 0;
}
void
Route::set_meter_point (MeterPoint p, bool force)
{
- /* CAN BE CALLED FROM PROCESS CONTEXT */
-
if (_meter_point == p && !force) {
return;
}
Route::the_instrument () const
{
Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+ return the_instrument_unlocked ();
+}
+
+boost::shared_ptr<Processor>
+Route::the_instrument_unlocked () const
+{
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
if (boost::dynamic_pointer_cast<PluginInsert>(*i)) {
if ((*i)->input_streams().n_midi() > 0 &&
return boost::shared_ptr<Processor>();
}
+
+
void
Route::non_realtime_locate (framepos_t pos)
{
}
}
}
+
+void
+Route::fill_buffers_with_input (BufferSet& bufs, boost::shared_ptr<IO> io, pframes_t nframes)
+{
+ size_t n_buffers;
+ size_t i;
+
+ /* MIDI
+ *
+ * We don't currently mix MIDI input together, so we don't need the
+ * complex logic of the audio case.
+ */
+
+ n_buffers = bufs.count().n_midi ();
+
+ for (i = 0; i < n_buffers; ++i) {
+
+ boost::shared_ptr<MidiPort> source_port = io->midi (i);
+ MidiBuffer& buf (bufs.get_midi (i));
+
+ if (source_port) {
+ buf.copy (source_port->get_midi_buffer(nframes));
+ } else {
+ buf.silence (nframes);
+ }
+ }
+
+ /* AUDIO */
+
+ n_buffers = bufs.count().n_audio();
+
+ size_t n_ports = io->n_ports().n_audio();
+ float scaling = 1.0f;
+
+ if (n_ports > n_buffers) {
+ scaling = ((float) n_buffers) / n_ports;
+ }
+
+ for (i = 0; i < n_ports; ++i) {
+
+ /* if there are more ports than buffers, map them onto buffers
+ * in a round-robin fashion
+ */
+
+ boost::shared_ptr<AudioPort> source_port = io->audio (i);
+ AudioBuffer& buf (bufs.get_audio (i%n_buffers));
+
+
+ if (i < n_buffers) {
+
+ /* first time through just copy a channel into
+ the output buffer.
+ */
+
+ buf.read_from (source_port->get_audio_buffer (nframes), nframes);
+
+ if (scaling != 1.0f) {
+ buf.apply_gain (scaling, nframes);
+ }
+
+ } else {
+
+ /* on subsequent times around, merge data from
+ * the port with what is already there
+ */
+
+ if (scaling != 1.0f) {
+ buf.accumulate_with_gain_from (source_port->get_audio_buffer (nframes), nframes, 0, scaling);
+ } else {
+ buf.accumulate_from (source_port->get_audio_buffer (nframes), nframes);
+ }
+ }
+ }
+
+ /* silence any remaining buffers */
+
+ for (; i < n_buffers; ++i) {
+ AudioBuffer& buf (bufs.get_audio (i));
+ buf.silence (nframes);
+ }
+
+ /* establish the initial setup of the buffer set, reflecting what was
+ copied into it. unless, of course, we are the auditioner, in which
+ case nothing was fed into it from the inputs at all.
+ */
+
+ if (!is_auditioner()) {
+ bufs.set_count (io->n_ports());
+ }
+}