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.
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.
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.
24 #include <pbd/error.h>
26 #include <midi++/types.h>
27 #include <midi++/manager.h>
28 #include <midi++/factory.h>
29 #include <midi++/channel.h>
35 /* XXX check for strdup leaks */
37 Manager *Manager::theManager = 0;
44 inputChannelNumber = 0;
45 outputChannelNumber = 0;
53 for (i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
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());
60 if (theManager == this) {
66 Manager::add_port (const XMLNode& node)
68 Port::Descriptor desc (node);
71 PortMap::iterator existing;
72 pair<string, Port *> newpair;
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).
80 if ((existing = ports_by_tag.find (desc.tag)) != ports_by_tag.end()) {
82 port = (*existing).second;
84 if (port->mode() == desc.mode) {
86 /* Same mode - reuse the port, and just
87 create a new tag entry.
90 newpair.first = desc.tag;
91 newpair.second = port;
93 ports_by_tag.insert (newpair);
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
103 if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
104 (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
105 error << "MIDIManager: port tagged \""
107 << "\" cannot be opened duplex and non-duplex"
112 /* modes must be different or complementary */
115 if (!PortFactory::ignore_duplicate_devices (desc.type)) {
117 if ((existing = ports_by_device.find (desc.device)) != ports_by_device.end()) {
119 port = (*existing).second;
121 if (port->mode() == desc.mode) {
123 /* Same mode - reuse the port, and just
124 create a new tag entry.
127 newpair.first = desc.tag;
128 newpair.second = port;
130 ports_by_tag.insert (newpair);
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
140 if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
141 (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
142 error << "MIDIManager: port tagged \""
144 << "\" cannot be opened duplex and non-duplex"
149 /* modes must be different or complementary */
153 port = factory.create_port (node);
164 newpair.first = port->name();
165 newpair.second = port;
166 ports_by_tag.insert (newpair);
168 newpair.first = port->device();
169 newpair.second = port;
170 ports_by_device.insert (newpair);
172 /* first port added becomes the default input
176 if (inputPort == 0) {
180 if (outputPort == 0) {
188 Manager::remove_port (Port* port)
190 PortMap::iterator res;
192 for (res = ports_by_device.begin(); res != ports_by_device.end(); ) {
193 PortMap::iterator tmp;
196 if (res->second == port) {
197 ports_by_device.erase (res);
203 for (res = ports_by_tag.begin(); res != ports_by_tag.end(); ) {
204 PortMap::iterator tmp;
207 if (res->second == port) {
208 ports_by_tag.erase (res);
219 Manager::set_input_port (string tag)
221 PortMap::iterator res;
224 for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
225 if (tag == (*res).first) {
235 inputPort = (*res).second;
241 Manager::set_output_port (string tag)
244 PortMap::iterator res;
247 for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
248 if (tag == (*res).first) {
258 // XXX send a signal to say we're about to change output ports
261 for (channel_t chan = 0; chan < 16; chan++) {
262 outputPort->channel (chan)->all_notes_off ();
265 outputPort = (*res).second;
267 // XXX send a signal to say we've changed output ports
273 Manager::port (string name)
275 PortMap::iterator res;
277 for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
278 if (name == (*res).first) {
279 return (*res).second;
287 Manager::foreach_port (int (*func)(const Port &, size_t, void *),
290 PortMap::const_iterator i;
294 for (n = 0, i = ports_by_device.begin();
295 i != ports_by_device.end(); i++, n++) {
297 if ((retval = func (*((*i).second), n, arg)) != 0) {
307 Manager::get_known_ports (vector<PortSet>& ports)
309 return PortFactory::get_known_ports (ports);