From f42f577bedbffcd2465341e033afac0a0326a491 Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Tue, 23 Jun 2009 09:50:02 +0000 Subject: Interpolation: First working but buggy version using libsamplerate git-svn-id: svn://localhost/ardour2/branches/3.0@5255 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/audio_diskstream.h | 2 +- libs/ardour/ardour/interpolation.h | 37 +++++++------ libs/ardour/ardour/session.h | 6 ++- libs/ardour/audio_diskstream.cc | 14 +++-- libs/ardour/interpolation.cc | 93 +++++++++++++++++++++++---------- libs/ardour/session_process.cc | 6 ++- libs/ardour/tests/interpolation-test.cc | 62 +++++++++++----------- libs/ardour/tests/interpolation-test.h | 3 +- libs/ardour/wscript | 2 +- 9 files changed, 137 insertions(+), 88 deletions(-) (limited to 'libs') diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h index 401ed9ec19..ad3b1adde2 100644 --- a/libs/ardour/ardour/audio_diskstream.h +++ b/libs/ardour/ardour/audio_diskstream.h @@ -146,7 +146,7 @@ class AudioDiskstream : public Diskstream } } - LinearInterpolation interpolation; + Interpolation interpolation; XMLNode* deprecated_io_node; diff --git a/libs/ardour/ardour/interpolation.h b/libs/ardour/ardour/interpolation.h index fc75451707..d0ba3c48bc 100644 --- a/libs/ardour/ardour/interpolation.h +++ b/libs/ardour/ardour/interpolation.h @@ -1,4 +1,6 @@ #include +#include + #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 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 \ No newline at end of file diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 18bc22ce87..5c2c32655f 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -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; diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index 9ff030678a..47d7b5c6e6 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -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 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 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()); diff --git a/libs/ardour/interpolation.cc b/libs/ardour/interpolation.cc index 066507283b..a4a4b08872 100644 --- a/libs/ardour/interpolation.cc +++ b/libs/ardour/interpolation.cc @@ -1,41 +1,76 @@ #include + #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) +{ +} + +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 { + state = src_new (SRC_LINEAR, 1, &error); + } +} + +void +Interpolation::add_channel_to (int input_buffer_size, int output_buffer_size) { - // 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 + SRC_DATA newdata; - // index in the input buffers - nframes_t i = 0; + /* 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; - double acceleration; - double distance = 0.0; + data.push_back (newdata); - if (_speed != _target_speed) { - acceleration = _target_speed - _speed; - } else { - acceleration = 0.0; - } + reset_state (); +} - 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; - } +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; - i = (distance + 0.5L); - // playback distance - return i; + 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); + } + + return data[channel].input_frames_used; } diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index d389f32696..e7f2ad416f 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -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)) { diff --git a/libs/ardour/tests/interpolation-test.cc b/libs/ardour/tests/interpolation-test.cc index 5a559cc830..3ec7910e1b 100644 --- a/libs/ardour/tests/interpolation-test.cc +++ b/libs/ardour/tests/interpolation-test.cc @@ -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]); } /* diff --git a/libs/ardour/tests/interpolation-test.h b/libs/ardour/tests/interpolation-test.h index 3231f32464..0c1b0de6c2 100644 --- a/libs/ardour/tests/interpolation-test.h +++ b/libs/ardour/tests/interpolation-test.h @@ -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() { diff --git a/libs/ardour/wscript b/libs/ardour/wscript index fc08dfde0d..172047bde3 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -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 = '' -- cgit v1.2.3