diff --git a/.vscode/.server-controller-port.log b/.vscode/.server-controller-port.log index d9ee9c4..1bc301f 100644 --- a/.vscode/.server-controller-port.log +++ b/.vscode/.server-controller-port.log @@ -1,5 +1,5 @@ { "port": 13452, - "time": 1746171059613, + "time": 1750505649575, "version": "0.0.3" } \ No newline at end of file diff --git a/dsp/filters.c b/dsp/filters.c index b033815..15a992a 100644 --- a/dsp/filters.c +++ b/dsp/filters.c @@ -5,11 +5,7 @@ void init_preemphasis(ResistorCapacitor *filter, float tau, float sample_rate, f filter->alpha = tau / (tau + dt); float omega = M_2PI * ref_freq / sample_rate; - float cos_omega = cosf(omega); - - float numerator = sqrtf(1.0f + filter->alpha * filter->alpha - 2.0f * filter->alpha * cos_omega); - - filter->gain = 1.0f / numerator; + filter->gain = 1.0f / sqrtf(1.0f + filter->alpha * filter->alpha - 2.0f * filter->alpha * cosf(omega)); filter->prev_sample = 0.0f; } diff --git a/dsp/gain_control.c b/dsp/gain_control.c index 7780e4c..ca16777 100644 --- a/dsp/gain_control.c +++ b/dsp/gain_control.c @@ -15,7 +15,7 @@ void initAGC(AGC* agc, int sampleRate, float targetLevel, float minGain, float m agc->currentLevel = 0.0f; agc->rms_buffer = 0.0f; - agc->rmsAlpha = expf(-1.0f / (sampleRate * 0.04f)); + agc->rmsAlpha = expf(-1.0f / (sampleRate * 0.02f)); } float process_agc(AGC* agc, float sidechain) { diff --git a/src/chimer95.c b/src/chimer95.c index 8bb3a02..e7d528e 100644 --- a/src/chimer95.c +++ b/src/chimer95.c @@ -44,10 +44,6 @@ static void stop(int signum) { to_run = 0; } -void show_version() { - printf("chimer95 (GTS time signal encoder by radio95) version 1.1\n"); -} - void show_help(char *name) { printf( "Usage:\t%s\n" @@ -66,50 +62,8 @@ void show_help(char *name) { ); } -void generate_signal(float *output, int buffer_size, Oscillator *osc, float volume, int *elapsed_samples, int total_samples, int pip_samples, int pause_samples, int beep_samples, int num_pips) { -#if USE_NEON - float32x4_t v_volume = vdupq_n_f32(volume); - - for (int i = 0; i < buffer_size; i += 4) { - if (*elapsed_samples >= total_samples) { - vst1q_f32(&output[i], vdupq_n_f32(0.0f)); - playing_sequence = 0; - } else { - int cycle_position = *elapsed_samples; - int pip_cycle = pip_samples + pause_samples; - float32x4_t v_samples; - - if (cycle_position < num_pips * pip_cycle) { - int within_cycle = cycle_position % pip_cycle; - if (within_cycle < pip_samples) { - float samples[4] = { - get_oscillator_sin_sample(osc), - get_oscillator_sin_sample(osc), - get_oscillator_sin_sample(osc), - get_oscillator_sin_sample(osc), - }; - v_samples = vmulq_f32(vld1q_f32(samples), v_volume); - } else { - v_samples = vdupq_n_f32(0.0f); - } - } else if (cycle_position < num_pips * pip_cycle + beep_samples) { - float samples[4] = { - get_oscillator_sin_sample(osc), - get_oscillator_sin_sample(osc), - get_oscillator_sin_sample(osc), - get_oscillator_sin_sample(osc), - }; - v_samples = vmulq_f32(vld1q_f32(samples), v_volume); - } else { - v_samples = vdupq_n_f32(0.0f); - } - - vst1q_f32(&output[i], v_samples); - (*elapsed_samples) += 4; - } - } -#else - for (int i = 0; i < buffer_size; i++) { +void generate_signal(float *output, Oscillator *osc, float volume, int *elapsed_samples, int total_samples, int pip_samples, int pause_samples, int beep_samples, int num_pips) { + for (int i = 0; i < BUFFER_SIZE; i++) { if (*elapsed_samples >= total_samples) { output[i] = 0; playing_sequence = 0; @@ -118,22 +72,14 @@ void generate_signal(float *output, int buffer_size, Oscillator *osc, float volu int pip_cycle = pip_samples + pause_samples; if (cycle_position < num_pips * pip_cycle) { - int within_cycle = cycle_position % pip_cycle; - if (within_cycle < pip_samples) { - output[i] = get_oscillator_sin_sample(osc) * volume; - } else { - output[i] = 0; - } - } else if (cycle_position < num_pips * pip_cycle + beep_samples) { - output[i] = get_oscillator_sin_sample(osc) * volume; - } else { - output[i] = 0; - } + if ((cycle_position % pip_cycle) < pip_samples) output[i] = get_oscillator_sin_sample(osc) * volume; + else output[i] = 0; + } else if (cycle_position < num_pips * pip_cycle + beep_samples) output[i] = get_oscillator_sin_sample(osc) * volume; + else output[i] = 0; (*elapsed_samples)++; } } -#endif } int check_time_for_sequence(int test_mode, int offset) { @@ -152,19 +98,11 @@ int check_time_for_sequence(int test_mode, int offset) { return SEQ_NONE; } - if (minute == 29 && second == (56 + offset)) { - last_sequence_time = now; - return SEQ_29_56; - } - - if (minute == 59 && second == (55 + offset)) { - last_sequence_time = now; - return SEQ_59_55; - } - + last_sequence_time = now; + if (minute == 29 && second == (56 + offset)) return SEQ_29_56; + if (minute == 59 && second == (55 + offset)) return SEQ_59_55; if (test_mode && second == (55 + offset) && minute != last_minute) { last_minute = minute; - last_sequence_time = now; return SEQ_TEST_HOUR; } @@ -172,7 +110,7 @@ int check_time_for_sequence(int test_mode, int offset) { } int main(int argc, char **argv) { - show_version(); + printf("chimer95 (GTS time signal encoder by radio95) version 1.1\n"); PulseOutputDevice output_device; @@ -266,9 +204,7 @@ int main(int argc, char **argv) { 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"); - } + 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; @@ -302,7 +238,7 @@ int main(int argc, char **argv) { } int num_pips = (sequence_type == SEQ_29_56) ? 4 : 5; - generate_signal(output, BUFFER_SIZE, &osc, master_volume, + generate_signal(output, &osc, master_volume, &elapsed_samples, total_sequence_samples, pip_samples, pause_samples, beep_samples, num_pips); diff --git a/src/dcf95.c b/src/dcf95.c index dd9d19a..f3226f5 100644 --- a/src/dcf95.c +++ b/src/dcf95.c @@ -119,7 +119,7 @@ void calculate_dcf77_bits(time_t now, int *bits) { bits[20] = 1; int minutes = t->tm_min; - for (int i = 0; i < 4; i++) bits[21 + i] = (minutes % 10 >> i) & 1; + for (int i = 0; i < 4; i++) bits[21 + i] = (minutes % 10 >> i) & 1; // BCD for (int i = 0; i < 3; i++) bits[25 + i] = (minutes / 10 >> i) & 1; int minute_parity = 0; @@ -155,8 +155,6 @@ void calculate_dcf77_bits(time_t now, int *bits) { int year_parity = 0; for (int i = 36; i <= 57; i++) year_parity ^= bits[i]; bits[58] = year_parity; - - bits[59] = 2; } void print_dcf77_bits(const int *bits) { @@ -205,7 +203,6 @@ int main(int argc, char **argv) { uint8_t test_mode = 0; uint8_t no_phase = 0; - // #region Parse Arguments int opt; const char *short_opt = "o:F:s:v:t:Tnh"; struct option long_opt[] = @@ -251,7 +248,6 @@ int main(int argc, char **argv) { return 0; } } - // #endregion if(test_mode) { time_t now = time(NULL) + offset + 60; @@ -364,17 +360,14 @@ int main(int argc, char **argv) { int current_bit = bit_position > 0 ? bit_position - 1 : 59; - in_dsss_period = (elapsed_samples >= dsss_start_samples && - elapsed_samples < dsss_end_samples); + in_dsss_period = (elapsed_samples >= dsss_start_samples && elapsed_samples < dsss_end_samples); float phase_offset = 0.0; if (in_dsss_period && transmitting && !no_phase) { if (current_cycle_count == 0) { if (current_chip_count < CHIPS_PER_BIT) { - unsigned int chip = generate_chip(); - - unsigned int modulated_chip = chip ^ dcf77_bits[current_bit]; + unsigned int modulated_chip = generate_chip() ^ dcf77_bits[current_bit]; if (modulated_chip == 0) phase_offset = phase_shift_rad; else phase_offset = -phase_shift_rad; @@ -386,12 +379,11 @@ int main(int argc, char **argv) { current_cycle_count = (current_cycle_count + 1) % CHIP_CYCLES; } - float t = osc.phase + phase_offset; - float carrier = sinf(t); + float carrier = sinf(osc.phase + phase_offset); advance_oscillator(&osc); if (transmitting) { - if ((dcf77_bits[current_bit] == 0 && ms_within_second < PULSE_0_DURATION) || + if (current_bit != 59 && (dcf77_bits[current_bit] == 0 && ms_within_second < PULSE_0_DURATION) || (dcf77_bits[current_bit] == 1 && ms_within_second < PULSE_1_DURATION)) { output[i] = carrier * master_volume * REDUCED_AMPLITUDE; } else output[i] = carrier * master_volume; diff --git a/src/fm95.c b/src/fm95.c index 1f23e4c..c9b83c7 100644 --- a/src/fm95.c +++ b/src/fm95.c @@ -9,6 +9,7 @@ #define DEFAULT_STEREO 1 #define DEFAULT_STEREO_POLAR 0 +#define DEFAULT_RDS_STREAMS 2 #define DEFAULT_CLIPPER_THRESHOLD 1.0f #define DEFAULT_SCA_FREQUENCY 67000.0f #define DEFAULT_SCA_DEVIATION 7000.0f @@ -30,7 +31,6 @@ #define INPUT_DEVICE "FM_Audio.monitor" #define OUTPUT_DEVICE "alsa_output.platform-soc_sound.stereo-fallback" #define RDS_DEVICE "RDS.monitor" -#define RDS2_DEVICE "\0" // Disabled, this is for the additional two RDS channels, 71.25 and 76 khz #define MPX_DEVICE "FM_MPX.monitor" #define SCA_DEVICE "\0" // Disabled @@ -45,12 +45,8 @@ #define PILOT_VOLUME 0.09f // 9% #define STEREO_VOLUME 0.3f // 30% #define RDS_VOLUME 0.0475f // 4.75% -#define RDS2_VOLUME 0.04f // 4% -#define RDS3_VOLUME 0.0375f // 3.75% -#define RDS4_VOLUME 0.035f // 3.5% -#define SCA_VOLUME 0.1f // 10%, needs to be high because this is analog - -#define MPX_VOLUME 1.0f +#define RDS_VOLUME_STEP 0.9f // 90%, so RDS2 stream 4 is 90% of stream 3 which is 90% of stream 2, which again is 90% of stream 1... +#define SCA_VOLUME 0.1f // 10%, needs to be high because this is analog. TODO: move sca to its own program (because then you can have as much scas as your computer allows to, here you have just one, and sca does not need any phase sync) static volatile sig_atomic_t to_run = 1; @@ -72,7 +68,7 @@ void show_help(char *name) { "\t-o,--output\tOverride output device [default: %s]\n" "\t-M,--mpx\tOverride MPX input device [default: %s]\n" "\t-r,--rds\tOverride RDS95 input device [default: %s]\n" - "\t-R,--rds2\tOverride the RDS2 additional stream device [default: %s]\n" + "\t-R,--rds_streams\tSpecifies the number of the RDS streams provided by RDS95 [default: %d]\n" "\t-S,--sca\tOverride the SCA input device [default: %s]\n" "\t-f,--sca_freq\tOverride the SCA frequency [default: %.1f]\n" "\t-F,--sca_dev\tOverride the SCA deviation [default: %.2f]\n" @@ -92,7 +88,7 @@ void show_help(char *name) { ,OUTPUT_DEVICE ,MPX_DEVICE ,RDS_DEVICE - ,RDS2_DEVICE + ,DEFAULT_RDS_STREAMS ,SCA_DEVICE ,DEFAULT_SCA_FREQUENCY ,DEFAULT_SCA_DEVIATION @@ -109,14 +105,15 @@ void show_help(char *name) { } int main(int argc, char **argv) { - printf("fm95 (an FM Processor by radio95) version 1.7\n"); + printf("fm95 (an FM Processor by radio95) version 1.8\n"); - PulseInputDevice input_device, mpx_device, rds_device, rds2_device, sca_device; + PulseInputDevice input_device, mpx_device, rds_device, sca_device; PulseOutputDevice output_device; float clipper_threshold = DEFAULT_CLIPPER_THRESHOLD; uint8_t stereo = DEFAULT_STEREO; uint8_t polar_stereo = DEFAULT_STEREO_POLAR; + uint8_t rds_streams = DEFAULT_RDS_STREAMS; float sca_frequency = DEFAULT_SCA_FREQUENCY; float sca_deviation = DEFAULT_SCA_DEVIATION; @@ -126,7 +123,6 @@ int main(int argc, char **argv) { char audio_output_device[48] = OUTPUT_DEVICE; char audio_mpx_device[48] = MPX_DEVICE; char audio_rds_device[48] = RDS_DEVICE; - char audio_rds2_device[48] = RDS2_DEVICE; char audio_sca_device[48] = SCA_DEVICE; float preemphasis_tau = DEFAULT_PREEMPHASIS_TAU; @@ -184,8 +180,12 @@ int main(int argc, char **argv) { case 'r': // RDS in memcpy(audio_rds_device, optarg, 47); break; - case 'R': // RDS2 in - memcpy(audio_rds2_device, optarg, 47); + case 'R': // RDS Streams + rds_streams = atoi(optarg); + if(rds_streams > 4) { + printf("Can't do more RDS streams than 4 (why even?)\n"); + exit(1); + } break; case 'S': //SCA in memcpy(audio_sca_device, optarg, 47); @@ -236,12 +236,9 @@ int main(int argc, char **argv) { // #endregion int mpx_on = (strlen(audio_mpx_device) != 0); - int rds_on = (strlen(audio_rds_device) != 0); - int rds2_on = (rds_on && strlen(audio_rds2_device) != 0); + int rds_on = (strlen(audio_rds_device) != 0 && rds_streams != 0); int sca_on = (strlen(audio_sca_device) != 0); - // #region Setup devices - // Define formats and buffer atributes pa_buffer_attr input_buffer_atr = { .maxlength = buffer_maxlength, @@ -275,7 +272,7 @@ int main(int argc, char **argv) { if(rds_on) { printf("Connecting to RDS95 device... (%s)\n", audio_rds_device); - opentime_pulse_error = init_PulseInputDevice(&rds_device, sample_rate, 2, "fm95", "RDS95 Input", audio_rds_device, &input_buffer_atr, PA_SAMPLE_FLOAT32NE); + opentime_pulse_error = init_PulseInputDevice(&rds_device, sample_rate, rds_streams, "fm95", "RDS95 Input", audio_rds_device, &input_buffer_atr, PA_SAMPLE_FLOAT32NE); if (opentime_pulse_error) { fprintf(stderr, "Error: cannot open RDS device: %s\n", pa_strerror(opentime_pulse_error)); free_PulseInputDevice(&input_device); @@ -283,18 +280,6 @@ int main(int argc, char **argv) { return 1; } } - if(rds2_on) { - printf("Connecting to RDS2 device... (%s)\n", audio_rds2_device); - - opentime_pulse_error = init_PulseInputDevice(&rds2_device, sample_rate, 1, "fm95", "RDS2 Input", audio_rds2_device, &input_buffer_atr, PA_SAMPLE_FLOAT32NE); - if (opentime_pulse_error) { - fprintf(stderr, "Error: cannot open RDS2 device: %s\n", pa_strerror(opentime_pulse_error)); - free_PulseInputDevice(&input_device); - if(mpx_on) free_PulseInputDevice(&mpx_device); - if(rds_on) free_PulseInputDevice(&rds_device); - return 1; - } - } if(sca_on) { printf("Connecting to SCA device... (%s)\n", audio_sca_device); @@ -305,7 +290,6 @@ int main(int argc, char **argv) { free_PulseInputDevice(&input_device); if(mpx_on) free_PulseInputDevice(&mpx_device); if(rds_on) free_PulseInputDevice(&rds_device); - if(rds2_on) free_PulseInputDevice(&rds2_device); return 1; } } @@ -318,11 +302,9 @@ int main(int argc, char **argv) { free_PulseInputDevice(&input_device); if(mpx_on) free_PulseInputDevice(&mpx_device); if(rds_on) free_PulseInputDevice(&rds_device); - if(rds2_on) free_PulseInputDevice(&rds2_device); if(sca_on) free_PulseInputDevice(&sca_device); return 1; } - // #endregion if(calibration_mode != 0) { Oscillator osc; @@ -350,7 +332,6 @@ int main(int argc, char **argv) { free_PulseInputDevice(&input_device); if(mpx_on) free_PulseInputDevice(&mpx_device); if(rds_on) free_PulseInputDevice(&rds_device); - if(rds2_on) free_PulseInputDevice(&rds2_device); if(sca_on) free_PulseInputDevice(&sca_device); free_PulseOutputDevice(&output_device); return 0; @@ -388,8 +369,7 @@ int main(int argc, char **argv) { float audio_stereo_input[BUFFER_SIZE*2]; // Stereo - float rds1_rds2_in[BUFFER_SIZE*2] = {0}; // Stereo - float rds3_rds4_in[BUFFER_SIZE*2] = {0}; // Stereo + float rds_in[BUFFER_SIZE*rds_streams] = {0}; // multichannel float mpx_in[BUFFER_SIZE] = {0}; float sca_in[BUFFER_SIZE] = {0}; @@ -411,21 +391,13 @@ int main(int argc, char **argv) { } } if(rds_on) { - if((pulse_error = read_PulseInputDevice(&rds_device, rds1_rds2_in, sizeof(rds1_rds2_in)))) { + if((pulse_error = read_PulseInputDevice(&rds_device, rds_in, sizeof(rds_in)))) { 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)); to_run = 0; break; } } - if(rds2_on) { - if((pulse_error = read_PulseInputDevice(&rds2_device, rds3_rds4_in, sizeof(rds3_rds4_in)))) { - if(pulse_error == -1) fprintf(stderr, "RDS2 PulseInputDevice reported as uninitialized."); - else fprintf(stderr, "Error reading from RDS2 device: %s\n", pa_strerror(pulse_error)); - to_run = 0; - break; - } - } if(sca_on) { if((pulse_error = read_PulseInputDevice(&sca_device, sca_in, sizeof(sca_in)))) { if(pulse_error == -1) fprintf(stderr, "SCA PulseInputDevice reported as uninitialized."); @@ -466,18 +438,13 @@ int main(int argc, char **argv) { } } if(rds_on && !polar_stereo) { - float rds_carrier = get_oscillator_cos_multiplier_ni(&osc, 12); // 57 KHz - float rds2_carrier_66 = get_oscillator_cos_multiplier_ni(&osc, 14); // 66.5 KHz - mpx += (rds1_rds2_in[2*i+0]*rds_carrier)*RDS_VOLUME; - mpx += (rds1_rds2_in[2*i+1]*rds2_carrier_66)*RDS2_VOLUME; - if(rds2_on) { - float rds2_carrier_71 = get_oscillator_cos_multiplier_ni(&osc, 15); // 71.25 KHz - float rds2_carrier_76 = get_oscillator_cos_multiplier_ni(&osc, 16); // 76 KHz - mpx += (rds3_rds4_in[2*i+0]*rds2_carrier_71)*RDS3_VOLUME; - mpx += (rds3_rds4_in[2*i+1]*rds2_carrier_76)*RDS4_VOLUME; + for(int stream = 0; stream < rds_streams; stream++) { + uint8_t osc_stream = 12+stream; + if(osc_stream == 13) osc_stream++; // 61.75 KHz is not used, idk why but would be cool if it was + mpx += (rds_in[rds_streams*i+stream]*get_oscillator_cos_multiplier_ni(&osc, osc_stream)) * (RDS_VOLUME * powf(RDS_VOLUME_STEP, stream - 1)); } } - if(mpx_on) mpx += mpx_in[i]*MPX_VOLUME; + if(mpx_on) mpx += mpx_in[i]; if(sca_on) mpx += modulate_fm(&sca_mod, hard_clip(sca_in[i], sca_clipper_threshold))*SCA_VOLUME; float mpxonly_power = measure_mpx(&mpx_only_power, mpx * mpx_deviation); @@ -492,12 +459,14 @@ int main(int argc, char **argv) { target_gain = fmaxf(target_gain, 0.1f); target_gain = fminf(target_gain, 1.0f); - bs412_audio_gain = 0.8f * bs412_audio_gain + 0.2f * target_gain; + bs412_audio_gain = 0.85f * bs412_audio_gain + 0.15f * target_gain; } } else { bs412_audio_gain = fminf(1.0f, bs412_audio_gain + 0.001f); } + audio *= bs412_audio_gain; + iirfilt_rrrf_execute(mpx_lpf, audio, &audio); // Should have no effect, as audio should be 0-15, and 23-53, this is a filter for 53, assuming the filter is good, this is precaution and recomendation audio = hard_clip(audio, 1.0f-mpx); // Prevent clipping, via clipping the audio signal with relation to the mpx signal @@ -520,7 +489,6 @@ int main(int argc, char **argv) { free_PulseInputDevice(&input_device); if(mpx_on) free_PulseInputDevice(&mpx_device); if(rds_on) free_PulseInputDevice(&rds_device); - if(rds2_on) free_PulseInputDevice(&rds2_device); if(sca_on) free_PulseInputDevice(&sca_device); free_PulseOutputDevice(&output_device); return 0;