ardour
delivery.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify it
5  under the terms of the GNU General Public License as published by the Free
6  Software Foundation; either version 2 of the License, or (at your option)
7  any later version.
8 
9  This program is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12  for more details.
13 
14  You should have received a copy of the GNU General Public License along
15  with this program; if not, write to the Free Software Foundation, Inc.,
16  675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 
19 #include <cmath>
20 #include <algorithm>
21 
22 #include "pbd/enumwriter.h"
23 #include "pbd/convert.h"
24 
25 #include "ardour/amp.h"
26 #include "ardour/audioengine.h"
27 #include "ardour/buffer_set.h"
28 #include "ardour/debug.h"
29 #include "ardour/delivery.h"
30 #include "ardour/io.h"
31 #include "ardour/mute_master.h"
32 #include "ardour/pannable.h"
33 #include "ardour/panner_shell.h"
34 #include "ardour/port.h"
35 #include "ardour/session.h"
36 
37 #include "i18n.h"
38 
39 namespace ARDOUR { class Panner; }
40 
41 using namespace std;
42 using namespace PBD;
43 using namespace ARDOUR;
44 
45 PBD::Signal0<void> Delivery::PannersLegal;
46 bool Delivery::panners_legal = false;
47 
48 /* deliver to an existing IO object */
49 
50 Delivery::Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<Pannable> pannable,
51  boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
52  : IOProcessor(s, boost::shared_ptr<IO>(), (role_requires_output_ports (r) ? io : boost::shared_ptr<IO>()), name)
53  , _role (r)
54  , _output_buffers (new BufferSet())
55  , _current_gain (GAIN_COEFF_UNITY)
56  , _no_outs_cuz_we_no_monitor (false)
57  , _mute_master (mm)
58  , _no_panner_reset (false)
59 {
60  if (pannable) {
61  bool is_send = false;
62  if (r & (Delivery::Send|Delivery::Aux)) is_send = true;
63  _panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable, is_send));
64  }
65 
66  _display_to_user = false;
67 
68  if (_output) {
69  _output->changed.connect_same_thread (*this, boost::bind (&Delivery::output_changed, this, _1, _2));
70  }
71 }
72 
73 /* deliver to a new IO object */
74 
75 Delivery::Delivery (Session& s, boost::shared_ptr<Pannable> pannable, boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
76  : IOProcessor(s, false, (role_requires_output_ports (r) ? true : false), name, "", DataType::AUDIO, (r == Send))
77  , _role (r)
78  , _output_buffers (new BufferSet())
79  , _current_gain (GAIN_COEFF_UNITY)
80  , _no_outs_cuz_we_no_monitor (false)
81  , _mute_master (mm)
82  , _no_panner_reset (false)
83 {
84  if (pannable) {
85  bool is_send = false;
86  if (r & (Delivery::Send|Delivery::Aux)) is_send = true;
87  _panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable, is_send));
88  }
89 
90  _display_to_user = false;
91 
92  if (_output) {
93  _output->changed.connect_same_thread (*this, boost::bind (&Delivery::output_changed, this, _1, _2));
94  }
95 }
96 
97 
99 {
100  DEBUG_TRACE (DEBUG::Destruction, string_compose ("delivery %1 destructor\n", _name));
101 
102  /* this object should vanish from any signal callback lists
103  that it is on before we get any further. The full qualification
104  of the method name is not necessary, but is here to make it
105  clear that this call is about signals, not data flow connections.
106  */
107 
109 
110  delete _output_buffers;
111 }
112 
113 std::string
115 {
116  switch (_role) {
117  case Main:
118  return _("main outs");
119  break;
120  case Listen:
121  return _("listen");
122  break;
123  case Send:
124  case Insert:
125  default:
126  return name();
127  }
128 }
129 
130 bool
132 {
133  if (_role == Main) {
134 
135  /* the out buffers will be set to point to the port output buffers
136  of our output object.
137  */
138 
139  if (_output) {
140  if (_output->n_ports() != ChanCount::ZERO) {
141  /* increase number of output ports if the processor chain requires it */
142  out = ChanCount::max (_output->n_ports(), in);
143  return true;
144  } else {
145  /* not configured yet - we will passthru */
146  out = in;
147  return true;
148  }
149  } else {
150  fatal << "programming error: this should never be reached" << endmsg;
151  abort(); /*NOTREACHED*/
152  }
153 
154 
155  } else if (_role == Insert) {
156 
157  /* the output buffers will be filled with data from the *input* ports
158  of this Insert.
159  */
160 
161  if (_input) {
162  if (_input->n_ports() != ChanCount::ZERO) {
163  out = _input->n_ports();
164  return true;
165  } else {
166  /* not configured yet - we will passthru */
167  out = in;
168  return true;
169  }
170  } else {
171  fatal << "programming error: this should never be reached" << endmsg;
172  abort(); /*NOTREACHED*/
173  }
174 
175  } else {
176  fatal << "programming error: this should never be reached" << endmsg;
177  }
178 
179  return false;
180 }
181 
183 bool
185 {
186 #ifndef NDEBUG
187  bool r = AudioEngine::instance()->process_lock().trylock();
188  assert (!r && "trylock inside Delivery::configure_io");
189 #endif
190 
191  /* check configuration by comparison with our I/O port configuration, if appropriate.
192  see ::can_support_io_configuration() for comments
193  */
194 
195  if (_role == Main) {
196 
197  if (_output) {
198  if (_output->n_ports() != out) {
199  if (_output->n_ports() != ChanCount::ZERO) {
200  _output->ensure_io (out, false, this);
201  } else {
202  /* I/O not yet configured */
203  }
204  }
205  }
206 
207  } else if (_role == Insert) {
208 
209  if (_input) {
210  if (_input->n_ports() != in) {
211  if (_input->n_ports() != ChanCount::ZERO) {
212  fatal << _name << " programming error: configure_io called with " << in << " and " << out << " with " << _input->n_ports() << " input ports" << endmsg;
213  abort(); /*NOTREACHED*/
214  } else {
215  /* I/O not yet configured */
216  }
217  }
218  }
219 
220  }
221 
222  if (!Processor::configure_io (in, out)) {
223  return false;
224  }
225 
226  reset_panner ();
227 
228  return true;
229 }
230 
231 void
232 Delivery::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, bool result_required)
233 {
234  assert (_output);
235 
236  PortSet& ports (_output->ports());
237  gain_t tgain;
238 
239  if (_output->n_ports ().get (_output->default_type()) == 0) {
240  goto out;
241  }
242 
243  if (!_active && !_pending_active) {
244  _output->silence (nframes);
245  goto out;
246  }
247 
248  /* this setup is not just for our purposes, but for anything that comes after us in the
249  processing pathway that wants to use this->output_buffers() for some reason.
250  */
251 
252  // TODO delayline -- latency-compensation
253  output_buffers().get_backend_port_addresses (ports, nframes);
254 
255  // this Delivery processor is not a derived type, and thus we assume
256  // we really can modify the buffers passed in (it is almost certainly
257  // the main output stage of a Route). Contrast with Send::run()
258  // which cannot do this.
259 
260  tgain = target_gain ();
261 
262  if (tgain != _current_gain) {
263  /* target gain has changed */
264 
266 
267  } else if (tgain < GAIN_COEFF_SMALL) {
268 
269  /* we were quiet last time, and we're still supposed to be quiet.
270  Silence the outputs, and make sure the buffers are quiet too,
271  */
272 
273  _output->silence (nframes);
274  if (result_required) {
275  bufs.set_count (output_buffers().count ());
276  Amp::apply_simple_gain (bufs, nframes, GAIN_COEFF_ZERO);
277  }
278  goto out;
279 
280  } else if (tgain != GAIN_COEFF_UNITY) {
281 
282  /* target gain has not changed, but is not unity */
283  Amp::apply_simple_gain (bufs, nframes, tgain);
284  }
285 
286  if (_panshell && !_panshell->bypassed() && _panshell->panner()) {
287 
288  // Use the panner to distribute audio to output port buffers
289 
290  _panshell->run (bufs, output_buffers(), start_frame, end_frame, nframes);
291 
292  // MIDI data will not have been delivered by the panner
293 
294  if (bufs.count().n_midi() > 0 && ports.count().n_midi () > 0) {
295  _output->copy_to_outputs (bufs, DataType::MIDI, nframes, 0);
296  }
297 
298  } else {
299 
300  // Do a 1:1 copy of data to output ports
301 
302  if (bufs.count().n_audio() > 0 && ports.count().n_audio () > 0) {
303  _output->copy_to_outputs (bufs, DataType::AUDIO, nframes, 0);
304  }
305 
306  if (bufs.count().n_midi() > 0 && ports.count().n_midi () > 0) {
307  _output->copy_to_outputs (bufs, DataType::MIDI, nframes, 0);
308  }
309  }
310 
311  if (result_required) {
312  bufs.read_from (output_buffers (), nframes);
313  }
314 
315  out:
317 }
318 
319 XMLNode&
320 Delivery::state (bool full_state)
321 {
322  XMLNode& node (IOProcessor::state (full_state));
323 
324  if (_role & Main) {
325  node.add_property("type", "main-outs");
326  } else if (_role & Listen) {
327  node.add_property("type", "listen");
328  } else {
329  node.add_property("type", "delivery");
330  }
331 
332  node.add_property("role", enum_2_string(_role));
333 
334  if (_panshell) {
335  node.add_child_nocopy (_panshell->get_state ());
336  if (_panshell->pannable()) {
337  node.add_child_nocopy (_panshell->pannable()->get_state ());
338  }
339  }
340 
341  return node;
342 }
343 
344 int
345 Delivery::set_state (const XMLNode& node, int version)
346 {
347  const XMLProperty* prop;
348 
349  if (IOProcessor::set_state (node, version)) {
350  return -1;
351  }
352 
353  if ((prop = node.property ("role")) != 0) {
354  _role = Role (string_2_enum (prop->value(), _role));
355  // std::cerr << this << ' ' << _name << " set role to " << enum_2_string (_role) << std::endl;
356  } else {
357  // std::cerr << this << ' ' << _name << " NO ROLE INFO\n";
358  }
359 
360  XMLNode* pan_node = node.child (X_("PannerShell"));
361 
362  if (pan_node && _panshell) {
363  _panshell->set_state (*pan_node, version);
364  }
365 
366  reset_panner ();
367 
368  XMLNode* pannnode = node.child (X_("Pannable"));
369  if (_panshell && _panshell->panner() && pannnode) {
370  _panshell->pannable()->set_state (*pannnode, version);
371  }
372 
373  return 0;
374 }
375 
376 void
378 {
379  /* caller must hold process lock */
380 
381  _panshell.reset ();
382 }
383 
384 uint32_t
386 {
387  if (_output) {
388  return _output->n_ports().n_audio();
389  }
390 
391  return _configured_output.n_audio();
392 }
393 
394 void
396 {
397  if (panners_legal) {
398  if (!_no_panner_reset) {
399 
400  if (_panshell && _role != Insert && _role != Listen) {
402  }
403  }
404 
405  } else {
407  PannersLegal.connect_same_thread (panner_legal_c, boost::bind (&Delivery::panners_became_legal, this));
408  }
409 }
410 
411 void
413 {
414  if (_panshell && _role != Insert) {
416  }
417 
419 }
420 
421 void
423 {
424  _no_panner_reset = true;
425 }
426 
427 void
429 {
430  _no_panner_reset = false;
431  reset_panner ();
432 }
433 
434 
435 int
437 {
438  panners_legal = false;
439  return 0;
440 }
441 
442 void
444 {
445  panners_legal = true;
446  PannersLegal ();
447 }
448 
449 void
451 {
452  /* io_lock, not taken: function must be called from Session::process() calltree */
453 
454  if (!_output) {
455  return;
456  }
457 
458  PortSet& ports (_output->ports());
459 
460  for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
461  i->flush_buffers (nframes);
462  }
463 }
464 
465 void
467 {
469 
470  if (_panshell) {
471  _panshell->pannable()->transport_stopped (now);
472  }
473 
474  if (_output) {
475  PortSet& ports (_output->ports());
476 
477  for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
478  i->transport_stopped ();
479  }
480  }
481 }
482 
483 void
485 {
486  if (_output) {
487  PortSet& ports (_output->ports());
488 
489  for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
490  i->realtime_locate ();
491  }
492  }
493 }
494 
495 gain_t
497 {
498  /* if we've been requested to deactivate, our target gain is zero */
499 
500  if (!_pending_active) {
501  return GAIN_COEFF_ZERO;
502  }
503 
504  /* if we've been told not to output because its a monitoring situation and
505  we're not monitoring, then be quiet.
506  */
507 
509  return GAIN_COEFF_ZERO;
510  }
511 
512  MuteMaster::MutePoint mp = MuteMaster::Main; // stupid gcc uninit warning
513 
514  switch (_role) {
515  case Main:
516  mp = MuteMaster::Main;
517  break;
518  case Listen:
519  mp = MuteMaster::Listen;
520  break;
521  case Send:
522  case Insert:
523  case Aux:
524  if (_pre_fader) {
526  } else {
528  }
529  break;
530  }
531 
532  gain_t desired_gain = _mute_master->mute_gain_at (mp);
533 
534  if (_role == Listen && _session.monitor_out() && !_session.listening()) {
535 
536  /* nobody is soloed, and this delivery is a listen-send to the
537  control/monitor/listen bus, we should be silent since
538  it gets its signal from the master out.
539  */
540 
541  desired_gain = GAIN_COEFF_ZERO;
542 
543  }
544 
545  return desired_gain;
546 }
547 
548 void
550 {
552 }
553 
554 bool
555 Delivery::set_name (const std::string& name)
556 {
557  bool ret = IOProcessor::set_name (name);
558 
559  if (ret && _panshell) {
560  ret = _panshell->set_name (name);
561  }
562 
563  return ret;
564 }
565 
566 bool ignore_output_change = false;
567 
568 void
569 Delivery::output_changed (IOChange change, void* /*src*/)
570 {
571  if (change.type & IOChange::ConfigurationChanged) {
572  reset_panner ();
574  }
575 }
576 
579 {
580  if (_panshell) {
581  return _panshell->panner();
582  } else {
583  return boost::shared_ptr<Panner>();
584  }
585 }
586 
bool _pre_fader
true if this processor is currently placed before the Amp, otherwise false
Definition: processor.h:134
int set_state(const XMLNode &, int version)
Definition: delivery.cc:345
void no_outs_cuz_we_no_monitor(bool)
Definition: delivery.cc:549
framecnt_t nominal_frame_rate() const
Definition: session.h:367
ARDOUR::Session & _session
LIBPBD_API Transmitter fatal
void run(BufferSet &bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, bool)
Definition: delivery.cc:232
const std::string & value() const
Definition: xml++.h:159
Delivery(Session &s, boost::shared_ptr< IO > io, boost::shared_ptr< Pannable >, boost::shared_ptr< MuteMaster > mm, const std::string &name, Role)
bool ignore_output_change
Definition: delivery.cc:566
LIBARDOUR_API uint64_t Destruction
Definition: debug.cc:38
#define enum_2_string(e)
Definition: enumwriter.h:97
virtual void transport_stopped(framepos_t now)
Definition: automatable.cc:370
bool _no_outs_cuz_we_no_monitor
Definition: delivery.h:115
uint32_t pans_required() const
Definition: delivery.h:103
void flush_buffers(framecnt_t nframes)
Definition: delivery.cc:450
void set_count(const ChanCount &count)
Definition: buffer_set.h:93
static int disable_panners(void)
Definition: delivery.cc:436
XMLNode & state(bool full)
Definition: delivery.cc:320
void reset_panner()
Definition: delivery.cc:395
bool apply_gain() const
Definition: amp.h:50
mute all pre-fader sends
Definition: mute_master.h:39
bool can_support_io_configuration(const ChanCount &in, ChanCount &out)
Definition: delivery.cc:131
uint32_t pframes_t
Definition: types.h:61
uint32_t n_audio() const
Definition: chan_count.h:63
Definition: Beats.hpp:239
float gain_t
Definition: types.h:58
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
void read_from(const BufferSet &in, framecnt_t nframes)
Definition: buffer_set.cc:434
static AudioEngine * instance()
Definition: audioengine.h:196
#define GAIN_COEFF_ZERO
Definition: dB.h:26
boost::shared_ptr< IO > _output
Definition: io_processor.h:84
void output_changed(IOChange, void *)
Definition: delivery.cc:569
uint32_t n_midi() const
Definition: chan_count.h:66
int set_state(const XMLNode &, int version)
ChanCount _configured_output
Definition: processor.h:132
#define _(Text)
Definition: i18n.h:11
virtual uint32_t pan_outs() const
Definition: delivery.cc:385
#define X_(Text)
Definition: i18n.h:13
int64_t framecnt_t
Definition: types.h:76
XMLProperty * property(const char *)
Definition: xml++.cc:413
#define string_2_enum(str, e)
Definition: enumwriter.h:98
enum ARDOUR::IOChange::Type type
#define GAIN_COEFF_SMALL
Definition: dB.h:27
bool _no_panner_reset
Definition: delivery.h:125
Definition: amp.h:29
bool set_name(const std::string &str)
BufferSet & output_buffers()
Definition: delivery.h:83
static void reset_panners()
Definition: delivery.cc:443
static void apply_simple_gain(BufferSet &bufs, framecnt_t nframes, gain_t target, bool midi_amp=true)
Definition: amp.cc:306
virtual bool configure_io(ChanCount in, ChanCount out)
Definition: processor.cc:246
gain_t _current_gain
Definition: delivery.h:109
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
static ChanCount max(const ChanCount &a, const ChanCount &b)
Definition: chan_count.h:138
int64_t framepos_t
Definition: types.h:66
bool set_name(const std::string &name)
Definition: delivery.cc:555
PBD::Property< std::string > _name
static bool panners_legal
Definition: delivery.h:118
mute all post-fader sends
Definition: mute_master.h:40
void get_backend_port_addresses(PortSet &, framecnt_t)
Definition: buffer_set.cc:124
XMLProperty * add_property(const char *name, const std::string &value)
XMLNode & state(bool full_state)
Glib::Threads::Mutex & process_lock()
Definition: audioengine.h:132
void realtime_locate()
Definition: delivery.cc:484
const char * name
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
boost::shared_ptr< PannerShell > _panshell
Definition: delivery.h:110
BufferSet * _output_buffers
Definition: delivery.h:108
boost::shared_ptr< IO > _input
Definition: io_processor.h:83
Definition: xml++.h:95
PBD::ScopedConnection panner_legal_c
Definition: delivery.h:122
std::string name() const
const ChanCount & count() const
Definition: buffer_set.h:87
void defer_pan_reset()
Definition: delivery.cc:422
bool listening() const
Definition: session.h:692
bool configure_io(ChanCount in, ChanCount out)
Definition: delivery.cc:184
boost::shared_ptr< MuteMaster > _mute_master
Definition: delivery.h:116
Definition: debug.h:30
void panners_became_legal()
Definition: delivery.cc:412
XMLNode * child(const char *) const
Definition: xml++.cc:309
void allow_pan_reset()
Definition: delivery.cc:428
static PBD::Signal0< void > PannersLegal
Definition: delivery.h:119
#define GAIN_COEFF_UNITY
Definition: dB.h:28
static const ChanCount ZERO
Definition: chan_count.h:149
void transport_stopped(framepos_t frame)
Definition: delivery.cc:466
boost::shared_ptr< Route > monitor_out() const
Definition: session.h:717
boost::shared_ptr< Panner > panner() const
Definition: delivery.cc:578
std::string display_name() const
Definition: delivery.cc:114
void attach_buffers(PortSet &ports)
Definition: buffer_set.cc:99
gain_t target_gain()
Definition: delivery.cc:496
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
Definition: io.h:67
mute listen out
Definition: mute_master.h:41