Open elanhickler opened 7 years ago
phew - that's actually totally against the rules. i need to think about the consequences...
robin, how about something simple: separate slider range "slidable range" and slider range "actual range"
We can have two ranges for sliders.
We need multiple ranges anyway, I eventually want to have a right click menu "extend range" option for some sliders where some power users may want extreme range while others will want "easy mode" ranges. You don't need to worry about this at the moment. Just something to think about.
hmm...well - i have something like this in func-shaper. there you can adjust min/max values of the a,b,c,d sliders. do you think, such functionality should be encapsulated into a class? we could make a slider subclass with min/max textfield widgets
or maybe not a subclass but one that contains a slider and 2 textfields
I just thought of something. We had a discussion on changing parameter ranges (in code) and that ruins presets, at GitLab I believe. What if you stored the ranges as part of the patch xml system? Then later you could also introduce the ability to change slider ranges. There's a lot of times I wish I could change parameter ranges for specific situations. If the user needs a larger range for convenience, it's... well... very convenient. This could be part of the slider right click menu.
the main reason for not doing such things is that i don't want to bloat and clutter the preset files. my reasoning is that it's rather unlikely to change a parameter range after a product has been published. i, as a programmer, have the responsibility to think about the appropriate range beforehand. and if that should really be necessary to change it at some point, i can still resort to the preset versioning and explicit conversion (and then, only range increases are legal without potentially breaking patches). i also don't store parameter values, when they are equal to their default values - also for economy reasons
for me it's necessary as there's still missing features in the library that prevents me from using the ranges I'd like to use. If the preset could store ranges I can wait comfortably while those features are being added and change the ranges later.
No idea how to do version converting of presets.
No idea how to do version converting of presets.
you retrieve the PatchFormat attribute from the xml, and compare the returned value to the AudioModule's patchFormatIndex member (that you can set in the constructor, if you need to upgrade the format). if the patch format in the xml is older than the member, make appropriate changes to the relevant xml-attibutes. look at PitchShifterAudioModule::convertXmlStateIfNecessary for an example (although, i don't really compare to the patchFormatIndex member there - i just look, if the returned value is equal to 0 and then i already know, what to do).
well, it's a bit messy.
i could provide hook-functions like storeParameterToXml/recallParameterFromXml which you could override and then you could store/recall min/max values there. ...i.e. make your own baseclass for all your AudioModules (subclass of my ModulatableAudioModule class)
but....i think, this will still mess up presets, when they are connected to meta-parameters
I'm no longer going to connect meta-parameters by default.
The problem I'm having right now is that I have a frequency knob with range -5000 to +5000. I want bipolar frequency and 0 frequency allowed. Problem is that the usual range of LFOs is between -10 and +10hz, difficult to get that with linear scaling, so I'd probably want to do exponential scaling, but you can't have negatives and zeros for expo. I propose pow3 scaling:
https://www.desmos.com/calculator/yhzdws7qfp
could you add it really fast?
Edit: Hmm, I'd prefer a bipolar exp scaling, something like if abs(value) is < 1.e-6, value is zero or if value is < -1.e-6, do inverted exp scaling. So that gives us an accuracy of 6 decimal places, where 0 is between -1.e-6 and +1.e-6.
here's bipolar expo scaling:
https://www.desmos.com/calculator/6cttsmpymr
or maybe (value^7)/20000 for bipolar-expo-like response
I wouldn't mind setting frequncy to range of 1.e-6 to 5000 for now with expo scaling if I could change it later to a bipolar slider and not mess up presets.
i think, it's time to facilitate the use of custom mapping functions for parameters. a bipolar version of the exponential mapping is something quite particular and it needs at least one additional parameter to specify its behavior. it could be based on my linToExpWithOffset function (and the corresponding expToLinWithOffset inverse function - we always need two-way mapping). this specifies another "offset" parameter that determines the curve/slope at zero. you could use the regular 20...20000 mapping with an offset of -20 and get roughly the same exp-scaling behavior, but from 0 to 20000. and then that could be mirrored for negative values. however, i think, this is too much to pack into the parameter class. most of the time, it will be just unneeded bloat in the objects
ok - my Parameter class supports now custom mapping functions. this was a sort of open-heart surgery of one of my most basic framework classes, so some care had to be taken and it will need some good testing. it has a new member function:
virtual void setMapper(rsParameterMapper* newMapper);
which you can use to pass an object of a subclass of rsParameterMapper into. your subclass must implement map
and unmap
for forward and backward mapping (unmap should be the inverse function of map, for example if map is exp then unmap should be log). however, you don't need to use this. the old ways (of selecting one of the enumerated scalings) still work - but what happens internally is that an appropriate mapper object is then created inside the Parameter object itself).
so, now the mapping is completely flexible and you can have any mapping you want by implementing your own mapper subclass and configuring the parameter object with it.
...as for the bipolar exponential mapping: i have thought about this and i think now, the best (most natural, smooth) function for this would be something based on sinh. for example y = a * sinh(b*x)
for some constants a,b chosen appropriately to cover the desired range and have the desired slope at the origin (the lower the value of b, the more linear it becomes). i think, this is the next task: working out the details of the sinh mapping. maybe it could be further flexibilized by using y = a * sinh(b*(x+c)) + d
no robin! I only understand pictures, you have to make desmos 😸
https://www.desmos.com/calculator/vpnilxqab0
this feels right to me.
OH WAIT A MINUTE, bipolar exponential FM might be f***ing amazing. Linear FM stays in tune, exponential FM does not, because lower values have less change in frequency unlike linear where you get the same amount of change in frequency whether you go higher or lower, but I've noticed expo FM having a really nice sound, distinct from linear FM, so I've wanted to get a "stable tuning" version of expo FM.
Wow, what if we did a crossfade from bipolar expo / bipolar linear mapper for use as an FM frequency mapper? That could make for some awesome sound synthesis.
YES!!! that sounds like some interesting stuff to explore!
mapper rsParameterMapperSinh doesn't seem to work, slider just goes to 0 when moved.
also you gotta fix this bug:
you have your numscalings before CUSTOM which throws an error becaue you check to make sure you're not using a scaling that is more than numscalings.
also you need to have a constructor, default calls the subclass's constructor I'm pretty sure
also, could you make setShape allow for chaning a AND b?
mapper rsParameterMapperSinh doesn't seem to work, slider just goes to 0 when moved.
yes, i know - i said that in the other thread. the patch to the slider class was actually simple. should work now.
as for "CUSTOM" being below NUM_SCALINGS: that's actually intentional: the custom scaling is not among the enumerated ones, so to speak. i think, i do this check only when you call setScaling - right? ...and you are not supposed to call that with "CUSTOM". the corresponding member will be set to CUSTOM, if you pass in a mapper object. does it throw an error anywhere? i haven't encountered any, so far.
btw.: when you use enumerated values, ALWAYS ALWAYS ALWAYS use the enumeration values. NEVER EVER EVER do things like: myParam->setScaling(2). i may change the order of the enumerations at some point, insert new items, etc. - this will then break your code
the same goes also for filter types in rosic. i've seen you using such "magic numbers" before
could you make setShape allow for chaning a AND b?
nope. a must be a function of b. they are coupled, otherwise, the min/max values come out wrong
basically, you set b and max, and that fixes a, well, min/max actually, but currently, it requires that min = -max
how would I get this shape?: https://www.desmos.com/calculator/vpnilxqab0
this exact function? well, you already know your b-value. it's one in this case. you want to know how to set max? just read off the value of the graph at x=1 - it's around 0.87. i probably could come up with an exact formula for the exact value but for what? i don't know what you are trying to achieve...
I'm going to use this curve for bipolar frequency and want to make an rsParameterMapper subclass, and need to setup the map and unmap functions.
(deleted next post)
I'm going to use this curve for bipolar frequency and want to make an rsParameterMapper subclass, and need to setup the map and unmap functions.
why do you want to make a subclass and not just use the rsParameterMapperSinh class? just set your min/max frequency value, like to -20000 to + 20000 or whatever and then set up your b (shape) value in a way which nicely balances the precision around zero with the precision at +-20k. this is exactly what this is made for. like
freqParam->setMapper(new rsParameterMapperSinh(-20000, +20000, 2.0));
the last constructor parameter, here 2.0, is "b" and it sets the shape, i.e. determines the trade-off between low-freq and high-freq precision of the slider. there actually is nothing more to do than just choosing your min/max (symmetrically) and setting the shape-parameter b.
edit: ok - i also deleted the other posts related to xoxos osc
sooooo, I set the min max of the mapper, but that is NOT the min/max of the slider? It is simply the min/max of controlling curvature or someting? On the slider I want -5000 to +5000 for example.
the min/max of the mapper is the min/max of the parameter is the min/max of the slider. you want a different range for the slider than the parameter has?
no, i just don't know, given your sinh mapper how to achieve this curve: https://www.desmos.com/calculator/vpnilxqab0
now, it's not like I MUST have this exact curve, but I thought it would be easy to try. No? Anyway, ill use your sinh mapper as is for now.
i think, there's no much sense in wanting this exact curve. our exponential mappings for frequencies say, 20...20000, are also scaled (input and output wise) so as to hit the correct values 20 and 20000 at 0 and 1 (it's also some y = a exp (b x) actually). more meaningful might be to solve for a b-value, such that a middle frequency...say 1000Hz is at half of (the right part of) the slider range. this is the only thing, one could do, when the maximum (value at 1) is already fixed. ...so something that could make sense is to choose b in a way such that a sinh(b x) and the A exp(B x) of the exp-scaling most closely resemble each other (the coeffs are of course different, that's why capital letters for exp)
...or wait...you are actually shifting your exp-function to the left...i think, this is different from what our exp-scaling does. it's an exp with shifted input....hmmm...
don't worry about it, I have no idea what I'm doing. 😄
make sure that you choose your b-value wisely. later changing it will break the mapping to meta parameters (i.e. may break patches with connected metas and daw automations)...it's similar to trying to change a parameter range later
Yes, I found a good way to think of it, just ask what range is most important.
I want -5000 to +5000, but the important values are perhaps -10 to +10, so I choose a B value where the slope around -10 to +10 looks about linear.
I have a gain slider that is -8 to +8. -1 to +1 is the most important. So again, just make the curve about linear around there.
Edit: Or maybe what I mean is that there is a "square" between 0 and your important value. Edit: Uhh nevermind, that's not a good explanation. This way of thinking doesn't work for my gain parameter.
still hitting this:
jura_Parameter.cpp line 195
Even though I can get past this build error, I'm still not getting scaling it seems:
myparams.cpp line 113
Is it possible to create a parameter mapper that skips 0 and is integer numbers? So I need a slider that has a sequence like this:
-5 -4 -3 -2 -1 +1 +2 +3 +4 +5
I can try to attempt it once the sinh works.
still hitting this
i need to know, which class/function this is. you cut the top off too early ;-)
here's how you can see the actual mapping function in term of max (m) and b: https://www.desmos.com/calculator/pamgkqwry9 i chose a range -20000 to +20000 as would be appropriate for frequencies in the audible range. the slider value would go from -1 to 1 in this case. i'd probably look at the frequency value at x=0.5 and make sure that the graph goes through (0.5, fMid) where fMid is some frequency in the middle of the audible range, in this case. say, having 1kHz at x=0.5 would call for b=6 (pi times thumb)
ok, i'm allowing to set Parameter::CUSTOM from client code now (have dragged the value before NUM_SCALINGS)
jura_Parameter.cpp line 195
myparams.cpp line 113
I thought setting to custom was what you had to do? not sure how else it'd work.
as said above, actually the idea was that the user/client doesn't manually sets this option but it is only set internally as soon as you pass a mapper. but i didn't take into account that the constructor also requires this setting....you could actually have passed any value to the constructor, like LINEAR - it would later be updated in the object to "custom" when you pass the mapper anyway. but it would be weird/confusing to do it that way, so i have now just dragged the value up. ...it's still not very elegant, though
is it possible make a parameter mapper that skips 0? -5 -4 -3 -2 -1 +1 +2 +3 +4 +5
here's the linear equations:
double map(double x) const override { return min + (max-min) * x; }
double unmap(double y) const override { return (y-min) / (max-min); }
if I copy that and add this to a new mapper class, would it work?:
x <= 0 ? x = x-1 : x
y >= 0 ? y = y+1 : y
hmm..you need rounding somewhere...but then, how would the inverse function "unmap" look like? such a function is actually not invertible. we need inversion, because when client code calls setValue and a Meta is connected, we have to able to figure out the meta value (which is always in 0..1).
...hmm...don't know, maybe we could somehow avoid the requirement of two-way mapping. ...or you just map the rounded value back
still not getting a bipolar exponential feel to the sliders, seems to be bipolar linear.
what's your b-value?
i've tried .01, .0075, .3, seems to make no difference
look at this - such low b leads to almost linear scaling:
https://www.desmos.com/calculator/pamgkqwry9
you need something of the order of 1...10, you need moar beee!!!
uhhh... but ranges im dealing with could be -8 to 8, -5000 to 5000, now I'm confused as to how to use desmos to find a good b value. I thought I knew, now I have no idea
this actually doesn't matter. the shape stays the same, just the whole graph gets scaled down by another "a" factor then
this is what i meant when i said: a is fixed by the max-value, as soon as b (shape) is chosen
...if i'm not mistaken
For sliders, could you provide an option per slider to allow user to type in and accept a value that is outside the range of the slider?