better, cleaner fix for copying sends/returns/port inserts via XML state
[ardour.git] / libs / ardour / port_insert.cc
1 /*
2     Copyright (C) 2000,2007 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 <string>
21
22
23 #include "pbd/failed_constructor.h"
24 #include "pbd/xml++.h"
25
26 #include "ardour/audioengine.h"
27 #include "ardour/audio_port.h"
28 #include "ardour/buffer_set.h"
29 #include "ardour/delivery.h"
30 #include "ardour/mtdm.h"
31 #include "ardour/plugin.h"
32 #include "ardour/port.h"
33 #include "ardour/port_insert.h"
34 #include "ardour/route.h"
35 #include "ardour/session.h"
36 #include "ardour/types.h"
37
38 #include "i18n.h"
39
40 using namespace std;
41 using namespace ARDOUR;
42 using namespace PBD;
43
44 string
45 PortInsert::name_and_id_new_insert (Session& s, uint32_t& bitslot)
46 {
47         bitslot = s.next_insert_id ();
48         return string_compose (_("insert %1"), bitslot+ 1);
49 }
50
51 PortInsert::PortInsert (Session& s, boost::shared_ptr<Pannable> pannable, boost::shared_ptr<MuteMaster> mm)
52         : IOProcessor (s, true, true, name_and_id_new_insert (s, _bitslot), "")
53         , _out (new Delivery (s, _output, pannable, mm, _name, Delivery::Insert))
54 {
55         _mtdm = 0;
56         _latency_detect = false;
57         _latency_flush_frames = false;
58         _measured_latency = 0;
59 }
60
61 PortInsert::~PortInsert ()
62 {
63         _session.unmark_insert_id (_bitslot);
64         delete _mtdm;
65 }
66
67 void
68 PortInsert::start_latency_detection ()
69 {
70         if (_mtdm != 0) {
71                 delete _mtdm;
72         }
73
74         _mtdm = new MTDM;
75         _latency_flush_frames = false;
76         _latency_detect = true;
77         _measured_latency = 0;
78 }
79
80 void
81 PortInsert::stop_latency_detection ()
82 {
83         _latency_flush_frames = signal_latency() + _session.engine().frames_per_cycle();
84         _latency_detect = false;
85 }
86
87 void
88 PortInsert::set_measured_latency (framecnt_t n)
89 {
90         _measured_latency = n;
91 }
92
93 framecnt_t
94 PortInsert::latency() const
95 {
96         /* because we deliver and collect within the same cycle,
97            all I/O is necessarily delayed by at least frames_per_cycle().
98
99            if the return port for insert has its own latency, we
100            need to take that into account too.
101         */
102
103         if (_measured_latency == 0) {
104                 return _session.engine().frames_per_cycle() + _input->latency();
105         } else {
106                 return _measured_latency;
107         }
108 }
109
110 void
111 PortInsert::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, bool)
112 {
113         if (_output->n_ports().n_total() == 0) {
114                 return;
115         }
116
117         if (_latency_detect) {
118
119                 if (_input->n_ports().n_audio() != 0) {
120
121                         AudioBuffer& outbuf (_output->ports().nth_audio_port(0)->get_audio_buffer (nframes));
122                         Sample* in = _input->ports().nth_audio_port(0)->get_audio_buffer (nframes).data();
123                         Sample* out = outbuf.data();
124
125                         _mtdm->process (nframes, in, out);
126
127                         outbuf.set_is_silent (false);
128                 }
129
130                 return;
131
132         } else if (_latency_flush_frames) {
133
134                 /* wait for the entire input buffer to drain before picking up input again so that we can't
135                    hear the remnants of whatever MTDM pumped into the pipeline.
136                 */
137
138                 silence (nframes);
139
140                 if (_latency_flush_frames > nframes) {
141                         _latency_flush_frames -= nframes;
142                 } else {
143                         _latency_flush_frames = 0;
144                 }
145
146                 return;
147         }
148
149         if (!_active && !_pending_active) {
150                 /* deliver silence */
151                 silence (nframes);
152                 goto out;
153         }
154
155         _out->run (bufs, start_frame, end_frame, nframes, true);
156         _input->collect_input (bufs, nframes, ChanCount::ZERO);
157
158   out:
159         _active = _pending_active;
160 }
161
162 XMLNode&
163 PortInsert::get_state(void)
164 {
165         return state (true);
166 }
167
168 XMLNode&
169 PortInsert::state (bool full)
170 {
171         XMLNode& node = IOProcessor::state(full);
172         char buf[32];
173         node.add_property ("type", "port");
174         snprintf (buf, sizeof (buf), "%" PRIu32, _bitslot);
175         node.add_property ("bitslot", buf);
176         snprintf (buf, sizeof (buf), "%" PRId64, _measured_latency);
177         node.add_property("latency", buf);
178         snprintf (buf, sizeof (buf), "%u", _session.get_block_size());
179         node.add_property("block_size", buf);
180
181         return node;
182 }
183
184 int
185 PortInsert::set_state (const XMLNode& node, int version)
186 {
187         XMLNodeList nlist = node.children();
188         XMLNodeIterator niter;
189         XMLPropertyList plist;
190         const XMLProperty *prop;
191
192         const XMLNode* insert_node = &node;
193
194         // legacy sessions: search for child Redirect node
195         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
196                 if ((*niter)->name() == "Redirect") {
197                         insert_node = *niter;
198                         break;
199                 }
200         }
201
202         IOProcessor::set_state (*insert_node, version);
203
204         if ((prop = node.property ("type")) == 0) {
205                 error << _("XML node describing port insert is missing the `type' field") << endmsg;
206                 return -1;
207         }
208
209         if (prop->value() != "port") {
210                 error << _("non-port insert XML used for port plugin insert") << endmsg;
211                 return -1;
212         }
213
214         uint32_t blocksize = 0;
215         if ((prop = node.property ("block_size")) != 0) {
216                 sscanf (prop->value().c_str(), "%u", &blocksize);
217         }
218
219         //if the jack period is the same as when the value was saved, we can recall our latency..
220         if ( (_session.get_block_size() == blocksize) && (prop = node.property ("latency")) != 0) {
221                 uint32_t latency = 0;
222                 sscanf (prop->value().c_str(), "%u", &latency);
223                 _measured_latency = latency;
224         }
225
226         if (!node.property ("ignore-bitslot")) {
227                 if ((prop = node.property ("bitslot")) == 0) {
228                         _bitslot = _session.next_insert_id();
229                 } else {
230                         _session.unmark_insert_id (_bitslot);
231                         sscanf (prop->value().c_str(), "%" PRIu32, &_bitslot);
232                         _session.mark_insert_id (_bitslot);
233                 }
234         }
235
236         return 0;
237 }
238
239 ARDOUR::framecnt_t
240 PortInsert::signal_latency() const
241 {
242         /* because we deliver and collect within the same cycle,
243            all I/O is necessarily delayed by at least frames_per_cycle().
244
245            if the return port for insert has its own latency, we
246            need to take that into account too.
247         */
248
249         if (_measured_latency == 0) {
250                 return _session.engine().frames_per_cycle() + _input->signal_latency();
251         } else {
252                 return _measured_latency;
253         }
254 }
255
256 /** Caller must hold process lock */
257 bool
258 PortInsert::configure_io (ChanCount in, ChanCount out)
259 {
260         assert (!AudioEngine::instance()->process_lock().trylock());
261
262         /* for an insert, processor input corresponds to IO output, and vice versa */
263
264         if (_input->ensure_io (in, false, this) != 0) {
265                 return false;
266         }
267
268         if (_output->ensure_io (out, false, this) != 0) {
269                 return false;
270         }
271
272         return Processor::configure_io (in, out);
273 }
274
275 bool
276 PortInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
277 {
278         out = in;
279         return true;
280 }
281
282 bool
283 PortInsert::set_name (const std::string& name)
284 {
285         bool ret = Processor::set_name (name);
286
287         ret = (ret && _input->set_name (name) && _output->set_name (name));
288
289         return ret;
290 }
291
292 void
293 PortInsert::activate ()
294 {
295         IOProcessor::activate ();
296
297         _out->activate ();
298 }
299
300 void
301 PortInsert::deactivate ()
302 {
303         IOProcessor::deactivate ();
304
305         _out->deactivate ();
306 }