1. IMPORTANT:
    We launched a new online community and this space is now closed. This community will be available as a read-only resources until further notice.
    JOIN US HERE

decoupling a filter from pitch in a karplus-strong delay line

Discussion in 'REAKTOR' started by meatwalker, Feb 20, 2007.

Thread Status:
Not open for further replies.
  1. meatwalker

    meatwalker Forum Member

    Messages:
    49
    hi. i notice that if i put a filter in a karpus-strong delay line it alters the pitch. i know why it happens since a lowpass is at the basis of the algorithim. i don't really understand how the tuning works within the karplus-strong but is it possible to decouple a filter from pitch with out getting into too much detail?

    im asking cause synths like steampipe have interesting controls like the allpass filter and the lo and hi passes in the delay line but its difficult actually use these in a melodic passage because they make the synth go out of tune.

    what would be a method to decouple these filters from the pitch? the only thing that i thought is if i could predict how much the filter would alter the pitch i could pass it through a module to tune it back corrospondingly. any hints on how this could be done or other there any other methods or resources u can suggest??

    thanku
     
  2. colB

    colB NI Product Owner

    Messages:
    3,969
    In KS, the pitch depends on the length of the delay line. Filters introduce phase delay - in effect this alters the length of the delay line in turn altering the pitch.
     
  3. Robin Davies

    Robin Davies Forum Member

    Messages:
    280
    A digital filter introduces a slight delay. Usually, the delay is described in terms of "phase delay" (delay in terms of phase shift for a particular reference frequency). For your purposes, you would be interested in the delay in samples (which will also be a function of frequency).

    You *can* compensate for the delay introduced by the filter. But it will require some heavy math lifting, because most of the existing literature is concerned more with phase delay rather than absolute delay. I'm not sure can think of an easy off-the-shelf way to calculate what the delay would be.

    I can suggest a general approach to try (with no guarantee that it actually works), but you'd have to take care of the details.

    Phase delay in IIR filters is difficult to calculate; it's much easier to do with FIR filters. The general plot summary: use the FFT design method for FIR filters. Start in the frequency domain with a 32-bin FFT of the filter. Set the amplitude appropriately for each bin. Then adjust the phase so that the sin/cos pair for the bin reaches 1 at 16 samples. (i.e. line up the phase of each bin at 16 samples of delay). Use an IFFT to convert to time domain. The result will be real coefficents for a 32-tap FIR filter with the frequency response you set in the bin amplitudes.

    With this filter in hand, you can the adjust the KP delay line by subtracting 16 sample from the delay length. When you feed it through the FIR, the effectively delay will be correct.

    Let me know if you're interested in this approach, I can supply more details. Implementing this approach in reaktor would be *TOUGH*.

    An alternate approach: start with an existing filter. Take the impulse response of the filter. Transform into frequency domain with FFT. Phase bash (line up the phases). Convert back to FIR parameters with IFFT.
    If you're handy with a programming language, a good approach would be to use a programming language to build pre-cooked tables for a pre-selected set of filter parameters. In a high-level language, it's not that hard to calculate these tables. Write a program that writes table data to a text file, and then import the table into reaktor. That's the approach I've used a lot when dealing with complex initializations in reaktor.

    fwiw, design methods for FIR that yeild "constant phase delay" will produce results that are equivalent to the technique given above (phase alignment at filter_length/2 samples).

    An alternate approach: calculate the absolute delay of an IIR filter at your target frequency. Subtract that amount of the delay line length. This will give you correct response at the fundamental frequency, and slightly skewed response at harmonic frequencies. But most real instruments have slightly skewed harmonics as well, so this may not be a bad thing. Unfortunately, this will be pretty tough going with the pre-built filters, since there's no documentation on how they were constructed. I'd have to do some serious thinking about how exactly to calculate the exact delay; but it's probably not that hard to do if you can get your hands on the IIR filter coefficients.

    Pretty tough going in Reaktor, either way.

    Maybe someone can suggest an easier way.

    Actually... an approach I *have* seen that's relatively easy: use the filter as is; and then use a table to make hand-tweaked tuning adjustments for each midi pitch. Add or subtract a pitch adjustment from the table from the intended pitch before feeding it to the KP unit. That's easy. And it produces good results. The downside: you have to rebuild the table by hand whenever you change the filter.
     
  4. CList

    CList Moderator

    Messages:
    3,299
    I'm not exactly sure what you hope to achieve by having the filter inside of the delay line, but couldn't you:

    1. Put a filter after the whole thing if you want a "filtered sound".

    2. Try one of the "phase linear" filters that you'll find (as a core macro) in the cross-over section of Flatblaster2. You won't have any resonance with this type of filter, but it does act as a 1-pole HP/LP filter without changing the phase of the input.

    - CList
     
  5. meatwalker

    meatwalker Forum Member

    Messages:
    49
    hmm i probably should have mentioned im an idiot so i guess its basically impossible i am having trouble with the basics of reaktor so i think if u guys dont know how to do this i dont have a chance

    clist: steampipe already has 1 pole hp and lp filters in the delay line by default and they still make the pitch change. i couldnt find the filters in flatblaster - do u think they are the same?

    robin: with the quick fix you suggested (with the table) would i still be able to sweep the filter and maintain a constant pitch?

    is it impossible to have a filter that compensates for its own delay?

    i think if someone could figure this out it would be totally awesome it can make the karplus strong synthesis much more interesting and usable
     
  6. CList

    CList Moderator

    Messages:
    3,299
    It's only in Flatblaster2.
    I started doing a whole explanation of where to find it in the structure, but it's easier if I just post it.
    Note that it takes a FREQUENCY not a PITCH - you might need to do a conversion.

    The corecell is attached. The Lo out is the LP filtered input based on the frequency setting, the Hi out its the HP filtering of the input based on the same freqeuncy.

    - CList
     

    Attached Files:

  7. CList

    CList Moderator

    Messages:
    3,299
    Note that my knowledge of DSP is nothing compared to Robin's so I have no idea if this will work or not! ^_^

    - C
     
  8. Chet Singer

    Chet Singer NI Product Owner

    Messages:
    822
    Robin explained it well. Compensating mathematically for the filter's delay is a daunting task.

    Steampipe takes a one-knob approach, subtracting samples from the delay line. It works pretty well, I think, as long as the cutoff frequency remains fixed.

    But it becomes more difficult when you realize that you often want the filter's cutoff frequency to vary along with the note number. This is especially true when modeling acoustic guitars, so that the low notes aren't unnaturally bright.

    Yamaha's VL solution was to build use piecewise-linear tables for both filter cutoff frequency and pitch compensation.

    An alternative would be to use a 2-dimensional compensation table, addressed by both filter cutoff frequency and note number. Then, the brightness could be varied without affecting the pitch. Because Reaktor's tables do both X and Y interpolation, not _every_ frequency or note need to be tuned. I built a KS ensemble with that feature once, but tuning it became so tedious that I lost interest before I was finished.
     
  9. Robin Davies

    Robin Davies Forum Member

    Messages:
    280
    Maybe..... Chet's post about Yamaha using peicewise linear interpolation from table driven data looks encouraging. But I'm pretty sure that the Yamaha guys would have actually calculated the table. Populating the table manually might also be a bit challenging. If you're trying to do note-by-note tuning, then it's fairly easy to adjust the table values (see below). If you're trying to populate the tables based on something other than MIDI note-by-note values, you'll have to come up with an ingenious way to tune the values against a reference pitch (see below). If you want variable resonance on the filter as well, manual tweeking will be out of the question. 2D table-driven conformal maps for filters get very complicated, and I don't think you'd be able to build one of these manually.

    Another interesting ensemble to look at is Cathedral Flutes. This is the ensemble I mentioned that used manual tuning tables. In this case, the ensemble is using physical modelling to generate flute-like tones. The basic mechanism is very similar to KP: a tuned delay line, with one of three sets of selectable fixed filters in the middle. What you might find interesting is how the tables were populated. The really cool thing about this ensemble: look for invisible macros around the internal tuning table. Make these macros visible, and look on the B view: voila! the reaktor UI that the author of this ensemble used to tune the pipes (including a small peice of instrument that plays reference pitches so that he could tune the instrument pitch against a reference tone). If you're going to go the manually populated table route, definitely look at this ensemble. Must have been a lot of hard work though.

    You might be able to use the same approach: one or two or three sets of hand-tuned filters. You could get away with fixed sets of filters from which the user can select two or three "instrument responses".

    In the meantime, I'll do some scribbling to see if I can think of a simple way to calculate the phase delay for a signle frequency in an IIR filter. Truth be told, I know the theory of this stuff in very general terms; translating general terms to actual implementable solutions is a challenge for me. ... I'll let you know if I think of an easier way. But don't hold your breath. This one smells like a really challenging reaktor problem.

    If you're able, precomputed tables would be a great way to go, esp. given Chet's posting about Yamaha's approach. That says that it can be done. And it also says that some very very good audio engineers used table interpolation to get a workable solution.
     
  10. Robin Davies

    Robin Davies Forum Member

    Messages:
    280
    Actually, scrath that last reply altogether. If you're going to allow configurable filters inside the KP delay line, then you'd use a different approach. In the previous method, you do fine tuning on the pitch of each note on the final instrument, with the filter in place, and place the fine-tuning parameters in a table.

    If you plan to use a configurable filter, then what you really want is a table of phase adjustments for a given cutoff frequency, for a given fundamental pitch. (e.g., what's the delay line adjustment for cutoff frequency 1200hz, with an input pitch of 440hz. That's a 2D table. Much more difficult, and you're definitely not going to be able to build it by hand tuning.

    To give you an idea of what you're up against, here's a test harness for plotting filter phase delay and response for a filter under test. (attached). You'll have to edit the structure to put another filter under test. I've been meaning to do this for a while just to see how some of the libary filters behaved. (Glad I did. I learned a lot. I'm going to be using the 2 Pole SV T filter a lot from now on).

    btw, the FlatBlaster2 filter doesn't seem to have linear phase delay (I don't think), except at cf = SR/4. (My guess; the analog prototype was linear phase, but the digital implementation isn't).

    I'm guessing that you'll need to go the FIR route, right now.
     

    Attached Files:

  11. CList

    CList Moderator

    Messages:
    3,299
    Ah, I see. I had only tested it in relation to a cross-over where you are splitting the frequencies and recombining them. After doing some more tests just now, I see what you mean, and I see that it's just phase-matched between the input and the *sum* of the HP and LP outputs, while the standard HP/LP filter does not have this behavior.

    Thanks for clearing that up...
    - CList
     
  12. Robin Davies

    Robin Davies Forum Member

    Messages:
    280
    Hey, that's a very cool trick. I get it. <files that away for future use>
     
  13. meatwalker

    meatwalker Forum Member

    Messages:
    49
    okay this is a really cool little ensemble you made.

    would it be possible by using this module to connect to another filter and somehow phase all the other frequencies corrospondingly so the absolute signal is not phased at all?
     
  14. meatwalker

    meatwalker Forum Member

    Messages:
    49
    has everything you've said so far apply also to the diffusion delay?

    steampipe has a DifDel H module in the delay line and it has the same effect on the frequency of the signal as a filter does.

    wondering if it might be more straightforward to pitch correct this one..or not?
     
  15. meatwalker

    meatwalker Forum Member

    Messages:
    49
     
  16. Robin Davies

    Robin Davies Forum Member

    Messages:
    280
    I really need a disclaimer: my DSP skills are far from solid. I'm a half-informed amateur, and a real pro would consider me an idiot. What follows is my best guess. A real DSP guru might reach different conclusions.

    Was doing a little reading today on the topic. The magic search phrase on google would be "constant group delay" (an exactly description of what you really want: it means each frequency gets delayed by the same number of samples).

    Speaking from bitter experience, filter design from scratch is really tough. No question that this is a tough problem. There are journal articles on exactly this topic on the ieee/acm sites ($$), that pretty much confirm that "approximately linear phase delay IIR filters" are a Hard problem.

    Here's the net result of my reading today. No answers. But some interest clues, and some indications as to the difficulty of each of the approaches..

    (1) "constant group delay" is the technical term for the property you need in your filters. Google for that.

    (2) IIR filters cannot have constant group delay. However, there are design techniques for generating IIR filters with "minimal" group delay. Most of these seem to be iterative techniques (hard to implement in C++, virtually out of the question in Reaktor, unless you use pre-computed tables, generated outside of reaktor). A tough road, I think. Although it's still possible that you might find a magic bullet.

    (3) A possibility method: (ties directly to your previous question). One approach to designing minimal phase IIR filters is to design an IIR filter, and follow it with an allpass filter with variable phase that compensates for the phase delay of the IIR fitler. I can't honestly say that I know how to do this. I couldn't find a cookbook recipe for doing it with IIR+IIR filters, although I know how to do it for IIR+FIR. Not a bad result: the flexibility of IIR filters, and the FIR all-pass phase adjustment filter is hard, but not poisonously so. Sweepable filters are out of the question; but compute-once at initialization time solutions are hard but doable.

    (4) Calculating phase delay of an IIR filter in advance requires matrix algrebra. But it may devolve into an implementable form for O(2) IIR filters. Not sure how to do this. But it looks doable. The strategy of calculating the group delay (in samples) at the fundamental frequency, given a set of IIR parameters may work. My *guess* is that you would need to use a butterworth or Chebychev(II) filter to get passably constant group delay at harmonic frequencies (and that you might be able to find a butterworth reaktor filter, but definitely won't find a Cebychev(II) filter). Hard, but survivable. I'm not honestly sure whether the results would be musical.

    Anyway. Here's my (not totally reliable) read of the situation. IIR solutions are capital-H Hard problems, although good audio engineers might be able to solve them. Definitely requires good grad or maybe post-grad level mathematics.

    Did I mention the FIR solution? <grin> I think you could do some pretty cool things with an FIR solution, and the performance will be ok. You can safely include a per-voice 32-tap FIR in an instrument and still acheive decent peformance in realtime. The big challenge is getting the FIR coefficients set up. The rough plot summary: a 16-bar adjustable bar graph picture thingy for frequency respose (adjustable bar-by-bar using the mouse); and, possibly, a 16-bar adjustable bar graph/picture thingy for non-linear phase adjustments, since real instruments actually do have non-linear phase too.

    The general implementation: feed the frequency response parmeters. and suitably adjusted phase parameters into a 32-sample IFFT, yeidling a 32-tap symmetric FIR. Window it to prevent clicks (hanning window, probably) to prevent clicks. The resulting FIR will have a 16-sample group delay for all frequencies. Subtract 16 samples from the length of your fractional delay line. Would probably be quite an interesting instrument.

    If you're interested in pursuing this route, I can give you further details, and theories as to how to compute the IFFT at initialization time, get the paramters into the FIRs, how best to implement FIRs in core (bucket brigade, not arrays, for optimal performance), &c.

    And a very good question, now that i think of it: how *did* steampipe do it?

    Anyway. I hope that was helpful rather than overwhelming.
     
  17. Robin Davies

    Robin Davies Forum Member

    Messages:
    280
    Honestly, I don't know. Maybe just swipe that module verbatim. Not at my reaktor machine, so I can't look at it.

    There is, of course, one more possible solution, that has a long and venerable tradition in Reaktor: scroow the theory, connect everything to knobs, and tweak until something interesting happens. (plus knobs to tune each individual note). And that's not totally unreasonable. KP is a bit of a seat-of-the-pants approximation of physical modelling, anyway. I have seen papers on adding 2 or 3 taps in the delay in order to approximately model, in a seat-of-the-pants kind of way, properties like damping, and string stiffness. That's essentially the same thing as a 3-tap FIR. If you convert that three tap FIR to a 5 tap symmtric form, you'd get constant group delay (no more need to tune), and 5 taps (three knobs) might just give you enough control over the instrument to be interestig. :p Just to make it clear, a 5 tap symmetric FIR has weight parameters, and knob2 => a[0] = a[4], knob1 => a[1] = a[3], knob0 => a[2] (maybe normalized so that damping is easier to control). That filter has a constant group delay of 2 samples. (<--- thinks that's a really good idea).

    THere are no FIR filters in the library. The basic filter implementation is very simple, although calculating the filter paramters is not. I'll take a crack at it this evening, for the fun of it. I think can whip something together.
     
  18. kid_sputnik

    kid_sputnik NI Product Owner

    Messages:
    3,552
    fwiw, i think gabriel mulzer (lxlnt here on the forums) posted an FIR filter for use in waveguide PM, in one of his packs of corecells, although i really dont remember what the upload was called.
     
  19. meatwalker

    meatwalker Forum Member

    Messages:
    49
    is it necessary for a fir filter to be controlled by a bar graph? (like a graphic eq?)

    would the filter still be sweepable (even if it meant just making a control to crossfade through all the bands) ? and is it possible to get more than 16 bands? this sounds like a good option so far. i am not really sure what you mean by 'taps' in the filter and how it relates to taps in the delay line

    what do you mean by that?

    sorry i don't really understand any of this. i actually don't know the KS implementation very intimately or the filter either. can u perhaps point me to a resource to better understand what u are talking about?

    anyway im really pleased that u have taken an interest in this topic u seem exceptionally competent really looking forward to seeing what develops all information u can provide is highly appreciated

    thanks friend :)
     
  20. Robin Davies

    Robin Davies Forum Member

    Messages:
    280
    No. There are other ways to specify parameters for a FIR filter than a bar graph. The algorithms for converting conventional things like filter cutoff frequency, and resonance, for FIR filters, are computationally very expensive, and would be very difficult to implement in reaktor.

    The idea behind the Karplus Strong algorithm is that you're loosely modelling a physical vibrating string. In the original algorithm, there's a very simple filter at the end of the delay line, and the output of the filter gets fed back into the beginning of the delay line. And that's sort of the main benefit of the Karplus Strong algorithm: that the filter is the simplest possible filter -- just blending consecutive values together -- but it still produces a string-like sound. Physical modelling synths that model vibrating strings would put a much more complicated filter there instead -- in phi-mod, the filter would try to more realistically model the effect of (for example) air damping on the string, stiffness of the string, coupling of the string with the bridge of the instrument, and resonance of the body of the instrument. The Karplus Strong algorithm uses a very naiive filter, that loosely models damping (not very accurately), but -- suprisingly -- it still produces interesting results. Classic Karplus Strong is used because it's easy, it's fast, and the sounds are fairly good. The point, though, is that typically you wouldn't want to sweep the filter, because the fixed filter in both cases is (to a greater or lesser extent) modelling charactersitics of a real instrument that don't change over time.

    I have seen a paper on an "Extended" Karplus Strong algorithm that uses a slightly more complicated filter to good effect.

    http://www.acoustics.hut.fi/~vpv/publications/cmj98.pdf <-- easier

    http://ccrma.stanford.edu/~jos/pasp/Extended_Karplus_Strong_Algorithm.html <--harder



    You could place swept filters outside of the Karplus Strong unit, on the output (after the feedback point). That's a reasonably sensible thing to do. But that's really different thing that sweeping the filter *inside* the delay loop. You could use pretty much any old filter outside the delay loop.

    If you're determined to sweep the inside filter, you *could* sweep the FIR filter, but once you do, you're really straying pretty far from the spirit of what the Karplus Strong algorithm is. The proposed FIR filter *could* be swept but it would be a very expensive operation, computationally. In the proposed method, you would have to do a 32-sample inverse fourier transform each time the filter design inputs (or the bar graph) changes. Not going to run well in realtime.

    However, the proposed FIR approach *would* allow you to calculate the filter at initialization time (with some difficulty). i.e. you can connect a knob (or other UI element) and change the parameters, on the understanding that you can't really do it on a note that's already playing. You wouldn't need precalculated tables. But attempts to change filter parameters while the note was playing would be pretty glitchy, just because it would take quite a while to recalcualte the FIR co-efficients (probably 64+ samples clocks).

    With respect to the question "could you use more than 32 taps/stages"... Yes. A little bit more. A 32-stage FIR filter requires 32 multiplies, and 32 adds for each sample, for each active voice. That's a fair bit of work, but most computers can keep up with that without too much problem. But, if you were to go to (say) 256 stages, I would expect that you would max out even fairly good CPUs. FIR filters require many more stages than IIR filters. A 32-stage FIR filters is pretty good quality.

    No problem. Happy to share the pain, and pay back some karmic debt. Just hope I'm not innundating you with too many details. Or turning you off. It's sort of the nature of the beast, in audio processing stuff. Some things are very easy to do. Some things that should be very easy to do are wickedly difficult. Unfortunately, you've stumbled across one of those cases. (Most non-off-the-shelf filter design problems fall into this category). If this is overwhelming, then please read everything so far as "no, you can't really do that", and move on to other problems that easier to tackle. There's lots of easy stuff. Sometimes the trick is to know when to look elsewhere. Truth be told, I found the question an interesting one, so I probably gave you a pretty hefty chunk of "stuff". This is a problem that would push my skills to the limit.

    Kinda of easier to explain with a picture than words, but here goes. A 'tap' is a point at which data is taken out of a delay line. A multi-tap delay line would use one delay line, but the output of the unit might be 0.4*(a sample delayed by 412 sample clocks) plus 0.6*(a sample delayed by 413 clock cycles). That's two "taps", one at 412, and one at 413 samples into the delay line. An FIR filter is a actually a very short delay line (32 samples in our case), with 32 "taps", delayed by 1, 2, 3, 4, 5, ... 28,29,30,31 samples. Loosely a 4 stage (or 4 tap) FIR filter looks like this:

    output = currentSample * a0
    + delayBuffer[1] * a1
    + delayBuffer[2] * a2
    + delayBuffer[3] * a3;

    (where a0, a1, a2, a3 are the FIR filter parameters, usually pre-computed). See the attachment for an example of what this looks like in Reaktor.
     

    Attached Files:

Thread Status:
Not open for further replies.