mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-23 05:37:22 +01:00
Interpolation: First working but buggy version using libsamplerate
git-svn-id: svn://localhost/ardour2/branches/3.0@5255 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
def335e427
commit
f42f577bed
9 changed files with 139 additions and 90 deletions
|
|
@ -146,7 +146,7 @@ class AudioDiskstream : public Diskstream
|
|||
}
|
||||
}
|
||||
|
||||
LinearInterpolation interpolation;
|
||||
Interpolation interpolation;
|
||||
|
||||
XMLNode* deprecated_io_node;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
#include <math.h>
|
||||
#include <samplerate.h>
|
||||
|
||||
#include "ardour/types.h"
|
||||
|
||||
#ifndef __interpolation_h__
|
||||
|
|
@ -8,26 +10,29 @@ namespace ARDOUR {
|
|||
|
||||
class Interpolation {
|
||||
protected:
|
||||
double _speed, _target_speed;
|
||||
|
||||
double _speed;
|
||||
|
||||
SRC_STATE* state;
|
||||
std::vector<SRC_DATA> data;
|
||||
|
||||
int error;
|
||||
|
||||
void reset_state ();
|
||||
|
||||
public:
|
||||
Interpolation () : _speed(0.0L) {}
|
||||
Interpolation ();
|
||||
~Interpolation ();
|
||||
|
||||
void set_speed (double new_speed) { _speed = new_speed; }
|
||||
void set_target_speed (double new_speed) { _target_speed = new_speed; }
|
||||
|
||||
double target_speed() const { return _target_speed; }
|
||||
double speed() const { return _speed; }
|
||||
void set_speed (double new_speed);
|
||||
void set_target_speed (double new_speed) {}
|
||||
double speed () const { return _speed; }
|
||||
|
||||
void add_channel_to (int input_buffer_size, int output_buffer_size);
|
||||
void remove_channel_from ();
|
||||
|
||||
virtual nframes_t interpolate (nframes_t nframes, Sample* input, Sample* output) = 0;
|
||||
};
|
||||
|
||||
class LinearInterpolation : public Interpolation {
|
||||
public:
|
||||
nframes_t interpolate (nframes_t nframes, Sample* input, Sample* output);
|
||||
nframes_t interpolate (int channel, nframes_t nframes, Sample* input, Sample* output);
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1006,11 +1006,13 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
|
|||
Location* start_location;
|
||||
Slave* _slave;
|
||||
bool _silent;
|
||||
|
||||
// varispeed playback
|
||||
volatile double _transport_speed;
|
||||
double _last_transport_speed;
|
||||
// varispeed playback
|
||||
double _target_transport_speed;
|
||||
LinearInterpolation interpolation;
|
||||
Interpolation interpolation;
|
||||
|
||||
bool auto_play_legal;
|
||||
nframes_t _last_slave_transport_frame;
|
||||
nframes_t maximum_output_latency;
|
||||
|
|
|
|||
|
|
@ -821,11 +821,12 @@ AudioDiskstream::process_varispeed_playback(nframes_t nframes, boost::shared_ptr
|
|||
interpolation.set_target_speed (_target_speed);
|
||||
interpolation.set_speed (_speed);
|
||||
|
||||
for (chan = c->begin(); chan != c->end(); ++chan) {
|
||||
int channel = 0;
|
||||
for (chan = c->begin(); chan != c->end(); ++chan, ++channel) {
|
||||
ChannelInfo* chaninfo (*chan);
|
||||
|
||||
playback_distance = interpolation.interpolate (
|
||||
nframes, chaninfo->current_playback_buffer, chaninfo->speed_buffer);
|
||||
channel, nframes, chaninfo->current_playback_buffer, chaninfo->speed_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2204,12 +2205,14 @@ AudioDiskstream::set_align_style_from_io ()
|
|||
int
|
||||
AudioDiskstream::add_channel_to (boost::shared_ptr<ChannelList> c, uint32_t how_many)
|
||||
{
|
||||
|
||||
while (how_many--) {
|
||||
c->push_back (new ChannelInfo(_session.audio_diskstream_buffer_size(), speed_buffer_size, wrap_buffer_size));
|
||||
interpolation.add_channel_to (_session.audio_diskstream_buffer_size(), speed_buffer_size);
|
||||
}
|
||||
|
||||
_n_channels.set(DataType::AUDIO, c->size());
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2226,8 +2229,11 @@ int
|
|||
AudioDiskstream::remove_channel_from (boost::shared_ptr<ChannelList> c, uint32_t how_many)
|
||||
{
|
||||
while (how_many-- && !c->empty()) {
|
||||
//delete c->back(); // FIXME: crash (thread safe with RCU?)
|
||||
// FIXME: crash (thread safe with RCU?)
|
||||
// memory leak, when disabled.... :(
|
||||
//delete c->back();
|
||||
c->pop_back();
|
||||
interpolation.remove_channel_from ();
|
||||
}
|
||||
|
||||
_n_channels.set(DataType::AUDIO, c->size());
|
||||
|
|
|
|||
|
|
@ -1,41 +1,76 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "ardour/interpolation.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
|
||||
nframes_t
|
||||
LinearInterpolation::interpolate (nframes_t nframes, Sample *input, Sample *output)
|
||||
Interpolation::Interpolation() : _speed (1.0L), state (0)
|
||||
{
|
||||
// the idea is that when the speed is not 1.0, we have to
|
||||
// interpolate between samples and then we have to store where we thought we were.
|
||||
// rather than being at sample N or N+1, we were at N+0.8792922
|
||||
|
||||
// index in the input buffers
|
||||
nframes_t i = 0;
|
||||
|
||||
double acceleration;
|
||||
double distance = 0.0;
|
||||
|
||||
if (_speed != _target_speed) {
|
||||
acceleration = _target_speed - _speed;
|
||||
}
|
||||
|
||||
Interpolation::~Interpolation()
|
||||
{
|
||||
state = src_delete (state);
|
||||
}
|
||||
|
||||
void
|
||||
Interpolation::set_speed (double new_speed)
|
||||
{
|
||||
_speed = new_speed;
|
||||
src_set_ratio (state, 1.0/_speed);
|
||||
}
|
||||
|
||||
void
|
||||
Interpolation::reset_state ()
|
||||
{
|
||||
if (state) {
|
||||
src_reset (state);
|
||||
} else {
|
||||
acceleration = 0.0;
|
||||
state = src_new (SRC_LINEAR, 1, &error);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Interpolation::add_channel_to (int input_buffer_size, int output_buffer_size)
|
||||
{
|
||||
SRC_DATA newdata;
|
||||
|
||||
/* Set up sample rate converter info. */
|
||||
newdata.end_of_input = 0 ;
|
||||
|
||||
newdata.input_frames = input_buffer_size;
|
||||
newdata.output_frames = output_buffer_size;
|
||||
|
||||
newdata.input_frames_used = 0 ;
|
||||
newdata.output_frames_gen = 0 ;
|
||||
|
||||
newdata.src_ratio = 1.0/_speed;
|
||||
|
||||
data.push_back (newdata);
|
||||
|
||||
reset_state ();
|
||||
}
|
||||
|
||||
void
|
||||
Interpolation::remove_channel_from ()
|
||||
{
|
||||
data.pop_back ();
|
||||
reset_state ();
|
||||
}
|
||||
|
||||
nframes_t
|
||||
Interpolation::interpolate (int channel, nframes_t nframes, Sample *input, Sample *output)
|
||||
{
|
||||
data[channel].data_in = input;
|
||||
data[channel].data_out = output;
|
||||
|
||||
data[channel].output_frames = nframes;
|
||||
data[channel].src_ratio = 1.0/_speed;
|
||||
|
||||
if ((error = src_process (state, &data[channel]))) {
|
||||
printf ("\nError : %s\n\n", src_strerror (error));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
for (nframes_t outsample = 0; outsample < nframes; ++outsample) {
|
||||
i = distance;
|
||||
Sample fractional_phase_part = distance - i;
|
||||
|
||||
if (input && output) {
|
||||
// Linearly interpolate into the output buffer
|
||||
output[outsample] =
|
||||
input[i] * (1.0f - fractional_phase_part) +
|
||||
input[i+1] * fractional_phase_part;
|
||||
}
|
||||
distance += _speed + acceleration;
|
||||
}
|
||||
|
||||
i = (distance + 0.5L);
|
||||
// playback distance
|
||||
return i;
|
||||
return data[channel].input_frames_used;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -327,7 +327,8 @@ Session::process_with_events (nframes_t nframes)
|
|||
} else {
|
||||
interpolation.set_target_speed (_target_transport_speed);
|
||||
interpolation.set_speed (_transport_speed);
|
||||
frames_moved = (long) interpolation.interpolate (nframes, 0, 0);
|
||||
//FIXME frames_moved = (long) interpolation.interpolate (nframes, 0, 0);
|
||||
frames_moved = _transport_speed * nframes;
|
||||
}
|
||||
|
||||
end_frame = _transport_frame + (nframes_t)frames_moved;
|
||||
|
|
@ -848,7 +849,8 @@ Session::process_without_events (nframes_t nframes)
|
|||
} else {
|
||||
interpolation.set_target_speed (_target_transport_speed);
|
||||
interpolation.set_speed (_transport_speed);
|
||||
frames_moved = (long) interpolation.interpolate (nframes, 0, 0);
|
||||
//FIXME frames_moved = (long) interpolation.interpolate (nframes, 0, 0);
|
||||
frames_moved = _transport_speed * nframes;
|
||||
}
|
||||
|
||||
if (process_routes (nframes)) {
|
||||
|
|
|
|||
|
|
@ -11,56 +11,54 @@ InterpolationTest::linearInterpolationTest ()
|
|||
{
|
||||
cout << "\nLinear Interpolation Test\n";
|
||||
cout << "\nSpeed: 1.0";
|
||||
linear.set_speed (1.0);
|
||||
linear.set_target_speed (linear.speed());
|
||||
nframes_t result = linear.interpolate (NUM_SAMPLES, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES * linear.speed()), result);
|
||||
interpolation.set_speed (1.0);
|
||||
nframes_t result = interpolation.interpolate (0, NUM_SAMPLES, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES * interpolation.speed()), result);
|
||||
/*
|
||||
*/
|
||||
for (int i=0; i < NUM_SAMPLES; ++i) {
|
||||
cout << "input[" << i << "] = " << input[i] << " output[" << i << "] = " << output[i] << endl;
|
||||
}
|
||||
for (int i = 0; i < NUM_SAMPLES; i += INTERVAL) {
|
||||
CPPUNIT_ASSERT_EQUAL (1.0f, output[i]);
|
||||
CPPUNIT_ASSERT_EQUAL (1.0f, output[i+1]);
|
||||
}
|
||||
|
||||
cout << "\nSpeed: 0.5";
|
||||
linear.set_speed (0.5);
|
||||
linear.set_target_speed (linear.speed());
|
||||
result = linear.interpolate (NUM_SAMPLES, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES * linear.speed()), result);
|
||||
for (int i = 0; i < NUM_SAMPLES; i += (INTERVAL / linear.speed() +0.5)) {
|
||||
interpolation.set_speed (0.5);
|
||||
result = interpolation.interpolate (0, NUM_SAMPLES, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES * interpolation.speed()), result);
|
||||
for (int i = 0; i < NUM_SAMPLES; i += (INTERVAL / interpolation.speed() +0.5)) {
|
||||
CPPUNIT_ASSERT_EQUAL (1.0f, output[i]);
|
||||
}
|
||||
|
||||
cout << "\nSpeed: 0.2";
|
||||
linear.set_speed (0.2);
|
||||
linear.set_target_speed (linear.speed());
|
||||
result = linear.interpolate (NUM_SAMPLES, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES * linear.speed()), result);
|
||||
interpolation.set_speed (0.2);
|
||||
result = interpolation.interpolate (0, NUM_SAMPLES, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES * interpolation.speed()), result);
|
||||
|
||||
cout << "\nSpeed: 0.02";
|
||||
linear.set_speed (0.02);
|
||||
linear.set_target_speed (linear.speed());
|
||||
result = linear.interpolate (NUM_SAMPLES, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES * linear.speed()), result);
|
||||
interpolation.set_speed (0.02);
|
||||
result = interpolation.interpolate (0, NUM_SAMPLES, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES * interpolation.speed()), result);
|
||||
|
||||
cout << "\nSpeed: 0.002";
|
||||
linear.set_speed (0.002);
|
||||
linear.set_target_speed (linear.speed());
|
||||
result = linear.interpolate (NUM_SAMPLES, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES * linear.speed()), result);
|
||||
interpolation.set_speed (0.002);
|
||||
result = interpolation.interpolate (0, NUM_SAMPLES, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES * interpolation.speed()), result);
|
||||
|
||||
cout << "\nSpeed: 2.0";
|
||||
linear.set_speed (2.0);
|
||||
linear.set_target_speed (linear.speed());
|
||||
result = linear.interpolate (NUM_SAMPLES / 2, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES / 2 * linear.speed()), result);
|
||||
for (int i = 0; i < NUM_SAMPLES / 2; i += (INTERVAL / linear.speed() +0.5)) {
|
||||
interpolation.set_speed (2.0);
|
||||
result = interpolation.interpolate (0, NUM_SAMPLES / 2, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES / 2 * interpolation.speed()), result);
|
||||
for (int i = 0; i < NUM_SAMPLES / 2; i += (INTERVAL / interpolation.speed() +0.5)) {
|
||||
CPPUNIT_ASSERT_EQUAL (1.0f, output[i]);
|
||||
}
|
||||
|
||||
cout << "\nSpeed: 10.0";
|
||||
linear.set_speed (10.0);
|
||||
linear.set_target_speed (linear.speed());
|
||||
result = linear.interpolate (NUM_SAMPLES / 10, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES / 10 * linear.speed()), result);
|
||||
for (int i = 0; i < NUM_SAMPLES / 10; i += (INTERVAL / linear.speed() +0.5)) {
|
||||
interpolation.set_speed (10.0);
|
||||
result = interpolation.interpolate (0, NUM_SAMPLES / 10, input, output);
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t)(NUM_SAMPLES / 10 * interpolation.speed()), result);
|
||||
for (int i = 0; i < NUM_SAMPLES / 10; i += (INTERVAL / interpolation.speed() +0.5)) {
|
||||
CPPUNIT_ASSERT_EQUAL (1.0f, output[i]);
|
||||
}
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class InterpolationTest : public CppUnit::TestFixture
|
|||
ARDOUR::Sample input[NUM_SAMPLES];
|
||||
ARDOUR::Sample output[NUM_SAMPLES];
|
||||
|
||||
ARDOUR::LinearInterpolation linear;
|
||||
ARDOUR::Interpolation interpolation;
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -48,6 +48,7 @@ class InterpolationTest : public CppUnit::TestFixture
|
|||
}
|
||||
output[i] = 0.0f;
|
||||
}
|
||||
interpolation.add_channel_to (NUM_SAMPLES, NUM_SAMPLES);
|
||||
}
|
||||
|
||||
void tearDown() {
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ def build(bld):
|
|||
tests/testrunner.cpp
|
||||
'''
|
||||
testobj.includes = obj.includes + ['../pbd/']
|
||||
testobj.uselib = 'CPPUNIT SIGCPP JACK GLIBMM'
|
||||
testobj.uselib = 'CPPUNIT SIGCPP JACK GLIBMM SAMPLERATE'
|
||||
testobj.target = 'run-tests'
|
||||
testobj.install_path = ''
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue