@@ -277,6 +277,7 @@ enum {
277
277
278
278
enum PostPonedEventType {
279
279
POSTPONED_PARAM_SET ,
280
+ POSTPONED_AUDIO_MONITOR ,
280
281
POSTPONED_OUTPUT_MONITOR ,
281
282
POSTPONED_MIDI_PROGRAM_CHANGE ,
282
283
POSTPONED_MIDI_MAP ,
@@ -305,6 +306,12 @@ typedef struct HMI_ADDRESSING_T hmi_addressing_t;
305
306
#endif
306
307
typedef struct PORT_T port_t ;
307
308
309
+ typedef struct AUDIO_MONITOR_T {
310
+ jack_port_t * port ;
311
+ char * source_port_name ;
312
+ float value ;
313
+ } audio_monitor_t ;
314
+
308
315
typedef struct CV_SOURCE_T {
309
316
port_t * port ;
310
317
jack_port_t * jack_port ;
@@ -586,6 +593,11 @@ typedef struct POSTPONED_PARAMETER_EVENT_T {
586
593
float value ;
587
594
} postponed_parameter_event_t ;
588
595
596
+ typedef struct POSTPONED_AUDIO_MONITOR_EVENT_T {
597
+ int index ;
598
+ float value ;
599
+ } postponed_audio_monitor_event_t ;
600
+
589
601
typedef struct POSTPONED_MIDI_PROGRAM_CHANGE_EVENT_T {
590
602
int8_t program ;
591
603
int8_t channel ;
@@ -628,6 +640,7 @@ typedef struct POSTPONED_EVENT_T {
628
640
enum PostPonedEventType type ;
629
641
union {
630
642
postponed_parameter_event_t parameter ;
643
+ postponed_audio_monitor_event_t audio_monitor ;
631
644
postponed_midi_program_change_event_t program_change ;
632
645
postponed_midi_map_event_t midi_map ;
633
646
postponed_transport_event_t transport ;
@@ -725,6 +738,9 @@ static jack_port_t *g_audio_in2_port;
725
738
static jack_port_t * g_audio_out1_port ;
726
739
static jack_port_t * g_audio_out2_port ;
727
740
#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 ;
728
744
static jack_port_t * g_midi_in_port ;
729
745
static jack_position_t g_jack_pos ;
730
746
static bool g_jack_rolling ;
@@ -1226,16 +1242,18 @@ static void RunPostPonedEvents(int ignored_effect_id)
1226
1242
// cached data, to make sure we only handle similar events once
1227
1243
bool got_midi_program = false;
1228
1244
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 ;
1230
1246
postponed_cached_symbol_events cached_param_set , cached_output_mon ;
1231
1247
1248
+ cached_audio_monitor .last_effect_id = -1 ;
1232
1249
cached_process_out_buf .last_effect_id = -1 ;
1233
1250
cached_param_set .last_effect_id = -1 ;
1234
- cached_output_mon .last_effect_id = -1 ;
1235
1251
cached_param_set .last_symbol [0 ] = '\0' ;
1236
1252
cached_param_set .last_symbol [MAX_CHAR_BUF_SIZE ] = '\0' ;
1253
+ cached_output_mon .last_effect_id = -1 ;
1237
1254
cached_output_mon .last_symbol [0 ] = '\0' ;
1238
1255
cached_output_mon .last_symbol [MAX_CHAR_BUF_SIZE ] = '\0' ;
1256
+ INIT_LIST_HEAD (& cached_audio_monitor .effects .siblings );
1239
1257
INIT_LIST_HEAD (& cached_process_out_buf .effects .siblings );
1240
1258
INIT_LIST_HEAD (& cached_param_set .symbols .siblings );
1241
1259
INIT_LIST_HEAD (& cached_output_mon .symbols .siblings );
@@ -1284,6 +1302,23 @@ static void RunPostPonedEvents(int ignored_effect_id)
1284
1302
strncpy (cached_param_set .last_symbol , eventptr -> event .parameter .symbol , MAX_CHAR_BUF_SIZE );
1285
1303
break ;
1286
1304
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
+
1287
1322
case POSTPONED_OUTPUT_MONITOR :
1288
1323
if (eventptr -> event .parameter .effect_id == ignored_effect_id )
1289
1324
continue ;
@@ -1553,6 +1588,11 @@ static void RunPostPonedEvents(int ignored_effect_id)
1553
1588
postponed_cached_effect_list_data * peffect ;
1554
1589
postponed_cached_symbol_list_data * psymbol ;
1555
1590
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
+ }
1556
1596
list_for_each_safe (it , it2 , & cached_process_out_buf .effects .siblings )
1557
1597
{
1558
1598
peffect = list_entry (it , postponed_cached_effect_list_data , siblings );
@@ -2790,6 +2830,49 @@ static int ProcessGlobalClient(jack_nframes_t nframes, void *arg)
2790
2830
}
2791
2831
#endif
2792
2832
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
+
2793
2876
if (UpdateGlobalJackPosition (pos_flag , false))
2794
2877
needs_post = true;
2795
2878
@@ -3958,6 +4041,7 @@ int effects_init(void* client)
3958
4041
3959
4042
pthread_mutex_init (& g_rtsafe_mutex , & mutex_atts );
3960
4043
pthread_mutex_init (& g_raw_midi_port_mutex , & mutex_atts );
4044
+ pthread_mutex_init (& g_audio_monitor_mutex , & mutex_atts );
3961
4045
pthread_mutex_init (& g_midi_learning_mutex , & mutex_atts );
3962
4046
#ifdef __MOD_DEVICES__
3963
4047
pthread_mutex_init (& g_hmi_mutex , & mutex_atts );
@@ -4533,6 +4617,7 @@ int effects_finish(int close_client)
4533
4617
sem_destroy (& g_postevents_semaphore );
4534
4618
pthread_mutex_destroy (& g_rtsafe_mutex );
4535
4619
pthread_mutex_destroy (& g_raw_midi_port_mutex );
4620
+ pthread_mutex_destroy (& g_audio_monitor_mutex );
4536
4621
pthread_mutex_destroy (& g_midi_learning_mutex );
4537
4622
#ifdef __MOD_DEVICES__
4538
4623
pthread_mutex_destroy (& g_hmi_mutex );
@@ -8255,6 +8340,76 @@ int effects_processing_enable(int enable)
8255
8340
return SUCCESS ;
8256
8341
}
8257
8342
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
+
8258
8413
int effects_monitor_midi_program (int channel , int enable )
8259
8414
{
8260
8415
if (channel < 0 || channel > 15 )
0 commit comments