Custom Filter Designs
  • Screenshot 2015-01-25 16.14.43.png
    674 x 389 - 97K
    afta8.SVFilter.audulus
    28K
  • Screenshot 2015-01-26 21.18.29.png
    751 x 258 - 87K
    afta8.LadderFilter.audulus
    24K
  • Yay! You're using the unit delay :)
  • Yeah finally figured it out :)
    Fairly essential for filter design ain't it!
  • Yep! Maybe we should talk about how it is important in the documentation? All I've got is:

    "The UnitDelay node is a single-sample delay. Like the #FeedbackDelay node, the UnitDelay can be used to determine where a delay occurs in a feedback loop.

    The presence of a UnitDelay node in the patch causes Audulus to switch into single-sample processing mode. This requires considerably more CPU. We are working on a way to improve that."
  • Yeah I think I asked about this a while back but I still don't know exactly what it's useful for?
  • 1.waveformview.jpg
    763 x 291 - 46K
    2.sampleview.jpg
    768 x 286 - 40K
    3.simpleLP.jpg
    516 x 403 - 17K
    4.simpleLP.jpg
    1173 x 518 - 52K
    5.simpleLP.jpg
    1077 x 439 - 44K
    6.simpleLP.jpg
    1007 x 479 - 40K
    7.simpleLP.jpg
    938 x 427 - 35K
    8.LPequivalent.jpg
    637 x 307 - 23K
  • Ohhhhh. Unit delay == get y[n-1]. That makes it click for me. Thanks, @afta8!
  • This is excellent, @afta8. Very helpful. Thanks.
  • @jjthrash and @Al_Thumbs, thanks for the feedback and glad you find it useful.. Go forth and make ze filters :)
  • Very clear explanation and an elegant solution. Thanks.

    I'm trying to wrap my head around this. So what you're saying is the UnitDelay gives you access to the immediate future, to the sample that will play next. Can I use it to make a compressor?

  • @JDRaoul, @afta8 will have a better explanation, but I'll try, just to help my own understanding advance.

    I think the unit delay gives you one sample in the immediate *past*. But that means the current sample is the immediate future from the unit delay's perspective.

    So, with 1 sample of latency, I think you could build a compressor to modify the output of the unit delay, based on the output of the input signal.

    E.g.
    input -> unit delay -> compressor -> output
    v---------------------^

    Or something like that.
  • @JDRaoul.. Thanks!

    The Unit Delay gives you access to the immediate past as @jjthrash has described. A sample in the immediate future would be described y[n+1] using the same terminology.

    Regarding a compressor I think you would need to use one or two envelope followers, maybe coupled with slew limiters to smooth the signals. Compressors work on signal levels over longer time periods and not at a single sample level so if you do something like what @jjthrash has mentioned then you would actually be doing waveshaping/distortion.
  • Incredibly thorough! Thank you - as soon as I saw that upclose picture of the waveform you made I slapped my forehead and went OF COURSE! Thank you! This is a great post for posterity.
  • "Can I use it to make a compressor" is my default question.
  • @JDRaoul, can't you use a crossfade to make a compressor somehow? ;)
  • @JDRaoul hahahaha yesss! Speaking of which can someone build a brick wall limiter to prevent ear damage with headphones?
  • @biminiroad a simple distorting limiter would be a math node with expression "abs(x) > 1 ? abs(x)/x : x"

    If you wanted to limit to a specific value, you could use "abs(x) > lim ? abs(x)/x*lim : x"

    But I'm guessing you're thinking of something significantly more sophisticated.
  • @jjthrash naw not something for audio processing something merely for safety - I've zapped myself a couple times on accident prematurely hooking up a really hot oscillator to the output. Will the math node do that then?
  • I was thinking: what if you could do unit delays within the Expr node? What would the syntax be?
  • @Taylor

    @ - unit delay happens "at" this point
    ; - unit (tittle) is delayed (comma)

    only single-character ones I could think of
  • lol @ JDRaoul... But you have got me thinking

    @biminiroad, I'm pretty sure the range node will give you a hard limiter/clip distortion, you can also stick everything through a sine node which will give you foldback distortion on overloaded signals

    @Taylor, how about using square brackets to select a position in the buffer of a particular input variable, therefore the expression for the simple LP would be: ((1-Fc)*input)+(Fc*input[-1]) this way you could also implement a Biquad using the expression node
  • +1 to above!
  • @afta8 I think it would be (1-Fc)*input + Fc*output[-1], right?
  • @Taylor, yes you're right, my bad... so you would still have to wire the output back into an input.. Hmm, not sure if that's any better than what we have now..

    Btw question about unit delay node if I have two in serial will that give me y[n-2] ?
  • @afta8, I'm afraid not. I just tested it at the code level and it didn't work :-\. It's a bug, because you should be able to chain two unit delays and get y[n-2].
  • @Taylor...."Expression Node? What would the syntax be?".....
    Just as the variable "e" (= 2.718) is a pre-assigned variable in Audulus, why not do the same with z^(-n), where that entire sub-expression is pre-defined. This would then also account for higher orders of z, i.e., cascade delays, as well as being a mathematically correct notation.
  • @BTL, that's problematic because currently z^(-n) is a valid expression.
  • .....and with the same thought in mind, why not also allow the user to select the order, "-n", of z when selecting the unit delay node?
  • But how about if it was restricted....is "e" not restricted?.....I'll check.
  • You could use a function. E.g. z(-2), z(-1). Non-negative inputs could just return 0.
  • @Taylor,
    If I create a math exp. Node of simply "e", I get the expected result, 2.718, at a connected value node. If I then create an expression of "d+e" , I do not get an input for "e" on the node, only for d, and if I set default of d=1 on the input, I get the expected 3.718 at the output.
    We could apply the same logic....when z^(-n) is present in a patch, all "z" variables of that form are restricted to that meaning.....this is not uncommon.
  • @BTL, yes, e is a reserved word. The problem is making z also reserved will break existing patches.
  • jjthrash's idea is also good, showing in a sense, "z as a function of the negative nth order", and that construct is not currently defined in Audulus.
  • ....non-negative inputs should return an expression error, as we can not predict the future....;-).
  • @Taylor,
    The more I think about it, the more I like jjthrash's idea. If you later decide to add functions, f(x), to Audulus, the z(n) function would already be reserved and, therefore, not done in hindsight where it would break patches.
  • @BTL, @jjthrash, yeah z(n) is good because the parser knows how to distinguish between a function named z and a variable named z. Could make for some confusing expressions, like z(-1) + z but at least it's fully backwards compatible.
  • @Taylor...sounds good....and how about allowing the user to select the order of n when selecting the Unit Delay Node....is that doable?
  • @Taylor, would it be possible to have single sample mode only run within a sub patch where a unitdelay node is present? Or even better, have it only apply to it's input signal? I'm guessing that this wouldn't work, but I don't exactly know why. Is it because it needs to receive a single sample at a time and therefore every signal in it's input network needs to be single sample? If so can single sample mode only apply to it's input network?
  • @BTL, yeah that should be doable (good point!). I'll put it on the list.

    @ceilidhshipley, good question! I think implementing single-sample in sub-paches only would be hard to implement, given the current architecture. Also, it might not be good to have a sub patch which consists just of a unit delay not act as a unit delay in the outer patch.

    When I first implemented the UnitDelay, I tried to write an optimization where only a minimal part of the patch is executed in single-sample mode. This turned out to be really tricky, so I compromised and just ran the entire patch in single-sample. But the plan is to work on that again.

    Eventually, I'd like all feedback loops to be delayed by just one sample, but that might cause performance problems, even with the above optimization.
  • Just found this thread and tried some things out in Audulus 3:
    _FilterDesign2.audulus
    716K
    _FilterDesign3.audulus
    386K
  • Transistor ladder module:
    _FilterDesign_ladder.audulus
    924K
  • @Taylor: Revisiting the question about syntax for unit delay, perhaps borrow from Faust: A single quote indicates a unit delay and an @ followed-by-an-expression represents multiple units. Simply putting x' would represent a unit delay. x@2 would represent a delay of 2 samples. x@n would be a delay of n samples.

    From the Faust reference: "Time expressions are used to express delays. The notation x@10 represent the signal x delayed by 10 samples. The notation x’ represents the signal x delayed by one sample and is therefore equivalent to x@1." (page 24 of http://faust.grame.fr/images/faust-quick-reference.pdf)

    I think that's straight-forward, elegant, and would not conflict with existing expressions.
  • @intrinsic - thanks for the suggestion - would love to do unit delays in-line like that.
  • What an amazingly great example, and how simple an explanation for what a LP traditional filter is. Even simpler than explaining a passive RC. Thanks for the great explanation, very well explained and an eye opener. Custom filters is what gives synths character, and this opens up a huge number of options to shape sounds.
  • As a learning curiosity, would a HP filter then calculate the low pass value (Afta example), and instead of just sending that, would send "a" minus the calculated LP value? I am guessing that would delete the slower moving waves.