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/internal_send.h"
25 #include "ardour/meter.h"
26 #include "ardour/route.h"
27 #include "ardour/session.h"
32 using namespace ARDOUR
;
35 InternalSend::InternalSend (Session
& s
, boost::shared_ptr
<MuteMaster
> mm
, boost::shared_ptr
<Route
> sendto
, Delivery::Role role
)
39 if (use_target (sendto
)) {
40 throw failed_constructor();
45 InternalSend::~InternalSend ()
48 _send_to
->release_return_buffer ();
53 InternalSend::use_target (boost::shared_ptr
<Route
> sendto
)
57 if ((target
= _send_to
->get_return_buffer ()) == 0) {
61 set_name (sendto
->name());
62 _send_to_id
= _send_to
->id();
64 target_connections
.drop_connections ();
66 _send_to
->DropReferences
.connect_same_thread (target_connections
, boost::bind (&InternalSend::send_to_going_away
, this));
67 _send_to
->PropertyChanged
.connect_same_thread (target_connections
, boost::bind (&InternalSend::send_to_property_changed
, this, _1
));;
74 InternalSend::send_to_going_away ()
77 target_connections
.drop_connections ();
83 InternalSend::run (BufferSet
& bufs
, sframes_t start_frame
, sframes_t end_frame
, nframes_t nframes
, bool)
85 if ((!_active
&& !_pending_active
) || !target
|| !_send_to
) {
90 // we have to copy the input, because we may alter the buffers with the amp
91 // in-place, which a send must never do.
93 assert(mixbufs
.available() >= bufs
.count());
94 mixbufs
.read_from (bufs
, nframes
);
98 gain_t tgain
= target_gain ();
100 if (tgain
!= _current_gain
) {
102 /* target gain has changed */
104 Amp::apply_gain (mixbufs
, nframes
, _current_gain
, tgain
);
105 _current_gain
= tgain
;
107 } else if (tgain
== 0.0) {
109 /* we were quiet last time, and we're still supposed to be quiet.
113 Amp::apply_simple_gain (mixbufs
, nframes
, 0.0);
116 } else if (tgain
!= 1.0) {
118 /* target gain has not changed, but is not zero or unity */
119 Amp::apply_simple_gain (mixbufs
, nframes
, tgain
);
122 // Can't automate gain for sends or returns yet because we need different buffers
123 // so that we don't overwrite the main automation data for the route amp
124 // _amp->setup_gain_automation (start_frame, end_frame, nframes);
126 _amp
->run (mixbufs
, start_frame
, end_frame
, nframes
, true);
128 /* XXX NEED TO PAN */
130 /* consider metering */
133 if (_amp
->gain_control()->get_value() == 0) {
136 _meter
->run (mixbufs
, start_frame
, end_frame
, nframes
, true);
140 /* deliver to target */
142 target
->merge_from (mixbufs
, nframes
);
145 _active
= _pending_active
;
149 InternalSend::set_block_size (nframes_t nframes
)
151 mixbufs
.ensure_buffers (_configured_input
, nframes
);
155 InternalSend::feeds (boost::shared_ptr
<Route
> other
) const
157 return _send_to
== other
;
161 InternalSend::state (bool full
)
163 XMLNode
& node (Send::state (full
));
165 /* this replaces any existing "type" property */
167 node
.add_property ("type", "intsend");
170 node
.add_property ("target", _send_to
->id().to_s());
177 InternalSend::get_state()
183 InternalSend::set_our_state (const XMLNode
& node
, int /*version*/)
185 const XMLProperty
* prop
;
187 if ((prop
= node
.property ("target")) != 0) {
189 _send_to_id
= prop
->value();
191 /* if we're loading a session, the target route may not have been
192 create yet. make sure we defer till we are sure that it should
196 if (!IO::connecting_legal
) {
197 IO::ConnectingLegal
.connect_same_thread (connect_c
, boost::bind (&InternalSend::connect_when_legal
, this));
199 connect_when_legal ();
207 InternalSend::set_state (const XMLNode
& node
, int version
)
209 Send::set_state (node
, version
);
210 return set_our_state (node
, version
);
214 InternalSend::connect_when_legal ()
216 connect_c
.disconnect ();
218 if (_send_to_id
== "0") {
219 /* it vanished before we could connect */
223 boost::shared_ptr
<Route
> sendto
;
225 if ((sendto
= _session
.route_by_id (_send_to_id
)) == 0) {
226 error
<< X_("cannot find route to connect to") << endmsg
;
230 return use_target (sendto
);
234 InternalSend::can_support_io_configuration (const ChanCount
& in
, ChanCount
& out
) const
241 InternalSend::configure_io (ChanCount in
, ChanCount out
)
243 bool ret
= Send::configure_io (in
, out
);
244 set_block_size (_session
.engine().frames_per_cycle());
249 InternalSend::set_name (const string
& str
)
251 /* rules for external sends don't apply to us */
252 return IOProcessor::set_name (str
);
256 InternalSend::display_name () const
259 return string_compose (X_("aux-%1"), _name
);
266 InternalSend::visible () const
276 InternalSend::send_to_property_changed (const PropertyChange
& what_changed
)
278 if (what_changed
.contains (Properties::name
)) {
279 set_name (_send_to
->name ());