openAVproductions / openAV-Ctlra

A plain C library to program with hardware controllers.
BSD 3-Clause "New" or "Revised" License
78 stars 16 forks source link

Mapping v1 #87

Closed harryhaaren closed 1 year ago

harryhaaren commented 6 years ago

A staging PR, to discuss the mapping strategy between Ctlra and any host. The "mappa" infrastructure is used to provide complex multi-layered mappings between the generic Ctlra events and the software-application.

A "target" is a value in the application that can be updated/changed by Ctlra. A "source" is a value in the application that can be read by Ctlra for feedback to hardware devices.

The APIs are currently prototype and POC only, these will change, please don't expect API stability at this point.

Be-ing commented 6 years ago

Cool! I'll take a look at this soonish. Feel free to ping me if it falls off my radar :)

harryhaaren commented 6 years ago

Hey @Be-ing - thanks for your continued input! If you do find some space time, have a look over the config file suggestion as per here https://github.com/openAVproductions/openAV-Ctlra/commit/103c10259d013b4427878c1a07f4b257189b04fc.

The current draft idea is to have a config file be written somewhere, and then load it inside a mappa instance. This basically "outsources" the UI and config part of the mappa creation. The logical "solution" is to provide a "mapping editor" of sorts, that is easy to invoke for an application (eg: Mixxx, Ardour etc), which then pops up a mapping dialog for the user.

Exactly what the editor looks like I'm not sure (have a few ideas, will try get them sketched up over the next week or so) but it provides lots of flexibility to the app. If App X wants, it can provide its own mapping-editor, which just writes a .ini file, which is then loaded into the mappa instance.

The layout of the file is very much a draft - although I think it shows promise. Its simple, and easy to write for applications. Its human readable, and parsing it doesn't require external dependencies as there are a number of easy-to-integrate lightweight .ini parsing projects.

Enough for now - I'll draft up a proper "document" on how I see this being used from an app point of view asap too, once I have feedback from the config file being shown on the device : )

harryhaaren commented 6 years ago

Follow up to above inline-comment: Where the control-object [group] and name are condensed into a single string, and then registered as a "target" in mappa library (see here, in short its a callback with some fancy userdata possibilities).

The end result is a simple yet powerful layered mapping approach, given large numbers of targets can be added without perf degradation. For Mixxx, I see a ControlProxy being registered for each ControlObject, and that can be stored (or a pointer to it) in the fancy "token" or userdata pointer. This allows the callback to directly derefence the ControlProxy (no lookup costs etc), and ->set() is called on it.

The "remappability" comes from the layered approach. Mappa exposes some "internal targets", which allow the state of the (hw->sw) and (sw->lights) mappings to be altered. Basically, we can switch the mapping look-up-tables on-the-fly... oh and we can add as many layers as we like.

Weakest points at the moment are:

Long story short - I think we're well on the way to replacing simple 1:1 MIDI Mapping with generic Ctlra events, and a simple mapping config file format abstracts away the UI details. For power-users, I still see the TCC scripting approach as appealing for total custom control. But I'd say ~90% of users would achieve everything they want with Mappa in its current form [edit current form when actually finished!].

harryhaaren commented 6 years ago

And a few more commits - now button pushing is performing layer switching when mapped to mappa:layer switch, and feedback is pushed to the device by setting light.0 = app_source_name

Be-ing commented 6 years ago

To clarify, is Mappa going to be part of Ctlra or a separate library which uses Ctlra?

fundamental commented 6 years ago

So, looking at the design some you have:

The way that the system works with the different layers seems like it will be the more unique component of the mapping system. Right now a limitation that I see is how the device nodes are mapped onto the application nodes. For instance, it looks like only a single float of state from the device is delivered. What's the range of the float? What's the granularity of the float? If it represents integer values, would mappa do the quantization work or the hysteresis? Is it always linear? Should 'trigger'/'toggle' events be differentiated from sliders? What about describing infinite range rotary encoders? Can multiple device inputs compose (coarse/fine)?

In terms of users working with such a system, having a text based serialization seems like a reasonable starting point, though there should be consideration for how this sort of information can be visually displayed to users as well (as well as feasible avenues for later libs to visually interact with). It seems like if the device has a physical key layout then it would be possible to display the mappings of the individual layers in a GUI outside of mappa in a visual format, so that might already be sufficient. It does sound like there is still some work in formalizing how different layers interact though to finalize that.

harryhaaren commented 6 years ago

@fundamental - pretty much 100% accurate summary. Applications can have "sources" too, see the struct mappa_source_t here , and source register function here.

Regarding mapping, ranges, scale-points, lin/log, etc, yes there is lots of metadata work / thinking to do here. A review of existing metadata (LADSPA / LV2, other plugin formats etc) is a possible starting point.

Users create mappings - and they'll want to create mappings to "user defined ranges" too -eg: I want the dial to not control the full SW parameter range 0 - 20kHz, only from 220Hz to 4kHz. That type of mapping metadata is something I see being added to the mapping string. Eg: slider.0 = name_of_control,start=220,end=4000,type=log This is an impromptu example, I'll need to think about words / names etc.

Keep in mind that the goal is to enable 90% of users - for totally wacky ideas I see users resorting to TCC enabled Ctlra->App scripting, or using the App scripting/mapping system, or hack source-code etc. Basic multi-layer mappings to/from any ctlra hardware to any ctlra app is the goal here.

fundamental commented 6 years ago

Applications can have "sources" too, see the ...

Ah, ok. It took me a few times to parse the code with the used notation. Do you think that defining things in terms of application{source,sink} and device{source,sink} might make things clearer? This sort of reminds me of the conundrum that the JACK server had with naming the capture/playback ports.

Keep in mind that the goal is to enable 90% of users

Yep. Though you do have to define the audience to know if you've captured that 90% or not. It seems like the system could integrate reasonably well with mixxx with the current direction, though it does seem like the single float as a response might end up being too constraining down the road. Particular to mixxx's usecase I imagine there's much more of a focus on 'triggers' as well, which I guess are handled via ignored float values.

harryhaaren commented 6 years ago

Reply to @fundamental;

Though you do have to define the audience to know if you've captured that 90% or not.

Good point - I'll think about this some. I've added issue #89 to track doing just that.

though it does seem like the single float as a response might end up being too constraining

Yes agreed - I want to let actual usage define this. The "single float" is the basis of a lot of DSP interactions, but we can add other callbacks - trigger being a good example. There are many other options that we could add - but its all at the cost of complexity. Hence, start small and see from there :)

Thanks for the input! As next steps I'm hoping to use this for a few smaller demo applications, then integrate with a larger existing project (Luppp / Mixxx) to see how it works. At that point I think we can critically analyse the workflow / developer effort required in using Ctlra/Mappa.

[edited: fixing formatting]

harryhaaren commented 1 year ago

Just a status update, while I think Mappa is still a good idea (tm) in theory, it is unlikely that this exact implementation is going to be merged into the Ctlra codebase, as (despite multiple attempts) it just didn't get the tracktion in other projects external to Ctlra/OpenAV.

No hard feelings here, but felt it worth saying before closing this PR. Its a good concept, but the implementation & uptake in the community need to be there for it to be worth Ctlra taking on all of this Mappa code.