0
1
mirror of https://github.com/radio95-rnt/fm95.git synced 2026-02-26 19:23:51 +01:00

restructure chimer95

This commit is contained in:
2025-06-28 16:03:04 +02:00
parent 6cea5eee19
commit ffbd230a37
2 changed files with 119 additions and 100 deletions

View File

@@ -3,6 +3,7 @@
#include <time.h>
#include <signal.h>
#include <string.h>
#include <stdbool.h>
#define buffer_maxlength 1024
#define buffer_tlength_fragsize 1024
@@ -81,7 +82,7 @@ void generate_signal(float *output, Oscillator *osc, float volume, int *elapsed_
}
}
int check_time_for_sequence(int test_mode, int offset) {
int check_time_for_sequence(int test_mode, int16_t offset) {
static time_t last_check = 0;
static int last_minute = -1;
@@ -93,9 +94,7 @@ int check_time_for_sequence(int test_mode, int offset) {
int minute = utc_time->tm_min;
int second = utc_time->tm_sec;
if (difftime(now, last_sequence_time) < 1.0) {
return SEQ_NONE;
}
if (difftime(now, last_sequence_time) < 1.0) return SEQ_NONE;
last_sequence_time = now;
if (minute == 29 && second == (56 + offset)) return SEQ_29_56;
@@ -108,17 +107,102 @@ int check_time_for_sequence(int test_mode, int offset) {
return SEQ_NONE;
}
int main(int argc, char **argv) {
printf("chimer95 (GTS time signal encoder by radio95) version 1.1\n");
typedef struct
{
float master_volume;
float freq;
uint32_t sample_rate;
int16_t offset;
bool test_mode;
} Chimer95_Config;
typedef struct
{
PulseOutputDevice output_device;
} Chimer95_Runtime;
int run_chimer95(Chimer95_Config config, Chimer95_Runtime* runtime) {
int pulse_error;
Oscillator osc;
init_oscillator(&osc, config.freq, config.sample_rate);
float output[BUFFER_SIZE];
int pip_samples = (int)((PIP_DURATION / 1000.0) * config.sample_rate);
int pause_samples = (int)((PIP_PAUSE / 1000.0) * config.sample_rate);
int beep_samples = (int)((BEEP_DURATION / 1000.0) * config.sample_rate);
int samples_29_56 = 4 * (pip_samples + pause_samples) + beep_samples;
int samples_59_55 = 5 * (pip_samples + pause_samples) + beep_samples;
printf("Ready to play time signals.\n");
printf("Will trigger at XX:29:%02d and XX:59:%02d\n", 56+config.offset, 55+config.offset);
if (config.test_mode) printf("TEST MODE: Will also play full hour signal at the end of every minute\n");
int elapsed_samples = 0;
int total_sequence_samples = 0;
int sequence_completed = 0;
while (to_run) {
if (!playing_sequence) {
int new_sequence = check_time_for_sequence(config.test_mode, config.offset);
if (new_sequence != SEQ_NONE) {
playing_sequence = 1;
sequence_type = new_sequence;
elapsed_samples = 0;
sequence_completed = 0;
if (new_sequence == SEQ_29_56) total_sequence_samples = samples_29_56;
else total_sequence_samples = samples_59_55;
memset(output, 0, sizeof(output));
} else {
static int idle_counter = 0;
if (idle_counter++ % 10 == 0) {
memset(output, 0, sizeof(output));
if((pulse_error = write_PulseOutputDevice(&runtime->output_device, output, sizeof(output)))) {
fprintf(stderr, "Error writing to output device: %s\n", pa_strerror(pulse_error));
to_run = 0;
break;
}
}
struct timespec ts = {0, 5000000}; // 5ms sleep
nanosleep(&ts, NULL);
continue;
}
}
int num_pips = (sequence_type == SEQ_29_56) ? 4 : 5;
generate_signal(output, &osc, config.master_volume,
&elapsed_samples, total_sequence_samples,
pip_samples, pause_samples, beep_samples, num_pips);
if (!playing_sequence && !sequence_completed) sequence_completed = 1;
if((pulse_error = write_PulseOutputDevice(&runtime->output_device, output, sizeof(output)))) {
fprintf(stderr, "Error writing to output device: %s\n", pa_strerror(pulse_error));
to_run = 0;
break;
}
}
return 0;
}
int main(int argc, char **argv) {
printf("chimer95 (GTS time signal encoder by radio95) version 1.2\n");
char audio_output_device[64] = OUTPUT_DEVICE;
float master_volume = DEFAULT_MASTER_VOLUME;
float freq = DEFAULT_FREQ;
int sample_rate = DEFAULT_SAMPLE_RATE;
int offset = DEFAULT_OFFSET;
int test_mode = 0;
Chimer95_Config config = {
.master_volume = DEFAULT_MASTER_VOLUME,
.freq = DEFAULT_FREQ,
.sample_rate = DEFAULT_SAMPLE_RATE,
.offset = DEFAULT_OFFSET,
.test_mode = 0
};
// Parse command line arguments
int opt;
@@ -141,19 +225,19 @@ int main(int argc, char **argv) {
audio_output_device[sizeof(audio_output_device) - 1] = '\0';
break;
case 'F':
freq = strtof(optarg, NULL);
config.freq = strtof(optarg, NULL);
break;
case 's':
sample_rate = strtol(optarg, NULL, 10);
config.sample_rate = strtol(optarg, NULL, 10);
break;
case 'v':
master_volume = strtof(optarg, NULL);
config.master_volume = strtof(optarg, NULL);
break;
case 't':
offset = strtol(optarg, NULL, 10);
config.offset = strtoul(optarg, NULL, 10);
break;
case 'T':
test_mode = 1;
config.test_mode = 1;
break;
case 'h':
show_help(argv[0]);
@@ -163,11 +247,11 @@ int main(int argc, char **argv) {
printf("Configuration:\n");
printf("\tOutput device: %s\n", audio_output_device);
printf("\tFrequency: %.1f Hz\n", freq);
printf("\tSample rate: %d Hz\n", sample_rate);
printf("\tVolume: %.2f\n", master_volume);
printf("\tTime offset: %d seconds\n", offset);
printf("\tTest mode: %s\n", test_mode ? "Enabled" : "Disabled");
printf("\tFrequency: %.1f Hz\n", config.freq);
printf("\tSample rate: %d Hz\n", config.sample_rate);
printf("\tVolume: %.2f\n", config.master_volume);
printf("\tTime offset: %d seconds\n", config.offset);
printf("\tTest mode: %s\n", config.test_mode ? "Enabled" : "Disabled");
// Setup PulseAudio
pa_buffer_attr output_buffer_atr = {
@@ -176,81 +260,22 @@ int main(int argc, char **argv) {
.prebuf = buffer_prebuf
};
int pulse_error;
Chimer95_Runtime runtime;
memset(&runtime, 0, sizeof(runtime));
printf("Connecting to output device... (%s)\n", audio_output_device);
pulse_error = init_PulseOutputDevice(&output_device, sample_rate, 1, "chimer95", "Main Audio Output", audio_output_device, &output_buffer_atr, PA_SAMPLE_FLOAT32NE);
int pulse_error = init_PulseOutputDevice(&runtime.output_device, config.sample_rate, 1, "chimer95", "Main Audio Output", audio_output_device, &output_buffer_atr, PA_SAMPLE_FLOAT32NE);
if (pulse_error) {
fprintf(stderr, "Error: cannot open output device: %s\n", pa_strerror(pulse_error));
return 1;
}
Oscillator osc;
init_oscillator(&osc, freq, sample_rate);
signal(SIGINT, stop);
signal(SIGTERM, stop);
float output[BUFFER_SIZE];
int pip_samples = (int)((PIP_DURATION / 1000.0) * sample_rate);
int pause_samples = (int)((PIP_PAUSE / 1000.0) * sample_rate);
int beep_samples = (int)((BEEP_DURATION / 1000.0) * sample_rate);
int samples_29_56 = 4 * (pip_samples + pause_samples) + beep_samples;
int samples_59_55 = 5 * (pip_samples + pause_samples) + beep_samples;
printf("Ready to play time signals.\n");
printf("Will trigger at XX:29:%02d and XX:59:%02d\n", 56+offset, 55+offset);
if (test_mode) printf("TEST MODE: Will also play full hour signal at the end of every minute\n");
int elapsed_samples = 0;
int total_sequence_samples = 0;
int sequence_completed = 0;
while (to_run) {
if (!playing_sequence) {
int new_sequence = check_time_for_sequence(test_mode, offset);
if (new_sequence != SEQ_NONE) {
playing_sequence = 1;
sequence_type = new_sequence;
elapsed_samples = 0;
sequence_completed = 0;
if (new_sequence == SEQ_29_56) total_sequence_samples = samples_29_56;
else total_sequence_samples = samples_59_55;
memset(output, 0, sizeof(output));
} else {
static int idle_counter = 0;
if (idle_counter++ % 10 == 0) {
memset(output, 0, sizeof(output));
write_PulseOutputDevice(&output_device, output, sizeof(output));
}
struct timespec ts = {0, 5000000}; // 5ms sleep
nanosleep(&ts, NULL);
continue;
}
}
int num_pips = (sequence_type == SEQ_29_56) ? 4 : 5;
generate_signal(output, &osc, master_volume,
&elapsed_samples, total_sequence_samples,
pip_samples, pause_samples, beep_samples, num_pips);
if (!playing_sequence && !sequence_completed) sequence_completed = 1;
if((pulse_error = write_PulseOutputDevice(&output_device, output, sizeof(output)))) {
fprintf(stderr, "Error writing to output device: %s\n", pa_strerror(pulse_error));
to_run = 0;
break;
}
}
int ret = run_chimer95(config, &runtime);
printf("Cleaning up...\n");
free_PulseOutputDevice(&output_device);
return 0;
free_PulseOutputDevice(&runtime.output_device);
return ret;
}

View File

@@ -122,8 +122,6 @@ int run_fm95(FM95_Config config, FM95_Runtime* runtime) {
Oscillator osc;
init_oscillator(&osc, (config.calibration == 2) ? 60 : 400, config.sample_rate);
signal(SIGINT, stop);
signal(SIGTERM, stop);
int pulse_error;
float output[BUFFER_SIZE];
@@ -166,9 +164,6 @@ int run_fm95(FM95_Config config, FM95_Runtime* runtime) {
// fs target min max attack release
initAGC(&agc, config.sample_rate, 0.65f, 0.0f, 1.75f, 0.03f, 0.225f);
signal(SIGINT, stop);
signal(SIGTERM, stop);
int pulse_error;
float audio_stereo_input[BUFFER_SIZE*2]; // Stereo
@@ -181,23 +176,20 @@ int run_fm95(FM95_Config config, FM95_Runtime* runtime) {
while (to_run) {
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
if(pulse_error == -1) fprintf(stderr, "Main PulseInputDevice reported as uninitialized.");
else fprintf(stderr, "Error reading from input device: %s\n", pa_strerror(pulse_error));
fprintf(stderr, "Error reading from input device: %s\n", pa_strerror(pulse_error));
to_run = 0;
break;
}
if(mpx_on) {
if((pulse_error = read_PulseInputDevice(&runtime->mpx_device, mpx_in, sizeof(mpx_in)))) {
if(pulse_error == -1) fprintf(stderr, "MPX PulseInputDevice reported as uninitialized.");
else fprintf(stderr, "Error reading from MPX device: %s\n", pa_strerror(pulse_error));
fprintf(stderr, "Error reading from MPX device: %s\n", pa_strerror(pulse_error));
fprintf(stderr, "Disabling MPX.\n");
mpx_on = 0;
}
}
if(rds_on) {
if((pulse_error = read_PulseInputDevice(&runtime->rds_device, rds_in, sizeof(float) * BUFFER_SIZE * config.rds_streams))) {
if(pulse_error == -1) fprintf(stderr, "RDS95 PulseInputDevice reported as uninitialized.");
else fprintf(stderr, "Error reading from RDS95 device: %s\n", pa_strerror(pulse_error));
fprintf(stderr, "Error reading from RDS95 device: %s\n", pa_strerror(pulse_error));
fprintf(stderr, "Disabling RDS.\n");
rds_on = 0;
}
@@ -249,8 +241,7 @@ int run_fm95(FM95_Config config, FM95_Runtime* runtime) {
}
if((pulse_error = write_PulseOutputDevice(&runtime->output_device, output, sizeof(output)))) {
if(pulse_error == -1) fprintf(stderr, "Main PulseOutputDevice reported as uninitialized.");
else fprintf(stderr, "Error writing to output device: %s\n", pa_strerror(pulse_error));
fprintf(stderr, "Error writing to output device: %s\n", pa_strerror(pulse_error));
to_run = 0;
break;
}
@@ -429,6 +420,9 @@ int main(int argc, char **argv) {
return 1;
}
signal(SIGINT, stop);
signal(SIGTERM, stop);
int ret = run_fm95(config, &runtime);
printf("Cleaning up...\n");
free_PulseInputDevice(&runtime.input_device);