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