Closed elanhickler closed 7 years ago
...also what would you do, if the object is possibly element of several arrays at the same time?
just don't 👍
edit: really though, several arrays that need to add and remove one instance of an object? that's some crazy code.
for example, my ModulationManager keeps an array of availableTargets and affectedTargets (where affectedTargets is a subset of availableTargets) and it totally makes sense - so in my per-sample function, i have to loop only over the targets that are actually affected (i.e. have incoming connections). i'm even considering to apply the same optimization to the sources (i don't do it so far because i assumed the number of sources would be rather low compared with the number of potential targets, so it may not be worth it - although, when i look at mushroom, i'm not so sure anymore about the validity of this assumption).
void ModulationManager::applyModulationsNoLock()
{
int i;
// compute output signals of all modulators:
for(i = 0; i < size(availableSources); i++)
availableSources[i]->updateModulationValue();
// maybe we should loop only over an array of "usedSources"?
// initialize modulation target values with their unmodulated values:
for(i = 0; i < size(affectedTargets); i++)
affectedTargets[i]->initModulatedValue();
// apply all modulations:
for(i = 0; i < size(modulationConnections); i++)
modulationConnections[i]->apply();
// let the targets do whatever work they have to do with the modulated value (typically,
// call setter-callbacks):
for(i = 0; i < size(affectedTargets); i++)
affectedTargets[i]->doModulationUpdate();
}
although, when i look at mushroom, i'm not so sure anymore about the validity of this assumption).
I want to make it more modular where you can add/remove LFOs/ADSRs/Breakpoints from the GUI, so the available sources may start off as just a few until the user adds stuff. I want to go for a wireless modular synth.
please put a pause function on a smoother. I need to be able to pause the value from changing.
or I could just set smoothing ~speed~ amount to infinity for specific parameters when needed.
oh! what is that good for?
for pausing PrettyScope. You click on the canvas to draw something, the x/y offset starts moving, you release mouse, the x/y needs to stop moving. This is "mouse auto pause mode" so it makes it easier to draw stuff.
so, you mean, you need it to stop immediately on releasing the mouse instead of keep moving and slowing down for some further fractions of a second?
huh? "instead of moving and slowing down" ? yeah, it has to stop changing value... but that's for me to worry about, all I need is to be able to change the speed of the smoother... you have a smoothing speed per smoother, right?
yes - actually, per smoothing-target and the smoother then takes over the value from the target when the target gets assigned. but that's technical details
okayyyy....the smoother is operational. i tested it in Chainer with FuncShaper. you can try it there with the dc-offset value. i also tested to assign it to a meta (and drive to the same meta) and that seems to work as well. modulation also.
you need to create your parameters as SmoothableParameter objects now. it's a subclass of ModulatableParameter. so currently, i have the rather weird inheritance hierarchy:
Parameter < MetaControlledParameter < ModulatableParameter < SmoothableParameter
although it seems to work, i want to try to change it into:
Parameter < SmoothableParameter < MetaControlledParameter < ModulatableParameter
we'll see how that works out. when i'm done with that, you can change your code back to creating ModulatableParameter objects. but if you want to try and use it right now, create SmoothableParameters
btw. it will also get invoked when you switch presets. i guess, when setting up a rather long smoothing time, we'll get a preset-morph when switching presets. ...but that will almost certainly create a huge cpu spike. we may consider to temporarily turn smoothing off on preset switch. ...i need to include some facilities for that...
oh - wait - now it's not working anymore...wtf?
edit: ok...i see...it works only when no meta is attached. when a meta is attached, it works when changing the meta, but not when changing the slider on the gui..but why did it seem to work at first? weird..
Yes, I want to use it immediately, I don't care if I have to change code later, I need to release Mushroom Generator ASAP.
But looks like I'll need to wait until you solve the meta attach issue.
i think, i first need to change my inheritance hierarchy and see how it will go then.
ok, it seems to work. you can keep your code as is - ModulatableParameter is now the outermost class and includes smoothing and meta-control. but for simpler plugins that don't use the mod-system, you can just create MetaControlledParameters to avoid the mod-system overhead
oh - i have no thread-safety measures in place yet. ...will add that next
quick description of how to use?
How do I turn off smoothing for certain sliders?
edit: oh I guess i can put smoothing to 0... buuut then how do I pause the smoother? give a time of DOUBLE_MAX? probably not ideal though.
And aren't you excited to employ the smoothing manager for morphable presets?
edit: ok
just don't add it to the smoothing manager.
do I need to create my own smoothing manager like for modulation?
quick description of how to use?
just look at processBlock of AudioModuleChain (that's the awkward class name of the Chainer). it's very similar to your smoother
And aren't you excited to employ the smoothing manager for morphable presets?
it might be fun to noodle around with but ultimately probably impractical for release due to the high cpu-load during the morph. if several dozens of parameters are simultaneously smoothing and each of them triggers (more or less heavy) calculations in the dsp engine, you can imagine how that drains on the cpu
How do I turn off smoothing for certain sliders? edit: oh I guess i can put smoothing to 0
exactly
Smoother Manager needs a "set smoothing amount for all sliders" function
hmm...ok, i think, i can add an option to override the individual setting in the smoothing-target
do I need to create my own smoothing manager like for modulation?
what? why?
thinking about it, if I need to disable smoothing for certain parameters and implement my own pause functionality, I won't be able to use the smoother manager's "set all sliders speed".
i could perhaps provide a global switch for turning smoothing off. might be needed anyway to disable it temporarily during preset recall for reasons stated above. ...but yeah, if you need some very special functionality that is relevant only to PrettyScope and unlikely to be useful anywhere else, it's probably best to do it in a subclass
pause functionality... preset morphing... disabling smoother for certain parameters... I need to think more about all of this... let's start a preset morphing discussion for fun.
For now, please get on adding grid settings saving to breakpoint module.
Once that's done, I still need work on the phaselocking autotuner.
I also need you to perhaps work on the multiband compressor, I'll fund you with the money coming from that person / project.
There's a lot to do still!!!!!!
....perhaps the smoother could have an undersampling function to get the cpu load down to managable levels, such that it doesn't update parameters every sample but only every N samples, where N is a user-adjustable undersampling factor.
undersampling... that reminds me. I'm also doing some SERIOUS code refactoring for prettyscope, I very badly want an upsampling method for it, it would improve the visuals by a factor of 10.
hmm...yeah - as said, in PhaseScope, i would probably try to replace the connecting lines with cubic splines but such a thing is not so easy to realize in PrettyScope, because OpenGL has no spline primitive, so at the end, the splines would have to be approximated by a sequence of lines anyway. within my own c++ pixel-code, i could add such a spline-drawing primitive
right, wouldn't we just upsample the audio buffer? the audio buffer is what creates the x/y points.
you could do that - but i'd certainly not recommend using an elliptic filter for the upsampling in this case (unless you like to see spurious gibbs ripples in the plot). you want something with good time-domain performance, i.e. bessel or maybe gaussian. the upsampled signal would not necessarily go through the original sample-points then anymore, though. with splines, it would.
I don't understand the issue. So.............. what needs to be done? Do we need an openGL expert to make splines instead of lines?
This is why I posted dood.al source code. https://gitlab.com/Hickler/Soundemote/issues/58
does that use splines? ...ahh - ok - i see. it seems to use a lanczos filter (FIR...seems to be some form of a windowed sinc). so it's basically sinc interpolation
ok i made some section links for easy navigation
My value change callbacks are not being hit. It's not even a problem of smoothing. Just simply moving a slider doesn't trigger a callback. My breakpoint isn't being hit for that callback.
call value change callbacks is false when i move a slider???
hmm...i guess, you are coming from here?:
void rsSmoothableParameter::setValue(double newValue, bool sendNotification, bool callCallbacks)
{
if(smoothingTime == 0.0 || smoothingManager == nullptr)
Parameter::setValue(newValue, sendNotification, callCallbacks);
else
{
double oldValue = getValue();
Parameter::setValue(newValue, sendNotification, false);
smoothingManager->addSmootherFor(this, newValue, oldValue);
}
}
yes, when the baseclass method is invoked, i pass "false" to the "callCallbacks" parameter because the callback call is deferred to the "updatedSmoothedValues" call which is supposed to be called right before the next sample is supposed to be produced
yes
so why it no work?
i'll have a look at it in the debugger myself tomorrow
did you forget that I am using modulatable parameter 2 for std::function?
Assigning modulation to a parameter, even if that modulation amount is 0, will allow slider to change value, however it is not smoothed.
also, smoothingManager.needsSmoothing();
is never true
ok, i fixed some bug. you created your own smoothing manager, but that's not how it's supposed to work. the smoothing manager exists once in the AudioPlugin object and is accessible globally by all AudioModules via a pointer (defined in baseclass AudioModule). ...so now the parameter setValue... functions get called...but it seems not being smoothed. but maybe that's now easier for you to figure out.
it's very similar to how the meta-stuff is handled - you don't create your own meta-manager either. ..but admittedly, that may not have been obvious
no idea why parameters are not smoothed.
what else do you have to do to make smoothing work?
im lost.
is smoothing speed 0 by default?
oh - i see in the debugger that smoothingTime is set to 0.01. seems like you are setting that somewhere? but that's in milliseconds!
i also see that the smootherPool has 399 array-elements - but you have only 58 parameters - something seems wrong about the initialization. expected would be, that when the parameters are intitialized (or a preset is loaded), that as many smoothers are created as there are parameters. i say expected - but that's probably not desired. i think, i should switch off smoothing on initialization and preset load
If you're dividing smoothing time by 1000, that's kinda pointless.
hmm...it's a matter of convention what units should be used for the parameters - seconds vs milliseconds in this case. i thought, milliseconds would be the more convenient unit here
I don't expect you to change this, but just think about it. Keep all time units in seconds throughout your library. To have multiple units of time is just an extra layer of complexity.
For example, I can make a slider display milliseconds or seconds, but the underlying value is always in seconds. Typing 1 vs .001 in code... well you don't know by looking at it whether it's a second of a millisecond or a millionth of a second.
Keeping time units the same means you never have to remember to specially multiply by 1000 for this or that object or parameter.
Smoothing works. Thanks.
If you want milliseconds then... you should name your function setSmoothingTimeMilliseconds... which will then make you not want to set things in milliseconds because of the extra long function name 😄
hmmm....yeaaa....i sort of agree that consistency of units throughout a library is desirable. i was certainly thinking about that for rapt. in the rosic classes, i mostly use units of whatever i considered the most convenient unit to present to an end user on the gui - like milliseconds for compressors but seconds for reverb-times and so on. but in the jura framework i'm a bit more sloppy because i consider it mainly for personal use anyway. hmmm
Robin I wish I could just write all my own code and not use your library (GUI stuff I mean) so you wouldn't have to worry about me and my opinions, but........... I'm here to make money and I can't afford to write my own stuff due to time and lack of knowledge. If my business is successful, more money will be flowing your way.
If it were up to me, I would continue to pay for you to develop your interface with public use in mind and create an awesome one-stop framework to build a plugin from scratch.... well that's what you're doing right now! There's money potential here. You're doing it anyway, so why keep saying it's for personal use? You can keep saying that, but I think there's a lot of potential here for your business to grow.
I could be wrong.
Could you put in a smoother for parameters?
The only non-obvious thing I would have to do is do some increment of the smoother in the processblock sample loop, easy. Would be pretty easy for you to implement as well.
Oh, and I'd have another place in code where I set the smoothing amount per parameter.
you have getValue, you have setValue. Add getSmoothedValue(), add incSmoothedValue(), or whatever.
I'm building my own system for smoothing for PrettyScope, already did it for Spiral Generator. Just annoying, waste of space in code!