-
Notifications
You must be signed in to change notification settings - Fork 13
New Controller Engine #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,304 @@ | ||
| # Controller Engine V2 | ||
|
|
||
| * **Owners:** | ||
| * @Swiftb0y, @acolombier | ||
|
|
||
| * **Implementation Status:** `Not implemented` | ||
|
|
||
| * **Related Issues and PRs:** | ||
| * [Create a reactive programming API for | ||
| controllers](https://github.com/mixxxdj/mixxx/issues/13440) | ||
| * [QML-based components API for | ||
| controllers](https://github.com/mixxxdj/mixxx/pull/13459) | ||
| * [Respect the Midi timestamp when | ||
| scratching](https://github.com/mixxxdj/mixxx/issues/6951) | ||
| * [make brake, soft start, and spinback part of the effects | ||
| system](https://github.com/mixxxdj/mixxx/issues/8867) | ||
| * [Move the controller screen rendering feature away from | ||
| `ControllerScriptEngineLegacy`](https://github.com/mixxxdj/mixxx/issues/13203) | ||
| * [Confusing Midi Sysex | ||
| handling](https://github.com/mixxxdj/mixxx/issues/12824) | ||
| * [Ability for controller to share data at | ||
| runtime](https://github.com/mixxxdj/mixxx/pull/12199) | ||
| * [Allow Controller Mappings to be located in their own | ||
| directory](https://github.com/mixxxdj/mixxx/issues/9906) | ||
| * [support external displays on | ||
| controllers](https://github.com/mixxxdj/mixxx/issues/8695) | ||
| * [Handle hot-plugging and graceful recovery of | ||
| controllers](https://github.com/mixxxdj/mixxx/issues/5614) | ||
| * [Controller scripts need to be able to | ||
| cross-communicate](https://github.com/mixxxdj/mixxx/issues/5165) | ||
|
|
||
| This document is supposed to serve as an overview for a new controller engine | ||
| for Mixxx. This does not only refer to the runtime "execution engine" of some | ||
| mapping specific code, but almost all aspects from protocol IO, to the metadata | ||
| schema, point-and-click mapping editor, and the scripting API. | ||
|
|
||
| ## Definitions | ||
|
|
||
| * Mapping: a file or set of files which defines everything that’s needed to a | ||
| controller to communicate with mixxx | ||
| * Controller: Physical self-contained piece of hardware, possibly consisting of | ||
| multiple sinks and sources | ||
| * Source: a source of data from the controller (midi/HID messages from a | ||
| particular port/endpoint) | ||
| * Sink: a port/endpoint of the controller that receives data from mixxx (e.g | ||
| screens, HID output report, write bulk endpoint are example of different sink | ||
| types) | ||
| * Manifest: Metadata about the controller definition. Execution Engine and | ||
| Source/sink topology. (equivalent to what we do with the XML in the current | ||
| legacy engine) | ||
| * Execution Engine: Scripting engine that evaluates the scripting source files | ||
| of the engine (so essentially what makes the scripting interactive/smart) | ||
| * Module: ES6/QML Module that's part of a mapping, evaluated in an execution | ||
| engine (its what you expect ;) ) | ||
| * Capability: abstract definition of a concept that is not native to mixxx (eg. | ||
| shift, controlling different decks with the same physical hardware (1/3, 2/4 | ||
| deck switching)). This is needed for “open-ended” cross-mapping communication | ||
| (avoiding “controller lock-in”). | ||
| * Point-and-click editor: A tool to easily customize a controller mapping by | ||
| clicking a button on screen and on the hardware surface and those two | ||
| corresponding to each other. | ||
|
|
||
| ## Why | ||
|
|
||
| The current controller engine suffers from a number of issues primarily | ||
| summarized as a lack of flexibility. | ||
|
|
||
| ### Pitfalls of the current solution | ||
|
|
||
| To summarize the issues linked in the Related Issues and | ||
| PRs section: | ||
|
|
||
| 1. The current controller engine is not able to handle multiple controllers at | ||
| once. This is important when a single piece of hardware is advertising | ||
| multiple different control endpoints (eg HID + Bulk for control + screens | ||
| such as Native Instruments Traktor devices) as well as when multiple pieces | ||
| of hardware are supposed to present a single unified control surface (such | ||
| as the modular Behringer CMD-MM1/-PL1/-DC1/-LC1 or modular NI Traktor | ||
| Kontrol F1/X1/Z1). Being able to bundle multiple different endpoints into | ||
| the same mapping is important for a good user experience and to allow for | ||
| more complex mappings. | ||
| 2. The current controller engine (`ControllerScriptEngineLegacy`) is not able | ||
| to support modules of any kind. This is important for code organization and | ||
| reusability. In order to increase mapping code quality and maintainability, | ||
| it is important to be able to split the mapping code into multiple files and | ||
| to be able to reuse code between different mappings. This is especially | ||
| important now that mapping authors are starting to reuse functionality | ||
| across different hardware devices (see Numark NS6II and Mixtrack variants or | ||
| similarity between different pioneer controllers) | ||
| 3. Current mappings modify global state and assume that they are the only | ||
| mapping running. This needs to be fixed in order to support multiple | ||
| mappings running at the same time in the same "execution engine". | ||
| 4. Device hotplug is currently not possible / hard to implement. This is | ||
| primarily because of the underlying protocol IO layer not willing to support | ||
| it. This document proposes an alternative approach that lets us more easily | ||
| switch the underlying library. | ||
| 5. Allow changing the manifest format. Many people have expressed distaste in | ||
| the XML manifest format. Careful implementation of the new format should | ||
| allow experimentation with different formats. | ||
| 6. Changing out infrastructure like this is virtually impossible. The proposed | ||
| architecture is designed to be modular and allows for all the required | ||
| components to be implemented gradually. | ||
|
|
||
| ## Goals | ||
|
|
||
| Goals and use cases for the solution as proposed in [How](#how): | ||
|
|
||
| * Allow multiple controllers to be used at the same time. | ||
| * Mappings should be able to organize themselves into modules. | ||
| * IO protocols should easily be changeable and not not be tied to the mapping. | ||
|
JoergAtGithub marked this conversation as resolved.
|
||
| * Allow easy, gradual implementation of the system. | ||
|
|
||
| ### Audience | ||
|
|
||
| This is primarily targeted at developers and power users who are interested in | ||
| the controller engine. End-users only interested in the point-and-click mapping | ||
| editor should not experience any significant changes. | ||
|
|
||
| ## Non-Goals | ||
|
|
||
| * Replace `ControllerScriptEngine` in the short term until we are confident in | ||
| the new design. | ||
| * make changes to the scratching code as it is orthogonal to this proposal. | ||
| * Make changes to the effects system as it is orthogonal to this proposal. | ||
|
|
||
| ## How | ||
|
|
||
| Explain the full overview of the proposed solution. Some guidelines: | ||
|
|
||
| ### File Structure | ||
|
|
||
| Built-in mappings reside in `res/controllers/` where each mapping is a directory | ||
| containing at least a manifest file named `manifest.xxx` (where `.xxx` is the | ||
| language-specific file extension (eg. `.xml`, `.yml`, `.json`, etc)). | ||
| Additionally, `res/controllers/lib` contains shared modules that can be used by | ||
| multiple mappings (such as componentsJS). | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can even allow to share mappings via an unpacked zip file with a fancy extension that Mixxx is able to unpack. I just remember discussions that mapping writers want to work only in a single file. So we need to be clear about our goals here.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I personally find it a little silly to zip files and then use a custom extension (looks like a bad attempt at hiding something) but from a technical perspective, I don't see anything wrong with that. Its just an extra step required while exporting. Importing is probably suboptimal if we would unpack the file during each scan to read the manifest.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It's less about hiding something and more about saying "this is a mixxx-mapping" so that we could add an "Import Mapping' button to the controller preferences that allows picking a file from the downloads directory and automatically copies it to the right location without listing every single non-mixxx-related zipfile in the directory.
I suppose the performance impact is neglible. As an alternative, mixxx could provide an "export button" that zips the file w/o the manifest and includes the manifest text in the zip comment if we're worried about that.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, all pretty fair suggestions. We'll just need need a good library for it I guess because Qt doesn't have any facilities afaict.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I guess we could do something similar than for NI stem format and add a prefix to the extension (e.g
Probably getting too much into implementation details, but we could inspire from tools that uses a similar mechanism. Thinking of tools like Terraform or Helm that also have many "third party" extension compressed in an archive, you can expand them into a "cache" folder on import and maintain a checksum comparison on the source archive. As long as that checksum doesn't change, you can safely use the manifest file from the filesystem. This also greatly simplify modding as users can change the expanded module on the fly, without having to use a different mechanism (some kind of "draft" folder) or need to repack an archive. TL;DR; I don't think this is a problem.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This would really be a non-goal for me. Then we need to support all these compression formats forever, and I think there is no good reason for it. Just agree on a single format (or rather two: packed for easy exchange and unpacked for easy development).
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Many file formats (like OpenDocument for Office application) use JAR files as container (just with a different file extension). The JAR file container defines the zipping and the manifest file format. And also handle topics like fast reading the manifest without unziping the whole files. But I don't think that JAR files are good for the developer experience of a mapping developer. I suggest to use just sub-directories per mapping. |
||
|
|
||
| ### Manifest | ||
|
|
||
| The manifest is a declarative file that describes the mapping. It contains the | ||
| following information: | ||
|
|
||
| * Sources and Sinks | ||
| * Execution Engines | ||
| * Used Mixxx APIs | ||
| * Capabilities | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am afraid this flexibility will introduce lot of boilerplate for no reason. I would prefer to straight forward code a new engine without adding facilities for a not yet known future engine. YAGNI
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean boilerplate in the C++ domain or just in the manifest? For the manifest I could imagine adding some shortcuts for the common usecase sure, but I'd like to keep the decoupled nature on the C++ side. Otherwise we'll be right back where we started with the current engine.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is more a general concern. This flexibility and abstraction to allow different engines, comes with the cost that things are harder to implement and cannot be optimized because we have only the common ground of all engines. |
||
|
|
||
| ### Sources and Sinks | ||
|
|
||
| Sources and Sinks are the endpoints of the controller. They are defined in the | ||
| manifest and are used to define the IO protocol of the controller. They are | ||
| characterized by their protocol (eg. MIDI, HID, Bulk, etc), their direction (eg. | ||
| input, output, bidirectional) and optionally explicitly their underlying | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why should I specify the direction for HID or BULK report? This information can be read from the device.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you elaborate?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Every USB device has "Endpoint Descriptors" ( https://beyondlogic.org/usbnutshell/usb5.shtml ), which contain this information per enpoint. If I know the supported device type, why should I store a copy of this information in the mapping files?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good point. Primarily so the mapping can declare stable identifiers to address them. What do you propose instead?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I propose to assign the device type to mapping by "Manufacuter ID" and "Product ID" and read out all information of the device, which we can gather via userspace APIs. Only what is not accessible on all supported systems, shall be stored in the mapping files.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there is a risk of doing a 1-to-1 relationship here. Having the IO driver respecting the USB descriptor is definitely a must have, but it would make sense to also explicately define the direction the mapping is interested with. This would help us planning for vendor which may be using not so compliant descriptor (BULK being probably the most at risk here, since it already involve a custom API made by the vendor), meaning that the port could be used for more than just receiving/sending mapping relevant data.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still not convinced how this direction property should be clearly seperated, e.g.:
Why do we need to enforce this by the top level architecture. I fear that this will restrict us in the future, as we will always have to force all USB protocols into this arbitrary structure.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think your concerns are valid. So the consequence is that we only apply the source/sink abstraction to midi. So no abstraction over these protocols. That may be fine, but then we would have to reimplement the PnC logic for each protocol. Do you have some other abstraction in mind?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need an entity to assign to the execution engine here, but this must be an abstract definition to be future proof. It should cover cases like:
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the comprehensive collection, but it doesn't answer my question. What do you imagine the common API between these to look like? We need some abstraction unless we want to reimplement common features such as the PnC editor for each protocol. |
||
| implementation (eg. `portmidi`, `rtmidi`, `libremidi`, etc). They will also | ||
|
Swiftb0y marked this conversation as resolved.
Outdated
|
||
| contain a heuristic description to map the source/sink to the physical | ||
| controller (protocol specific, in the case of HID, usb vid&pid could be used for | ||
| example). | ||
|
|
||
| ### Execution Engines | ||
|
|
||
| Execution engines is yet another section of the manifest. It defines the | ||
| scripting engine that will be used to evaluate the mapping. It is defined by its | ||
| type (JS, QML, something else?) along with a specific entry point. In the case | ||
| of JS, this would be a ES6 module that exports a controller class to be | ||
| instantiated. In the case of QML, this would be a QML file that defines a | ||
| controller object. | ||
|
|
||
| ### Capabilities | ||
|
|
||
| Capabilities are the concept that allows for cross-mapping communication while | ||
| avoiding controller-lock-in. They are defined by mixxx and are used to define | ||
| concepts that can't be easily mapped to ControlObjects. For example, a | ||
| capability could be `shift` or `deck-switching`. Capabilities are defined in the | ||
| manifest and can be used by the execution engine to communicate with other | ||
| mappings. Capabilities are essentially "opt-in" APIs. | ||
|
|
||
| ### Point-and-click editor | ||
|
|
||
| In order to still support the point and click style use-case, we add yet another | ||
| section that directly connects patterns of midi messages to a control object. | ||
| This section is again attached to a source/sink. There is no support for | ||
| interacting with an execution engine via this section. This essentially works | ||
| like the current mapping editor, but removes the | ||
| `<key>path.to.some.JS.input.handler</key>` feature as it is not compatible with | ||
| the new architecture. This method is favoured over code generation as that is | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have failed to implement that in other protocols than midi.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not yet, The dispatcher. I know @acolombier made some experiments regarding that. I'm sure a dispatcher functionality could work for protocols other than midi (at least as long the data format is simple enough) but I consider them out-of-scope for this PR. It wouldn't be super hard to add on later though.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Than lets at least consider it right form the start. It would be an immediate user benefit to have all back-ends GUI learnable.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have build a working PoC which allows to learn action by implementing a naive diff on HID report. Certain venodr (like NI) also appears to be providing a fairly complete HID descriptor. This means that we could be able to implement a HID layer for it. I don't think it would be possible with BULK tho, but I believe that controller using BULK for input are becoming rare nowadays.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For my understanding it is only a difference how generic such a driver will be. I can Imagine to build a driver for a bulk controller with a weird protocol without any self documentation.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm fairly confident it will if we adapt the sources and sinks model... |
||
| not always possible, nor would it likely produce a good result. Moreover, this | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would disagree with this statement. Yes, it is correct for JavaScript, especially as we have very different styles of JS across on the different mapping. Kooha-2024-05-28-21-24-49.mp4
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The simple standard mappings must be stored in a semantic language, which allows the mapping wizard to read the already mapped controls. This must work for MIDI and HID.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have two issues with code generation:
I didn't really intend there to be override logic. At least not directly. Each protocol can opt into using a dispatcher module (instead of just getting all its traffic dumped to some handler directly). Then the manifest can specify a CO to be controlled and the execution engine can specify some code to executed based on receiving some message. If both the manifest and the execution specify something for the same message, the action declared in the manifest takes precedence. Does that make sense?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A code generator is not what is needed, we need an editor! Which allows to read a mapping into the GUI and allows to re-map the controls.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Agreed, this is why, due to its declarative nature, QML could be a good pick.
Not sure why this wouldn't? This proposal suggestd a new engine agnostic to the IO backend, but also stands as an independent implementation, that doesn't have to live with the legacy engine, but rather be an alternative. At least I believe that was the the ambition when we discussed about it with @Swiftb0y
That's exactly what Qt Creator does. And all the relevant source is under compatible license AFAIK. QML is a declarative language, and custom QML component can allow to keep mappable property in the "code" using well constrained property
qtdeclarative and qt-creator(particularly
I think this statement is not always true. QML boilerplate can be extremely simple if we design the engine in a sensible manner. My previous attempt as part of #11407 shouldn't be taken as reference as it was attempting to align as much as possible with the legacy JS engine it would live in. Now assuming we make separate agnostic engine (or even QML only), this could be greatly simplified, and potentially contain even less boilerplate than bare JS
It does make sense, and was what I had in mind already. But this is what I meant by the override logic: instead of having a single source of truth, which follow the same API, you end up with two APIs which aren't compatible. This means that someone with a limited knowledge cannot use the point-and-click to establish a basic behaviour and then override certain hooks with simple logic, especially when trying to implement new controller, not yet supported. |
||
| would let us recycle parts of the current codebase. _No need to reinvent the | ||
| wheel._ Execution engines can still be wired up explicitly to access the | ||
| dispatcher here as well. This is to avoid the need to have a separate dispatcher | ||
| defined in the mapping and for easier integration with "hybrid" mappings. the | ||
| API is essentially already implemented as [Registering MIDI Input Handlers From | ||
| Javascript](https://github.com/mixxxdj/mixxx/pull/12781), though QML would need | ||
| a separate declarative API. | ||
|
|
||
| ### Wiring it all together | ||
|
|
||
| Since this flexible layout results in a many-to-many relationship sources/sinks | ||
| and execution engines, we specify a separate section in the manifest that | ||
| defines how sources and sinks are connected to execution engines. | ||
|
|
||
| ### Sharing mappings with modules | ||
|
|
||
| In order to share mappings that access modules outside the mappings root folder, | ||
| the execution engine must be able to create a list of all files accessed and | ||
| export them along the controller files. This would be done by creating a copy of | ||
| all the required files in the root of the mapping during exporting. That tree is | ||
| then overlaid over the built-in libraries. This is currently only possible | ||
| within a `QQmlEngine` using `QQmlEngine::addUrlInterceptor` and | ||
| `QQmlEngine::addImportPath`. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This sounds scary to be honest. Remember that we need to catch users with school level programming skills.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you elaborate on how that's scary? All I'm saying is that we would export the libraries loaded from outside the mapping folder and copy those into mapping. Then when we load the mapping we prefer the versions bundled with the mapping over those built into mixxx. This avoids issues where users would complain when the mapping they download from the forum suddenly breaks / works differently when they run it on a different mixxx version. That allows us to have less strict stability requirements for our libraries.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It probably sound scary for me because I did not understand it. My general concern is that we should keep the required programming knowledge at a minimum. With a stable API and a complete documentation. The idea presented here sounds like a receipt for the opposite, but I could be wrong.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I agree. All I'm proposing here is how we can ensure we bundled and load the correct shared (across mappings; eg common-controller-scripts.js) dependencies when the mappings are being shared on the forum. This is essentially the same we already do when overlaying |
||
|
|
||
| ### Mixxx APIs | ||
|
|
||
| In order to obtain optimal developer experience of mixxx APIs in the execution | ||
| engine, each execution engine should have its own implementation that maps | ||
| idiomatically to the strengths of the execution engine. This is especially | ||
| important for QML, as it is a reaktive declarative language that does have many | ||
| more features than JS. This is essentially already the case in our current | ||
| codebase, see `*JSProxy` and `*QMLProxy` classes as examples. | ||
|
|
||
| ### Migration from `ControllerScriptEngineLegacy` | ||
|
|
||
| We can gradually transition to the new architecture by modelling the semantics | ||
| of `ControllerScriptEngineLegacy` as a separate execution engine. This would | ||
| allow us to gradually migrate old mappings to the new architecture. | ||
|
|
||
| ## Current unknowns | ||
|
|
||
| How feasible is the heuristic detection of sources and sinks? How do we handle | ||
| multiple sources/sinks of the same type originating from different controllers? | ||
| Eg how do we avoid that the screen from one piece of hardware is connected to | ||
| the wrong controller? | ||
|
|
||
| ## Alternatives | ||
|
|
||
| 1. Shoehorn the new architecture into the existing `ControllerScriptEngine` | ||
| class. This would not eliminate the one-controller-per-mapping limitation and | ||
| would not allow us to iterate on the design nor on the API. | ||
|
|
||
| ## Architecture summary | ||
|
|
||
| ```mermaid | ||
| flowchart LR | ||
| %% Define front-end web components | ||
| subgraph io["IO"] | ||
| co["Control Object"] | ||
| midiIO["Midi IO"] | ||
| hidIO["HID IO"] | ||
| mixxxLib["Mixxx Library"] | ||
| mixxxUi["Mixxx UI"] | ||
| end | ||
| style io fill:transparent,stroke:green,color:#fff | ||
|
|
||
| subgraph layers["Intermediary Layers"] | ||
| co---midiDispatcher["MIDI Dispatcher"] | ||
| midiIO---midiDispatcher | ||
| mixxxUi---uiShift["UI Shift Capability"] | ||
| end | ||
| style layers fill:transparent,stroke:yellow,color:#fff | ||
|
|
||
| subgraph proxies["API Proxies"] | ||
| co---coJSProxy["COJSProxy"] | ||
| co---coQMLProxy["COQmlProxy"] | ||
| midiIO---midiJSProxy["MIDI IO JSProxy"] | ||
| midiIO---midiQMLProxy["MIDI IO QmlProxy"] | ||
| hidIO---hidJSProxy["HID IO JSProxy"] | ||
| hidIO---hidQMLProxy["HID IO QMLProxy"] | ||
| midiDispatcher---midiDispatcherJSProxy["MIDI Dispatcher JSProxy"] | ||
| mixxxLib---libQmlProxy["Library QmlProxy"] | ||
| uiShift---CapJSProxy["Capability JSProxy"] | ||
| end | ||
| style proxies fill:transparent,stroke:cyan,color:#fff | ||
|
|
||
| subgraph engine["Execution Engine"] | ||
| coJSProxy---jsEngine["JSExecution Engine"] | ||
| midiJSProxy---jsEngine | ||
| hidJSProxy---jsEngine | ||
| hidQMLProxy---jsEngine | ||
|
Swiftb0y marked this conversation as resolved.
Outdated
|
||
| midiDispatcherJSProxy---jsEngine | ||
| CapJSProxy---jsEngine | ||
| coJSProxy---jsLegacyEngine["LegacyJS Execution Engine"] | ||
| hidJSProxy---jsLegacyEngine | ||
| hidQMLProxy---jsLegacyEngine | ||
| midiJSProxy---jsLegacyEngine | ||
| CapJSProxy---jsLegacyEngine | ||
| coQMLProxy---qmlEngine["QmlExecutionEngine"] | ||
| midiQMLProxy---qmlEngine | ||
| libQmlProxy---qmlEngine | ||
| end | ||
| style engine fill:transparent,stroke:red,color:#fff | ||
| ``` | ||
|
|
||
| ## Action Plan | ||
|
|
||
| The following action plan is very abstract because the architecture is designed | ||
| to be implemented gradually. Once we have decided on priorities, we can decide | ||
| on a more concrete plan. | ||
|
|
||
| 1. Define the abstract Manifest outline. | ||
| 2. Implement a concrete manifest parser of the basic outline. | ||
| 3. Choose any component from the architecture summary diagram and implement it | ||
| using tests and making instanstiable by via the manifest. | ||
| 4. Once 2 connected components are implemented, implement their connection via | ||
| the manifest. | ||
| 5. Repeat until all components are implemented. | ||
Uh oh!
There was an error while loading. Please reload this page.