Skip to content

Commit 754070f

Browse files
committed
Schedule multi param changes so they happen in sync
Signed-off-by: falkTX <[email protected]>
1 parent 665ae0a commit 754070f

File tree

3 files changed

+130
-35
lines changed

3 files changed

+130
-35
lines changed

src/effects.c

Lines changed: 119 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
614619
typedef struct POSTPONED_PARAMETER_EVENT_T {
615620
int effect_id;
616621
const char* symbol;
@@ -725,6 +730,7 @@ typedef struct RAW_MIDI_PORT_ITEM {
725730
typedef 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;
861867
static bool g_monitored_midi_controls[16];
862868
static 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
865876
static hylia_t* g_hylia_instance;
866877
static 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+
93249408
void effects_output_data_ready(void)
93259409
{
93269410
if (g_verbose_debug) {

src/effects.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ typedef enum {
9797
#define MAX_POSTPONED_EVENTS 8192
9898
#define MAX_HMI_ADDRESSINGS 128
9999

100+
#define MAX_SYNC_SCHEDULED_PARAMS 512
101+
100102
// used for local stack variables
101103
#define MAX_CHAR_BUF_SIZE 255
102104

@@ -203,6 +205,7 @@ int effects_monitor_midi_control(int channel, int enable);
203205
int effects_monitor_midi_program(int channel, int enable);
204206
void effects_transport(int rolling, double beats_per_bar, double beats_per_minute);
205207
int effects_transport_sync_mode(const char *mode);
208+
void effect_sync_scheduled_params(int realtime);
206209
void effects_output_data_ready(void);
207210
int effects_show_external_ui(int effect_id);
208211
void effects_idle_external_uis(void);

src/monitor/monitor-client.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
#include "../utils.h"
3636
#include "../dsp/compressor_core.h"
3737

38+
#ifndef STANDALONE_MONITOR_CLIENT
39+
#include "../effects.h"
40+
#endif
41+
3842
/*
3943
************************************************************************************************************************
4044
* LOCAL DEFINES
@@ -283,6 +287,10 @@ static int ProcessMonitor(jack_nframes_t nframes, void *arg)
283287
{
284288
monitor_client_t *const mon = arg;
285289

290+
#ifndef STANDALONE_MONITOR_CLIENT
291+
effect_sync_scheduled_params(true);
292+
#endif
293+
286294
if (mon->muted)
287295
{
288296
for (uint32_t i=0; i < mon->numports; ++i)

0 commit comments

Comments
 (0)