solo models work again (amazing how hard this was); remove crufty debug output; remov...
[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 <iostream>
21
22 #include "pbd/error.h"
23 #include "pbd/failed_constructor.h"
24
25 #include "ardour/amp.h"
26 #include "ardour/internal_send.h"
27 #include "ardour/meter.h"
28 #include "ardour/route.h"
29 #include "ardour/session.h"
30
31 #include "i18n.h"
32
33 using namespace PBD;
34 using namespace ARDOUR;
35
36 InternalSend::InternalSend (Session& s, boost::shared_ptr<MuteMaster> mm, boost::shared_ptr<Route> sendto)
37         : Send (s, mm, true)
38         , _send_to (sendto)
39 {
40         if ((target = _send_to->get_return_buffer ()) == 0) {
41                 throw failed_constructor();
42         }
43
44         _send_to->GoingAway.connect (mem_fun (*this, &InternalSend::send_to_going_away));
45 }
46
47 InternalSend::InternalSend (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
48         : Send (s, mm, node, true)
49 {
50         set_state (node);
51 }
52
53 InternalSend::~InternalSend ()
54 {
55         if (_send_to) {
56                 _send_to->release_return_buffer ();
57         }
58
59         connect_c.disconnect ();
60 }
61
62 void
63 InternalSend::send_to_going_away ()
64 {
65         target = 0;
66         _send_to.reset ();
67         _send_to_id = "0";
68 }
69
70 void
71 InternalSend::run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
72 {
73         if (!_active || !target || !_send_to) {
74                 _meter->reset ();
75                 return;
76         }
77
78         // we have to copy the input, because we may alter the buffers with the amp
79         // in-place, which a send must never do.
80         
81         BufferSet& sendbufs = _session.get_mix_buffers (bufs.count());
82         sendbufs.read_from (bufs, nframes);
83         assert(sendbufs.count() == bufs.count());
84         
85         /* gain control */
86
87         gain_t tgain = target_gain ();
88         
89         if (tgain != _current_gain) {
90                 
91                 /* target gain has changed */
92
93                 Amp::apply_gain (sendbufs, nframes, _current_gain, tgain);
94                 _current_gain = tgain;
95
96         } else if (tgain == 0.0) {
97
98                 /* we were quiet last time, and we're still supposed to be quiet.
99                 */
100
101                 _meter->reset ();
102                 Amp::apply_simple_gain (sendbufs, nframes, 0.0);
103                 
104                 return;
105
106         } else if (tgain != 1.0) {
107
108                 /* target gain has not changed, but is not unity */
109                 Amp::apply_simple_gain (sendbufs, nframes, tgain);
110         }
111         
112         // Can't automate gain for sends or returns yet because we need different buffers
113         // so that we don't overwrite the main automation data for the route amp
114         // _amp->setup_gain_automation (start_frame, end_frame, nframes);
115
116         _amp->run (sendbufs, start_frame, end_frame, nframes);
117
118         /* consider metering */
119         
120         if (_metering) {
121                 if (_amp->gain_control()->get_value() == 0) {
122                         _meter->reset();
123                 } else {
124                         _meter->run (sendbufs, start_frame, end_frame, nframes);
125                 }
126         }
127
128         /* deliver to target */
129
130         target->merge_from (sendbufs, nframes);
131 }
132
133 bool
134 InternalSend::feeds (boost::shared_ptr<Route> other) const
135 {
136         return _send_to == other;
137 }
138
139 XMLNode&
140 InternalSend::state (bool full)
141 {
142         XMLNode& node (Send::state (full));
143
144         /* this replaces any existing property */
145
146         node.add_property ("type", "intsend");
147
148         if (_send_to) {
149                 node.add_property ("target", _send_to->id().to_s());
150         }
151         
152         return node;
153 }
154
155 XMLNode&
156 InternalSend::get_state()
157 {
158         return state (true);
159 }
160
161 int
162 InternalSend::set_state (const XMLNode& node)
163 {
164         const XMLProperty* prop;
165
166         Send::set_state (node);
167
168         if ((prop = node.property ("target")) != 0) {
169
170                 _send_to_id = prop->value();
171
172                 /* if we're loading a session, the target route may not have been
173                    create yet. make sure we defer till we are sure that it should
174                    exist.
175                 */
176
177                 if (!IO::connecting_legal) {
178                         connect_c = IO::ConnectingLegal.connect (mem_fun (*this, &InternalSend::connect_when_legal));
179                 } else {
180                         connect_when_legal ();
181                 }
182         }
183         
184         return 0;
185 }
186
187 int
188 InternalSend::connect_when_legal ()
189 {
190         connect_c.disconnect ();
191
192         if (_send_to_id == "0") {
193                 /* it vanished before we could connect */
194                 return 0;
195         }
196
197         if ((_send_to = _session.route_by_id (_send_to_id)) == 0) {
198                 error << X_("cannot find route to connect to") << endmsg;
199                 return -1;
200         } 
201         
202         if ((target = _send_to->get_return_buffer ()) == 0) {
203                 error << X_("target for internal send has no return buffer") << endmsg;
204                 return -1;
205         }
206
207         return 0;
208 }
209
210 bool 
211 InternalSend::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
212 {
213         out = in;
214         return true;
215 }