Fix unused parameter warnings since GCC apparently doesn't feel like listening to...
[ardour.git] / libs / midi++2 / manager.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         inputPort = 0;
42         outputPort = 0;
43         inputChannelNumber = 0;
44         outputChannelNumber = 0;
45         api_data = 0;
46 }
47
48 Manager::~Manager ()
49 {
50         PortMap::iterator i;
51
52         for (i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
53                 delete (*i).second;
54         }
55
56         ports_by_device.erase (ports_by_device.begin(), ports_by_device.end());
57         ports_by_tag.erase (ports_by_tag.begin(), ports_by_tag.end());
58
59         if (theManager == this) {
60                 theManager = 0;
61         }
62 }
63
64 Port *
65 Manager::add_port (const XMLNode& node)
66 {
67         Port::Descriptor desc (node);
68         PortFactory factory;
69         Port *port;
70         PortMap::iterator existing;
71         pair<string, Port *> newpair;
72
73         /* do not allow multiple ports with the same tag. if attempted, just return the existing
74            port with the same tag. XXX this is really caused by the mess of setup_midi() being
75            called twice in Ardour, once in the global init() function and once after the user RC file
76            has been loaded (there may be extra ports in it). 
77          */
78
79         if ((existing = ports_by_tag.find (desc.tag)) != ports_by_tag.end()) {
80
81                 port = (*existing).second;
82                 
83                 if (port->mode() == desc.mode) {
84                         
85                         /* Same mode - reuse the port, and just
86                            create a new tag entry.
87                         */
88                         
89                         newpair.first = desc.tag;
90                         newpair.second = port;
91                         
92                         ports_by_tag.insert (newpair);
93                         return port;
94                 }
95                 
96                 /* If the existing is duplex, and this request
97                    is not, then fail, because most drivers won't
98                    allow opening twice with duplex and non-duplex
99                    operation.
100                 */
101                 
102                 if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
103                     (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
104                         error << "MIDIManager: port tagged \""
105                               << desc.tag
106                               << "\" cannot be opened duplex and non-duplex"
107                               << endmsg;
108                         return 0;
109                 }
110                 
111                 /* modes must be different or complementary */
112         }
113
114         if (!PortFactory::ignore_duplicate_devices (desc.type)) {
115
116                 if ((existing = ports_by_device.find (desc.device)) != ports_by_device.end()) {
117                         
118                         port = (*existing).second;
119                         
120                         if (port->mode() == desc.mode) {
121                                 
122                                 /* Same mode - reuse the port, and just
123                                    create a new tag entry.
124                                 */
125                                 
126                                 newpair.first = desc.tag;
127                                 newpair.second = port;
128                                 
129                                 ports_by_tag.insert (newpair);
130                                 return port;
131                         }
132                         
133                         /* If the existing is duplex, and this request
134                            is not, then fail, because most drivers won't
135                            allow opening twice with duplex and non-duplex
136                            operation.
137                         */
138                         
139                         if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
140                             (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
141                                 error << "MIDIManager: port tagged \""
142                                       << desc.tag
143                                       << "\" cannot be opened duplex and non-duplex"
144                                       << endmsg;
145                                 return 0;
146                         }
147                         
148                         /* modes must be different or complementary */
149                 }
150         }
151         
152         port = factory.create_port (node, api_data);
153         
154         if (port == 0) {
155                 return 0;
156         }
157
158         if (!port->ok()) {
159                 delete port;
160                 return 0;
161         }
162
163         newpair.first = port->name();
164         newpair.second = port;
165         ports_by_tag.insert (newpair);
166
167         newpair.first = port->device();
168         newpair.second = port;
169         ports_by_device.insert (newpair);
170
171         /* first port added becomes the default input
172            port.
173         */
174
175         if (inputPort == 0) {
176                 inputPort = port;
177         } 
178
179         if (outputPort == 0) {
180                 outputPort = port;
181         }
182
183         return port;
184 }
185
186 int 
187 Manager::remove_port (Port* port)
188 {
189         PortMap::iterator res;
190
191         for (res = ports_by_device.begin(); res != ports_by_device.end(); ) {
192                 PortMap::iterator tmp;
193                 tmp = res;
194                 ++tmp;
195                 if (res->second == port) {
196                         ports_by_device.erase (res);
197                 } 
198                 res = tmp;
199         }
200
201
202         for (res = ports_by_tag.begin(); res != ports_by_tag.end(); ) {
203                 PortMap::iterator tmp;
204                 tmp = res;
205                 ++tmp;
206                 if (res->second == port) {
207                         ports_by_tag.erase (res);
208                 } 
209                 res = tmp;
210         }
211         
212         delete port;
213
214         return 0;
215 }
216
217 int
218 Manager::set_input_port (string tag)
219 {
220         PortMap::iterator res;
221         bool found = false;
222
223         for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
224                 if (tag == (*res).first) {
225                         found = true;
226                         break;
227                 }
228         }
229         
230         if (!found) {
231                 return -1;
232         }
233
234         inputPort = (*res).second;
235
236         return 0;
237 }
238
239 int
240 Manager::set_output_port (string tag)
241
242 {
243         PortMap::iterator res;
244         bool found = false;
245
246         for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
247                 if (tag == (*res).first) {
248                         found = true;
249                         break;
250                 }
251         }
252         
253         if (!found) {
254                 return -1;
255         }
256
257         // XXX send a signal to say we're about to change output ports
258
259         if (outputPort) {
260                 for (channel_t chan = 0; chan < 16; chan++) {
261                         outputPort->channel (chan)->all_notes_off (0);
262                 }
263         }
264         outputPort = (*res).second;
265
266         // XXX send a signal to say we've changed output ports
267
268         return 0;
269 }
270
271 Port *
272 Manager::port (string name)
273 {
274         PortMap::iterator res;
275
276         for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
277                 if (name == (*res).first) {
278                         return (*res).second;
279                 }
280         }
281
282         return 0;
283 }
284
285 int
286 Manager::foreach_port (int (*func)(const Port &, size_t, void *),
287                            void *arg)
288 {
289         PortMap::const_iterator i;
290         int retval;
291         int n;
292                 
293         for (n = 0, i = ports_by_device.begin(); 
294                     i != ports_by_device.end(); i++, n++) {
295
296                 if ((retval = func (*((*i).second), n, arg)) != 0) {
297                         return retval;
298                 }
299         }
300
301         return 0;
302 }
303
304 void
305 Manager::cycle_start(nframes_t nframes)
306 {
307         for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
308                 (*i).second->cycle_start (nframes);
309         }
310 }
311
312 void
313 Manager::cycle_end()
314 {
315         for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
316                 (*i).second->cycle_end ();
317         }
318 }
319
320
321 int
322 Manager::get_known_ports (vector<PortSet>& ports)
323 {
324         return PortFactory::get_known_ports (ports);
325 }