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;
43 inputChannelNumber = 0;
44 outputChannelNumber = 0;
52 for (i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
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());
59 if (theManager == this) {
65 Manager::add_port (const XMLNode& node)
67 Port::Descriptor desc (node);
70 PortMap::iterator existing;
71 pair<string, Port *> newpair;
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).
79 if ((existing = ports_by_tag.find (desc.tag)) != ports_by_tag.end()) {
81 port = (*existing).second;
83 if (port->mode() == desc.mode) {
85 /* Same mode - reuse the port, and just
86 create a new tag entry.
89 newpair.first = desc.tag;
90 newpair.second = port;
92 ports_by_tag.insert (newpair);
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
102 if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
103 (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
104 error << "MIDIManager: port tagged \""
106 << "\" cannot be opened duplex and non-duplex"
111 /* modes must be different or complementary */
114 if (!PortFactory::ignore_duplicate_devices (desc.type)) {
116 if ((existing = ports_by_device.find (desc.device)) != ports_by_device.end()) {
118 port = (*existing).second;
120 if (port->mode() == desc.mode) {
122 /* Same mode - reuse the port, and just
123 create a new tag entry.
126 newpair.first = desc.tag;
127 newpair.second = port;
129 ports_by_tag.insert (newpair);
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
139 if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
140 (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
141 error << "MIDIManager: port tagged \""
143 << "\" cannot be opened duplex and non-duplex"
148 /* modes must be different or complementary */
152 port = factory.create_port (node, api_data);
163 newpair.first = port->name();
164 newpair.second = port;
165 ports_by_tag.insert (newpair);
167 newpair.first = port->device();
168 newpair.second = port;
169 ports_by_device.insert (newpair);
171 /* first port added becomes the default input
175 if (inputPort == 0) {
179 if (outputPort == 0) {
187 Manager::remove_port (Port* port)
189 PortMap::iterator res;
191 for (res = ports_by_device.begin(); res != ports_by_device.end(); ) {
192 PortMap::iterator tmp;
195 if (res->second == port) {
196 ports_by_device.erase (res);
202 for (res = ports_by_tag.begin(); res != ports_by_tag.end(); ) {
203 PortMap::iterator tmp;
206 if (res->second == port) {
207 ports_by_tag.erase (res);
218 Manager::set_input_port (string tag)
220 PortMap::iterator res;
223 for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
224 if (tag == (*res).first) {
234 inputPort = (*res).second;
240 Manager::set_output_port (string tag)
243 PortMap::iterator res;
246 for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
247 if (tag == (*res).first) {
257 // XXX send a signal to say we're about to change output ports
260 for (channel_t chan = 0; chan < 16; chan++) {
261 outputPort->channel (chan)->all_notes_off (0);
264 outputPort = (*res).second;
266 // XXX send a signal to say we've changed output ports
272 Manager::port (string name)
274 PortMap::iterator res;
276 for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
277 if (name == (*res).first) {
278 return (*res).second;
286 Manager::foreach_port (int (*func)(const Port &, size_t, void *),
289 PortMap::const_iterator i;
293 for (n = 0, i = ports_by_device.begin();
294 i != ports_by_device.end(); i++, n++) {
296 if ((retval = func (*((*i).second), n, arg)) != 0) {
305 Manager::cycle_start(nframes_t nframes)
307 for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
308 (*i).second->cycle_start (nframes);
315 for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
316 (*i).second->cycle_end ();
322 Manager::get_known_ports (vector<PortSet>& ports)
324 return PortFactory::get_known_ports (ports);