MIDI vari-speed playback

This commit is contained in:
Robin Gareus 2015-03-10 22:05:21 +01:00
parent 3139b7e980
commit 7619946b4b
4 changed files with 61 additions and 24 deletions

View file

@ -68,6 +68,13 @@ public:
framecnt_t interpolate (int channel, framecnt_t nframes, Sample* input, Sample* output); 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 } // namespace ARDOUR
#endif #endif

View file

@ -38,6 +38,7 @@
#include "ardour/diskstream.h" #include "ardour/diskstream.h"
#include "ardour/midi_buffer.h" #include "ardour/midi_buffer.h"
#include "ardour/utils.h" #include "ardour/utils.h"
#include "ardour/interpolation.h"
struct tm; struct tm;
@ -186,6 +187,8 @@ class LIBARDOUR_API MidiDiskstream : public Diskstream
*/ */
MidiBuffer _gui_feed_buffer; MidiBuffer _gui_feed_buffer;
mutable Glib::Threads::Mutex _gui_feed_buffer_mutex; mutable Glib::Threads::Mutex _gui_feed_buffer_mutex;
CubicMidiInterpolation interpolation;
}; };
}; /* namespace ARDOUR */ }; /* namespace ARDOUR */

View file

@ -21,6 +21,7 @@
#include <cstdio> #include <cstdio>
#include "ardour/interpolation.h" #include "ardour/interpolation.h"
#include "ardour/midi_buffer.h"
using namespace ARDOUR; using namespace ARDOUR;
@ -150,3 +151,38 @@ CubicInterpolation::interpolate (int channel, framecnt_t nframes, Sample *input,
return i; 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;
}

View file

@ -135,6 +135,7 @@ MidiDiskstream::init ()
_capture_buf = new MidiRingBuffer<framepos_t>(size); _capture_buf = new MidiRingBuffer<framepos_t>(size);
_n_channels = ChanCount(DataType::MIDI, 1); _n_channels = ChanCount(DataType::MIDI, 1);
interpolation.add_channel_to (0,0);
} }
MidiDiskstream::~MidiDiskstream () MidiDiskstream::~MidiDiskstream ()
@ -522,44 +523,35 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
playback_distance = nframes; playback_distance = nframes;
} else if (_actual_speed != 1.0f && _target_speed > 0) {
interpolation.set_speed (_target_speed);
playback_distance = interpolation.distance (nframes);
} else { } else {
/* XXX: should be doing varispeed stuff here, similar to the code in AudioDiskstream::process */
playback_distance = nframes; playback_distance = nframes;
#ifndef NO_SIMPLE_MIDI_VARISPEED
if (_target_speed > 0) {
playback_distance = nframes * _target_speed;
}
#endif
} }
if (need_disk_signal) { if (need_disk_signal) {
/* copy the diskstream data to all output buffers */ /* copy the diskstream data to all output buffers */
MidiBuffer& mbuf (bufs.get_midi (0)); MidiBuffer& mbuf (bufs.get_midi (0));
#ifndef NO_SIMPLE_MIDI_VARISPEED get_playback (mbuf, playback_distance);
get_playback (mbuf, nframes * _target_speed);
#else
get_playback (mbuf, nframes);
#endif
/* leave the audio count alone */ /* leave the audio count alone */
ChanCount cnt (DataType::MIDI, 1); ChanCount cnt (DataType::MIDI, 1);
cnt.set (DataType::AUDIO, bufs.count().n_audio()); cnt.set (DataType::AUDIO, bufs.count().n_audio());
bufs.set_count (cnt); bufs.set_count (cnt);
#ifndef NO_SIMPLE_MIDI_VARISPEED /* vari-speed */
if (_target_speed > 0 && playback_distance != nframes) { if (_target_speed > 0 && _actual_speed != 1.0f) {
MidiBuffer& mbuf (bufs.get_midi (0)); MidiBuffer& mbuf (bufs.get_midi (0));
for (MidiBuffer::iterator i = mbuf.begin(); i != mbuf.end(); ++i) { for (MidiBuffer::iterator i = mbuf.begin(); i != mbuf.end(); ++i) {
MidiBuffer::TimeType *tme = i.timeptr(); MidiBuffer::TimeType *tme = i.timeptr();
*tme = (*tme) / _target_speed; *tme = (*tme) * nframes / playback_distance;
} }
} }
#endif
} }
return 0; return 0;
@ -568,14 +560,13 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
frameoffset_t frameoffset_t
MidiDiskstream::calculate_playback_distance (pframes_t nframes) 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; 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) { if (_actual_speed < 0.0) {
return -playback_distance; return -playback_distance;
} else { } else {