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:
199
src/chimer95.c
199
src/chimer95.c
@@ -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;
|
||||
}
|
||||
20
src/fm95.c
20
src/fm95.c
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user