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:
Hans Baier 2009-06-23 09:50:02 +00:00
parent def335e427
commit f42f577bed
9 changed files with 139 additions and 90 deletions

View file

@ -146,7 +146,7 @@ class AudioDiskstream : public Diskstream
}
}
LinearInterpolation interpolation;
Interpolation interpolation;
XMLNode* deprecated_io_node;

View file

@ -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

View file

@ -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;

View file

@ -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());

View file

@ -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;
}

View file

@ -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)) {

View file

@ -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]);
}
/*

View file

@ -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() {

View file

@ -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 = ''