2 Copyright (C) 2006 Paul Davis
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.
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.
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.
22 #include "ardour/midi_port.h"
23 #include "ardour/data_type.h"
24 #include "ardour/audioengine.h"
26 using namespace ARDOUR
;
29 MidiPort::MidiPort (const std::string
& name
, Flags flags
)
30 : Port (name
, DataType::MIDI
, flags
)
31 , _has_been_mixed_down (false)
32 , _resolve_required (false)
33 , _input_active (true)
35 _buffer
= new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI
));
44 MidiPort::cycle_start (pframes_t nframes
)
46 Port::cycle_start (nframes
);
50 assert (_buffer
->size () == 0);
52 if (sends_output ()) {
53 jack_midi_clear_buffer (jack_port_get_buffer (_jack_port
, nframes
));
58 MidiPort::get_midi_buffer (pframes_t nframes
)
60 if (_has_been_mixed_down
) {
64 if (receives_input ()) {
68 void* jack_buffer
= jack_port_get_buffer (_jack_port
, nframes
);
69 const pframes_t event_count
= jack_midi_get_event_count (jack_buffer
);
71 assert (event_count
< _buffer
->capacity());
73 /* suck all relevant MIDI events from the JACK MIDI port buffer
77 for (pframes_t i
= 0; i
< event_count
; ++i
) {
81 jack_midi_event_get (&ev
, jack_buffer
, i
);
83 if (ev
.buffer
[0] == 0xfe) {
84 /* throw away active sensing */
88 /* check that the event is in the acceptable time range */
90 if ((ev
.time
>= (_global_port_buffer_offset
+ _port_buffer_offset
)) &&
91 (ev
.time
< (_global_port_buffer_offset
+ _port_buffer_offset
+ nframes
))) {
92 _buffer
->push_back (ev
);
94 cerr
<< "Dropping incoming MIDI at time " << ev
.time
<< "; offset="
95 << _global_port_buffer_offset
<< " limit="
96 << (_global_port_buffer_offset
+ _port_buffer_offset
+ nframes
) << "\n";
101 _buffer
->silence (nframes
);
105 _buffer
->silence (nframes
);
109 _has_been_mixed_down
= true;
117 MidiPort::cycle_end (pframes_t
/*nframes*/)
119 _has_been_mixed_down
= false;
123 MidiPort::cycle_split ()
125 _has_been_mixed_down
= false;
129 MidiPort::resolve_notes (void* jack_buffer
, MidiBuffer::TimeType when
)
135 for (uint8_t channel
= 0; channel
<= 0xF; channel
++) {
136 ev
[0] = (MIDI_CMD_CONTROL
| channel
);
138 /* we need to send all notes off AND turn the
139 * sustain/damper pedal off to handle synths
140 * that prioritize sustain over AllNotesOff
143 ev
[1] = MIDI_CTL_SUSTAIN
;
145 if (jack_midi_event_write (jack_buffer
, when
, ev
, 3) != 0) {
146 cerr
<< "failed to deliver sustain-zero on channel " << channel
<< " on port " << name() << endl
;
149 ev
[1] = MIDI_CTL_ALL_NOTES_OFF
;
151 if (jack_midi_event_write (jack_buffer
, 0, ev
, 3) != 0) {
152 cerr
<< "failed to deliver ALL NOTES OFF on channel " << channel
<< " on port " << name() << endl
;
158 MidiPort::flush_buffers (pframes_t nframes
, framepos_t time
)
160 if (sends_output ()) {
162 void* jack_buffer
= jack_port_get_buffer (_jack_port
, nframes
);
164 if (_resolve_required
) {
165 /* resolve all notes at the start of the buffer */
166 resolve_notes (jack_buffer
, 0);
167 _resolve_required
= false;
170 for (MidiBuffer::iterator i
= _buffer
->begin(); i
!= _buffer
->end(); ++i
) {
172 const Evoral::MIDIEvent
<MidiBuffer::TimeType
> ev (*i
, false);
174 // event times are in frames, relative to cycle start
176 assert (ev
.time() < (nframes
+ _global_port_buffer_offset
+ _port_buffer_offset
));
178 if (ev
.event_type() == LoopEventType
) {
179 resolve_notes (jack_buffer
, ev
.time());
183 if (ev
.time() >= _global_port_buffer_offset
+ _port_buffer_offset
) {
184 if (jack_midi_event_write (jack_buffer
, (jack_nframes_t
) ev
.time(), ev
.buffer(), ev
.size()) != 0) {
185 cerr
<< "write failed, drop flushed note off on the floor, time "
186 << ev
.time() << " > " << _global_port_buffer_offset
+ _port_buffer_offset
<< endl
;
189 cerr
<< "drop flushed event on the floor, time " << ev
.time()
190 << " < " << _global_port_buffer_offset
+ _port_buffer_offset
<< endl
;
197 MidiPort::transport_stopped ()
199 _resolve_required
= true;
203 MidiPort::realtime_locate ()
205 _resolve_required
= true;
213 _buffer
= new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI
));
217 MidiPort::set_input_active (bool yn
)