heronarts / LX

Core library for 3D LED lighting engines
https://chromatik.co/
Other
41 stars 25 forks source link

Use relative knob changes on MFT and add incrementNormalized() to parameters #55

Closed jkbelcher closed 2 years ago

jkbelcher commented 2 years ago

The MFT can be configured to send increase/decrease MIDI CCs on knob rotation instead of absolute (0-127) position. I think this is a preferable setting for use with LX. It avoids an annoying MFT firmware limitation where the hardware device always sets the encoder level indicators when using absolute position. This makes it impossible to see on the MFT when a discreteParameter has incremented to a new value. With the knobs sending relative CCs ("ENC 3FH/41H" midi type) the indicator levels are set only by returning MIDI which retains more control from LX.

This also opens up the possibility of wrappable parameters which is super useful for things like hue or degrees of rotation. A parameter can be made wrappable like this: public final CompoundParameter angle = (CompoundParameter) new CompoundParameter("Angle", .5, 0, 1) .setWrap(true);

I added some methods for wrap and incrementNormalized() for use by the MFT but not sure if LXListenableNormalizedParameter is the right home for them. They're mainly for BoundedParameter and DiscreteParameter which are some but not all of the subclasses of LXListenableNormalizedParameter.

DiscreteParameters are now incremented/decremented by the MFT with a fixed amount of knob rotation regardless of the number of items in the list. From my perspective this is a preferred behavior; it felt inconsistent when Enum(30 items) and Enum(4 items) required different amounts of rotation to increment one item a list. However if someone is using DiscreteParameters with 100+ values this might not be the desired behavior.

jkbelcher commented 2 years ago

As for when to bump a discrete parameter, I think that should probably be an IncrementMode option on DiscreteParameter. I can imagine scenarios where both behaviors are reasonable. Some DiscreteParameters are really just like BoundedParameters that only have int values, but you think of them like a knob and it should just move over the range. Others are more like EnumParameters where you are iterating through settings and it makes send to iterate in that way.

Could be something like this on DiscreteParameter:

enum IncrementMode {
  NORMALIZED,
  RELATIVE
}

Great, was looking for a way to accommodate both types. Which do you think should be the default? Maybe default to NORMALIZED on DiscreteParameter and RELATIVE on ObjectParameter<>?

mcslee commented 2 years ago

Great, was looking for a way to accommodate both types. Which do you think should be the default? Maybe default to NORMALIZED on DiscreteParameter and RELATIVE on ObjectParameter<>?

Yep agreed, that sounds good.

jkbelcher commented 2 years ago

Ok, updates available for review. Had to add some special handling of DiscreteParameter when IncrementMode=NORMALIZED on the MFT because you can't just bump the normalized value along to the next value. I went with a solution similar to UIKnob where the controlling device tracks an absolute value for the parameter.

mcslee commented 2 years ago

Made some very minor post-commit touchups: https://github.com/heronarts/LX/commit/c259d40f2be5d275c8fba0b116ef66672207c0a1