fbfd02d50904cf6b4775c814309babca8233553f
[ardour.git] / libs / ardour / connection.cc
1 /*
2     Copyright (C) 2002 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     $Id$
19 */
20
21 #include <algorithm>
22
23 #include <pbd/failed_constructor.h>
24 #include <ardour/ardour.h>
25 #include <ardour/connection.h>
26 #include <pbd/xml++.h>
27
28 #include "i18n.h"
29
30 using namespace ARDOUR;
31 using namespace PBD;
32
33 Connection::Connection (const XMLNode& node)
34 {
35         if (set_state (node)) {
36                 throw failed_constructor();
37         }
38 }
39
40 InputConnection::InputConnection (const XMLNode& node)
41         : Connection (node)
42 {
43 }
44
45 OutputConnection::OutputConnection (const XMLNode& node)
46         : Connection (node)
47 {
48 }
49
50 void
51 Connection::set_name (string name, void *src)
52 {
53         _name = name;
54         NameChanged (src);
55 }
56
57 void
58 Connection::add_connection (int port, string portname)
59 {
60         {
61                 Glib::Mutex::Lock lm (port_lock);
62                 _ports[port].push_back (portname);
63         }
64          ConnectionsChanged (port); /* EMIT SIGNAL */
65 }
66
67 void
68 Connection::remove_connection (int port, string portname)
69 {
70         bool changed = false;
71
72         {
73                 Glib::Mutex::Lock lm (port_lock);
74                 PortList& pl = _ports[port];
75                 PortList::iterator i = find (pl.begin(), pl.end(), portname);
76                 
77                 if (i != pl.end()) {
78                         pl.erase (i);
79                         changed = true;
80                 }
81         }
82
83         if (changed) {
84                  ConnectionsChanged (port); /* EMIT SIGNAL */
85         }
86 }
87
88 const Connection::PortList&
89 Connection::port_connections (int port) const
90 {
91         Glib::Mutex::Lock lm (port_lock);
92         return _ports[port];
93 }
94
95 bool
96 Connection::operator== (const Connection& other) const
97 {
98         return other._ports == _ports;
99 }
100
101 void
102 Connection::add_port ()
103 {
104         {
105                 Glib::Mutex::Lock lm (port_lock);
106                 _ports.push_back (PortList());
107         }
108          ConfigurationChanged(); /* EMIT SIGNAL */
109 }
110
111 void
112 Connection::remove_port (int which_port)
113 {
114         bool changed = false;
115
116         {
117                 Glib::Mutex::Lock lm (port_lock);
118                 vector<PortList>::iterator i;
119                 int n;
120                 
121                 for (n = 0, i = _ports.begin(); i != _ports.end() && n < which_port; ++i, ++n);
122
123                 if (i != _ports.end()) {
124                         _ports.erase (i);
125                         changed = true;
126                 }
127         }
128
129         if (changed) {
130                  ConfigurationChanged(); /* EMIT SIGNAL */
131         }
132 }
133
134 void 
135 Connection::clear ()
136 {
137         {
138                 Glib::Mutex::Lock lm (port_lock);
139                 _ports.clear ();
140         }
141
142          ConfigurationChanged(); /* EMIT SIGNAL */
143 }
144
145 XMLNode&
146 Connection::get_state ()
147 {
148         XMLNode *node;
149         string str;
150
151         if (dynamic_cast<InputConnection *> (this)) {
152                 node = new XMLNode ("InputConnection");
153         } else {
154                 node = new XMLNode ("OutputConnection");
155         }
156
157         node->add_property ("name", _name);
158
159         for (vector<PortList>::iterator i = _ports.begin(); i != _ports.end(); ++i) {
160
161                 str += '{';
162
163                 for (vector<string>::iterator ii = (*i).begin(); ii != (*i).end(); ++ii) {
164                         if (ii != (*i).begin()) {
165                                 str += ',';
166                         }
167                         str += *ii;
168                 }
169                 str += '}';
170         }
171
172         node->add_property ("connections", str);
173
174         return *node;
175 }
176
177 int
178 Connection::set_state (const XMLNode& node)
179 {
180         const XMLProperty *prop;
181
182         if ((prop = node.property ("name")) == 0) {
183                 error << _("Node for Connection has no \"name\" property") << endmsg;
184                 return -1;
185         }
186
187         _name = prop->value();
188         _sysdep = false;
189         
190         if ((prop = node.property ("connections")) == 0) {
191                 error << _("Node for Connection has no \"connections\" property") << endmsg;
192                 return -1;
193         }
194         
195         set_connections (prop->value());
196
197         return 0;
198 }
199
200 int
201 Connection::set_connections (const string& str)
202 {
203         vector<string> ports;
204         int i;
205         int n;
206         int nports;
207         
208         if ((nports = count (str.begin(), str.end(), '{')) == 0) {
209                 return 0;
210         }
211
212         for (n = 0; n < nports; ++n) {
213                 add_port ();
214         }
215
216         string::size_type start, end, ostart;
217
218         ostart = 0;
219         start = 0;
220         end = 0;
221         i = 0;
222
223         while ((start = str.find_first_of ('{', ostart)) != string::npos) {
224                 start += 1;
225
226                 if ((end = str.find_first_of ('}', start)) == string::npos) {
227                         error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
228                         return -1;
229                 }
230
231                 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
232                         error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
233
234                         return -1;
235                         
236                 } else if (n > 0) {
237
238                         for (int x = 0; x < n; ++x) {
239                                 add_connection (i, ports[x]);
240                         }
241                 }
242
243                 ostart = end+1;
244                 i++;
245         }
246
247         return 0;
248 }
249
250 int
251 Connection::parse_io_string (const string& str, vector<string>& ports)
252 {
253         string::size_type pos, opos;
254
255         if (str.length() == 0) {
256                 return 0;
257         }
258
259         pos = 0;
260         opos = 0;
261
262         ports.clear ();
263
264         while ((pos = str.find_first_of (',', opos)) != string::npos) {
265                 ports.push_back (str.substr (opos, pos - opos));
266                 opos = pos + 1;
267         }
268         
269         if (opos < str.length()) {
270                 ports.push_back (str.substr(opos));
271         }
272
273         return ports.size();
274 }
275