diff --git a/filter/bs412.c b/filter/bs412.c index a0ca48c..de3fdc9 100644 --- a/filter/bs412.c +++ b/filter/bs412.c @@ -31,7 +31,7 @@ void init_bs412(BS412Compressor* comp, uint32_t mpx_deviation, float target_powe #endif } -float bs412_compress(BS412Compressor* comp, float audio, float sample_mpx) { +float bs412_compress(BS412Compressor* comp, float audio, float sample_mpx, float* mpx_power) { float combined = audio + sample_mpx; float output_sample = (audio * comp->gain) + sample_mpx; @@ -66,6 +66,8 @@ float bs412_compress(BS412Compressor* comp, float audio, float sample_mpx) { comp->sample_counter++; + if(mpx_power != NULL) *mpx_power = deviation_to_dbr(avg_power); + if(comp->can_compress) return output_sample; return combined; } diff --git a/filter/bs412.h b/filter/bs412.h index ad403d1..d1e550e 100644 --- a/filter/bs412.h +++ b/filter/bs412.h @@ -32,4 +32,4 @@ typedef struct float deviation_to_dbr(float deviation); void init_bs412(BS412Compressor *comp, uint32_t mpx_deviation, float target_power, float attack, float release, float max_gain, uint32_t sample_rate); -float bs412_compress(BS412Compressor *comp, float audio, float sample_mpx); \ No newline at end of file +float bs412_compress(BS412Compressor *comp, float audio, float sample_mpx, float* mpx_power); \ No newline at end of file diff --git a/io/ipc.c b/io/ipc.c index d2cd639..ab3f413 100644 --- a/io/ipc.c +++ b/io/ipc.c @@ -43,14 +43,16 @@ static void *listener_thread(void *arg) { printf("[ipc] new client fd=%d\n", client_fd); - int *fd_ptr = malloc(sizeof(int)); - if (!fd_ptr) { close(client_fd); continue; } - *fd_ptr = client_fd; + ipc_client_arg_t *carg = malloc(sizeof(ipc_client_arg_t)); + if (!carg) { close(client_fd); continue; } + carg->client_fd = client_fd; + carg->user_data = ctx->user_data; pthread_t tid; - if (pthread_create(&tid, NULL, ctx->handler, fd_ptr) != 0) { + if (pthread_create(&tid, NULL, + (void *(*)(void *))ctx->handler, carg) != 0) { perror("ipc: pthread_create"); - free(fd_ptr); + free(carg); close(client_fd); continue; } @@ -61,10 +63,13 @@ static void *listener_thread(void *arg) { return NULL; } -int create_ipc(ipc_ctx_t *ctx, ipc_client_fn handler, const char* socket_path) { - ctx->handler = handler; - ctx->running = 1; - ctx->server_fd = make_server_socket(socket_path); +int create_ipc(ipc_ctx_t *ctx, ipc_client_fn handler, + const char *socket_path, void *user_data) +{ + ctx->handler = handler; + ctx->user_data = user_data; + ctx->running = 1; + ctx->server_fd = make_server_socket(socket_path); ctx->socket_path = strdup(socket_path); if (ctx->server_fd < 0) return -1; @@ -76,7 +81,6 @@ int create_ipc(ipc_ctx_t *ctx, ipc_client_fn handler, const char* socket_path) { return -1; } - /* store tid so destroy_ipc can join it */ ctx->_tid = tid; printf("[ipc] listening on %s\n", socket_path); diff --git a/io/ipc.h b/io/ipc.h index 95b049d..5ba00bb 100644 --- a/io/ipc.h +++ b/io/ipc.h @@ -6,17 +6,24 @@ #include #include -#define IPC_SOCKET_PATH "/tmp/ipc_demo.sock" #define IPC_BACKLOG 1 -typedef void *(*ipc_client_fn)(void *client_fd_ptr); +typedef struct { + int client_fd; + void *user_data; +} ipc_client_arg_t; + +typedef void *(*ipc_client_fn)(ipc_client_arg_t *arg); typedef struct { int server_fd; volatile int running; ipc_client_fn handler; + void *user_data; pthread_t _tid; /* internal — do not touch */ - char* socket_path; + char *socket_path; } ipc_ctx_t; -int create_ipc(ipc_ctx_t *ctx, ipc_client_fn handler, const char* socket_path); + +int create_ipc(ipc_ctx_t *ctx, ipc_client_fn handler, + const char *socket_path, void *user_data); void destroy_ipc(ipc_ctx_t *ctx); \ No newline at end of file diff --git a/src/fm95.c b/src/fm95.c index 43f9d84..4661245 100644 --- a/src/fm95.c +++ b/src/fm95.c @@ -93,6 +93,10 @@ typedef struct { FM95_DeviceNames* devices; } FM95_SetupContext; +typedef struct { + float mpx_power; +} FM95_RunResult; + bool compare_dvs(const FM95_DeviceNames *a, const FM95_DeviceNames *b) { return strcmp(a->input, b->input) == 0 && strcmp(a->output, b->output) == 0 && strcmp(a->mpx, b->mpx) == 0 && strcmp(a->rds, b->rds) == 0; } @@ -143,8 +147,9 @@ void cleanup_audio_runtime(FM95_Runtime *rt, const FM95_Options options) { free_PulseDevice(&rt->output_device); } -int run_fm95(const FM95_Config config, FM95_Runtime* runtime) { +int run_fm95(const FM95_Config config, FM95_Runtime* runtime, FM95_RunResult* result) { float output[BUFFER_SIZE]; + FM95_RunResult temp_result = {}; int pulse_error; @@ -172,9 +177,9 @@ int run_fm95(const FM95_Config config, FM95_Runtime* runtime) { bool mpx_on = config.options.mpx_on; bool rds_on = config.options.rds_on; - float softclip_norm = config.volumes.makeup / tanhf(config.volumes.drive); - while (to_run) { + float softclip_norm = config.volumes.makeup / tanhf(config.volumes.drive); + if((pulse_error = read_PulseInputDevice(&runtime->input_device, audio_stereo_input, sizeof(audio_stereo_input)))) { // get output from the function and assign it into pulse_error, this comment to avoid confusion fprintf(stderr, "Error reading from input device: %s\n", pa_strerror(pulse_error)); to_run = 0; @@ -237,11 +242,12 @@ int run_fm95(const FM95_Config config, FM95_Runtime* runtime) { } } - mpx = bs412_compress(&runtime->bs412, audio, mpx+mpx_in[i]); + mpx = bs412_compress(&runtime->bs412, audio, mpx+mpx_in[i], &temp_result.mpx_power); output[i] = tanhf(mpx)*config.master_volume; // Ensure peak deviation of 75 khz (or the set deviation), assuming we're calibrated correctly advance_oscillator(&runtime->osc); } + memcpy(result, &temp_result, sizeof(FM95_RunResult)); if((pulse_error = write_PulseOutputDevice(&runtime->output_device, output, sizeof(output)))) { fprintf(stderr, "Error writing to output device: %s\n", pa_strerror(pulse_error)); @@ -458,23 +464,56 @@ void init_runtime(FM95_Runtime* runtime, const FM95_Config config) { } #define BUF_SIZE 256 -#define PREFIX "ECHO: " -#define PREFIX_LEN 6 -static void *handle_client(void *arg) { - int fd = *(int *)arg; +typedef struct { + FM95_Runtime* runtime; + FM95_Config* config; + FM95_RunResult* run_result; +} FM95_Data; + +static void *handle_client(ipc_client_arg_t *arg) { + int fd = arg->client_fd; + FM95_Data* data = arg->user_data; free(arg); char buf[BUF_SIZE]; + char reply = 0; ssize_t n; while ((n = recv(fd, buf, sizeof(buf) - 1, 0)) > 0) { + reply = 0; buf[n] = '\0'; - printf("[client fd=%d] %s\n", fd, buf); + switch (buf[0]) { + case 1: + // Reload + to_run = 0; + to_reload = 1; + break; + case 2: + // Quit + to_run = 0; + to_reload = 0; + break; + case 100: + // Toggle stereo + data->config->stereo ^= 1; + break; + case 101: + // Set makeup + float val; + memcpy(&val, buf + 1, sizeof(float)); + data->config->volumes.makeup = val; + break; + case 0xff: + // Fetch data + send(fd, data->run_result, sizeof(FM95_RunResult), 0); + break; + default: + reply = 1; // Unknown command + break; + } - char reply[BUF_SIZE + PREFIX_LEN]; - snprintf(reply, sizeof(reply), PREFIX "%s", buf); - send(fd, reply, strlen(reply), 0); + send(fd, &reply, 1, 0); } printf("[client fd=%d] disconnected\n", fd); @@ -485,14 +524,6 @@ static void *handle_client(void *arg) { int main(int argc, char **argv) { printf("fm95 (an FM Processor by radio95) version 2.5\n"); - ipc_ctx_t ctx; - ipc_ctx_t *pctx = &ctx; - if(create_ipc(pctx, handle_client, "/etc/fm95/ctl.socket") < 0) { - printf("Could not create IPC.\n"); - pctx = NULL; - } - - FM95_Config config = { .volumes = { .pilot = 0.09f, @@ -580,9 +611,22 @@ int main(int argc, char **argv) { init_runtime(&runtime, config); + FM95_RunResult runres = {}; + FM95_Data fmdata = { + .config = &config, + .runtime = &runtime, + .run_result = &runres + }; + ipc_ctx_t ctx; + ipc_ctx_t *pctx = &ctx; + if(create_ipc(pctx, handle_client, "/etc/fm95/ctl.socket", &fmdata) < 0) { + printf("Could not create IPC.\n"); + pctx = NULL; + } + int ret; while(true) { - ret = run_fm95(config, &runtime); + ret = run_fm95(config, &runtime, &runres); if(to_reload) { to_reload = 0; printf("Reloading...\n");