From da9f1fff73ef1a93060e940c1b098eae74e72c29 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 2 Dec 2025 11:27:43 -0500 Subject: [PATCH 01/23] Controller Shared Data: Initial Proposal Signed-off-by: Owen Williams --- .../2025-12-02_controller_shared_data.md | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 proposals/2025-12-02_controller_shared_data.md diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md new file mode 100644 index 0000000..01d65b5 --- /dev/null +++ b/proposals/2025-12-02_controller_shared_data.md @@ -0,0 +1,156 @@ +# Controller Shared Data + +* **Owners:** + * `@ywwg` + * `@acolombier` + +* **Implementation Status:** `Partially implemented` + +* **Related Issues and PRs:** + * [Ability for controller to share data at runtime](https://github.com/mixxxdj/mixxx/pull/12199) + +> TL;DR: Allow controllers to set and get data objects of arbitrary type for sharing between the controller code and the engine. Think: ControlObjects of arbitrary type that controllers can declare. + +## Why + +There are multiple scenarios where controllers need to share and access data outside the container of the controller mapping file. +This includes situations where some controllers expose more than one USB device that need to communicate with each other, or when a DJ connects multiple instances of the same hardware to Mixxx. + +### Pitfalls of the current solution + +ControlObjects are the normal way we share data, but: + +* Controllers can't declare control objects. +* Putting controller-specific data inside Mixxx itself would be bad and lead to bloat. +* Controllers need to share more types of data than just double values. + +## Goals + +Goals and use cases for the solution as proposed in [How](#how): + +* Namespacing: Allow different controllers to declare same-named data objects without risk of collisions +* Support controllers with screens that require communication from HID to separate Bulk USB devices (Traktor S4 MK3). +* Build a data model foundation for users with multiple instances of the same controller (CDJ-2000). +* Design an API that can support the features we wish to add in the future without breaking controller mappings that use the API defined here. + +### Audience + +Users of modern controllers or multiple controllers will appreciate this work. +Specifically, this work is required to fully support the Traktor S4 MK3, which has separate devices for the controller and the two screens (two total USB devices). + +## Non-Goals + +* We do not intend to fully support the multi-device scenario yet, that needs further design to associate specific devices with specific controller configurations. +* We do not intend to immediately support "global" objects accessible across namespaces, like "universal shift". + +## "Universal Shift" + +"Universal Shift" refers to the idea that a shift button pressed on one controller can be detected by any and all other controllers. +This may be a useful use-case but creates a lot of difficulties that we are avoiding for now. + +## How + +### Data Object + +We will create a central object inside Mixxx that contains a triple-keyed map: + +* Namespace (string) + * Grouping (string) + * Key (string) + * Value (QVariant) + +#### Namespace + +`Namespace` is a string that is unique to each controller **mapping definition**. +All connected controllers of the same model will share the same namespace. +e.g. Two CDJ-2000's will both have a namespace like `CDJ_2000`. +No two hardware mappings will have the same namespace, and we can enforce that with a precommit check. + +#### Grouping + +`Grouping` is a logical value defined by the controller mapping definition. +It can be like a Mixxx-style group ("`[Channel1]`") but it can be any arbitrary string. +Many controllers will want to define something like `deck1` to refer to a device that can itself be assigned to multiple mixxx channels. +This document does not use the word `group`, instead prefering `grouping`, to try to differentiate Mixxx-style "groups" from this concept, which is a distinct abstraction. + +The controller mapping decides how these groups behave and Mixxx does no enforcement of them. +To reiterate: even if a "grouping" "looks like" a Mixxx group, it is not. + +#### Key + +`Key` is a logical value defined by the controller mapping definition. +It could refer to a button, light, knob, or abstract name. + +The controller mapping decides how these groups behave and Mixxx does no enforcement of them. +Similar to "grouping", keys bear no relation to equivalent Mixxx keys. + +#### Example + +The shift button on the left side of a Traktor S4MK3 would be stored this way: + +psuedocode: + +`sharedData["S4MK3"]["deck1"]["shift"] = true` + +### API + +The shared data API should be roughly the same across Controllers, QML, and C++. +The primary difference is that C++ will have access to the namespace value at all times, whereas controllers and QML will have that value elided. + +The controller javascript has access to the shared data object through three functions: + +#### Get + +excuse the pseudo-js: + +`engine.GetSharedData(grouping: string, key: string): Error | any` + +`namespace` is set automatically by the engine code, so controllers can't get that wrong. + +This function returns error if the value is not found. + +#### Set + +`engine.SetSharedData(grouping: string, key: string, value: any): void` + +`namespace` is set automatically by the engine code, so controllers can't get that wrong. + +Calling "set" triggers "updated" signals to all subscribers across the engine, QML (e.g. controller screen code), and controllers. + +Controllers do not get notified about updates they initiated themselves, to prevent circular signal loops. + +#### Updated + +Controllers get notified about data updates via a standard callback: + +`function SharedDataUpdated(grouping: string, key: string, value: any){}` + +Controllers get update calls for each updated item separately, and can handle them however they wish. + +### Possible extensions + +The following are possibile future extensions to this proposal that are currently out of scope and will not be implemented in the first version: + +#### Cross-device communication / subscription + +There is a possibility controller authors may want access to signals sent from other controllers, for instance a "universal shift" button. +For this purpose we may choose to allow controller to "subscribe" to updates from other namespaces, or all namespaces, in a read-only fashion. +In this scenario, controllers would not have the ability to write updates to namespaces outside their own. +This may be brittle because controllers would need to know about all possible valid namespaces, so this feature would need more care to make it maintainable. + +#### "Global" namespace + +Another possibility is that we may want a "global" namespaces that all controllers can read and write to. +This would be another way to support a "universal shift" button. +This would have to be carefully managed to prevent collisions between controller configs. +One way to do this would be to "bless" specific groupings and keys for the global namespace, and controller authors would have to add their requested global grouping/key to Mixxx. + +## Alternatives + +The original implementation did not have groupings and keys and instead had a single namespaced data blob that controllers had to manage themselves. +This approach requires a lot more work on the part of the controller author to merge and manage the data object. + +## Action Plan + +1. Build on the existing PR to implement the desired API +2. Rewrite the Traktor S4 MK3 mapping to support the new API. From 54c539e854c45eb1548ff66c7b4d689e5f41a0b6 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 2 Dec 2025 12:58:19 -0500 Subject: [PATCH 02/23] clarify future direction Signed-off-by: Owen Williams --- proposals/2025-12-02_controller_shared_data.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 01d65b5..31c7961 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -31,7 +31,7 @@ Goals and use cases for the solution as proposed in [How](#how): * Namespacing: Allow different controllers to declare same-named data objects without risk of collisions * Support controllers with screens that require communication from HID to separate Bulk USB devices (Traktor S4 MK3). * Build a data model foundation for users with multiple instances of the same controller (CDJ-2000). -* Design an API that can support the features we wish to add in the future without breaking controller mappings that use the API defined here. +* Ensure that the API could support the features we may wish to add in the future, such as global namespace, without breaking controller mappings that use the API defined here. ### Audience @@ -127,9 +127,9 @@ Controllers get notified about data updates via a standard callback: Controllers get update calls for each updated item separately, and can handle them however they wish. -### Possible extensions +### Possible future directions -The following are possibile future extensions to this proposal that are currently out of scope and will not be implemented in the first version: +The following are possibile future extensions to this proposal that are currently out of scope and will not be implemented in the first version, but we want to make sure to leave room in case we add them in the future: #### Cross-device communication / subscription From 8bce9f993474ac0f7db82166944bae2c4b038f5e Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 2 Dec 2025 13:00:00 -0500 Subject: [PATCH 03/23] more clarification Signed-off-by: Owen Williams --- proposals/2025-12-02_controller_shared_data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 31c7961..22d41c7 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -46,7 +46,7 @@ Specifically, this work is required to fully support the Traktor S4 MK3, which h ## "Universal Shift" "Universal Shift" refers to the idea that a shift button pressed on one controller can be detected by any and all other controllers. -This may be a useful use-case but creates a lot of difficulties that we are avoiding for now. +This may be a useful use-case but creates a lot of difficulties, so for now Universal Shift is out of scope for this first implementation. ## How From 207bc3509367aad373c92bd7626052692c3fce1d Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 2 Dec 2025 13:02:43 -0500 Subject: [PATCH 04/23] optional Signed-off-by: Owen Williams --- proposals/2025-12-02_controller_shared_data.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 22d41c7..0e2101d 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -121,11 +121,12 @@ Controllers do not get notified about updates they initiated themselves, to prev #### Updated -Controllers get notified about data updates via a standard callback: +Controllers get notified about data updates via a standard callback, which they can optionally implement: `function SharedDataUpdated(grouping: string, key: string, value: any){}` Controllers get update calls for each updated item separately, and can handle them however they wish. +There is no effect (no logging or error) If a controller does not implement this function. ### Possible future directions From ccac3837191722eebb8139da692420f63b000ad7 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 2 Dec 2025 13:10:57 -0500 Subject: [PATCH 05/23] spelling Signed-off-by: Owen Williams --- proposals/2025-12-02_controller_shared_data.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 0e2101d..949361b 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -71,7 +71,7 @@ No two hardware mappings will have the same namespace, and we can enforce that w `Grouping` is a logical value defined by the controller mapping definition. It can be like a Mixxx-style group ("`[Channel1]`") but it can be any arbitrary string. Many controllers will want to define something like `deck1` to refer to a device that can itself be assigned to multiple mixxx channels. -This document does not use the word `group`, instead prefering `grouping`, to try to differentiate Mixxx-style "groups" from this concept, which is a distinct abstraction. +This document does not use the word `group`, instead preferring `grouping`, to try to differentiate Mixxx-style "groups" from this concept, which is a distinct abstraction. The controller mapping decides how these groups behave and Mixxx does no enforcement of them. To reiterate: even if a "grouping" "looks like" a Mixxx group, it is not. @@ -88,7 +88,7 @@ Similar to "grouping", keys bear no relation to equivalent Mixxx keys. The shift button on the left side of a Traktor S4MK3 would be stored this way: -psuedocode: +pseudocode: `sharedData["S4MK3"]["deck1"]["shift"] = true` @@ -130,7 +130,7 @@ There is no effect (no logging or error) If a controller does not implement this ### Possible future directions -The following are possibile future extensions to this proposal that are currently out of scope and will not be implemented in the first version, but we want to make sure to leave room in case we add them in the future: +The following are possible future extensions to this proposal that are currently out of scope and will not be implemented in the first version, but we want to make sure to leave room in case we add them in the future: #### Cross-device communication / subscription From c44cf037cf2df179286a1859d411ecb936858d53 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 2 Dec 2025 13:18:32 -0500 Subject: [PATCH 06/23] wrap text to satisfy precommit Signed-off-by: Owen Williams --- .../2025-12-02_controller_shared_data.md | 138 ++++++++++++------ 1 file changed, 90 insertions(+), 48 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 949361b..8a2a0fc 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -7,46 +7,65 @@ * **Implementation Status:** `Partially implemented` * **Related Issues and PRs:** - * [Ability for controller to share data at runtime](https://github.com/mixxxdj/mixxx/pull/12199) + * [Ability for controller to share data at + runtime](https://github.com/mixxxdj/mixxx/pull/12199) -> TL;DR: Allow controllers to set and get data objects of arbitrary type for sharing between the controller code and the engine. Think: ControlObjects of arbitrary type that controllers can declare. +> TL;DR: Allow controllers to set and get data objects of arbitrary type for +> sharing between the controller code and the engine. Think: ControlObjects of +> arbitrary type that controllers can declare. ## Why -There are multiple scenarios where controllers need to share and access data outside the container of the controller mapping file. -This includes situations where some controllers expose more than one USB device that need to communicate with each other, or when a DJ connects multiple instances of the same hardware to Mixxx. +There are multiple scenarios where controllers need to share and access data +outside the container of the controller mapping file. This includes situations +where some controllers expose more than one USB device that need to communicate +with each other, or when a DJ connects multiple instances of the same hardware +to Mixxx. ### Pitfalls of the current solution ControlObjects are the normal way we share data, but: * Controllers can't declare control objects. -* Putting controller-specific data inside Mixxx itself would be bad and lead to bloat. +* Putting controller-specific data inside Mixxx itself would be bad and lead to + bloat. * Controllers need to share more types of data than just double values. ## Goals Goals and use cases for the solution as proposed in [How](#how): -* Namespacing: Allow different controllers to declare same-named data objects without risk of collisions -* Support controllers with screens that require communication from HID to separate Bulk USB devices (Traktor S4 MK3). -* Build a data model foundation for users with multiple instances of the same controller (CDJ-2000). -* Ensure that the API could support the features we may wish to add in the future, such as global namespace, without breaking controller mappings that use the API defined here. +* Namespacing: Allow different controllers to declare same-named data objects + without risk of collisions +* Support controllers with screens that require communication from HID to + separate Bulk USB devices (Traktor S4 MK3). +* Build a data model foundation for users with multiple instances of the same + controller (CDJ-2000). +* Ensure that the API could support the features we may wish to add in the + future, such as global namespace, without breaking controller mappings that + use the API defined here. ### Audience Users of modern controllers or multiple controllers will appreciate this work. -Specifically, this work is required to fully support the Traktor S4 MK3, which has separate devices for the controller and the two screens (two total USB devices). +Specifically, this work is required to fully support the Traktor S4 MK3, which +has separate devices for the controller and the two screens (two total USB +devices). ## Non-Goals -* We do not intend to fully support the multi-device scenario yet, that needs further design to associate specific devices with specific controller configurations. -* We do not intend to immediately support "global" objects accessible across namespaces, like "universal shift". +* We do not intend to fully support the multi-device scenario yet, that needs + further design to associate specific devices with specific controller + configurations. +* We do not intend to immediately support "global" objects accessible across + namespaces, like "universal shift". ## "Universal Shift" -"Universal Shift" refers to the idea that a shift button pressed on one controller can be detected by any and all other controllers. -This may be a useful use-case but creates a lot of difficulties, so for now Universal Shift is out of scope for this first implementation. +"Universal Shift" refers to the idea that a shift button pressed on one +controller can be detected by any and all other controllers. This may be a +useful use-case but creates a lot of difficulties, so for now Universal Shift is +out of scope for this first implementation. ## How @@ -61,28 +80,34 @@ We will create a central object inside Mixxx that contains a triple-keyed map: #### Namespace -`Namespace` is a string that is unique to each controller **mapping definition**. -All connected controllers of the same model will share the same namespace. -e.g. Two CDJ-2000's will both have a namespace like `CDJ_2000`. -No two hardware mappings will have the same namespace, and we can enforce that with a precommit check. +`Namespace` is a string that is unique to each controller **mapping +definition**. All connected controllers of the same model will share the same +namespace. e.g. Two CDJ-2000's will both have a namespace like `CDJ_2000`. No +two hardware mappings will have the same namespace, and we can enforce that with +a precommit check. #### Grouping -`Grouping` is a logical value defined by the controller mapping definition. -It can be like a Mixxx-style group ("`[Channel1]`") but it can be any arbitrary string. -Many controllers will want to define something like `deck1` to refer to a device that can itself be assigned to multiple mixxx channels. -This document does not use the word `group`, instead preferring `grouping`, to try to differentiate Mixxx-style "groups" from this concept, which is a distinct abstraction. +`Grouping` is a logical value defined by the controller mapping definition. It +can be like a Mixxx-style group ("`[Channel1]`") but it can be any arbitrary +string. Many controllers will want to define something like `deck1` to refer to +a device that can itself be assigned to multiple mixxx channels. This document +does not use the word `group`, instead preferring `grouping`, to try to +differentiate Mixxx-style "groups" from this concept, which is a distinct +abstraction. -The controller mapping decides how these groups behave and Mixxx does no enforcement of them. -To reiterate: even if a "grouping" "looks like" a Mixxx group, it is not. +The controller mapping decides how these groups behave and Mixxx does no +enforcement of them. To reiterate: even if a "grouping" "looks like" a Mixxx +group, it is not. #### Key -`Key` is a logical value defined by the controller mapping definition. -It could refer to a button, light, knob, or abstract name. +`Key` is a logical value defined by the controller mapping definition. It could +refer to a button, light, knob, or abstract name. -The controller mapping decides how these groups behave and Mixxx does no enforcement of them. -Similar to "grouping", keys bear no relation to equivalent Mixxx keys. +The controller mapping decides how these groups behave and Mixxx does no +enforcement of them. Similar to "grouping", keys bear no relation to equivalent +Mixxx keys. #### Example @@ -95,9 +120,11 @@ pseudocode: ### API The shared data API should be roughly the same across Controllers, QML, and C++. -The primary difference is that C++ will have access to the namespace value at all times, whereas controllers and QML will have that value elided. +The primary difference is that C++ will have access to the namespace value at +all times, whereas controllers and QML will have that value elided. -The controller javascript has access to the shared data object through three functions: +The controller javascript has access to the shared data object through three +functions: #### Get @@ -105,7 +132,8 @@ excuse the pseudo-js: `engine.GetSharedData(grouping: string, key: string): Error | any` -`namespace` is set automatically by the engine code, so controllers can't get that wrong. +`namespace` is set automatically by the engine code, so controllers can't get +that wrong. This function returns error if the value is not found. @@ -113,43 +141,57 @@ This function returns error if the value is not found. `engine.SetSharedData(grouping: string, key: string, value: any): void` -`namespace` is set automatically by the engine code, so controllers can't get that wrong. +`namespace` is set automatically by the engine code, so controllers can't get +that wrong. -Calling "set" triggers "updated" signals to all subscribers across the engine, QML (e.g. controller screen code), and controllers. +Calling "set" triggers "updated" signals to all subscribers across the engine, +QML (e.g. controller screen code), and controllers. -Controllers do not get notified about updates they initiated themselves, to prevent circular signal loops. +Controllers do not get notified about updates they initiated themselves, to +prevent circular signal loops. #### Updated -Controllers get notified about data updates via a standard callback, which they can optionally implement: +Controllers get notified about data updates via a standard callback, which they +can optionally implement: `function SharedDataUpdated(grouping: string, key: string, value: any){}` -Controllers get update calls for each updated item separately, and can handle them however they wish. -There is no effect (no logging or error) If a controller does not implement this function. +Controllers get update calls for each updated item separately, and can handle +them however they wish. There is no effect (no logging or error) If a controller +does not implement this function. ### Possible future directions -The following are possible future extensions to this proposal that are currently out of scope and will not be implemented in the first version, but we want to make sure to leave room in case we add them in the future: +The following are possible future extensions to this proposal that are currently +out of scope and will not be implemented in the first version, but we want to +make sure to leave room in case we add them in the future: #### Cross-device communication / subscription -There is a possibility controller authors may want access to signals sent from other controllers, for instance a "universal shift" button. -For this purpose we may choose to allow controller to "subscribe" to updates from other namespaces, or all namespaces, in a read-only fashion. -In this scenario, controllers would not have the ability to write updates to namespaces outside their own. -This may be brittle because controllers would need to know about all possible valid namespaces, so this feature would need more care to make it maintainable. +There is a possibility controller authors may want access to signals sent from +other controllers, for instance a "universal shift" button. For this purpose we +may choose to allow controller to "subscribe" to updates from other namespaces, +or all namespaces, in a read-only fashion. In this scenario, controllers would +not have the ability to write updates to namespaces outside their own. This may +be brittle because controllers would need to know about all possible valid +namespaces, so this feature would need more care to make it maintainable. #### "Global" namespace -Another possibility is that we may want a "global" namespaces that all controllers can read and write to. -This would be another way to support a "universal shift" button. -This would have to be carefully managed to prevent collisions between controller configs. -One way to do this would be to "bless" specific groupings and keys for the global namespace, and controller authors would have to add their requested global grouping/key to Mixxx. +Another possibility is that we may want a "global" namespaces that all +controllers can read and write to. This would be another way to support a +"universal shift" button. This would have to be carefully managed to prevent +collisions between controller configs. One way to do this would be to "bless" +specific groupings and keys for the global namespace, and controller authors +would have to add their requested global grouping/key to Mixxx. ## Alternatives -The original implementation did not have groupings and keys and instead had a single namespaced data blob that controllers had to manage themselves. -This approach requires a lot more work on the part of the controller author to merge and manage the data object. +The original implementation did not have groupings and keys and instead had a +single namespaced data blob that controllers had to manage themselves. This +approach requires a lot more work on the part of the controller author to merge +and manage the data object. ## Action Plan From bcf509843cf35a846723f6cbd9c5efa876634ed4 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 2 Dec 2025 14:57:19 -0500 Subject: [PATCH 07/23] grouping -> entity Signed-off-by: Owen Williams --- .../2025-12-02_controller_shared_data.md | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 8a2a0fc..c883392 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -74,7 +74,7 @@ out of scope for this first implementation. We will create a central object inside Mixxx that contains a triple-keyed map: * Namespace (string) - * Grouping (string) + * Entity (string) * Key (string) * Value (QVariant) @@ -86,18 +86,15 @@ namespace. e.g. Two CDJ-2000's will both have a namespace like `CDJ_2000`. No two hardware mappings will have the same namespace, and we can enforce that with a precommit check. -#### Grouping +#### Entity -`Grouping` is a logical value defined by the controller mapping definition. It +`Entity` is a logical value defined by the controller mapping definition. It can be like a Mixxx-style group ("`[Channel1]`") but it can be any arbitrary string. Many controllers will want to define something like `deck1` to refer to -a device that can itself be assigned to multiple mixxx channels. This document -does not use the word `group`, instead preferring `grouping`, to try to -differentiate Mixxx-style "groups" from this concept, which is a distinct -abstraction. +a device that can itself be assigned to multiple mixxx channels. -The controller mapping decides how these groups behave and Mixxx does no -enforcement of them. To reiterate: even if a "grouping" "looks like" a Mixxx +The controller mapping decides how these entities behave and Mixxx does no +enforcement of them. To reiterate: even if an "entity" "looks like" a Mixxx group, it is not. #### Key @@ -105,8 +102,8 @@ group, it is not. `Key` is a logical value defined by the controller mapping definition. It could refer to a button, light, knob, or abstract name. -The controller mapping decides how these groups behave and Mixxx does no -enforcement of them. Similar to "grouping", keys bear no relation to equivalent +The controller mapping decides how these keys behave and Mixxx does no +enforcement of them. Similar to "entity", keys bear no relation to equivalent Mixxx keys. #### Example @@ -130,7 +127,7 @@ functions: excuse the pseudo-js: -`engine.GetSharedData(grouping: string, key: string): Error | any` +`engine.GetSharedData(entity: string, key: string): Error | any` `namespace` is set automatically by the engine code, so controllers can't get that wrong. @@ -139,7 +136,7 @@ This function returns error if the value is not found. #### Set -`engine.SetSharedData(grouping: string, key: string, value: any): void` +`engine.SetSharedData(entity: string, key: string, value: any): void` `namespace` is set automatically by the engine code, so controllers can't get that wrong. @@ -155,7 +152,7 @@ prevent circular signal loops. Controllers get notified about data updates via a standard callback, which they can optionally implement: -`function SharedDataUpdated(grouping: string, key: string, value: any){}` +`function SharedDataUpdated(entity: string, key: string, value: any){}` Controllers get update calls for each updated item separately, and can handle them however they wish. There is no effect (no logging or error) If a controller @@ -183,12 +180,12 @@ Another possibility is that we may want a "global" namespaces that all controllers can read and write to. This would be another way to support a "universal shift" button. This would have to be carefully managed to prevent collisions between controller configs. One way to do this would be to "bless" -specific groupings and keys for the global namespace, and controller authors -would have to add their requested global grouping/key to Mixxx. +specific entities and keys for the global namespace, and controller authors +would have to add their requested global entity/key to Mixxx. ## Alternatives -The original implementation did not have groupings and keys and instead had a +The original implementation did not have entities and keys and instead had a single namespaced data blob that controllers had to manage themselves. This approach requires a lot more work on the part of the controller author to merge and manage the data object. From a7bc66fec34fc6ad78e723f315e4a17c1bfb6eed Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Wed, 3 Dec 2025 11:27:11 -0500 Subject: [PATCH 08/23] tighten allowed value types Signed-off-by: Owen Williams --- proposals/2025-12-02_controller_shared_data.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index c883392..a0b8779 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -106,6 +106,11 @@ The controller mapping decides how these keys behave and Mixxx does no enforcement of them. Similar to "entity", keys bear no relation to equivalent Mixxx keys. +#### Value + +In the engine, the `value` is stored as a QVariant, however we want to only support a limited set of types in Javascript / Typescript: double, bool, and string. +The list of allowable types can be expanded as needed, but we want to be sure that the shared data system does not become a "bag of bytes" message bus for large pieces of data like bitmaps or code, nor should it be used to circumvent intentional limitations or gaps in the overall javascript framework. + #### Example The shift button on the left side of a Traktor S4MK3 would be stored this way: From 4b6ebfaf802334ae711526faa521e07c0d2523b6 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Fri, 5 Dec 2025 14:34:14 -0500 Subject: [PATCH 09/23] SafeData Signed-off-by: Owen Williams --- .../2025-12-02_controller_shared_data.md | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index a0b8779..dede62d 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -76,7 +76,7 @@ We will create a central object inside Mixxx that contains a triple-keyed map: * Namespace (string) * Entity (string) * Key (string) - * Value (QVariant) + * Value ("SafeData") #### Namespace @@ -108,8 +108,22 @@ Mixxx keys. #### Value -In the engine, the `value` is stored as a QVariant, however we want to only support a limited set of types in Javascript / Typescript: double, bool, and string. -The list of allowable types can be expanded as needed, but we want to be sure that the shared data system does not become a "bag of bytes" message bus for large pieces of data like bitmaps or code, nor should it be used to circumvent intentional limitations or gaps in the overall javascript framework. +In the engine, the `value` is stored as a QVariant, however we want to only +support a limited set of types in Javascript / Typescript. For the first +implementation, we will support bool, number, and string, and Arrays of those: + +```typescript +type SafePrimitive = string | number | boolean | null; + +type SafeData = + | SafePrimitive + | SafePrimitive[]; +``` + +The list of allowable types can be expanded as needed, but we want to be sure +that the shared data system does not become a "bag of bytes" message bus for +large pieces of data like bitmaps or code, nor should it be used to circumvent +intentional limitations or gaps in the overall javascript framework. #### Example From 865ef6f74ef4ce713e85ef20a6fe76e7f5c9907d Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Fri, 5 Dec 2025 14:42:19 -0500 Subject: [PATCH 10/23] qjsvalue Signed-off-by: Owen Williams --- proposals/2025-12-02_controller_shared_data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index dede62d..576303e 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -108,7 +108,7 @@ Mixxx keys. #### Value -In the engine, the `value` is stored as a QVariant, however we want to only +In the engine, the `value` is stored as a QJSValue, however we want to only support a limited set of types in Javascript / Typescript. For the first implementation, we will support bool, number, and string, and Arrays of those: From e92fbeebef5fb6f525bb5ca52476d0a9750cebf4 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Mon, 8 Dec 2025 12:19:42 -0500 Subject: [PATCH 11/23] Update proposals/2025-12-02_controller_shared_data.md Co-authored-by: Antoine Colombier <7086688+acolombier@users.noreply.github.com> --- proposals/2025-12-02_controller_shared_data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 576303e..9d2b9df 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -146,7 +146,7 @@ functions: excuse the pseudo-js: -`engine.GetSharedData(entity: string, key: string): Error | any` +`engine.getSharedData(entity: Entity, key: string): SafeData?` `namespace` is set automatically by the engine code, so controllers can't get that wrong. From 64f00a25ceb05aabe2e258eb443b334638cd4683 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 9 Dec 2025 20:06:56 -0500 Subject: [PATCH 12/23] address notes Signed-off-by: Owen Williams --- .../2025-12-02_controller_shared_data.md | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 576303e..c29c4bc 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -97,6 +97,24 @@ The controller mapping decides how these entities behave and Mixxx does no enforcement of them. To reiterate: even if an "entity" "looks like" a Mixxx group, it is not. +Here is partial suggestion for entity definition, which could be extended over +time. + +```typescript +declare Entities { +type Mixer = 'mixer'; +type Main = 'main'; +type Library = 'library'; +type Decks = 'deck1' | 'deck2' | 'deck3' | 'deck4'; +type Channels = 'channel1' | 'channel2' | 'channel3' | 'channel4'; +type Controller = 'controller'; +} +type Entity = Entities.Mixer | Entities.Main | Entities.Library | Entities.Decks | Entities.Channels | Entities.Controller; +``` + +Numbered entity names could also be validated with a regular expression such as +`deck[0-9]+`. + #### Key `Key` is a logical value defined by the controller mapping definition. It could @@ -129,9 +147,9 @@ intentional limitations or gaps in the overall javascript framework. The shift button on the left side of a Traktor S4MK3 would be stored this way: -pseudocode: +pseudocode -- not final naming: -`sharedData["S4MK3"]["deck1"]["shift"] = true` +`m_shared_data["S4MK3"]["deck1"]["shift"] = true` ### API @@ -146,7 +164,7 @@ functions: excuse the pseudo-js: -`engine.GetSharedData(entity: string, key: string): Error | any` +`engine.getSharedData(entity: Entity, key: string): SafeData?` `namespace` is set automatically by the engine code, so controllers can't get that wrong. @@ -155,7 +173,7 @@ This function returns error if the value is not found. #### Set -`engine.SetSharedData(entity: string, key: string, value: any): void` +`engine.getSharedData(entity: Entity, key: string, value: SafeData): void` `namespace` is set automatically by the engine code, so controllers can't get that wrong. @@ -168,14 +186,15 @@ prevent circular signal loops. #### Updated -Controllers get notified about data updates via a standard callback, which they -can optionally implement: +Controllers can subscribe to notifications about data updates via a method +similar to how they subscribe to engine Control Object updates: + +(not final naming) -`function SharedDataUpdated(entity: string, key: string, value: any){}` +`function makeSharedDataConnection(entity: Entity, name: string, callback: CoCallback): ScriptConnection | undefined;` -Controllers get update calls for each updated item separately, and can handle -them however they wish. There is no effect (no logging or error) If a controller -does not implement this function. +In this first implementation, controllers can only subscribe to updates for +their own namespace. ### Possible future directions From d3923e92bdf29e7bfb30117534de1705540c8be7 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 9 Dec 2025 20:08:23 -0500 Subject: [PATCH 13/23] typo Signed-off-by: Owen Williams --- proposals/2025-12-02_controller_shared_data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index c29c4bc..86cc8ad 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -173,7 +173,7 @@ This function returns error if the value is not found. #### Set -`engine.getSharedData(entity: Entity, key: string, value: SafeData): void` +`engine.setSharedData(entity: Entity, key: string, value: SafeData): void` `namespace` is set automatically by the engine code, so controllers can't get that wrong. From 82b35592b42865439e99c90e76a06a67916a2dbd Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 9 Dec 2025 20:09:47 -0500 Subject: [PATCH 14/23] qvariant, not qjsvalue Signed-off-by: Owen Williams --- proposals/2025-12-02_controller_shared_data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 86cc8ad..70b9039 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -126,7 +126,7 @@ Mixxx keys. #### Value -In the engine, the `value` is stored as a QJSValue, however we want to only +In the engine, the `value` is stored as a QVariant, however we want to only support a limited set of types in Javascript / Typescript. For the first implementation, we will support bool, number, and string, and Arrays of those: From 4f185334ec0676107d17d1be7e751e2ae6220b6b Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 16 Dec 2025 15:17:40 -0500 Subject: [PATCH 15/23] Update proposals/2025-12-02_controller_shared_data.md Co-authored-by: JoergAtGithub <64457745+JoergAtGithub@users.noreply.github.com> --- proposals/2025-12-02_controller_shared_data.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 70b9039..2e9a431 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -10,8 +10,7 @@ * [Ability for controller to share data at runtime](https://github.com/mixxxdj/mixxx/pull/12199) -> TL;DR: Allow controllers to set and get data objects of arbitrary type for -> sharing between the controller code and the engine. Think: ControlObjects of +> TL;DR: Allow controllers mappings to set and retrieve variables of different data types in order to exchange them between the controller code and the engine. Think: ControlObjects of > arbitrary type that controllers can declare. ## Why From c87b346c58f410358415be173836b9f5c7ac8038 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 16 Dec 2025 15:19:09 -0500 Subject: [PATCH 16/23] Apply suggestions from code review Co-authored-by: JoergAtGithub <64457745+JoergAtGithub@users.noreply.github.com> --- proposals/2025-12-02_controller_shared_data.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 2e9a431..3528ac9 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -87,10 +87,15 @@ a precommit check. #### Entity -`Entity` is a logical value defined by the controller mapping definition. It +`Entity` is a logical value defined by the controller mapping definition or during the initialization of the mapping script (e.g. for readout of a serial number using MIDI commands). It can be like a Mixxx-style group ("`[Channel1]`") but it can be any arbitrary string. Many controllers will want to define something like `deck1` to refer to a device that can itself be assigned to multiple mixxx channels. +For the case of multiple devices of the same type, it is intended to implement functionality to gather a unique device identifier in a later step. These will than be used as Entity to distinguish the identical devices. +These identifiers include, but are not limited to: + +- USB device serial number (only works for USB and not each manufacturer use unique serial numbers) +- Operating system provided device identifiers like Container-ID on Windows or Location-ID on macOS The controller mapping decides how these entities behave and Mixxx does no enforcement of them. To reiterate: even if an "entity" "looks like" a Mixxx @@ -163,7 +168,7 @@ functions: excuse the pseudo-js: -`engine.getSharedData(entity: Entity, key: string): SafeData?` +`engine.getSharedValue(entity: Entity|string, key: string): SafeData?` `namespace` is set automatically by the engine code, so controllers can't get that wrong. From c74b978c280246fa158669db18f7c655a7f947e4 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 16 Dec 2025 15:19:34 -0500 Subject: [PATCH 17/23] Update proposals/2025-12-02_controller_shared_data.md Co-authored-by: JoergAtGithub <64457745+JoergAtGithub@users.noreply.github.com> --- proposals/2025-12-02_controller_shared_data.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 3528ac9..e76f519 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -48,8 +48,8 @@ Goals and use cases for the solution as proposed in [How](#how): Users of modern controllers or multiple controllers will appreciate this work. Specifically, this work is required to fully support the Traktor S4 MK3, which -has separate devices for the controller and the two screens (two total USB -devices). +has separate USB interfaces for the controller and the two screens (two total USB +interfaces). ## Non-Goals From 7fcb53f2cf966b9ea5afc72b3d8d3c85d96fbe4b Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 16 Dec 2025 15:20:03 -0500 Subject: [PATCH 18/23] Update proposals/2025-12-02_controller_shared_data.md Co-authored-by: JoergAtGithub <64457745+JoergAtGithub@users.noreply.github.com> --- proposals/2025-12-02_controller_shared_data.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index e76f519..862dd25 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -15,9 +15,8 @@ ## Why -There are multiple scenarios where controllers need to share and access data -outside the container of the controller mapping file. This includes situations -where some controllers expose more than one USB device that need to communicate +There are multiple scenarios where controller mapping scripts need to share and access data outside the container of their own controller script engine. This includes situations +where some controllers expose more than one USB interface that need to communicate with each other, or when a DJ connects multiple instances of the same hardware to Mixxx. From 9505f69b6f2268276c5b1e29e1fceaf8df94d2e5 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 16 Dec 2025 15:21:41 -0500 Subject: [PATCH 19/23] word wrap / lint Signed-off-by: Owen Williams --- .../2025-12-02_controller_shared_data.md | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 862dd25..c364f9b 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -10,15 +10,17 @@ * [Ability for controller to share data at runtime](https://github.com/mixxxdj/mixxx/pull/12199) -> TL;DR: Allow controllers mappings to set and retrieve variables of different data types in order to exchange them between the controller code and the engine. Think: ControlObjects of -> arbitrary type that controllers can declare. +> TL;DR: Allow controllers mappings to set and retrieve variables of different +> data types in order to exchange them between the controller code and the +> engine. Think: ControlObjects of arbitrary type that controllers can declare. ## Why -There are multiple scenarios where controller mapping scripts need to share and access data outside the container of their own controller script engine. This includes situations -where some controllers expose more than one USB interface that need to communicate -with each other, or when a DJ connects multiple instances of the same hardware -to Mixxx. +There are multiple scenarios where controller mapping scripts need to share and +access data outside the container of their own controller script engine. This +includes situations where some controllers expose more than one USB interface +that need to communicate with each other, or when a DJ connects multiple +instances of the same hardware to Mixxx. ### Pitfalls of the current solution @@ -86,15 +88,20 @@ a precommit check. #### Entity -`Entity` is a logical value defined by the controller mapping definition or during the initialization of the mapping script (e.g. for readout of a serial number using MIDI commands). It -can be like a Mixxx-style group ("`[Channel1]`") but it can be any arbitrary -string. Many controllers will want to define something like `deck1` to refer to -a device that can itself be assigned to multiple mixxx channels. -For the case of multiple devices of the same type, it is intended to implement functionality to gather a unique device identifier in a later step. These will than be used as Entity to distinguish the identical devices. -These identifiers include, but are not limited to: - -- USB device serial number (only works for USB and not each manufacturer use unique serial numbers) -- Operating system provided device identifiers like Container-ID on Windows or Location-ID on macOS +`Entity` is a logical value defined by the controller mapping definition or +during the initialization of the mapping script (e.g. for readout of a serial +number using MIDI commands). It can be like a Mixxx-style group ("`[Channel1]`") +but it can be any arbitrary string. Many controllers will want to define +something like `deck1` to refer to a device that can itself be assigned to +multiple mixxx channels. For the case of multiple devices of the same type, it +is intended to implement functionality to gather a unique device identifier in a +later step. These will than be used as Entity to distinguish the identical +devices. These identifiers include, but are not limited to: + +* USB device serial number (only works for USB and not each manufacturer use + unique serial numbers) +* Operating system provided device identifiers like Container-ID on Windows or + Location-ID on macOS The controller mapping decides how these entities behave and Mixxx does no enforcement of them. To reiterate: even if an "entity" "looks like" a Mixxx From 9c71d508e67f158763f89afaccd757eea61237df Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 16 Dec 2025 15:22:55 -0500 Subject: [PATCH 20/23] tweak Signed-off-by: Owen Williams --- proposals/2025-12-02_controller_shared_data.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index c364f9b..60d9660 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -82,9 +82,8 @@ We will create a central object inside Mixxx that contains a triple-keyed map: `Namespace` is a string that is unique to each controller **mapping definition**. All connected controllers of the same model will share the same -namespace. e.g. Two CDJ-2000's will both have a namespace like `CDJ_2000`. No -two hardware mappings will have the same namespace, and we can enforce that with -a precommit check. +namespace. e.g. Two CDJ-2000's will both have a namespace like `CDJ_2000`. All +hardware mappings must have distinct namespaces. #### Entity From 38d7025814b18c889a7810b8f8f6b70b054c2e56 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Thu, 18 Dec 2025 16:00:34 -0500 Subject: [PATCH 21/23] notes based on meeting Signed-off-by: Owen Williams --- .../2025-12-02_controller_shared_data.md | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 60d9660..42d1db9 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -81,40 +81,42 @@ We will create a central object inside Mixxx that contains a triple-keyed map: #### Namespace `Namespace` is a string that is unique to each controller **mapping -definition**. All connected controllers of the same model will share the same -namespace. e.g. Two CDJ-2000's will both have a namespace like `CDJ_2000`. All -hardware mappings must have distinct namespaces. +definition**. All hardware mapping configurations must specify distinct +namespaces. + +Multiple device support is still out of scope for this proposal, but we +anticipate that this design can expand to support that use case. For example, +the namespace MAY have a suffix appended to distinguish distinct devices based +on an automatically-detected unique device identifier, e.g. two CDJ-2000's could +have namespaces like `CDJ_2000-ABCDEF` and `CDJ_2000-FEDBCA`. This suffix would +be applied in C++ code outside of the awareness of the controller mapping. + +If a unique serial number cannot be determined at runtime, a special controller +preference (defined in Mixxx, not controller mappings) could be used to map +which controller is associated with which device through a new API, and this +value will be passed to controller mappings. #### Entity -`Entity` is a logical value defined by the controller mapping definition or -during the initialization of the mapping script (e.g. for readout of a serial -number using MIDI commands). It can be like a Mixxx-style group ("`[Channel1]`") -but it can be any arbitrary string. Many controllers will want to define -something like `deck1` to refer to a device that can itself be assigned to -multiple mixxx channels. For the case of multiple devices of the same type, it -is intended to implement functionality to gather a unique device identifier in a -later step. These will than be used as Entity to distinguish the identical -devices. These identifiers include, but are not limited to: - -* USB device serial number (only works for USB and not each manufacturer use - unique serial numbers) -* Operating system provided device identifiers like Container-ID on Windows or - Location-ID on macOS - -The controller mapping decides how these entities behave and Mixxx does no +`Entity` is a logical value defined by the controller mapping definition. It can +be like a Mixxx-style group ("`[Channel1]`") but it can be any of the +preselected names listed below. Many controllers will want to define something +like `deck1` to refer to a device that can itself be assigned to multiple mixxx +channels. + +The controller mapping decides how these entities behave and Mixxx does not enforcement of them. To reiterate: even if an "entity" "looks like" a Mixxx group, it is not. -Here is partial suggestion for entity definition, which could be extended over -time. +Here is the proposed initial description for entity definition, which is +anticipated be extended over time. ```typescript declare Entities { type Mixer = 'mixer'; type Main = 'main'; type Library = 'library'; -type Decks = 'deck1' | 'deck2' | 'deck3' | 'deck4'; +type Decks = 'deck1' | 'deck2'; type Channels = 'channel1' | 'channel2' | 'channel3' | 'channel4'; type Controller = 'controller'; } @@ -173,7 +175,7 @@ functions: excuse the pseudo-js: -`engine.getSharedValue(entity: Entity|string, key: string): SafeData?` +`engine.getSharedValue(entity: Entity, key: string): SafeData?` `namespace` is set automatically by the engine code, so controllers can't get that wrong. From d9fee84d7fbc95979c374ab6c3bae45479c8dfa3 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Thu, 18 Dec 2025 16:05:25 -0500 Subject: [PATCH 22/23] notes based on meeting Signed-off-by: Owen Williams --- proposals/2025-12-02_controller_shared_data.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index 42d1db9..eb44e52 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -126,6 +126,9 @@ type Entity = Entities.Mixer | Entities.Main | Entities.Library | Entities.Decks Numbered entity names could also be validated with a regular expression such as `deck[0-9]+`. +'Entity' values are enforced by Typescript library code before function calls +are handed off to C++. + #### Key `Key` is a logical value defined by the controller mapping definition. It could From 222f7edba834424de9533dee7a2af0fdb5c15542 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Thu, 18 Dec 2025 16:08:23 -0500 Subject: [PATCH 23/23] last notes in meeting Signed-off-by: Owen Williams --- proposals/2025-12-02_controller_shared_data.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/proposals/2025-12-02_controller_shared_data.md b/proposals/2025-12-02_controller_shared_data.md index eb44e52..6e321b8 100644 --- a/proposals/2025-12-02_controller_shared_data.md +++ b/proposals/2025-12-02_controller_shared_data.md @@ -76,7 +76,7 @@ We will create a central object inside Mixxx that contains a triple-keyed map: * Namespace (string) * Entity (string) * Key (string) - * Value ("SafeData") + * Value ("SafeValue") #### Namespace @@ -147,7 +147,7 @@ implementation, we will support bool, number, and string, and Arrays of those: ```typescript type SafePrimitive = string | number | boolean | null; -type SafeData = +type SafeValue = | SafePrimitive | SafePrimitive[]; ``` @@ -163,7 +163,7 @@ The shift button on the left side of a Traktor S4MK3 would be stored this way: pseudocode -- not final naming: -`m_shared_data["S4MK3"]["deck1"]["shift"] = true` +`m_shared_value["S4MK3"]["deck1"]["shift"] = true` ### API @@ -171,7 +171,7 @@ The shared data API should be roughly the same across Controllers, QML, and C++. The primary difference is that C++ will have access to the namespace value at all times, whereas controllers and QML will have that value elided. -The controller javascript has access to the shared data object through three +The controller javascript has access to the shared value object through three functions: #### Get @@ -187,7 +187,7 @@ This function returns error if the value is not found. #### Set -`engine.setSharedData(entity: Entity, key: string, value: SafeData): void` +`engine.setSharedValue(entity: Entity, key: string, value: SafeData): void` `namespace` is set automatically by the engine code, so controllers can't get that wrong. @@ -205,7 +205,7 @@ similar to how they subscribe to engine Control Object updates: (not final naming) -`function makeSharedDataConnection(entity: Entity, name: string, callback: CoCallback): ScriptConnection | undefined;` +`function makeSharedValueConnection(entity: Entity, name: string, callback: CoCallback): ScriptConnection | undefined;` In this first implementation, controllers can only subscribe to updates for their own namespace.