22#include " ../../utils/digital.hpp"
33#include " ../../utils/TaskWorker.hpp"
44#include " ../../utils/TaskProcessor.hpp"
5+ #include " ../../utils/SpscLatestValue.hpp"
56#include < atomic>
6- #include < memory>
77
88namespace StoermelderPackOne {
99namespace Strip {
@@ -55,12 +55,12 @@ struct StripModule : StripModuleBase, StripIdFixModule {
5555 std::atomic<bool > lastBypassState{false };
5656
5757 /* * [Stored to JSON] */
58- /* This is owned be the engine thread */
58+ /* This is owned by the engine thread */
5959 std::set<std::tuple<int64_t , int >> excludedParams;
60- /* Snapshot published for UI thread: shared_ptr to immutable set. Use std::atomic_load/store for atomic access . */
61- std::shared_ptr< const std::set<std::tuple<int64_t , int >>> excludedParamsPtr;
62- /* Snapshot published by UI Thread, only used for loading presets */
63- std::shared_ptr< const std::set<std::tuple<int64_t , int >>> excludedParamsPtrUi;
60+ /* Snapshot published for UI thread (engine writes, UI reads) . */
61+ SpscLatestValue< std::set<std::tuple<int64_t , int >>> excludedParamsPtr;
62+ /* Snapshot published by UI thread for engine to consume once (UI writes, engine reads). */
63+ SpscLatestValue< std::set<std::tuple<int64_t , int >>> excludedParamsPtrUi;
6464
6565 /* Indicates that learn mode is ready - only used for LED */
6666 std::atomic<bool > excludeLearn{false };
@@ -108,7 +108,8 @@ struct StripModule : StripModuleBase, StripIdFixModule {
108108 presetLoadReplace = false ;
109109 // Initialize snapshot to empty set so UI can read safely immediately
110110 excludedParams.clear ();
111- std::atomic_store (&excludedParamsPtr, std::make_shared<const std::set<std::tuple<int64_t , int >>>());
111+ excludedParamsPtr.store ({});
112+ excludedParamsPtrUi.store ({});
112113 Module::onReset (e);
113114 }
114115
@@ -414,7 +415,7 @@ struct StripModule : StripModuleBase, StripIdFixModule {
414415 excludedParams.erase (it);
415416 }
416417 // Publish updated snapshot for UI readers
417- std::atomic_store (& excludedParamsPtr, std::make_shared< const std::set<std::tuple< int64_t , int >>> (excludedParams) );
418+ excludedParamsPtr. store (excludedParams);
418419 }
419420 }
420421
@@ -432,7 +433,7 @@ struct StripModule : StripModuleBase, StripIdFixModule {
432433 */
433434 void groupExcludeClear () {
434435 excludedParams.clear ();
435- std::atomic_store (& excludedParamsPtr, std::make_shared< const std::set<std::tuple< int64_t , int >>>() );
436+ excludedParamsPtr. store ({} );
436437 }
437438
438439 /* *
@@ -458,7 +459,7 @@ struct StripModule : StripModuleBase, StripIdFixModule {
458459 if (mNext ->getId () == moduleId) {
459460 excludedParams.insert (std::make_tuple (moduleId, paramId));
460461 // Publish updated snapshot for UI readers
461- std::atomic_store (& excludedParamsPtr, std::make_shared< const std::set<std::tuple< int64_t , int >>> (excludedParams) );
462+ excludedParamsPtr. store (excludedParams);
462463 return ;
463464 }
464465 m = mNext ;
@@ -475,7 +476,7 @@ struct StripModule : StripModuleBase, StripIdFixModule {
475476 if (mNext ->getId () == moduleId) {
476477 excludedParams.insert (std::make_tuple (moduleId, paramId));
477478 // Publish updated snapshot for UI readers
478- std::atomic_store (& excludedParamsPtr, std::make_shared< const std::set<std::tuple< int64_t , int >>> (excludedParams) );
479+ excludedParamsPtr. store (excludedParams);
479480 return ;
480481 }
481482 m = mNext ;
@@ -497,7 +498,7 @@ struct StripModule : StripModuleBase, StripIdFixModule {
497498 */
498499 void groupExcludeRemove (int64_t moduleId, int paramId) {
499500 excludedParams.erase (std::make_tuple (moduleId, paramId));
500- std::atomic_store (& excludedParamsPtr, std::make_shared< const std::set<std::tuple< int64_t , int >>> (excludedParams) );
501+ excludedParamsPtr. store (excludedParams);
501502 }
502503
503504 /* *
@@ -513,12 +514,9 @@ struct StripModule : StripModuleBase, StripIdFixModule {
513514 * To be called from engine-thread only.
514515 */
515516 void groupExcludeLoad () {
516- auto snapUi = std::atomic_load (&excludedParamsPtrUi);
517- if (snapUi) {
518- excludedParams = *snapUi;
519- // Publish updated snapshot for UI readers
520- std::atomic_store (&excludedParamsPtr, std::make_shared<const std::set<std::tuple<int64_t , int >>>(excludedParams));
521- std::atomic_store (&excludedParamsPtrUi, std::shared_ptr<const std::set<std::tuple<int64_t , int >>>{});
517+ if (excludedParamsPtrUi.load_if_new (excludedParams)) {
518+ // Publish updated snapshot for UI reader
519+ excludedParamsPtr.store (excludedParams);
522520 }
523521 }
524522
@@ -532,16 +530,13 @@ struct StripModule : StripModuleBase, StripIdFixModule {
532530
533531 json_object_set_new (rootJ, " onMode" , json_integer ((int )onMode));
534532
535- // Use atomic snapshot published by the engine thread
536- auto snap = std::atomic_load (&excludedParamsPtr);
533+ // Use snapshot published by the engine thread
537534 json_t * excludedParamsJ = json_array ();
538- if (snap) {
539- for (auto t : *snap) {
540- json_t * excludedParamJ = json_object ();
541- json_object_set_new (excludedParamJ, " moduleId" , json_integer (std::get<0 >(t)));
542- json_object_set_new (excludedParamJ, " paramId" , json_integer (std::get<1 >(t)));
543- json_array_append_new (excludedParamsJ, excludedParamJ);
544- }
535+ for (auto t : excludedParamsPtr.peek ()) {
536+ json_t * excludedParamJ = json_object ();
537+ json_object_set_new (excludedParamJ, " moduleId" , json_integer (std::get<0 >(t)));
538+ json_object_set_new (excludedParamJ, " paramId" , json_integer (std::get<1 >(t)));
539+ json_array_append_new (excludedParamsJ, excludedParamJ);
545540 }
546541 json_object_set_new (rootJ, " excludedParams" , excludedParamsJ);
547542
@@ -578,7 +573,7 @@ struct StripModule : StripModuleBase, StripIdFixModule {
578573 snap.insert (std::make_tuple (moduleId, paramId));
579574 }
580575 // Publish snapshot for engine thread
581- std::atomic_store (& excludedParamsPtrUi, std::make_shared< const std::set<std::tuple< int64_t , int >>> (snap) );
576+ excludedParamsPtrUi. store (snap);
582577 groupExcludeLoadRequest ();
583578 }
584579
@@ -690,14 +685,13 @@ struct ExcludeButton : TL1105 {
690685 module ->groupExcludeClearRequest ();
691686 }));
692687
693- // Use atomic snapshot published by the engine thread to avoid racing with engine mutations
694- auto snap = std::atomic_load (&module ->excludedParamsPtr );
688+ const auto & snap = module ->excludedParamsPtr .peek ();
695689
696- if (! snap || snap-> size () == 0 )
690+ if (snap. empty () )
697691 return ;
698692
699693 menu->addChild (new MenuSeparator ());
700- for (auto it : * snap) {
694+ for (auto it : snap) {
701695 int64_t moduleId = std::get<0 >(it);
702696 int paramId = std::get<1 >(it);
703697
0 commit comments