RobinSchmidt / RS-MET

Codebase for RS-MET products (Robin Schmidt's Music Engineering Tools)
Other
56 stars 6 forks source link

Need special filters for my BasicOscillator to solve a few problems #78

Open elanhickler opened 7 years ago

elanhickler commented 7 years ago

hey Robin, you don't need to do this now, but just think about it.

Issue 1: It would be nice to have filters that can go to 0hz, or like, it was a feature built in. It would also be nice if this filter have up to 4 poles. At 1.e-6 hz, for a lowpass the output value is pretty much frozen. For a highpass, there's essentially no filter. So you could do "if frequency is <= 1.e-6, disable filter" in the case of a highpass, or, in the case of a lowpass, do "freeze internal values."

Issue 2: Near-zero filtering for a highpass will freeze its internal values and therefore possibly output DC values. (the filter itself outputs DC value on TOP of DC input). To solve this I currently do a hard reset on the HP filter if cutoff is <= 1.e-6. I would rather somehow have the filter be in "continuous slow reset". It's difficult to describe the problem or the solution needed.

You'll have to play around with my BasicOscillator to see the problems, it's a lot of fun! I'll detail the problems when you are closer to having time for this and my BasicOscillator is available as an audio plugin / standalone build. I am perfecting it so there's the least possible chance of you getting noise explosions, while keeping the code as elementary as posible. It's very responsive and does what you expect. With one or two BasicOscillators you already have a huge amount of exploration and a nice synthesizer.

elanhickler commented 7 years ago

also, do you have a noise generator object i can throw in?

elanhickler commented 7 years ago

this is your reset code

template<class TSig, class TPar>
void LadderFilter<TSig, TPar>::reset()
{
  for(int i = 0; i < 5; i++) // later use: ArrayFunctions::clear(y, 5);
    y[i] = 0;
}

somehow, i'd want the y[i] values not to jump to 0, but to go to 0 over time, maybe over a few seconds of time.

you could call it slowReset() heehee. Oh but I'd be maybe calling this every sample... so it's continually slowly resetting.

elanhickler commented 7 years ago

I just tried to implement the rosic::noiseGenerator, is there a way to get a stereo signal out of the buffer? Seems like that was part of the intention.

elanhickler commented 7 years ago

chck out my thread on how im using my basicoscillator to create antialiased sawtooth: https://www.kvraudio.com/forum/viewtopic.php?f=33&t=490991&p=6870867#p6870867

RobinSchmidt commented 7 years ago

I just tried to implement the rosic::noiseGenerator, is there a way to get a stereo signal out of the buffer? Seems like that was part of the intention.

what makes you think so? however, i think, reading the table off with a pointer that is halfway delayed to the main read-pointer, one could create a nice (as in perceptually uncorrelated) stereo signal. i guess, i could add a function for that.

as for "slow-reset": i think, it could be done by setting a flag "isInSlowReset" mode, check that flag at each sample and if it's true, apply a decay to the filter's state variables in getSample(). after some specified number of samples (which depends on the slowness, i.e. the decay time constant), set the flag back to false

as for zero cutoff: have you tried that with the rapt-ladder? i just went through the design (coeff computation) formulas per hand with a zero cutoff and the coeffs approach the correct limit. the (per-stage) feedback coeff goes to one and the input coeff goes to zero - that should give a frozen output. each stage would just output the previous value (multiplied by 1) plus the input multiplied by 0. so it should actually work

RobinSchmidt commented 7 years ago

chck out my thread on how im using my basicoscillator to create antialiased sawtooth

not bad. a little noisy at high freqs, but that's certainly better than the ugly sound of aliasing. as for your claim that an analog osc would also be noisy, if the speed of light was comparable to audio sample-rates.....hmmm....dunno...maybe quantum randomness could inject such a noise

elanhickler commented 7 years ago

I'm getting some issues with RAPT:Ladder lowpass

a. 20,000hz filter cutoff still darkens the sound b. increasing LP order (using LP_6/12/18/24) as you go up, the sound darkens even more. c. increasing oversampling seems to change the cutoff slightly, seems like a related issue.

gaussian filter didn't have these issues.

Edit: just confirmed. Gaussain even with 1 pole is perfect.

RobinSchmidt commented 7 years ago

a/b: try sampleRate/2. just went through the formulas for it, the input coeff goes to 1 and the feedback coeff goes to 0, so the filter goes into bypass at fs/2 (when using the lowpass mode, that is)

c: hmm...at high resonance or low/no resonance? the formulas were derived so as to match the resonance frequency at high resonance - that may have effect on the cutoff of the individual stages in case no resonance is used. if that's really an important issue, i could use a different formula for low resonance settings (maybe in a subclass specifically tailored to your application). what my formulas do is to compensate for the unit delay in the feedback path (which would otherwise let the resonance detoriate at high frequencies)

elanhickler commented 7 years ago

I don't need resonance at all! (in this case)

and yes, this is with no resonance.

edit: ill try samplerate/2. but last time I went above 20,000hz, the filter cutoff started to reflect... as in... going above 20,000hz seem to begin to lower the cutoff.

RobinSchmidt commented 7 years ago

Gaussain even with 1 pole is perfect.

really? then you could also use the simpler OnePoleFilter class. however, i just went through the design-formula for the case fc = fs/2. the input coeff goes to 0.96 and the feedback coeff to 0.04, so there actually should be a slight amount of darkening. the design formulas there:

      double x = exp(-2.0 * PI * cutoff * sampleRateRec); 
      b0 = 1-x;
      b1 = 0.0;
      a1 = x;

are some textbook formulas derived from and impulse-invariant s-to-z mapping. they should be well behaved for fc=0, though. e^0 is 1, so b0 (input coeff) is zero and a1 (feedback coeff) is 1