[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [fluid-dev] question on linear interpolation
Re: [fluid-dev] question on linear interpolation
Thu, 31 Dec 2015 11:38:54 -0800
Hi Mr Green,
Yes, I am carrying the fractional part. In my case, it's 12 bits and I shift right by 4 to get the upper 8 bits to index to the coefficient table.
But let me cite an example,
Suppose I have x[i]=100 and x[i+1]=100 (which occurs often in a lower note frequency).
Assume after looking up the coefficient table, you get coeffs = .3 and coeffs = .7
So if you do the math,
out=100*.3 + 100*.7 = 100. So no change.
In my case, I can have 4 consecutive values of 100 (at note = 60) as shown in the previous images.
So any of the coefficients in the table will return a value and 1-value, if the current sample and then next are the same, the output is always the original value. So in the general case where sampe[i]=sample[i+1],
out = sample* frac + sample*(1-frac) = sample*(frac +1 -frac) = sample = out.
This is why I was asking if you're adding to the data set by up-sampling, pre-filtering, or something else. This is hinted at in the paper by Olli Niemitalo.
I suppose you that the interpolated value could be stuffed back into the original data (recursion) but I don't see that occurring in fluid_voice_dsp.c.
On Wed, Dec 30, 2015, at 07:21 PM, Element Green wrote:
I'm developing an embedded project using some of the code in
The target is an ARM Cortex M4 and am using integer math. Most of
the coefficients are in Q15 format.
So far, I'm able to generate different notes with sound font files
and use some of the CMSIS DSP libraries to generate high order IIR
But I am having no luck with any interpolation routines. I ran some
tests using the command line version of FluidSynth on a laptop
running Ubuntu 14.
I created a sine wave sound font (using Swami) with a sample rate of
20050 Hz, root note is 86. It's looping over several cycles. The
image Midi_60_no_interpolation.jpg picture shows the result
with no interpolation (I get the exact same results on my embedded
platform). This is using "interp 0". (Note that the ringing is due
to the sinc function in the Codec filter/decimator.)
If I then set "interp 1", I get the image as shown in Midi_60_linear_interpolation.jpg
which is a major improvement.
I have reviewed the code inside fluid_voice_dsp.c and have
set up my program to emulate the equations. I converted the
floating point coefficients to Q15 format. It seems to do exactly
what it's supposed to do. Yet I see no improvement what-so-ever
except at higher note values.
However...I don't see how linear interpolation can work. If you
have straight lines (i.e. the "steps" in the first waveform), a
linear interpolation won't change anything since the current sample
and the next sample are the same over several samples.
Are you up-sampling before you to do the linear interpolation? I
didn't see any evidence in the code. Or do you simply take the loop
sample as is and step through it using dsp_phase_index? I don't
think the bi-quad post filter has an effect since it has a very high
cut-off. Nor should the reverb or chorus blocks have any effect
(since they're disabled anyway in my test).
What am I missing?
Thanks for your time and consideration. Any advice or insight is
appreciated. I really like FluidSynth.
P.S. I also implemented the 4th order interpolation but it didn't
change anything--I still get the "stepped" waveform. (At 50MHz
clock, the M4 can process 128 samples in <1uS with sound fonts
stored in internal Flash memory. Pretty impressive.)
Let me make sure I understand your situation correctly.. So you have taken the interpolation code in fluid_rvoice_dsp.c and adapted it to integer math and there is something wrong with the ported code, since it is not interpolating as expected.
It has been a while since I delved into the interpolation code and I did not originally write it (though I did muck about in that area a bit). If you look at the fluid_rvoice_dsp_config() routine you will see that it initializes the interpolation tables, including interp_coeff_linear, which essentially stores 2 tables of linearly increasing and decreasing values from 0 to 1. These values are then used depending on the current sample index fraction (think of the current sample pointer as being at a position which may be in between 2 consecutive samples - the fraction component). If the fractional position is closer to the first sample, then it will have a higher weight in the linear calculation of the sample value which gets synthesized. I hope that makes sense and perhaps you already knew this - seeing as you have done this port.
I would make sure that your ported code retains this fractional sample pointer component and is using it properly and that your linear coefficients table is properly initialized. You should be able to see this stuff at work by single stepping the code and looking at the calculations to see if they are behaving as expected.
Hope that helps. Maybe I did not get your scenario right though, if so, please explain in more detail.
fluid-dev mailing list