2fd7a5e5f2994589c6b1ce57a675765bf6aebe85
[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 (const XMLNode& node,
38                           const string &dirpath,
39                           const string &pattern) 
40         : Port (node)
41 {       
42         Descriptor desc (node);
43
44         open (desc);
45
46         if (_fd < 0) {
47                 switch (errno) {
48                 case EBUSY:
49                         error << "MIDI: port device in use" << endmsg;
50                         break;
51                 case ENOENT:
52                         error << "MIDI: no such port device" << endmsg;
53                         break;
54                 case EACCES:
55                         error << "MIDI: access to port denied" << endmsg;
56                         break;
57                 default:
58                         break;
59                 } 
60         } else {
61                 _ok = true;
62
63                 if (midi_dirpath == 0) {
64                         midi_dirpath = new string (dirpath);
65                         midi_filename_pattern = new string (pattern);
66                 }
67
68                 if (desc.mode & O_NONBLOCK == 0) {
69                         /* we unconditionally set O_NONBLOCK during
70                            open, but the request didn't ask for it,
71                            so remove it.
72                         */
73
74                         int flags = fcntl (_fd, F_GETFL, 0);
75                         fcntl (_fd, F_SETFL, flags & ~(O_NONBLOCK));
76                 }
77         }
78 }
79
80 void
81 FD_MidiPort::open (const Descriptor& desc)
82
83 {
84         int mode = desc.mode | O_NONBLOCK;
85         _fd = ::open (desc.device.c_str(), mode);
86 }
87
88 vector<string *> *
89 FD_MidiPort::list_devices ()
90
91 {
92         PathScanner scanner;
93
94         return scanner (*midi_dirpath, *midi_filename_pattern, false, true);
95 }       
96
97 int
98 FD_MidiPort::selectable () const
99
100 {
101         long flags;
102         
103         /* turn on non-blocking mode, since we plan to use select/poll
104            to tell us when there is data to read.
105         */
106
107         flags = fcntl (_fd, F_GETFL);
108         flags |= O_NONBLOCK;
109
110         if (fcntl (_fd, F_SETFL, flags)) {
111                 error << "FD_MidiPort: could not turn on non-blocking mode"
112                       << " (" << strerror (errno) 
113                       << ')'
114                       << endmsg;
115
116                 return -1;
117         }
118
119         return _fd;
120 }
121
122
123 int
124 FD_MidiPort::do_slow_write (byte *msg, unsigned int msglen)
125
126 {
127         size_t n;
128         size_t i;
129
130         for (n = 0; n < msglen; n++) {
131
132                 if (::write (_fd, &msg[n], 1) != 1) {
133                         break;
134                 }
135
136                 bytes_written++;
137                 for (i = 0; i < slowdown * 10000; i++);
138         }
139
140
141         if (n && output_parser) {
142                 output_parser->raw_preparse (*output_parser, msg, n);
143                 for (unsigned int i = 0; i < n; i++) {
144                         output_parser->scanner (msg[i]);
145                 }
146                 output_parser->raw_postparse (*output_parser, msg, n);
147         }
148         
149         return n;
150 }
151
152 int
153 FD_MidiPort::read (byte* buf, size_t max)
154 {
155         int nread;
156         
157         if ((_mode & O_ACCMODE) == O_WRONLY) {
158                 return -EACCES;
159         }
160         
161         // cerr << "MIDI: read up to " << max << " from " << _fd << " (" << name() << ')' << endl;
162         
163         if ((nread = ::read (_fd, buf, max)) > 0) {
164                 bytes_read += nread;
165
166                 // cerr << " read " << nread << endl;
167
168                 if (input_parser) {
169                         input_parser->raw_preparse 
170                                 (*input_parser, buf, nread);
171                         for (int i = 0; i < nread; i++) {
172                                 input_parser->scanner (buf[i]);
173                         }       
174                         input_parser->raw_postparse 
175                                 (*input_parser, buf, nread);
176                 }
177         }
178         
179         return nread;
180 }