@@ -305,6 +305,7 @@ enum PostPonedEventType {
305305 POSTPONED_PARAM_SET ,
306306 POSTPONED_PARAM_STATE ,
307307 POSTPONED_AUDIO_MONITOR ,
308+ POSTPONED_CPU_MONITOR ,
308309 POSTPONED_OUTPUT_MONITOR ,
309310 POSTPONED_MIDI_CONTROL_CHANGE ,
310311 POSTPONED_MIDI_PROGRAM_CHANGE ,
@@ -467,6 +468,10 @@ typedef struct EFFECT_T {
467468 bool jack_activated ;
468469 bool lv2_activated ;
469470
471+ bool monitor_cpu ;
472+ bool monitor_cpu_reset ;
473+ float cpu_load ;
474+
470475 // previous transport state
471476 bool transport_rolling ;
472477 uint32_t transport_frame ;
@@ -644,6 +649,11 @@ typedef struct POSTPONED_AUDIO_MONITOR_EVENT_T {
644649 float value ;
645650} postponed_audio_monitor_event_t ;
646651
652+ typedef struct POSTPONED_CPU_MONITOR_EVENT_T {
653+ int effect_id ;
654+ float cpu_load ;
655+ } postponed_cpu_monitor_event_t ;
656+
647657typedef struct POSTPONED_MIDI_CONTROL_CHANGE_EVENT_T {
648658 int8_t channel ;
649659 int8_t control ;
@@ -694,6 +704,7 @@ typedef struct POSTPONED_EVENT_T {
694704 postponed_parameter_event_t parameter ;
695705 postponed_parameter_state_t state ;
696706 postponed_audio_monitor_event_t audio_monitor ;
707+ postponed_cpu_monitor_event_t cpu_monitor ;
697708 postponed_midi_control_change_event_t control_change ;
698709 postponed_midi_program_change_event_t program_change ;
699710 postponed_midi_map_event_t midi_map ;
@@ -790,7 +801,7 @@ static jack_client_t *g_jack_global_client;
790801static jack_nframes_t g_sample_rate , g_max_allowed_midi_delta ;
791802static float g_sample_rate_f ;
792803static const char * * g_capture_ports , * * g_playback_ports ;
793- static int32_t g_midi_buffer_size , g_block_length ;
804+ static int32_t g_midi_buffer_size , g_block_length , g_block_time_us ;
794805static int32_t g_thread_policy , g_thread_priority ;
795806#ifdef MOD_IO_PROCESSING_ENABLED
796807static jack_port_t * g_audio_in1_port ;
@@ -1104,6 +1115,7 @@ static void AllocatePortBuffers(effect_t* effect, int in_size, int out_size)
11041115static int BufferSize (jack_nframes_t nframes , void * data )
11051116{
11061117 g_block_length = nframes ;
1118+ g_block_time_us = nframes * 1e6 / g_sample_rate ;
11071119 g_midi_buffer_size = jack_port_type_get_buffer_size (g_jack_global_client , JACK_DEFAULT_MIDI_TYPE );
11081120
11091121 if (data )
@@ -1354,10 +1366,11 @@ static void RunPostPonedEvents(int ignored_effect_id)
13541366 // cached data, to make sure we only handle similar events once
13551367 bool got_midi_program = false;
13561368 bool got_transport = false;
1357- postponed_cached_effect_events cached_audio_monitor , cached_process_out_buf ;
1369+ postponed_cached_effect_events cached_audio_monitor , cached_cpu_monitor , cached_process_out_buf ;
13581370 postponed_cached_symbol_events cached_param_set , cached_param_state , cached_output_mon ;
13591371
13601372 cached_audio_monitor .last_effect_id = -1 ;
1373+ cached_cpu_monitor .last_effect_id = -1 ;
13611374 cached_process_out_buf .last_effect_id = -1 ;
13621375 cached_param_set .last_effect_id = -1 ;
13631376 cached_param_set .last_symbol [0 ] = '\0' ;
@@ -1369,6 +1382,7 @@ static void RunPostPonedEvents(int ignored_effect_id)
13691382 cached_output_mon .last_symbol [0 ] = '\0' ;
13701383 cached_output_mon .last_symbol [MAX_CHAR_BUF_SIZE ] = '\0' ;
13711384 INIT_LIST_HEAD (& cached_audio_monitor .effects .siblings );
1385+ INIT_LIST_HEAD (& cached_cpu_monitor .effects .siblings );
13721386 INIT_LIST_HEAD (& cached_process_out_buf .effects .siblings );
13731387 INIT_LIST_HEAD (& cached_param_set .symbols .siblings );
13741388 INIT_LIST_HEAD (& cached_param_state .symbols .siblings );
@@ -1455,6 +1469,18 @@ static void RunPostPonedEvents(int ignored_effect_id)
14551469 cached_audio_monitor .last_effect_id = eventptr -> event .audio_monitor .index ;
14561470 break ;
14571471
1472+ case POSTPONED_CPU_MONITOR :
1473+ if (ShouldIgnorePostPonedEffectEvent (eventptr -> event .audio_monitor .index , & cached_audio_monitor ))
1474+ continue ;
1475+
1476+ snprintf (buf , FEEDBACK_BUF_SIZE , "cpu_monitor %i %f" , eventptr -> event .cpu_monitor .effect_id ,
1477+ eventptr -> event .cpu_monitor .cpu_load );
1478+ socket_send_feedback_debug (buf );
1479+
1480+ // save for fast checkup next time
1481+ cached_cpu_monitor .last_effect_id = eventptr -> event .cpu_monitor .effect_id ;
1482+ break ;
1483+
14581484 case POSTPONED_OUTPUT_MONITOR :
14591485 if (eventptr -> event .parameter .effect_id == ignored_effect_id )
14601486 continue ;
@@ -1751,6 +1777,11 @@ static void RunPostPonedEvents(int ignored_effect_id)
17511777 peffect = list_entry (it , postponed_cached_effect_list_data , siblings );
17521778 free (peffect );
17531779 }
1780+ list_for_each_safe (it , it2 , & cached_cpu_monitor .effects .siblings )
1781+ {
1782+ peffect = list_entry (it , postponed_cached_effect_list_data , siblings );
1783+ free (peffect );
1784+ }
17541785 list_for_each_safe (it , it2 , & cached_process_out_buf .effects .siblings )
17551786 {
17561787 peffect = list_entry (it , postponed_cached_effect_list_data , siblings );
@@ -2073,10 +2104,15 @@ static int ProcessPlugin(jack_nframes_t nframes, void *arg)
20732104 }
20742105
20752106 /* common variables */
2107+ const bool monitor_cpu = effect -> monitor_cpu ;
20762108 bool needs_post = false;
20772109 const float * buffer_in ;
20782110 float * buffer_out ;
20792111 float value ;
2112+ uint64_t time_start ;
2113+
2114+ if (monitor_cpu )
2115+ time_start = time_ns_get ();
20802116
20812117 /* transport */
20822118 uint8_t stack_buf [MAX_CHAR_BUF_SIZE + 1 ];
@@ -2618,6 +2654,37 @@ static int ProcessPlugin(jack_nframes_t nframes, void *arg)
26182654 if (effect -> hints & HINT_STATE_UNSAFE )
26192655 pthread_mutex_unlock (& effect -> state_restore_mutex );
26202656
2657+ if (monitor_cpu )
2658+ {
2659+ if (effect -> monitor_cpu_reset )
2660+ {
2661+ effect -> cpu_load = 0.f ;
2662+ effect -> monitor_cpu_reset = false;
2663+ }
2664+
2665+ float cpu_load = ((int32_t )(time_ns_get () - time_start ) / g_block_time_us ) * 0.001f ;
2666+
2667+ if (cpu_load > effect -> cpu_load )
2668+ {
2669+ effect -> cpu_load = cpu_load ;
2670+
2671+ postponed_event_list_data * const posteventptr = rtsafe_memory_pool_allocate_atomic (g_rtsafe_mem_pool );
2672+
2673+ if (posteventptr != NULL )
2674+ {
2675+ posteventptr -> event .type = POSTPONED_CPU_MONITOR ;
2676+ posteventptr -> event .cpu_monitor .effect_id = effect -> instance ;
2677+ posteventptr -> event .cpu_monitor .cpu_load = cpu_load ;
2678+
2679+ pthread_mutex_lock (& g_rtsafe_mutex );
2680+ list_add_tail (& posteventptr -> siblings , & g_rtsafe_list );
2681+ pthread_mutex_unlock (& g_rtsafe_mutex );
2682+
2683+ needs_post = true;
2684+ }
2685+ }
2686+ }
2687+
26212688 if (needs_post )
26222689 sem_post (& g_postevents_semaphore );
26232690
@@ -4460,6 +4527,8 @@ int effects_init(void* client)
44604527 return ERR_JACK_CLIENT_CREATION ;
44614528 }
44624529
4530+ time_ns_init ();
4531+
44634532 /* Register jack ports */
44644533 g_midi_in_port = jack_port_register (g_jack_global_client , "midi_in" , JACK_DEFAULT_MIDI_TYPE , JackPortIsInput , 0 );
44654534
@@ -4531,6 +4600,7 @@ int effects_init(void* client)
45314600 /* Get buffers size */
45324601 g_block_length = jack_get_buffer_size (g_jack_global_client );
45334602 g_sample_rate = jack_get_sample_rate (g_jack_global_client );
4603+ g_block_time_us = g_block_length * 1e6 / g_sample_rate ;
45344604 g_sample_rate_f = g_sample_rate ;
45354605 g_midi_buffer_size = jack_port_type_get_buffer_size (g_jack_global_client , JACK_DEFAULT_MIDI_TYPE );
45364606 g_max_allowed_midi_delta = (jack_nframes_t )(g_sample_rate * 0.2 ); // max 200ms of allowed delta
@@ -9512,6 +9582,30 @@ int effects_monitor_audio_levels(const char *source_port_name, int enable)
95129582 return SUCCESS ;
95139583}
95149584
9585+ int effects_monitor_cpu_load (int enable , int num_effects , int * effects )
9586+ {
9587+ if (num_effects <= 0 )
9588+ return ERR_INVALID_OPERATION ;
9589+
9590+ effect_t * effect ;
9591+
9592+ for (int i = 0 , effect_id ; i < num_effects ; i ++ )
9593+ {
9594+ effect_id = effects [i ];
9595+ if (InstanceExist (effect_id ))
9596+ {
9597+ effect = & g_effects [effect_id ];
9598+
9599+ if (enable != 0 )
9600+ effect -> monitor_cpu_reset = true;
9601+
9602+ effect -> monitor_cpu = enable != 0 ;
9603+ }
9604+ }
9605+
9606+ return SUCCESS ;
9607+ }
9608+
95159609int effects_monitor_midi_control (int channel , int enable )
95169610{
95179611 if (channel < 0 || channel > 15 )
@@ -9676,6 +9770,20 @@ void effects_output_data_ready(void)
96769770
96779771 if (! g_postevents_ready )
96789772 {
9773+ // recalculate max cpu usage again
9774+ for (int i = 0 ; i < MAX_PLUGIN_INSTANCES ; ++ i )
9775+ {
9776+ effect_t * effect = & g_effects [i ];
9777+
9778+ if (effect -> lilv_instance == NULL )
9779+ continue ;
9780+ if (effect -> lilv_plugin == NULL )
9781+ continue ;
9782+
9783+ if (effect -> monitor_cpu )
9784+ effect -> monitor_cpu_reset = true;
9785+ }
9786+
96799787 g_postevents_ready = true;
96809788 sem_post (& g_postevents_semaphore );
96819789 }
0 commit comments