provide support for playhead-to-next/previous-region-boundary actions, and bindings...
[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         if (!PortFactory::ignore_duplicate_devices (desc.type)) {
75
76                 if ((existing = ports_by_device.find (desc.device)) != ports_by_device.end()) {
77                         
78                         port = (*existing).second;
79                         
80                         if (port->mode() == desc.mode) {
81                                 
82                                 /* Same mode - reuse the port, and just
83                                    create a new tag entry.
84                                 */
85                                 
86                                 newpair.first = desc.tag;
87                                 newpair.second = port;
88                                 
89                                 ports_by_tag.insert (newpair);
90                                 return port;
91                         }
92                         
93                         /* If the existing is duplex, and this request
94                            is not, then fail, because most drivers won't
95                            allow opening twice with duplex and non-duplex
96                            operation.
97                         */
98                         
99                         if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
100                             (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
101                                 error << "MIDIManager: port tagged \""
102                                       << desc.tag
103                                       << "\" cannot be opened duplex and non-duplex"
104                                       << endmsg;
105                                 return 0;
106                         }
107                         
108                         /* modes must be different or complementary */
109                 }
110         }
111         
112         port = factory.create_port (node);
113         
114         if (port == 0) {
115                 return 0;
116         }
117
118         if (!port->ok()) {
119                 delete port;
120                 return 0;
121         }
122
123         newpair.first = port->name();
124         newpair.second = port;
125         ports_by_tag.insert (newpair);
126
127         newpair.first = port->device();
128         newpair.second = port;
129         ports_by_device.insert (newpair);
130
131         /* first port added becomes the default input
132            port.
133         */
134
135         if (inputPort == 0) {
136                 inputPort = port;
137         } 
138
139         if (outputPort == 0) {
140                 outputPort = port;
141         }
142
143         return port;
144 }
145
146 int 
147 Manager::remove_port (Port* port)
148 {
149         PortMap::iterator res;
150
151         for (res = ports_by_device.begin(); res != ports_by_device.end(); ) {
152                 PortMap::iterator tmp;
153                 tmp = res;
154                 ++tmp;
155                 if (res->second == port) {
156                         ports_by_device.erase (res);
157                 } 
158                 res = tmp;
159         }
160
161
162         for (res = ports_by_tag.begin(); res != ports_by_tag.end(); ) {
163                 PortMap::iterator tmp;
164                 tmp = res;
165                 ++tmp;
166                 if (res->second == port) {
167                         ports_by_tag.erase (res);
168                 } 
169                 res = tmp;
170         }
171         
172         delete port;
173
174         return 0;
175 }
176
177 int
178 Manager::set_input_port (string tag)
179 {
180         PortMap::iterator res;
181         bool found = false;
182
183         for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
184                 if (tag == (*res).first) {
185                         found = true;
186                         break;
187                 }
188         }
189         
190         if (!found) {
191                 return -1;
192         }
193
194         inputPort = (*res).second;
195
196         return 0;
197 }
198
199 int
200 Manager::set_output_port (string tag)
201
202 {
203         PortMap::iterator res;
204         bool found = false;
205
206         for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
207                 if (tag == (*res).first) {
208                         found = true;
209                         break;
210                 }
211         }
212         
213         if (!found) {
214                 return -1;
215         }
216
217         // XXX send a signal to say we're about to change output ports
218
219         if (outputPort) {
220                 for (channel_t chan = 0; chan < 16; chan++) {
221                         outputPort->channel (chan)->all_notes_off ();
222                 }
223         }
224         outputPort = (*res).second;
225
226         // XXX send a signal to say we've changed output ports
227
228         return 0;
229 }
230
231 Port *
232 Manager::port (string name)
233 {
234         PortMap::iterator res;
235
236         for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
237                 if (name == (*res).first) {
238                         return (*res).second;
239                 }
240         }
241
242         return 0;
243 }
244
245 int
246 Manager::foreach_port (int (*func)(const Port &, size_t, void *),
247                            void *arg)
248 {
249         PortMap::const_iterator i;
250         int retval;
251         int n;
252                 
253         for (n = 0, i = ports_by_device.begin(); 
254                     i != ports_by_device.end(); i++, n++) {
255
256                 if ((retval = func (*((*i).second), n, arg)) != 0) {
257                         return retval;
258                 }
259         }
260
261         return 0;
262 }
263
264
265 int
266 Manager::get_known_ports (vector<PortSet>& ports)
267 {
268         return PortFactory::get_known_ports (ports);
269 }