mirror of
https://github.com/radio95-rnt/fm95.git
synced 2026-02-26 19:23:51 +01:00
changes
This commit is contained in:
2
.vscode/.server-controller-port.log
vendored
2
.vscode/.server-controller-port.log
vendored
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"port": 13452,
|
||||
"time": 1737836988947,
|
||||
"time": 1737842835132,
|
||||
"version": "0.0.3"
|
||||
}
|
||||
36
README.md
36
README.md
@@ -1,36 +1,28 @@
|
||||
# FMTools
|
||||
FMTools is a repository of apps you can use to make your FM broadcast better, pirate or not this will help you if you don't have something, maybe you want a better stereo encoder? SCA? We have what you need, for RDS just use MiniRDS
|
||||
|
||||
# STCode
|
||||
STCode is a simple stereo encoder for FM, it uses pasimple and math to:
|
||||
- Calculate mono signal ((L+R)/2)
|
||||
- Generate the stereo pilot in phase to the stereo subcarrier
|
||||
- Generate the stereo diffrence signal using DSB-SC ((L-R)/2)
|
||||
# fm95
|
||||
FM95 is a audio processor for FM, it does:
|
||||
- Pre-Emphasis
|
||||
- Low Pass Filter
|
||||
- Stereo
|
||||
- SSB Stereo
|
||||
- Polar Stereo
|
||||
- Polar SSB Stereo (huh)
|
||||
|
||||
All that in about 3.5% cpu usage on a RPI-5 (stereo tool has 3 threads which do 100% cpu usage anyway, one 200)
|
||||
Supports 2 inputs:
|
||||
- Audio (via Pulse)
|
||||
- MPX (via Pulse)
|
||||
and one output:
|
||||
- MPX (via Pulse or ALSA)
|
||||
|
||||
Also nearly no latency, not like Stereo Tool (or mpxgen which doesn't even work)
|
||||
|
||||
As far as i've tested it (29-31 december) it's been fine but after a fix it was great, so i'd recommend this to you
|
||||
|
||||
Also i'd recommend to use the SSB version because it's more spectrum effiecent
|
||||
but SSB has slightly more cpu usage
|
||||
|
||||
This supports alsa output
|
||||
|
||||
# PSTCode
|
||||
This is a yet another version of a Stereo encoder, however for the OIRT band which is in use in Russia, Belarus and other countries
|
||||
|
||||
Haven't tested it nor plan to
|
||||
Note that i haven't tested it, but i will on monday (29-01-25)
|
||||
|
||||
# SCAMod
|
||||
SCAMod is a simple FM modulator which can be used to modulate a secondary audio stream, has similiar cpu usage and latency as STCode
|
||||
|
||||
Has a fine quality, but as it goes for 12 khz fm signals
|
||||
|
||||
# MonoPass
|
||||
want to keep mono for a reason but have the lpf and preemphasis, do so
|
||||
|
||||
# How to compile?
|
||||
To compile you need `cmake` and `libpulse-dev`, if you have those then do these commands:
|
||||
```
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../lib/constants.h"
|
||||
#include "../lib/oscillator.h"
|
||||
#include "../lib/filters.h"
|
||||
|
||||
#include "options.h"
|
||||
|
||||
#define SAMPLE_RATE 192000 // Don't go lower than 108 KHz, becuase it (53000*2) and (38000+15000)
|
||||
|
||||
#define INPUT_DEVICE "real_real_tx_audio_input.monitor"
|
||||
#define OUTPUT_DEVICE "alsa_output.platform-soc_sound.stereo-fallback"
|
||||
// #define ALSA_OUTPUT // Output, not input or both
|
||||
#define BUFFER_SIZE 512
|
||||
#define CLIPPER_THRESHOLD 0.525 // Adjust this as needed
|
||||
|
||||
#include <pulse/simple.h>
|
||||
#include <pulse/error.h>
|
||||
#ifdef ALSA_OUTPUT
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
|
||||
#define MONO_VOLUME 0.45f // L+R Signal
|
||||
#define STEREO_VOLUME 0.45f // L-R signal
|
||||
|
||||
#ifdef PREEMPHASIS
|
||||
#define PREEMPHASIS_TAU 0.00005 // 50 microseconds, use 0.000075 if in america
|
||||
#endif
|
||||
|
||||
#ifdef LPF
|
||||
#define LPF_CUTOFF 15000
|
||||
#endif
|
||||
|
||||
volatile sig_atomic_t to_run = 1;
|
||||
|
||||
float hard_clip(float sample) {
|
||||
if (sample > CLIPPER_THRESHOLD) {
|
||||
return CLIPPER_THRESHOLD; // Clip to the upper threshold
|
||||
} else if (sample < -CLIPPER_THRESHOLD) {
|
||||
return -CLIPPER_THRESHOLD; // Clip to the lower threshold
|
||||
} else {
|
||||
return sample; // No clipping
|
||||
}
|
||||
}
|
||||
|
||||
void uninterleave(const float *input, float *left, float *right, size_t num_samples) {
|
||||
// For stereo, usually it is like this: LEFT RIGHT LEFT RIGHT LEFT RIGHT so this is used to get LEFT LEFT LEFT and RIGHT RIGHT RIGHT
|
||||
for (size_t i = 0; i < num_samples/2; i++) {
|
||||
left[i] = input[i * 2];
|
||||
right[i] = input[i * 2 + 1];
|
||||
}
|
||||
}
|
||||
|
||||
static void stop(int signum) {
|
||||
(void)signum;
|
||||
printf("\nReceived stop signal. Cleaning up...\n");
|
||||
to_run = 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("PSTCode : (Polar) Stereo encoder made by radio95 (with help of ChatGPT and Claude, thanks!). Note that this version is for the OIRT band which is in use in Russia, Belarus and other CIS countries\n");
|
||||
// Define formats and buffer atributes
|
||||
pa_sample_spec stereo_format = {
|
||||
.format = PA_SAMPLE_FLOAT32NE, //Float32 NE, or Float32 Native Endian, the float in c uses the endianess of your pc, or native endian, and float is float32, and double is float64
|
||||
.channels = 2,
|
||||
.rate = SAMPLE_RATE // Same sample rate makes it easy, leave the resampling to pipewire, it should know better
|
||||
};
|
||||
pa_sample_spec mono_format = {
|
||||
.format = PA_SAMPLE_FLOAT32NE,
|
||||
.channels = 1,
|
||||
.rate = SAMPLE_RATE
|
||||
};
|
||||
|
||||
pa_buffer_attr input_buffer_atr = {
|
||||
.maxlength = buffer_maxlength,
|
||||
.fragsize = buffer_tlength_fragsize
|
||||
};
|
||||
#ifndef ALSA_OUTPUT
|
||||
pa_buffer_attr output_buffer_atr = {
|
||||
.maxlength = buffer_maxlength,
|
||||
.tlength = buffer_tlength_fragsize,
|
||||
.prebuf = buffer_prebuf
|
||||
};
|
||||
#endif
|
||||
|
||||
printf("Connecting to input device... (%s)\n", INPUT_DEVICE);
|
||||
|
||||
pa_simple *input_device = pa_simple_new(
|
||||
NULL,
|
||||
"PolarStereoEncoder",
|
||||
PA_STREAM_RECORD,
|
||||
INPUT_DEVICE,
|
||||
"Audio Input",
|
||||
&stereo_format,
|
||||
NULL,
|
||||
&input_buffer_atr,
|
||||
NULL
|
||||
);
|
||||
if (!input_device) {
|
||||
fprintf(stderr, "Error: cannot open input device.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Connecting to output device... (%s)\n", OUTPUT_DEVICE);
|
||||
|
||||
#ifndef ALSA_OUTPUT
|
||||
pa_simple *output_device = pa_simple_new(
|
||||
NULL,
|
||||
"PolarStereoEncoder",
|
||||
PA_STREAM_PLAYBACK,
|
||||
OUTPUT_DEVICE,
|
||||
"MPX",
|
||||
&mono_format,
|
||||
NULL,
|
||||
&output_buffer_atr,
|
||||
NULL
|
||||
);
|
||||
if (!output_device) {
|
||||
fprintf(stderr, "Error: cannot open output device.\n");
|
||||
pa_simple_free(input_device);
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
snd_pcm_hw_params_t *output_params;
|
||||
snd_pcm_t *output_handle;
|
||||
int output_error = snd_pcm_open(&output_handle, OUTPUT_DEVICE, SND_PCM_STREAM_PLAYBACK, 0);
|
||||
if(output_error < 0) {
|
||||
fprintf(stderr, "Error: cannot open output device: %s\n", snd_strerror(output_error));
|
||||
pa_simple_free(input_device);
|
||||
return 1;
|
||||
}
|
||||
snd_pcm_hw_params_malloc(&output_params);
|
||||
snd_pcm_hw_params_any(output_handle, output_params);
|
||||
snd_pcm_hw_params_set_access(output_handle, output_params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
snd_pcm_hw_params_set_format(output_handle, output_params, SND_PCM_FORMAT_FLOAT); // Same as pulse's Float32NE
|
||||
snd_pcm_hw_params_set_channels(output_handle, output_params, 1);
|
||||
unsigned int rate = SAMPLE_RATE;
|
||||
int dir;
|
||||
snd_pcm_hw_params_set_rate_near(output_handle, output_params, &rate, &dir);
|
||||
snd_pcm_uframes_t frames = BUFFER_SIZE;
|
||||
snd_pcm_hw_params_set_period_size_near(output_handle, output_params, &frames, &dir); // i don't have a clue why like this
|
||||
output_error = snd_pcm_hw_params(output_handle, output_params);
|
||||
if(output_error < 0) {
|
||||
fprintf(stderr, "Error: cannot open output device: %s\n", snd_strerror(output_error));
|
||||
snd_pcm_close(output_handle);
|
||||
pa_simple_free(input_device);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
Oscillator stereo_osc;
|
||||
init_oscillator(&stereo_osc, 31250.0, SAMPLE_RATE);
|
||||
#ifdef PREEMPHASIS
|
||||
ResistorCapacitor preemp_l, preemp_r;
|
||||
init_rc_tau(&preemp_l, PREEMPHASIS_TAU, SAMPLE_RATE);
|
||||
init_rc_tau(&preemp_r, PREEMPHASIS_TAU, SAMPLE_RATE);
|
||||
#endif
|
||||
#ifdef LPF
|
||||
ResistorCapacitor lpf_l, lpf_r;
|
||||
init_low_pass_filter(&lpf_l, LPF_CUTOFF, SAMPLE_RATE);
|
||||
init_low_pass_filter(&lpf_r, LPF_CUTOFF, SAMPLE_RATE);
|
||||
#endif
|
||||
|
||||
signal(SIGINT, stop);
|
||||
signal(SIGTERM, stop);
|
||||
|
||||
int pulse_error;
|
||||
float input[BUFFER_SIZE*2]; // Input from device, interleaved stereo
|
||||
float left[BUFFER_SIZE+64], right[BUFFER_SIZE+64]; // Audio, same thing as in input but ininterleaved, ai told be there could be a buffer overflow here
|
||||
float mpx[BUFFER_SIZE]; // MPX, this goes to the output
|
||||
while (to_run) {
|
||||
if (pa_simple_read(input_device, input, sizeof(input), &pulse_error) < 0) {
|
||||
fprintf(stderr, "Error reading from input device: %s\n", pa_strerror(pulse_error));
|
||||
to_run = 0;
|
||||
break;
|
||||
}
|
||||
uninterleave(input, left, right, BUFFER_SIZE*2);
|
||||
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
float l_in = left[i];
|
||||
float r_in = right[i];
|
||||
|
||||
#ifdef PREEMPHASIS
|
||||
#ifdef LPF
|
||||
float lowpassed_left = apply_low_pass_filter(&lpf_l, l_in);
|
||||
float lowpassed_right = apply_low_pass_filter(&lpf_r, r_in);
|
||||
float preemphasized_left = apply_pre_emphasis(&preemp_l, lowpassed_left)*2;
|
||||
float preemphasized_right = apply_pre_emphasis(&preemp_r, lowpassed_right)*2;
|
||||
float current_left_input = hard_clip(preemphasized_left);
|
||||
float current_right_input = hard_clip(preemphasized_right);
|
||||
#else
|
||||
float preemphasized_left = apply_pre_emphasis(&preemp_l, l_in)*2;
|
||||
float preemphasized_right = apply_pre_emphasis(&preemp_r, r_in)*2;
|
||||
float current_left_input = hard_clip(preemphasized_left);
|
||||
float current_right_input = hard_clip(preemphasized_right);
|
||||
#endif
|
||||
#else
|
||||
#ifdef LPF
|
||||
float lowpassed_left = apply_low_pass_filter(&lpf_l, l_in);
|
||||
float lowpassed_right = apply_low_pass_filter(&lpf_r, r_in);
|
||||
float current_left_input = hard_clip(lowpassed_left);
|
||||
float current_right_input = hard_clip(lowpassed_right);
|
||||
#else
|
||||
float current_left_input = hard_clip(l_in);
|
||||
float current_right_input = hard_clip(r_in);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
float mono = (current_left_input + current_right_input) / 2.0f; // Stereo to Mono
|
||||
float stereo = (current_left_input - current_right_input) / 2.0f; // Also Stereo to Mono but a bit diffrent
|
||||
|
||||
float stereo_carrier = get_oscillator_sin_sample(&stereo_osc);
|
||||
// -14 db is somewhere around 20% of a 1 volt signal
|
||||
|
||||
mpx[i] = mono * MONO_VOLUME +
|
||||
((stereo+0.2) * stereo_carrier)*STEREO_VOLUME; // the 0.2 add DC, you know what happens then? Carrier wave
|
||||
}
|
||||
|
||||
#ifndef ALSA_OUTPUT
|
||||
if (pa_simple_write(output_device, mpx, sizeof(mpx), &pulse_error) < 0) {
|
||||
fprintf(stderr, "Error writing to output device: %s\n", pa_strerror(pulse_error));
|
||||
to_run = 0;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
snd_pcm_writei(output_handle, mpx, sizeof(mpx));
|
||||
#endif
|
||||
}
|
||||
printf("Cleaning up...\n");
|
||||
pa_simple_free(input_device);
|
||||
#ifndef ALSA_OUTPUT
|
||||
pa_simple_free(output_device);
|
||||
#else
|
||||
snd_pcm_drain(output_handle);
|
||||
snd_pcm_close(output_handle);
|
||||
snd_pcm_hw_params_free(&output_params);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -10,20 +10,16 @@
|
||||
|
||||
#define DEFAULT_STEREO 1
|
||||
#define DEFAULT_STEREO_POLAR 0
|
||||
#define DEFAULT_STEREO_SSB 0
|
||||
#define DEFAULT_CLIPPER_THRESHOLD 1.0f
|
||||
#define DEFAULT_ALSA_OUTPUT 0
|
||||
|
||||
//#define SSB
|
||||
#ifdef SSB
|
||||
//#define USB
|
||||
#endif
|
||||
|
||||
#include "../lib/constants.h"
|
||||
#include "../lib/oscillator.h"
|
||||
#include "../lib/filters.h"
|
||||
#ifdef SSB
|
||||
#include "../lib/hilbert.h"
|
||||
#endif
|
||||
|
||||
#define SAMPLE_RATE 192000 // Don't go lower than 108 KHz, becuase it (53000*2) and (38000+15000)
|
||||
|
||||
@@ -90,6 +86,10 @@ void show_help(char *name) {
|
||||
" -o,--output Override output device\n"
|
||||
" -M,--mpx Override MPX input device\n"
|
||||
" -c,--clipper Override the clipper threshold\n"
|
||||
" -P,--polar Force Polar Stereo (does not take effect with -m)\n"
|
||||
" -g,--ge Force Zenith/GE stereo (does not take effect with -m, default)\n"
|
||||
" -S,--ssb Force SSB\n"
|
||||
" -D,--dsb Force DSB\n"
|
||||
,name
|
||||
);
|
||||
}
|
||||
@@ -97,6 +97,8 @@ void show_help(char *name) {
|
||||
int main(int argc, char **argv) {
|
||||
show_version();
|
||||
int stereo = DEFAULT_STEREO;
|
||||
int polar_stereo = DEFAULT_STEREO_POLAR;
|
||||
int ssb = DEFAULT_STEREO_SSB;
|
||||
float clipper_threshold = DEFAULT_CLIPPER_THRESHOLD;
|
||||
#ifndef MPX_DEVICE
|
||||
char audio_mpx_device[64] = "\0";
|
||||
@@ -112,17 +114,21 @@ int main(int argc, char **argv) {
|
||||
int alsa_output = DEFAULT_ALSA_OUTPUT;
|
||||
|
||||
int opt;
|
||||
const char *short_opt = "msi:o:apM:c:hv";
|
||||
const char *short_opt = "msi:o:apM:c:PgSDhv";
|
||||
struct option long_opt[] =
|
||||
{
|
||||
{"mono", no_argument, NULL, 'm'},
|
||||
{"stereo", no_argument, NULL, 's'},
|
||||
{"input", optional_argument, NULL, 'i'},
|
||||
{"output", optional_argument, NULL, 'o'},
|
||||
{"alsa_out", optional_argument, NULL, 'a'},
|
||||
{"pulse_put", optional_argument, NULL, 'p'},
|
||||
{"alsa_out", no_argument, NULL, 'a'},
|
||||
{"pulse_put", no_argument, NULL, 'p'},
|
||||
{"mpx", optional_argument, NULL, 'M'},
|
||||
{"clipper", optional_argument, NULL, 'c'},
|
||||
{"polar", no_argument, NULL, 'P'},
|
||||
{"ge", no_argument, NULL, 'g'},
|
||||
{"ssb", no_argument, NULL, 'S'},
|
||||
{"dsb", no_argument, NULL, 'D'},
|
||||
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
@@ -160,6 +166,22 @@ int main(int argc, char **argv) {
|
||||
clipper_threshold = strtof(optarg, NULL);
|
||||
printf("Running with a clipper threshold of %f\n", clipper_threshold);
|
||||
break;
|
||||
case 'P': //Polar
|
||||
polar_stereo = 1;
|
||||
printf("Using polar stereo\n");
|
||||
break;
|
||||
case 'g': //GE
|
||||
polar_stereo = 0;
|
||||
printf("Using Zenith/GE stereo\n");
|
||||
break;
|
||||
case 'S': //SSB
|
||||
ssb = 1;
|
||||
printf("Using SSB\n");
|
||||
break;
|
||||
case 'D': //DSB
|
||||
ssb = 0;
|
||||
printf("Using DSB\n");
|
||||
break;
|
||||
case 'v': // Version
|
||||
show_version();
|
||||
return 0;
|
||||
@@ -278,14 +300,15 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
Oscillator pilot_osc;
|
||||
init_oscillator(&pilot_osc, 19000.0, SAMPLE_RATE); // Pilot, it's there to indicate stereo and as a refrence signal with the stereo carrier
|
||||
|
||||
#ifdef SSB
|
||||
if(polar_stereo == 1) {
|
||||
init_oscillator(&pilot_osc, 31250.0, SAMPLE_RATE); // Pilot, it's there to indicate stereo and as a refrence signal with the stereo carrier
|
||||
} else {
|
||||
init_oscillator(&pilot_osc, 19000.0, SAMPLE_RATE); // Pilot, it's there to indicate stereo and as a refrence signal with the stereo carrier
|
||||
}
|
||||
HilbertTransformer hilbert; // An Hilbert shifts a signal in quadrature, generating the I/Q data
|
||||
init_hilbert(&hilbert);
|
||||
DelayLine monoDelay; // Hilbert introduces a delay of 99 samples, this should be here to sync the mono with stereo to a sample
|
||||
init_delay_line(&monoDelay, 99);
|
||||
#endif
|
||||
#ifdef PREEMPHASIS
|
||||
ResistorCapacitor preemp_l, preemp_r;
|
||||
init_rc_tau(&preemp_l, PREEMPHASIS_TAU, SAMPLE_RATE);
|
||||
@@ -354,29 +377,54 @@ int main(int argc, char **argv) {
|
||||
float mono = (current_left_input + current_right_input) / 2.0f; // Stereo to Mono
|
||||
if(stereo == 1) {
|
||||
float stereo = (current_left_input - current_right_input) / 2.0f; // Also Stereo to Mono but a bit diffrent
|
||||
float stereo_carrier = get_oscillator_sin_multiplier_ni(&pilot_osc, 2); // Get stereo carrier via multiplication
|
||||
#ifdef SSB
|
||||
float stereo_carrier_cos = get_oscillator_cos_multiplier_ni(&pilot_osc, 2) // Get Carrier Q of I/Q
|
||||
float pilot = get_oscillator_sin_sample(&pilot_osc);
|
||||
if(polar_stereo == 1) {
|
||||
if(ssb) {
|
||||
float stereo_carrier = get_oscillator_sin_multiplier_ni(&pilot_osc, 1); // Get stereo carrier via multiplication
|
||||
float stereo_carrier_cos = get_oscillator_cos_sample(&pilot_osc); // Get Carrier Q of I/Q
|
||||
|
||||
float stereo_i, stereo_q;
|
||||
apply_hilbert(&hilbert, stereo, &stereo_i, &stereo_q); // Compute I/Q
|
||||
#ifdef USB
|
||||
float signal = (stereo_i*cos38+stereo_q*(sin38*0.775f));
|
||||
#else
|
||||
float signal = (stereo_i*cos38-stereo_q*(sin38*0.775f));
|
||||
#endif
|
||||
output[i] = mono*MONO_VOLUME +
|
||||
pilot*PILOT_VOLUME +
|
||||
signal*STEREO_VOLUME
|
||||
;
|
||||
#else
|
||||
float pilot = get_oscillator_sin_sample(&pilot_osc);
|
||||
output[i] = mono*MONO_VOLUME +
|
||||
pilot*PILOT_VOLUME +
|
||||
(stereo*stereo_carrier)*STEREO_VOLUME;
|
||||
if(strlen(audio_mpx_device) != 0) output[i] += multiplex_in*MPX_VOLUME;
|
||||
#endif
|
||||
float stereo_i, stereo_q;
|
||||
stereo += 0.2;
|
||||
apply_hilbert(&hilbert, stereo, &stereo_i, &stereo_q); // Compute I/Q
|
||||
#ifdef USB
|
||||
float signal = (stereo_i*stereo_carrier_cos+stereo_q*(stereo_carrier*0.775f));
|
||||
#else
|
||||
float signal = (stereo_i*stereo_carrier_cos-stereo_q*(stereo_carrier*0.775f));
|
||||
#endif
|
||||
output[i] = delay_line(&monoDelay, mono)*MONO_VOLUME +
|
||||
signal*STEREO_VOLUME;
|
||||
if(strlen(audio_mpx_device) != 0) output[i] += multiplex_in*MPX_VOLUME;
|
||||
} else {
|
||||
float stereo_carrier = get_oscillator_sin_sample(&pilot_osc);
|
||||
output[i] = mono*MONO_VOLUME +
|
||||
((stereo+0.2)*stereo_carrier)*STEREO_VOLUME;
|
||||
if(strlen(audio_mpx_device) != 0) output[i] += multiplex_in*MPX_VOLUME;
|
||||
}
|
||||
} else {
|
||||
if(ssb) {
|
||||
float stereo_carrier = get_oscillator_sin_multiplier_ni(&pilot_osc, 2); // Get stereo carrier via multiplication
|
||||
float stereo_carrier_cos = get_oscillator_cos_multiplier_ni(&pilot_osc, 2); // Get Carrier Q of I/Q
|
||||
float pilot = get_oscillator_sin_sample(&pilot_osc);
|
||||
|
||||
float stereo_i, stereo_q;
|
||||
apply_hilbert(&hilbert, stereo, &stereo_i, &stereo_q); // Compute I/Q
|
||||
#ifdef USB
|
||||
float signal = (stereo_i*stereo_carrier_cos+stereo_q*(stereo_carrier*0.775f));
|
||||
#else
|
||||
float signal = (stereo_i*stereo_carrier_cos-stereo_q*(stereo_carrier*0.775f));
|
||||
#endif
|
||||
output[i] = delay_line(&monoDelay, mono)*MONO_VOLUME +
|
||||
pilot*PILOT_VOLUME +
|
||||
signal*STEREO_VOLUME;
|
||||
if(strlen(audio_mpx_device) != 0) output[i] += multiplex_in*MPX_VOLUME;
|
||||
} else {
|
||||
float stereo_carrier = get_oscillator_sin_multiplier_ni(&pilot_osc,2);
|
||||
float pilot = get_oscillator_sin_sample(&pilot_osc);
|
||||
output[i] = mono*MONO_VOLUME +
|
||||
pilot*PILOT_VOLUME +
|
||||
(stereo*stereo_carrier)*STEREO_VOLUME;
|
||||
if(strlen(audio_mpx_device) != 0) output[i] += multiplex_in*MPX_VOLUME;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
output[i] = mono*MONO_VOLUME; // Only Mono
|
||||
}
|
||||
@@ -402,9 +450,7 @@ int main(int argc, char **argv) {
|
||||
snd_pcm_close(output_handle);
|
||||
snd_pcm_hw_params_free(output_params);
|
||||
}
|
||||
#ifdef SSB
|
||||
exit_hilbert(&hilbert);
|
||||
exit_delay_line(&monoDelay);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user