remove Glib::ustring from libardour; allow any characters except '/' and '\' in paths...
[ardour.git] / libs / ardour / internal_send.cc
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/internal_send.h"
25 #include "ardour/meter.h"
26 #include "ardour/route.h"
27 #include "ardour/session.h"
28
29 #include "i18n.h"
30
31 using namespace PBD;
32 using namespace ARDOUR;
33 using namespace std;
34
35 InternalSend::InternalSend (Session& s, boost::shared_ptr<MuteMaster> mm, boost::shared_ptr<Route> sendto, Delivery::Role role)
36         : Send (s, mm, role)
37         , target (0)
38 {
39         if (sendto) {
40                 if (use_target (sendto)) {
41                         throw failed_constructor();
42                 }
43         }
44 }
45
46 InternalSend::~InternalSend ()
47 {
48         if (_send_to) {
49                 _send_to->release_return_buffer ();
50         }
51 }
52
53 int
54 InternalSend::use_target (boost::shared_ptr<Route> sendto)
55 {
56         _send_to = sendto;
57
58         if ((target = _send_to->get_return_buffer ()) == 0) {
59                 return -1;
60         }
61         
62         set_name (sendto->name());
63         _send_to_id = _send_to->id();
64
65         target_connections.drop_connections ();
66
67         _send_to->DropReferences.connect_same_thread (target_connections, boost::bind (&InternalSend::send_to_going_away, this));
68         _send_to->PropertyChanged.connect_same_thread (target_connections, boost::bind (&InternalSend::send_to_property_changed, this, _1));;
69
70         return 0;
71 }
72
73
74 void
75 InternalSend::send_to_going_away ()
76 {
77         target = 0;
78         target_connections.drop_connections ();
79         _send_to.reset ();
80         _send_to_id = "0";
81 }
82
83 void
84 InternalSend::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool)
85 {
86         if ((!_active && !_pending_active) || !target || !_send_to) {
87                 _meter->reset ();
88                 return;
89         }
90
91         // we have to copy the input, because we may alter the buffers with the amp
92         // in-place, which a send must never do.
93
94         assert(mixbufs.available() >= bufs.count());
95         mixbufs.read_from (bufs, nframes);
96
97         /* gain control */
98
99         gain_t tgain = target_gain ();
100
101         if (tgain != _current_gain) {
102
103                 /* target gain has changed */
104
105                 Amp::apply_gain (mixbufs, nframes, _current_gain, tgain);
106                 _current_gain = tgain;
107                 
108         } else if (tgain == 0.0) {
109
110                 /* we were quiet last time, and we're still supposed to be quiet.
111                 */
112
113                 _meter->reset ();
114                 Amp::apply_simple_gain (mixbufs, nframes, 0.0);
115                 goto out;
116
117         } else if (tgain != 1.0) {
118
119                 /* target gain has not changed, but is not zero or unity */
120                 Amp::apply_simple_gain (mixbufs, nframes, tgain);
121         }
122
123         // Can't automate gain for sends or returns yet because we need different buffers
124         // so that we don't overwrite the main automation data for the route amp
125         // _amp->setup_gain_automation (start_frame, end_frame, nframes);
126
127         _amp->run (mixbufs, start_frame, end_frame, nframes, true);
128
129         /* XXX NEED TO PAN */
130
131         /* consider metering */
132
133         if (_metering) {
134                 if (_amp->gain_control()->get_value() == 0) {
135                         _meter->reset();
136                 } else {
137                         _meter->run (mixbufs, start_frame, end_frame, nframes, true);
138                 }
139         }
140
141         /* deliver to target */
142
143         target->merge_from (mixbufs, nframes);
144
145   out:
146         _active = _pending_active;
147 }
148
149 int
150 InternalSend::set_block_size (nframes_t nframes)
151 {
152         mixbufs.ensure_buffers (_configured_input, nframes);
153
154         /* ensure that our target can cope with us merging this many frames to it */
155         if (target) {
156                 target->ensure_buffers (_configured_input, nframes);
157         }
158         return 0;
159 }
160
161 bool
162 InternalSend::feeds (boost::shared_ptr<Route> other) const
163 {
164         return _send_to == other;
165 }
166
167 XMLNode&
168 InternalSend::state (bool full)
169 {
170         XMLNode& node (Send::state (full));
171
172         /* this replaces any existing "type" property */
173
174         node.add_property ("type", "intsend");
175
176         if (_send_to) {
177                 node.add_property ("target", _send_to->id().to_s());
178         }
179
180         return node;
181 }
182
183 XMLNode&
184 InternalSend::get_state()
185 {
186         return state (true);
187 }
188
189 int
190 InternalSend::set_our_state (const XMLNode& node, int /*version*/)
191 {
192         const XMLProperty* prop;
193
194         if ((prop = node.property ("target")) != 0) {
195
196                 _send_to_id = prop->value();
197
198                 /* if we're loading a session, the target route may not have been
199                    create yet. make sure we defer till we are sure that it should
200                    exist.
201                 */
202
203                 if (!IO::connecting_legal) {
204                         IO::ConnectingLegal.connect_same_thread (connect_c, boost::bind (&InternalSend::connect_when_legal, this));
205                 } else {
206                         connect_when_legal ();
207                 }
208         }
209
210         return 0;
211 }
212
213 int
214 InternalSend::set_state (const XMLNode& node, int version)
215 {
216         Send::set_state (node, version);
217         return set_our_state (node, version);
218 }
219
220 int
221 InternalSend::connect_when_legal ()
222 {
223         connect_c.disconnect ();
224
225         if (_send_to_id == "0") {
226                 /* it vanished before we could connect */
227                 return 0;
228         }
229
230         boost::shared_ptr<Route> sendto;
231
232         if ((sendto = _session.route_by_id (_send_to_id)) == 0) {
233                 error << X_("cannot find route to connect to") << endmsg;
234                 return -1;
235         }
236
237         return use_target (sendto);
238 }
239
240 bool
241 InternalSend::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
242 {
243         out = in;
244         return true;
245 }
246
247 bool
248 InternalSend::configure_io (ChanCount in, ChanCount out)
249 {
250         bool ret = Send::configure_io (in, out);
251         set_block_size (_session.engine().frames_per_cycle());
252         return ret;
253 }
254
255 bool
256 InternalSend::set_name (const string& str)
257 {
258         /* rules for external sends don't apply to us */
259         return IOProcessor::set_name (str);
260 }
261
262 string
263 InternalSend::display_name () const
264 {
265         if (_role == Aux) {
266                 return string_compose (X_("aux-%1"), _name);
267         } else {
268                 return _name;
269         }
270 }
271
272 bool
273 InternalSend::visible () const
274 {
275         if (_role == Aux) {
276                 return true;
277         }
278
279         return false;
280 }
281
282 void
283 InternalSend::send_to_property_changed (const PropertyChange& what_changed)
284 {
285         if (what_changed.contains (Properties::name)) {
286                 set_name (_send_to->name ());
287         }
288 }