2 Copyright (C) 2009 Paul Davis
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.
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.
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.
20 #include "pbd/error.h"
21 #include "pbd/failed_constructor.h"
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.h"
29 #include "ardour/panner_shell.h"
30 #include "ardour/route.h"
31 #include "ardour/session.h"
36 using namespace ARDOUR
;
39 InternalSend::InternalSend (Session
& s
, boost::shared_ptr
<Pannable
> p
, boost::shared_ptr
<MuteMaster
> mm
, boost::shared_ptr
<Route
> sendto
, Delivery::Role role
)
40 : Send (s
, p
, mm
, role
)
43 if (use_target (sendto
)) {
44 throw failed_constructor();
51 InternalSend::~InternalSend ()
54 _send_to
->remove_send_from_internal_return (this);
59 InternalSend::init_gain ()
61 if (_role
== Listen
) {
62 /* send to monitor bus is always at unity */
63 _amp
->set_gain (1.0, this);
65 /* aux sends start at -inf dB */
66 _amp
->set_gain (0, this);
71 InternalSend::use_target (boost::shared_ptr
<Route
> sendto
)
74 _send_to
->remove_send_from_internal_return (this);
79 _send_to
->add_send_to_internal_return (this);
81 mixbufs
.ensure_buffers (_send_to
->internal_return()->input_streams(), _session
.get_block_size());
82 mixbufs
.set_count (_send_to
->internal_return()->input_streams());
86 set_name (sendto
->name());
87 _send_to_id
= _send_to
->id();
89 target_connections
.drop_connections ();
91 _send_to
->DropReferences
.connect_same_thread (target_connections
, boost::bind (&InternalSend::send_to_going_away
, this));
92 _send_to
->PropertyChanged
.connect_same_thread (target_connections
, boost::bind (&InternalSend::send_to_property_changed
, this, _1
));;
98 InternalSend::send_to_going_away ()
100 target_connections
.drop_connections ();
106 InternalSend::run (BufferSet
& bufs
, framepos_t start_frame
, framepos_t end_frame
, pframes_t nframes
, bool)
108 if ((!_active
&& !_pending_active
) || !_send_to
) {
113 // we have to copy the input, because we may alter the buffers with the amp
114 // in-place, which a send must never do.
116 assert(mixbufs
.available() >= bufs
.count());
118 if (_panshell
&& !_panshell
->bypassed()) {
119 _panshell
->run (bufs
, mixbufs
, start_frame
, end_frame
, nframes
);
121 mixbufs
.read_from (bufs
, nframes
);
126 gain_t tgain
= target_gain ();
128 if (tgain
!= _current_gain
) {
130 /* target gain has changed */
132 Amp::apply_gain (mixbufs
, nframes
, _current_gain
, tgain
);
133 _current_gain
= tgain
;
135 } else if (tgain
== 0.0) {
137 /* we were quiet last time, and we're still supposed to be quiet.
141 Amp::apply_simple_gain (mixbufs
, nframes
, 0.0);
144 } else if (tgain
!= 1.0) {
146 /* target gain has not changed, but is not zero or unity */
147 Amp::apply_simple_gain (mixbufs
, nframes
, tgain
);
150 // Can't automate gain for sends or returns yet because we need different buffers
151 // so that we don't overwrite the main automation data for the route amp
152 // _amp->setup_gain_automation (start_frame, end_frame, nframes);
154 _amp
->run (mixbufs
, start_frame
, end_frame
, nframes
, true);
156 /* consider metering */
159 if (_amp
->gain_control()->get_value() == 0) {
162 _meter
->run (mixbufs
, start_frame
, end_frame
, nframes
, true);
166 /* target will pick up our output when it is ready */
169 _active
= _pending_active
;
173 InternalSend::set_block_size (pframes_t nframes
)
176 mixbufs
.ensure_buffers (_send_to
->internal_return()->input_streams(), nframes
);
183 InternalSend::feeds (boost::shared_ptr
<Route
> other
) const
185 return _send_to
== other
;
189 InternalSend::state (bool full
)
191 XMLNode
& node (Send::state (full
));
193 /* this replaces any existing "type" property */
195 node
.add_property ("type", "intsend");
198 node
.add_property ("target", _send_to
->id().to_s());
205 InternalSend::get_state()
211 InternalSend::set_state (const XMLNode
& node
, int version
)
213 const XMLProperty
* prop
;
217 Send::set_state (node
, version
);
219 if ((prop
= node
.property ("target")) != 0) {
221 _send_to_id
= prop
->value();
223 /* if we're loading a session, the target route may not have been
224 create yet. make sure we defer till we are sure that it should
228 if (!IO::connecting_legal
) {
229 IO::ConnectingLegal
.connect_same_thread (connect_c
, boost::bind (&InternalSend::connect_when_legal
, this));
231 connect_when_legal ();
239 InternalSend::connect_when_legal ()
241 connect_c
.disconnect ();
243 if (_send_to_id
== "0") {
244 /* it vanished before we could connect */
248 boost::shared_ptr
<Route
> sendto
;
250 if ((sendto
= _session
.route_by_id (_send_to_id
)) == 0) {
251 error
<< X_("cannot find route to connect to") << endmsg
;
255 return use_target (sendto
);
259 InternalSend::can_support_io_configuration (const ChanCount
& in
, ChanCount
& out
) const
266 InternalSend::pan_outs () const
268 /* the number of targets for our panner is determined by what we are
269 sending to, if anything.
273 return _send_to
->internal_return()->input_streams().n_audio();
276 return 1; /* zero is more accurate, but 1 is probably safer as a way to
282 InternalSend::configure_io (ChanCount in
, ChanCount out
)
284 bool ret
= Send::configure_io (in
, out
);
285 set_block_size (_session
.engine().frames_per_cycle());
290 InternalSend::set_name (const string
& str
)
292 /* rules for external sends don't apply to us */
293 return IOProcessor::set_name (str
);
297 InternalSend::display_name () const
300 return string_compose (X_("aux-%1"), _name
);
307 InternalSend::visible () const
317 InternalSend::send_to_property_changed (const PropertyChange
& what_changed
)
319 if (what_changed
.contains (Properties::name
)) {
320 set_name (_send_to
->name ());
325 InternalSend::set_can_pan (bool yn
)
328 _panshell
->set_bypassed (!yn
);
333 InternalSend::cycle_start (pframes_t nframes
)
335 Delivery::cycle_start (nframes
);
337 for (BufferSet::audio_iterator b
= mixbufs
.audio_begin(); b
!= mixbufs
.audio_end(); ++b
) {