ardour
midi_port.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 Paul 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 
19 #include <cassert>
20 #include <iostream>
21 
22 #include "pbd/compose.h"
23 #include "pbd/debug.h"
24 
25 #include "ardour/audioengine.h"
26 #include "ardour/data_type.h"
27 #include "ardour/debug.h"
28 #include "ardour/midi_buffer.h"
29 #include "ardour/midi_port.h"
30 
31 using namespace std;
32 using namespace ARDOUR;
33 using namespace PBD;
34 
35 #define port_engine AudioEngine::instance()->port_engine()
36 
37 MidiPort::MidiPort (const std::string& name, PortFlags flags)
38  : Port (name, DataType::MIDI, flags)
39  , _has_been_mixed_down (false)
40  , _resolve_required (false)
41  , _input_active (true)
42  , _always_parse (false)
43  , _trace_on (false)
44 {
45  _buffer = new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI));
46 }
47 
49 {
50  delete _buffer;
51 }
52 
53 void
55 {
57 
58  Port::cycle_start (nframes);
59 
60  _buffer->clear ();
61 
62  if (sends_output ()) {
63  port_engine.midi_clear (port_engine.get_buffer (_port_handle, nframes));
64  }
65 
66  if (_always_parse || (receives_input() && _trace_on)) {
67  MidiBuffer& mb (get_midi_buffer (nframes));
68 
69  /* dump incoming MIDI to parser */
70 
71  for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) {
72  uint8_t* buf = (*b).buffer();
73 
74  _self_parser.set_timestamp (now + (*b).time());
75 
76  uint32_t limit = (*b).size();
77 
78  for (size_t n = 0; n < limit; ++n) {
79  _self_parser.scanner (buf[n]);
80  }
81  }
82  }
83 }
84 
85 Buffer&
87 {
88  return get_midi_buffer (nframes);
89 }
90 
91 MidiBuffer &
93 {
95  return *_buffer;
96  }
97 
98  if (receives_input ()) {
99 
100  if (_input_active) {
101 
102  void* buffer = port_engine.get_buffer (_port_handle, nframes);
103  const pframes_t event_count = port_engine.get_midi_event_count (buffer);
104 
105  /* suck all relevant MIDI events from the MIDI port buffer
106  into our MidiBuffer
107  */
108 
109  for (pframes_t i = 0; i < event_count; ++i) {
110 
111  pframes_t timestamp;
112  size_t size;
113  uint8_t* buf;
114 
115  port_engine.midi_event_get (timestamp, size, &buf, buffer, i);
116 
117  if (buf[0] == 0xfe) {
118  /* throw away active sensing */
119  continue;
120  } else if ((buf[0] & 0xF0) == 0x90 && buf[2] == 0) {
121  /* normalize note on with velocity 0 to proper note off */
122  buf[0] = 0x80 | (buf[0] & 0x0F); /* note off */
123  buf[2] = 0x40; /* default velocity */
124  }
125 
126  /* check that the event is in the acceptable time range */
127 
128  if ((timestamp >= (_global_port_buffer_offset + _port_buffer_offset)) &&
129  (timestamp < (_global_port_buffer_offset + _port_buffer_offset + nframes))) {
130  _buffer->push_back (timestamp, size, buf);
131  } else {
132  cerr << "Dropping incoming MIDI at time " << timestamp << "; offset="
133  << _global_port_buffer_offset << " limit="
134  << (_global_port_buffer_offset + _port_buffer_offset + nframes) << "\n";
135  }
136  }
137 
138  } else {
139  _buffer->silence (nframes);
140  }
141 
142  } else {
143  _buffer->silence (nframes);
144  }
145 
146  if (nframes) {
147  _has_been_mixed_down = true;
148  }
149 
150  return *_buffer;
151 }
152 
153 void
155 {
156  _has_been_mixed_down = false;
157 }
158 
159 void
161 {
162  _has_been_mixed_down = false;
163 }
164 
165 void
167 {
168  for (uint8_t channel = 0; channel <= 0xF; channel++) {
169 
170  uint8_t ev[3] = { ((uint8_t) (MIDI_CMD_CONTROL | channel)), MIDI_CTL_SUSTAIN, 0 };
171 
172  /* we need to send all notes off AND turn the
173  * sustain/damper pedal off to handle synths
174  * that prioritize sustain over AllNotesOff
175  */
176 
177  if (port_engine.midi_event_put (port_buffer, when, ev, 3) != 0) {
178  cerr << "failed to deliver sustain-zero on channel " << (int)channel << " on port " << name() << endl;
179  }
180 
181  ev[1] = MIDI_CTL_ALL_NOTES_OFF;
182 
183  if (port_engine.midi_event_put (port_buffer, 0, ev, 3) != 0) {
184  cerr << "failed to deliver ALL NOTES OFF on channel " << (int)channel << " on port " << name() << endl;
185  }
186  }
187 }
188 
189 void
191 {
192  if (sends_output ()) {
193 
194  void* port_buffer = 0;
195 
196  if (_resolve_required) {
197  port_buffer = port_engine.get_buffer (_port_handle, nframes);
198  /* resolve all notes at the start of the buffer */
199  resolve_notes (port_buffer, 0);
200  _resolve_required = false;
201  }
202 
203  if (_buffer->empty()) {
204  return;
205  }
206 
207  if (!port_buffer) {
208  port_buffer = port_engine.get_buffer (_port_handle, nframes);
209  }
210 
211 
212  for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) {
213 
214  const Evoral::MIDIEvent<MidiBuffer::TimeType> ev (*i, false);
215 
216 
217  if (sends_output() && _trace_on) {
218  uint8_t const * const buf = ev.buffer();
220 
221  _self_parser.set_timestamp (now + ev.time());
222 
223  uint32_t limit = ev.size();
224 
225  for (size_t n = 0; n < limit; ++n) {
226  _self_parser.scanner (buf[n]);
227  }
228  }
229 
230 
231  // event times are in frames, relative to cycle start
232 
233 #ifndef NDEBUG
235  DEBUG_STR_DECL(a);
236  DEBUG_STR_APPEND(a, string_compose ("MidiPort %1 pop event @ %2 sz %3 ", _buffer, ev.time(), ev.size()));
237  for (size_t i=0; i < ev.size(); ++i) {
238  DEBUG_STR_APPEND(a,hex);
239  DEBUG_STR_APPEND(a,"0x");
240  DEBUG_STR_APPEND(a,(int)(ev.buffer()[i]));
241  DEBUG_STR_APPEND(a,' ');
242  }
243  DEBUG_STR_APPEND(a,'\n');
244  DEBUG_TRACE (DEBUG::MidiIO, DEBUG_STR(a).str());
245  }
246 #endif
247 
248  assert (ev.time() < (nframes + _global_port_buffer_offset + _port_buffer_offset));
249 
251  if (port_engine.midi_event_put (port_buffer, (pframes_t) ev.time(), ev.buffer(), ev.size()) != 0) {
252  cerr << "write failed, drop flushed note off on the floor, time "
253  << ev.time() << " > " << _global_port_buffer_offset + _port_buffer_offset << endl;
254  }
255  } else {
256  cerr << "drop flushed event on the floor, time " << ev.time()
257  << " too early for " << _global_port_buffer_offset
258  << " + " << _port_buffer_offset;
259  for (size_t xx = 0; xx < ev.size(); ++xx) {
260  cerr << ' ' << hex << (int) ev.buffer()[xx];
261  }
262  cerr << dec << endl;
263  }
264  }
265 
266  /* done.. the data has moved to the port buffer, mark it so
267  */
268 
269  _buffer->clear ();
270  }
271 }
272 
273 void
275 {
276  _resolve_required = true;
277 }
278 
279 void
281 {
282  _resolve_required = true;
283 }
284 
285 void
287 {
288  _resolve_required = true;
289 }
290 
291 void
293 {
294  Port::reset ();
295  delete _buffer;
296  cerr << name() << " new MIDI buffer of size " << AudioEngine::instance()->raw_buffer_size (DataType::MIDI) << endl;
297  _buffer = new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI));
298 }
299 
300 void
302 {
303  _input_active = yn;
304 }
305 
306 void
308 {
309  _always_parse = yn;
310 }
311 
312 void
314 {
315  _trace_on = yn;
316 }
void resolve_notes(void *buffer, framepos_t when)
Definition: midi_port.cc:166
void flush_buffers(pframes_t nframes)
Definition: midi_port.cc:190
bool _always_parse
Definition: midi_port.h:73
bool empty() const
Definition: midi_buffer.h:56
void cycle_end(pframes_t nframes)
Definition: midi_port.cc:154
MIDI::Parser _self_parser
Definition: midi_port.h:87
bool sends_output() const
Definition: port.h:74
bool _has_been_mixed_down
Definition: midi_port.h:70
LIBARDOUR_API uint64_t MidiIO
Definition: debug.cc:44
void silence(framecnt_t nframes, framecnt_t offset=0)
Definition: midi_buffer.cc:290
uint32_t pframes_t
Definition: types.h:61
Definition: Beats.hpp:239
std::string name() const
Definition: port.h:54
framepos_t TimeType
Definition: midi_buffer.h:38
MidiBuffer * _buffer
Definition: midi_port.h:69
static AudioEngine * instance()
Definition: audioengine.h:196
virtual void reset()
Definition: port.cc:277
framecnt_t _port_buffer_offset
Definition: port.h:156
void cycle_split()
Definition: midi_port.cc:160
#define MIDI_CMD_CONTROL
Definition: midi_events.h:110
bool _resolve_required
Definition: midi_port.h:71
void set_input_active(bool yn)
Definition: midi_port.cc:301
uint32_t size() const
Definition: Event.hpp:134
Definition: amp.h:29
#define MIDI_CTL_SUSTAIN
Definition: midi_events.h:65
virtual void cycle_start(pframes_t)
Definition: port.cc:283
Time time() const
Definition: Event.hpp:132
PortFlags
Definition: types.h:610
framepos_t sample_time_at_cycle_start()
void realtime_locate()
Definition: midi_port.cc:286
PortEngine::PortHandle _port_handle
Definition: port.h:150
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
int64_t framepos_t
Definition: types.h:66
MidiBuffer & get_midi_buffer(pframes_t nframes)
Definition: midi_port.cc:92
size_t raw_buffer_size(DataType t)
Buffer & get_buffer(pframes_t nframes)
Definition: midi_port.cc:86
LIBPBD_API uint64_t debug_bits
Definition: debug.cc:55
const char * name
bool receives_input() const
Definition: port.h:69
#define DEBUG_STR_APPEND(id, s)
Definition: debug.h:58
bool push_back(const Evoral::MIDIEvent< TimeType > &event)
Definition: midi_buffer.cc:136
#define port_engine
Definition: midi_port.cc:35
virtual void clear()
Definition: buffer.h:70
void set_trace_on(bool yn)
Definition: midi_port.cc:313
Definition: debug.h:30
void set_always_parse(bool yn)
Definition: midi_port.cc:307
static pframes_t _global_port_buffer_offset
Definition: port.h:153
iterator begin()
Definition: midi_buffer.h:127
const uint8_t * buffer() const
Definition: Event.hpp:135
#define DEBUG_STR(id)
Definition: debug.h:57
#define DEBUG_STR_DECL(id)
Definition: debug.h:56
#define MIDI_CTL_ALL_NOTES_OFF
Definition: midi_events.h:100
void require_resolve()
Definition: midi_port.cc:274
bool _input_active
Definition: midi_port.h:72
void cycle_start(pframes_t nframes)
Definition: midi_port.cc:54
Definition: ardour.h:41
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
void transport_stopped()
Definition: midi_port.cc:280