@@ -277,6 +277,7 @@ enum {
277277
278278enum PostPonedEventType {
279279 POSTPONED_PARAM_SET ,
280+ POSTPONED_AUDIO_MONITOR ,
280281 POSTPONED_OUTPUT_MONITOR ,
281282 POSTPONED_MIDI_PROGRAM_CHANGE ,
282283 POSTPONED_MIDI_MAP ,
@@ -305,6 +306,12 @@ typedef struct HMI_ADDRESSING_T hmi_addressing_t;
305306#endif
306307typedef struct PORT_T port_t ;
307308
309+ typedef struct AUDIO_MONITOR_T {
310+ jack_port_t * port ;
311+ char * source_port_name ;
312+ float value ;
313+ } audio_monitor_t ;
314+
308315typedef struct CV_SOURCE_T {
309316 port_t * port ;
310317 jack_port_t * jack_port ;
@@ -586,6 +593,11 @@ typedef struct POSTPONED_PARAMETER_EVENT_T {
586593 float value ;
587594} postponed_parameter_event_t ;
588595
596+ typedef struct POSTPONED_AUDIO_MONITOR_EVENT_T {
597+ int index ;
598+ float value ;
599+ } postponed_audio_monitor_event_t ;
600+
589601typedef struct POSTPONED_MIDI_PROGRAM_CHANGE_EVENT_T {
590602 int8_t program ;
591603 int8_t channel ;
@@ -628,6 +640,7 @@ typedef struct POSTPONED_EVENT_T {
628640 enum PostPonedEventType type ;
629641 union {
630642 postponed_parameter_event_t parameter ;
643+ postponed_audio_monitor_event_t audio_monitor ;
631644 postponed_midi_program_change_event_t program_change ;
632645 postponed_midi_map_event_t midi_map ;
633646 postponed_transport_event_t transport ;
@@ -725,6 +738,9 @@ static jack_port_t *g_audio_in2_port;
725738static jack_port_t * g_audio_out1_port ;
726739static jack_port_t * g_audio_out2_port ;
727740#endif
741+ static audio_monitor_t * g_audio_monitors ;
742+ static pthread_mutex_t g_audio_monitor_mutex ;
743+ static int g_audio_monitor_count ;
728744static jack_port_t * g_midi_in_port ;
729745static jack_position_t g_jack_pos ;
730746static bool g_jack_rolling ;
@@ -1226,16 +1242,18 @@ static void RunPostPonedEvents(int ignored_effect_id)
12261242 // cached data, to make sure we only handle similar events once
12271243 bool got_midi_program = false;
12281244 bool got_transport = false;
1229- postponed_cached_effect_events cached_process_out_buf ;
1245+ postponed_cached_effect_events cached_audio_monitor , cached_process_out_buf ;
12301246 postponed_cached_symbol_events cached_param_set , cached_output_mon ;
12311247
1248+ cached_audio_monitor .last_effect_id = -1 ;
12321249 cached_process_out_buf .last_effect_id = -1 ;
12331250 cached_param_set .last_effect_id = -1 ;
1234- cached_output_mon .last_effect_id = -1 ;
12351251 cached_param_set .last_symbol [0 ] = '\0' ;
12361252 cached_param_set .last_symbol [MAX_CHAR_BUF_SIZE ] = '\0' ;
1253+ cached_output_mon .last_effect_id = -1 ;
12371254 cached_output_mon .last_symbol [0 ] = '\0' ;
12381255 cached_output_mon .last_symbol [MAX_CHAR_BUF_SIZE ] = '\0' ;
1256+ INIT_LIST_HEAD (& cached_audio_monitor .effects .siblings );
12391257 INIT_LIST_HEAD (& cached_process_out_buf .effects .siblings );
12401258 INIT_LIST_HEAD (& cached_param_set .symbols .siblings );
12411259 INIT_LIST_HEAD (& cached_output_mon .symbols .siblings );
@@ -1284,6 +1302,23 @@ static void RunPostPonedEvents(int ignored_effect_id)
12841302 strncpy (cached_param_set .last_symbol , eventptr -> event .parameter .symbol , MAX_CHAR_BUF_SIZE );
12851303 break ;
12861304
1305+ case POSTPONED_AUDIO_MONITOR :
1306+ if (ShouldIgnorePostPonedEffectEvent (eventptr -> event .audio_monitor .index , & cached_audio_monitor ))
1307+ continue ;
1308+
1309+ pthread_mutex_lock (& g_audio_monitor_mutex );
1310+ if (eventptr -> event .audio_monitor .index < g_audio_monitor_count )
1311+ g_audio_monitors [eventptr -> event .audio_monitor .index ].value = 0.f ;
1312+ pthread_mutex_unlock (& g_audio_monitor_mutex );
1313+
1314+ snprintf (buf , FEEDBACK_BUF_SIZE , "audio_monitor %i %f" , eventptr -> event .audio_monitor .index ,
1315+ eventptr -> event .audio_monitor .value );
1316+ socket_send_feedback_debug (buf );
1317+
1318+ // save for fast checkup next time
1319+ cached_audio_monitor .last_effect_id = eventptr -> event .audio_monitor .index ;
1320+ break ;
1321+
12871322 case POSTPONED_OUTPUT_MONITOR :
12881323 if (eventptr -> event .parameter .effect_id == ignored_effect_id )
12891324 continue ;
@@ -1553,6 +1588,11 @@ static void RunPostPonedEvents(int ignored_effect_id)
15531588 postponed_cached_effect_list_data * peffect ;
15541589 postponed_cached_symbol_list_data * psymbol ;
15551590
1591+ list_for_each_safe (it , it2 , & cached_audio_monitor .effects .siblings )
1592+ {
1593+ peffect = list_entry (it , postponed_cached_effect_list_data , siblings );
1594+ free (peffect );
1595+ }
15561596 list_for_each_safe (it , it2 , & cached_process_out_buf .effects .siblings )
15571597 {
15581598 peffect = list_entry (it , postponed_cached_effect_list_data , siblings );
@@ -2790,6 +2830,49 @@ static int ProcessGlobalClient(jack_nframes_t nframes, void *arg)
27902830 }
27912831#endif
27922832
2833+ // Handle audio monitors
2834+ if (pthread_mutex_trylock (& g_audio_monitor_mutex ) == 0 )
2835+ {
2836+ float * monitorbuf ;
2837+ float absvalue , oldvalue ;
2838+
2839+ for (int i = 0 ; i < g_audio_monitor_count ; ++ i )
2840+ {
2841+ monitorbuf = (float * )jack_port_get_buffer (g_audio_monitors [i ].port , nframes );
2842+ oldvalue = value = g_audio_monitors [i ].value ;
2843+
2844+ for (jack_nframes_t i = 0 ; i < nframes ; i ++ )
2845+ {
2846+ absvalue = fabsf (monitorbuf [i ]);
2847+
2848+ if (absvalue > value )
2849+ value = absvalue ;
2850+ }
2851+
2852+ if (oldvalue < value )
2853+ {
2854+ g_audio_monitors [i ].value = value ;
2855+
2856+ postponed_event_list_data * const posteventptr = rtsafe_memory_pool_allocate_atomic (g_rtsafe_mem_pool );
2857+
2858+ if (posteventptr )
2859+ {
2860+ posteventptr -> event .type = POSTPONED_AUDIO_MONITOR ;
2861+ posteventptr -> event .audio_monitor .index = i ;
2862+ posteventptr -> event .audio_monitor .value = value ;
2863+
2864+ pthread_mutex_lock (& g_rtsafe_mutex );
2865+ list_add_tail (& posteventptr -> siblings , & g_rtsafe_list );
2866+ pthread_mutex_unlock (& g_rtsafe_mutex );
2867+
2868+ needs_post = true;
2869+ }
2870+ }
2871+ }
2872+
2873+ pthread_mutex_unlock (& g_audio_monitor_mutex );
2874+ }
2875+
27932876 if (UpdateGlobalJackPosition (pos_flag , false))
27942877 needs_post = true;
27952878
@@ -3958,6 +4041,7 @@ int effects_init(void* client)
39584041
39594042 pthread_mutex_init (& g_rtsafe_mutex , & mutex_atts );
39604043 pthread_mutex_init (& g_raw_midi_port_mutex , & mutex_atts );
4044+ pthread_mutex_init (& g_audio_monitor_mutex , & mutex_atts );
39614045 pthread_mutex_init (& g_midi_learning_mutex , & mutex_atts );
39624046#ifdef __MOD_DEVICES__
39634047 pthread_mutex_init (& g_hmi_mutex , & mutex_atts );
@@ -4533,6 +4617,7 @@ int effects_finish(int close_client)
45334617 sem_destroy (& g_postevents_semaphore );
45344618 pthread_mutex_destroy (& g_rtsafe_mutex );
45354619 pthread_mutex_destroy (& g_raw_midi_port_mutex );
4620+ pthread_mutex_destroy (& g_audio_monitor_mutex );
45364621 pthread_mutex_destroy (& g_midi_learning_mutex );
45374622#ifdef __MOD_DEVICES__
45384623 pthread_mutex_destroy (& g_hmi_mutex );
@@ -8255,6 +8340,76 @@ int effects_processing_enable(int enable)
82558340 return SUCCESS ;
82568341}
82578342
8343+ int effects_monitor_audio_levels (const char * source_port_name , int enable )
8344+ {
8345+ if (g_jack_global_client == NULL )
8346+ return ERR_INVALID_OPERATION ;
8347+
8348+ if (enable )
8349+ {
8350+ for (int i = 0 ; i < g_audio_monitor_count ; ++ i )
8351+ {
8352+ if (!strcmp (g_audio_monitors [i ].source_port_name , source_port_name ))
8353+ return SUCCESS ;
8354+ }
8355+
8356+ pthread_mutex_lock (& g_audio_monitor_mutex );
8357+ g_audio_monitors = realloc (g_audio_monitors , sizeof (audio_monitor_t ) * (g_audio_monitor_count + 1 ));
8358+ pthread_mutex_unlock (& g_audio_monitor_mutex );
8359+
8360+ if (g_audio_monitors == NULL )
8361+ return ERR_MEMORY_ALLOCATION ;
8362+
8363+ audio_monitor_t * monitor = & g_audio_monitors [g_audio_monitor_count ];
8364+
8365+ char port_name [0xff ];
8366+ snprintf (port_name , sizeof (port_name ) - 1 , "monitor_%d" , g_audio_monitor_count + 1 );
8367+
8368+ jack_port_t * port = jack_port_register (g_jack_global_client ,
8369+ port_name ,
8370+ JACK_DEFAULT_AUDIO_TYPE ,
8371+ JackPortIsInput ,
8372+ 0 );
8373+ if (port == NULL )
8374+ return ERR_JACK_PORT_REGISTER ;
8375+
8376+ snprintf (port_name , sizeof (port_name ) - 1 , "%s:monitor_%d" ,
8377+ jack_get_client_name (g_jack_global_client ), g_audio_monitor_count + 1 );
8378+ jack_connect (g_jack_global_client , source_port_name , port_name );
8379+
8380+ monitor -> port = port ;
8381+ monitor -> source_port_name = strdup (source_port_name );
8382+ monitor -> value = 0.f ;
8383+
8384+ ++ g_audio_monitor_count ;
8385+ }
8386+ else
8387+ {
8388+ if (g_audio_monitor_count == 0 )
8389+ return ERR_INVALID_OPERATION ;
8390+
8391+ audio_monitor_t * monitor = & g_audio_monitors [g_audio_monitor_count - 1 ];
8392+
8393+ if (strcmp (monitor -> source_port_name , source_port_name ))
8394+ return ERR_INVALID_OPERATION ;
8395+
8396+ pthread_mutex_lock (& g_audio_monitor_mutex );
8397+ -- g_audio_monitor_count ;
8398+ pthread_mutex_unlock (& g_audio_monitor_mutex );
8399+
8400+ jack_port_unregister (g_jack_global_client , monitor -> port );
8401+ free (monitor -> source_port_name );
8402+
8403+ if (g_audio_monitor_count == 0 )
8404+ {
8405+ free (g_audio_monitors );
8406+ g_audio_monitors = NULL ;
8407+ }
8408+ }
8409+
8410+ return SUCCESS ;
8411+ }
8412+
82588413int effects_monitor_midi_program (int channel , int enable )
82598414{
82608415 if (channel < 0 || channel > 15 )
0 commit comments