mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-13 10:06:33 +01:00
MIDI vari-speed playback
This commit is contained in:
parent
3139b7e980
commit
7619946b4b
4 changed files with 61 additions and 24 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 if (_actual_speed != 1.0f && _target_speed > 0) {
|
||||
|
||||
interpolation.set_speed (_target_speed);
|
||||
|
||||
playback_distance = interpolation.distance (nframes);
|
||||
|
||||
} else {
|
||||
|
||||
/* XXX: should be doing varispeed stuff here, similar to the code in AudioDiskstream::process */
|
||||
|
||||
playback_distance = nframes;
|
||||
|
||||
#ifndef NO_SIMPLE_MIDI_VARISPEED
|
||||
if (_target_speed > 0) {
|
||||
playback_distance = nframes * _target_speed;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue