[announcement] PM.Chamberlin~ (state-variable filter)

Peter McCulloch's icon

Hi everybody, I've just posted a new svf filter to the toolbox. It does self-oscillation and saturation, supports higher cutoff rates than svf~ and adds a peak filtering mode. (it is more expensive, however) You can also control it via MIDI values and the tuning is accurate enough for melodic playing. It also has the option of only using one output which should save a bit of CPU when you don't need all the outputs.

PM

Charles Baker's icon

Tomita Whistle, here we come....;-)
Thanks!
License mentions source?
filter model used?
Anyway, thanks again!

Charlie

Peter McCulloch's icon

Re source: It's a binary distribution. That said, the filter is ported (lightly) from the ICST DSP library which is BSD-licensed, however, so you can definitely take a look at that. They also made an interesting two-part PDF which explains how it works.

The model is a Chamberlin state-variable digital filter, and has a non-linearity in the feedback, IIRC. The frequency is updated every 16 samples, so it works decent enough for sweeps, but FM is probably asking a bit much. Might add the ability to up/downsample the freq input in the future.

Charles Baker's icon

Aw...yeah, we want to add lfo&env to freq for whistle patch, right, and stepping is bad to hear there...16 samps is *prob* ok, tho...
Thanks for reference, I had seen this design before, and indeed, it does sound excellent, oscillates great, and the non linearity in the feedback gives that lovely fat 'formanty' sound. Thanks again!
charlie

AudioMatt's icon

this external shows up as a folder and max doesn't see it. any suggestions?

Peter McCulloch's icon

Which Max, and which OS?

AudioMatt's icon

doh! sorry

Max 5.1.8
Mac OS 10.6.8
2.66 intel core 2 duo

Peter McCulloch's icon

I'm not sure. I tested the link and I see the external fine; I can explore the package contents.

What do you see when you unpack it? I see PM.Chamberlin~.mxo, PM.Chamberlin~.maxhelp, and license.txt

I changed the link to add the bundle bit and updated the plist files; I'm not sure if this is a 10.5-10.6 difference or what the story is. HTH, and let me know.

AudioMatt's icon

one more thing.. peter this sounds great.

Timo Rozendal's icon

thanks Peter, the filter sounds great, it's a useful addition to the msp toolbox!

However, I think there is still some unwanted (bitcruhs-like) distortion in the signal. This distortion is changing when you change the signal vector size.

Max Patch
Copy patch and select New From Clipboard in Max.

Listen to this test patch:

I can provide audio samples if you don't hear any differences on your system (mine is: 44.1kHz, mac os 10.5.8).
(addition: I am also curious about the level difference, I wasn't expecting that)

thanks!

Timo

Timo Rozendal's icon

idea: could it be that for upsampling you do not take into account the last values of the previous signal vector? (that you don't store these in your object structure)

Peter McCulloch's icon

Hi Timo,

I hear a level difference (-6dB), but I'm not getting the bit crushing. I think the level difference could be from the saturation code. I've tried this at signal vectors of 64,128, and 256 at 44.1kHz.

Max Patch
Copy patch and select New From Clipboard in Max.

Because of the saturation, pre and post gain can make a big difference in the sound of the filter. I'd like to hear the recordings if you have time. Also, does this happen in both modes of the filter? (mono vs. poly outs) The code is slightly different there, and that could account for it.

Timo Rozendal's icon

Hi Peter,
I sorry for the delay but now I have time to reply and make examples for you.
I hear it in both modes of the filter (mono & poly outs), it's not clearly visible in the scope~ and spectroscope~, but it is clearly audible on my system.
Timo

2556.sv512.aif
aif
Timo Rozendal's icon

I included some spectrum plots of the audiofiles I attached to the previous post, this clearly shows the distortion that I hear (note: green is incoming audio, red is filtered audio, sv means signal vector size)

2561.sv32.png
png
AlexHarker's icon

Hey Timo,

Those spectrum plots look pretty cool!

If only you could get spectral plots like that it MaxMSP......

;-)

Well - maybe sometime in the not too distant future..

Alex

Timo Rozendal's icon

yeah Alex, having spectrum plots like this in in max would be awesome!! :-p

Peter McCulloch's icon

Thanks for the thorough example. I'll have to look through the code. The filter equation is from the ICST library. My guess is that the distortion may be from updating the filter coeff every 8 samples, and the filter coeff is affected by the feedback, so the slower updates could be causing the distortion.

I could add an option to set the update rate. I might do it as a % where 0-100 is scaled to 0-n where n is the result of the vector size 2^n.

Timo Rozendal's icon

Peter, what if you update the filter coeffs only when they change? Do you still hear it? Maybe when you set the coeffs the 'history' of the filter is reset as well.

If it's due to the filter resetting it is still weird that it changes with signal vector size (which are all multiple of 8 in my examples)

Peter McCulloch's icon

Had the coffee now; the base2 log isn't great, and I'll probably just go with a sample delay.

It's also interesting that the distortion seems to go up as the vector size increases. There's a multiply involving 1/vs, and I hadn't taken the do_every_nth factor into account there, and I'll see about tweaking it.

It'd be really nice if we could message people privately. I had someone offer to build a windows version, but I have no way of contacting them...

Timo Rozendal's icon

"It'd be really nice if we could message people privately. I had someone offer to build a windows version, but I have no way of contacting them... "

sometimes you can see the mail address of the person who replies in the email notification you receive in your mailbox

looking forward to the tweaks :-)

Peter McCulloch's icon

I think I've got it tracked down. I had an error in my bit logic in the coeff update routine. See if this works better. There's still some noise in it, but it looks harmonic, and much cleaner with a sine wave through it. It's available on the download page.

One issue still to be resolved: updaterate of 1 sample sounds bad, but updaterate of 2 samples sounds fine.

I'm coming from Java, so I'm not used to doing a lot of bit-manipulation tricks. My do every nth code looks like this: (for i in vector)

if (0 == (i | nth))

where nth is nth -1 (so if every 8 samples, use 7 for the bitmask). Hopefully I'm getting that right now...

Timo Rozendal's icon

Hi Peter,

Thanks, the 'bitcrush effect' is gone.
Yes, there still is some distortion and, but this is due to the saturation I think and it really depends on the level of incoming audio.

Only it seems that in this version you have broken the non-signal frequency input, it only reacts on signal input now.

I don't think "if (0 == (i | nth))" is doing what you want (check it with the max bitwise-or object if you like),
I think you are looking for "if (0 == (i % nth))" (where nth is nth - 0). Though you need to make sure that your signal vector size is a multiple of nth.

Max Patch
Copy patch and select New From Clipboard in Max.

(it might be possible with bitmask operations as well if you stick to powers of 2, but I don't know them so well either)

Peter McCulloch's icon

You're right, it definitely isn't. I need:
0 == (i & nth) where nth = nth-1 (so if you say 8, it uses 7 for the bitmask)

The reason for doing this via bitmask and not % is that I'm trying to avoid adding a division to the mix. The 2^x-1 bitmask should always be non-zero except for when i%(2^x) is 0.

I'll have to see what I did to kill the non-signal input...

Timo Rozendal's icon

Hi Peter, yes 0 == (i & nth) works, but I don't think it works well for all values (I guess it only works for powers of 2).

if updaterate is 8 samples for example then nth = 7, then (i&nth)==0 for i=0, 8, 16 which is correct

if updaterate is 7 samples for example, then nth = 6, then (i&nth)==0 for i=0 , 1, 8 ,9, 16 ,7 which is NOT what you want

if updaterate is 6 samples for example, then nth = 5, then (i&nth)==0 for i=0, 2, 8, 10, 16, 18 which is NOT what you want

Max Patch
Copy patch and select New From Clipboard in Max.

check it here: