summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2015-03-10 22:05:21 +0100
committerRobin Gareus <robin@gareus.org>2015-03-10 22:15:44 +0100
commit7619946b4b804416a08b11d168e5e71f77d0c1ac (patch)
tree8b920a3336cf9a6db960625f6ab385834eba8a24 /libs
parent3139b7e9804496395beb787622d5de90266b8e4a (diff)
MIDI vari-speed playback
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/interpolation.h7
-rw-r--r--libs/ardour/ardour/midi_diskstream.h3
-rw-r--r--libs/ardour/interpolation.cc36
-rw-r--r--libs/ardour/midi_diskstream.cc37
4 files changed, 60 insertions, 23 deletions
diff --git a/libs/ardour/ardour/interpolation.h b/libs/ardour/ardour/interpolation.h
index 64b0431e0f..3c661d8592 100644
--- a/libs/ardour/ardour/interpolation.h
+++ b/libs/ardour/ardour/interpolation.h
@@ -68,6 +68,13 @@ public:
framecnt_t interpolate (int channel, framecnt_t nframes, Sample* input, Sample* output);
};
+class BufferSet;
+
+class LIBARDOUR_API CubicMidiInterpolation : public Interpolation {
+public:
+ framecnt_t distance (framecnt_t nframes, bool roll = true);
+};
+
} // namespace ARDOUR
#endif
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h
index 7e72ef9a7e..742b327b36 100644
--- a/libs/ardour/ardour/midi_diskstream.h
+++ b/libs/ardour/ardour/midi_diskstream.h
@@ -38,6 +38,7 @@
#include "ardour/diskstream.h"
#include "ardour/midi_buffer.h"
#include "ardour/utils.h"
+#include "ardour/interpolation.h"
struct tm;
@@ -186,6 +187,8 @@ class LIBARDOUR_API MidiDiskstream : public Diskstream
*/
MidiBuffer _gui_feed_buffer;
mutable Glib::Threads::Mutex _gui_feed_buffer_mutex;
+
+ CubicMidiInterpolation interpolation;
};
}; /* namespace ARDOUR */
diff --git a/libs/ardour/interpolation.cc b/libs/ardour/interpolation.cc
index bccaa45553..79b43bc58e 100644
--- a/libs/ardour/interpolation.cc
+++ b/libs/ardour/interpolation.cc
@@ -21,6 +21,7 @@
#include <cstdio>
#include "ardour/interpolation.h"
+#include "ardour/midi_buffer.h"
using namespace ARDOUR;
@@ -150,3 +151,38 @@ CubicInterpolation::interpolate (int channel, framecnt_t nframes, Sample *input,
return i;
}
+
+framecnt_t
+CubicMidiInterpolation::distance (framecnt_t nframes, bool roll)
+{
+ assert(phase.size() == 1);
+
+ framecnt_t i = 0;
+
+ double acceleration;
+ double distance = 0.0;
+
+ if (nframes < 3) {
+ return nframes;
+ }
+
+ if (_speed != _target_speed) {
+ acceleration = _target_speed - _speed;
+ } else {
+ acceleration = 0.0;
+ }
+
+ distance = phase[0];
+
+ for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
+ distance += _speed + acceleration;
+ }
+
+ if (roll) {
+ phase[0] = distance - floor(distance);
+ }
+
+ i = floor(distance);
+
+ return i;
+}
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index ae0828a3a4..f19c88d3b3 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -135,6 +135,7 @@ MidiDiskstream::init ()
_capture_buf = new MidiRingBuffer<framepos_t>(size);
_n_channels = ChanCount(DataType::MIDI, 1);
+ interpolation.add_channel_to (0,0);
}
MidiDiskstream::~MidiDiskstream ()
@@ -522,44 +523,35 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
playback_distance = nframes;
- } else {
-
- /* XXX: should be doing varispeed stuff here, similar to the code in AudioDiskstream::process */
+ } else if (_actual_speed != 1.0f && _target_speed > 0) {
- playback_distance = nframes;
+ interpolation.set_speed (_target_speed);
-#ifndef NO_SIMPLE_MIDI_VARISPEED
- if (_target_speed > 0) {
- playback_distance = nframes * _target_speed;
- }
-#endif
+ playback_distance = interpolation.distance (nframes);
+ } else {
+ playback_distance = nframes;
}
if (need_disk_signal) {
/* copy the diskstream data to all output buffers */
MidiBuffer& mbuf (bufs.get_midi (0));
-#ifndef NO_SIMPLE_MIDI_VARISPEED
- get_playback (mbuf, nframes * _target_speed);
-#else
- get_playback (mbuf, nframes);
-#endif
+ get_playback (mbuf, playback_distance);
/* leave the audio count alone */
ChanCount cnt (DataType::MIDI, 1);
cnt.set (DataType::AUDIO, bufs.count().n_audio());
bufs.set_count (cnt);
-#ifndef NO_SIMPLE_MIDI_VARISPEED
- if (_target_speed > 0 && playback_distance != nframes) {
+ /* vari-speed */
+ if (_target_speed > 0 && _actual_speed != 1.0f) {
MidiBuffer& mbuf (bufs.get_midi (0));
for (MidiBuffer::iterator i = mbuf.begin(); i != mbuf.end(); ++i) {
MidiBuffer::TimeType *tme = i.timeptr();
- *tme = (*tme) / _target_speed;
+ *tme = (*tme) * nframes / playback_distance;
}
}
-#endif
}
return 0;
@@ -568,14 +560,13 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
frameoffset_t
MidiDiskstream::calculate_playback_distance (pframes_t nframes)
{
-#ifndef NO_SIMPLE_MIDI_VARISPEED
- frameoffset_t playback_distance = nframes * _target_speed;
-#else
frameoffset_t playback_distance = nframes;
- /* XXX: should be doing varispeed stuff once it's implemented in ::process() above */
+ if (!record_enabled() && _actual_speed != 1.0f && _actual_speed > 0.f) {
+ interpolation.set_speed (_target_speed);
+ playback_distance = interpolation.distance (nframes, false);
+ }
-#endif
if (_actual_speed < 0.0) {
return -playback_distance;
} else {