[BUG] filtercoeff + biquad = less accurate than lists + biquad
Usually when you use signal domain control, it’s because you think it’s more accurate than using max messages, and that your sound is going to sound smoother, etc.
But here it’s just up side down : In my example patch attached, using filtercoeff~ -> biquad~ is less accurate than when sending max lists to the biquad~, this, in any situations.
But before, here, there is a strange fact about all max filters (which is not a bug), that I just discovered and I have to explain it first :
Normally when you send a signal to a signal object, you suppose that this signal object is "listening" to the whole signal, each sample… but for all standard msp filter objects, in fact, they don’t. I realized this while accelerating an LFO on the biquad frequency, with a high Q value (using noise~ as source) : Except of course the source sound on their first inlet, Biquad~, lores~, reson~, svf~, onepole~ are in fact just "listening" to their own signal inlets only once per signal vector**. I imagine this comes like this for efficiency reasons. And then some of these objects (are supposed to) smooth these vector-spaced input data, with a ramp, during the signal vector : Biquad~. And some others don’t smooth the data: lores~, and also cascade~. (for the others, i didn’t test if they smooth of not) After complaining about this "vector-limit" in an other topic ( http://www.cycling74.com/forums/index.php?t=msg&goto=178433#msg_178433 ), i finally found that, as i don’t specially love the sound of ring modulation and fm-like-synthesis and then will not want LFO on the filter frequency more than 20Hz, and while staying at short signal vector size about 128, that finally this won’t be an issue for me… hmm, this is not an issue for biquad~ because it smooth the coeff data, but it can be an issue with lores~ or also cascade~, as they don’t smooth anything during the vector !!
But let’s go back to our bug, now :
So while testing with filtergraph.maxhelp, I found that Biquad~ is smoothing these coeff data during one signal vector.
Then after, in filtercoeff.maxhelp, i found that this time, biquad~ doesn’t smooth anything, but change suddenly the coeffs at each vector.*** What is strange is that when I delete some of the 5 patch cords between the filtercoeff~ and the biquad~, then the biquad~ is sometimes smoothing again.
See example patch attached.
** And I’m then wondering about the utility for the filtercoeff~ object to have four signal domain outlets… one simple outlet sending list messages to biquad~ (at each vector), would be more efficient than that.
*** The use of the smooth attribute in biquad~, found in the doc, doesn’t seem to produce any effect on my MacBookPro/Os X.5.7/Max 5.0.6
Alexandre wrote on Fri, 31 July 2009 08:40
But let’s go back to our bug, now :
not a bug precisely but maybe a little ‘underdocumented’.
use the resamp (int) message to make [filtercoeff~] output more often (see patch below).
----------begin_max5_patcher---------- 2189.3oc6bkrbahDF9r7SAQ0bXlDG6dkkop4v7HjKykTob0B0RlYPfF.4jLo hd1GnaPBrXoYQXvkuHa1+9+5+sd6+G2rX4J+uwCWp86ZeVawhebyhEhSkbhE oGuX4N12rcYghaaoG+q9q96k2JuTD+aQhSay1GcHfeTaiFD..Z5Y2wFeuHO1 Nt3t9KdvZlGK6Z6YQ1O53s8g.tcjDDTh0cfa0vPXxefPTxePf6.ZeI8gbVKd Uwf3iDP1ax6vNGOWdj.ivbe5Pm+S7oEuuS2q+gnraFjbxedyMI+b6zfCLQRJ vTAJ.a9xPA1961w8htfCB4QZQO5Dp8Dy8.WKxWCl7y13S6uOxYGyUaOOXiev NlmMO6wcc7319G7DuCT2XMccAcgE5OPpP+Aiqf0LdYXsH+sac40HDHhQBtoI .W1nWSSOsVgnHZyNq7TQeeOW9AW5jP5eoKFAG1shGzQUbHPnUCMEMSzZkSzI U7Uas8c8CReEIOC3NjkI.ak++f4dMcu4EUGgcq1xULuscj3J26wFG2HdfsOe yliZt9ecex82M1EQk9LzAROHV0RuvRUivsgrnUQVgNa8XtI7kR+Wm3yMt9wn oiTEFIbaPHMqGpiWd8zphEB10Qu5CGikH.ne7CjHBFoWKAQJ2gDpMDDrAMog jYd+wXGP8lYfTgpiYsLi97hYr+tsKOQuoebigHXlArNpgNynl3W4QMZG4Ehk TmQ5elnWa3cR+c2LlDyJm+8.a8wRYl+LvIwOe05KloY8KoGjQsDCpThQubhg ZQglFu3rydMalqcWUaff7wyAzZoGX+MnFt344EJdPJukRbKRx4g+DOHzw2KW Cxhk4xpOMviLOQcgZhtYtT7RxJz029e3BF.jcx07Ms5k3um6c9A.xbKy8Sw6 zwae.OLt+OrnTnm+CyN3F8P47bwqugYyq7gqP+XwxsANq88RfQgmM4zYev3r ioRGM4Qt3N7X6K4gi78cWwBdxIzYkKuPaQr5NyKtiaQ73tuItTb5DYWzY29. GY21Nctc7H1ZVDSBjbsS4GpgbZAELoJb95LsJZd8t6iS6O+UpiAqJqYfnSWP cQtf3KLxdtglY92WY1Z0XuUs2n5ROT5PZQlSI4+baGYS42nANAmlXrkL8FZ1 uUwI55URJvJk77bR13Jj7BWN1RKxrkRKcVKsnVJsj4rzlZVqtzhmnRaMdAe+ w95BL0.fHGARzcz5cApCFQefExJaFPlY9NUkLoluQlM5rRYxz5MxrQegJSlF uQlUSlfVRl5udIy2c+QMXecaZJ5yEAKnUBnozvozWw74GO1+90fk8qgHmxEY PoZIT7qWB8CCAeZXI4SnTOsQ9jLy4yhy0aQBk4t+Ql1enE538qeE7a2id+m5 cZShbywoC1EsYG.HkxTWY9ELNph2ebXrqw5XEC7.eMGEWC0S5LMfCBKiiazn ZG3UrYcp4buMkSWIKnyyFTcTJwZVZIGGjFbGh1ayY4j1KmJDZigUHuhSJ21O bn7NJmRIrYizo4vp6MoLmi4yAvbFRv4VadJXNqOKMmG.kuzk2TJS0rxGDMyU 9ttcvV5XDp5fR950unqOasXABMHgZjwXzgkpc9ny50bumS.4stwinNatUE0n jL4GQ8d1DkYPRR67sdiNKAuMLFpLNaXKC0FFCzbebgTaZs.saZsPf43zZEme McXTeHxQWfzbH449DHr5PTjuWSdojd+szKe4leQed6fxyzwuNacXDK5PnVXP eUljiJETtHQLPMwaC7HphpiRSV9UmWT+CDqJ.rZCfhbmWnfmnJ4j9ZDMBdqT gOjtjkaniloC3TfNNuXsR1QNUrXsDhZx0KmmB8ODXmAhr40VqnbulGF43cZw y84yKdHspxBMOKryY8d+Xc7vrkXlRsrsE2IKtA0vMcRg6jo9VMbSlV31PUbi mT3FQUD2kHfJgaHDmzmWhbjogFmO5Z0RnrDkXwBmNZPspkXNhaq4ItEtRmi7 s4jB2DPa36Ijmcba36oCtgVswtbBw25JhaDXlx2SqLEoDUw8DKSQnp3lLSw8 zJSQpp9uEBXGh6PHhbCyVBMxcgo3nqUDIy1HQSnb1UE1SKGjDU6hDYhEHUU9 l.lm3FQmmcIENsRbQU+5Srv+Jh5oUvHhxIkWCrgi+nxoplMZZMXhp5.zXRAa yVXPNc5mL9BzTNpGxfjomLF9xc7dH6I95Gh+Jb6nGXQQANqNDIGR876.dk1w 20dwl1v4ktQyq5l255uh4lta8O8IWV6lW+lyLwXVBoPxxZD1zr4R2CFrb9UP nVyrO1Utw.KWfOoKYh53FHo+0KhtTKz1xb7NVqLH2lEnb0JEKZEx.tVYPwFx ykuhtWTzpnnwvcikK+fiZnS6Op12llWe2r1Z.BD0+Z50KR8FpyUiIjrlw.kq jAy58FLup3P8ov5jRKXnjctbyJUXgSZMkKrNUUwI+jVmXFprJ5Xk5joNdw.1 lnG0vKfgs510jHlUsojKA95iPZfFHYT4JbW58E+wb1EKfIzyccgf1wCCYa4W nWDvCY61q8Kv9UhJQx0vstz.xrhZnH4J5Ron4h3yWb4YHYommjbJWcYxwIcx lbRJpnqpI8dhd5ltHs3xSI9hVtVgIrJXhLtXBoBlviKlfpfIz3hIfJXBNZXB hU.SII9NIwDXzvDgpRaGbbwjtBX5Y.+ZiIjJ535Vip9DREeABLgFWLgTAS3w ESXUvDYbwDQELQmV9BPiqu.D4JfIXRBrwpoxIIMYEvmcTeQqoJncb8viQpD0 okYLfsLESyLUN+xTxoi5IZ0sTEssvOKBqmGsH3PgVnRbKdbauApxfiHlnSuL evJ6YAMsvzy5Bv0FSFpniiIie1XM1KHywUeRELUb0Mb0wDUoLo0GULoqRufn iKlvplb+zBR3V5EOKNXZsIHMFN.8r3fwG7ya9eXwZ0fN -----------end_max5_patcher-----------
i’m still wondering, why at ‘resamp 1′ the coeffs are updated only every second sample (according to [capture~]) and not every sample.
hum.. 6 years already using max, and sometimes this software is so mysterious :
One more observation i just made is that, as opposed to what I supposed, it looks like Biquad~ is the only filter to really "listening" to its signal parameters at each sample… …at the only condition that the five signal coeff inlets are connected to a signal patch cord !
Ok, so now, using "resamp 1" this sounds fine !
> why at ‘resamp 1′ the coeffs are updated only every second sample
it looks like a small bug: i just notice that ‘resamp 10′ makes 11 identical samples, ‘resamp 3′ makes 4, ‘resamp 2′ makes 3, ‘resamp 1′ makes 2. but anyway we can’t hear any difference.
After few hours on this, I just would like to suggest something to C74 team :
As there is so much objects in your soft, and as you didn’t think to write this important information about filtercoeff~ in the reference doc, which should be, i think :
"When instantiated, Filtercoeff~ only outputs coefficients at the rate of the signal vector size to preserve cpu; to have more precision, then send it a ‘resamp (int)’ message to select a new rate."
… Then you really should consider, one day, to put the whole doc on an OPEN wiki database… and we would complete it when we feel that it’s needed* !
* Here for filtercoeff, but there are many other examples of things that would be fun to have in the doc
I am pretty sure this is documented somewhere, although it might be in the SDK, which understandably many Max/MSP users never have reason to read.
The basic issue is efficiency. Most filters only sample parameter inputs once per sample vector. If you want the parameters updated every sample, you have to set the vector size to 1. Please do not be surprised when you see your CPU usage skyrocket.
As an aside: parameter changes that occur as Max events won’t be handled more often than once per sample vector, either. So I don’t know about "less" accurate.
(sorry double post – see down here)
Thanks Peter for your remarks,
> If you want the parameters updated every sample, you have to set the vector
> size to 1. Please do not be surprised when you see your CPU usage skyrocket.
Of course nobody should use vector size less than 128 or 64. If one want the parameters updated (almost) every sample, better use filtercoeff+biquad with "resamp 1", as Volker just showed, than any other filter, because we then can stay at any vector size we want, plus this "resamp 1" will change almost nothing on the cpu usage, unless we have hundreds of filtercoeff running.
> parameter changes that occur as Max events won’t be handled more often
> than once per sample vector, either. So I don’t know about "less" accurate.
You probably didn’t listen to my patch example (or does it sound different on your system??), or maybe my first post was not clear enough : You’re right that Max events are handled once per sample vector, but what I hear, from the biquad~ fed with Max events at each vector, is a "SMOOTHED" curve of the filtering frequency… while I hear, from the biquad~ fed with filtercoeff~, a curve in "STAIRS". Is that clear ?
I Understand that it’s kind of complicated : Strangely, Biquad~, the same object, output a smoothed result when receiving Max events, and output a result in "stairs" when receiving signal coeffs from filtercoeff~ ! ***
The filtercoeff~ will ALWAYS be less accurate (and less efficient) than directly sending Max events every vector to the biquad~… Until you send a "resamp 1" message to filtercoeff~… for it to become then the most accurate.
> ..which understandably many Max/MSP users never have reason to read.
I totally agree that it’s important to have simple, efficient objects that works fine in most situations without bothering users with complicated stuff. But, even if this is a Great software with greats objects, here, this is simply not logical at all, because…
…When are you going to use filtercoeff~ ?
-> This is when you want rather fast moves on your filter ! (if you need only few moves on the frequency, you will feel more efficient to use filtergraph->biquad or even snapshot->filtergraph->biquad if your input is a signal), And then the max users are going to use a "less accurate" object (because they don’t know about the "resamp 1" feature),filtercoeff~, which will make the biquad produce "stairs" on the sound, EXACTLY WHEN they had thought using a more accurate object !!!! This is what i meant by "the world up side down".
And after, you read topics here about "poor Max Sound quality", where people are wondering about the quality of the max filters, or aliasing, etc…
Maybe "that" could explain "this"…
*** And I maintain this looks like a bug or "forgotten code".
> for what you are trying to achieve…
I’m ok with the "max-evens->biquad~" way. I just made this topic to show that "filtercoeff + biquad" is less accurate than "lists + biquad" (…until you don’t find this "resamp 1" hidden feature)
> maybe smooth-biquad~ would be useful
if you listen to this "smooth-biquad~.help" from cnmat, you’ll notice that it doesn’t make any difference – with max-events – in the example, as it is supposed to. I imagine that when the cnmat wrote this "smooth-biquad~.help", few years ago, the standard biquad~ object was not, at this time, smoothed for max-events.
And then ok, it does make a difference, i just found it, replacing the biquad~, after the filtercoeff, im my example patch, by [smooth-biquad~], this will then do the same than max-evens->biquad~ without any "stairs".
So C74 team have introduced this smooth feature in biquad~ but, contrary to [smooth-biquad~], they only did the half job, they made it work only for max-event inputs… not for signal input. And as, by default, the signals input are going out only once per vector, in filtercoeff~, we then have a situation where the "max-evens" way of doing, as you see in my example, is more accurate than the "signal" way of doing… Making the filtercoeff~ object, in its default mode (without a "resamp 1" msg), totally useless.
|Alexandre wrote on Mon, 03 August 2009 14:35|
|You probably didn’t listen to my patch example (or does it sound different on your system??), or maybe my first post was not clear enough : You’re right that Max events are handled once per sample vector, but what I hear, from the biquad~ fed with Max events at each vector, is a "SMOOTHED" curve of the filtering frequency… while I hear, from the biquad~ fed with filtercoeff~, a curve in "STAIRS". Is that clear ?|
I confess I didn’t listen to your example; I was just trying to quickly address some general points about how MSP filters are (mostly) implemented.
Your explanation is quite clear, so I understand your concern better now.
The bigger misunderstanding on my part was that I was focusing on biquad~, where the main issue is filtercoeff~. Given that calculations filtercoeff~ performs are complex and expensive, it’s quite typical of MSP objects in that situation to only calculate once per signal vector.
biquad~, OTOH, has no idea where its signal inputs are coming from. No object ever knows where the patch cords coming into its inlets originate. So all biquad~ can do is "believe" the signal input. It’s cute that biquad~ interpolates between Max message parameters over the course of a signal vector, and that should be a very inexpensive calculation.
|Of course nobody should use vector size less than 128 or 64.|
There’s a time and place for everything, even for extremely small vector sizes.-!
Actually, the resamp message to filtercoeff~ is a bit like setting a really small signal vector size to that one object (not identical, but I would expect a similar rise in CPU utilization). Never mind the idiosyncratic behavior you observed with that message. That might be worthy of a bug report.
And, if Gregory is reading, it would be helpful if the documentation for the resamp message included a sentence or two explaining what the "resampling" is all about. I don’t think there is much in the documentation (outside the SDK) that explains the only-calculate-once-per-signal-vector strategy used by some MSP objects. So I agree with Alexandre that a bit more here would be welcome.
Thanks for clarification Peter,
(And also, sorry if i can be unpleasant on other topic, i’m a bit direct sometimes.)
> the resamp message to filtercoeff~ is a bit like setting a
> really small signal vector size to that one object (not
> identical, but I would expect a similar rise in CPU utilization).
> No object ever knows where the patch cords coming into its inlets
> originate. So all biquad~ can do is "believe" the signal input.
> It’s cute that biquad~ interpolates between Max message parameters
> over the course of a signal vector…
Hm, i didn’t think about that. Forgive me if i put a [BUG] title on the topic, in fact, this not-logical situation i’m talking about may not come from a "bug"…
You’re true, biquad~ just can’t smooth data for a period of a vector if it doesn’t know when is the next signal value coming !
And about [smooth-biquad~] from cnmat, i just found that it just smooth the data over the vector, then it’s is not really made to be used with this "resamp" option of filtercoeff~. Maybe C74 team could put this way of doing as an option on the standard biquad~. I even think it should be the default option, as almost nobody knows about the "resamp" feature.
Forums > MaxMSP