Skip to content

Commit

Permalink
Implement monitor_audio_levels (#89)
Browse files Browse the repository at this point in the history
* Initial code for monitor_audio_levels command

Signed-off-by: falkTX <[email protected]>

* Finish monitor_audio_levels implementation

Signed-off-by: falkTX <[email protected]>

---------

Signed-off-by: falkTX <[email protected]>
  • Loading branch information
falkTX authored Oct 29, 2024
1 parent d157ce0 commit a0bf7d3
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 2 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ The commands supported by mod-host are:
* unmap the MIDI controller from a control port
e.g.: midi_unmap 0 "gain"

monitor_audio_levels <source_port_name> <enable>
* monitor audio levels for a specific jack port (on the feedback port)
e.g.: monitor_audio_levels "system:capture_1" 1

monitor_midi_program <midi_channel> <enable>
* listen to MIDI program change messages (on the feedback port)
e.g.: monitor_midi_program 0 1
Expand Down
159 changes: 157 additions & 2 deletions src/effects.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ enum {

enum PostPonedEventType {
POSTPONED_PARAM_SET,
POSTPONED_AUDIO_MONITOR,
POSTPONED_OUTPUT_MONITOR,
POSTPONED_MIDI_PROGRAM_CHANGE,
POSTPONED_MIDI_MAP,
Expand Down Expand Up @@ -305,6 +306,12 @@ typedef struct HMI_ADDRESSING_T hmi_addressing_t;
#endif
typedef struct PORT_T port_t;

typedef struct AUDIO_MONITOR_T {
jack_port_t *port;
char *source_port_name;
float value;
} audio_monitor_t;

typedef struct CV_SOURCE_T {
port_t *port;
jack_port_t *jack_port;
Expand Down Expand Up @@ -586,6 +593,11 @@ typedef struct POSTPONED_PARAMETER_EVENT_T {
float value;
} postponed_parameter_event_t;

typedef struct POSTPONED_AUDIO_MONITOR_EVENT_T {
int index;
float value;
} postponed_audio_monitor_event_t;

typedef struct POSTPONED_MIDI_PROGRAM_CHANGE_EVENT_T {
int8_t program;
int8_t channel;
Expand Down Expand Up @@ -628,6 +640,7 @@ typedef struct POSTPONED_EVENT_T {
enum PostPonedEventType type;
union {
postponed_parameter_event_t parameter;
postponed_audio_monitor_event_t audio_monitor;
postponed_midi_program_change_event_t program_change;
postponed_midi_map_event_t midi_map;
postponed_transport_event_t transport;
Expand Down Expand Up @@ -725,6 +738,9 @@ static jack_port_t *g_audio_in2_port;
static jack_port_t *g_audio_out1_port;
static jack_port_t *g_audio_out2_port;
#endif
static audio_monitor_t *g_audio_monitors;
static pthread_mutex_t g_audio_monitor_mutex;
static int g_audio_monitor_count;
static jack_port_t *g_midi_in_port;
static jack_position_t g_jack_pos;
static bool g_jack_rolling;
Expand Down Expand Up @@ -1226,16 +1242,18 @@ static void RunPostPonedEvents(int ignored_effect_id)
// cached data, to make sure we only handle similar events once
bool got_midi_program = false;
bool got_transport = false;
postponed_cached_effect_events cached_process_out_buf;
postponed_cached_effect_events cached_audio_monitor, cached_process_out_buf;
postponed_cached_symbol_events cached_param_set, cached_output_mon;

cached_audio_monitor.last_effect_id = -1;
cached_process_out_buf.last_effect_id = -1;
cached_param_set.last_effect_id = -1;
cached_output_mon.last_effect_id = -1;
cached_param_set.last_symbol[0] = '\0';
cached_param_set.last_symbol[MAX_CHAR_BUF_SIZE] = '\0';
cached_output_mon.last_effect_id = -1;
cached_output_mon.last_symbol[0] = '\0';
cached_output_mon.last_symbol[MAX_CHAR_BUF_SIZE] = '\0';
INIT_LIST_HEAD(&cached_audio_monitor.effects.siblings);
INIT_LIST_HEAD(&cached_process_out_buf.effects.siblings);
INIT_LIST_HEAD(&cached_param_set.symbols.siblings);
INIT_LIST_HEAD(&cached_output_mon.symbols.siblings);
Expand Down Expand Up @@ -1284,6 +1302,23 @@ static void RunPostPonedEvents(int ignored_effect_id)
strncpy(cached_param_set.last_symbol, eventptr->event.parameter.symbol, MAX_CHAR_BUF_SIZE);
break;

case POSTPONED_AUDIO_MONITOR:
if (ShouldIgnorePostPonedEffectEvent(eventptr->event.audio_monitor.index, &cached_audio_monitor))
continue;

pthread_mutex_lock(&g_audio_monitor_mutex);
if (eventptr->event.audio_monitor.index < g_audio_monitor_count)
g_audio_monitors[eventptr->event.audio_monitor.index].value = 0.f;
pthread_mutex_unlock(&g_audio_monitor_mutex);

snprintf(buf, FEEDBACK_BUF_SIZE, "audio_monitor %i %f", eventptr->event.audio_monitor.index,
eventptr->event.audio_monitor.value);
socket_send_feedback_debug(buf);

// save for fast checkup next time
cached_audio_monitor.last_effect_id = eventptr->event.audio_monitor.index;
break;

case POSTPONED_OUTPUT_MONITOR:
if (eventptr->event.parameter.effect_id == ignored_effect_id)
continue;
Expand Down Expand Up @@ -1553,6 +1588,11 @@ static void RunPostPonedEvents(int ignored_effect_id)
postponed_cached_effect_list_data *peffect;
postponed_cached_symbol_list_data *psymbol;

list_for_each_safe(it, it2, &cached_audio_monitor.effects.siblings)
{
peffect = list_entry(it, postponed_cached_effect_list_data, siblings);
free(peffect);
}
list_for_each_safe(it, it2, &cached_process_out_buf.effects.siblings)
{
peffect = list_entry(it, postponed_cached_effect_list_data, siblings);
Expand Down Expand Up @@ -2790,6 +2830,49 @@ static int ProcessGlobalClient(jack_nframes_t nframes, void *arg)
}
#endif

// Handle audio monitors
if (pthread_mutex_trylock(&g_audio_monitor_mutex) == 0)
{
float *monitorbuf;
float absvalue, oldvalue;

for (int i = 0; i < g_audio_monitor_count; ++i)
{
monitorbuf = (float*)jack_port_get_buffer(g_audio_monitors[i].port, nframes);
oldvalue = value = g_audio_monitors[i].value;

for (jack_nframes_t i = 0 ; i < nframes; i++)
{
absvalue = fabsf(monitorbuf[i]);

if (absvalue > value)
value = absvalue;
}

if (oldvalue < value)
{
g_audio_monitors[i].value = value;

postponed_event_list_data* const posteventptr = rtsafe_memory_pool_allocate_atomic(g_rtsafe_mem_pool);

if (posteventptr)
{
posteventptr->event.type = POSTPONED_AUDIO_MONITOR;
posteventptr->event.audio_monitor.index = i;
posteventptr->event.audio_monitor.value = value;

pthread_mutex_lock(&g_rtsafe_mutex);
list_add_tail(&posteventptr->siblings, &g_rtsafe_list);
pthread_mutex_unlock(&g_rtsafe_mutex);

needs_post = true;
}
}
}

pthread_mutex_unlock(&g_audio_monitor_mutex);
}

if (UpdateGlobalJackPosition(pos_flag, false))
needs_post = true;

Expand Down Expand Up @@ -3958,6 +4041,7 @@ int effects_init(void* client)

pthread_mutex_init(&g_rtsafe_mutex, &mutex_atts);
pthread_mutex_init(&g_raw_midi_port_mutex, &mutex_atts);
pthread_mutex_init(&g_audio_monitor_mutex, &mutex_atts);
pthread_mutex_init(&g_midi_learning_mutex, &mutex_atts);
#ifdef __MOD_DEVICES__
pthread_mutex_init(&g_hmi_mutex, &mutex_atts);
Expand Down Expand Up @@ -4533,6 +4617,7 @@ int effects_finish(int close_client)
sem_destroy(&g_postevents_semaphore);
pthread_mutex_destroy(&g_rtsafe_mutex);
pthread_mutex_destroy(&g_raw_midi_port_mutex);
pthread_mutex_destroy(&g_audio_monitor_mutex);
pthread_mutex_destroy(&g_midi_learning_mutex);
#ifdef __MOD_DEVICES__
pthread_mutex_destroy(&g_hmi_mutex);
Expand Down Expand Up @@ -8255,6 +8340,76 @@ int effects_processing_enable(int enable)
return SUCCESS;
}

int effects_monitor_audio_levels(const char *source_port_name, int enable)
{
if (g_jack_global_client == NULL)
return ERR_INVALID_OPERATION;

if (enable)
{
for (int i = 0; i < g_audio_monitor_count; ++i)
{
if (!strcmp(g_audio_monitors[i].source_port_name, source_port_name))
return SUCCESS;
}

pthread_mutex_lock(&g_audio_monitor_mutex);
g_audio_monitors = realloc(g_audio_monitors, sizeof(audio_monitor_t) * (g_audio_monitor_count + 1));
pthread_mutex_unlock(&g_audio_monitor_mutex);

if (g_audio_monitors == NULL)
return ERR_MEMORY_ALLOCATION;

audio_monitor_t *monitor = &g_audio_monitors[g_audio_monitor_count];

char port_name[0xff];
snprintf(port_name, sizeof(port_name) - 1, "monitor_%d", g_audio_monitor_count + 1);

jack_port_t *port = jack_port_register(g_jack_global_client,
port_name,
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput,
0);
if (port == NULL)
return ERR_JACK_PORT_REGISTER;

snprintf(port_name, sizeof(port_name) - 1, "%s:monitor_%d",
jack_get_client_name(g_jack_global_client), g_audio_monitor_count + 1);
jack_connect(g_jack_global_client, source_port_name, port_name);

monitor->port = port;
monitor->source_port_name = strdup(source_port_name);
monitor->value = 0.f;

++g_audio_monitor_count;
}
else
{
if (g_audio_monitor_count == 0)
return ERR_INVALID_OPERATION;

audio_monitor_t *monitor = &g_audio_monitors[g_audio_monitor_count - 1];

if (strcmp(monitor->source_port_name, source_port_name))
return ERR_INVALID_OPERATION;

pthread_mutex_lock(&g_audio_monitor_mutex);
--g_audio_monitor_count;
pthread_mutex_unlock(&g_audio_monitor_mutex);

jack_port_unregister(g_jack_global_client, monitor->port);
free(monitor->source_port_name);

if (g_audio_monitor_count == 0)
{
free(g_audio_monitors);
g_audio_monitors = NULL;
}
}

return SUCCESS;
}

int effects_monitor_midi_program(int channel, int enable)
{
if (channel < 0 || channel > 15)
Expand Down
1 change: 1 addition & 0 deletions src/effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ int effects_state_set_tmpdir(const char *dir);
int effects_aggregated_midi_enable(int enable);
int effects_freewheeling_enable(int enable);
int effects_processing_enable(int enable);
int effects_monitor_audio_levels(const char *source_port_name, int enable);
int effects_monitor_midi_program(int channel, int enable);
void effects_transport(int rolling, double beats_per_bar, double beats_per_minute);
int effects_transport_sync_mode(const char *mode);
Expand Down
9 changes: 9 additions & 0 deletions src/mod-host.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,13 @@ static void monitor_output_cb(proto_t *proto)
protocol_response_int(resp, proto);
}

static void monitor_audio_levels_cb(proto_t *proto)
{
int resp;
resp = effects_monitor_audio_levels(proto->list[1], atoi(proto->list[2]));
protocol_response_int(resp, proto);
}

static void monitor_midi_program_cb(proto_t *proto)
{
int resp;
Expand Down Expand Up @@ -380,6 +387,7 @@ static void cc_map_cb(proto_t *proto)
}
else
{
scalepoints_count = 0;
scalepoints = NULL;
}

Expand Down Expand Up @@ -714,6 +722,7 @@ static int mod_host_init(jack_client_t* client, int socket_port, int feedback_po
protocol_add_command(EFFECT_SET_BPB, effects_set_beats_per_bar_cb);
protocol_add_command(MONITOR_ADDR_SET, monitor_addr_set_cb);
protocol_add_command(MONITOR_OUTPUT, monitor_output_cb);
protocol_add_command(MONITOR_AUDIO_LEVELS, monitor_audio_levels_cb);
protocol_add_command(MONITOR_MIDI_PROGRAM, monitor_midi_program_cb);
protocol_add_command(MIDI_LEARN, midi_learn_cb);
protocol_add_command(MIDI_MAP, midi_map_cb);
Expand Down
1 change: 1 addition & 0 deletions src/mod-host.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
#define EFFECT_SET_BPB "set_bpb %f"
#define MONITOR_ADDR_SET "monitor %s %i %i"
#define MONITOR_OUTPUT "monitor_output %i %s"
#define MONITOR_AUDIO_LEVELS "monitor_audio_levels %i %s"
#define MONITOR_MIDI_PROGRAM "monitor_midi_program %i %i"
#define MIDI_LEARN "midi_learn %i %s %f %f"
#define MIDI_MAP "midi_map %i %s %i %i %f %f"
Expand Down

0 comments on commit a0bf7d3

Please sign in to comment.