summaryrefslogtreecommitdiff
path: root/libs/ardour/midi_port.cc
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2017-10-29 18:30:18 +0100
committerRobin Gareus <robin@gareus.org>2017-10-29 20:04:00 +0100
commit927788a0b0bf6a621e7cee60365f4e8cbd67d829 (patch)
tree43ebe89319b4b9416391f2f195dbc4f8effad161 /libs/ardour/midi_port.cc
parent7fb3c3e137d7a96998f21a4ec275339b4bc08c1a (diff)
Move vari-speed into backend (resample ports)
Previously Ardour used a /local/ per track vari-speed mechanism. Now that the disk-reader is a latency-compensated processor, the speed of each disk-reader would need to be maintained locally, offset by each disk-reader's output latency. Furthermore each disk-reader may produce a different number of samples, depending on its global alignment. This commit introduces port-data resampling directly at the engine-level: Up/down-sample all input ports at the beginning, and down/up-sample output port-data using the inverse ratio at the end of the session's process cycle. The session itself is unaware of the speed-change, and only needs to handle transport speeds {-1, 0, +1}. This also allows for aligned cue-monitoring and vari-speed recording, and also pitch-shifts synthesized MIDI along.
Diffstat (limited to 'libs/ardour/midi_port.cc')
-rw-r--r--libs/ardour/midi_port.cc19
1 files changed, 16 insertions, 3 deletions
diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc
index a6553b7fb6..24dc994535 100644
--- a/libs/ardour/midi_port.cc
+++ b/libs/ardour/midi_port.cc
@@ -138,9 +138,15 @@ MidiPort::get_midi_buffer (pframes_t nframes)
continue;
}
+ timestamp = floor (timestamp * _speed_ratio);
+
/* check that the event is in the acceptable time range */
if ((timestamp < (_global_port_buffer_offset + _port_buffer_offset)) ||
(timestamp >= (_global_port_buffer_offset + _port_buffer_offset + nframes))) {
+ // XXX this is normal after a split cycles:
+ // The engine buffer contains the data for the complete cycle, but
+ // only the part after _global_port_buffer_offset is needed.
+#ifndef NDEBUG
cerr << "Dropping incoming MIDI at time " << timestamp << "; offset="
<< _global_port_buffer_offset << " limit="
<< (_global_port_buffer_offset + _port_buffer_offset + nframes)
@@ -148,9 +154,14 @@ MidiPort::get_midi_buffer (pframes_t nframes)
<< " + " << _port_buffer_offset
<< " + " << nframes
<< ")\n";
+#endif
continue;
}
+ /* adjust timestamp to match current cycle */
+ timestamp -= _global_port_buffer_offset + _port_buffer_offset;
+ assert (timestamp >= 0 && timestamp < nframes);
+
if ((buf[0] & 0xF0) == 0x90 && buf[2] == 0) {
/* normalize note on with velocity 0 to proper note off */
uint8_t ev[3];
@@ -196,19 +207,20 @@ MidiPort::resolve_notes (void* port_buffer, MidiBuffer::TimeType when)
for (uint8_t channel = 0; channel <= 0xF; channel++) {
uint8_t ev[3] = { ((uint8_t) (MIDI_CMD_CONTROL | channel)), MIDI_CTL_SUSTAIN, 0 };
+ pframes_t tme = floor (when / _speed_ratio);
/* we need to send all notes off AND turn the
* sustain/damper pedal off to handle synths
* that prioritize sustain over AllNotesOff
*/
- if (port_engine.midi_event_put (port_buffer, when, ev, 3) != 0) {
+ if (port_engine.midi_event_put (port_buffer, tme, ev, 3) != 0) {
cerr << "failed to deliver sustain-zero on channel " << (int)channel << " on port " << name() << endl;
}
ev[1] = MIDI_CTL_ALL_NOTES_OFF;
- if (port_engine.midi_event_put (port_buffer, when, ev, 3) != 0) {
+ if (port_engine.midi_event_put (port_buffer, tme, ev, 3) != 0) {
cerr << "failed to deliver ALL NOTES OFF on channel " << (int)channel << " on port " << name() << endl;
}
}
@@ -279,7 +291,8 @@ MidiPort::flush_buffers (pframes_t nframes)
assert (ev.time() < (nframes + _global_port_buffer_offset));
if (ev.time() >= _global_port_buffer_offset) {
- if (port_engine.midi_event_put (port_buffer, (pframes_t) ev.time() + _port_buffer_offset, ev.buffer(), ev.size()) != 0) {
+ pframes_t tme = floor ((ev.time() + _port_buffer_offset) / _speed_ratio);
+ if (port_engine.midi_event_put (port_buffer, tme, ev.buffer(), ev.size()) != 0) {
cerr << "write failed, dropped event, time "
<< ev.time() << " + " << _port_buffer_offset
<< " > " << _global_port_buffer_offset << endl;