diff options
author | Robin Gareus <robin@gareus.org> | 2015-03-10 22:05:21 +0100 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2015-03-10 22:15:44 +0100 |
commit | 7619946b4b804416a08b11d168e5e71f77d0c1ac (patch) | |
tree | 8b920a3336cf9a6db960625f6ab385834eba8a24 | |
parent | 3139b7e9804496395beb787622d5de90266b8e4a (diff) |
MIDI vari-speed playback
-rw-r--r-- | libs/ardour/ardour/interpolation.h | 7 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_diskstream.h | 3 | ||||
-rw-r--r-- | libs/ardour/interpolation.cc | 36 | ||||
-rw-r--r-- | libs/ardour/midi_diskstream.cc | 37 |
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 { |