From 16959cac7a17a48f5139fab4c1fa580d52b3f643 Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Mon, 24 Jul 2023 18:32:09 -0400 Subject: [PATCH] WIP: audio_work 2; --- include/dsd.h | 48 +- src/dmr_bs.c | 107 +++- src/dmr_ms.c | 90 ++- src/dsd_audio.c | 46 +- src/dsd_audio2.c | 1450 +++++++++++++++++++++++++++++++++++++++++++ src/dsd_main.c | 256 +++++--- src/dsd_mbe.c | 130 ++-- src/dsd_ncurses.c | 63 +- src/dsd_rigctl.c | 42 +- src/dsd_upsample2.c | 259 ++++++++ src/m17.c | 304 +++++++-- src/nxdn_voice.c | 7 + src/p25p1_ldu1.c | 78 +++ src/p25p1_ldu2.c | 77 +++ src/p25p2_frame.c | 137 +++- src/ysf.c | 81 ++- 16 files changed, 2902 insertions(+), 273 deletions(-) create mode 100644 src/dsd_audio2.c create mode 100644 src/dsd_upsample2.c diff --git a/include/dsd.h b/include/dsd.h index 186802e..2e9f9f3 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -65,7 +65,7 @@ #include //PULSE AUDIO #define SAMPLE_RATE_IN 48000 //48000 -#define SAMPLE_RATE_OUT 48000 //8000, +#define SAMPLE_RATE_OUT 8000 //8000 #ifdef USE_RTLSDR #include @@ -399,6 +399,9 @@ typedef struct //Use P25p1 heuristics uint8_t use_heuristics; + //Use floating point audio output + int floating_point; + } dsd_opts; typedef struct @@ -420,6 +423,22 @@ typedef struct float *audio_out_temp_buf_p; float audio_out_temp_bufR[160]; float *audio_out_temp_buf_pR; + //new stereo float sample storage + float f_l[160]; //single sample left + float f_r[160]; //single sample right + float f_l4[4][160]; //quad sample for up to a P25p2 4V + float f_r4[4][160]; //quad sample for up to a P25p2 4V + //new stereo short sample storage + short s_l[160]; //single sample left + short s_r[160]; //single sample right + short s_l4[4][160]; //quad sample for up to a P25p2 4V + short s_r4[4][160]; //quad sample for up to a P25p2 4V + //new stereo short sample storage tapped from 48_k internal upsampling + short s_lu[160*6]; //single sample left + short s_ru[160*6]; //single sample right + short s_l4u[4][160*6]; //quad sample for up to a P25p2 4V + short s_r4u[4][160*6]; //quad sample for up to a P25p2 4V + //end int audio_out_idx; int audio_out_idx2; int audio_out_idxR; @@ -872,8 +891,31 @@ void closePulseInput (dsd_opts * opts); void closePulseOutput (dsd_opts * opts); void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state); void writeSynthesizedVoiceR (dsd_opts * opts, dsd_state * state); -void playSynthesizedVoice (dsd_opts * opts, dsd_state * state); -void playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state); +void playSynthesizedVoice (dsd_opts * opts, dsd_state * state); //short mono output +void playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state); //short mono output rigth (obsolete)? +//new float stuff +void playSynthesizedVoiceFS (dsd_opts * opts, dsd_state * state); //float stereo mix +void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state); //float stereo mix 3v2 DMR...and X2-TDMA +void playSynthesizedVoiceFS4 (dsd_opts * opts, dsd_state * state); //float stereo mix 4v2 P25p2 +// void playSynthesizedVoiceFL (dsd_opts * opts, dsd_state * state); //float left when using stereo configuration +void playSynthesizedVoiceFM (dsd_opts * opts, dsd_state * state); //float mono + +void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state); //short stereo mix +void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state); //short stereo mix 3v2 DMR...and X2-TDMA +void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state); //short stereo mix 4v2 P25p2 + +void upsampleF (float invalue, float prev, float outbuf[6]); +void playSynthesizedVoiceFS3_48k (dsd_opts * opts, dsd_state * state); +void playSynthesizedVoiceFS4_48k (dsd_opts * opts, dsd_state * state); + +void upsampleS (short invalue, short prev, short outbuf[6]); +void playSynthesizedVoiceSS3_48k (dsd_opts * opts, dsd_state * state); +void playSynthesizedVoiceSS4_48k (dsd_opts * opts, dsd_state * state); + +//borrowed from CODEC2 for testing +void fdmdv_8_to_48_float(float out48k[], float in8k[], int n); + +// void openAudioOutDevice (dsd_opts * opts, int speed); void openAudioInDevice (dsd_opts * opts); diff --git a/src/dmr_bs.c b/src/dmr_bs.c index 1cfd94d..32e049c 100644 --- a/src/dmr_bs.c +++ b/src/dmr_bs.c @@ -373,8 +373,51 @@ void dmrBS (dsd_opts * opts, dsd_state * state) memcpy (m3, ambe_fr3, sizeof(m3)); processMbeFrame (opts, state, NULL, ambe_fr, NULL); + if(internalslot == 0) + { + memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu)); + } + + else + { + memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR)); + memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru)); + } + + processMbeFrame (opts, state, NULL, ambe_fr2, NULL); - processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + if(internalslot == 0) + { + memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu)); + } + + else + { + memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR)); + memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru)); + } + + processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + if(internalslot == 0) + { + memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu)); + } + + else + { + memcpy(state->f_r4[2], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR)); + memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru)); + } + //run sbrc here to look for the late entry key and alg after we observe potential errors in VC6 if (internalslot == 0 && vc1 == 6) dmr_sbrc (opts, state, power); @@ -437,6 +480,18 @@ void dmrBS (dsd_opts * opts, dsd_state * state) } SKIP: + + //both working now, will need support added for ENC audio and no key + //NOTE: We want this to play regardless of whether the slot is voice or data, to play silence in one slot and voice in the second, or voices in both + if (internalslot == 0 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000) + playSynthesizedVoiceFS3 (opts, state); //Float Stereo Mix 3v2 + if (internalslot == 0 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 48000) + playSynthesizedVoiceFS3_48k (opts, state); //Float Stereo Mix 3v2 + if (internalslot == 0 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) + playSynthesizedVoiceSS3 (opts, state); //Short Stereo Mix 3v2 + if (internalslot == 0 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 48000) + playSynthesizedVoiceSS3_48k (opts, state); //Short Stereo Mix 3v2 + if (skipcount > 2) //after 2 consecutive data frames, drop back to getFrameSync and process with dmr_data_sync { //set tests to all good so we don't get a bogus/redundant voice error @@ -722,9 +777,49 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state) memcpy (m3, ambe_fr3, sizeof(m3)); if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here + // processMbeFrame (opts, state, NULL, ambe_fr, NULL); + // processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + // processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + processMbeFrame (opts, state, NULL, ambe_fr, NULL); + if(internalslot == 0) + { + memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l)); + } + + else + { + memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR)); + memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r)); + } + + processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + if(internalslot == 0) + { + memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l)); + } + + else + { + memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR)); + memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r)); + } + processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + if(internalslot == 0) + { + memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l)); + } + + else + { + memcpy(state->f_r4[2], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR)); + memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r)); + } //collect the mi fragment dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3); @@ -735,6 +830,16 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state) //update voice sync time for trunking purposes (particularly Con+) if (opts->p25_is_tuned == 1) state->last_vc_sync_time = time(NULL); + //NOTE: Only play on slot 0, if slot 1, then it'll play after the next TDMA frame in the BS loop instead + if (internalslot == 0 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000) + playSynthesizedVoiceFS3 (opts, state); //Float Stereo Mix 3v2 + if (internalslot == 0 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 48000) + playSynthesizedVoiceFS3_48k (opts, state); //Float Stereo Mix 3v2 + if (internalslot == 0 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) + playSynthesizedVoiceSS3 (opts, state); //Short Stereo Mix 3v2 + if (internalslot == 0 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 48000) + playSynthesizedVoiceSS3_48k (opts, state); //Short Stereo Mix 3v2 + dmrBS (opts, state); //bootstrap into full TDMA frame for BS mode END: //if we have a tact err, then produce sync pattern/err message diff --git a/src/dmr_ms.c b/src/dmr_ms.c index a4a530a..bed0459 100644 --- a/src/dmr_ms.c +++ b/src/dmr_ms.c @@ -280,17 +280,61 @@ void dmrMS (dsd_opts * opts, dsd_state * state) if (state->directmode == 0) { processMbeFrame (opts, state, NULL, ambe_fr, NULL); + memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu)); processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu)); processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu)); } else { processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio on tdma direct + memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu)); processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu)); processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu)); } } + if (opts->floating_point == 0) + { + // processAudio(opts, state); //needed here? -- nothign to test it with + + // if (opts->wav_out_f != NULL) + // writeSynthesizedVoice (opts, state); + + // if (opts->pulse_digi_out_channels == 1) + // playSynthesizedVoice(opts, state); + + if(opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceSS3(opts, state); + } + + if (opts->floating_point == 1) //float audio is really quiet now (look into it) + { + + memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); + + // if (opts->pulse_digi_out_channels == 1) + // playSynthesizedVoiceFM3(opts, state); + + if(opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS3(opts, state); + } + if (vc == 6) { dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB); @@ -557,14 +601,58 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) if (state->directmode == 0) { processMbeFrame (opts, state, NULL, ambe_fr, NULL); + memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu)); processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu)); processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu)); } else { - processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio + processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio on tdma direct + memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu)); processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu)); processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu)); + } + + if (opts->floating_point == 0) + { + // processAudio(opts, state); //NOTE: -fa switch will not work with this set up -- honestly shouldn't be needed + + // if (opts->wav_out_f != NULL) + // writeSynthesizedVoice (opts, state); + + // if (opts->pulse_digi_out_channels == 1) + // playSynthesizedVoice(opts, state); + + if(opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceSS3(opts, state); + } + + if (opts->floating_point == 1) //float audio is really quiet now (look into it) + { + + memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); + + // if (opts->pulse_digi_out_channels == 1) + // playSynthesizedVoiceFM(opts, state); + + if(opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS3(opts, state); } //collect the mi fragment diff --git a/src/dsd_audio.c b/src/dsd_audio.c index c4e98f5..d94a68f 100644 --- a/src/dsd_audio.c +++ b/src/dsd_audio.c @@ -21,14 +21,15 @@ pa_sample_spec ss; pa_sample_spec tt; pa_sample_spec zz; pa_sample_spec cc; +pa_sample_spec ff; //float void closePulseOutput (dsd_opts * opts) { pa_simple_free (opts->pulse_digi_dev_out); - if (opts->dmr_stereo == 1) - { - pa_simple_free (opts->pulse_digi_dev_outR); - } + // if (opts->dmr_stereo == 1) + // { + // pa_simple_free (opts->pulse_digi_dev_outR); + // } } void closePulseInput (dsd_opts * opts) @@ -40,32 +41,35 @@ void openPulseOutput(dsd_opts * opts) { ss.format = PA_SAMPLE_S16NE; - ss.channels = opts->pulse_raw_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse - ss.rate = opts->pulse_raw_rate_out; //48000 + ss.channels = opts->pulse_raw_out_channels; + ss.rate = opts->pulse_raw_rate_out; tt.format = PA_SAMPLE_S16NE; - tt.channels = opts->pulse_digi_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse - tt.rate = opts->pulse_digi_rate_out; //48000, switches to 8000 when using RTL dongle + tt.channels = opts->pulse_digi_out_channels; + tt.rate = opts->pulse_digi_rate_out; + + ff.format = PA_SAMPLE_FLOAT32NE; + ff.channels = opts->pulse_digi_out_channels; + ff.rate = opts->pulse_digi_rate_out; if (opts->monitor_input_audio == 1) { opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL); } -//tt - pa_channel_map* left = 0; //NULL and 0 are same in this context - pa_channel_map* right = 0; //NULL and 0 are same in this context + pa_channel_map* fl = 0; //NULL and 0 are same in this context + pa_channel_map* ss = 0; //NULL and 0 are same in this context - if (opts->dmr_stereo == 0) + if (opts->floating_point == 0) { - opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &tt, left, NULL, NULL); + opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &tt, ss, NULL, NULL); } - if (opts->dmr_stereo == 1) + if (opts->floating_point == 1) { - opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME1", PA_STREAM_PLAYBACK, NULL, "XDMA SLOT 1", &tt, left, NULL, NULL); - opts->pulse_digi_dev_outR = pa_simple_new(NULL, "DSD-FME2", PA_STREAM_PLAYBACK, NULL, "XDMA SLOT 2", &tt, right, NULL, NULL); + opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &ff, fl, NULL, NULL); + } } @@ -197,6 +201,8 @@ processAudio (dsd_opts * opts, dsd_state * state) *state->audio_out_float_buf_p = -32768.0F; } *state->audio_out_buf_p = (short) *state->audio_out_float_buf_p; + //tap the pointer here and store the short upsample buffer samples + state->s_lu[n] = (short) *state->audio_out_float_buf_p; state->audio_out_buf_p++; state->audio_out_float_buf_p++; } @@ -215,6 +221,10 @@ processAudio (dsd_opts * opts, dsd_state * state) *state->audio_out_temp_buf_p = -32768.0F; } *state->audio_out_buf_p = (short) *state->audio_out_temp_buf_p; + //tap the pointer here and store the short buffer samples + state->s_l[n] = (short) *state->audio_out_temp_buf_p; + //debug + // fprintf (stderr, " %d", state->s_l[n]); state->audio_out_buf_p++; state->audio_out_temp_buf_p++; state->audio_out_idx++; @@ -339,6 +349,8 @@ processAudioR (dsd_opts * opts, dsd_state * state) *state->audio_out_float_buf_pR = -32768.0F; } *state->audio_out_buf_pR = (short) *state->audio_out_float_buf_pR; + //tap the pointer here and store the short upsample buffer samples + state->s_ru[n] = (short) *state->audio_out_float_buf_pR; state->audio_out_buf_pR++; state->audio_out_float_buf_pR++; } @@ -357,6 +369,8 @@ processAudioR (dsd_opts * opts, dsd_state * state) *state->audio_out_temp_buf_pR = -32768.0F; } *state->audio_out_buf_pR = (short) *state->audio_out_temp_buf_pR; + //tap the pointer here and store the short buffer samples + state->s_r[n] = (short) *state->audio_out_temp_buf_pR; state->audio_out_buf_pR++; state->audio_out_temp_buf_pR++; state->audio_out_idxR++; diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c new file mode 100644 index 0000000..07f7d52 --- /dev/null +++ b/src/dsd_audio2.c @@ -0,0 +1,1450 @@ +#include "dsd.h" + +void agf (dsd_opts * opts, dsd_state * state, float samp[160]) +{ + int i, run; + run = 1; + float empty[160]; + memset (empty, 0.1f, sizeof(empty)); + + if(opts->pulse_digi_out_channels == 2){}; //compiler warning garbo + + float max = 0.0f; + float mmax = 0.75f; + float mmin = -0.75f; + float df; //decimation value + df = (384.0f / (float)opts->pulse_digi_out_channels) * (50.0f - state->aout_gain); + + //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; + + for (i = 0; i < 160; i++) + { + samp[i] = samp[i] / df; + + //simple clipping + if (samp[i] > mmax) + samp[i] = mmax; + if (samp[i] < mmin) + samp[i] = mmin; //this could have been an issue before "-mmin"? + + //max value + if (fabs(samp[i]) > max) + max = samp[i]; + + } + + //crude auto gain for float values + if (max < 0.351f && max > 0.1f && state->aout_gain < 42) state->aout_gain += 0.33f; //state->aout_gain++; + if (max > 0.35f && state->aout_gain > 1) state->aout_gain -= 0.33f; //state->aout_gain--; + + AGF_END: ; //do nothing + +} + +//float stereo mix 3v2 DMR +void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state) +{ + + //NOTE: This runs once for every two timeslots, if we are in the BS voice loop + //it doesn't matter if both slots have voice, or if one does, the slot without voice + //will play silence while this runs if no voice present + + int i; + uint8_t encL, encR; + float stereo_samp1[320]; //8k 2-channel stereo interleave mix + float stereo_samp2[320]; //8k 2-channel stereo interleave mix + float stereo_samp3[320]; //8k 2-channel stereo interleave mix + + //note, always set a stereo float mix to a baseline value and not zero! + memset (stereo_samp1, 0.1f, sizeof(stereo_samp1)); + memset (stereo_samp2, 0.1f, sizeof(stereo_samp2)); + memset (stereo_samp3, 0.1f, sizeof(stereo_samp3)); + + //dmr enc checkdown for whether or not to fill the stereo sample or not for playback or writing + encL = encR = 0; + encL = (state->dmr_so >> 6) & 0x1; + encR = (state->dmr_soR >> 6) & 0x1; + + //checkdown to see if we can lift the 'mute' if a key is available + if (encL) + { + if (state->payload_algid == 0) + { + if (state->K != 0 || state->K1 != 0) + { + encL = 0; + } + } + else if (state->payload_algid == 0x21) + { + if (state->R != 0) + { + encL = 0; + } + } + } + + if (encR) + { + if (state->payload_algidR == 0) + { + if (state->K != 0 || state->K1 != 0) + { + encR = 0; + } + } + else if (state->payload_algidR == 0x21) + { + if (state->RR != 0) + { + encR = 0; + } + } + } + + //TODO: add option to bypass enc with a toggle as well + + //run autogain on the f_ buffers + agf (opts, state, state->f_l4[0]); + agf (opts, state, state->f_r4[0]); + agf (opts, state, state->f_l4[1]); + agf (opts, state, state->f_r4[1]); + agf (opts, state, state->f_l4[2]); + agf (opts, state, state->f_r4[2]); + + //interleave left and right channels from the temp (float) buffer with makeshift 'volume' decimation + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp1[i*2+0] = state->f_l4[0][i]; + if (!encR) + stereo_samp1[i*2+1] = state->f_r4[0][i]; + } + + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp2[i*2+0] = state->f_l4[1][i]; + if (!encR) + stereo_samp2[i*2+1] = state->f_r4[1][i]; + } + + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp3[i*2+0] = state->f_l4[2][i]; + if (!encR) + stereo_samp3[i*2+1] = state->f_r4[2][i]; + } + + //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions + if (encL && encR) + goto FS3_END; + + if (opts->audio_out_type == 0) //Pulse Audio + { + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp1, 320*4, NULL); //switch to sizeof(stereo_samp1) * 2? + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp2, 320*4, NULL); + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp3, 320*4, NULL); + } + + //No OSS, since we can't use float output, but STDOUT can with play, aplay, etc + + if (opts->audio_out_type == 1) //STDOUT (still need these seperated? or not really?) + { + write (opts->audio_out_fd, stereo_samp1, 320*4); + write (opts->audio_out_fd, stereo_samp2, 320*4); + write (opts->audio_out_fd, stereo_samp3, 320*4); + } + + FS3_END: + + memset (state->audio_out_temp_buf, 0.1f, sizeof(state->audio_out_temp_buf)); + memset (state->audio_out_temp_bufR, 0.1f, sizeof(state->audio_out_temp_bufR)); + + //set float temp buffer to baseline + memset (state->f_l4, 0.1f, sizeof(state->f_l4)); + memset (state->f_r4, 0.1f, sizeof(state->f_r4)); + + //if we don't run processAudio, then I don't think we really need any of the items below active + state->audio_out_idx = 0; + state->audio_out_idxR = 0; + + 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; + } + + 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; + } + +} + +//float stereo mix 3v2 DMR with 8k to 48k upsample +void playSynthesizedVoiceFS3_48k (dsd_opts * opts, dsd_state * state) +{ + + //NOTE: The old version UpsampleF had a high pitch ring to it + //new version has an odd 'pattering' or 'crackle' sound or clipping? + + int i, n; + uint8_t encL, encR; + // int j, k; + // float prev; + float stereo_samp1[320*6]; //48k 2-channel stereo interleave mix + float stereo_samp2[320*6]; //48k 2-channel stereo interleave mix + float stereo_samp3[320*6]; //48k 2-channel stereo interleave mix + float stereo_samp4[320*6]; //48k 2-channel stereo interleave mix + float out[6]; + float temp_l[4][160*6]; //temp storage + float temp_r[4][160*6]; //temp storage + float baseline = 0.0f; + + memset (stereo_samp1, baseline, sizeof(stereo_samp1)); + memset (stereo_samp2, baseline, sizeof(stereo_samp2)); + memset (stereo_samp3, baseline, sizeof(stereo_samp3)); + memset (stereo_samp4, baseline, sizeof(stereo_samp4)); + + memset (temp_l, baseline, sizeof(temp_l)); + memset (temp_r, baseline, sizeof(temp_r)); + memset (out, baseline, sizeof(out)); + + //dmr enc checkdown for whether or not to fill the stereo sample or not for playback or writing + encL = encR = 0; + encL = (state->dmr_so >> 6) & 0x1; + encR = (state->dmr_soR >> 6) & 0x1; + + //checkdown to see if we can lift the 'mute' if a key is available + if (encL) + { + if (state->payload_algid == 0) + { + if (state->K != 0 || state->K1 != 0) + { + encL = 0; + } + } + else if (state->payload_algid == 0x21) + { + if (state->R != 0) + { + encL = 0; + } + } + } + + if (encR) + { + if (state->payload_algidR == 0) + { + if (state->K != 0 || state->K1 != 0) + { + encR = 0; + } + } + else if (state->payload_algidR == 0x21) + { + if (state->RR != 0) + { + encR = 0; + } + } + } + + //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions + if (encL && encR) + goto FS348_END; + + //TODO: Test Upsampling //void upsampleF (float invalue, float prev, float outbuf[6]) + // prev = 0.0f; + // for (j = 0; j < 3; j++) + // { + + // for (i = 0; i < 160; i++) + // { + // upsampleF (state->f_l4[j][i] / ((float) 480*10), prev, out); + // // upsampleF (state->f_l4[j][i], prev, out); + // for (k = 0; k < 6; k++) temp_l[j][i*6+k] = out[k]; + // } + // } + + // prev = 0.0f; //test value + // for (j = 0; j < 3; j++) + // { + + // for (i = 0; i < 160; i++) + // { + // upsampleF (state->f_r4[j][i] / ((float) 480*10), prev, out); + // // upsampleF (state->f_r4[j][i], prev, out); + // for (k = 0; k < 6; k++) temp_r[j][i*6+k] = out[k]; + // } + // } + + n = 160; + fdmdv_8_to_48_float(temp_l[0], state->f_l4[0], n); + fdmdv_8_to_48_float(temp_l[1], state->f_l4[1], n); + fdmdv_8_to_48_float(temp_l[2], state->f_l4[2], n); + fdmdv_8_to_48_float(temp_r[0], state->f_r4[0], n); + fdmdv_8_to_48_float(temp_r[1], state->f_r4[1], n); + fdmdv_8_to_48_float(temp_r[2], state->f_r4[2], n); + + //interleave left and right channels from the temp (float) buffer + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp1[i*2+0] = temp_l[0][i]; + if (!encR) + stereo_samp1[i*2+1] = temp_r[0][i]; + } + + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp2[i*2+0] = temp_l[1][i]; + if (!encR) + stereo_samp2[i*2+1] = temp_r[1][i]; + } + + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp3[i*2+0] = temp_l[2][i]; + if (!encR) + stereo_samp3[i*2+1] = temp_r[2][i]; + } + + if (opts->audio_out_type == 0) //Pulse Audio + { + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp1, 320*4*6, NULL); + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp2, 320*4*6, NULL); + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp3, 320*4*6, NULL); + } + + //No OSS, since we can't use float output, but STDOUT can with play, aplay, etc + + if (opts->audio_out_type == 1) //STDOUT + { + write (opts->audio_out_fd, stereo_samp1, 320*4*6); + write (opts->audio_out_fd, stereo_samp2, 320*4*6); + write (opts->audio_out_fd, stereo_samp3, 320*4*6); + } + + FS348_END: + + memset (state->audio_out_temp_buf, baseline, sizeof(state->audio_out_temp_buf)); + memset (state->audio_out_temp_bufR, baseline, sizeof(state->audio_out_temp_bufR)); + + //set float temp buffer to baseline + memset (state->f_l4, baseline, sizeof(state->f_l4)); + memset (state->f_r4, baseline, sizeof(state->f_r4)); + + //if we don't run processAudio, then I don't think we really need any of the items below active + state->audio_out_idx = 0; + state->audio_out_idxR = 0; + + 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; + } + + 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; + } + +} + +//float stereo mix 4v2 P25p2 +void playSynthesizedVoiceFS4 (dsd_opts * opts, dsd_state * state) +{ + + //NOTE: This will run for every TS % 2, except on SACCH inverted slots (10 and 11) + //WIP: Get the real TS number out of the P25p2 frame, and not our ts_counter values + + int i, encL, encR; + float stereo_samp1[320]; //8k 2-channel stereo interleave mix + float stereo_samp2[320]; //8k 2-channel stereo interleave mix + float stereo_samp3[320]; //8k 2-channel stereo interleave mix + float stereo_samp4[320]; //8k 2-channel stereo interleave mix + + float empty[320]; //this is used to see if we want to play a single 2v or double 2v or not + + //p25p2 enc checkdown for whether or not to fill the stereo sample or not for playback or writing + encL = encR = 1; + if (state->payload_algid == 0 || state->payload_algid == 0x80) + encL = 0; + if (state->payload_algidR == 0 || state->payload_algidR == 0x80) + encR = 0; + + //checkdown to see if we can lift the 'mute' if a key is available + if (encL) + { + if (state->payload_algid == 0xAA) + { + if (state->R != 0) + { + encL = 0; + } + } + } + + if (encR) + { + if (state->payload_algidR == 0xAA) + { + if (state->RR != 0) + { + encR = 0; + } + } + } + + //note, always set a stereo float mix to a baseline value and not zero! + memset (stereo_samp1, 0.1f, sizeof(stereo_samp1)); + memset (stereo_samp2, 0.1f, sizeof(stereo_samp2)); + memset (stereo_samp3, 0.1f, sizeof(stereo_samp3)); + memset (stereo_samp4, 0.1f, sizeof(stereo_samp4)); + + memset (empty, 0.1f, sizeof(empty)); + + //run autogain on the f_ buffers + agf (opts, state, state->f_l4[0]); + agf (opts, state, state->f_r4[0]); + agf (opts, state, state->f_l4[1]); + agf (opts, state, state->f_r4[1]); + agf (opts, state, state->f_l4[2]); //doing 2 and 3 here will break the memcmp below, so we also do it on empty + agf (opts, state, state->f_r4[2]); + agf (opts, state, state->f_l4[3]); + agf (opts, state, state->f_r4[3]); + agf (opts, state, empty); //running empty may cause auto gain control issues, and also any auto gain applied here will invalidate the memcmp + + //interleave left and right channels from the temp (float) buffer with makeshift 'volume' decimation + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp1[i*2+0] = state->f_l4[0][i]; // / ((float) 480.0f*10.0f) + if (!encR) + stereo_samp1[i*2+1] = state->f_r4[0][i]; + } + + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp2[i*2+0] = state->f_l4[1][i]; + if (!encR) + stereo_samp2[i*2+1] = state->f_r4[1][i]; + } + + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp3[i*2+0] = state->f_l4[2][i]; + if (!encR) + stereo_samp3[i*2+1] = state->f_r4[2][i]; + } + + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp4[i*2+0] = state->f_l4[3][i]; + if (!encR) + stereo_samp4[i*2+1] = state->f_r4[3][i]; + } + + if (encL && encR) + goto END_FS4; + + if (opts->audio_out_type == 0) //Pulse Audio + { + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp1, 320*4, NULL); //switch to sizeof(stereo_samp1) * 2? + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp2, 320*4, NULL); + //only play these two if not a single 2v or double 2v (minor skip can still occur on a 4v and 2v combo, but will probably only be perceivable if one is a tone) + if (memcmp(empty, stereo_samp3, sizeof(empty)) != 0) + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp3, 320*4, NULL); + if (memcmp(empty, stereo_samp4, sizeof(empty)) != 0) + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp4, 320*4, NULL); + } + + //No OSS, since we can't use float output, but the STDOUT can with play, aplay, etc + + if (opts->audio_out_type == 1) //STDOUT + { + write (opts->audio_out_fd, stereo_samp1, 320*4); + write (opts->audio_out_fd, stereo_samp2, 320*4); + //only play these two if not a single 2v or double 2v (minor skip can still occur on a 4v and 2v combo, but will probably only be perceivable if one is a tone) + if (memcmp(empty, stereo_samp3, sizeof(empty)) != 0) + write (opts->audio_out_fd, stereo_samp3, 320*4); + if (memcmp(empty, stereo_samp4, sizeof(empty)) != 0) + write (opts->audio_out_fd, stereo_samp4, 320*4); + } + + END_FS4: + + memset (state->audio_out_temp_buf, 0.1f, sizeof(state->audio_out_temp_buf)); + memset (state->audio_out_temp_bufR, 0.1f, sizeof(state->audio_out_temp_bufR)); + + //set float temp buffer to baseline + memset (state->f_l4, 0.1f, sizeof(state->f_l4)); + memset (state->f_r4, 0.1f, sizeof(state->f_r4)); + + //if we don't run processAudio, then I don't think we really need any of the items below active + state->audio_out_idx = 0; + state->audio_out_idxR = 0; + + 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; + } + + 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; + } + +} + +//float stereo mix 4v2 P25p2 with 8k to 48k upsample +void playSynthesizedVoiceFS4_48k (dsd_opts * opts, dsd_state * state) +{ + + //NOTE: The old version UpsampleF had a high pitch ring to it + //new version has an odd 'pattering' or 'crackle' sound or clipping? + + int i, n, encL, encR; + // int j, k; + // float prev; + float stereo_samp1[320*6]; //48k 2-channel stereo interleave mix + float stereo_samp2[320*6]; //48k 2-channel stereo interleave mix + float stereo_samp3[320*6]; //48k 2-channel stereo interleave mix + float stereo_samp4[320*6]; //48k 2-channel stereo interleave mix + float out[6]; + float temp_l[4][160*6]; //temp storage + float temp_r[4][160*6]; //temp storage + float empty[320*6]; + float baseline = 0.0f; + + memset (stereo_samp1, baseline, sizeof(stereo_samp1)); + memset (stereo_samp2, baseline, sizeof(stereo_samp2)); + memset (stereo_samp3, baseline, sizeof(stereo_samp3)); + memset (stereo_samp4, baseline, sizeof(stereo_samp4)); + + memset (temp_l, baseline, sizeof(temp_l)); + memset (temp_r, baseline, sizeof(temp_r)); + memset (out, baseline, sizeof(out)); + memset (empty, baseline, sizeof(empty)); + + //p25p2 enc checkdown for whether or not to fill the stereo sample or not for playback or writing + encL = encR = 1; + if (state->payload_algid == 0 || state->payload_algid == 0x80) + encL = 0; + if (state->payload_algidR == 0 || state->payload_algidR == 0x80) + encR = 0; + + //checkdown to see if we can lift the 'mute' if a key is available + if (encL) + { + if (state->payload_algid == 0xAA) + { + if (state->R != 0) + { + encL = 0; + } + } + } + + if (encR) + { + if (state->payload_algidR == 0xAA) + { + if (state->RR != 0) + { + encR = 0; + } + } + } + + //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions + if (encL && encR) + goto FS448_END; + + //TODO: Test Upsampling //void upsampleF (float invalue, float prev, float outbuf[6]) + // prev = 0.0f; + // for (j = 0; j < 4; j++) + // { + + // for (i = 0; i < 160; i++) + // { + // upsampleF (state->f_l4[j][i] / ((float) 480*10), prev, out); + // // upsampleF (state->f_l4[j][i], prev, out); + // for (k = 0; k < 6; k++) temp_l[j][i*6+k] = out[k]; + // } + // } + + // prev = 0.0f; //test value + // for (j = 0; j < 4; j++) + // { + + // for (i = 0; i < 160; i++) + // { + // upsampleF (state->f_r4[j][i] / ((float) 480*10), prev, out); + // // upsampleF (state->f_r4[j][i], prev, out); + // for (k = 0; k < 6; k++) temp_r[j][i*6+k] = out[k]; + // } + // } + + n = 160; //not sure why we are using 159 though + fdmdv_8_to_48_float(temp_l[0], state->f_l4[0], n); + fdmdv_8_to_48_float(temp_l[1], state->f_l4[1], n); + fdmdv_8_to_48_float(temp_l[2], state->f_l4[2], n); + fdmdv_8_to_48_float(temp_l[3], state->f_l4[3], n); + fdmdv_8_to_48_float(temp_r[0], state->f_r4[0], n); + fdmdv_8_to_48_float(temp_r[1], state->f_r4[1], n); + fdmdv_8_to_48_float(temp_r[2], state->f_r4[2], n); + fdmdv_8_to_48_float(temp_r[3], state->f_r4[3], n); + + //interleave left and right channels from the temp (float) buffer + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp1[i*2+0] = temp_l[0][i]; + if (!encR) + stereo_samp1[i*2+1] = temp_r[0][i]; + } + + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp2[i*2+0] = temp_l[1][i]; + if (!encR) + stereo_samp2[i*2+1] = temp_r[1][i]; + } + + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp3[i*2+0] = temp_l[2][i]; + if (!encR) + stereo_samp3[i*2+1] = temp_r[2][i]; + } + + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp4[i*2+0] = temp_l[3][i]; + if (!encR) + stereo_samp4[i*2+1] = temp_r[3][i]; + } + + if (opts->audio_out_type == 0) //Pulse Audio + { + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp1, 320*4*6, NULL); + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp2, 320*4*6, NULL); + if (memcmp(empty, stereo_samp3, sizeof(empty)) != 0) + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp3, 320*4*6, NULL); + if (memcmp(empty, stereo_samp4, sizeof(empty)) != 0) + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp4, 320*4*6, NULL); + } + + //No OSS, since we can't use float output, but STDOUT can with play, aplay, etc + + if (opts->audio_out_type == 1) //STDOUT + { + write (opts->audio_out_fd, stereo_samp1, 320*4*6); + write (opts->audio_out_fd, stereo_samp2, 320*4*6); + if (memcmp(empty, stereo_samp3, sizeof(empty)) != 0) + write (opts->audio_out_fd, stereo_samp3, 320*4*6); + if (memcmp(empty, stereo_samp4, sizeof(empty)) != 0) + write (opts->audio_out_fd, stereo_samp4, 320*4*6); + } + + FS448_END: + + memset (state->audio_out_temp_buf, baseline, sizeof(state->audio_out_temp_buf)); + memset (state->audio_out_temp_bufR, baseline, sizeof(state->audio_out_temp_bufR)); + + //set float temp buffer to baseline + memset (state->f_l4, baseline, sizeof(state->f_l4)); + memset (state->f_r4, baseline, sizeof(state->f_r4)); + + //if we don't run processAudio, then I don't think we really need any of the items below active + state->audio_out_idx = 0; + state->audio_out_idxR = 0; + + 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; + } + + 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; + } + +} + +//float stereo mix -- when using P25p1 and P25p2, we need to send P25p1 to this, also DMR MS/Simplex and YSF +void playSynthesizedVoiceFS (dsd_opts * opts, dsd_state * state) +{ + + int i; + int encL; + float stereo_samp1[320]; //8k 2-channel stereo interleave mix + + //note, always set a stereo float mix to a baseline value and not zero! + memset (stereo_samp1, 0.1f, sizeof(stereo_samp1)); + + //TODO: ENC Check on P25p1, NXDN, dPMR, etc + encL = 0; + + //TODO: add option to bypass enc with a toggle as well + + //run autogain on the f_ buffers + agf (opts, state, state->f_l); + + //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions + if (encL) + goto FS_END; + + + //interleave left and right channels from the temp (float) buffer with makeshift 'volume' decimation + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp1[i*2+0] = state->f_l[i]; + + //test loading right side with same + if (!encL) + stereo_samp1[i*2+1] = state->f_l[i]; + } + + + if (opts->audio_out_type == 0) //Pulse Audio + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp1, 320*4, NULL); //switch to sizeof(stereo_samp1) * 2? + + + //No OSS, since we can't use float output, but STDOUT can with play, aplay, etc + + if (opts->audio_out_type == 1) + write (opts->audio_out_fd, stereo_samp1, 320*4); + + + FS_END: + + memset (state->audio_out_temp_buf, 0.1f, sizeof(state->audio_out_temp_buf)); + memset (state->audio_out_temp_bufR, 0.1f, sizeof(state->audio_out_temp_bufR)); + + //set float temp buffer to baseline + memset (state->f_l4, 0.1f, sizeof(state->f_l4)); + memset (state->f_r4, 0.1f, sizeof(state->f_r4)); + + //if we don't run processAudio, then I don't think we really need any of the items below active + state->audio_out_idx = 0; + state->audio_out_idxR = 0; + + 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; + } + + 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; + } + +} + +void playSynthesizedVoiceFM (dsd_opts * opts, dsd_state * state) +{ + + agf(opts, state, state->f_l); + + if (opts->audio_out_type == 0) + pa_simple_write(opts->pulse_digi_dev_out, state->f_l, 160*4, NULL); + + if (opts->audio_out_type == 1 || opts->audio_out_type == 5) + write(opts->audio_out_fd, state->f_l, 160*4); + + 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; + } + + memset (state->audio_out_temp_buf, 0, sizeof(state->audio_out_temp_buf)); + +} + +//Stereo Mix - Short (SB16LE) -- When Playing Short FDMA samples when setup for stereo output +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)); + + //dmr enc checkdown for whether or not to fill the stereo sample or not for playback or writing + encL = 0; + + //TODO: Enc Checkdown + + //TODO: add option to bypass enc with a toggle as well + + //interleave left and right channels from the short storage area + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp1[i*2+0] = state->s_l[i]; + + //testing double left and right channel + if (!encL) + stereo_samp1[i*2+1] = state->s_l[i]; + + } + + //at this point, if still flagged as enc, then we can skip all playback/writing functions + if (encL) + goto SSM_END; + + if (opts->audio_out_type == 0) //Pulse Audio + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp1, 320*2, NULL); + + if (opts->audio_out_type == 1 || opts->audio_out_type == 5) //STDOUT or OSS + write (opts->audio_out_fd, stereo_samp1, 320*2); + + + SSM_END: + + //run cleanup since we pulled stuff from processAudio + state->audio_out_idx = 0; + state->audio_out_idxR = 0; + + //set float temp buffer to baseline + memset (state->s_l4, 1, sizeof(state->s_l4)); + memset (state->s_r4, 1, sizeof(state->s_r4)); + + 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; + } + + 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; + } + +} + +//short stereo mix 3v2 DMR +void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state) +{ + + //NOTE: This runs once for every two timeslots, if we are in the BS voice loop + //it doesn't matter if both slots have voice, or if one does, the slot without voice + //will play silence while this runs if no voice present + + int i; + uint8_t encL, encR; + short stereo_samp1[320]; //8k 2-channel stereo interleave mix + short stereo_samp2[320]; //8k 2-channel stereo interleave mix + short stereo_samp3[320]; //8k 2-channel stereo interleave mix + + memset (stereo_samp1, 1, sizeof(stereo_samp1)); + memset (stereo_samp2, 1, sizeof(stereo_samp2)); + memset (stereo_samp3, 1, sizeof(stereo_samp3)); + + //dmr enc checkdown for whether or not to fill the stereo sample or not for playback or writing + encL = encR = 0; + encL = (state->dmr_so >> 6) & 0x1; + encR = (state->dmr_soR >> 6) & 0x1; + + //checkdown to see if we can lift the 'mute' if a key is available + if (encL) + { + if (state->payload_algid == 0) + { + if (state->K != 0 || state->K1 != 0) + { + encL = 0; + } + } + else if (state->payload_algid == 0x21) + { + if (state->R != 0) + { + encL = 0; + } + } + } + + if (encR) + { + if (state->payload_algidR == 0) + { + if (state->K != 0 || state->K1 != 0) + { + encR = 0; + } + } + else if (state->payload_algidR == 0x21) + { + if (state->RR != 0) + { + encR = 0; + } + } + } + + //TODO: add option to bypass enc with a toggle as well + + //interleave left and right channels from the short storage area + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp1[i*2+0] = state->s_l4[0][i]; + if (!encR) + stereo_samp1[i*2+1] = state->s_r4[0][i]; + } + + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp2[i*2+0] = state->s_l4[1][i]; + if (!encR) + stereo_samp2[i*2+1] = state->s_r4[1][i]; + } + + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp3[i*2+0] = state->s_l4[2][i]; + if (!encR) + stereo_samp3[i*2+1] = state->s_r4[2][i]; + } + + //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions + if (encL && encR) + goto SS3_END; + + if (opts->audio_out_type == 0) //Pulse Audio + { + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp1, 320*2, NULL); + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp2, 320*2, NULL); + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp3, 320*2, NULL); + } + + + if (opts->audio_out_type == 1 || opts->audio_out_type == 5) //STDOUT or OSS + { + write (opts->audio_out_fd, stereo_samp1, 320*2); + write (opts->audio_out_fd, stereo_samp2, 320*2); + write (opts->audio_out_fd, stereo_samp3, 320*2); + } + + SS3_END: + + //run cleanup since we pulled stuff from processAudio + state->audio_out_idx = 0; + state->audio_out_idxR = 0; + + //set float temp buffer to baseline + memset (state->s_l4, 1, sizeof(state->s_l4)); + memset (state->s_r4, 1, sizeof(state->s_r4)); + + 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; + } + + 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; + } + +} + +//short stereo mix 4v2 P25p2 +void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state) +{ + + //NOTE: This runs once for every two timeslots, if we are in the BS voice loop + //it doesn't matter if both slots have voice, or if one does, the slot without voice + //will play silence while this runs if no voice present + + int i; + uint8_t encL, encR; + short stereo_samp1[320]; //8k 2-channel stereo interleave mix + 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 empty[320]; //this is used to see if we want to play a single 2v or double 2v or not + + memset (stereo_samp1, 1, sizeof(stereo_samp1)); + memset (stereo_samp2, 1, sizeof(stereo_samp2)); + memset (stereo_samp3, 1, sizeof(stereo_samp3)); + memset (stereo_samp4, 1, sizeof(stereo_samp4)); + + memset (empty, 1, sizeof(empty)); + + + //p25p2 enc checkdown for whether or not to fill the stereo sample or not for playback or writing + encL = encR = 1; + if (state->payload_algid == 0 || state->payload_algid == 0x80) + encL = 0; + if (state->payload_algidR == 0 || state->payload_algidR == 0x80) + encR = 0; + + //checkdown to see if we can lift the 'mute' if a key is available + if (encL) + { + if (state->payload_algid == 0xAA) + { + if (state->R != 0) + { + encL = 0; + } + } + } + + if (encR) + { + if (state->payload_algidR == 0xAA) + { + if (state->RR != 0) + { + encR = 0; + } + } + } + + + //TODO: add option to bypass enc with a toggle as well + + //interleave left and right channels from the short storage area + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp1[i*2+0] = state->s_l4[0][i]; + if (!encR) + stereo_samp1[i*2+1] = state->s_r4[0][i]; + } + + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp2[i*2+0] = state->s_l4[1][i]; + if (!encR) + stereo_samp2[i*2+1] = state->s_r4[1][i]; + } + + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp3[i*2+0] = state->s_l4[2][i]; + if (!encR) + stereo_samp3[i*2+1] = state->s_r4[2][i]; + } + + for (i = 0; i < 160; i++) + { + if (!encL) + stereo_samp4[i*2+0] = state->s_l4[3][i]; + if (!encR) + stereo_samp4[i*2+1] = state->s_r4[3][i]; + } + + //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions + if (encL && encR) + goto SS4_END; + + if (opts->audio_out_type == 0) //Pulse Audio + { + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp1, 320*2, NULL); + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp2, 320*2, NULL); + //only play these two if not a single 2v or double 2v (minor skip can still occur on a 4v and 2v combo, but will probably only be perceivable if one is a tone) + if (memcmp(empty, stereo_samp3, sizeof(empty)) != 0) + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp3, 320*2, NULL); + if (memcmp(empty, stereo_samp4, sizeof(empty)) != 0) + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp4, 320*2, NULL); + } + + + if (opts->audio_out_type == 1 || opts->audio_out_type == 5) //STDOUT or OSS + { + write (opts->audio_out_fd, stereo_samp1, 320*2); + write (opts->audio_out_fd, stereo_samp2, 320*2); + //only play these two if not a single 2v or double 2v (minor skip can still occur on a 4v and 2v combo, but will probably only be perceivable if one is a tone) + if (memcmp(empty, stereo_samp3, sizeof(empty)) != 0) + write (opts->audio_out_fd, stereo_samp3, 320*2); + if (memcmp(empty, stereo_samp4, sizeof(empty)) != 0) + write (opts->audio_out_fd, stereo_samp4, 320*2); + } + + SS4_END: + + //run cleanup since we pulled stuff from processAudio + state->audio_out_idx = 0; + state->audio_out_idxR = 0; + + //set float temp buffer to baseline + memset (state->s_l4, 1, sizeof(state->s_l4)); + memset (state->s_r4, 1, sizeof(state->s_r4)); + + 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; + } + + 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; + } + +} + +//short stereo mix 3v2 DMR with tapped 8k to 48k upsample +void playSynthesizedVoiceSS3_48k (dsd_opts * opts, dsd_state * state) +{ + + //NOTE: This runs once for every two timeslots, if we are in the BS voice loop + //it doesn't matter if both slots have voice, or if one does, the slot without voice + //will play silence while this runs if no voice present + + int i; + uint8_t encL, encR; + short stereo_samp1[320*6]; //48k 2-channel stereo interleave mix + short stereo_samp2[320*6]; //48k 2-channel stereo interleave mix + short stereo_samp3[320*6]; //48k 2-channel stereo interleave mix + + memset (stereo_samp1, 1, sizeof(stereo_samp1)); + memset (stereo_samp2, 1, sizeof(stereo_samp2)); + memset (stereo_samp3, 1, sizeof(stereo_samp3)); + + //dmr enc checkdown for whether or not to fill the stereo sample or not for playback or writing + encL = encR = 0; + encL = (state->dmr_so >> 6) & 0x1; + encR = (state->dmr_soR >> 6) & 0x1; + + //checkdown to see if we can lift the 'mute' if a key is available + if (encL) + { + if (state->payload_algid == 0) + { + if (state->K != 0 || state->K1 != 0) + { + encL = 0; + } + } + else if (state->payload_algid == 0x21) + { + if (state->R != 0) + { + encL = 0; + } + } + } + + if (encR) + { + if (state->payload_algidR == 0) + { + if (state->K != 0 || state->K1 != 0) + { + encR = 0; + } + } + else if (state->payload_algidR == 0x21) + { + if (state->RR != 0) + { + encR = 0; + } + } + } + + //TODO: add option to bypass enc with a toggle as well + + //interleave left and right channels from the short storage area + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp1[i*2+0] = state->s_l4u[0][i]; + if (!encR) + stereo_samp1[i*2+1] = state->s_r4u[0][i]; + } + + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp2[i*2+0] = state->s_l4u[1][i]; + if (!encR) + stereo_samp2[i*2+1] = state->s_r4u[1][i]; + } + + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp3[i*2+0] = state->s_l4u[2][i]; + if (!encR) + stereo_samp3[i*2+1] = state->s_r4u[2][i]; + } + + //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions + if (encL && encR) + goto SS3u_END; + + if (opts->audio_out_type == 0) //Pulse Audio + { + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp1, 320*2*6, NULL); + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp2, 320*2*6, NULL); + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp3, 320*2*6, NULL); + } + + + if (opts->audio_out_type == 1 || opts->audio_out_type == 5) //STDOUT or OSS + { + write (opts->audio_out_fd, stereo_samp1, 320*2*6); + write (opts->audio_out_fd, stereo_samp2, 320*2*6); + write (opts->audio_out_fd, stereo_samp3, 320*2*6); + } + + SS3u_END: + + //run cleanup since we pulled stuff from processAudio + state->audio_out_idx = 0; + state->audio_out_idxR = 0; + + //set short temp buffer to baseline + memset (state->s_l4u, 1, sizeof(state->s_l4u)); + memset (state->s_r4u, 1, sizeof(state->s_r4u)); + + 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; + } + + 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; + } + +} + +//short stereo mix 4v2 P25p2 with tapped 8k to 48k upsample +void playSynthesizedVoiceSS4_48k (dsd_opts * opts, dsd_state * state) +{ + + int i, encL, encR; + short stereo_samp1[320*6]; //48k 2-channel stereo interleave mix + short stereo_samp2[320*6]; //48k 2-channel stereo interleave mix + short stereo_samp3[320*6]; //48k 2-channel stereo interleave mix + short stereo_samp4[320*6]; //48k 2-channel stereo interleave mix + + memset (stereo_samp1, 1, sizeof(stereo_samp1)); + memset (stereo_samp2, 1, sizeof(stereo_samp2)); + memset (stereo_samp3, 1, sizeof(stereo_samp3)); + memset (stereo_samp4, 1, sizeof(stereo_samp4)); + + float empty[320]; //this is used to see if we want to play a single 2v or double 2v or not + + memset (empty, 1, sizeof(empty)); + + //p25p2 enc checkdown for whether or not to fill the stereo sample or not for playback or writing + encL = encR = 1; + if (state->payload_algid == 0 || state->payload_algid == 0x80) + encL = 0; + if (state->payload_algidR == 0 || state->payload_algidR == 0x80) + encR = 0; + + //checkdown to see if we can lift the 'mute' if a key is available + if (encL) + { + if (state->payload_algid == 0xAA) + { + if (state->R != 0) + { + encL = 0; + } + } + } + + if (encR) + { + if (state->payload_algidR == 0xAA) + { + if (state->RR != 0) + { + encR = 0; + } + } + } + + //TODO: add option to bypass enc with a toggle as well + + //interleave left and right channels from the short storage area + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp1[i*2+0] = state->s_l4u[0][i]; + if (!encR) + stereo_samp1[i*2+1] = state->s_r4u[0][i]; + } + + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp2[i*2+0] = state->s_l4u[1][i]; + if (!encR) + stereo_samp2[i*2+1] = state->s_r4u[1][i]; + } + + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp3[i*2+0] = state->s_l4u[2][i]; + if (!encR) + stereo_samp3[i*2+1] = state->s_r4u[2][i]; + } + + for (i = 0; i < 160*6; i++) + { + if (!encL) + stereo_samp4[i*2+0] = state->s_l4u[3][i]; + if (!encR) + stereo_samp4[i*2+1] = state->s_r4u[3][i]; + } + + //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions + if (encL && encR) + goto SS4u_END; + + if (opts->audio_out_type == 0) //Pulse Audio + { + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp1, 320*2*6, NULL); + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp2, 320*2*6, NULL); + if (memcmp(empty, stereo_samp3, sizeof(empty)) != 0) + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp3, 320*2*6, NULL); + if (memcmp(empty, stereo_samp4, sizeof(empty)) != 0) + pa_simple_write(opts->pulse_digi_dev_out, stereo_samp4, 320*2*6, NULL); + } + + + if (opts->audio_out_type == 1 || opts->audio_out_type == 5) //STDOUT or OSS + { + write (opts->audio_out_fd, stereo_samp1, 320*2*6); + write (opts->audio_out_fd, stereo_samp2, 320*2*6); + if (memcmp(empty, stereo_samp3, sizeof(empty)) != 0) + write (opts->audio_out_fd, stereo_samp3, 320*2*6); + if (memcmp(empty, stereo_samp4, sizeof(empty)) != 0) + write (opts->audio_out_fd, stereo_samp4, 320*2*6); + } + + SS4u_END: + + //run cleanup since we pulled stuff from processAudio + state->audio_out_idx = 0; + state->audio_out_idxR = 0; + + //set short temp buffer to baseline + memset (state->s_l4u, 1, sizeof(state->s_l4u)); + memset (state->s_r4u, 1, sizeof(state->s_r4u)); + + 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; + } + + 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; + } + +} \ No newline at end of file diff --git a/src/dsd_main.c b/src/dsd_main.c index 2a7521b..53ee89b 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -101,6 +101,14 @@ void noCarrier (dsd_opts * opts, dsd_state * state) { + //is this not being set properly? + if (opts->floating_point == 1) + { + //test for WIP auto gain, disable later if needbe + state->aout_gain = 25.0f; + state->aout_gainR = 25.0f; + } + //clear heuristics from last carrier signal if (opts->frame_p25p1 == 1 && opts->use_heuristics == 1) { @@ -286,17 +294,18 @@ noCarrier (dsd_opts * opts, dsd_state * state) sprintf (state->slot1light, "%s", ""); sprintf (state->slot2light, "%s", ""); state->firstframe = 0; - if (opts->audio_gain == (float) 0) - { - if (state->audio_smoothing == 0) state->aout_gain = 15; //15 - else state->aout_gain = 25; //25 - } + //this really isn't the best placement for this sort of check + // if (opts->audio_gain == (float) 0) + // { + // if (state->audio_smoothing == 0) state->aout_gain = 15; //15 + // else state->aout_gain = 25; //25 + // } - if (opts->audio_gainR == (float) 0) - { - if (state->audio_smoothing == 0) state->aout_gainR = 15; //15 - else state->aout_gainR = 25; //25 - } + // if (opts->audio_gainR == (float) 0) + // { + // if (state->audio_smoothing == 0) state->aout_gainR = 15; //15 + // else state->aout_gainR = 25; //25 + // } memset (state->aout_max_buf, 0, sizeof (float) * 200); state->aout_max_buf_p = state->aout_max_buf; state->aout_max_buf_idx = 0; @@ -485,12 +494,35 @@ noCarrier (dsd_opts * opts, dsd_state * state) state->m17_enc_st = 0; memset(state->m17_meta, 0, sizeof(state->m17_meta)); + //set float temp buffer to baseline + memset (state->audio_out_temp_buf, 0.1f, sizeof(state->audio_out_temp_buf)); + memset (state->audio_out_temp_bufR, 0.1f, sizeof(state->audio_out_temp_bufR)); + + //set float temp buffer to baseline + memset (state->f_l, 0.1f, sizeof(state->f_l)); + memset (state->f_r, 0.1f, sizeof(state->f_r)); + + //set float temp buffer to baseline + memset (state->f_l4, 0.1f, sizeof(state->f_l4)); + memset (state->f_r4, 0.1f, sizeof(state->f_r4)); + + //zero out the short sample storage buffers + memset (state->s_l, 1, sizeof(state->s_l)); + memset (state->s_r, 1, sizeof(state->s_r)); + memset (state->s_l4, 1, sizeof(state->s_l4)); + memset (state->s_r4, 1, sizeof(state->s_r4)); + + memset (state->s_lu, 1, sizeof(state->s_lu)); + memset (state->s_ru, 1, sizeof(state->s_ru)); + memset (state->s_l4u, 1, sizeof(state->s_l4u)); + memset (state->s_r4u, 1, sizeof(state->s_r4u)); + } //nocarrier void initOpts (dsd_opts * opts) { - + opts->floating_point = 0; //use floating point audio output opts->onesymbol = 10; opts->mbe_in_file[0] = 0; opts->mbe_in_f = NULL; @@ -589,9 +621,9 @@ initOpts (dsd_opts * opts) opts->rtl_rms = 0; //root means square power level on rtl input signal //end RTL user options opts->pulse_raw_rate_in = 48000; - opts->pulse_raw_rate_out = 48000; // + opts->pulse_raw_rate_out = 48000;// opts->pulse_digi_rate_in = 48000; - opts->pulse_digi_rate_out = 24000; //new default for XDMA + opts->pulse_digi_rate_out = 8000; // opts->pulse_raw_in_channels = 1; opts->pulse_raw_out_channels = 1; opts->pulse_digi_in_channels = 1; //2 @@ -700,7 +732,10 @@ initOpts (dsd_opts * opts) opts->use_dsp_output = 0; //Use P25p1 heuristics - opts->use_heuristics = 0; + opts->use_heuristics = 0; + + // if (opts->floating_point == 1) + // state->aout_gain = 25.0f; } //initopts @@ -724,6 +759,28 @@ initState (dsd_state * state) //Upsampled Audio Smoothing state->audio_smoothing = 0; + memset (state->audio_out_temp_buf, 0.1f, sizeof(state->audio_out_temp_buf)); + memset (state->audio_out_temp_bufR, 0.1f, sizeof(state->audio_out_temp_bufR)); + + //set float temp buffer to baseline + memset (state->f_l, 0.1f, sizeof(state->f_l)); + memset (state->f_r, 0.1f, sizeof(state->f_r)); + + //set float temp buffer to baseline + memset (state->f_l4, 0.1f, sizeof(state->f_l4)); + memset (state->f_r4, 0.1f, sizeof(state->f_r4)); + + //zero out the short sample storage buffers + memset (state->s_l, 1, sizeof(state->s_l)); + memset (state->s_r, 1, sizeof(state->s_r)); + memset (state->s_l4, 1, sizeof(state->s_l4)); + memset (state->s_r4, 1, sizeof(state->s_r4)); + + memset (state->s_lu, 1, sizeof(state->s_lu)); + memset (state->s_ru, 1, sizeof(state->s_ru)); + memset (state->s_l4u, 1, sizeof(state->s_l4u)); + memset (state->s_r4u, 1, sizeof(state->s_r4u)); + state->audio_out_buf = malloc (sizeof (short) * 1000000); state->audio_out_bufR = malloc (sizeof (short) * 1000000); memset (state->audio_out_buf, 0, 100 * sizeof (short)); @@ -800,8 +857,8 @@ initState (dsd_state * state) state->firstframe = 0; sprintf (state->slot1light, "%s", ""); sprintf (state->slot2light, "%s", ""); - state->aout_gain = 0; - state->aout_gainR = 0; + state->aout_gain = 15; //was 0 + state->aout_gainR = 15; //was 0 memset (state->aout_max_buf, 0, sizeof (float) * 200); state->aout_max_buf_p = state->aout_max_buf; state->aout_max_buf_idx = 0; @@ -1136,7 +1193,7 @@ usage () printf (" null for no audio output\n"); printf (" -d Create mbe data files, use this directory (TDMA version is experimental)\n"); printf (" -r Read/Play saved mbe data from file(s)\n"); - printf (" -g Audio output gain (default = 0 = auto, disable = -1)\n"); + printf (" -g Audio output gain (default = 0 = auto, disable = -1)\n"); printf (" -w Output synthesized speech to a .wav file, FDMA modes only.\n"); printf (" -7 Create/Use Custom directory for Per Call decoded .wav file saving.\n"); printf (" (Single Nested Directory Only! Use Before the -P option!)\n"); @@ -1152,6 +1209,7 @@ usage () printf (" -V Enable Audio Smoothing on Upsampled 48k/1 or 24k/2 Audio (Capital V)\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"); @@ -1276,38 +1334,38 @@ void liveScanner (dsd_opts * opts, dsd_state * state) { -if (opts->audio_in_type == 1) -{ - opts->pulse_digi_rate_out = 48000; - opts->pulse_digi_out_channels = 1; - if (opts->dmr_stereo == 1) - { - opts->pulse_digi_rate_out = 24000; - opts->pulse_digi_out_channels = 2; - fprintf (stderr, "STDIN Audio Rate Out set to 24000 Khz/2 Channel \n"); - } - else fprintf (stderr, "STDIN Audio Rate Out set to 48000 Khz/1 Channel \n"); - opts->pulse_raw_rate_out = 48000; - opts->pulse_raw_out_channels = 1; +// if (opts->audio_in_type == 1) +// { +// opts->pulse_digi_rate_out = 48000; +// opts->pulse_digi_out_channels = 1; +// if (opts->dmr_stereo == 1) +// { +// opts->pulse_digi_rate_out = 24000; +// opts->pulse_digi_out_channels = 2; +// fprintf (stderr, "STDIN Audio Rate Out set to 24000 Khz/2 Channel \n"); +// } +// else fprintf (stderr, "STDIN Audio Rate Out set to 48000 Khz/1 Channel \n"); +// opts->pulse_raw_rate_out = 48000; +// opts->pulse_raw_out_channels = 1; -} +// } #ifdef USE_RTLSDR if(opts->audio_in_type == 3) { //still need this section mostly due the the crackling on the rtl dongle when upsampled //probably need to dig a little deeper, maybe inlvl releated? - opts->pulse_digi_rate_out = 48000; //revert to 8K/1 for RTL input, random crackling otherwise - opts->pulse_digi_out_channels = 1; - if (opts->dmr_stereo == 1) - { - opts->pulse_digi_rate_out = 24000; //rtl needs 24000 by 2 channel for DMR TDMA Stereo output - opts->pulse_digi_out_channels = 2; //minimal crackling 'may' be observed, not sure, can't test to see on DMR with RTL - // fprintf (stderr, "RTL Audio Rate Out set to 24000 Khz/2 Channel \n"); - } - // else fprintf (stderr, "RTL Audio Rate Out set to 48000 Khz/1 Channel \n"); - opts->pulse_raw_rate_out = 48000; - opts->pulse_raw_out_channels = 1; + // opts->pulse_digi_rate_out = 48000; //revert to 8K/1 for RTL input, random crackling otherwise + // opts->pulse_digi_out_channels = 1; + // if (opts->dmr_stereo == 1) + // { + // opts->pulse_digi_rate_out = 24000; //rtl needs 24000 by 2 channel for DMR TDMA Stereo output + // opts->pulse_digi_out_channels = 2; //minimal crackling 'may' be observed, not sure, can't test to see on DMR with RTL + // // fprintf (stderr, "RTL Audio Rate Out set to 24000 Khz/2 Channel \n"); + // } + // // else fprintf (stderr, "RTL Audio Rate Out set to 48000 Khz/1 Channel \n"); + // opts->pulse_raw_rate_out = 48000; + // opts->pulse_raw_out_channels = 1; open_rtlsdr_stream(opts); opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again @@ -1482,7 +1540,7 @@ main (int argc, char **argv) exitflag = 0; - while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:YK:b:H:X:NQ:WrlZTF01:2:345:6:7:89:Ek:")) != -1) + while ((c = getopt (argc, argv, "yhaepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:YK:b:H:X:NQ:WrlZTF01:2:345:6:7:89:Ek:")) != -1) { opterr = 0; switch (c) @@ -1524,6 +1582,13 @@ main (int argc, char **argv) fprintf (stderr,"DMR Late Entry Encryption Identifiers Disabled (VC6 Single Burst)\n"); break; + case 'y': //use experimental 'float' audio output + opts.floating_point = 1; //enable floating point audio output + opts.audio_gain = 0; + state.aout_gain = 25.0f; //seems like a nonimal value for float during testing anyways + fprintf (stderr,"Enabling Experimental Floating Point Audio Output\n"); + break; + case 'Y': //conventional scanner mode opts.scanner_mode = 1; //enable scanner opts.p25_trunk = 0; //turn off trunking mode if user enabled it @@ -1868,7 +1933,7 @@ main (int argc, char **argv) opts.frame_provoice = 0; opts.frame_ysf = 1; opts.frame_m17 = 0; - opts.pulse_digi_rate_out = 48000; // /dev/dsp does need this set to 48000 to properly process the upsampling + opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; //switching in 'stereo' for 'mono' opts.dmr_mono = 1; @@ -1889,7 +1954,7 @@ main (int argc, char **argv) opts.frame_provoice = 0; opts.frame_ysf = 0; opts.frame_m17 = 0; - opts.pulse_digi_rate_out = 48000; + opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; state.dmr_stereo = 0; @@ -1911,7 +1976,7 @@ main (int argc, char **argv) opts.frame_provoice = 0; opts.frame_ysf = 0; opts.frame_m17 = 0; - opts.pulse_digi_rate_out = 48000; + opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; opts.dmr_mono = 0; @@ -1938,7 +2003,7 @@ main (int argc, char **argv) opts.mod_qpsk = 0; opts.mod_gfsk = 1; state.rf_mod = 2; - opts.pulse_digi_rate_out = 48000; + opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; opts.dmr_mono = 0; @@ -2112,7 +2177,7 @@ main (int argc, char **argv) opts.dmr_stereo = 1; opts.dmr_mono = 0; // opts.setmod_bw = 12000; //safe default on both DMR and P25 - opts.pulse_digi_rate_out = 24000; + opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 2; sprintf (opts.output_name, "XDMA"); fprintf (stderr,"Decoding XDMA P25 and DMR\n"); @@ -2134,7 +2199,7 @@ main (int argc, char **argv) opts.mod_qpsk = 0; opts.mod_gfsk = 0; state.rf_mod = 0; - opts.pulse_digi_rate_out = 48000; + opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; opts.dmr_mono = 0; @@ -2160,7 +2225,7 @@ main (int argc, char **argv) opts.mod_qpsk = 0; opts.mod_gfsk = 0; // state.rf_mod = 0; // - opts.pulse_digi_rate_out = 24000; + opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 2; opts.dmr_mono = 0; opts.dmr_stereo = 1; @@ -2190,7 +2255,7 @@ main (int argc, char **argv) opts.mod_qpsk = 0; opts.mod_gfsk = 0; state.rf_mod = 0; - opts.pulse_digi_rate_out = 48000; + opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; opts.dmr_stereo = 0; opts.dmr_mono = 0; @@ -2519,19 +2584,22 @@ main (int argc, char **argv) #endif } - //doesn't work correctly, so just going to reroute to /dev/dsp instead - // if((strncmp(opts.audio_in_dev, "udp", 3) == 0)) //udp socket input from SDR++, GQRX, and others - // { - // fprintf (stderr, "UDP Input not working, falling back to OSS /dev/dsp Audio Input.\n"); - // sprintf (opts.audio_in_dev, "%s", "/dev/dsp"); - // opts.audio_in_type = 5; - // } - int fmt; - int speed = 48000; + int speed; + //The long of the short is that PADSP can open multiple virtual /dev/dsp devices each with different sampling rates and channel configurations + //but the instance inside of Cygwin is a single instance tied to one sample rate AND one channel configuration, so if you change it on the output, it + //also changes on the input, and the way dsd handles this is to upsample output to make it work correctly, so if we were to make a true short stereo mix, + //we would have to handle upsampling for it as well in Cygwin (alternatively, find another output method, like RTAudio, or something else) - //NOTE: Both /dev/audio AND /dev/dsp randomly open multiple input streams in Linux under padsp wrapper + //It should be noted that Pulse Audio instances do not have this same issue, and can run at different input/rate and output/rate/channel configurations + + //TL:DR; the only reason /dev/dsp works as both input and output in Cygwin is because both input and output are exactly 1 channel - 48k + + //TODO: Test opening OSS input as 2-channel 48k, and see if we can read it in, if not, then double samplespersymble and center + //doing so will break the filters though + + speed = 48000; if((strncmp(opts.audio_in_dev, "/dev/audio", 10) == 0)) { sprintf (opts.audio_in_dev, "%s", "/dev/dsp"); @@ -2551,7 +2619,6 @@ main (int argc, char **argv) if (opts.audio_in_fd == -1) { fprintf (stderr, "Error, couldn't open %s\n", opts.audio_in_dev); - opts.audio_out = 0; } fmt = 0; @@ -2578,10 +2645,7 @@ main (int argc, char **argv) opts.audio_in_type = 5; //5 will become OSS input type } - //Codec2 only running at 8k output currently, need to match for OSS - if (opts.frame_m17 == 1) - speed = 8000; - + //check for OSS output if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0)) { sprintf (opts.audio_out_dev, "%s", "/dev/dsp"); @@ -2597,8 +2661,7 @@ main (int argc, char **argv) if((strncmp(opts.audio_out_dev, "/dev/dsp", 8) == 0)) { fprintf (stderr, "OSS Output %s.\n", opts.audio_out_dev); - opts.audio_out_fd = open (opts.audio_out_dev, O_RDWR); //O_WRONLY - opts.audio_out_fdR = open (opts.audio_out_dev, O_RDWR); + opts.audio_out_fd = open (opts.audio_out_dev, O_RDWR); if (opts.audio_out_fd == -1) { fprintf (stderr, "Error, couldn't open #1 %s\n", opts.audio_out_dev); @@ -2606,49 +2669,37 @@ main (int argc, char **argv) exit(1); } - if (opts.audio_out_fdR == -1) - { - fprintf (stderr, "Error, couldn't open #2 %s\n", opts.audio_out_dev); - opts.audio_out = 0; - exit(1); - } fmt = 0; if (ioctl (opts.audio_out_fd, SNDCTL_DSP_RESET) < 0) { fprintf (stderr, "ioctl reset error \n"); } - if (ioctl (opts.audio_out_fdR, SNDCTL_DSP_RESET) < 0) - { - fprintf (stderr, "ioctl reset error \n"); - } + fmt = speed; if (ioctl (opts.audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0) { fprintf (stderr, "ioctl speed error \n"); } - if (ioctl (opts.audio_out_fdR, SNDCTL_DSP_SPEED, &fmt) < 0) - { - fprintf (stderr, "ioctl speed error \n"); - } - fmt = 0; + + fmt = 0; //this seems okay to be 1 or 0, not sure what the difference really is (works in stereo on 0) if (ioctl (opts.audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0) { fprintf (stderr, "ioctl stereo error \n"); } - if (ioctl (opts.audio_out_fdR, SNDCTL_DSP_STEREO, &fmt) < 0) - { - fprintf (stderr, "ioctl stereo error \n"); - } + fmt = AFMT_S16_LE; if (ioctl (opts.audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0) { fprintf (stderr, "ioctl setfmt error \n"); } - if (ioctl (opts.audio_out_fdR, SNDCTL_DSP_SETFMT, &fmt) < 0) - { - fprintf (stderr, "ioctl setfmt error \n"); - } - + + //setup for one or two-channel configuration -- OSS -- cygwin OSS does not like this at all, even when set to 1 + // fmt = opts.pulse_digi_out_channels; //number of channels is also be a problem for Cygwin... + // if (ioctl (opts.audio_out_fd, SNDCTL_DSP_CHANNELS, &fmt) < 0) + // { + // fprintf (stderr, "ioctl channels error \n"); + // } + opts.audio_out_type = 5; //5 will become OSS output type } @@ -2668,19 +2719,19 @@ main (int argc, char **argv) opts.audio_out = 0; //turn off so we won't playSynthesized } - if (opts.playfiles == 1) + if((strncmp(opts.audio_out_dev, "-", 1) == 0)) + { + opts.audio_out_fd = fileno(stdout); //STDOUT_FILENO; + opts.audio_out_type = 1; //using 1 for stdout to match input stdin as 1 + fprintf(stderr, "Audio Out Device: -\n"); + } + + if (opts.playfiles == 1) //redo? { opts.split = 1; opts.playoffset = 0; opts.playoffsetR = 0; opts.delay = 0; - - //open wav file should be handled directly by the -w switch now - // if (strlen(opts.wav_out_file) > 0 && opts.dmr_stereo_wav == 0) - // { - // openWavOutFile (&opts, &state); - // } - opts.pulse_digi_rate_out = 48000; opts.pulse_digi_out_channels = 1; if (opts.audio_out_type == 0) openPulseOutput(&opts); @@ -2709,11 +2760,10 @@ main (int argc, char **argv) else { opts.split = 0; - opts.playoffset = 0; //not sure what the playoffset actually does for us + opts.playoffset = 0; opts.playoffsetR = 0; opts.delay = 0; openAudioInDevice (&opts); - // opts.audio_out_fd = opts.audio_in_fd; //not sure that this really does much anymore, other than cause problems } signal(SIGINT, handler); @@ -2727,6 +2777,8 @@ main (int argc, char **argv) else { + //debug + fprintf (stderr, "AIT: %d AOT: %d RATE: %d GAIN: %f \n", opts.audio_in_type, opts.audio_out_type, opts.pulse_digi_rate_out, state.aout_gain); liveScanner (&opts, &state); } diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index 6969aa1..0b7ac08 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -24,11 +24,11 @@ void keyring(dsd_opts * opts, dsd_state * state) { UNUSED(opts); - if (state->currentslot == 0) - state->R = state->rkey_array[state->payload_keyid]; + if (state->currentslot == 0) + state->R = state->rkey_array[state->payload_keyid]; - if (state->currentslot == 1) - state->RR = state->rkey_array[state->payload_keyidR]; + if (state->currentslot == 1) + state->RR = state->rkey_array[state->payload_keyidR]; } void RC4(int drop, uint8_t keylength, uint8_t messagelength, uint8_t key[], uint8_t cipher[], uint8_t plain[]) @@ -528,7 +528,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t rckey[9] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key - 0x00, 0x00, 0x00, 0x00}; // <- MI + 0x00, 0x00, 0x00, 0x00}; // <- MI //easier to manually load up rather than make a loop rckey[0] = ((state->R & 0xFF00000000) >> 32); @@ -606,8 +606,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t rckey[13] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key - 0x00, 0x00, 0x00, 0x00, 0x00, // <- MI - 0x00, 0x00, 0x00}; // <- MI cont. + 0x00, 0x00, 0x00, 0x00, 0x00, // <- MI + 0x00, 0x00, 0x00}; // <- MI cont. //easier to manually load up rather than make a loop rckey[0] = ((state->R & 0xFF00000000) >> 32); @@ -811,21 +811,21 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a //DMR RC4, Slot 2 if (state->currentslot == 1 && state->payload_algidR == 0x21 && state->RR != 0) { - uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t rckey[9] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key - 0x00, 0x00, 0x00, 0x00}; // <- MI + uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t rckey[9] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key + 0x00, 0x00, 0x00, 0x00}; // <- MI - //easier to manually load up rather than make a loop - rckey[0] = ((state->RR & 0xFF00000000) >> 32); - rckey[1] = ((state->RR & 0xFF000000) >> 24); - rckey[2] = ((state->RR & 0xFF0000) >> 16); - rckey[3] = ((state->RR & 0xFF00) >> 8); - rckey[4] = ((state->RR & 0xFF) >> 0); - rckey[5] = ((state->payload_miR & 0xFF000000) >> 24); - rckey[6] = ((state->payload_miR & 0xFF0000) >> 16); - rckey[7] = ((state->payload_miR & 0xFF00) >> 8); - rckey[8] = ((state->payload_miR & 0xFF) >> 0); + //easier to manually load up rather than make a loop + rckey[0] = ((state->RR & 0xFF00000000) >> 32); + rckey[1] = ((state->RR & 0xFF000000) >> 24); + rckey[2] = ((state->RR & 0xFF0000) >> 16); + rckey[3] = ((state->RR & 0xFF00) >> 8); + rckey[4] = ((state->RR & 0xFF) >> 0); + rckey[5] = ((state->payload_miR & 0xFF000000) >> 24); + rckey[6] = ((state->payload_miR & 0xFF0000) >> 16); + rckey[7] = ((state->payload_miR & 0xFF00) >> 8); + rckey[8] = ((state->payload_miR & 0xFF) >> 0); // if (opts->payload == 1) // { @@ -891,8 +891,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t rckey[13] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key - 0x00, 0x00, 0x00, 0x00, 0x00, // <- MI - 0x00, 0x00, 0x00}; // <- MI cont. + 0x00, 0x00, 0x00, 0x00, 0x00, // <- MI + 0x00, 0x00, 0x00}; // <- MI cont. //easier to manually load up rather than make a loop rckey[0] = ((state->RR & 0xFF00000000) >> 32); @@ -1047,30 +1047,35 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } //end reverse mute test - #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output - //OSS Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other - if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstR == 16 || state->dmrburstR == 21) ) - { - opts->audio_out = 0; - preempt = 1; - if (opts->payload == 0) - fprintf (stderr, " *MUTED*"); - } - #endif + //No more Slot Pre-emption...ever + // #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output + // //OSS Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other + // if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstR == 16 || state->dmrburstR == 21) ) + // { + // opts->audio_out = 0; + // preempt = 1; + // if (opts->payload == 0) + // fprintf (stderr, " *MUTED*"); + // } + // #endif state->debug_audio_errors += state->errs2 + state->errs; if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0) { - if (opts->audio_out == 1) + if (opts->audio_out == 1 && opts->floating_point == 0 ) //&& opts->pulse_digi_rate_out == 8000 { processAudio(opts, state); } - if (opts->audio_out == 1) - { - playSynthesizedVoice (opts, state); - } + // if (opts->audio_out == 1) + // { + // playSynthesizedVoice (opts, state); + // } } + + memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); //these are for mono or FDMA where we don't need to buffer and wait for a stereo mix + // playSynthesizedVoiceFL (opts, state); //Float Left + } if (opts->dmr_stereo == 1 && state->currentslot == 1) @@ -1118,46 +1123,55 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } //end reverse mute test - #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output - //OSS Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other - if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstL == 16 || state->dmrburstL == 21) ) - { - opts->audio_out = 0; - preempt = 1; - if (opts->payload == 0) - fprintf (stderr, " *MUTED*"); - } - #endif + // #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output + // //OSS Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other + // if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstL == 16 || state->dmrburstL == 21) ) + // { + // opts->audio_out = 0; + // preempt = 1; + // if (opts->payload == 0) + // fprintf (stderr, " *MUTED*"); + // } + // #endif state->debug_audio_errorsR += state->errs2R + state->errsR; if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0) { - if (opts->audio_out == 1) + if (opts->audio_out == 1 && opts->floating_point == 0 ) //&& opts->pulse_digi_rate_out == 8000 { processAudioR(opts, state); } - if (opts->audio_out == 1) - { - playSynthesizedVoiceR (opts, state); - } + // if (opts->audio_out == 1) + // { + // playSynthesizedVoiceR (opts, state); + // } } + + memcpy (state->f_r, state->audio_out_temp_bufR, sizeof(state->f_r)); + // playSynthesizedVoiceFR (opts, state); //Float Right + } //if using anything but DMR Stereo, borrowing state->dmr_encL to signal enc or clear for other types if (opts->dmr_mono == 0 && opts->dmr_stereo == 0 && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) ) { state->debug_audio_errors += state->errs2 + state->errs; - if (opts->audio_out == 1) + if (opts->audio_out == 1 && opts->floating_point == 0 ) //&& opts->pulse_digi_rate_out == 8000 { processAudio(opts, state); } - if (opts->audio_out == 1) - { - playSynthesizedVoice (opts, state); - } + // if (opts->audio_out == 1) + // { + // playSynthesizedVoice (opts, state); + // } + // playSynthesizedVoiceFL (opts, state); + + memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); //P25p1 FDMA 8k/1 channel -f1 switch } + // playSynthesizedVoiceFS (opts, state); //Float Stereo Mix -- disable and move this later on + //if using anything but DMR Stereo, borrowing state->dmr_encL to signal enc or clear for other types if (opts->wav_out_f != NULL && opts->dmr_stereo == 0 && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0)) { diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index f875905..5c00115 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -9,6 +9,8 @@ * 2022-08 DSD-FME Florida Man Edition *-----------------------------------------------------------------------------*/ +//TODO: Simulate Tone by playing AMBE FF32D2D2D2D880 x 4 on call alert (NXDN Foreign Lady Chirp on End) + #include "dsd.h" #include "git_ver.h" @@ -2251,10 +2253,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (i == 5) printw (" %s ", "Aero Build"); if (i == 6) printw (" v2.1c (20230720) \n"); #elif ZDEV_BUILD - if (i == 5) printw (" %s ", "zDEV3 Build"); + if (i == 5) printw (" %s ", "Audio WIP "); if (i == 6) printw (" %s \n", GIT_TAG); #else - if (i == 5) printw (" %s ", "zDEV3 Build"); + if (i == 5) printw (" %s ", "Audio WIP"); if (i == 6) printw (" %s \n", GIT_TAG); #endif else printw ("\n"); @@ -2269,11 +2271,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) printw ("--Input Output----------------------------------------------------------------\n"); if (opts->audio_in_type == 0) { - printw ("| Pulse Audio Input: [%2i] kHz [%i] Channel\n", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels); + printw ("| Pulse Audio Input: %i kHz; %i Channel;\n", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels); } if (opts->audio_in_type == 5) { - printw ("| OSS Audio Input: [%2i] kHz [1] Channel\n", SAMPLE_RATE_IN/1000); + printw ("| OSS Audio Input: %i kHz; 1 Channel;\n", SAMPLE_RATE_IN/1000); } if (opts->audio_in_type == 4) { @@ -2311,14 +2313,17 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } if (opts->audio_out_type == 0) { - printw ("| Pulse Audio Output: [%2i] kHz [%i] Channel", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels); - if (state->audio_smoothing == 1) printw (" - Smoothing On"); + printw ("| Pulse Audio Output: %i kHz; %i Channel; Auto Gain: %.1f;", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels, state->aout_gain*2); + if (state->audio_smoothing == 1 && opts->floating_point == 0) printw (" Smoothing On;"); //only on short + if (opts->floating_point == 1) printw (" Floating Point;"); + printw (" \n"); } if (opts->audio_out_type == 5) { - printw ("| OSS Audio Output: [%2i] kHz [1] Channel", SAMPLE_RATE_OUT/1000); - if (state->audio_smoothing == 1) printw (" - Smoothing On"); + printw ("| OSS Audio Output: %i kHz; %d Channel; Auto Gain %.1f;", SAMPLE_RATE_OUT/1000, opts->pulse_digi_out_channels, state->aout_gain*2); + if (state->audio_smoothing == 1 && opts->floating_point == 0) printw (" Smoothing On;"); //nly on short + if (opts->floating_point == 1) printw (" Floating Point;"); printw (" \n"); } if (opts->monitor_input_audio == 1) @@ -2784,7 +2789,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } else if (lls == 0 || lls == 1) //P1 { - printw ("P25 P1 - [%05llX][%03llX][%03llX] RFSS: [%lld] SITE: [%lld] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid); + printw ("P25p1 - [%05llX][%03llX][%03llX] RFSS: [%lld] SITE: [%lld] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid); if (state->p25_cc_freq != 0) { printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000); @@ -2792,7 +2797,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } else if (lls == 35 || lls == 36) //P2 { - printw ("P25 P2 - [%05llX][%03llX][%03llX] RFSS: [%lld] SITE: [%lld] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid); + printw ("P25p2 - [%05llX][%03llX][%03llX] RFSS: [%lld] SITE: [%lld] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid); if (state->p2_wacn == 0 || state->p2_sysid == 0 || state->p2_cc == 0) { attron(COLOR_PAIR(2)); @@ -2834,11 +2839,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) printw ("%s | ", state->call_string[0]); printw ("%s ", DMRBusrtTypes[state->dmrburstL]); - #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output - // - if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21)) printw ("*M*"); - // - #endif + // #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output + // // + // if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21)) printw ("*M*"); + // // + // #endif printw ("\n"); @@ -3037,11 +3042,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) //THIS IS THE NEW ONE printw ("%s | ", state->call_string[1]); printw ("%s ", DMRBusrtTypes[state->dmrburstR]); - #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output - // - if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21) ) printw ("*M*"); - // - #endif + // #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output + // // + // if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && ( state->dmrburstL == 16 || state->dmrburstL == 21) && (state->dmrburstR == 16 || state->dmrburstR == 21) ) printw ("*M*"); + // // + // #endif printw ("\n"); printw ("| V XTRA | "); //10 spaces @@ -3484,6 +3489,24 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) ncursesMenu (opts, state); //just a quick test } + if (c == 43) //+ key, increment aout_gain + { + if (state->aout_gain < 50) + state->aout_gain++; + //probably won't use aout_gainR with new short and float systems + if (state->aout_gainR < 50) + state->aout_gainR++; + } + + if (c == 45) //- key, decrement aout_gain + { + if (state->aout_gain > 0) + state->aout_gain--; + //probably won't use aout_gainR with new short and float systems + if (state->aout_gainR > 0) + state->aout_gainR--; + } + if (c == 122) //'z' key, toggle payload to console { if (opts->payload == 1) opts->payload = 0; diff --git a/src/dsd_rigctl.c b/src/dsd_rigctl.c index 518dc26..8f21c06 100644 --- a/src/dsd_rigctl.c +++ b/src/dsd_rigctl.c @@ -279,4 +279,44 @@ void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency) sendto(handle, data, 5, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in)); close (handle); //close socket after sending. -} \ No newline at end of file +} + +// int udp_sock_con(dsd_opts * opts, dsd_state * state) +// { +// UNUSED(state); +// UNUSED(opts); + +// int handle, err; //convert handle and address to state variables +// handle = err = 0; +// unsigned short udp_port = 9999; +// struct sockaddr_in address; +// handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); +// if (handle != 0) +// { +// fprintf (stderr, " UDP Socket Error \n"); +// return (handle); +// } +// memset((char * ) & address, 0, sizeof(address)); +// address.sin_family = AF_INET; +// err = address.sin_addr.s_addr = inet_addr("127.0.0.1"); //make user configurable later +// if (err != 0) +// { +// fprintf (stderr, " UDP inet_addr Error \n"); +// return (err); +// } +// address.sin_port = htons(udp_port); +// if (err != 0) +// { +// fprintf (stderr, " UDP htons Error \n"); +// return (err); +// } +// // close (handle); //close socket after sending. //leave open for the blaster +// } + +// int udp_sock_send(dsd_opts * opts, dsd_state * state, short samp[320]) +// { +// UNUSED(state); +// UNUSED(opts); + +// sendto(handle, samp, 320, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in)); +// } \ No newline at end of file diff --git a/src/dsd_upsample2.c b/src/dsd_upsample2.c new file mode 100644 index 0000000..9aabd7b --- /dev/null +++ b/src/dsd_upsample2.c @@ -0,0 +1,259 @@ +#include "dsd.h" + +static const float fdmdv_os_filter48[48]= { + -3.55606818e-04, + -8.98615286e-04, + -1.40119781e-03, + -1.71713852e-03, + -1.56471179e-03, + -6.28128960e-04, + 1.24522223e-03, + 3.83138676e-03, + 6.41309478e-03, + 7.85893186e-03, + 6.93514929e-03, + 2.79361991e-03, + -4.51051400e-03, + -1.36671853e-02, + -2.21034939e-02, + -2.64084653e-02, + -2.31425052e-02, + -9.84218694e-03, + 1.40648474e-02, + 4.67316298e-02, + 8.39615986e-02, + 1.19925275e-01, + 1.48381174e-01, + 1.64097819e-01, + 1.64097819e-01, + 1.48381174e-01, + 1.19925275e-01, + 8.39615986e-02, + 4.67316298e-02, + 1.40648474e-02, + -9.84218694e-03, + -2.31425052e-02, + -2.64084653e-02, + -2.21034939e-02, + -1.36671853e-02, + -4.51051400e-03, + 2.79361991e-03, + 6.93514929e-03, + 7.85893186e-03, + 6.41309478e-03, + 3.83138676e-03, + 1.24522223e-03, + -6.28128960e-04, + -1.56471179e-03, + -1.71713852e-03, + -1.40119781e-03, + -8.98615286e-04, + -3.55606818e-04 +}; + + +//from CODEC2 +//float filter /* Generate using fir1(47,1/2) in Octave */ +static const float fdmdv_os_filter[48]= { + -0.0008215855034550382, + -0.0007833023901802921, + 0.001075563790768233, + 0.001199092367787555, + -0.001765309502928316, + -0.002055372115328064, + 0.002986877604154257, + 0.003462567920638414, + -0.004856570111126334, + -0.005563143845031497, + 0.007533613299748122, + 0.008563932468880897, + -0.01126857129039911, + -0.01280782411693687, + 0.01651443896361847, + 0.01894875110322284, + -0.02421604439474981, + -0.02845107338464062, + 0.03672973563400258, + 0.04542046150312214, + -0.06189165826716491, + -0.08721876380763803, + 0.1496157094199961, + 0.4497962274137046, + 0.4497962274137046, + 0.1496157094199961, + -0.08721876380763803, + -0.0618916582671649, + 0.04542046150312216, + 0.03672973563400257, + -0.02845107338464062, + -0.02421604439474984, + 0.01894875110322284, + 0.01651443896361848, + -0.01280782411693687, + -0.0112685712903991, + 0.008563932468880899, + 0.007533613299748123, + -0.005563143845031501, + -0.004856570111126346, + 0.003462567920638419, + 0.002986877604154259, + -0.002055372115328063, + -0.001765309502928318, + 0.001199092367787557, + 0.001075563790768233, + -0.0007833023901802925, + -0.0008215855034550383 +}; + +//produce 6 float samples (48k) for every 1 float sample (8k) +void upsampleF (float invalue, float prev, float outbuf[6]) +{ + + float c, d; + + c = prev; //may ned up needing storage for the prev value to prevent the high pitch 'ring' sound + d = invalue; + + // basic triangle interpolation + outbuf[0] = c = ((invalue * (float) 0.166) + (c * (float) 0.834)); + outbuf[1] = c = ((invalue * (float) 0.332) + (c * (float) 0.668)); + outbuf[2] = c = ((invalue * (float) 0.500) + (c * (float) 0.5)); + outbuf[3] = c = ((invalue * (float) 0.668) + (c * (float) 0.332)); + outbuf[4] = c = ((invalue * (float) 0.834) + (c * (float) 0.166)); + outbuf[5] = c = d; + prev = d; //shift prev to the last d value for the next repitition + + // fdmdv_os_filter48 + +} + +//produce 6 short samples (48k) for every 1 short sample (8k) +void upsampleS (short invalue, short prev, short outbuf[6]) +{ + + float c, d; + + c = prev; + d = invalue; + + // basic triangle interpolation + outbuf[0] = c = ((invalue * (float) 0.166) + (c * (float) 0.834)); + outbuf[1] = c = ((invalue * (float) 0.332) + (c * (float) 0.668)); + outbuf[2] = c = ((invalue * (float) 0.500) + (c * (float) 0.5)); + outbuf[3] = c = ((invalue * (float) 0.668) + (c * (float) 0.332)); + outbuf[4] = c = ((invalue * (float) 0.834) + (c * (float) 0.166)); + outbuf[5] = c = d; + prev = d; //shift prev to the last d value for the next repitition + +} + +// void fdmdv_8_to_48_short(short out48k[], short in8k[], int n) +// { +// int i,j,k,l; +// float acc; + +// //FDMDV_OS_TAPS_48K = 48 +// //FDMDV_OS_48 = 6 +// //unsure of what the n value would be, could be number of samples to process? + +// for(i=0; im17_enc != 0) +// { +// //process scrambler or AES-CTR decryption +// //(no AES-CTR right now, Scrambler should be easy enough) +// } + +// if (opts->payload == 1) +// { +// fprintf (stderr, "\n CODEC2: "); +// for (i = 0; i < 8; i++) +// fprintf (stderr, "%02X", voice1[i]); +// fprintf (stderr, " (1600)"); + +// fprintf (stderr, "\n A_DATA: "); //arbitrary data +// for (i = 0; i < 8; i++) +// fprintf (stderr, "%02X", voice2[i]); +// } + +// #ifdef USE_CODEC2 +// size_t nsam; +// nsam = 320; + +// short samp1[nsam]; +// memset (samp1, 0, sizeof(samp1)); + +// codec2_decode(state->codec2_1600, samp1, voice1); + +// if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio +// { +// pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL); +// } + +// if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS +// { +// write (opts->audio_out_fd, samp1, nsam*2); +// } + +// if (opts->audio_out_type == 1 && state->m17_enc == 0) //STDOUT +// { +// write (opts->audio_out_fd, samp1, nsam*2); +// } + +// //WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history +// if(opts->wav_out_f != NULL && state->m17_enc == 0) //WAV +// { +// sf_write_short(opts->wav_out_f, samp1, nsam); +// } + +// //TODO: Codec2 Raw file saving +// // if(mbe_out_dir) +// // { + +// // } + +// #endif + +// } + +// void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t payload[128]) +// { +// int i; +// unsigned char voice1[8]; +// unsigned char voice2[8]; + +// for (i = 0; i < 8; i++) +// { +// voice1[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+0], 8); +// voice2[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+64], 8); +// } + +// //TODO: Add some decryption methods +// if (state->m17_enc != 0) +// { +// //process scrambler or AES-CTR decryption +// //(no AES-CTR right now, Scrambler should be easy enough) +// } + +// if (opts->payload == 1) +// { +// fprintf (stderr, "\n CODEC2: "); +// for (i = 0; i < 8; i++) +// fprintf (stderr, "%02X", voice1[i]); +// fprintf (stderr, " (3200)"); + +// fprintf (stderr, "\n CODEC2: "); +// for (i = 0; i < 8; i++) +// fprintf (stderr, "%02X", voice2[i]); +// fprintf (stderr, " (3200)"); +// } + +// #ifdef USE_CODEC2 +// size_t nsam; +// nsam = 160; +// short samp1[nsam]; +// short samp2[nsam]; +// memset (samp1, 0, sizeof(samp1)); +// memset (samp2, 0, sizeof(samp2)); + +// short upsamp[nsam*6]; //having more than one causes a memory overflow issue +// // short upsamp3[nsam*6]; //having more than one causes a memory overflow issue +// short out[6]; +// short prev; +// int j; +// memset (upsamp, 0, sizeof(upsamp)); +// memset (out, 0, sizeof(out)); + +// //Still thinking codec2_decode causes a memory overflow +// codec2_decode(state->codec2_3200, samp1, voice1); +// codec2_decode(state->codec2_3200, samp2, voice2); + +// if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio +// { +// pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL); +// pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL); +// } + +// if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS +// { +// // write (opts->audio_out_fd, samp1, nsam*2); +// // write (opts->audio_out_fd, samp2, nsam*2); + +// //upsample to 48k and then play +// prev = samp1[0]; +// for (i = 0; i < 160; i++) +// { +// upsampleS (samp1[i], prev, out); +// for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j]; +// } +// write (opts->audio_out_fd, upsamp, nsam*2*6); +// prev = samp2[0]; +// for (i = 0; i < 160; i++) +// { +// upsampleS (samp2[i], prev, out); +// for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j]; +// } +// write (opts->audio_out_fd, upsamp, nsam*2*6); +// } + +// if (opts->audio_out_type == 1 && state->m17_enc == 0) //STDOUT +// { +// write (opts->audio_out_fd, samp1, nsam*2); +// write (opts->audio_out_fd, samp2, nsam*2); +// } + +// //WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history +// if(opts->wav_out_f != NULL && state->m17_enc == 0) //WAV +// { +// sf_write_short(opts->wav_out_f, samp1, nsam); +// sf_write_short(opts->wav_out_f, samp2, nsam); +// } + +// //TODO: Codec2 Raw file saving +// // if(mbe_out_dir) +// // { + +// // } + +// #endif + +// } + void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t payload[128]) { - //If payload is the same from the stream in this mode, I suppose we could use this area to parse - //or send off the remaining data to be handled or decoded , or just print out the raw data bytes - int i; - unsigned char voice1[8]; //codec2_bytes_per_frame + unsigned char voice1[8]; unsigned char voice2[8]; for (i = 0; i < 8; i++) @@ -321,42 +492,53 @@ void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t payload[1 fprintf (stderr, "%02X", voice1[i]); fprintf (stderr, " (1600)"); - fprintf (stderr, "\n LSDATA: "); //low speed data + fprintf (stderr, "\n A_DATA: "); //arbitrary data for (i = 0; i < 8; i++) fprintf (stderr, "%02X", voice2[i]); } #ifdef USE_CODEC2 size_t nsam; - nsam = 320; //codec2_samples_per_frame(state->codec2_1600); - - short samp1[nsam]; - // short samp2[nsam]; - memset (samp1, 0, sizeof(samp1)); - // memset (samp2, 0, sizeof(samp2)); + nsam = 320; + //converted to using allocated memory pointers to prevent the overflow issues + short * samp1 = malloc (sizeof(short) * nsam); + short * upsamp = malloc (sizeof(short) * nsam * 6); + short * out = malloc (sizeof(short) * 6); + short prev; + int j; codec2_decode(state->codec2_1600, samp1, voice1); - // codec2_decode(state->codec2_1600, samp2, voice2); - - if (opts->audio_out_type == 0 && state->m17_enc == 0) + if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio { pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL); - // pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL); } - if (opts->audio_out_type == 5 && state->m17_enc == 0) + if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS + { + // write (opts->audio_out_fd, samp1, nsam*2); + + //upsample to 48k and then play + prev = samp1[0]; + for (i = 0; i < 160; i++) + { + upsampleS (samp1[i], prev, out); + for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j]; + } + write (opts->audio_out_fd, upsamp, nsam*2*6); + + } + + if (opts->audio_out_type == 1 && state->m17_enc == 0) //STDOUT { write (opts->audio_out_fd, samp1, nsam*2); - // write (opts->audio_out_fd, samp2, nsam*2); } //WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history - if(opts->wav_out_f != NULL && state->m17_enc == 0) + if(opts->wav_out_f != NULL && state->m17_enc == 0) //WAV { sf_write_short(opts->wav_out_f, samp1, nsam); - // sf_write_short(opts->wav_out_f, samp2, nsam); } //TODO: Codec2 Raw file saving @@ -365,6 +547,10 @@ void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t payload[1 // } + free (samp1); + free (upsamp); + free (out); + #endif } @@ -372,7 +558,7 @@ void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t payload[1 void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t payload[128]) { int i; - unsigned char voice1[8]; //codec2_bytes_per_frame + unsigned char voice1[8]; unsigned char voice2[8]; for (i = 0; i < 8; i++) @@ -403,32 +589,55 @@ void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t payload[1 #ifdef USE_CODEC2 size_t nsam; - nsam = 160; //codec2_samples_per_frame(state->codec2_3200); - - short samp1[nsam]; - short samp2[nsam]; - memset (samp1, 0, sizeof(samp1)); - memset (samp2, 0, sizeof(samp2)); + nsam = 160; + //converted to using allocated memory pointers to prevent the overflow issues + short * samp1 = malloc (sizeof(short) * nsam); + short * samp2 = malloc (sizeof(short) * nsam); + short * upsamp = malloc (sizeof(short) * nsam * 6); + short * out = malloc (sizeof(short) * 6); + short prev; + int j; codec2_decode(state->codec2_3200, samp1, voice1); codec2_decode(state->codec2_3200, samp2, voice2); - - if (opts->audio_out_type == 0 && state->m17_enc == 0) + if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio { pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL); pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL); } - if (opts->audio_out_type == 5 && state->m17_enc == 0) + if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS + { + // write (opts->audio_out_fd, samp1, nsam*2); + // write (opts->audio_out_fd, samp2, nsam*2); + + //upsample to 48k and then play + prev = samp1[0]; + for (i = 0; i < 160; i++) + { + upsampleS (samp1[i], prev, out); + for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j]; + } + write (opts->audio_out_fd, upsamp, nsam*2*6); + prev = samp2[0]; + for (i = 0; i < 160; i++) + { + upsampleS (samp2[i], prev, out); + for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j]; + } + write (opts->audio_out_fd, upsamp, nsam*2*6); + } + + if (opts->audio_out_type == 1 && state->m17_enc == 0) //STDOUT { write (opts->audio_out_fd, samp1, nsam*2); write (opts->audio_out_fd, samp2, nsam*2); } //WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history - if(opts->wav_out_f != NULL && state->m17_enc == 0) + if(opts->wav_out_f != NULL && state->m17_enc == 0) //WAV { sf_write_short(opts->wav_out_f, samp1, nsam); sf_write_short(opts->wav_out_f, samp2, nsam); @@ -440,6 +649,11 @@ void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t payload[1 // } + free (samp1); + free (samp2); + free (upsamp); + free (out); + #endif } @@ -618,11 +832,11 @@ void processM17LSF(dsd_opts * opts, dsd_state * state) //NOTE2: Even with the preamble detection and LSF sync, we still get bad decode on this int i, j, k, x; - uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits) - uint8_t m17_rnd_bits[500]; //368 bits that are still scrambled (randomized) - uint8_t m17_int_bits[500]; //368 bits that are still interleaved - uint8_t m17_bits[500]; //368 bits that have been de-interleaved and de-scramble - uint8_t m17_depunc[500]; //488 bits after depuncturing + uint8_t dbuf[184]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits) + uint8_t m17_rnd_bits[368]; //368 bits that are still scrambled (randomized) + uint8_t m17_int_bits[368]; //368 bits that are still interleaved + uint8_t m17_bits[368]; //368 bits that have been de-interleaved and de-scramble + uint8_t m17_depunc[488]; //488 bits after depuncturing memset (dbuf, 0, sizeof(dbuf)); memset (m17_rnd_bits, 0, sizeof(m17_rnd_bits)); @@ -659,7 +873,7 @@ void processM17LSF(dsd_opts * opts, dsd_state * state) for (i = 0; i < 488; i++) { if (p1[k++] == 1) m17_depunc[x++] = m17_bits[j++]; - else m17_depunc[x++] = 1; + else m17_depunc[x++] = 0; if (k == 61) k = 0; //61 -- should reset 8 times againt the array @@ -669,11 +883,11 @@ void processM17LSF(dsd_opts * opts, dsd_state * state) // fprintf (stderr, "K = %d; J = %d; X = %d", k, j, x); //setup the convolutional decoder - uint8_t temp[500]; + uint8_t temp[488]; uint8_t s0; uint8_t s1; - uint8_t m_data[32]; - uint8_t trellis_buf[400]; + uint8_t m_data[30]; + uint8_t trellis_buf[244]; memset (trellis_buf, 0, sizeof(trellis_buf)); memset (temp, 0, sizeof (temp)); memset (m_data, 0, sizeof (m_data)); diff --git a/src/nxdn_voice.c b/src/nxdn_voice.c index ecd0aa2..5041dbf 100644 --- a/src/nxdn_voice.c +++ b/src/nxdn_voice.c @@ -89,6 +89,13 @@ void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182 } processMbeFrame (opts, state, NULL, ambe_fr, NULL); + + memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); + + if (opts->floating_point == 0) + playSynthesizedVoice(opts, state); + if (opts->floating_point == 1) + playSynthesizedVoiceFM(opts, state); } if (opts->payload == 1) diff --git a/src/p25p1_ldu1.c b/src/p25p1_ldu1.c index f92d221..550ceb6 100644 --- a/src/p25p1_ldu1.c +++ b/src/p25p1_ldu1.c @@ -59,12 +59,29 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '0'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); // IMBE 2 #ifdef TRACE_DSD state->debug_prefix_2 = '1'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 2 read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -77,6 +94,15 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '2'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 3 read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -89,6 +115,15 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '3'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 4 read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -101,6 +136,15 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '4'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 5 read_and_correct_hex_word (opts, state, &(hex_parity[11][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_parity[10][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -113,6 +157,15 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '5'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 6 read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -125,6 +178,15 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '6'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 7 read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -137,6 +199,14 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '7'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); // Read data after IMBE 8: LSD (low speed data) { @@ -180,6 +250,14 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '8'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); if (opts->errorbars == 1) { diff --git a/src/p25p1_ldu2.c b/src/p25p1_ldu2.c index b3e655f..ee8b32a 100644 --- a/src/p25p1_ldu2.c +++ b/src/p25p1_ldu2.c @@ -63,12 +63,29 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '0'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); // IMBE 2 #ifdef TRACE_DSD state->debug_prefix_2 = '1'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 2 read_and_correct_hex_word (opts, state, &(hex_data[15][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[14][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -81,6 +98,15 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '2'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 3 read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -93,6 +119,15 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '3'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 4 read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -105,6 +140,15 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '4'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 5 read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -117,6 +161,15 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '5'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 6 read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -129,6 +182,13 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '6'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 7 read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -141,6 +201,15 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '7'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + // Read data after IMBE 8: LSD (low speed data) { char lsd[8]; @@ -183,6 +252,14 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '8'; #endif process_IMBE (opts, state, &status_count); + if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(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) + playSynthesizedVoiceFM(opts, state); + if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); //set vc counter to 0 state->p25vc = 0; diff --git a/src/p25p2_frame.c b/src/p25p2_frame.c index c8f9d7c..68fe65d 100644 --- a/src/p25p2_frame.c +++ b/src/p25p2_frame.c @@ -480,20 +480,71 @@ void process_4V (dsd_opts * opts, dsd_state * state) fprintf (stderr, "\n"); } - #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output - //Cygwin OSS Slot Preference Pre-emption shim - if (opts->audio_out_type == 5) - { - //set to 21 for MBE OSS shim to preempt audio - if (state->currentslot == 0) state->dmrburstL = 21; - else state->dmrburstR = 21; - } - #endif + // #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output + // //Cygwin OSS Slot Preference Pre-emption shim + // if (opts->audio_out_type == 5) + // { + // //set to 21 for MBE OSS shim to preempt audio + // if (state->currentslot == 0) state->dmrburstL = 21; + // else state->dmrburstR = 21; + // } + // #endif processMbeFrame (opts, state, NULL, ambe_fr1, NULL); + if(state->currentslot == 0) + { + memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu)); + } + else + { + memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR)); + memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru)); + } + processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + if(state->currentslot == 0) + { + memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu)); + } + else + { + memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR)); + memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru)); + } + processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + if(state->currentslot == 0) + { + memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu)); + } + else + { + memcpy(state->f_r4[2], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR)); + memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru)); + } + processMbeFrame (opts, state, NULL, ambe_fr4, NULL); + if(state->currentslot == 0) + { + memcpy(state->f_l4[3], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[3], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[3], state->s_lu, sizeof(state->s_lu)); + } + else + { + memcpy(state->f_r4[3], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR)); + memcpy(state->s_r4[3], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[3], state->s_ru, sizeof(state->s_ru)); + } } @@ -647,18 +698,44 @@ void process_2V (dsd_opts * opts, dsd_state * state) fprintf (stderr, "\n"); } - #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output - //Cygwin OSS Slot Preference Pre-emption shim - if (opts->audio_out_type == 5) - { - //set to 21 for MBE OSS shim to preempt audio - if (state->currentslot == 0) state->dmrburstL = 21; - else state->dmrburstR = 21; - } - #endif + // #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output + // //Cygwin OSS Slot Preference Pre-emption shim + // if (opts->audio_out_type == 5) + // { + // //set to 21 for MBE OSS shim to preempt audio + // if (state->currentslot == 0) state->dmrburstL = 21; + // else state->dmrburstR = 21; + // } + // #endif processMbeFrame (opts, state, NULL, ambe_fr1, NULL); + if(state->currentslot == 0) + { + memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu)); + } + else + { + memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR)); + memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru)); + } + processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + if(state->currentslot == 0) + { + memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf)); + memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l)); + memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu)); + + } + else + { + memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR)); + memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru)); + } process_ESS(opts, state); @@ -696,7 +773,7 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state) for (ts_counter = 0; ts_counter < 4; ts_counter++) //12 { - + int sacch = 0; p2_duid[0] = p2bit[0+(ts_counter*360)]; p2_duid[1] = p2bit[1+(ts_counter*360)]; p2_duid[2] = p2bit[74+(ts_counter*360)]; @@ -706,7 +783,7 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state) p2_duid[6] = p2bit[318+(ts_counter*360)]; p2_duid[7] = p2bit[319+(ts_counter*360)]; - //process p2_duid with (8,4,4) encoding/decoding + //process p2_duid with (8,4,4) encoding/decoding (hamming?) int p2_duid_complete = 0; for (int i = 0; i < 8; i++) { @@ -738,7 +815,11 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state) if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_fR == NULL)) openMbeOutFileR (opts, state); } } - else fprintf (stderr, "VCH S "); + else + { + sacch = 1; + fprintf (stderr, "VCH S "); + } //check to see when last voice activity occurred in order to allow tuning on phase 2 //mac_signal or mac_idle when no more voice activity on current channel @@ -843,6 +924,19 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state) //add 360 bits to each counter vc_counter = vc_counter + 360; + //WIP: The skip issue was fixed with this check and also with a check to play the extra samples on a 2V + if (sacch == 0 && ts_counter & 1 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000) //this should be a real TS value %2 and non-inverted frames, so 0-9, need a way to get real TS number each go around + playSynthesizedVoiceFS4 (opts, state); + + if (sacch == 0 && ts_counter & 1 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 48000) //this should be a real TS value %2 and non-inverted frames, so 0-9, need a way to get real TS number each go around + playSynthesizedVoiceFS4_48k (opts, state); + + if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //this should be a real TS value %2 and non-inverted frames, so 0-9, need a way to get real TS number each go around + playSynthesizedVoiceSS4 (opts, state); + + if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 48000) //this should be a real TS value %2 and non-inverted frames, so 0-9, need a way to get real TS number each go around + playSynthesizedVoiceSS4_48k (opts, state); + //flip slots after each TS processed if (state->currentslot == 0) { @@ -886,6 +980,7 @@ void processP2 (dsd_opts * opts, dsd_state * state) //process DUID will run through all collected frames and handle them appropriately process_P2_DUID (opts, state); + state->dmr_stereo = 0; state->p2_is_lcch = 0; diff --git a/src/ysf.c b/src/ysf.c index 384a54e..4622d38 100644 --- a/src/ysf.c +++ b/src/ysf.c @@ -729,6 +729,32 @@ void ysf_ehr (dsd_opts * opts, dsd_state * state, uint8_t dbuf[180], int start, processMbeFrame (opts, state, NULL, ambe_fr, NULL); + if (opts->floating_point == 0) + { + // processAudio(opts, state); //needed here? -- nothign to test it with + + if (opts->wav_out_f != NULL) + writeSynthesizedVoice (opts, state); + + if (opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(opts, state); + + if(opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceSS(opts, state); + } + + if (opts->floating_point == 1) //float audio is really quiet now (look into it) + { + + memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); + + if (opts->pulse_digi_out_channels == 1) + playSynthesizedVoiceFM(opts, state); + + if(opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + } + } if (opts->payload == 1) @@ -986,18 +1012,37 @@ void processYSF(dsd_opts * opts, dsd_state * state) state->errs2 = vech_bits[103]; //should be zero, but if it isn't, then its an error + state->debug_audio_errors += state->errs2; + mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); if (opts->payload == 1) PrintAMBEData (opts, state, ambe_d); - processAudio(opts, state); - - if (opts->wav_out_f != NULL) - writeSynthesizedVoice (opts, state); + if (opts->floating_point == 0) + { + processAudio(opts, state); - playSynthesizedVoice (opts, state); + if (opts->wav_out_f != NULL) + writeSynthesizedVoice (opts, state); + if (opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(opts, state); + + if(opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceSS(opts, state); + } + + if (opts->floating_point == 1) + { + memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); + + if (opts->pulse_digi_out_channels == 1) + playSynthesizedVoiceFM(opts, state); + + if(opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + } } @@ -1094,6 +1139,32 @@ void processYSF(dsd_opts * opts, dsd_state * state) processMbeFrame(opts, state, imbe_fr, NULL, NULL); state->synctype = st; + if (opts->floating_point == 0) + { + // processAudio(opts, state); //needed here? -- seems to be running from within mbelib + + if (opts->wav_out_f != NULL) + writeSynthesizedVoice (opts, state); + + if (opts->pulse_digi_out_channels == 1) + playSynthesizedVoice(opts, state); + + if(opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceSS(opts, state); + } + + if (opts->floating_point == 1) //float audio is really quiet now (look into it) + { + + memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); + + if (opts->pulse_digi_out_channels == 1) + playSynthesizedVoiceFM(opts, state); + + if(opts->pulse_digi_out_channels == 2) + playSynthesizedVoiceFS(opts, state); + } + } if (ft == 1 && fn == 0)