SynthMaker

Frequency to Pitch little quasi-bug

Archive · 2005 19 old posts

From the original SynthMaker forum (2004–2014), with its members’ names and dates.

lalo ·

i think this little quasi-bug is still here

Pitch and Frequency

maybe is worth to move that thread in this section

lalo

jorge ·

Thanks for bumping it lalo. Here is a schematic that lets you compare different ways of calculating the PitchToFreq conversion:

Here is the code shown above in case you want to copy and paste it:

polyin in; polyout out; float x,x2,x3,x4,x5; float a4,ln2; ln2=0.69314718056; a4=440/22050; x=ln2*((in-57)/12); x2=x*x; x3=x2*x; x4=x3*x; x5=x4*x;

out=1+x+(1/2)*x2+(1/6)*x3+(1/24)*x4+(1/120)*x5; out=(out*a4)/2;

The taylor aproximation done in the code seems to not be precise enough, it would be interesting to experiment with using more terms in the aproximation until it passes the lalo quality control.

The code is meant to aproximate around the A4=57=440Hz note so that should give the highest precision. I might be doing something wrong here, at least the fact that its not precise enough is wrong.

Here's the schematic: [old link]

unkargherth ·

Sorry, but, What's wrong with the standard formula?

freq=440*2^((x-57)/12) / 44100

beign x the midi note

Can be used without approximations and always give the correct result on the whole input range

As a bonus, can be implemented in floats. No code module needed

On the approximation issue, the problem is that Taylor series works well usually for a small range of input values, but in this case range is big ( 1-127) so if it's a bit incorrect at 57, the error at 4 or at 112 could be enormous, with independence of number of terms you use

stefan ·

unkargherth wrote: Sorry, but, What's wrong with the standard formula?

freq=440*2^((x-57)/12) / 44100

beign x the midi note

Can be used without approximations and always give the correct result on the whole input range

As a bonus, can be implemented in floats. No code module needed

The main issue here is the 2^, "raised to" is a bit tricky, but it's doable, and hopefully we'll get such a function in the code component soon enough. I have handed some code for it over to jorge, but I'm not completely sure that actual implementation was suitable for SM, so something else might have to be done.

Also, in for instance Nildon, there's no gain in doing pitch calculation on float instead of poly data, only losses, due to modulations of pitch (on oscillators and filters), all modulations are at audio rate.

unkargherth wrote: On the approximation issue, the problem is that Taylor series works well usually for a small range of input values, but in this case range is big ( 1-127) so if it's a bit incorrect at 57, the error at 4 or at 112 could be enormous, with independence of number of terms you use

The range isn't a problem really, but logarithmic output is 🙂

jorge ·

unkargherth wrote: Sorry, but, What's wrong with the standard formula?

freq=440*2^((x-57)/12) / 44100

Nothing wrong except you dont have a "2^" function in SSE so when compiling it you have to somehow generate the code for it, that's why I've used the taylor expansion series as "*" and "+" SSE calculations are most often faster than table look ups or more complex FPU instructions.

stefan ·

jorge wrote: unkargherth wrote: Sorry, but, What's wrong with the standard formula?

freq=440*2^((x-57)/12) / 44100

Nothing wrong except you dont have a "2^" function in SSE so when compiling it you have to somehow generate the code for it, that's why I've used the taylor expansion series as "*" and "+" SSE calculations are most often faster than table look ups or more complex FPU instructions.

Atm, it seems like a interpolated look-up table might be the best way to go.

jorge ·

stefancrs wrote: Atm, it seems like a interpolated look-up table might be the best way to go.

You might be right, specially when the range is limited. I think we need to find out how precise the taylor version is with more terms. Adding one more term will make very little difference in terms of performance and a huge difference in terms of precision. I think we should try that first ( or even two more taylor terms ) before going for the look-up table.

unkargherth ·

Well i've done some more test on the schematic jorge posted.

i added two terms to taylor expansion and results are better for the medium range ( in fact no difrences with "Correct" c++ version for notes around 440). But the error is enormouson midi note 12 or midi note 112 to put two examples( approximately error = 20*correct value), so still unusable

I would have to make a table swoing the results but seems like MMmon sometimes gets Stuck on a note, don't know the reason. You should believe me as i can't demostrate it

jorge ·

unkargherth wrote: i added two terms to taylor expansion and results are better for the medium range ( in fact no difrences with "Correct" c++ version for notes around 440). But the error is enormouson midi note 12 or midi note 112 to put two examples( approximately error = 20*correct value), so still unusable

Thanks unkargherth, it looks like it will have to be a look-up table then. Or what about having two taylor aproximations centered at different notes? I might try to create a schematic to plot the pitchToFreq conversion with graphs, one for the exact value using float components and another for the aproximated one using the SSE code.

unkargherth wrote: I would have to make a table swoing the results but seems like MMmon sometimes gets Stuck on a note, don't know the reason. You should believe me as i can't demostrate it

If the MidiMono has a bug I'd really like to recreate it. It always keeps the last note played even after note off, that was on purpose although I'm not sure if it is the desired behaviour.

unkargherth ·

I think it should stop when note offs, Other that that mono leads will last forever with last note beign eternal

On the Freq issue i really think that should be a table ( and a big one, maybe 64k) an use at least linear interpolation. This gives a max error of approx 0.000393 % if my calculation don't fail miserably. Obviously with such big table you loose cache efficiency, but i think is the better trade off we can find

jorge ·

unkargherth wrote: On the Freq issue i really think that should be a table ( and a big one, maybe 64k) an use at least linear interpolation. This gives a max error of approx 0.000393 % if my calculation don't fail miserably. Obviously with such big table you loose cache efficiency, but i think is the better trade off we can find

I'd expect that a much smaller table would be enough when using interpolation. For sound waveforms a 2K table with linear interpolation gives slightly better results than a 64K table without interpolation.

unkargherth ·

jorge wrote: I'd expect that a much smaller table would be enough when using interpolation. For sound waveforms a 2K table with linear interpolation gives slightly better results than a 64K table without interpolation.

Yes, but wavefor output values has a small range ( -1..1) while frequency range is big ( 20 22050) and worst than that it has exponential growing

Diference between phase= and ph=0.1 in waveform ( sine one) in a 2k table is 0.00030679 while in a 2k freq table diffrence between Midi note 57 and 58 is 0.021 in range 0..1 or 26 HZ in range 0..22050. and will be doubled in next octave, quadrupled at a6 and so on.

A big table shopuld minimize this errors, also using some kind of higher level interpolation ( hermite maybe) also could help ( in fact hermite interpolation requires a number of mults and adds not much bigger than a seven level ln taylor expansion)

Also, i supose the table could be global, and interpolation precalculated ( i've done it a couple of times, for wavetables) so cpu impact didn't have to be so high compared with the complexity of a real, non aproximated version of pow for floats, ( which otherwise is, in my opinion really needed at any cost in code module)

jorge ·

unkargherth wrote: Yes, but wavefor output values has a small range ( -1..1) while frequency range is big ( 20 22050) and worst than that it has exponential growing

Diference between phase= and ph=0.1 in waveform ( sine one) in a 2k table is 0.00030679 while in a 2k freq table diffrence between Midi note 57 and 58 is 0.021 in range 0..1 or 26 HZ in range 0..22050. and will be doubled in next octave, quadrupled at a6 and so on

Thanks unkargherth, that info will be very useful for fixing the PitchToFreq component. At the moment the best option seems to be a 64K table with linear interpolation as you suggested.

unkargherth ·

sooryy. edited my last message while you typing jorge, some interesting info there

lalo ·

wow! some deep stuff here!

congrats to jorge and unk 🙂

i'll be happy to test the pitch accuracy wich a very important thing... it has to be precise even at fractional hz values.... that because one day we may like to do microtonal stuff and similar things (i'll certainly do it 🙂 )

one question : how this 64k interpolated table will interact with data recieved from i.e. the pitch bend module for example?... oh..i'm stoopeed...the 64k will output midi notes data right?

so microtonal operations will be a matter of change the 64k table mappings... so should'nt that table be open to SMakers? i mean a kind of table GEN module a la Csound or simply a table a la pd/Max.MSP...and it's output will be feed into the freq to pitch module... or even be used as an osc itself 😉

lalo

unkargherth ·

lalo wrote: one question : how this 64k interpolated table will interact with data recieved from i.e. the pitch bend module for example?... oh..i'm stoopeed...the 64k will output midi notes data right?

I think the 64 k table is to convert MIDINote Information (MIDI note number on Note on's) to frequency information in range 0..1, beign 1 Your Nyquist Freq (half samplerate)

Then, it has nothing ot do with pitch bend. Pitch bend is an integer value betwenn 0 and 16384, with 8192 meaning no pitchbend at all

Is your own responsability how to convert this in frequency information, basically, because as you probably know, usually pitch bend works on a user definable range which most synth manufactures defaults to 2 semitones up or down, but could be changed in the patch by the user

So, if the users make no selection, a pitchbend value of 16384 means "2 semitones above the currently playing note" while, if the users set the "Bend range" to 12, 16384 means "An octave above currently playing note"

Then, to include pitch bend information in frequency you should do

final freq= notefreq * 2^(bendrange*(bendinfo-8192)/12)

Or something similar ( sorry, written for memory, check it for correctnes first)

Where notefreq is the poly output "freq" from Midi2Poly module

lalo ·

yes everything clear 😉 and what do you think about the table module idea , guys?

lalo

unkargherth ·

Well, would be nice to have a Table that can be precalculated at start and aaccesed from code module, kinda Buzz in Csound for example, This opens much facilities ( new waveforms for new oscilators , Non-linear functables,etc) Anyway one of a kind would'nt be enough. I f you want do it well, you need a lot of variant ( wrapped or non-wrapped, no/linear/hermite interpolated, ability to linik between them in some way, for multisample wavetables for example). So iot's a VERY, VERY Good Idea, but requires a lot of work and optimization

On having manageable Pitch tables, well, i supose in microtonality projects it's basic, but i never used so really i can't give my opinion on that

lalo ·

maybe the upcoming arrays can have those features? like choosing wrap, no-wrap, interpolation methods etc..?

lalo

Wrote something here? To have a post removed or your name hidden, write to [email protected].

Before your first post

A few rules keep this a friendly place. You agree to them once.

Shown next to what you post, here and in the app. It doesn’t have to be your real name: 3–24 lower-case letters, digits or _ (capitals become lower case, spaces become _).

    Then your post goes up straight away.

    Delete this reply?

    Open it in SynthMaker?

    It goes on the track you’re editing there, in place of that track’s sound, and into My sounds. Your other tracks stay as they are.

    Want to keep that track’s sound? Start a new song in SynthMaker first (Song › New song), then open this.

    Report this reply?

    Only the developer reads reports. The person isn’t told who reported them.

    What’s wrong with it?

    Block this person?

    You won’t see their posts and replies here any more. They aren’t told, and you can unblock them at any time.

    People you’ve blocked

    Their posts and replies are hidden from you. Unblock someone to see them again.

    The community rules

    A few rules keep this a friendly place. Everyone agrees to them once, before their first post.