cfa2b4c689ef177c1100785407d5814d7dd544e7
[ardour.git] / libs / ardour / io_processor.cc
1 /*
2     Copyright (C) 2001 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 <fstream>
21 #include <algorithm>
22 #include <string>
23 #include <cerrno>
24 #include <unistd.h>
25 #include <sstream>
26
27 #include <sigc++/bind.h>
28
29 #include "pbd/xml++.h"
30 #include "pbd/enumwriter.h"
31
32 #include "ardour/io_processor.h"
33 #include "ardour/session.h"
34 #include "ardour/utils.h"
35 #include "ardour/send.h"
36 #include "ardour/port_insert.h"
37 #include "ardour/plugin_insert.h"
38 #include "ardour/io.h"
39 #include "ardour/route.h"
40
41 #include "i18n.h"
42
43 using namespace std;
44 using namespace ARDOUR;
45 using namespace PBD;
46
47 /* create an IOProcessor that proxies to a new IO object */
48
49 IOProcessor::IOProcessor (Session& s, bool with_input, bool with_output,
50                           const string& proc_name, const string io_name, DataType dtype)
51         : Processor(s, proc_name)
52 {
53         /* these are true in this constructor whether we actually create the associated
54            IO objects or not.
55         */
56
57         _own_input = true;
58         _own_output = true;
59
60         if (with_input) {
61                 _input.reset (new IO(s, io_name.empty() ? proc_name : io_name, IO::Input, dtype));
62         }
63
64         if (with_output) {
65                 _output.reset (new IO(s, io_name.empty() ? proc_name : io_name, IO::Output, dtype));
66         }
67
68         cerr << "fresh create IOP name = " << proc_name << " in = " << _input << " out = " << _output << endl;
69 }
70
71 /* create an IOProcessor that proxies to an existing IO object */
72
73 IOProcessor::IOProcessor (Session& s, boost::shared_ptr<IO> in, boost::shared_ptr<IO> out, 
74                           const string& proc_name, DataType dtype)
75         : Processor(s, proc_name)
76         , _input (in)
77         , _output (out)
78 {
79         cerr << "XML create IOP name = " << proc_name << " in = " << in << " out = " << out << endl;
80         if (in) {
81                 _own_input = false;
82         } else {
83                 _own_input = true;
84         }
85
86         if (out) {
87                 _own_output = false;
88         } else {
89                 _own_output = true;
90         }
91 }
92
93 IOProcessor::~IOProcessor ()
94 {
95         notify_callbacks ();
96 }
97
98 void
99 IOProcessor::set_input (boost::shared_ptr<IO> io)
100 {
101         /* CALLER MUST HOLD PROCESS LOCK */
102
103         _input = io;
104         _own_input = false;
105 }
106
107 void
108 IOProcessor::set_output (boost::shared_ptr<IO> io)
109 {
110         /* CALLER MUST HOLD PROCESS LOCK */
111
112         _output = io;
113         _own_output = false;
114 }
115
116 XMLNode&
117 IOProcessor::state (bool full_state)
118 {
119         XMLNode& node (Processor::state (full_state));
120         
121         if (_own_input) {
122                 node.add_property ("own-input", "yes");
123                 if (_input) {
124                         XMLNode& i (_input->state (full_state));
125                         // i.name() = X_("output");
126                         node.add_child_nocopy (i);
127                 }
128         } else {
129                 node.add_property ("own-input", "no");
130                 if (_input) {
131                         node.add_property ("input", _input->name());
132                 }
133         }
134         
135         if (_own_output) {
136                 node.add_property ("own-output", "yes");
137                 if (_output) {
138                         XMLNode& o (_output->state (full_state));
139                         // o.name() = X_("output");
140                         node.add_child_nocopy (o);
141                 }
142         } else {
143                 node.add_property ("own-output", "no");
144                 if (_output) {
145                         node.add_property ("output", _output->name());
146                 }
147         }
148
149         return node;
150 }
151
152 int
153 IOProcessor::set_state (const XMLNode& node)
154 {
155         const XMLProperty *prop;
156         const XMLNode *io_node = 0;
157
158         Processor::set_state(node);
159
160         if ((prop = node.property ("own-input")) != 0) {
161                 _own_input = (prop->value() == "yes");
162         }
163
164         if ((prop = node.property ("own-output")) != 0) {
165                 _own_output = (prop->value() == "yes");
166         }
167
168         cerr << _name << " own input = " << _own_input << " output = " << _own_output << endl;
169         
170         /* don't attempt to set state for a proxied IO that we don't own */
171
172         XMLNodeList nlist = node.children();
173         XMLNodeIterator niter;
174         
175         if (_own_input) {
176                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
177                         if ((*niter)->name() == "input") {
178                                 io_node = (*niter);
179                                 break;
180                         }
181                 }
182                 
183                 if (io_node) {
184                         _input->set_state(*io_node);
185                         
186                         // legacy sessions: use IO name
187                         if ((prop = node.property ("name")) == 0) {
188                                 set_name (_input->name());
189                         }
190                         
191                 } else {
192                         /* no input */
193                 }
194
195         }
196         
197         if (_own_output) {
198                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
199                         if ((*niter)->name() == "output") {
200                                 io_node = (*niter);
201                                 break;
202                         }
203                 }
204                 
205                 if (io_node) {
206                         _output->set_state(*io_node);
207                         
208                         // legacy sessions: use IO name
209                         if ((prop = node.property ("name")) == 0) {
210                                 set_name (_output->name());
211                         }
212                 } else {
213                         /* no output */
214                 }
215         }
216
217         return 0;
218 }
219
220 void
221 IOProcessor::silence (nframes_t nframes)
222 {
223         if (_own_output && _output) {
224                 _output->silence (nframes);
225         }
226 }
227
228 ChanCount
229 IOProcessor::output_streams() const
230 {
231         return _output ? _output->n_ports() : ChanCount::ZERO;
232 }
233
234 ChanCount
235 IOProcessor::input_streams () const
236 {
237         return _input ? _input->n_ports() : ChanCount::ZERO;
238 }
239
240 ChanCount
241 IOProcessor::natural_output_streams() const
242 {
243         return _output ? _output->n_ports() : ChanCount::ZERO;
244 }
245
246 ChanCount
247 IOProcessor::natural_input_streams () const
248 {
249         return _input ? _input->n_ports() : ChanCount::ZERO;
250 }
251
252 bool
253 IOProcessor::set_name (const std::string& name)
254 {
255         bool ret = SessionObject::set_name (name);
256
257         if (ret && _own_input && _input) {
258                 ret = _input->set_name (name);
259         }
260
261         if (ret && _own_output && _output) {
262                 ret = _output->set_name (name);
263         }
264
265         return ret;
266 }
267
268 bool
269 IOProcessor::feeds (boost::shared_ptr<Route> other) const
270 {
271         return _output && _output->connected_to (other->input());
272 }