diff --git a/examples/Example_Usage.md b/examples/Example_Usage.md index 88e6e3b..34723c9 100644 --- a/examples/Example_Usage.md +++ b/examples/Example_Usage.md @@ -78,7 +78,7 @@ Detailed Setup: ``` RTL-SDR options: - Usage: rtl:dev:freq:gain:ppm:bw:sq:udp + Usage: rtl:dev:freq:gain:ppm:bw:sq:vol NOTE: all arguments after rtl are optional now for trunking, but user configuration is recommended dev RTL-SDR Device Index Number freq RTL-SDR Frequency (851800000 or 851.8M) @@ -86,9 +86,9 @@ RTL-SDR options: ppm RTL-SDR PPM Error (default = 0) bw RTL-SDR Bandwidth kHz (default = 12)(8, 12, 16, 24) sq RTL-SDR Squelch Level vs RMS Value (Optional) - udp RTL-SDR Legacy UDP Remote Port (Optional -- External Use Only) - Example: dsd-fme-zdev -fs -i rtl -C cap_plus_channel.csv -T - Example: dsd-fme-zdev -fp -i rtl:0:851.375M:22:-2:24:0:6021 + vol RTL-SDR Sample 'Volume' Multiplier (default = 1)(1,2,3) + Example: dsd-fme -fs -i rtl -C cap_plus_channel.csv -T + Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:2 ``` diff --git a/include/dsd.h b/include/dsd.h index fb91c09..2464afc 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -86,6 +86,35 @@ extern volatile uint8_t exitflag; //fix for issue #136 +//new audio filter stuff from: https://github.com/NedSimao/FilteringLibrary +typedef struct { + float coef[2]; + float v_out[2]; +}LPFilter; + +typedef struct { + float coef; + float v_out[2]; + float v_in[2]; + +}HPFilter; + +typedef struct { + LPFilter lpf; + HPFilter hpf; + float out_in; +}PBFilter; + +typedef struct { + float alpha; + float beta; + + float vin[3]; + float vout[3]; + +}NOTCHFilter; +//end new filters + //group csv import struct typedef struct { @@ -231,6 +260,7 @@ typedef struct FILE *symbol_out_f; float audio_gain; float audio_gainR; + float audio_gainA; int audio_out; int dmr_stereo_wav; char wav_out_dir[512]; @@ -285,6 +315,7 @@ typedef struct int rtl_started; long int rtl_rms; int monitor_input_audio; + int analog_only; int pulse_raw_rate_in; int pulse_raw_rate_out; int pulse_digi_rate_in; @@ -405,6 +436,12 @@ typedef struct int slot1_on; int slot2_on; + //enable filter options + int use_lpf; + int use_hpf; + int use_pbf; + int use_hpf_d; + //'DSP' Format Output uint8_t use_dsp_output; char dsp_out_file[2048]; @@ -507,6 +544,7 @@ typedef struct char slot0light[8]; float aout_gain; float aout_gainR; + float aout_gainA; float aout_max_buf[200]; float aout_max_bufR[200]; float *aout_max_buf_p; @@ -630,6 +668,16 @@ typedef struct dPMRVoiceFS2Frame_t dPMRVoiceFS2Frame; + //new audio filter structs + LPFilter RCFilter; + HPFilter HRCFilter; + PBFilter PBF; + NOTCHFilter NF; + LPFilter RCFilterL; + HPFilter HRCFilterL; + LPFilter RCFilterR; + HPFilter HRCFilterR; + char dpmr_caller_id[20]; char dpmr_target_id[20]; @@ -953,7 +1001,11 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state); //float stere void playSynthesizedVoiceFS4 (dsd_opts * opts, dsd_state * state); //float stereo mix 4v2 P25p2 void playSynthesizedVoiceFM (dsd_opts * opts, dsd_state * state); //float mono void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot); //float gain control +void agsm (dsd_opts * opts, dsd_state * state, short * input, int len); //short gain control for analog things +void analog_gain (dsd_opts * opts, dsd_state * state, short * input, int len); //manual gain handling for analong things //new short stuff +void playSynthesizedVoiceMS (dsd_opts * opts, dsd_state * state); //short mono mix +void playSynthesizedVoiceMSR (dsd_opts * opts, dsd_state * state); //short mono mix R (needed for OSS 48k input/output) void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state); //short stereo mix void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state); //short stereo mix 3v2 DMR void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state); //short stereo mix 4v2 P25p2 @@ -1295,12 +1347,24 @@ void eot_cc(dsd_opts * opts, dsd_state * state); //end of TX return to CC //Generic Tuning Functions void return_to_cc (dsd_opts * opts, dsd_state * state); -//misc generic audio filtering for analog at 48k/1 +//misc audio filtering for analog long int raw_rms(short *samples, int len, int step); -void analog_deemph_filter(short * input, int len); -void analog_preemph_filter(short * input, int len); -void analog_dc_block_filter(short * input, int len); -void analog_clipping_filter(short * input, int len); +void init_audio_filters(dsd_state * state); +void lpf(dsd_state * state, short * input, int len); +void hpf(dsd_state * state, short * input, int len); +void pbf(dsd_state * state, short * input, int len); +void nf(dsd_state * state, short * input, int len); +void hpf_dL(dsd_state * state, short * input, int len); +void hpf_dR(dsd_state * state, short * input, int len); +//from: https://github.com/NedSimao/FilteringLibrary +void LPFilter_Init(LPFilter *filter, float cutoffFreqHz, float sampleTimeS); +float LPFilter_Update(LPFilter *filter, float v_in); +void HPFilter_Init(HPFilter *filter, float cutoffFreqHz, float sampleTimeS); +float HPFilter_Update(HPFilter *filter, float v_in); +void PBFilter_Init(PBFilter *filter, float HPF_cutoffFreqHz, float LPF_cutoffFreqHz, float sampleTimeS); +float PBFilter_Update(PBFilter *filter, float v_in); +void NOTCHFilter_Init(NOTCHFilter *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS); +float NOTCHFilter_Update(NOTCHFilter *filter, float vin); //csv imports int csvGroupImport(dsd_opts * opts, dsd_state * state); diff --git a/src/3.c b/src/3.c index c2adde2..e104993 100644 --- a/src/3.c +++ b/src/3.c @@ -321,4 +321,274 @@ uint16_t q_abs_diff(const uint16_t v1, const uint16_t v2) // // Wojciech Kaczmarski, SP5WWP // M17 Project, 29 December 2023 -//-------------------------------------------------------------------- \ No newline at end of file +//-------------------------------------------------------------------- + + +//audio filter stuff sourced from: https://github.com/NedSimao/FilteringLibrary +//no license / information provided in source code +#define PI 3.141592653 + +//do we need this for test input sthit? +// #define PLOT_POINTS 100 +// #define SAMPLE_TIME_S 0.001 +// #define CUTOFFFREQ_HZ 50 +// #define sine_freq 40 +// #define sine_freq_1 500 +// #define HFC 50 +// #define LFC 100 + + +void LPFilter_Init(LPFilter *filter, float cutoffFreqHz, float sampleTimeS) +{ + + float RC=0.0; + RC=1.0/(2*PI*cutoffFreqHz); + filter->coef[0]=sampleTimeS/(sampleTimeS+RC); + filter->coef[1]=RC/(sampleTimeS+RC); + + filter->v_out[0]=0.0; + filter->v_out[1]=0.0; + +} + + +float LPFilter_Update(LPFilter *filter, float v_in) +{ + + filter->v_out[1]=filter->v_out[0]; + filter->v_out[0]=(filter->coef[0]*v_in) + (filter->coef[1]*filter->v_out[1]); + + return (filter->v_out[0]); + +} + + +/******************************************************************************************************** + * HIGH PASS FILTER +********************************************************************************************************/ +void HPFilter_Init(HPFilter *filter, float cutoffFreqHz, float sampleTimeS) +{ + + float RC=0.0; + RC=1.0/(2*PI*cutoffFreqHz); + + filter->coef=RC/(sampleTimeS+RC); + + filter->v_in[0]=0.0; + filter->v_in[1]=0.0; + + filter->v_out[0]=0.0; + filter->v_out[1]=0.0; + +} + + +float HPFilter_Update(HPFilter *filter, float v_in) +{ + + filter->v_in[1]=filter->v_in[0]; + filter->v_in[0]=v_in; + + filter->v_out[1]=filter->v_out[0]; + filter->v_out[0]=filter->coef * (filter->v_in[0] - filter->v_in[1]+filter->v_out[1]); + + return (filter->v_out[0]); + +} + +/******************************************************************************************************** + * BAND PASS FILTER +********************************************************************************************************/ + + +void PBFilter_Init(PBFilter *filter, float HPF_cutoffFreqHz, float LPF_cutoffFreqHz, float sampleTimeS) +{ + + LPFilter_Init(&filter->lpf, LPF_cutoffFreqHz, sampleTimeS); + HPFilter_Init(&filter->hpf, HPF_cutoffFreqHz, sampleTimeS); + + filter->out_in=0.0; + +} + +float PBFilter_Update(PBFilter *filter, float v_in) +{ + + filter->out_in=HPFilter_Update(&filter->hpf, v_in); + + filter->out_in=LPFilter_Update(&filter->lpf, filter->out_in); + + return (filter->out_in); + +} + +/******************************************************************************************************** + * NOTCH FILTER +********************************************************************************************************/ + + +void NOTCHFilter_Init(NOTCHFilter *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS) +{ + + //filter frequency to angular (rad/s) + float w0_rps=2.0 * PI *centerFreqHz; + float ww_rps=2.0 * PI *notchWidthHz; + + //pre warp center frequency + float w0_pw_rps=(2.0/sampleTimeS) * tanf(0.5 * w0_rps * sampleTimeS); + + //computing filter coefficients + + filter->alpha=4.0 + w0_rps*w0_pw_rps*sampleTimeS*sampleTimeS; + filter->beta=2.0*ww_rps*sampleTimeS; + + //clearing input and output buffers + + for (uint8_t n=0; n<3; n++) + { + filter->vin[n]=0; + filter->vout[n]=0; + } + +} + +float NOTCHFilter_Update(NOTCHFilter *filter, float vin) +{ + + //shifting samples + filter->vin[2]=filter->vin[1]; + filter->vin[1]=filter->vin[0]; + + filter->vout[2]=filter->vout[1]; + filter->vout[1]=filter->vout[0]; + + filter->vin[0]=vin; + + //compute new output + filter->vout[0]=(filter->alpha*filter->vin[0] + 2.0 *(filter->alpha -8.0)*filter->vin[1] + filter->alpha*filter->vin[2] + -(2.0f*(filter->alpha-8.0)*filter->vout[1]+(filter->alpha-filter->beta)*filter->vout[2]))/(filter->alpha+filter->beta); + + + return (filter->vout[0]); +} + +void init_audio_filters (dsd_state * state) +{ + //still not sure if this is even correct or not, but 48k sounds good now + LPFilter_Init(&state->RCFilter, 960, (float)1/(float)48000); + HPFilter_Init(&state->HRCFilter, 960, (float)1/(float)48000); + + //left and right variants for stereo output testing on digital voice samples + LPFilter_Init(&state->RCFilterL, 960, (float)1/(float)16000); + HPFilter_Init(&state->HRCFilterL, 960, (float)1/(float)16000); + LPFilter_Init(&state->RCFilterR, 960, (float)1/(float)16000); + HPFilter_Init(&state->HRCFilterR, 960, (float)1/(float)16000); + + //PBFilter_Init(PBFilter *filter, float HPF_cutoffFreqHz, float LPF_cutoffFreqHz, float sampleTimeS); + //NOTCHFilter_Init(NOTCHFilter *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS); + + //NOTE: PBFilter_init also inits a LPF and HPF, but on another set of filters, might be worth + //testing just using the PBFilter by itself and see how it does without the hpf used + + //passband filter working (seems to be), notch filter unsure which values to use, doesn't have any appreciable affect when used as is + PBFilter_Init(&state->PBF, 8000, 12000, (float)1/(float)1536000); //RTL Sampling at 1536000 S/s. + NOTCHFilter_Init(&state->NF, 1000, 4000, (float)1/(float)1536000); + +} + +//FUNCTIONS for handing use of above filters + +//lpf +void lpf(dsd_state * state, short * input, int len) +{ + int i; + for (i = 0; i < len; i++) + { + // fprintf (stderr, "\n in: %05d", input[i]); + input[i] = LPFilter_Update(&state->RCFilter, input[i]); + // fprintf (stderr, "\n out: %05d", input[i]); + } +} + +//hpf +void hpf(dsd_state * state, short * input, int len) +{ + int i; + for (i = 0; i < len; i++) + { + // fprintf (stderr, "\n in: %05d", input[i]); + input[i] = HPFilter_Update(&state->HRCFilter, input[i]); + // fprintf (stderr, "\n out: %05d", input[i]); + } +} + +//hpf digital left +void hpf_dL(dsd_state * state, short * input, int len) +{ + int i; + for (i = 0; i < len; i++) + { + // fprintf (stderr, "\n in: %05d", input[i]); + input[i] = HPFilter_Update(&state->HRCFilterL, input[i]); + // fprintf (stderr, "\n out: %05d", input[i]); + } +} + +//hpf digital right +void hpf_dR(dsd_state * state, short * input, int len) +{ + int i; + for (i = 0; i < len; i++) + { + // fprintf (stderr, "\n in: %05d", input[i]); + input[i] = HPFilter_Update(&state->HRCFilterR, input[i]); + // fprintf (stderr, "\n out: %05d", input[i]); + } +} + +//nf +void nf(dsd_state * state, short * input, int len) +{ + int i; + for (i = 0; i < len; i++) + { + // fprintf (stderr, "\n in: %05d", input[i]); + input[i] = NOTCHFilter_Update(&state->NF, input[i]); + // fprintf (stderr, "\n out: %05d", input[i]); + } +} + +//pbf +void pbf(dsd_state * state, short * input, int len) +{ + int i; + for (i = 0; i < len; i++) + { + // fprintf (stderr, "\n in: %05d", input[i]); + input[i] = PBFilter_Update(&state->PBF, input[i]); + } +} + +//Generic RMS function derived from RTL_FM (RTL_SDR) RMS code (doesnt' really work correctly outside of RTL) +long int raw_rms(int16_t *samples, int len, int step) //use samplespersymbol as len +{ + + int i; + long int rms; + long p, t, s; + double dc, err; + + p = t = 0L; + for (i=0; ifloating_point == 0) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 1) playSynthesizedVoiceFM(opts, state); } diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c index e149850..a9b5c1a 100644 --- a/src/dsd_audio2.c +++ b/src/dsd_audio2.c @@ -12,6 +12,9 @@ #include "dsd.h" #include +//NOTE: Tones produce ringing sound when put through the hpf_d, may want to look into tweaking it, +//or looking for a way to store is_tone by glancing at ambe_d values and not running hpf_d on them + //TODO: WAV File saving (works fine on shorts, but on float, writing short to wav is not auto-gained, //so super quiet, either convert to float wav files, or run processAudio AFTER memcpy of the temp_buf) @@ -721,6 +724,128 @@ void playSynthesizedVoiceFM (dsd_opts * opts, dsd_state * state) } +//Mono - Short (SB16LE) - Drop-in replacement for playSyntesizedVoice, but easier to manipulate +void playSynthesizedVoiceMS (dsd_opts * opts, dsd_state * state) +{ + int i; + size_t len = state->audio_out_idx; + + //debug + // fprintf (stderr, " L LEN: %d", len); + + short mono_samp[len]; + memset (mono_samp, 0, len*sizeof(short)); + + if (opts->slot1_on == 0) + goto MS_END; + + if (len == 160) + { + for (i = 0; i < len; i++) + mono_samp[i] = state->s_l[i]; + } + else if (len == 960) + { + state->audio_out_buf_p -= 960; //rewind first + for (i = 0; i < len; i++) + { + mono_samp[i] = *state->audio_out_buf_p; + state->audio_out_buf_p++; + } + } + + if (opts->use_hpf_d == 1) + hpf_dL(state, state->s_l, len); + + if (opts->audio_out_type == 0) //Pulse Audio + pa_simple_write(opts->pulse_digi_dev_out, mono_samp, len*2, NULL); + + if (opts->audio_out_type == 8) //UDP Audio + udp_socket_blaster (opts, state, len*2, mono_samp); + + if (opts->audio_out_type == 1 || opts->audio_out_type == 2 || opts->audio_out_type == 5) //STDOUT or OSS + write (opts->audio_out_fd, mono_samp, len*2); + + MS_END: + + //run cleanup since we pulled stuff from processAudio + state->audio_out_idx = 0; + + //set short temp buffer to baseline + memset (state->s_l, 0, sizeof(state->s_l)); + + if (state->audio_out_idx2 >= 800000) + { + state->audio_out_float_buf_p = state->audio_out_float_buf + 100; + state->audio_out_buf_p = state->audio_out_buf + 100; + memset (state->audio_out_float_buf, 0, 100 * sizeof (float)); + memset (state->audio_out_buf, 0, 100 * sizeof (short)); + state->audio_out_idx2 = 0; + } + +} + +//Mono - Short (SB16LE) - Drop-in replacement for playSyntesizedVoiceR, but easier to manipulate +void playSynthesizedVoiceMSR (dsd_opts * opts, dsd_state * state) +{ + int i; + size_t len = state->audio_out_idxR; + + //debug + // fprintf (stderr, " R LEN: %d", len); + + short mono_samp[len]; + memset (mono_samp, 0, len*sizeof(short)); + + if (opts->slot2_on == 0) + goto MS_ENDR; + + if (len == 160) + { + for (i = 0; i < len; i++) + mono_samp[i] = state->s_r[i]; + } + else if (len == 960) + { + state->audio_out_buf_pR -= 960; //rewind first + for (i = 0; i < len; i++) + { + mono_samp[i] = *state->audio_out_buf_pR; + state->audio_out_buf_pR++; + } + } + + if (opts->use_hpf_d == 1) + hpf_dR(state, mono_samp, len); + + if (opts->audio_out_type == 0) //Pulse Audio + pa_simple_write(opts->pulse_digi_dev_out, mono_samp, len*2, NULL); + + if (opts->audio_out_type == 8) //UDP Audio + udp_socket_blaster (opts, state, len*2, mono_samp); + + if (opts->audio_out_type == 1 || opts->audio_out_type == 2 || opts->audio_out_type == 5) //STDOUT or OSS + write (opts->audio_out_fd, mono_samp, len*2); + + MS_ENDR: + + //run cleanup since we pulled stuff from processAudioR + state->audio_out_idxR = 0; + + //set short temp buffer to baseline + memset (state->s_r, 0, sizeof(state->s_r)); + + if (state->audio_out_idx2R >= 800000) + { + state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100; + state->audio_out_buf_pR = state->audio_out_bufR + 100; + memset (state->audio_out_float_bufR, 0, 100 * sizeof (float)); + memset (state->audio_out_bufR, 0, 100 * sizeof (short)); + state->audio_out_idx2R = 0; + } + +} + //Stereo Mix - Short (SB16LE) -- When Playing Short FDMA samples when setup for stereo output void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state) { @@ -728,7 +853,7 @@ void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state) int i; int encL; short stereo_samp1[320]; //8k 2-channel stereo interleave mix - memset (stereo_samp1, 1, sizeof(stereo_samp1)); + memset (stereo_samp1, 0, sizeof(stereo_samp1)); //enc checkdown for whether or not to fill the stereo sample or not for playback or writing encL = 0; @@ -785,6 +910,10 @@ void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state) //likewise, override and unmute if TG hold matches TG if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0; + //test hpf + if (opts->use_hpf_d == 1) + hpf_dL(state, state->s_l, 160); + //interleave left and right channels from the short storage area for (i = 0; i < 160; i++) { @@ -951,6 +1080,18 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state) if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0; if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0; + //test hpf + if (opts->use_hpf_d == 1) + { + hpf_dL(state, state->s_l4[0], 160); + hpf_dL(state, state->s_l4[1], 160); + hpf_dL(state, state->s_l4[2], 160); + + hpf_dR(state, state->s_r4[0], 160); + hpf_dR(state, state->s_r4[1], 160); + hpf_dR(state, state->s_r4[2], 160); + } + //interleave left and right channels from the short storage area for (i = 0; i < 160; i++) { @@ -1045,7 +1186,7 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state) short stereo_samp2[320]; //8k 2-channel stereo interleave mix short stereo_samp3[320]; //8k 2-channel stereo interleave mix short stereo_samp4[320]; - + short empss[160]; //this is used to see if we want to run HPF on an empty set short empty[320]; //this is used to see if we want to play a single 2v or double 2v or not memset (stereo_samp1, 0, sizeof(stereo_samp1)); @@ -1054,7 +1195,7 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state) memset (stereo_samp4, 0, sizeof(stereo_samp4)); memset (empty, 0, sizeof(empty)); - + memset (empss, 0, sizeof(empss)); //p25p2 enc checkdown for whether or not to fill the stereo sample or not for playback or writing encL = encR = 1; @@ -1137,6 +1278,24 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state) if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0; if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0; + //test hpf + if (opts->use_hpf_d == 1) + { + hpf_dL(state, state->s_l4[0], 160); + hpf_dL(state, state->s_l4[1], 160); + if (memcmp(empss, state->s_l4[2], sizeof(empss)) != 0) + hpf_dL(state, state->s_l4[2], 160); + if (memcmp(empss, state->s_l4[3], sizeof(empss)) != 0) + hpf_dL(state, state->s_l4[3], 160); + + hpf_dR(state, state->s_r4[0], 160); + hpf_dR(state, state->s_r4[1], 160); + if (memcmp(empss, state->s_r4[2], sizeof(empss)) != 0) + hpf_dR(state, state->s_r4[2], 160); + if (memcmp(empss, state->s_r4[3], sizeof(empss)) != 0) + hpf_dR(state, state->s_r4[3], 160); + } + //interleave left and right channels from the short storage area for (i = 0; i < 160; i++) { @@ -1349,64 +1508,75 @@ void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot) } -//the previous version, not quite as good at audio gain normalization, but keeping it just in case -// void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot) -// { -// int i, run; -// run = 1; -// float empty[160]; -// memset (empty, 0.0f, sizeof(empty)); +//automatic gain short mono for analog audio and some digital mono (WIP) +void agsm (dsd_opts * opts, dsd_state * state, short * input, int len) +{ + int i; -// float mmax = 0.75f; -// float mmin = -0.75f; -// float aavg = 0.0f; //average of the absolute value -// float df; //decimation value -// df = 8000.0f; //test value -- this would be the ideal perfect value if everybody spoke directly into the mic at a reasonable volume + UNUSED(opts); -// if (slot == 0) -// df = (384.0f / (float)opts->pulse_digi_out_channels) * (50.0f - state->aout_gain); -// if (slot == 1) -// df = (384.0f / (float)opts->pulse_digi_out_channels) * (50.0f - state->aout_gainR); + //NOTE: This seems to be doing better now that I got it worked out properly + //This may produce a mild buzz sound though on the low end -// //this comparison is to determine whether or not to run gain on 'empty' samples (2v last 2, silent frames, etc) -// if (memcmp(empty, samp, sizeof(empty)) == 0) run = 0; -// if (run == 0) goto AGF_END; + float avg = 0.0f; //average of 20 samples + float coeff = 0.0f; //gain coeffiecient + float max = 0.0f; //the highest sample value + float nom = 4800.0f; //nominator value for 48k + float samp[960]; memset (samp, 0.0f, 960*sizeof(float)); -// for (i = 0; i < 160; i++) -// { + //assign internal float from short input + for (i = 0; i < len; i++) + samp[i] = (float)input[i]; -// samp[i] = samp[i] / df; + for (i = 0; i < len; i++) + { + if ( fabsf (samp[i]) > max) + { + max = fabsf (samp[i]); + } + } -// aavg += fabsf(samp[i]); + for (i = 0; i < len; i++) + avg += (float)samp[i]; -// //simple clipping -// if (samp[i] > mmax) -// samp[i] = mmax; -// if (samp[i] < mmin) -// samp[i] = mmin; - -// //may have been a tad too loud on the high end -// // samp[i] *= 0.5f; //testing various values here - -// } - -// aavg /= 160.0f; - -// if (slot == 0) -// { -// if (aavg < 0.075f && state->aout_gain < 42.0f) state->aout_gain += 1.0f; -// if (aavg >= 0.075f && state->aout_gain > 1.0f) state->aout_gain -= 1.0f; -// } - -// if (slot == 1) -// { -// if (aavg < 0.075f && state->aout_gainR < 42.0f) state->aout_gainR += 1.0f; -// if (aavg >= 0.075f && state->aout_gainR > 1.0f) state->aout_gainR -= 1.0f; -// } - -// //debug -// // fprintf (stderr, "\nS%d - DF = %f AAVG = %f", slot, df, aavg); + avg /= (float)len; -// AGF_END: ; //do nothing + coeff = fabsf (nom / max); -// } \ No newline at end of file + //keep coefficient with tolerable range when silence to prevent crackle/buzz + if (coeff > 3.0f) coeff = 3.0f; + + //apply the coefficient to bring the max value to our desired maximum value + for (i = 0; i < 20; i++) + samp[i] *= coeff; + + //debug + // fprintf (stderr, "\n M: %f; C: %f; A: %f; ", max, coeff, avg); + + // debug + // for (i = 0; i < len; i++) + // { + // fprintf (stderr, " in: %d", input[i]); + // fprintf (stderr, " out: %f", samp[i]); + // } + + //return new smaple values post agc + for (i = 0; i < len; i++) + input[i] = (short)samp[i]; + + state->aout_gainA = coeff; //store for internal use + +} + +//until analog agc is fixed, going to use a manual gain control on this +void analog_gain (dsd_opts * opts, dsd_state * state, short * input, int len) +{ + + int i; + UNUSED(state); + + float gain = (opts->audio_gainA / 100.0f) * 5.0f; //scale 0x - 5x + + for (i = 0; i < len; i++) + input[i] *= gain; +} \ No newline at end of file diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c index 4a64b7b..e10f3cc 100644 --- a/src/dsd_frame_sync.c +++ b/src/dsd_frame_sync.c @@ -195,7 +195,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) int lmin, lmax, lidx; //assign t_max value based on decoding type expected (all non-auto decodes first) - int t_max; //maximum values allowed for t will depend on decoding type - NXDN will be 10, others will be more + int t_max = 24; //initialize as an actual value to prevent any overflow related issues if (opts->frame_nxdn48 == 1 || opts->frame_nxdn96 == 1) { t_max = 10; @@ -218,6 +218,10 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { t_max = 19; //Phase 2 S-ISCH is only 19 } + else if (opts->analog_only == 1) //shim to make sure this is set to a reasonable value + { + t_max = 24; + } else t_max = 24; //24 for everything else int lbuf[48], lbuf2[48]; //if we use t_max in these arrays, and t >= t_max in condition below, then it can overflow those checks in there if t exceeds t_max diff --git a/src/dsd_main.c b/src/dsd_main.c index 300f342..e800a5b 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -583,6 +583,7 @@ initOpts (dsd_opts * opts) opts->mbe_out_fR = NULL; //second slot on a TDMA system opts->audio_gain = 0; opts->audio_gainR = 0; + opts->audio_gainA = 50.0f; //scale of 1 - 100 opts->audio_out = 1; opts->wav_out_file[0] = 0; opts->wav_out_fileR[0] = 0; @@ -691,6 +692,7 @@ initOpts (dsd_opts * opts) opts->dmr_mute_encR = 1; opts->monitor_input_audio = 0; //enable with -8 + opts->analog_only = 0; //only turned on with -fA opts->inverted_p2 = 0; opts->p2counter = 0; @@ -766,6 +768,12 @@ initOpts (dsd_opts * opts) opts->slot1_on = 1; opts->slot2_on = 1; + //enable filter options + opts->use_lpf = 0; + opts->use_hpf = 1; + opts->use_pbf = 1; + opts->use_hpf_d = 1; + //dsp structured file opts->dsp_out_file[0] = 0; opts->use_dsp_output = 0; @@ -899,6 +907,7 @@ initState (dsd_state * state) sprintf (state->slot2light, "%s", ""); state->aout_gain = 25.0f; state->aout_gainR = 25.0f; + state->aout_gainA = 0.0f; //use purely as a display or internal value, no user setting memset (state->aout_max_buf, 0, sizeof (float) * 200); state->aout_max_buf_p = state->aout_max_buf; state->aout_max_buf_idx = 0; @@ -1236,7 +1245,7 @@ usage () printf (" /dev/dsp for OSS audio (Depreciated: Will require padsp wrapper in Linux) \n"); #endif printf (" rtl for rtl dongle (Default Values -- see below)\n"); - printf (" rtl:dev:freq:gain:ppm:bw:sq:udp for rtl dongle (see below)\n"); + printf (" rtl:dev:freq:gain:ppm:bw:sq:vol for rtl dongle (see below)\n"); printf (" tcp for tcp client SDR++/GNURadio Companion/Other (Port 7355)\n"); printf (" tcp:192.168.7.5:7355 for custom address and port \n"); printf (" filename.bin for OP25/FME capture bin files\n"); @@ -1283,12 +1292,12 @@ usage () // #ifdef AERO_BUILD printf (" If using /dev/dsp input and output at 48k1, launch two instances of DSD-FME w -V 1 and -V 2 if needed"); // #endif - printf (" (Audio Smoothing is now disabled on all upsampled output by default -- fix crackle/buzz bug)\n"); + // printf (" (Audio Smoothing is now disabled on all upsampled output by default -- fix crackle/buzz bug)\n"); printf (" -z Set TDMA Voice Slot Preference when using /dev/dsp audio output (prevent lag and stuttering)\n"); printf (" -y Enable Experimental Pulse Audio Float Audio Output\n"); printf ("\n"); printf ("RTL-SDR options:\n"); - printf (" Usage: rtl:dev:freq:gain:ppm:bw:sq:udp\n"); + printf (" Usage: rtl:dev:freq:gain:ppm:bw:sq:vol\n"); printf (" NOTE: all arguments after rtl are optional now for trunking, but user configuration is recommended\n"); printf (" dev RTL-SDR Device Index Number or 8 Digit Serial Number, no strings! (default 0)\n"); printf (" freq RTL-SDR Frequency (851800000 or 851.8M) \n"); @@ -1296,9 +1305,10 @@ usage () printf (" ppm RTL-SDR PPM Error (default = 0)\n"); printf (" bw RTL-SDR Bandwidth kHz (default = 12)(4, 6, 8, 12, 16, 24) \n"); printf (" sq RTL-SDR Squelch Level vs RMS Value (Optional)\n"); - printf (" udp RTL-SDR Legacy UDP Remote Port (Optional -- External Use Only)\n"); + // printf (" udp RTL-SDR Legacy UDP Remote Port (Optional -- External Use Only)\n"); //NOTE: This is still available as an option in the ncurses menu + printf (" vol RTL-SDR Sample 'Volume' Multiplier (default = 1)(1,2,3)\n"); printf (" Example: dsd-fme -fs -i rtl -C cap_plus_channel.csv -T\n"); - printf (" Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:6021\n"); + printf (" Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:2\n"); printf ("\n"); printf ("Encoder options:\n"); printf (" -fZ M17 Stream Voice Encoder\n"); @@ -1640,7 +1650,7 @@ main (int argc, char **argv) initOpts (&opts); initState (&state); - + init_audio_filters(&state); //audio filters InitAllFecFunction(); // CNXDNConvolution_init(); //seems to function better without initting it @@ -2027,6 +2037,7 @@ main (int argc, char **argv) case 'g': sscanf (optarg, "%f", &opts.audio_gain); + opts.audio_gainA = opts.audio_gain; //straight assignment if (opts.audio_gain < (float) 0 ) { fprintf (stderr,"Disabling audio out gain setting\n"); @@ -2108,6 +2119,7 @@ main (int argc, char **argv) opts.dmr_mono = 0; state.rf_mod = 0; opts.monitor_input_audio = 1; + opts.analog_only = 1; sprintf (opts.output_name, "Analog Monitor"); fprintf (stderr,"Only Monitoring Passive Analog Signal\n"); } @@ -2178,14 +2190,13 @@ main (int argc, char **argv) opts.dmr_stereo = 0; opts.dmr_mono = 0; state.dmr_stereo = 0; - // opts.setmod_bw = 12500; + // opts.setmod_bw = 16000; sprintf (opts.output_name, "EDACS/PV"); fprintf (stderr,"Setting symbol rate to 9600 / second\n"); fprintf (stderr,"Decoding only ProVoice frames.\n"); fprintf (stderr,"EDACS Analog Voice Channels are Experimental.\n"); - //rtl specific tweaks + //misc tweaks opts.rtl_bandwidth = 24; - // opts.rtl_gain_value = 36; } else if (optarg[0] == 'h') //standard / net w/o ESK { @@ -2611,6 +2622,10 @@ main (int argc, char **argv) opts.m17encoder = 1; opts.pulse_digi_rate_out = 48000; opts.pulse_digi_out_channels = 1; + //filters disabled by default, use ncurses VBN switches + opts.use_lpf = 0; + opts.use_hpf = 0; + opts.use_pbf = 0; sprintf (opts.output_name, "M17 Encoder"); } else if (optarg[0] == 'B') //Captial B to Run the M17 BRT encoder @@ -2901,8 +2916,12 @@ main (int argc, char **argv) if (curr != NULL) opts.rtl_squelch_level = atoi (curr); else goto RTLEND; - curr = strtok(NULL, ":"); //rtl udp port "-U" - if (curr != NULL) opts.rtl_udp_port = atoi (curr); + // curr = strtok(NULL, ":"); //rtl udp port "-U" + // if (curr != NULL) opts.rtl_udp_port = atoi (curr); + // else goto RTLEND; + + curr = strtok(NULL, ":"); //rtl sample / volume multiplier + if (curr != NULL) opts.rtl_volume_multiplier = atoi (curr); else goto RTLEND; RTLEND: @@ -2934,15 +2953,19 @@ main (int argc, char **argv) } + if (opts.rtl_volume_multiplier > 3 || opts.rtl_volume_multiplier < 0) + opts.rtl_volume_multiplier = 1; //I wonder if you could flip polarity by using -1 + fprintf (stderr, "Dev %d ", opts.rtl_dev_index); fprintf (stderr, "Freq %d ", opts.rtlsdr_center_freq); fprintf (stderr, "Gain %d ", opts.rtl_gain_value); fprintf (stderr, "PPM %d ", opts.rtlsdr_ppm_error); fprintf (stderr, "BW %d ", opts.rtl_bandwidth); fprintf (stderr, "SQ %d ", opts.rtl_squelch_level); - fprintf (stderr, "UDP %d \n", opts.rtl_udp_port); + // fprintf (stderr, "UDP %d \n", opts.rtl_udp_port); + fprintf (stderr, "VOL %d \n", opts.rtl_volume_multiplier); opts.audio_in_type = 3; - state.audio_smoothing = 0; //disable smoothing to prevent random crackling/buzzing + // opts.rtl_volume_multiplier = 2; //TODO: Make this an extra value on the end rtl_ok = 1; #endif diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index d1d58e9..07075c8 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -134,7 +134,7 @@ void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv) if (opts->audio_out == 1 && opts->floating_point == 0) { - playSynthesizedVoice (opts, state); + playSynthesizedVoiceMS (opts, state); } if (opts->floating_point == 1) { @@ -174,7 +174,7 @@ void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv) if (opts->audio_out == 1 && opts->floating_point == 0) { - playSynthesizedVoice (opts, state); + playSynthesizedVoiceMS (opts, state); } if (opts->floating_point == 1) { @@ -1084,7 +1084,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } if (opts->audio_out == 1 && opts->floating_point == 0 && opts->audio_out_type == 5 && opts->slot1_on == 1) //for OSS 48k 1 channel configs -- relocate later if possible { - playSynthesizedVoice (opts, state); //it may be more beneficial to move this to each individual decoding type to handle, but ultimately, let's just simpifly mbe handling instead + playSynthesizedVoiceMS (opts, state); //it may be more beneficial to move this to each individual decoding type to handle, but ultimately, let's just simpifly mbe handling instead } } @@ -1161,7 +1161,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } if (opts->audio_out == 1 && opts->floating_point == 0 && opts->audio_out_type == 5 && opts->slot2_on == 1) //for OSS 48k 1 channel configs -- relocate later if possible { - playSynthesizedVoiceR (opts, state); + playSynthesizedVoiceMSR (opts, state); } } diff --git a/src/dsd_mbe2.c b/src/dsd_mbe2.c index 76dc0fe..55dcebb 100644 --- a/src/dsd_mbe2.c +++ b/src/dsd_mbe2.c @@ -115,7 +115,7 @@ void soft_mbe (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char amb PrintAMBEData (opts, state, ambe_d); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) playSynthesizedVoiceFM(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) @@ -138,7 +138,7 @@ void soft_mbe (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char amb PrintAMBEData (opts, state, ambe_d); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) playSynthesizedVoiceFM(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index a91dd1c..9d43a7d 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -728,6 +728,17 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) wscanw(entry_win, "%d", &opts->rtl_udp_port); noecho(); + entry_win = newwin(6, WIDTH+18, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " RTL Vol Multiplier (1,2,3) (Default = 1): "); + mvwprintw(entry_win, 3, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%d", &opts->rtl_volume_multiplier); + if (opts->rtl_volume_multiplier > 3 || opts->rtl_volume_multiplier < 0) + opts->rtl_volume_multiplier = 1; + noecho(); + entry_win = newwin(8, WIDTH+22, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " RTL RMS Squelch Level (NXDN/dPMR/Analog/Raw only): "); @@ -766,19 +777,20 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state) } - entry_win = newwin(17, WIDTH+20, starty+10, startx+10); + entry_win = newwin(18, WIDTH+20, starty+10, startx+10); box (entry_win, 0, 0); mvwprintw(entry_win, 2, 2, " Starting RTL Input. Cannot Release/Stop Until Exit."); mvwprintw(entry_win, 4, 2, " RTL Frequency: %d Hz", opts->rtlsdr_center_freq); mvwprintw(entry_win, 5, 2, " RTL Device Index Number: %d; SN:%s", opts->rtl_dev_index, serial); mvwprintw(entry_win, 6, 2, " RTL Device Bandwidth: %d kHz", opts->rtl_bandwidth); mvwprintw(entry_win, 7, 2, " RTL Device Gain: %d", opts->rtl_gain_value); - mvwprintw(entry_win, 8, 2, " RTL Device UDP Port: %d", opts->rtl_udp_port); - mvwprintw(entry_win, 9, 2, " RTL Device PPM: %d", opts->rtlsdr_ppm_error); - mvwprintw(entry_win, 10, 2, " RTL RMS Squelch: %d", opts->rtl_squelch_level); - mvwprintw(entry_win, 12, 2, " Are You Sure?"); - mvwprintw(entry_win, 13, 2, " 1 = Yes, 2 = No "); - mvwprintw(entry_win, 14, 3, " "); + mvwprintw(entry_win, 8, 2, " RTL Volume Multiplier: %d", opts->rtl_volume_multiplier); + mvwprintw(entry_win, 9, 2, " RTL Device UDP Port: %d", opts->rtl_udp_port); + mvwprintw(entry_win, 10, 2, " RTL Device PPM: %d", opts->rtlsdr_ppm_error); + mvwprintw(entry_win, 11, 2, " RTL RMS Squelch: %d", opts->rtl_squelch_level); + mvwprintw(entry_win, 13, 2, " Are You Sure?"); + mvwprintw(entry_win, 14, 2, " 1 = Yes, 2 = No "); + mvwprintw(entry_win, 15, 3, " "); echo(); refresh(); wscanw(entry_win, "%d", &confirm); @@ -2344,7 +2356,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) printw ("--Input Output----------------------------------------------------------------\n"); if (opts->audio_in_type == 0) { - printw ("| Pulse Audio Input: %i kHz; %i Channel; ", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels); + printw ("| Pulse Signal Input: %i kHz; %i Ch; ", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels); if (opts->use_rigctl == 1) printw ("RIG: %s:%d; ", opts->tcp_hostname, opts->rigctlportno); printw ("\n"); @@ -2352,7 +2364,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (opts->audio_in_type == 5) { - printw ("| OSS Audio Input: %i kHz; 1 Channel;", SAMPLE_RATE_IN/1000); + printw ("| OSS Signal Input: %i kHz; 1 Ch;", SAMPLE_RATE_IN/1000); if (opts->use_rigctl == 1) printw ("RIG: %s:%d; ", opts->tcp_hostname, opts->rigctlportno); printw ("\n"); @@ -2365,7 +2377,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (opts->audio_in_type == 8) { - printw ("| TCP Audio Input: %s:%d; %d kHz 1 Channel; ", opts->tcp_hostname, opts->tcp_portno, opts->wav_sample_rate/1000); + printw ("| TCP Signal Input: %s:%d; %d kHz; 1 Ch; ", opts->tcp_hostname, opts->tcp_portno, opts->wav_sample_rate/1000); if (opts->use_rigctl == 1) printw ("RIG: %s:%d; ", opts->tcp_hostname, opts->rigctlportno); printw ("\n"); @@ -2386,13 +2398,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) { printw ("| RTL: %d;", opts->rtl_dev_index); if (opts->rtl_gain_value == 0) - printw (" Gain: AGC;"); + printw (" G: AGC;"); else - printw (" Gain: %idB;", opts->rtl_gain_value); + printw (" G: %idB;", opts->rtl_gain_value); + printw (" V: %iX;", opts->rtl_volume_multiplier); printw (" PPM: %i;", opts->rtlsdr_ppm_error); printw (" SQ: %i;", opts->rtl_squelch_level); printw (" RMS: %04li;", opts->rtl_rms); - printw (" BW: %i kHz;", opts->rtl_bandwidth); + printw (" BW: %i;", opts->rtl_bandwidth); printw (" FRQ: %i;", opts->rtlsdr_center_freq); if (opts->rtl_udp_port != 0) printw ("\n| External RTL Tuning on UDP Port: %i", opts->rtl_udp_port); printw ("\n"); @@ -2400,11 +2413,12 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (opts->audio_out_type == 0) { - printw ("| Pulse Audio Output: %i kHz; %i Ch; G: %02.0f%%", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2); + printw ("| Pulse Digital Output: %i kHz; %i Ch; G: %02.0f%%", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2); if (opts->pulse_digi_out_channels == 2) printw (" G: %02.0f%%", state->aout_gainR*2); if (opts->floating_point == 1) printw (" FLOAT: %02.0f%%;", opts->audio_gain*2); - if (opts->audio_gain == 0) printw (" (+/-) Auto"); - if (opts->audio_gain > 0) printw (" (+/-) Manual"); + if (opts->audio_gain == 0) printw (" (+|-) Auto"); + if (opts->audio_gain > 0) printw (" (+|-) Manual"); + if (opts->use_hpf_d == 1) printw (" HPF"); if (opts->call_alert == 1) printw (" *CA!"); //Call Alert // if (state->audio_smoothing == 1 && opts->floating_point == 0) printw (" Smoothing On;"); //only on short printw (" \n"); @@ -2412,7 +2426,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if ( opts->audio_out_type == 0 && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) ) { - printw ("| Pulse Audio Output: %i kHz; %i Ch; Analog Monitor RMS: %04ld ", opts->pulse_raw_rate_out/1000, opts->pulse_raw_out_channels, opts->rtl_rms); + printw ("| Pulse Analog Output: %i kHz; %i Ch; G: %02.0f%% (/|*) ", opts->pulse_raw_rate_out/1000, opts->pulse_raw_out_channels, opts->audio_gainA); + if (opts->audio_gainA == 0.0f) printw ("Auto "); + else printw ("Manual "); + if (opts->audio_in_type != 3) printw ("RMS: %04ld; ", opts->rtl_rms); + if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |"); + if (opts->use_hpf == 1) printw ("HP|"); else printw (" |"); + if (opts->use_pbf == 1) printw ("PB|"); else printw (" |"); printw (" \n"); } @@ -2422,6 +2442,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (opts->pulse_digi_out_channels == 2) printw (" G: %02.0f%%", state->aout_gainR*2); if (opts->audio_gain == 0) printw (" (+/-) Auto"); if (opts->audio_gain > 0) printw (" (+/-) Manual"); + if (opts->use_hpf_d == 1) printw (" HPF"); if (opts->call_alert == 1) printw (" *CA!"); //Call Alert // if (state->audio_smoothing == 1 && opts->floating_point == 0) printw (" Smoothing On;"); //only on short if ( (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1) && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) ) @@ -2431,17 +2452,22 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (opts->audio_out_type == 8) { - printw ("| UDP Audio Output: %s:%d; %d kHz %d Ch; %02.0f%%", opts->udp_hostname, opts->udp_portno, opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2); + printw ("| UDP Digital Output: %s:%d; %d kHz %d Ch; %02.0f%%", opts->udp_hostname, opts->udp_portno, opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2); if (opts->pulse_digi_out_channels == 2) printw (" G: %02.0f%%", state->aout_gainR*2); if (opts->audio_gain == 0) printw (" (+/-) Auto"); if (opts->audio_gain > 0) printw (" (+/-) Manual"); + if (opts->use_hpf_d == 1) printw (" HPF"); if (opts->call_alert == 1) printw (" *CA!"); //Call Alert if ( (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1) && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) ) printw (" - Monitor RMS: %04ld ", opts->rtl_rms); printw (" \n"); if (opts->udp_sockfdA != 0) //Analog Output on udp port +2 { - printw ("| UDP Audio Output: %s:%d; 48 kHz 1 Ch; Analog Output; ", opts->udp_hostname, opts->udp_portno+2); + printw ("| UDP Analog Output: %s:%d; 48 kHz 1 Ch; ", opts->udp_hostname, opts->udp_portno+2); + if (opts->audio_in_type != 3) printw ("RMS: %04ld; ", opts->rtl_rms); + if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |"); + if (opts->use_hpf == 1) printw ("HP|"); else printw (" |"); + if (opts->use_pbf == 1) printw ("PB|"); else printw (" |"); printw (" \n"); } } @@ -2621,7 +2647,15 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (opts->mod_gfsk == 1) printw ("[GFSK]"); printw ( "[%d] \n", (48000*opts->wav_interpolator)/state->samplesPerSymbol); if (opts->m17encoder == 1) printw ("| Encoding: [%s] ", opts->output_name); - if (opts->m17encoder == 1) printw ("(\\) \n"); + if (opts->m17encoder == 1) printw (" Toggle (\\); "); + if (opts->m17encoder == 1) printw (" Mic Gain (/|*): %02.0f%% ", opts->audio_gainA); + if (opts->m17encoder == 1) + { + if (opts->use_lpf == 1) printw ("F: |LP|"); else printw ("F: | |"); + if (opts->use_hpf == 1) printw ("HP|"); else printw (" |"); + if (opts->use_pbf == 1) printw ("PB|"); else printw (" |"); + printw ("\n"); + } printw ("| Decoding: [%s] ", opts->output_name); if (opts->aggressive_framesync == 0) printw ("CRC/(RAS) "); //debug -- troubleshoot voice tuning after grant on DMR CC, subsequent grant may not tune because tuner isn't available @@ -3920,6 +3954,18 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } + if (c == 42) // * key, increment audio_gainA + { + if (opts->audio_gainA < 100) + opts->audio_gainA++; + } + + if (c == 47) // / key, decrement audio_gainA + { + if (opts->audio_gainA > 0) + opts->audio_gainA--; + } + if (c == 122) //'z' key, toggle payload to console { if (opts->payload == 1) opts->payload = 0; @@ -4544,6 +4590,30 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } + if (c == 86) // 'V' Key, toggle LPF + { + if (opts->use_lpf == 0) opts->use_lpf = 1; + else opts->use_lpf = 0; + } + + if (c == 66) // 'B' Key, toggle HPF + { + if (opts->use_hpf == 0) opts->use_hpf = 1; + else opts->use_hpf = 0; + } + + if (c == 78) // 'N' Key, toggle PBF + { + if (opts->use_pbf == 0) opts->use_pbf = 1; + else opts->use_pbf = 0; + } + + if (c == 72) // 'H' Key, toggle HPF on digital + { + if (opts->use_hpf_d == 0) opts->use_hpf_d = 1; + else opts->use_hpf_d = 0; + } + if (opts->m17encoder == 1 && c == 92) //'\' key - toggle M17 encoder Encode + TX { if (state->m17encoder_tx == 0) state->m17encoder_tx = 1; diff --git a/src/dsd_symbol.c b/src/dsd_symbol.c index 32c9e63..46b4e9b 100644 --- a/src/dsd_symbol.c +++ b/src/dsd_symbol.c @@ -17,29 +17,6 @@ #include "dsd.h" -long int raw_rms(int16_t *samples, int len, int step) //use samplespersymbol as len -{ - - int i; - long int rms; - long p, t, s; - double dc, err; - - p = t = 0L; - for (i=0; iwav_out_raw); } - //test running analog audio through a de-emphasis filter - analog_deemph_filter(state->analog_out, 960); - //and dc_block filter analog_dc_block_filter - analog_dc_block_filter(state->analog_out, 960); - //test running analog audio through a pre-emphasis filter - analog_preemph_filter(state->analog_out, 960); - //test running analog short sample clipping filter - analog_clipping_filter(state->analog_out, 960); + //low pass filter + if (opts->use_lpf == 1) + lpf(state, state->analog_out, 960); + + //high pass filter + if (opts->use_hpf == 1) + hpf (state, state->analog_out, 960); + + //pass band filter + if (opts->use_pbf == 1) + pbf(state, state->analog_out, 960); + + //manual gain control + if (opts->audio_gainA > 0.0f) + analog_gain (opts, state, state->analog_out, 960); + + //automatic gain control + else + agsm(opts, state, state->analog_out, 960); + + //Running RMS after filtering does remove the analog spike from the RMS value + //but noise floor noise will still produce higher values + // if (opts->audio_in_type != 3 && opts->monitor_input_audio == 1) + // opts->rtl_rms = raw_rms(state->analog_out, 960, 1); //seems to be working now, but RMS values are lower on actual analog signal than on no signal but noise if ( (opts->rtl_rms > opts->rtl_squelch_level) && opts->monitor_input_audio == 1 && state->carrier == 0 ) //added carrier check here in lieu of disabling it above diff --git a/src/edacs-fme.c b/src/edacs-fme.c index e84c5dd..71a6256 100644 --- a/src/edacs-fme.c +++ b/src/edacs-fme.c @@ -85,124 +85,21 @@ void openWavOutFile48k (dsd_opts * opts, dsd_state * state) } } -//generic rms type function -long int gen_rms(short *samples, int len, int step) -{ - - int i; - long int rms; - long p, t, s; - double dc, err; - - p = t = 0L; - for (i=0; i 32760) - input[i] = 32760; - else if (input[i] < -32760) - input[i] = -32760; - } -} - -//modified from version found in rtl_fm -static short avg = 0; -void analog_deemph_filter(short * input, int len) -{ - // static short avg; // cheating... - int i, d; - - // int a = (int)round(1.0/((1.0-exp(-1.0/(96000 * 75e-6))))); //48000 is rate out, but doubling it sounds 'beefier' - int a = 8; //result of calc above is 8, so save a cycle on the low end CPUs - - // de-emph IIR - // avg = avg * (1 - alpha) + sample * alpha; - - for (i = 0; i < len; i++) - { - d = input[i] - avg; - if (d > 0) - avg += (d + a/2) / a; - else - avg += (d - a/2) / a; - - input[i] = (short)avg; - } -} - -//modified from version found in rtl_fm -static int dc_avg = 0; -void analog_dc_block_filter(short * input, int len) -{ - int i, avg; - int64_t sum = 0; - for (i=0; i < len; i++) - sum += input[i]; - - avg = sum / len; - avg = (avg + dc_avg * 9) / 10; - for (i=0; i < len; i++) - input[i] -= (short)avg; - - dc_avg = avg; -} - //listening to and playing back analog audio void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn) { - //reset static states for new channel - pstate = 1; - avg = 0; - dc_avg = 0; - int i, result; int count = 5; //RMS has a 5 count (5 * 180ms) now before cutting off; short analog1[960]; short analog2[960]; short analog3[960]; - short sample = 0; + short sample = 0; + + #define DEBUG_ANALOG //enable to digitize analog if 'data' bursts heard + + uint8_t d1[192]; + uint8_t d2[192]; + uint8_t d3[192]; state->last_cc_sync_time = time(NULL); state->last_vc_sync_time = time(NULL); @@ -211,6 +108,10 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn memset (analog2, 0, sizeof(analog2)); memset (analog3, 0, sizeof(analog3)); + memset (d1, 0, sizeof(d1)); + memset (d2, 0, sizeof(d2)); + memset (d3, 0, sizeof(d3)); + long int rms = opts->rtl_squelch_level + 1; //one more for the initial loop phase long int sql = opts->rtl_squelch_level; @@ -239,7 +140,7 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn analog3[i] = sample; } //this rms will only work properly (for now) with squelch enabled in SDR++ or other - rms = gen_rms(analog3, 960, 1); + rms = raw_rms(analog3, 960, 1); } //NOTE: The core dumps observed previously were due to SDR++ Remote Server connection dropping due to Internet/Other issues @@ -250,6 +151,10 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn //not be a sample to read in and it hangs on sf_short read until it crashes out, the fix below will prevent issues //when SDR++ is closed locally, or the TCP connection closes suddenly. + //NOTE: Observed two segfaults on EDACS STM analog when doing radio tests or otherwise holding the radio + //open for extremely long periods of time, could be an issue in digitize where dibit_buf_p is not + //reset for an extended period of time and overflows, may need to reset buffer occassionally here + //TCP Input w/ Simple TCP Error Detection Implemented to prevent hard crash if TCP drops off if (opts->audio_in_type == 8) { @@ -293,7 +198,7 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn } //this rms will only work properly (for now) with squelch enabled in SDR++ - rms = gen_rms(analog3, 960, 1); + rms = raw_rms(analog3, 960, 1); } //RTL Input @@ -330,22 +235,71 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn sr += digitize (opts, state, (int)analog1[i]); } - //test running analog audio through a de-emphasis filter - analog_deemph_filter(analog1, 960); - analog_deemph_filter(analog2, 960); - analog_deemph_filter(analog3, 960); - //and dc_block filter analog_dc_block_filter - analog_dc_block_filter(analog1, 960); - analog_dc_block_filter(analog2, 960); - analog_dc_block_filter(analog3, 960); - //test running analog audio through a pre-emphasis filter - analog_preemph_filter(analog1, 960); - analog_preemph_filter(analog2, 960); - analog_preemph_filter(analog3, 960); - //test running analog short sample clipping filter - analog_clipping_filter(analog1, 960); - analog_clipping_filter(analog2, 960); - analog_clipping_filter(analog3, 960); + #ifdef DEBUG_ANALOG + //save digitized samples to array for looking into those 'data' sounding bursts, + //this format assumes the same sample per symbol rateused in EDACS/PV + for (i = 0; i < 192; i++) //Samples Per Symbol is 5, so incrememnt every 5 + { + d1[i] = digitize (opts, state, (int)analog1[i*5]); + d2[i] = digitize (opts, state, (int)analog2[i*5]); + d3[i] = digitize (opts, state, (int)analog3[i*5]); + } + #endif + + //Bugfix for buffer overflow from using digitize function, reset buffers + if (state->dibit_buf_p > state->dibit_buf + 900000) + state->dibit_buf_p = state->dibit_buf + 200; + + //dmr buffer + if (state->dmr_payload_p > state->dmr_payload_buf + 900000) + state->dmr_payload_p = state->dmr_payload_buf + 200; + + // low pass filter + if (opts->use_lpf == 1) + { + lpf (state, analog1, 960); + lpf (state, analog2, 960); + lpf (state, analog3, 960); + } + + //high pass filter + if (opts->use_hpf == 1) + { + hpf (state, analog1, 960); + hpf (state, analog2, 960); + hpf (state, analog3, 960); + } + + //pass band filter + if (opts->use_pbf == 1) + { + pbf (state, analog1, 960); + pbf (state, analog2, 960); + pbf (state, analog3, 960); + } + + //manual gain control + if (opts->audio_gainA > 0.0f) + { + analog_gain (opts, state, analog1, 960); + analog_gain (opts, state, analog2, 960); + analog_gain (opts, state, analog3, 960); + } + + //automatic gain control + else + { + agsm (opts, state, analog1, 960); + agsm (opts, state, analog2, 960); + agsm (opts, state, analog3, 960); + } + + //NOTE: Ideally, we would run raw_rms for TCP/VS here, but the analog spike on EDACS (STM) + //system gets filtered out, and when they hold the radio open and don't talk, + //it counts against the squelch hit as no audio, so we will just have to use + //the squelch checkbox in SDR++ and similar when using those input methods + // if (opts->audio_in_type != 3) + // rms = raw_rms(analog3, 960, 1); //reconfigured to use seperate audio out stream that is always 48k short if (opts->audio_out_type == 0 && opts->slot1_on == 1) @@ -426,6 +380,30 @@ void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn fprintf (stderr, "%s", KNRM); + #ifdef PRETTY_COLORS + {} //do nothing + #else + fprintf (stderr, "SQL HIT: %d; ", 5-cnt); //add cnt since user can't see red or green + #endif + + #ifdef DEBUG_ANALOG + //debug digitized version of analog out when data bursts may be present + //NOTE: Without a 'framesync' these could be shifted into odd positions + if (opts->payload == 1) + { + fprintf (stderr, "\n A_DUMP: "); + for (i = 0; i < 24; i++) + fprintf (stderr, "%02X", (uint8_t)ConvertBitIntoBytes(&d1[i*8], 8)); + fprintf (stderr, "\n "); + for (i = 0; i < 24; i++) + fprintf (stderr, "%02X", (uint8_t)ConvertBitIntoBytes(&d2[i*8], 8)); + fprintf (stderr, "\n "); + for (i = 0; i < 24; i++) + fprintf (stderr, "%02X", (uint8_t)ConvertBitIntoBytes(&d3[i*8], 8)); + // fprintf (stderr, "\n"); + } + #endif + if (count > 0) fprintf (stderr, "\n"); } diff --git a/src/m17.c b/src/m17.c index f470cc0..415afd5 100644 --- a/src/m17.c +++ b/src/m17.c @@ -359,6 +359,10 @@ void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t * payload codec2_decode(state->codec2_1600, samp1, voice1); + //hpf_d on codec2 sounds better than not on those .rrc samples + if (opts->use_hpf_d == 1) + hpf_dL(state, samp1, nsam); + if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio { pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL); @@ -459,6 +463,13 @@ void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t * payload codec2_decode(state->codec2_3200, samp1, voice1); codec2_decode(state->codec2_3200, samp2, voice2); + //hpf_d on codec2 sounds better than not on those .rrc samples + if (opts->use_hpf_d == 1) + { + hpf_dL(state, samp1, nsam); + hpf_dL(state, samp2, nsam); + } + if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio { pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL); @@ -1840,18 +1851,51 @@ void encodeM17STR(dsd_opts * opts, dsd_state * state) #endif } - //read in RMS value for vox function; NOTE: may not work correctly on STDIN and TCP due to blocking when no samples to read + //read in RMS value for vox function; NOTE: will not work correctly SOCAT STDIO TCP due to blocking when no samples to read if (opts->audio_in_type == 3) opts->rtl_rms = rtl_return_rms(); else opts->rtl_rms = raw_rms(voice1, nsam, 1) / 2; //dividing by two so mic isn't so sensitive on vox - //decimate audio input (default 100% on mic is WAY TOO LOUD for the encoder, fine tune in volume control) - for (i = 0; i < 160; i++) + //low pass filter + if (opts->use_lpf == 1) { - //NOTE: Use + and - in ncurses to fine tune manually - voice1[i] *= (float)state->aout_gain/ (float)25.0f; - voice2[i] *= (float)state->aout_gain/ (float)25.0f; + lpf (state, voice1, 160); + lpf (state, voice2, 160); } + //high pass filter + if (opts->use_hpf == 1) + { + hpf (state, voice1, 160); + hpf (state, voice2, 160); + } + + //passband filter + if (opts->use_pbf == 1) + { + pbf (state, voice1, 160); + pbf (state, voice2, 160); + } + + //manual gain control + if (opts->audio_gainA > 0.0f) + { + analog_gain (opts, state, voice1, 160); + analog_gain (opts, state, voice2, 160); + } + + //automatic gain control + else + { + agsm (opts, state, voice1, 160); + agsm (opts, state, voice2, 160); + } + + //NOTE: Similar to EDACS analog, if calculating raw rms here after filtering, + //anytime the walkie-talkie is held open but no voice, the center spike is removed, + //and counts against the squelch hits making vox mode inconsistent + // if (opts->audio_in_type != 3) + // opts->rtl_rms = raw_rms(voice1, 160, 1); + //convert out audio input into CODEC2 (3200bps) 8 byte data stream uint8_t vc1_bytes[8]; memset (vc1_bytes, 0, sizeof(vc1_bytes)); uint8_t vc2_bytes[8]; memset (vc2_bytes, 0, sizeof(vc2_bytes)); diff --git a/src/nxdn_voice.c b/src/nxdn_voice.c index 927ff65..326151f 100644 --- a/src/nxdn_voice.c +++ b/src/nxdn_voice.c @@ -93,7 +93,7 @@ void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182 memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); if (opts->floating_point == 0 ) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 1) playSynthesizedVoiceFM(opts, state); } diff --git a/src/p25p1_ldu1.c b/src/p25p1_ldu1.c index 7c784ed..2950a71 100644 --- a/src/p25p1_ldu1.c +++ b/src/p25p1_ldu1.c @@ -60,7 +60,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -74,7 +74,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -95,7 +95,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -116,7 +116,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -137,7 +137,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -158,7 +158,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -179,7 +179,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -200,7 +200,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -261,7 +261,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) diff --git a/src/p25p1_ldu2.c b/src/p25p1_ldu2.c index dec7113..54cd32e 100644 --- a/src/p25p1_ldu2.c +++ b/src/p25p1_ldu2.c @@ -65,7 +65,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -79,7 +79,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -100,7 +100,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -121,7 +121,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -142,7 +142,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -163,7 +163,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -184,7 +184,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) playSynthesizedVoiceFM(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) @@ -203,7 +203,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) @@ -264,7 +264,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state) #endif process_IMBE (opts, state, &status_count); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1) diff --git a/src/provoice.c b/src/provoice.c index c16166d..9809e91 100644 --- a/src/provoice.c +++ b/src/provoice.c @@ -221,12 +221,12 @@ void processProVoice (dsd_opts * opts, dsd_state * state) processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1); if (opts->floating_point == 0) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 1) playSynthesizedVoiceFM(opts, state); processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2); if (opts->floating_point == 0) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 1) playSynthesizedVoiceFM(opts, state); @@ -399,12 +399,12 @@ void processProVoice (dsd_opts * opts, dsd_state * state) processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1); if (opts->floating_point == 0) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 1) playSynthesizedVoiceFM(opts, state); processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2); if (opts->floating_point == 0) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if (opts->floating_point == 1) playSynthesizedVoiceFM(opts, state); diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp index e571503..2762d47 100644 --- a/src/rtl_sdr_fm.cpp +++ b/src/rtl_sdr_fm.cpp @@ -815,6 +815,34 @@ void dongle_init(struct dongle_state *s) s->demod_target = &demod; } +void demod_init_analog(struct demod_state *s) +{ + s->rate_in = rtl_bandwidth; + s->rate_out = rtl_bandwidth; + s->squelch_level = 0; + s->conseq_squelch = 10; + s->terminate_on_squelch = 0; + s->squelch_hits = 11; + s->downsample_passes = 1; // + s->comp_fir_size = 0; + s->prev_index = 0; + s->post_downsample = 1; //1 -- once this works, default = 4 -- doesn't work on the official rtl-sdr source code either + s->custom_atan = 0; + s->deemph = 1; // + s->rate_out2 = rtl_bandwidth; // -1 flag for disabled -- this enables low_pass_real, seems to work okay + s->mode_demod = &fm_demod; + s->pre_j = s->pre_r = s->now_r = s->now_j = 0; + s->prev_lpr_index = 0; + s->deemph_a = 0; // + s->now_lpr = 0; + s->dc_block = 1; // + s->dc_avg = 0; + pthread_rwlock_init(&s->rw, NULL); + pthread_cond_init(&s->ready, NULL); + pthread_mutex_init(&s->ready_m, NULL); + s->output_target = &output; +} + void demod_init_ro2(struct demod_state *s) { s->rate_in = rtl_bandwidth; @@ -1005,6 +1033,8 @@ void open_rtlsdr_stream(dsd_opts *opts) //init with low pass if decoding P25 or EDACS/Provoice if (opts->frame_p25p1 == 1 || opts->frame_p25p2 == 1 || opts->frame_provoice == 1) demod_init_ro2(&demod); + else if (opts->analog_only == 1 || opts->m17encoder == 1) + demod_init_analog(&demod); else demod_init(&demod); output_init(&output); controller_init(&controller); diff --git a/src/ysf.c b/src/ysf.c index a94bbd3..8ed1910 100644 --- a/src/ysf.c +++ b/src/ysf.c @@ -737,7 +737,7 @@ void ysf_ehr (dsd_opts * opts, dsd_state * state, uint8_t dbuf[180], int start, writeSynthesizedVoice (opts, state); if (opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if(opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); @@ -1027,7 +1027,7 @@ void processYSF(dsd_opts * opts, dsd_state * state) if (opts->wav_out_f != NULL) writeSynthesizedVoice (opts, state); if (opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if(opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state); @@ -1147,7 +1147,7 @@ void processYSF(dsd_opts * opts, dsd_state * state) writeSynthesizedVoice (opts, state); if (opts->pulse_digi_out_channels == 1) - playSynthesizedVoice(opts, state); + playSynthesizedVoiceMS(opts, state); if(opts->pulse_digi_out_channels == 2) playSynthesizedVoiceSS(opts, state);