change MidiPlaylist::dump() into ::render(); change type of initial argument
[ardour.git] / libs / ardour / io_processor.cc
1 /*
2  * Copyright (C) 2001-2018 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2007-2012 David Robillard <d@drobilla.net>
4  * Copyright (C) 2009-2010 Carl Hetherington <carl@carlh.net>
5  * Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <list>
23 #include <string>
24
25 #include "pbd/xml++.h"
26 #include "pbd/enumwriter.h"
27
28 #include "ardour/chan_count.h"
29 #include "ardour/data_type.h"
30 #include "ardour/io.h"
31 #include "ardour/io_processor.h"
32 #include "ardour/processor.h"
33 #include "ardour/route.h"
34 #include "ardour/session_object.h"
35 #include "ardour/types.h"
36
37 #include "pbd/i18n.h"
38
39 using namespace std;
40 using namespace ARDOUR;
41 using namespace PBD;
42
43 namespace ARDOUR { class Session; }
44
45 /* create an IOProcessor that proxies to a new IO object */
46
47 IOProcessor::IOProcessor (Session& s, bool with_input, bool with_output,
48                           const string& proc_name, const string io_name, DataType dtype, bool sendish)
49         : Processor(s, proc_name)
50 {
51         /* these are true in this constructor whether we actually create the associated
52            IO objects or not.
53         */
54
55         _own_input = true;
56         _own_output = true;
57
58         if (with_input) {
59                 _input.reset (new IO(s, io_name.empty() ? proc_name : io_name, IO::Input, dtype, sendish));
60         }
61
62         if (with_output) {
63                 _output.reset (new IO(s, io_name.empty() ? proc_name : io_name, IO::Output, dtype, sendish));
64         }
65 }
66
67 /* create an IOProcessor that proxies to an existing IO object */
68
69 IOProcessor::IOProcessor (Session& s, boost::shared_ptr<IO> in, boost::shared_ptr<IO> out,
70                           const string& proc_name, DataType /*dtype*/)
71         : Processor(s, proc_name)
72         , _input (in)
73         , _output (out)
74 {
75         if (in) {
76                 _own_input = false;
77         } else {
78                 _own_input = true;
79         }
80
81         if (out) {
82                 _own_output = false;
83         } else {
84                 _own_output = true;
85         }
86 }
87
88 IOProcessor::~IOProcessor ()
89 {
90 }
91
92 void
93 IOProcessor::set_input (boost::shared_ptr<IO> io)
94 {
95         /* CALLER MUST HOLD PROCESS LOCK */
96
97         _input = io;
98         _own_input = false;
99 }
100
101 void
102 IOProcessor::set_output (boost::shared_ptr<IO> io)
103 {
104         /* CALLER MUST HOLD PROCESS LOCK */
105
106         _output = io;
107         _own_output = false;
108 }
109
110 XMLNode&
111 IOProcessor::state ()
112 {
113         XMLNode& node (Processor::state ());
114
115         node.set_property ("own-input", _own_input);
116
117         if (_input) {
118                 if (_own_input) {
119                         XMLNode& i (_input->get_state ());
120                         // i.name() = X_("output");
121                         node.add_child_nocopy (i);
122                 } else {
123                         node.set_property ("input", _input->name ());
124                 }
125         }
126
127         node.set_property ("own-output", _own_output);
128
129         if (_output) {
130                 if (_own_output) {
131                         XMLNode& o (_output->get_state ());
132                         node.add_child_nocopy (o);
133                 } else {
134                         node.set_property ("output", _output->name ());
135                 }
136         }
137
138         return node;
139 }
140
141 int
142 IOProcessor::set_state (const XMLNode& node, int version)
143 {
144         if (version < 3000) {
145                 return set_state_2X (node, version);
146         }
147
148         XMLProperty const * prop;
149         const XMLNode *io_node = 0;
150
151         Processor::set_state(node, version);
152
153         bool ignore_name = node.property ("ignore-name");
154
155         node.get_property ("own-input", _own_input);
156         node.get_property ("own-output", _own_output);
157
158         /* don't attempt to set state for a proxied IO that we don't own */
159
160         XMLNodeList nlist = node.children();
161         XMLNodeIterator niter;
162         const string instr = enum_2_string (IO::Input);
163         const string outstr = enum_2_string (IO::Output);
164
165         std::string str;
166         if (_own_input && _input) {
167                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
168                         if ((*niter)->get_property ("name", str) && (_name == str || ignore_name)) {
169                                 if ((*niter)->get_property ("direction", str) && str == instr) {
170                                         io_node = (*niter);
171                                         break;
172                                 }
173                         }
174                 }
175
176                 if (io_node) {
177                         _input->set_state(*io_node, version);
178
179                         // legacy sessions: use IO name
180                         if ((prop = node.property ("name")) == 0) {
181                                 set_name (_input->name());
182                         }
183
184                 } else {
185                         /* no input, which is OK */
186                 }
187
188         }
189
190         if (_own_output && _output) {
191                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
192                         if ((*niter)->name() == "IO") {
193                                 if ((*niter)->get_property ("name", str) && (_name == str || ignore_name)) {
194                                         if ((*niter)->get_property ("direction", str) && str == outstr) {
195                                                 io_node = (*niter);
196                                                 break;
197                                         }
198                                 }
199                         }
200                 }
201
202                 if (io_node) {
203                         _output->set_state(*io_node, version);
204
205                         // legacy sessions: use IO name
206                         if ((prop = node.property ("name")) == 0) {
207                                 set_name (_output->name());
208                         }
209                 } else {
210                         /* no output, which is OK */
211                 }
212         }
213
214         return 0;
215 }
216
217 int
218 IOProcessor::set_state_2X (const XMLNode& node, int version)
219 {
220         _own_input = _own_output = true;
221
222         Processor::set_state_2X (node, version);
223
224         return 0;
225 }
226
227 void
228 IOProcessor::silence (samplecnt_t nframes, samplepos_t /* start_sample */)
229 {
230         if (_own_output && _output) {
231                 _output->silence (nframes);
232         }
233 }
234
235 ChanCount
236 IOProcessor::natural_output_streams() const
237 {
238         return _output ? _output->n_ports() : ChanCount::ZERO;
239 }
240
241 ChanCount
242 IOProcessor::natural_input_streams () const
243 {
244         return _input ? _input->n_ports() : ChanCount::ZERO;
245 }
246
247 bool
248 IOProcessor::set_name (const std::string& name)
249 {
250         bool ret = SessionObject::set_name (name);
251
252         if (ret && _own_input && _input) {
253                 ret = _input->set_name (name);
254         }
255
256         if (ret && _own_output && _output) {
257                 ret = _output->set_name (name);
258         }
259
260         return ret;
261 }
262
263 bool
264 IOProcessor::feeds (boost::shared_ptr<Route> other) const
265 {
266         return _output && _output->connected_to (other->input());
267 }
268
269 void
270 IOProcessor::disconnect ()
271 {
272         if (_input) {
273                 _input->disconnect (this);
274         }
275
276         if (_output) {
277                 _output->disconnect (this);
278         }
279 }
280
281 /** Set up the XML description of a send so that we will not
282  *  reset its name or bitslot during ::set_state()
283  *  @param state XML send state.
284  *  @param session Session.
285  */
286 void
287 IOProcessor::prepare_for_reset (XMLNode &state, const std::string& name)
288 {
289         state.set_property ("ignore-bitslot", true);
290         state.set_property ("ignore-name", true);
291
292         XMLNodeList nlist = state.children();
293         XMLNodeIterator niter;
294
295         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
296                 if ((*niter)->name() == IO::state_node_name.c_str()) {
297                         IO::prepare_for_reset (**niter, name);
298                 }
299         }
300 }