ardour
internal_send.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
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #include "pbd/error.h"
21 #include "pbd/failed_constructor.h"
22 
23 #include "ardour/amp.h"
24 #include "ardour/audio_buffer.h"
25 #include "ardour/internal_return.h"
26 #include "ardour/internal_send.h"
27 #include "ardour/meter.h"
28 #include "ardour/panner_shell.h"
29 #include "ardour/route.h"
30 #include "ardour/session.h"
31 #include "ardour/audioengine.h"
32 
33 #include "i18n.h"
34 
35 namespace ARDOUR { class MuteMaster; class Pannable; }
36 
37 using namespace PBD;
38 using namespace ARDOUR;
39 using namespace std;
40 
41 PBD::Signal1<void, pframes_t> InternalSend::CycleStart;
42 
43 InternalSend::InternalSend (Session& s,
46  boost::shared_ptr<Route> sendfrom,
48  Delivery::Role role,
49  bool ignore_bitslot)
50  : Send (s, p, mm, role, ignore_bitslot)
51  , _send_from (sendfrom)
52 {
53  if (sendto) {
54  if (use_target (sendto)) {
55  throw failed_constructor();
56  }
57  }
58 
59  init_gain ();
60 
61  _send_from->DropReferences.connect_same_thread (source_connection, boost::bind (&InternalSend::send_from_going_away, this));
62  CycleStart.connect_same_thread (*this, boost::bind (&InternalSend::cycle_start, this, _1));
63 }
64 
66 {
67  if (_send_to) {
69  }
70 }
71 
72 void
74 {
75  if (_role == Listen) {
76  /* send to monitor bus is always at unity */
77  _amp->set_gain (GAIN_COEFF_UNITY, this);
78  } else {
79  /* aux sends start at -inf dB */
80  _amp->set_gain (GAIN_COEFF_ZERO, this);
81  }
82 }
83 
84 int
86 {
87  if (_send_to) {
89  }
90 
91  _send_to = sendto;
92 
94 
96  mixbufs.set_count (_send_to->internal_return()->input_streams());
97 
98  reset_panner ();
99 
100  set_name (sendto->name());
101  _send_to_id = _send_to->id();
102 
104 
105  _send_to->DropReferences.connect_same_thread (target_connections, boost::bind (&InternalSend::send_to_going_away, this));
106  _send_to->PropertyChanged.connect_same_thread (target_connections, boost::bind (&InternalSend::send_to_property_changed, this, _1));
107  _send_to->io_changed.connect_same_thread (target_connections, boost::bind (&InternalSend::target_io_changed, this));
108 
109  return 0;
110 }
111 
112 void
114 {
115  assert (_send_to);
117  mixbufs.set_count (_send_to->internal_return()->input_streams());
118  reset_panner();
119 }
120 
121 void
123 {
124  _send_from.reset();
125 }
126 
127 void
129 {
131  _send_to.reset ();
132  _send_to_id = "0";
133 }
134 
135 void
136 InternalSend::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, bool)
137 {
138  if ((!_active && !_pending_active) || !_send_to) {
139  _meter->reset ();
140  return;
141  }
142 
143  // we have to copy the input, because we may alter the buffers with the amp
144  // in-place, which a send must never do.
145 
146  if (_panshell && !_panshell->bypassed() && role() != Listen) {
147  _panshell->run (bufs, mixbufs, start_frame, end_frame, nframes);
148  } else {
149  if (role() == Listen) {
150  /* We're going to the monitor bus, so discard MIDI data */
151 
152  uint32_t const bufs_audio = bufs.count().get (DataType::AUDIO);
153  uint32_t const mixbufs_audio = mixbufs.count().get (DataType::AUDIO);
154 
155  /* monitor-section has same number of channels as master-bus (on creation).
156  *
157  * There is no clear answer what should happen when trying to PFL or AFL
158  * a track that has more channels (bufs_audio from source-track is
159  * larger than mixbufs).
160  *
161  * There are two options:
162  * 1: discard additional channels (current)
163  * OR
164  * 2: require the monitor-section to have at least as many channels
165  * as the largest count of any route
166  */
167  //assert (mixbufs.available().get (DataType::AUDIO) >= bufs_audio);
168 
169  /* Copy bufs into mixbufs, going round bufs more than once if necessary
170  to ensure that every mixbuf gets some data.
171  */
172 
173  uint32_t j = 0;
174  for (uint32_t i = 0; i < mixbufs_audio; ++i) {
175  mixbufs.get_audio(i).read_from (bufs.get_audio(j), nframes);
176  ++j;
177 
178  if (j == bufs_audio) {
179  j = 0;
180  }
181  }
182 
183  } else {
184  assert (mixbufs.available() >= bufs.count());
185  mixbufs.read_from (bufs, nframes);
186  }
187  }
188 
189  /* gain control */
190 
191  gain_t tgain = target_gain ();
192 
193  if (tgain != _current_gain) {
194 
195  /* target gain has changed */
196 
198 
199  } else if (tgain == GAIN_COEFF_ZERO) {
200 
201  /* we were quiet last time, and we're still supposed to be quiet.
202  */
203 
204  _meter->reset ();
206  goto out;
207 
208  } else if (tgain != GAIN_COEFF_UNITY) {
209 
210  /* target gain has not changed, but is not zero or unity */
211  Amp::apply_simple_gain (mixbufs, nframes, tgain);
212  }
213 
214  _amp->set_gain_automation_buffer (_session.send_gain_automation_buffer ());
215  _amp->setup_gain_automation (start_frame, end_frame, nframes);
216  _amp->run (mixbufs, start_frame, end_frame, nframes, true);
217 
218  _delayline->run (mixbufs, start_frame, end_frame, nframes, true);
219 
220  /* consider metering */
221 
222  if (_metering) {
223  if (_amp->gain_control()->get_value() == GAIN_COEFF_ZERO) {
224  _meter->reset();
225  } else {
226  _meter->run (mixbufs, start_frame, end_frame, nframes, true);
227  }
228  }
229 
230  /* target will pick up our output when it is ready */
231 
232  out:
234 }
235 
236 int
238 {
239  if (_send_to) {
240  mixbufs.ensure_buffers (_send_to->internal_return()->input_streams(), nframes);
241  }
242 
243  return 0;
244 }
245 
246 bool
248 {
249  return _send_to == other;
250 }
251 
252 XMLNode&
254 {
255  XMLNode& node (Send::state (full));
256 
257  /* this replaces any existing "type" property */
258 
259  node.add_property ("type", "intsend");
260 
261  if (_send_to) {
262  node.add_property ("target", _send_to->id().to_s());
263  }
264 
265  return node;
266 }
267 
268 XMLNode&
270 {
271  return state (true);
272 }
273 
274 int
275 InternalSend::set_state (const XMLNode& node, int version)
276 {
277  const XMLProperty* prop;
278 
279  init_gain ();
280 
281  Send::set_state (node, version);
282 
283  if ((prop = node.property ("target")) != 0) {
284 
285  _send_to_id = prop->value();
286 
287  /* if we're loading a session, the target route may not have been
288  create yet. make sure we defer till we are sure that it should
289  exist.
290  */
291 
292  if (!IO::connecting_legal) {
293  IO::ConnectingLegal.connect_same_thread (connect_c, boost::bind (&InternalSend::connect_when_legal, this));
294  } else {
296  }
297  }
298 
299  return 0;
300 }
301 
302 int
304 {
306 
307  if (_send_to_id == "0") {
308  /* it vanished before we could connect */
309  return 0;
310  }
311 
313 
314  if ((sendto = _session.route_by_id (_send_to_id)) == 0) {
315  error << string_compose (_("%1 - cannot find any track/bus with the ID %2 to connect to"), display_name(), _send_to_id) << endmsg;
316  cerr << string_compose (_("%1 - cannot find any track/bus with the ID %2 to connect to"), display_name(), _send_to_id) << endl;
317  return -1;
318  }
319 
320  return use_target (sendto);
321 }
322 
323 bool
325 {
326  out = in;
327  return true;
328 }
329 
330 uint32_t
332 {
333  /* the number of targets for our panner is determined by what we are
334  sending to, if anything.
335  */
336 
337  if (_send_to) {
338  return _send_to->internal_return()->input_streams().n_audio();
339  }
340 
341  return 1; /* zero is more accurate, but 1 is probably safer as a way to
342  * say "don't pan"
343  */
344 }
345 
346 bool
348 {
349  bool ret = Send::configure_io (in, out);
351  return ret;
352 }
353 
354 bool
355 InternalSend::set_name (const string& str)
356 {
357  /* rules for external sends don't apply to us */
358  return IOProcessor::set_name (str);
359 }
360 
361 string
363 {
364  if (_role == Aux) {
365  return string_compose (X_("%1"), _name);
366  } else {
367  return _name;
368  }
369 }
370 
371 bool
373 {
374  if (_role == Aux) {
375  return true;
376  }
377 
378  return false;
379 }
380 
381 void
383 {
384  if (what_changed.contains (Properties::name)) {
385  set_name (_send_to->name ());
386  }
387 }
388 
389 void
391 {
392  if (_panshell) {
393  _panshell->set_bypassed (!yn);
394  }
395 }
396 
397 void
399 {
401  b->prepare ();
402  }
403 }
boost::shared_ptr< InternalReturn > internal_return() const
Definition: route.h:238
framecnt_t nominal_frame_rate() const
Definition: session.h:367
ARDOUR::Session & _session
void ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capacity)
Definition: buffer_set.cc:149
PBD::Signal0< void > DropReferences
Definition: destructible.h:34
const std::string & value() const
Definition: xml++.h:159
PBD::Signal1< void, const PropertyChange & > PropertyChanged
Definition: stateful.h:87
boost::shared_ptr< Route > route_by_id(PBD::ID)
Definition: session.cc:3338
bool feeds(boost::shared_ptr< Route > other) const
XMLNode & state(bool full)
void set_count(const ChanCount &count)
Definition: buffer_set.h:93
uint32_t pan_outs() const
void reset_panner()
Definition: delivery.cc:395
pframes_t samples_per_cycle() const
Definition: audioengine.cc:983
boost::shared_ptr< PeakMeter > _meter
Definition: send.h:82
XMLNode & state(bool full)
Definition: send.cc:209
LIBARDOUR_API PBD::PropertyDescriptor< std::string > name
bool apply_gain() const
Definition: amp.h:50
Role role() const
Definition: delivery.h:70
XMLNode & get_state(void)
int set_state(const XMLNode &, int version)
Definition: send.cc:227
bool configure_io(ChanCount in, ChanCount out)
void remove_send_from_internal_return(InternalSend *)
Definition: route.cc:2954
PBD::Signal0< void > io_changed
Definition: route.h:320
uint32_t pframes_t
Definition: types.h:61
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
static PBD::Signal0< int > ConnectingLegal
Definition: io.h:185
float gain_t
Definition: types.h:58
static bool connecting_legal
Definition: io.h:186
bool _metering
Definition: send.h:80
void set_can_pan(bool yn)
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
int set_block_size(pframes_t)
void read_from(const BufferSet &in, framecnt_t nframes)
Definition: buffer_set.cc:434
std::string display_name() const
AudioBuffer & get_audio(size_t i)
Definition: buffer_set.h:100
bool can_support_io_configuration(const ChanCount &in, ChanCount &out)
#define GAIN_COEFF_ZERO
Definition: dB.h:26
#define _(Text)
Definition: i18n.h:11
bool configure_io(ChanCount in, ChanCount out)
Definition: send.cc:326
#define X_(Text)
Definition: i18n.h:13
XMLProperty * property(const char *)
Definition: xml++.cc:413
static PBD::Signal1< void, pframes_t > CycleStart
Definition: internal_send.h:60
audio_iterator audio_begin()
Definition: buffer_set.h:173
PBD::ScopedConnection connect_c
Definition: internal_send.h:67
Definition: amp.h:29
const PBD::ID & id() const
Definition: stateful.h:68
std::string to_s() const
Definition: id.cc:78
bool set_name(const std::string &str)
gain_t * send_gain_automation_buffer() const
Definition: session.cc:4833
static void apply_simple_gain(BufferSet &bufs, framecnt_t nframes, gain_t target, bool midi_amp=true)
Definition: amp.cc:306
PBD::ScopedConnection source_connection
Definition: internal_send.h:68
gain_t _current_gain
Definition: delivery.h:109
boost::shared_ptr< Amp > _amp
Definition: send.h:81
int64_t framepos_t
Definition: types.h:66
audio_iterator audio_end()
Definition: buffer_set.h:174
boost::shared_ptr< DelayLine > _delayline
Definition: send.h:83
PBD::Property< std::string > _name
bool set_name(const std::string &)
void cycle_start(pframes_t)
boost::shared_ptr< Route > _send_to
Definition: internal_send.h:65
XMLProperty * add_property(const char *name, const std::string &value)
uint32_t get(DataType t) const
Definition: chan_count.h:59
boost::shared_ptr< PannerShell > _panshell
Definition: delivery.h:110
pframes_t get_block_size() const
Definition: session.h:393
Definition: xml++.h:95
std::string name() const
const ChanCount & count() const
Definition: buffer_set.h:87
Definition: debug.h:30
const ChanCount & available() const
Definition: buffer_set.h:84
boost::shared_ptr< Route > _send_from
Definition: internal_send.h:64
bool contains(PropertyDescriptor< T > p) const
void send_to_property_changed(const PBD::PropertyChange &)
bool visible() const
int set_state(const XMLNode &node, int version)
#define GAIN_COEFF_UNITY
Definition: dB.h:28
void run(BufferSet &bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, bool)
void read_from(const Sample *src, framecnt_t len, framecnt_t dst_offset=0, framecnt_t src_offset=0)
Definition: audio_buffer.h:39
gain_t target_gain()
Definition: delivery.cc:496
AudioEngine & engine()
Definition: session.h:546
void add_send_to_internal_return(InternalSend *)
Definition: route.cc:2940
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
PBD::ScopedConnectionList target_connections
Definition: internal_send.h:69
int use_target(boost::shared_ptr< Route >)