[PD] ipoke~ ?

Matt Barber brbrofsvl at gmail.com
Wed Jun 13 22:27:22 CEST 2012

Hi, I've been going through the vdelayxw code myself. See comments:

On Wed, Jun 13, 2012 at 12:30 PM, katja <katjavetter at gmail.com> wrote:
> On Sat, Jun 9, 2012 at 5:18 PM, Matt Barber <brbrofsvl at gmail.com> wrote:
>> Csound has a variable write delay opcode that would be worth looking
>> at - the csound website has just been flagged by google for having
>> malicious content so I can't link to the manual page, but the opcode
>> is called "vdelayxw."
> Unfortunately I can not understand the c code of vdelayxw. There's
> comments for the obvious things but not for the magic numbers and
> other tricks. But it may be a method for sinc-interpolated resampling.

It almost certainly is some kind of windowed sinc, and you're right
about the magic numbers. I don't think you need to know for sure what
the exact interpolation scheme is to make sense of it, though; my
understanding of it is as follows:

For both the variable read and variable write delay opcodes in csound,
one chooses an interpolation window size - say 32 samples.

Now, let's say we're trying to READ from the delay line at sample
index 116.33. So we need to interpolate between sample 116 and 117.
Given our 32-point interpolation window, the earliest sample that will
have an effect on the interpolation is sample 101, and the last one is
sample 132, so to find the correct interpolation we need to sum
together all the scaled windowed sincs (or whatever convolution kernel
is in the interpolation window) for each of those 32 samples, at index
116.33, which gives us our read value.

The write works rather in reverse: if we want to write a sample at
index 116.33, then we need to calculate the windowed sinc (or
whatever) for the input sample centered on 116.33, and MIX (not
overwrite) those values for samples 101-132 into those samples. What
emerges, then, becomes the cumulative effect of having interpolated:
imagine the next sample written is at index 118.54 - you're going to
mix its function into samples 103-134, and the overlap with the
previous action is going to cause the interpolation to "work" once
those samples reach the read head.

In that way, a variable write into a delay line is somewhat easier
conceptually -- if it's done this way -- than a [tabwrite4~] would be,
because the way the table is read is predetermined. Nothing is ever
read until all the relevant input samples have had a chance to affect
the output in the appropriate way.

> On the other hand, think of [tabread4~]: it's interpolation scheme is
> fixed, no matter what resampling factor. With extreme resampling,
> aliases may be noticeable. But what the hell, it doesn't sound like
> the original music anyway, when sped up or down to extremes. That is
> the difference with an offline resampling job, when the original sound
> must be preserved insofar the new frequency range allows. In that
> sense, an interpolation scheme like in [tabread4~] could be used for
> realtime variable speed writing, leaving the consequences for the
> user. For example, if you make large jumps through the table, many old
> samples would simply not be rewritten.
> But even with interpolation quality requirements so relaxed, it is not
> by itself clear how the samples should be written. Using
> sinc-interpolation, each input sample could be written as many samples
> of a (eventually phase-shifted) sinc function, with amplitude
> compensation for the overlap. The interpolation scheme of [tabread4~]
> however can not calculate four output samples based on one input
> sample, it could only calculate one output sample based on four input
> samples.

Two points here. The last thing you said is not actually true -- each
interpolation scheme has an associated convolution function, which can
be calculated by imagining what the interpolation would look like for
a single sample whose value was 1.0 surrounded by zeroes everywhere
else. This 4-point piecewise function can be used to write four
samples in its immediate vicinity the same way that the sinc does in
the csound example.

It seems the bigger question to me is, if you skip somewhere far in
the table, you're going to write four samples, and then another four
samples somewhere else. Maybe this is OK, but another way to think of
what to do would be to imagine the incoming signal as something you're
interpolating over the way you would do when reading from a table, in
which case a very large index increment if you're writing could be
just like a bunch of very small index increments when you're reading.
So say you jump ahead 48 samples - one way to do it would be to write
ALL 48 samples as an interpolation over the the two input samples.

That would open up some other problems, like how to interpret the
difference between jumping back in a table vs "wrapping back around."
Not sure how to deal with that at all (this problem doesn't arise in
the delay line version of a variable write because what is represented
is always a chunk of time rather than an abstract table of numbers to
be used for whatever, so there's no real concept of "wraparound" in
the delay-line version).

It would also lead to there not being a good way to "keep writing into
index 1.5 of the table" -- the incoming input samples would be
interpolated over zero samples of the table, and so nothing would get

> Imagine how one would do this with a fixed resampling factor. For
> example with resampling factor 0.75 (downsampling) you would write 64
> * 0.75 = 48 samples into the array for every block of 64 input
> samples, while incrementing the read index by 1 / 0.75 = 1.3333333.
> Another example, with resampling factor 1.5 (upsampling) you would
> write 64 * 1.5 = 96 samples into the array for each block of 64 input
> samples, while incrementing the read index with 1 / 1.5 = 0.6666666.
> The perform loop would not iterate over an integer n (= blocksize),
> but it would just break when the float read index exceeds n. To
> accommodate for interpolation, and for index increments larger than
> one, a few samples of fixed delay 'headroom' must be introduced.

This is a good point -- but the problem wouldn't exist if you were
writing four samples in the table for every incoming sample.

I'm just not sure in that case if a 4-point cubic interpolation is
nearly enough for the kind of upsampling that might need to occur.

> In a [tabwrite4~], resampling factor would follow from index
> increments calculated from float index values received at the inlet.
> But what to do with large increments, exceeding the delay 'headroom'
> at the end of the input buffer? And another question: what to do with
> very small increments, leading to massive amounts of written samples
> and possibly to cpu overload?

I'm not sure I understand this - I assume you mean "very small
increments in the written table." So lets say you're going to try to
write a whole 64-sample input block to between indices 10 and 11 of
the table. If you're writing 4 samples each time, what you end up with
is not cpu overload, but just four samples with possibly a very high
amplitude, depending upon the nature of the signal. And actually, if
you think about this with regard to the delay line, this would be what
would happen if the sound source were moving toward a microphone at or
near the speed of sound, so the "very high amplitude" would in effect
be a digital "sonic boom."


More information about the Pd-list mailing list