@Miller, I just saw your message - we will try that asap!


Hello Chuck, 

Good point! Thanks for these thoughts, there is no good reason to duplicate the table with each object, apart from initially being too lazy to code it correctly.  

I will have a look at the code again and see which solution I can arrive at! Method 3. sounds a bit like the unique pointer idea in modern C++…

There is another thing that I struggle to understand: (I already posed this question on Github)

Should the sinc interpolation change its filter characteristics when you change the delay time?

If that is the case, the code would need a little bit of adaption.

From what I understand, increasing the delay time is like downsampling (is it?). Now, I wonder how exactly delay time and sample rate are related mathematically. E.g. if I took the derivative of the delay time, would I get something that is proportional to the change in sample rate?

I read about the filter curve adaption during downsampling here:
https://www2.spsc.tugraz.at/www-archive/downloads/Mueller11_DopplerSRC_0.pdf
...but how would that apply to delay time interpolation?

Also: Is it really mandatory to choose a filter cutoff below pi, when the input and output Sample rates match? For a simple static delay that should be the case.

Best wishes, 
Clemens


Am 2021-04-29 um 17:55 schrieb Charles Z Henry <czhenry@gmail.com>:

It's sort of disappointing that it has to be so expensive, but you do
what you have to to get the quality and consistency of the sound.  The
question of whether there is an optimal interpolating kernel (which
I'd like to work on) isn't really going to help you in the near term.
It's enough just to find a solution that works well and performs well.

You've got a scalability issue when using multiple instances of delreadsinc~:
Each new instance recalculates the table when created.  The table is
stored in the struct _sigvdsinc so it is also duplicated for each
instance beyond the first.
So, I propose a few other choices:
1.  Calculate the table during setup and add a class method that
returns a pointer to that table, so that a new object doesn't
calculate the table.  It just points at the existing table.  This
option would use memory, even if the object is never used, and would
not free the table under any circumstances (not great, but easy)
2.  Add a class method that returns NULL if the table has not been
created or a pointer to the existing table and a class method to set
the pointer.  The first instance of the object used would run the
initialize_sinc_table function, but each additional instance would
not.  The table hangs around for future use, even if the instances are
deleted.
3.  Add the class methods in 2. plus methods to keep a count of the
number of instances.  Then, when the last instance is deleted, the
table is freed and the pointer re-assigned to NULL.

By my approximation, that table uses about (4*4096*10) 160 kB (or 320
kB in double precision).  I'm not real clear on the differences in
stack, static array allocation, and dynamic allocation in
behavior/performance.  I know it's there, just can't seem to digest it
when I look at it.  You might have had some reasons in mind to
allocate the array the way you did--I'd like to learn more about this

Best,
Chuck

On Wed, Apr 28, 2021 at 2:27 PM Max <abonnements@revolwear.com> wrote:

Hi Chuck,

Clemens isn't on the list (yet), he sent me some measurements he made in
response to your post.

All at 48kHz.

https://cloud.yuca.biz/s/WZseAmBQm9z6NdL

he says he can't hear a difference with 10 samples cutoff@pi and 14
samples cutoff@0.85*pi
It sounds better than than delread4~ from 6 samples cutoff@pi upwards.

greetings,
Max & Clemens



On 28.04.21 17:56, Charles Z Henry wrote:
I read through the code in your d_delay.c for the delread_sinc implementation.
It's a 22-point interpolator--very high quality and it looks like a
good implementation

The Hermite spline is the best 4-point cubic interpolator, but the
point of those polynomial interpolators is just to be cheap, and good
enough for regular usage.  It doesn't require a table, so it also
doesn't need as much cache space

I don't think it's *the* optimal 4-point interpolator.  It's just the
best cubic polynomial 4-point interpolator.  You could re-use your
sinc interpolator code for other shorter interpolation kernels, ones
that are better than cubics but more expensive to calculate.

At least for me, it's still an open mathematical problem that I've
come back to, from time to time.  I started to wonder if I could
expand the error terms in the truncated sinc spectrum in the form of
1/w, 1/w^2, 1/w^3, .... and then cancel them out by polynomial
correctors.  An alternative to windowing the sinc function, this could
be a more precise way to set the rate of attenuation in the stop-band,
while still retaining all the smoothness of the sinc shape.
I get a break from teaching in about 3 weeks.  I'm looking at the math
right now, and I don't think I can solve it quickly (or maybe at all).

How short does your sinc interpolator with Blackman-Harris window need
to be when you start to get the timbre change effect?

Best,
Chuck

On Sun, Apr 25, 2021 at 7:18 PM Max <abonnements@revolwear.com> wrote:

Interesting. I've included that in the test patch.
It exposes the same samplerate dependent timbre change. So far only the
Sinc function solves the issue.


On 25.04.21 23:15, Sebastian Shader wrote:
I have a [vdhs~] object in my library that does hermite spline
interpolation for a delay line (like tabread4c~).
https://github.com/sebshader/shadylib
(also on deken)

I had to re-make delread~ as delread4c~ because delread~s delay lines
are not exposed in the .h files

-seb

-----Original Message-----
From: Max <abonnements@revolwear.com>
To: pd-list@lists.iem.at <pd-list@lists.iem.at>
Sent: Sun, Apr 25, 2021 5:45 am
Subject: [PD] 4-point interpolation changes timbre depending on sample rate

Hi list,

the 4-point interpolation in tabread4~ has been a popular topic in the
past, going back to at least 2008. [1]

A similar issue is in delread4~. In fact a simple resonator changes its
timbre quite drastically by just changing the sample rate of the audio
interface. Attached is a test patch.

The issue becomes audible when choosing an odd delay time and compare
the result between an odd and an even sample rate (e.g. 44.1k vs. 48k).

This is not good. In fact this is a serious defect. Imagine you want to
market a product like a synth plugin (based on libpd) which sounds
different depending on if the daw is opened in 44.1 or 48 kHz.

Cyrille Henry has coded tabread4c~ with a four-point cubic interpolation
in the nusmuk library, but there is no delread4c~ equivalent in nusmuk.

Clemens Wegener has coded delreadsinc~ which implements a
Whittaker–Shannon interpolation (Sinc function). This implementation
does sounds consistent in any sample rate. It also sounds much better at
very slow speeds inside a pitch shifter where delread4~ produces serious
artefacts. The Sinc function requires a larger padding for the
interpolation.

There are a couple of questions regarding on how to contribute this to Pd.
Vanilla objects are currently:

delwrite~ = the sink
delread~ = control rate tap
delread4~ (vd~) = audio rate tap with a four-point interpolation

1. the code in delwrite~ isn't agnostic towards the interpolation since
it already provides the padding for the 4 point interpolation

2. if we add more interpolation methods to delread / tabread, the
cleanest way would be to just have one tap object and the interpolation
can be changed by a message and argument to it. currently there are
implementations for the miller 4pt, cubic 4pt and Sinc.

Unfortunately delread4 already carries the 4 from 4-point interpolation
in its name, so probably it would be the best to deprecate that and find
a new name like varidelay~ or so.



[1] Review of tabread4~ threads in the archive
https://lists.puredata.info/pipermail/pd-list/2019-06/125391.html
<https://lists.puredata.info/pipermail/pd-list/2019-06/125391.html>

[2] https://github.com/chairaudio/pure-data/tree/feature/delreadsinc
<https://github.com/chairaudio/pure-data/tree/feature/delreadsinc>

_______________________________________________
Pd-list@lists.iem.at <mailto:Pd-list@lists.iem.at> mailing list
UNSUBSCRIBE and account-management ->
https://lists.puredata.info/listinfo/pd-list
<https://lists.puredata.info/listinfo/pd-list>

_______________________________________________
Pd-list@lists.iem.at mailing list
UNSUBSCRIBE and account-management -> https://lists.puredata.info/listinfo/pd-list



_______________________________________________
Pd-list@lists.iem.at mailing list
UNSUBSCRIBE and account-management -> https://lists.puredata.info/listinfo/pd-list





_______________________________________________
Pd-list@lists.iem.at mailing list
UNSUBSCRIBE and account-management -> https://lists.puredata.info/listinfo/pd-list



_______________________________________________
Pd-list@lists.iem.at mailing list
UNSUBSCRIBE and account-management -> https://lists.puredata.info/listinfo/pd-list