PluginInfo::type added to copy constructor. But why is the copy constructor defined...
[ardour.git] / libs / midi++2 / midimanager.cc
1 /*
2     Copyright (C) 1998-99 Paul Barton-Davis 
3     This program is free software; you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation; either version 2 of the License, or
6     (at your option) any later version.
7
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12
13     You should have received a copy of the GNU General Public License
14     along with this program; if not, write to the Free Software
15     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16
17     $Id$
18 */
19
20 #include <fcntl.h>
21
22 #include <glib.h>
23
24 #include <pbd/error.h>
25
26 #include <midi++/types.h>
27 #include <midi++/manager.h>
28 #include <midi++/factory.h>
29 #include <midi++/channel.h>
30
31 using namespace std;
32 using namespace MIDI;
33 using namespace PBD;
34
35 /* XXX check for strdup leaks */
36
37 Manager *Manager::theManager = 0;
38
39 Manager::Manager () 
40       
41 {
42         inputPort = 0;
43         outputPort = 0;
44         inputChannelNumber = 0;
45         outputChannelNumber = 0;
46 }
47
48 Manager::~Manager ()
49
50 {
51         PortMap::iterator i;
52
53         for (i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
54                 delete (*i).second;
55         }
56
57         ports_by_device.erase (ports_by_device.begin(), ports_by_device.end());
58         ports_by_tag.erase (ports_by_tag.begin(), ports_by_tag.end());
59
60         if (theManager == this) {
61                 theManager = 0;
62         }
63 }
64
65 Port *
66 Manager::add_port (const XMLNode& node)
67 {
68         Port::Descriptor desc (node);
69         PortFactory factory;
70         Port *port;
71         PortMap::iterator existing;
72         pair<string, Port *> newpair;
73
74         /* do not allow multiple ports with the same tag. if attempted, just return the existing
75            port with the same tag. XXX this is really caused by the mess of setup_midi() being
76            called twice in Ardour, once in the global init() function and once after the user RC file
77            has been loaded (there may be extra ports in it). 
78          */
79
80         if ((existing = ports_by_tag.find (desc.tag)) != ports_by_tag.end()) {
81
82                 port = (*existing).second;
83                 
84                 if (port->mode() == desc.mode) {
85                         
86                         /* Same mode - reuse the port, and just
87                            create a new tag entry.
88                         */
89                         
90                         newpair.first = desc.tag;
91                         newpair.second = port;
92                         
93                         ports_by_tag.insert (newpair);
94                         return port;
95                 }
96                 
97                 /* If the existing is duplex, and this request
98                    is not, then fail, because most drivers won't
99                    allow opening twice with duplex and non-duplex
100                    operation.
101                 */
102                 
103                 if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
104                     (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
105                         error << "MIDIManager: port tagged \""
106                               << desc.tag
107                               << "\" cannot be opened duplex and non-duplex"
108                               << endmsg;
109                         return 0;
110                 }
111                 
112                 /* modes must be different or complementary */
113         }
114
115         if (!PortFactory::ignore_duplicate_devices (desc.type)) {
116
117                 if ((existing = ports_by_device.find (desc.device)) != ports_by_device.end()) {
118                         
119                         port = (*existing).second;
120                         
121                         if (port->mode() == desc.mode) {
122                                 
123                                 /* Same mode - reuse the port, and just
124                                    create a new tag entry.
125                                 */
126                                 
127                                 newpair.first = desc.tag;
128                                 newpair.second = port;
129                                 
130                                 ports_by_tag.insert (newpair);
131                                 return port;
132                         }
133                         
134                         /* If the existing is duplex, and this request
135                            is not, then fail, because most drivers won't
136                            allow opening twice with duplex and non-duplex
137                            operation.
138                         */
139                         
140                         if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
141                             (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
142                                 error << "MIDIManager: port tagged \""
143                                       << desc.tag
144                                       << "\" cannot be opened duplex and non-duplex"
145                                       << endmsg;
146                                 return 0;
147                         }
148                         
149                         /* modes must be different or complementary */
150                 }
151         }
152         
153         port = factory.create_port (node);
154         
155         if (port == 0) {
156                 return 0;
157         }
158
159         if (!port->ok()) {
160                 delete port;
161                 return 0;
162         }
163
164         newpair.first = port->name();
165         newpair.second = port;
166         ports_by_tag.insert (newpair);
167
168         newpair.first = port->device();
169         newpair.second = port;
170         ports_by_device.insert (newpair);
171
172         /* first port added becomes the default input
173            port.
174         */
175
176         if (inputPort == 0) {
177                 inputPort = port;
178         } 
179
180         if (outputPort == 0) {
181                 outputPort = port;
182         }
183
184         return port;
185 }
186
187 int 
188 Manager::remove_port (Port* port)
189 {
190         PortMap::iterator res;
191
192         for (res = ports_by_device.begin(); res != ports_by_device.end(); ) {
193                 PortMap::iterator tmp;
194                 tmp = res;
195                 ++tmp;
196                 if (res->second == port) {
197                         ports_by_device.erase (res);
198                 } 
199                 res = tmp;
200         }
201
202
203         for (res = ports_by_tag.begin(); res != ports_by_tag.end(); ) {
204                 PortMap::iterator tmp;
205                 tmp = res;
206                 ++tmp;
207                 if (res->second == port) {
208                         ports_by_tag.erase (res);
209                 } 
210                 res = tmp;
211         }
212         
213         delete port;
214
215         return 0;
216 }
217
218 int
219 Manager::set_input_port (string tag)
220 {
221         PortMap::iterator res;
222         bool found = false;
223
224         for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
225                 if (tag == (*res).first) {
226                         found = true;
227                         break;
228                 }
229         }
230         
231         if (!found) {
232                 return -1;
233         }
234
235         inputPort = (*res).second;
236
237         return 0;
238 }
239
240 int
241 Manager::set_output_port (string tag)
242
243 {
244         PortMap::iterator res;
245         bool found = false;
246
247         for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
248                 if (tag == (*res).first) {
249                         found = true;
250                         break;
251                 }
252         }
253         
254         if (!found) {
255                 return -1;
256         }
257
258         // XXX send a signal to say we're about to change output ports
259
260         if (outputPort) {
261                 for (channel_t chan = 0; chan < 16; chan++) {
262                         outputPort->channel (chan)->all_notes_off ();
263                 }
264         }
265         outputPort = (*res).second;
266
267         // XXX send a signal to say we've changed output ports
268
269         return 0;
270 }
271
272 Port *
273 Manager::port (string name)
274 {
275         PortMap::iterator res;
276
277         for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
278                 if (name == (*res).first) {
279                         return (*res).second;
280                 }
281         }
282
283         return 0;
284 }
285
286 int
287 Manager::foreach_port (int (*func)(const Port &, size_t, void *),
288                            void *arg)
289 {
290         PortMap::const_iterator i;
291         int retval;
292         int n;
293                 
294         for (n = 0, i = ports_by_device.begin(); 
295                     i != ports_by_device.end(); i++, n++) {
296
297                 if ((retval = func (*((*i).second), n, arg)) != 0) {
298                         return retval;
299                 }
300         }
301
302         return 0;
303 }
304
305
306 int
307 Manager::get_known_ports (vector<PortSet>& ports)
308 {
309         return PortFactory::get_known_ports (ports);
310 }