interpolation.h / audio_diskstream.cc: make varispeed sound well again, by replacing the code by the original implementation for later comparison and step-by-step refactoring

git-svn-id: svn://localhost/ardour2/branches/3.0@5260 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Hans Baier 2009-06-23 14:53:37 +00:00
parent 417309d6d4
commit 2641040701
2 changed files with 89 additions and 21 deletions

View file

@ -40,25 +40,31 @@ class FixedPointLinearInterpolation : public Interpolation {
std::vector<uint64_t> last_phase;
// Fixed point is just an integer with an implied scaling factor.
// In 40.24 the scaling factor is 2^24 = 16777216,
// so a value of 10*2^24 (in integer space) is equivalent to 10.0.
//
// The advantage is that addition and modulus [like x = (x + y) % 2^40]
// have no rounding errors and no drift, and just require a single integer add.
// (swh)
static const int64_t fractional_part_mask = 0xFFFFFF;
static const Sample binary_scaling_factor = 16777216.0f;
// Fixed point is just an integer with an implied scaling factor.
// In 40.24 the scaling factor is 2^24 = 16777216,
// so a value of 10*2^24 (in integer space) is equivalent to 10.0.
//
// The advantage is that addition and modulus [like x = (x + y) % 2^40]
// have no rounding errors and no drift, and just require a single integer add.
// (swh)
static const int64_t fractional_part_mask = 0xFFFFFF;
static const Sample binary_scaling_factor = 16777216.0f;
public:
FixedPointLinearInterpolation () : phi (FIXPOINT_ONE), target_phi (FIXPOINT_ONE) {}
FixedPointLinearInterpolation () : phi (FIXPOINT_ONE), target_phi (FIXPOINT_ONE) {}
void set_speed (double new_speed) {
target_phi = (uint64_t) (FIXPOINT_ONE * fabs(new_speed));
phi = target_phi;
}
uint64_t get_phi() { return phi; }
uint64_t get_target_phi() { return target_phi; }
uint64_t get_last_phase() { assert(last_phase.size()); return last_phase[0]; }
void set_last_phase(uint64_t phase) { assert(last_phase.size()); last_phase[0] = phase; }
void add_channel_to (int input_buffer_size, int output_buffer_size);
void remove_channel_from ();

View file

@ -816,18 +816,80 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
void
AudioDiskstream::process_varispeed_playback(nframes_t nframes, boost::shared_ptr<ChannelList> c)
{
ChannelList::iterator chan;
interpolation.set_target_speed (_target_speed);
interpolation.set_speed (_speed);
ChannelList::iterator chan;
int channel = 0;
for (chan = c->begin(); chan != c->end(); ++chan, ++channel) {
ChannelInfo* chaninfo (*chan);
/*
interpolation.set_speed (_target_speed);
int channel = 0;
for (chan = c->begin(); chan != c->end(); ++chan, ++channel) {
ChannelInfo* chaninfo (*chan);
playback_distance = interpolation.interpolate (
channel, nframes, chaninfo->current_playback_buffer, chaninfo->speed_buffer);
}
*/
// the idea behind phase 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
// so the "phase" element, if you want to think about this way,
// varies from 0 to 1, representing the "offset" between samples
uint64_t phase = interpolation.get_last_phase();
interpolation.set_speed (_target_speed);
// acceleration
uint64_t phi = interpolation.get_phi();
uint64_t target_phi = interpolation.get_target_phi();
int64_t phi_delta;
// index in the input buffers
nframes_t i = 0;
playback_distance = interpolation.interpolate (
channel, nframes, chaninfo->current_playback_buffer, chaninfo->speed_buffer);
}
// Linearly interpolate into the speed buffer
// using 40.24 fixed point math
//
// Fixed point is just an integer with an implied scaling factor.
// In 40.24 the scaling factor is 2^24 = 16777216,
// so a value of 10*2^24 (in integer space) is equivalent to 10.0.
//
// The advantage is that addition and modulus [like x = (x + y) % 2^40]
// have no rounding errors and no drift, and just require a single integer add.
// (swh)
const int64_t fractional_part_mask = 0xFFFFFF;
const Sample binary_scaling_factor = 16777216.0f;
// phi = fixed point speed
if (phi != target_phi) {
phi_delta = ((int64_t)(target_phi - phi)) / nframes;
} else {
phi_delta = 0;
}
for (chan = c->begin(); chan != c->end(); ++chan) {
Sample fractional_phase_part;
ChannelInfo* chaninfo (*chan);
i = 0;
phase = interpolation.get_last_phase();
for (nframes_t outsample = 0; outsample < nframes; ++outsample) {
i = phase >> 24;
fractional_phase_part = (phase & fractional_part_mask) / binary_scaling_factor;
chaninfo->speed_buffer[outsample] =
chaninfo->current_playback_buffer[i] * (1.0f - fractional_phase_part) +
chaninfo->current_playback_buffer[i+1] * fractional_phase_part;
phase += phi + phi_delta;
}
chaninfo->current_playback_buffer = chaninfo->speed_buffer;
}
playback_distance = i; // + 1;
interpolation.set_last_phase (phase & fractional_part_mask);
}
bool