@@ -611,6 +611,11 @@ typedef struct HMI_ADDRESSING_T {
611611} hmi_addressing_t ;
612612#endif
613613
614+ typedef struct SYNC_SCHEDULED_PARAM_T {
615+ port_t * port ;
616+ float value ;
617+ } sync_scheduled_param_t ;
618+
614619typedef struct POSTPONED_PARAMETER_EVENT_T {
615620 int effect_id ;
616621 const char * symbol ;
@@ -725,6 +730,7 @@ typedef struct RAW_MIDI_PORT_ITEM {
725730typedef struct CACHED_EFFECT_FLUSH_T {
726731 effect_t * effect ;
727732 port_t * * ports ;
733+ int num_ports ;
728734} cached_effect_flush_t ;
729735
730736
@@ -861,6 +867,11 @@ static pthread_mutex_t g_midi_learning_mutex;
861867static bool g_monitored_midi_controls [16 ];
862868static bool g_monitored_midi_programs [16 ];
863869
870+ /* Postponed port updates */
871+ static sync_scheduled_param_t g_sync_scheduled_params [MAX_SYNC_SCHEDULED_PARAMS ];
872+ static pthread_mutex_t g_sync_scheduled_params_mutex ;
873+ static unsigned int g_sync_scheduled_param_count ;
874+
864875#ifdef HAVE_HYLIA
865876static hylia_t * g_hylia_instance ;
866877static hylia_time_info_t g_hylia_timeinfo ;
@@ -4374,6 +4385,7 @@ int effects_init(void* client)
43744385 pthread_mutex_init (& g_raw_midi_port_mutex , & mutex_atts );
43754386 pthread_mutex_init (& g_audio_monitor_mutex , & mutex_atts );
43764387 pthread_mutex_init (& g_midi_learning_mutex , & mutex_atts );
4388+ pthread_mutex_init (& g_sync_scheduled_params_mutex , & mutex_atts );
43774389#ifdef MOD_HMI_CONTROL_ENABLED
43784390 pthread_mutex_init (& g_hmi_mutex , & mutex_atts );
43794391#endif
@@ -4960,6 +4972,7 @@ int effects_finish(int close_client)
49604972 pthread_mutex_destroy (& g_raw_midi_port_mutex );
49614973 pthread_mutex_destroy (& g_audio_monitor_mutex );
49624974 pthread_mutex_destroy (& g_midi_learning_mutex );
4975+ pthread_mutex_destroy (& g_sync_scheduled_params_mutex );
49634976#ifdef MOD_HMI_CONTROL_ENABLED
49644977 pthread_mutex_destroy (& g_hmi_mutex );
49654978#endif
@@ -6436,11 +6449,19 @@ int effects_remove(int effect_id)
64366449
64376450 start = 0 ;
64386451 end = MAX_PLUGIN_INSTANCES ;
6452+
6453+ // clear all sync scheduled params if removing all plugins
6454+ pthread_mutex_lock (& g_sync_scheduled_params_mutex );
6455+ g_sync_scheduled_param_count = 0 ;
6456+ pthread_mutex_unlock (& g_sync_scheduled_params_mutex );
64396457 }
64406458 else
64416459 {
64426460 start = effect_id ;
64436461 end = start + 1 ;
6462+
6463+ // trigger sync scheduled params now for no dangling pointers
6464+ effect_sync_scheduled_params (false);
64446465 }
64456466
64466467 // stop plugins processing
@@ -6867,17 +6888,36 @@ int effects_set_parameter_multi(const char *control_symbol, float value, int num
68676888 }
68686889
68696890 // the critical loop, must be as fast and small as possible
6870- port_t * port ;
6871- for (int i = 0 ; i < num_ports ; i ++ )
6891+ bool scheduled = true;
6892+ pthread_mutex_lock (& g_sync_scheduled_params_mutex );
6893+ if (g_sync_scheduled_param_count + num_ports <= MAX_SYNC_SCHEDULED_PARAMS )
68726894 {
6873- port = ports [i ];
6874- port -> prev_value = * port -> buffer = value ;
6895+ int p = g_sync_scheduled_param_count ;
6896+ for (int i = 0 ; i < num_ports ; i ++ , p ++ )
6897+ {
6898+ g_sync_scheduled_params [p ].port = ports [i ];
6899+ g_sync_scheduled_params [p ].value = value ;
6900+ }
6901+ g_sync_scheduled_param_count = p ;
68756902 }
6903+ else
6904+ {
6905+ scheduled = false;
6906+ }
6907+ pthread_mutex_unlock (& g_sync_scheduled_params_mutex );
68766908
6909+ if (! scheduled )
6910+ {
6911+ // no space to schedule events, trigger param changes now
6912+ for (int i = 0 ; i < num_ports ; i ++ )
6913+ {
6914+ port_t * port = ports [i ];
6915+ port -> prev_value = * port -> buffer = value ;
68776916#ifdef WITH_EXTERNAL_UI_SUPPORT
6878- for (int i = 0 ; i < num_ports ; i ++ )
6879- ports [i ]-> hints |= HINT_SHOULD_UPDATE ;
6917+ port -> hints |= HINT_SHOULD_UPDATE ;
68806918#endif
6919+ }
6920+ }
68816921
68826922 free (ports );
68836923
@@ -6947,6 +6987,7 @@ int effects_flush_parameters_multi(int reset, int param_count, const flushed_par
69476987 if (num_effects == 1 )
69486988 return effects_flush_parameters (* effects , reset , param_count , params );
69496989
6990+ cached_effect_flush_t * cached_effect ;
69506991 effect_t * effect ;
69516992 port_t * port ;
69526993
@@ -6963,54 +7004,70 @@ int effects_flush_parameters_multi(int reset, int param_count, const flushed_par
69637004 {
69647005 effect = & (g_effects [effect_id ]);
69657006
6966- cached_effect_flush_t * cached_effect = & cached_effects [num_cached_effects ++ ];
7007+ cached_effect = & cached_effects [num_cached_effects ++ ];
69677008 cached_effect -> effect = effect ;
69687009 cached_effect -> ports = malloc (sizeof (port_t * ) * param_count );
7010+ cached_effect -> num_ports = 0 ;
69697011
69707012 for (int j = 0 ; j < param_count ; j ++ )
6971- cached_effect -> ports [j ] = FindEffectInputPortBySymbol (effect , params [j ].symbol );
7013+ {
7014+ if ((cached_effect -> ports [cached_effect -> num_ports ] = FindEffectInputPortBySymbol (effect , params [j ].symbol )))
7015+ ++ cached_effect -> num_ports ;
7016+ }
69727017 }
69737018 }
69747019
6975- for (int i = 0 ; i < num_cached_effects ; i ++ )
7020+ // the critical loop, must be as fast and small as possible
7021+ bool scheduled = true;
7022+ const int resetb = reset != 0 ? 1 : 0 ;
7023+ pthread_mutex_lock (& g_sync_scheduled_params_mutex );
7024+ if (g_sync_scheduled_param_count + (param_count + resetb ) * num_cached_effects <= MAX_SYNC_SCHEDULED_PARAMS )
69767025 {
6977- effect = cached_effects [ i ]. effect ;
6978- if ( effect -> reset_index > = 0 && reset != 0 )
7026+ int p = g_sync_scheduled_param_count ;
7027+ for ( int i = 0 ; i < num_cached_effects ; i ++ )
69797028 {
6980- port = effect -> ports [effect -> reset_index ];
6981- port -> prev_value = * (port -> buffer ) = reset ;
7029+ cached_effect = & cached_effects [i ];
7030+ effect = cached_effect -> effect ;
7031+ for (int j = 0 ; j < cached_effect -> num_ports ; j ++ , p ++ )
7032+ {
7033+ g_sync_scheduled_params [p ].port = cached_effect -> ports [j ];
7034+ g_sync_scheduled_params [p ].value = params [j ].value ;
7035+ }
7036+ if (effect -> reset_index >= 0 && reset != 0 )
7037+ {
7038+ g_sync_scheduled_params [p ].port = effect -> ports [effect -> reset_index ];
7039+ g_sync_scheduled_params [p ].value = reset ;
7040+ ++ p ;
7041+ }
69827042 }
7043+ g_sync_scheduled_param_count = p ;
7044+ }
7045+ else
7046+ {
7047+ scheduled = false;
69837048 }
7049+ pthread_mutex_unlock (& g_sync_scheduled_params_mutex );
69847050
6985- // the critical loop, must be as fast and small as possible
6986- for (int j = 0 ; j < param_count ; j ++ )
7051+ if (! scheduled )
69877052 {
7053+ // no space to schedule events, trigger param changes now
69887054 for (int i = 0 ; i < num_cached_effects ; i ++ )
69897055 {
6990- if ((port = cached_effects [i ].ports [j ]))
7056+ cached_effect = & cached_effects [i ];
7057+ effect = cached_effect -> effect ;
7058+ for (int j = 0 ; j < cached_effect -> num_ports ; j ++ )
7059+ {
7060+ port = cached_effect -> ports [j ];
69917061 port -> prev_value = * (port -> buffer ) = params [j ].value ;
6992- }
6993- }
6994-
69957062#ifdef WITH_EXTERNAL_UI_SUPPORT
6996- for (int i = 0 ; i < num_cached_effects ; i ++ )
6997- {
6998- for (int j = 0 ; j < param_count ; j ++ )
6999- {
7000- if ((port = cached_effects [i ].ports [j ]))
70017063 port -> hints |= HINT_SHOULD_UPDATE ;
7002- }
7003- }
70047064#endif
7005-
7006- // reset a 2nd time in case plugin was processing while we changed parameters
7007- for (int i = 0 ; i < num_cached_effects ; i ++ )
7008- {
7009- effect = cached_effects [i ].effect ;
7010- if (effect -> reset_index >= 0 && reset != 0 )
7011- {
7012- port = effect -> ports [effect -> reset_index ];
7013- port -> prev_value = * (port -> buffer ) = reset ;
7065+ }
7066+ if (effect -> reset_index >= 0 && reset != 0 )
7067+ {
7068+ port = effect -> ports [effect -> reset_index ];
7069+ port -> prev_value = * (port -> buffer ) = reset ;
7070+ }
70147071 }
70157072 }
70167073
@@ -9321,6 +9378,33 @@ int effects_transport_sync_mode(const char* mode)
93219378 return SUCCESS ;
93229379}
93239380
9381+ void effect_sync_scheduled_params (int realtime )
9382+ {
9383+ port_t * port ;
9384+
9385+ if (realtime != 0 )
9386+ {
9387+ if (pthread_mutex_trylock (& g_sync_scheduled_params_mutex ) != 0 )
9388+ return ;
9389+ }
9390+ else
9391+ {
9392+ pthread_mutex_lock (& g_sync_scheduled_params_mutex );
9393+ }
9394+
9395+ for (unsigned int i = 0 ; i < g_sync_scheduled_param_count ; i ++ )
9396+ {
9397+ port = g_sync_scheduled_params [i ].port ;
9398+ port -> prev_value = * port -> buffer = g_sync_scheduled_params [i ].value ;
9399+ #ifdef WITH_EXTERNAL_UI_SUPPORT
9400+ port -> hints |= HINT_SHOULD_UPDATE ;
9401+ #endif
9402+ }
9403+
9404+ g_sync_scheduled_param_count = 0 ;
9405+ pthread_mutex_unlock (& g_sync_scheduled_params_mutex );
9406+ }
9407+
93249408void effects_output_data_ready (void )
93259409{
93269410 if (g_verbose_debug ) {
0 commit comments