more work on the new all-Processor-all-The-Time redesign of Route - LOTS OF BREAKAGE...
[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, const string& proc_name, const string io_name, DataType dtype)
50         : Processor(s, proc_name)
51         , _io (new IO(s, io_name.empty() ? proc_name : io_name, dtype))
52 {
53         _own_io = true;
54 }
55
56 /* create an IOProcessor that proxies to an existing IO object */
57
58 IOProcessor::IOProcessor (Session& s, IO* io, const string& proc_name, DataType dtype)
59         : Processor(s, proc_name)
60         , _io (io)
61 {
62         _own_io = false;
63 }
64
65 IOProcessor::~IOProcessor ()
66 {
67         notify_callbacks ();
68 }
69
70 void
71 IOProcessor::set_io (boost::shared_ptr<IO> io)
72 {
73         /* CALLER MUST HOLD PROCESS LOCK */
74
75         _io = io;
76         _own_io = false;
77 }
78
79 XMLNode&
80 IOProcessor::state (bool full_state)
81 {
82         XMLNode& node (Processor::state (full_state));
83         
84         if (_own_io) {
85                 node.add_child_nocopy (_io->state (full_state));
86                 node.add_property ("own-io", "yes");
87         } else {
88                 node.add_property ("own-io", "no");
89                 node.add_property ("io", _io->name());
90         }
91
92         return node;
93 }
94
95 int
96 IOProcessor::set_state (const XMLNode& node)
97 {
98         const XMLProperty *prop;
99         const XMLNode *io_node = 0;
100
101         Processor::set_state(node);
102
103         if ((prop = node.property ("own-io")) != 0) {
104                 _own_io = prop->value() == "yes";
105         }
106
107         /* don't attempt to set state for a proxied IO that we don't own */
108
109         if (!_own_io) {
110
111                 /* look up the IO object we're supposed to proxy to */
112
113                 if ((prop = node.property ("io")) == 0) {
114                         fatal << "IOProcessor has no named IO object" << endmsg;
115                         /*NOTREACHED*/
116                 }
117
118                 boost::shared_ptr<Route> r = _session.route_by_name (prop->value());
119
120                 if (!r) {
121                         fatal << string_compose ("IOProcessor uses an unknown IO object called %1", prop->value()) << endmsg;
122                         /*NOTREACHED*/
123                 }
124
125                 /* gotcha */
126
127                 _io = boost::static_pointer_cast<IO> (r);
128
129                 return 0;
130         }
131
132         XMLNodeList nlist = node.children();
133         XMLNodeIterator niter;
134
135         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
136                 if ((*niter)->name() == IO::state_node_name) {
137                         io_node = (*niter);
138                         break;
139                 } else if ((*niter)->name() == "Redirect") {
140                         XMLNodeList rlist = (*niter)->children();
141                         XMLNodeIterator riter;
142
143                         for (riter = rlist.begin(); riter != rlist.end(); ++riter) {
144                                 if ( (*riter)->name() == IO::state_node_name) {
145                                         warning << _("Found legacy IO in a redirect") << endmsg;
146                                         io_node = (*riter);
147                                         break;
148                                 }
149                         }
150                 }
151         }
152
153         if (io_node) {
154                 _io->set_state(*io_node);
155
156                 // legacy sessions: use IO name
157                 if ((prop = node.property ("name")) == 0) {
158                         set_name (_io->name());
159                 }
160
161         } else {
162                 error << _("XML node describing a redirect is missing an IO node") << endmsg;
163                 return -1;
164         }
165
166         return 0;
167 }
168
169 void
170 IOProcessor::silence (nframes_t nframes)
171 {
172         if (_own_io) {
173                 _io->silence (nframes);
174         }
175 }
176
177 ChanCount
178 IOProcessor::output_streams() const
179 {
180         return _io->n_outputs();
181 }
182
183 ChanCount
184 IOProcessor::input_streams () const
185 {
186         return _io->n_inputs();
187 }
188
189 ChanCount
190 IOProcessor::natural_output_streams() const
191 {
192         return _io->n_outputs();
193 }
194
195 ChanCount
196 IOProcessor::natural_input_streams () const
197 {
198         return _io->n_inputs();
199 }
200
201 void
202 IOProcessor::automation_snapshot (nframes_t now, bool force)
203 {
204         if (_own_io) {
205                 _io->automation_snapshot(now, force);
206         }
207 }
208
209 bool
210 IOProcessor::set_name (const std::string& name)
211 {
212         bool ret = SessionObject::set_name (name);
213
214         if (ret && _own_io) {
215                 ret = _io->set_name (name);
216         }
217
218         return ret;
219 }