Add ARDOUR::ardour_search_path that contains the directories in the ARDOUR_PATH envir...
[ardour.git] / libs / midi++2 / fd_midiport.cc
1 /*
2     Copyright (C) 1999 Paul Barton-Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <fcntl.h>
22 #include <cerrno>
23
24 #include <pbd/error.h>
25 #include <pbd/pathscanner.h>
26
27 #include <midi++/types.h>
28 #include <midi++/fd_midiport.h>
29
30 using namespace std;
31 using namespace MIDI;
32 using namespace PBD;
33
34 string *FD_MidiPort::midi_dirpath = 0;
35 string *FD_MidiPort::midi_filename_pattern = 0;
36
37 FD_MidiPort::FD_MidiPort (PortRequest &req, 
38                           const string &dirpath,
39                           const string &pattern) 
40         : Port (req)
41 {       
42         open (req);
43
44         if (_fd < 0) {
45                 switch (errno) {
46                 case EBUSY:
47                         error << "MIDI: port device in use" << endmsg;
48                         req.status = PortRequest::Busy;
49                         break;
50                 case ENOENT:
51                         error << "MIDI: no such port device" << endmsg;
52                         req.status = PortRequest::NoSuchFile;
53                         break;
54                 case EACCES:
55                         error << "MIDI: access to port denied" << endmsg;
56                         req.status = PortRequest::NotAllowed;
57                         break;
58                 default:
59                         req.status = PortRequest::Unknown;
60                 } 
61         } else {
62                 _ok = true;
63                 req.status = PortRequest::OK;
64
65                 if (midi_dirpath == 0) {
66                         midi_dirpath = new string (dirpath);
67                         midi_filename_pattern = new string (pattern);
68                 }
69
70                 if (req.mode & O_NONBLOCK == 0) {
71                         /* we unconditionally set O_NONBLOCK during
72                            open, but the request didn't ask for it,
73                            so remove it.
74                         */
75
76                         int flags = fcntl (_fd, F_GETFL, 0);
77                         fcntl (_fd, F_SETFL, flags & ~(O_NONBLOCK));
78                 }
79         }
80 }
81
82 void
83 FD_MidiPort::open (PortRequest &req)
84
85 {
86         int mode = req.mode | O_NONBLOCK;
87         _fd = ::open (req.devname, mode);
88 }
89
90 vector<string *> *
91 FD_MidiPort::list_devices ()
92
93 {
94         PathScanner scanner;
95
96         return scanner (*midi_dirpath, *midi_filename_pattern, false, true);
97 }       
98
99 int
100 FD_MidiPort::selectable () const
101
102 {
103         long flags;
104         
105         /* turn on non-blocking mode, since we plan to use select/poll
106            to tell us when there is data to read.
107         */
108
109         flags = fcntl (_fd, F_GETFL);
110         flags |= O_NONBLOCK;
111
112         if (fcntl (_fd, F_SETFL, flags)) {
113                 error << "FD_MidiPort: could not turn on non-blocking mode"
114                       << " (" << strerror (errno) 
115                       << ')'
116                       << endmsg;
117
118                 return -1;
119         }
120
121         return _fd;
122 }
123
124
125 int
126 FD_MidiPort::do_slow_write (byte *msg, unsigned int msglen)
127
128 {
129         size_t n;
130         size_t i;
131
132         for (n = 0; n < msglen; n++) {
133
134                 if (::write (_fd, &msg[n], 1) != 1) {
135                         break;
136                 }
137
138                 bytes_written++;
139                 for (i = 0; i < slowdown * 10000; i++);
140         }
141
142
143         if (n && output_parser) {
144                 output_parser->raw_preparse (*output_parser, msg, n);
145                 for (unsigned int i = 0; i < n; i++) {
146                         output_parser->scanner (msg[i]);
147                 }
148                 output_parser->raw_postparse (*output_parser, msg, n);
149         }
150         
151         return n;
152 }
153
154 int
155 FD_MidiPort::read (byte* buf, size_t max, timestamp_t timestamp)
156 {
157         int nread;
158         
159         if ((_mode & O_ACCMODE) == O_WRONLY) {
160                 return -EACCES;
161         }
162         
163         // cerr << "MIDI: read up to " << max << " from " << _fd << " (" << name() << ')' << endl;
164         
165         if ((nread = ::read (_fd, buf, max)) > 0) {
166                 bytes_read += nread;
167
168                 // cerr << " read " << nread << endl;
169
170                 if (input_parser) {
171                         input_parser->raw_preparse 
172                                 (*input_parser, buf, nread);
173                         for (int i = 0; i < nread; i++) {
174                                 input_parser->scanner (buf[i]);
175                         }       
176                         input_parser->raw_postparse 
177                                 (*input_parser, buf, nread);
178                 }
179         }
180         
181         return nread;
182 }