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

    Jul 20 2011 | 7:52 pm
    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.

    • Jul 21 2011 | 12:48 am
      Tomita Whistle, here we come....;-) Thanks! License mentions source? filter model used? Anyway, thanks again!
    • Jul 21 2011 | 7:11 am
      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.
    • Jul 21 2011 | 1:00 pm
      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
    • Jul 21 2011 | 6:19 pm
      this external shows up as a folder and max doesn't see it. any suggestions?
    • Jul 22 2011 | 3:51 am
      Which Max, and which OS?
    • Jul 22 2011 | 4:39 am
      doh! sorry
      Max 5.1.8 Mac OS 10.6.8 2.66 intel core 2 duo
    • Jul 22 2011 | 8:50 pm
      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.
    • Jul 25 2011 | 9:18 pm
      one more thing.. peter this sounds great.
    • Aug 17 2011 | 12:41 pm
      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.
      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)
    • Aug 17 2011 | 12:42 pm
      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)
    • Aug 17 2011 | 3:41 pm
      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.
      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.
    • Aug 22 2011 | 6:22 am
      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
    • Aug 22 2011 | 6:30 am
      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)
    • Aug 22 2011 | 9:43 am
      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..
    • Aug 22 2011 | 10:28 am
      yeah Alex, having spectrum plots like this in in max would be awesome!! :-p
    • Aug 22 2011 | 1:13 pm
      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.
    • Aug 22 2011 | 1:22 pm
      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)
    • Aug 22 2011 | 2:30 pm
      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...
    • Aug 22 2011 | 2:36 pm
      "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 :-)
    • Aug 22 2011 | 4:08 pm
      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...
    • Aug 23 2011 | 7:04 am
      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.
      (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)
    • Aug 23 2011 | 4:15 pm
      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...
    • Aug 24 2011 | 7:16 am
      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
      check it here: