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_send.h"
26 #include "ardour/meter.h"
27 #include "ardour/panner.h"
28 #include "ardour/panner_shell.h"
29 #include "ardour/route.h"
30 #include "ardour/session.h"
35 using namespace ARDOUR
;
38 InternalSend::InternalSend (Session
& s
, boost::shared_ptr
<Pannable
> p
, boost::shared_ptr
<MuteMaster
> mm
, boost::shared_ptr
<Route
> sendto
, Delivery::Role role
)
39 : Send (s
, p
, mm
, role
)
42 if (use_target (sendto
)) {
43 throw failed_constructor();
50 InternalSend::~InternalSend ()
53 _send_to
->remove_send_from_internal_return (this);
58 InternalSend::init_gain ()
60 if (_role
== Listen
) {
61 /* send to monitor bus is always at unity */
62 _amp
->set_gain (1.0, this);
64 /* aux sends start at -inf dB */
65 _amp
->set_gain (0, this);
70 InternalSend::use_target (boost::shared_ptr
<Route
> sendto
)
73 _send_to
->remove_send_from_internal_return (this);
78 _send_to
->add_send_to_internal_return (this);
80 set_name (sendto
->name());
81 _send_to_id
= _send_to
->id();
83 target_connections
.drop_connections ();
85 _send_to
->DropReferences
.connect_same_thread (target_connections
, boost::bind (&InternalSend::send_to_going_away
, this));
86 _send_to
->PropertyChanged
.connect_same_thread (target_connections
, boost::bind (&InternalSend::send_to_property_changed
, this, _1
));;
92 InternalSend::send_to_going_away ()
94 target_connections
.drop_connections ();
100 InternalSend::run (BufferSet
& bufs
, framepos_t start_frame
, framepos_t end_frame
, pframes_t nframes
, bool)
102 if ((!_active
&& !_pending_active
) || !_send_to
) {
107 // we have to copy the input, because we may alter the buffers with the amp
108 // in-place, which a send must never do.
110 assert(mixbufs
.available() >= bufs
.count());
112 if (_panshell
&& !_panshell
->bypassed()) {
113 mixbufs
.set_count (_send_to
->n_outputs ());
114 _panshell
->run (bufs
, mixbufs
, start_frame
, end_frame
, nframes
);
116 mixbufs
.read_from (bufs
, nframes
);
121 gain_t tgain
= target_gain ();
123 if (tgain
!= _current_gain
) {
125 /* target gain has changed */
127 Amp::apply_gain (mixbufs
, nframes
, _current_gain
, tgain
);
128 _current_gain
= tgain
;
130 } else if (tgain
== 0.0) {
132 /* we were quiet last time, and we're still supposed to be quiet.
136 Amp::apply_simple_gain (mixbufs
, nframes
, 0.0);
139 } else if (tgain
!= 1.0) {
141 /* target gain has not changed, but is not zero or unity */
142 Amp::apply_simple_gain (mixbufs
, nframes
, tgain
);
145 // Can't automate gain for sends or returns yet because we need different buffers
146 // so that we don't overwrite the main automation data for the route amp
147 // _amp->setup_gain_automation (start_frame, end_frame, nframes);
149 _amp
->run (mixbufs
, start_frame
, end_frame
, nframes
, true);
151 /* consider metering */
154 if (_amp
->gain_control()->get_value() == 0) {
157 _meter
->run (mixbufs
, start_frame
, end_frame
, nframes
, true);
162 if (_session
.transport_rolling()) {
163 for (BufferSet::audio_iterator b
= mixbufs
.audio_begin(); b
!= mixbufs
.audio_end(); ++b
) {
164 Sample
* p
= b
->data ();
165 for (pframes_t n
= 0; n
< nframes
; ++n
) {
167 cerr
<< "\tnon-zero data SENT to " << b
->data() << endl
;
175 /* target will pick up our output when it is ready */
178 _active
= _pending_active
;
182 InternalSend::set_block_size (pframes_t nframes
)
184 mixbufs
.ensure_buffers (_configured_input
, nframes
);
189 InternalSend::feeds (boost::shared_ptr
<Route
> other
) const
191 return _send_to
== other
;
195 InternalSend::state (bool full
)
197 XMLNode
& node (Send::state (full
));
199 /* this replaces any existing "type" property */
201 node
.add_property ("type", "intsend");
204 node
.add_property ("target", _send_to
->id().to_s());
211 InternalSend::get_state()
217 InternalSend::set_state (const XMLNode
& node
, int version
)
219 const XMLProperty
* prop
;
223 Send::set_state (node
, version
);
225 if ((prop
= node
.property ("target")) != 0) {
227 _send_to_id
= prop
->value();
229 /* if we're loading a session, the target route may not have been
230 create yet. make sure we defer till we are sure that it should
234 if (!IO::connecting_legal
) {
235 IO::ConnectingLegal
.connect_same_thread (connect_c
, boost::bind (&InternalSend::connect_when_legal
, this));
237 connect_when_legal ();
245 InternalSend::connect_when_legal ()
247 connect_c
.disconnect ();
249 if (_send_to_id
== "0") {
250 /* it vanished before we could connect */
254 boost::shared_ptr
<Route
> sendto
;
256 if ((sendto
= _session
.route_by_id (_send_to_id
)) == 0) {
257 error
<< X_("cannot find route to connect to") << endmsg
;
261 return use_target (sendto
);
265 InternalSend::can_support_io_configuration (const ChanCount
& in
, ChanCount
& out
) const
272 InternalSend::configure_io (ChanCount in
, ChanCount out
)
274 bool ret
= Send::configure_io (in
, out
);
275 set_block_size (_session
.engine().frames_per_cycle());
280 InternalSend::set_name (const string
& str
)
282 /* rules for external sends don't apply to us */
283 return IOProcessor::set_name (str
);
287 InternalSend::display_name () const
290 return string_compose (X_("aux-%1"), _name
);
297 InternalSend::visible () const
307 InternalSend::send_to_property_changed (const PropertyChange
& what_changed
)
309 if (what_changed
.contains (Properties::name
)) {
310 set_name (_send_to
->name ());
315 InternalSend::set_can_pan (bool yn
)
318 _panshell
->set_bypassed (!yn
);
323 InternalSend::cycle_start (pframes_t nframes
)
325 Delivery::cycle_start (nframes
);
327 for (BufferSet::audio_iterator b
= mixbufs
.audio_begin(); b
!= mixbufs
.audio_end(); ++b
) {