From 9acc0142749060892de1c326ce079a59b664c8a1 Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Wed, 27 Dec 2023 18:05:23 -0500 Subject: [PATCH] Patch - Even More TDMA (DMR/P2) Mono Stereo Tests; --- patch/enable_pref_slots_p2_trunking.patch | 319 ++++++++ patch/p25p2_superframe_18V_enc_check.patch | 769 ++++++++++++++++++ ...__mono_stereo_interleaving_enc_check.patch | 769 ++++++++++++++++++ 3 files changed, 1857 insertions(+) create mode 100644 patch/enable_pref_slots_p2_trunking.patch create mode 100644 patch/p25p2_superframe_18V_enc_check.patch create mode 100644 patch/wolf_p25p2_and_dmr__mono_stereo_interleaving_enc_check.patch diff --git a/patch/enable_pref_slots_p2_trunking.patch b/patch/enable_pref_slots_p2_trunking.patch new file mode 100644 index 0000000..4330110 --- /dev/null +++ b/patch/enable_pref_slots_p2_trunking.patch @@ -0,0 +1,319 @@ +diff --git a/src/p25p1_mdpu.c b/src/p25p1_mdpu.c +index 7d29860..00c1828 100644 +--- a/src/p25p1_mdpu.c ++++ b/src/p25p1_mdpu.c +@@ -527,13 +527,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state) + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (channelt & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + + } +@@ -644,13 +644,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state) + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (channelt & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + + } +@@ -753,13 +753,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state) + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (channel & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + } + +@@ -876,13 +876,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state) + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (channelt & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + + } +diff --git a/src/p25p1_tsbk.c b/src/p25p1_tsbk.c +index c801b7f..345335a 100644 +--- a/src/p25p1_tsbk.c ++++ b/src/p25p1_tsbk.c +@@ -294,13 +294,13 @@ void processTSBK(dsd_opts * opts, dsd_state * state) + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (channel & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + + } +diff --git a/src/p25p2_vpdu.c b/src/p25p2_vpdu.c +index 468b71a..1b14d71 100644 +--- a/src/p25p2_vpdu.c ++++ b/src/p25p2_vpdu.c +@@ -75,8 +75,6 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + + //Temp Fix: Disable Slot Playback when MAC_SIGNAL present (good CRC), + //during trunking, will re-enable when call grant is received, prevent lagging: +- if (opts->p25_trunk == 1 && opts->p25_is_tuned == 0) opts->slot1_on = 0; +- if (opts->p25_trunk == 1 && opts->p25_is_tuned == 0) opts->slot2_on = 0; + + //TODO: Iron out issues with audio playing in every non SACCH slot when no voice present + //without it stuttering during actual voice +@@ -156,13 +154,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (channel & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + + } +@@ -256,13 +254,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (channel & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + + } +@@ -387,13 +385,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (tunable_chan & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + + } +@@ -512,13 +510,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (channel & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + + } +@@ -643,13 +641,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (channel & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + } + +@@ -749,13 +747,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (channel & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + } + +@@ -919,13 +917,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (tunable_chan & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + + } +@@ -1110,13 +1108,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (tunable_chan & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + + } +@@ -1246,13 +1244,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (tunable_chan & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + + } +@@ -1375,13 +1373,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (channelt & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + + } +@@ -1498,13 +1496,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + //this will only occur in realtime tuning, not not required .bin or .wav playback + if (channelt & 1) //VCH1 + { +- opts->slot1_on = 0; +- opts->slot2_on = 1; ++ //opts->slot1_on = 0; ++ opts->slot_preference = 1; + } + else //VCH0 + { +- opts->slot1_on = 1; +- opts->slot2_on = 0; ++ opts->slot_preference = 0; ++ //opts->slot2_on = 0; + } + } + +@@ -1516,9 +1514,6 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + opts->frame_p25p1 = 1; //enable, just in case it isn't already +- +- //enable voice on slot 1 (just in case they start talking too, but probably won't) +- opts->slot1_on = 1; + } + + } diff --git a/patch/p25p2_superframe_18V_enc_check.patch b/patch/p25p2_superframe_18V_enc_check.patch new file mode 100644 index 0000000..6aa180a --- /dev/null +++ b/patch/p25p2_superframe_18V_enc_check.patch @@ -0,0 +1,769 @@ +diff --git a/include/dsd.h b/include/dsd.h +index 0b47dee..f459528 100644 +--- a/include/dsd.h ++++ b/include/dsd.h +@@ -437,8 +437,8 @@ typedef struct + //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 ++ short s_l4[36][160]; //quad sample for up to a P25p2 4V ++ short s_r4[36][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 +@@ -654,6 +654,7 @@ typedef struct + int p2_vch_chan_num; //vch channel number (0 or 1, not the 0-11 TS) + int ess_b[2][96]; //external storage for ESS_B fragments + int fourv_counter[2]; //external reference counter for ESS_B fragment collection ++ int voice_counter[2]; //external reference counter for 18V x 2 P25p2 Superframe + int p2_is_lcch; //flag to tell us when a frame is lcch and not sacch + + //iden freq storage for frequency calculations +@@ -926,6 +927,7 @@ void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot); //floa + void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state); //short stereo mix + void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state); //short stereo mix 3v2 DMR + void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state); //short stereo mix 4v2 P25p2 ++void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state); //short stereo mix 18V Superframe + void upsampleS (short invalue, short prev, short outbuf[6]); //upsample 8k to 48k short + // + void openAudioOutDevice (dsd_opts * opts, int speed); +diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c +index a836afc..5eaf3c4 100644 +--- a/src/dsd_audio2.c ++++ b/src/dsd_audio2.c +@@ -906,8 +906,31 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state) + //CHEAT: Using the slot on/off, use that to set encL or encR back on + //as a simple way to turn off voice synthesis in a particular slot + //its not really 'disabled', we just aren't playing it +- if (opts->slot1_on == 0) encL = 1; +- if (opts->slot2_on == 0) encR = 1; ++ // if (opts->slot1_on == 0) encL = 1; ++ // if (opts->slot2_on == 0) encR = 1; ++ ++ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only ++ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default ++ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well ++ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (opts->slot_preference == 0 && state->dmrburstL == 16 && encL == 0) //slot 1 is preferred, and voice in slot 1 ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (opts->slot_preference == 1 && state->dmrburstR == 16 && encR == 0) //slot 2 is preferred, and voice in slot 2 ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ else if (state->dmrburstL == 16 && state->dmrburstR != 16 && encL == 0) //voice in left, no voice in right ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (state->dmrburstR == 16 && state->dmrburstL != 16 && encR == 0) //voice in right, no voice in left ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels) ++ ++ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback ++ { ++ encL = 1; ++ encR = 1; ++ } + + //WIP: Mute if on B list (or not W list) + char modeL[8]; +@@ -944,12 +967,37 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state) + if (strcmp(modeL, "B") == 0) encL = 1; + if (strcmp(modeR, "B") == 0) encR = 1; + ++ //check to see if we need to enable slot and toggle slot preference here ++ //this method will always favor slot 2 (this is a patch anyways, so....meh) ++ if (strcmp(modeL, "A") == 0) ++ { ++ opts->slot1_on = 1; ++ opts->slot_preference = 0; ++ } ++ if (strcmp(modeR, "A") == 0) ++ { ++ opts->slot2_on = 1; ++ opts->slot_preference = 1; ++ } ++ + //if TG Hold in place, mute anything but that TG #132 +- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1; +- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1; +- //likewise, override and unmute if TG hold matches TG +- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0; +- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0; ++ if (state->tg_hold != 0 && state->tg_hold != TGL) ++ encL = 1; ++ if (state->tg_hold != 0 && state->tg_hold != TGR) ++ encR = 1; ++ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference) ++ if (state->tg_hold != 0 && state->tg_hold == TGL) ++ { ++ encL = 0; ++ opts->slot1_on = 1; ++ opts->slot_preference = 0; ++ } ++ if (state->tg_hold != 0 && state->tg_hold == TGR) ++ { ++ encR = 0; ++ opts->slot2_on = 1; ++ opts->slot_preference = 1; ++ } + + //interleave left and right channels from the short storage area + for (i = 0; i < 160; i++) +@@ -1092,8 +1140,31 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state) + //CHEAT: Using the slot on/off, use that to set encL or encR back on + //as a simple way to turn off voice synthesis in a particular slot + //its not really 'disabled', we just aren't playing it +- if (opts->slot1_on == 0) encL = 1; +- if (opts->slot2_on == 0) encR = 1; ++ // if (opts->slot1_on == 0) encL = 1; ++ // if (opts->slot2_on == 0) encR = 1; ++ ++ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only ++ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default ++ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well ++ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1 ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2 ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels) ++ ++ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback ++ { ++ encL = 1; ++ encR = 1; ++ } + + //WIP: Mute if on B list (or not W list) + char modeL[8]; +@@ -1130,12 +1201,37 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state) + if (strcmp(modeL, "B") == 0) encL = 1; + if (strcmp(modeR, "B") == 0) encR = 1; + ++ //check to see if we need to enable slot and toggle slot preference here ++ //this method will always favor slot 2 (this is a patch anyways, so....meh) ++ if (strcmp(modeL, "A") == 0) ++ { ++ opts->slot1_on = 1; ++ opts->slot_preference = 0; ++ } ++ if (strcmp(modeR, "A") == 0) ++ { ++ opts->slot2_on = 1; ++ opts->slot_preference = 1; ++ } ++ + //if TG Hold in place, mute anything but that TG #132 +- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1; +- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1; +- //likewise, override and unmute if TG hold matches TG +- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0; +- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0; ++ if (state->tg_hold != 0 && state->tg_hold != TGL) ++ encL = 1; ++ if (state->tg_hold != 0 && state->tg_hold != TGR) ++ encR = 1; ++ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference) ++ if (state->tg_hold != 0 && state->tg_hold == TGL) ++ { ++ encL = 0; ++ opts->slot1_on = 1; ++ opts->slot_preference = 0; ++ } ++ if (state->tg_hold != 0 && state->tg_hold == TGR) ++ { ++ encR = 0; ++ opts->slot2_on = 1; ++ opts->slot_preference = 1; ++ } + + //interleave left and right channels from the short storage area + for (i = 0; i < 160; i++) +@@ -1238,6 +1334,226 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state) + + } + ++//short stereo mix 18v superframe ++void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state) ++{ ++ ++ //NOTE: This will run once every superframe during a sacch field ++ //exact implementation to be determined ++ ++ int i, j; ++ uint8_t encL, encR; ++ ++ short stereo_sf[18][320]; //8k 2-channel stereo interleave mix for full superframe ++ // memset (stereo_sf, 1, 18*sizeof(short)); //I don't think 18*sizeof(short) was large enough, should probably be 18*320*sizeof(short) ++ memset (stereo_sf, 1, sizeof(stereo_sf)); ++ ++ short empty[320]; ++ 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 ++ ++ //CHEAT: Using the slot on/off, use that to set encL or encR back on ++ //as a simple way to turn off voice synthesis in a particular slot ++ //its not really 'disabled', we just aren't playing it ++ // if (opts->slot1_on == 0) encL = 1; ++ // if (opts->slot2_on == 0) encR = 1; ++ ++ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only ++ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default ++ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well ++ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1 ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2 ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels) ++ ++ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback ++ { ++ encL = 1; ++ encR = 1; ++ } ++ ++ //WIP: Mute if on B list (or not W list) ++ char modeL[8]; ++ sprintf (modeL, "%s", ""); ++ char modeR[8]; ++ sprintf (modeR, "%s", ""); ++ ++ int TGL = state->lasttg; ++ int TGR = state->lasttgR; ++ ++ //if we are using allow/whitelist mode, then write 'B' to mode for block ++ //comparison below will look for an 'A' to write to mode if it is allowed ++ if (opts->trunk_use_allow_list == 1) ++ { ++ sprintf (modeL, "%s", "B"); ++ sprintf (modeR, "%s", "B"); ++ } ++ ++ for (i = 0; i < state->group_tally; i++) ++ { ++ if (state->group_array[i].groupNumber == TGL) ++ { ++ strcpy (modeL, state->group_array[i].groupMode); ++ // break; //need to keep going to check other potential slot group ++ } ++ if (state->group_array[i].groupNumber == TGR) ++ { ++ strcpy (modeR, state->group_array[i].groupMode); ++ // break; //need to keep going to check other potential slot group ++ } ++ } ++ ++ //flag either left or right as 'enc' to mute if B ++ if (strcmp(modeL, "B") == 0) encL = 1; ++ if (strcmp(modeR, "B") == 0) encR = 1; ++ ++ //check to see if we need to enable slot and toggle slot preference here ++ //this method will always favor slot 2 (this is a patch anyways, so....meh) ++ if (strcmp(modeL, "A") == 0) ++ { ++ opts->slot1_on = 1; ++ opts->slot_preference = 0; ++ } ++ if (strcmp(modeR, "A") == 0) ++ { ++ opts->slot2_on = 1; ++ opts->slot_preference = 1; ++ } ++ ++ //if TG Hold in place, mute anything but that TG #132 ++ if (state->tg_hold != 0 && state->tg_hold != TGL) ++ encL = 1; ++ if (state->tg_hold != 0 && state->tg_hold != TGR) ++ encR = 1; ++ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference) ++ if (state->tg_hold != 0 && state->tg_hold == TGL) ++ { ++ encL = 0; ++ opts->slot1_on = 1; ++ opts->slot_preference = 0; ++ } ++ if (state->tg_hold != 0 && state->tg_hold == TGR) ++ { ++ encR = 0; ++ opts->slot2_on = 1; ++ opts->slot_preference = 1; ++ } ++ ++ //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions ++ if (encL && encR) ++ goto SS18_END; ++ ++ //interleave left and right channels from the short storage area ++ for (j = 0; j < 18; j++) ++ { ++ for (i = 0; i < 160; i++) ++ { ++ if (!encL) ++ stereo_sf[j][i*2+0] = state->s_l4[j][i]; ++ if (!encR) ++ stereo_sf[j][i*2+1] = state->s_r4[j][i]; ++ } ++ } ++ ++ if (opts->audio_out_type == 0) //Pulse Audio ++ { ++ for (j = 0; j < 18; j++) ++ { ++ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely ++ pa_simple_write(opts->pulse_digi_dev_out, stereo_sf[j], 320*2, NULL); ++ } ++ } ++ ++ if (opts->audio_out_type == 8) //UDP Audio ++ { ++ for (j = 0; j < 18; j++) ++ { ++ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely ++ udp_socket_blaster (opts, state, 320*2, stereo_sf[j]); ++ } ++ } ++ ++ ++ if (opts->audio_out_type == 1 || opts->audio_out_type == 2) //STDOUT or OSS 8k/2channel ++ { ++ for (j = 0; j < 18; j++) ++ { ++ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely ++ write (opts->audio_out_fd, stereo_sf[j], 320*2); ++ } ++ } ++ ++ SS18_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; ++ } ++ ++} ++ + //largely borrowed from Boatbod OP25 (simplified single tone ID version) + void soft_tonef (float samp[160], int n, int ID, int AD) + { +diff --git a/src/dsd_main.c b/src/dsd_main.c +index 1d2616b..02590a6 100644 +--- a/src/dsd_main.c ++++ b/src/dsd_main.c +@@ -382,6 +382,8 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5 + } + state->fourv_counter[0] = 0; + state->fourv_counter[1] = 0; ++ state->voice_counter[0] = 0; ++ state->voice_counter[1] = 0; + + //values displayed in ncurses terminal + // state->p25_vc_freq[0] = 0; +@@ -745,7 +747,7 @@ initOpts (dsd_opts * opts) + //slot preference is used during OSS audio playback to + //prefer one tdma voice slot over another when both are playing back + //this is a fix to OSS 48k/1 output +- opts->slot_preference = 0; //default prefer slot 1 -- state->currentslot = 0; ++ opts->slot_preference = 2; //default prefer slot 1 -- state->currentslot = 0; + + //hardset slots to synthesize + opts->slot1_on = 1; +@@ -941,6 +943,8 @@ initState (dsd_state * state) + } + state->fourv_counter[0] = 0; + state->fourv_counter[1] = 0; ++ state->voice_counter[0] = 0; ++ state->voice_counter[1] = 0; + + state->K = 0; + state->R = 0; +diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c +index 4646e77..fc3f28b 100644 +--- a/src/dsd_ncurses.c ++++ b/src/dsd_ncurses.c +@@ -2568,11 +2568,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + { + printw ("| Voice Error: [%i][%i] Slot 1 (1)", state->errs, state->errs2); + if (opts->slot1_on == 0) printw (" OFF"); +- if (opts->slot1_on == 1) printw (" ON"); ++ if (opts->slot1_on == 1) printw (" ON"); if (opts->slot_preference == 0) printw (" *Preferred"); + printw ("\n"); + printw ("| Voice Error: [%i][%i] Slot 2 (2)", state->errsR, state->errs2R); + if (opts->slot2_on == 0) printw (" OFF"); +- if (opts->slot2_on == 1) printw (" ON"); ++ if (opts->slot2_on == 1) printw (" ON"); if (opts->slot_preference == 1) printw (" *Preferred"); + printw ("\n"); + } + printw ("------------------------------------------------------------------------------\n"); +@@ -3654,8 +3654,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + //switching, but want to control each seperately plz + if (opts->slot1_on == 1) + { +- opts->slot1_on = 0; +- opts->slot_preference = 1; //slot 2 ++ opts->slot1_on = 0; if (opts->slot_preference == 0) opts->slot_preference = 2; ++ // opts->slot_preference = 1; //slot 2 + //clear any previously buffered audio + state->audio_out_float_buf_p = state->audio_out_float_buf + 100; + state->audio_out_buf_p = state->audio_out_buf + 100; +@@ -3680,8 +3680,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + //switching, but want to control each seperately plz + if (opts->slot2_on == 1) + { +- opts->slot2_on = 0; +- opts->slot_preference = 0; //slot 1 ++ opts->slot2_on = 0; if (opts->slot_preference == 1) opts->slot_preference = 2; ++ // opts->slot_preference = 0; //slot 1 + //clear any previously buffered audio + state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100; + state->audio_out_buf_pR = state->audio_out_bufR + 100; +@@ -3701,6 +3701,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + } + } + ++ if (c == 51) //'3' key, cycle slot preferences ++ { ++ if (opts->slot_preference < 2) ++ opts->slot_preference++; ++ else opts->slot_preference = 0; ++ } ++ + if (c == 43) //+ key, increment audio_gain + { + +diff --git a/src/p25p2_frame.c b/src/p25p2_frame.c +index c391eba..99a4840 100644 +--- a/src/p25p2_frame.c ++++ b/src/p25p2_frame.c +@@ -490,18 +490,27 @@ void process_4V (dsd_opts * opts, dsd_state * state) + // else state->dmrburstR = 21; + // } + // #endif ++ ++ //unsure of the best location for these counter resets ++ if (state->voice_counter[0] >= 18) ++ state->voice_counter[0] = 0; ++ ++ if (state->voice_counter[1] >= 18) ++ state->voice_counter[1] = 0; + + 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_l4[0], state->s_l, sizeof(state->s_l)); ++ memcpy(state->s_l4[(state->voice_counter[0]++)%18], 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_r4[0], state->s_r, sizeof(state->s_r)); ++ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru)); + } + +@@ -509,13 +518,15 @@ void process_4V (dsd_opts * opts, dsd_state * state) + 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_l4[1], state->s_l, sizeof(state->s_l)); ++ memcpy(state->s_l4[(state->voice_counter[0]++)%18], 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_r4[1], state->s_r, sizeof(state->s_r)); ++ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru)); + } + +@@ -523,13 +534,15 @@ void process_4V (dsd_opts * opts, dsd_state * state) + 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_l4[2], state->s_l, sizeof(state->s_l)); ++ memcpy(state->s_l4[(state->voice_counter[0]++)%18], 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_r4[2], state->s_r, sizeof(state->s_r)); ++ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru)); + } + +@@ -537,13 +550,15 @@ void process_4V (dsd_opts * opts, dsd_state * state) + 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_l4[3], state->s_l, sizeof(state->s_l)); ++ memcpy(state->s_l4[(state->voice_counter[0]++)%18], 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_r4[3], state->s_r, sizeof(state->s_r)); ++ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[3], state->s_ru, sizeof(state->s_ru)); + } + +@@ -709,17 +724,26 @@ void process_2V (dsd_opts * opts, dsd_state * state) + // } + // #endif + ++ //unsure of the best location for these counter resets ++ if (state->voice_counter[0] >= 18) ++ state->voice_counter[0] = 0; ++ ++ if (state->voice_counter[1] >= 18) ++ state->voice_counter[1] = 0; ++ + 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_l4[0], state->s_l, sizeof(state->s_l)); ++ memcpy(state->s_l4[(state->voice_counter[0]++)%18], 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_r4[0], state->s_r, sizeof(state->s_r)); ++ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru)); + } + +@@ -727,17 +751,19 @@ void process_2V (dsd_opts * opts, dsd_state * state) + 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_l4[1], state->s_l, sizeof(state->s_l)); ++ memcpy(state->s_l4[(state->voice_counter[0]++)%18], 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_r4[1], state->s_r, sizeof(state->s_r)); ++ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru)); + } +- ++ // if (state->currentslot == 0) state->voice_counter[0] = 0; if (state->currentslot == 1) state->voice_counter[1] = 0; + process_ESS(opts, state); + + //reset drop bytes after a 2V +@@ -930,6 +956,8 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state) + state->p2_is_lcch = 0; + state->fourv_counter[0] = 0; + state->fourv_counter[1] = 0; ++ state->voice_counter[0] = 0; ++ state->voice_counter[1] = 0; + + goto END; + } +@@ -949,8 +977,32 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state) + if (sacch == 0 && ts_counter & 1 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000) + playSynthesizedVoiceFS4 (opts, state); + +- if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) +- playSynthesizedVoiceSS4 (opts, state); ++ // if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) ++ // playSynthesizedVoiceSS4 (opts, state); ++ ++ // fprintf (stderr, " VCH0: %d;", state->voice_counter[0]); //debug ++ // fprintf (stderr, " VCH1: %d;", state->voice_counter[1]); //debug ++ ++ //this works, but may still have an element of 'dual voice stutter' which was my initial complaint, but shouldn't 'lag' during trunking operations (hopefully) ++ if ( (state->voice_counter[0] >= 18 || state->voice_counter[1] >= 18 ) && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1 ++ { ++ playSynthesizedVoiceSS18 (opts, state); ++ state->voice_counter[0] = 0; //reset ++ state->voice_counter[1] = 0; //reset ++ } ++ ++ //these two will work, but NOT at the same time on dual voice ++ // if (state->voice_counter[0] >= 18 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1 ++ // { ++ // playSynthesizedVoiceSS18 (opts, state); ++ // state->voice_counter[0] = 0; //reset ++ // } ++ ++ // if (state->voice_counter[1] >= 18 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1 ++ // { ++ // playSynthesizedVoiceSS18 (opts, state); ++ // state->voice_counter[1] = 0; //reset ++ // } + + //debug: fix burst indicator for ncurses if marginal signal + // if (voice) +diff --git a/src/p25p2_xcch.c b/src/p25p2_xcch.c +index 101d1e4..847fe71 100644 +--- a/src/p25p2_xcch.c ++++ b/src/p25p2_xcch.c +@@ -122,6 +122,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180] + { + //reset fourv_counter and dropbyte on PTT + state->fourv_counter[0] = 0; ++ state->voice_counter[0] = 0; + state->dropL = 256; + + state->dmrburstL = 20; +@@ -171,6 +172,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180] + { + //reset fourv_counter and dropbyte on PTT + state->fourv_counter[1] = 0; ++ state->voice_counter[1] = 0; + state->dropR = 256; + state->payload_algidR = 0; //zero this out as well + +@@ -230,6 +232,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180] + { + + state->fourv_counter[0] = 0; ++ state->voice_counter[0] = 0; + state->dropL = 256; + state->dmrburstL = 23; + state->payload_algid = 0; +@@ -258,6 +261,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180] + { + + state->fourv_counter[1] = 0; ++ state->voice_counter[1] = 0; + state->dropR = 256; + state->dmrburstR = 23; + state->payload_algidR = 0; +@@ -498,6 +502,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156] + { + //reset fourv_counter and dropbyte on PTT + state->fourv_counter[0] = 0; ++ state->voice_counter[0] = 0; + state->dropL = 256; + + state->dmrburstL = 20; +@@ -538,6 +543,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156] + { + //reset fourv_counter and dropbyte on PTT + state->fourv_counter[1] = 0; ++ state->voice_counter[1] = 0; + state->dropR = 256; + + state->dmrburstR = 20; +@@ -594,6 +600,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156] + { + + state->fourv_counter[0] = 0; ++ state->voice_counter[0] = 0; + state->dropL = 256; + state->dmrburstL = 23; + state->payload_algid = 0; //zero this out as well +@@ -622,6 +629,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156] + { + + state->fourv_counter[1] = 0; ++ state->voice_counter[1] = 0; + state->dropR = 256; + state->dmrburstR = 23; + state->payload_algidR = 0; //zero this out as well +@@ -723,6 +731,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156] + state->payload_keyid = 0; + state->dmrburstL = 24; + state->fourv_counter[0] = 0; ++ state->voice_counter[0] = 0; + state->lastsrc = 0; + state->lasttg = 0; + +@@ -733,6 +742,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156] + state->payload_keyidR = 0; + state->dmrburstR = 24; + state->fourv_counter[1] = 0; ++ state->voice_counter[1] = 0; + state->lastsrcR = 0; + state->lasttgR = 0; + diff --git a/patch/wolf_p25p2_and_dmr__mono_stereo_interleaving_enc_check.patch b/patch/wolf_p25p2_and_dmr__mono_stereo_interleaving_enc_check.patch new file mode 100644 index 0000000..6aa180a --- /dev/null +++ b/patch/wolf_p25p2_and_dmr__mono_stereo_interleaving_enc_check.patch @@ -0,0 +1,769 @@ +diff --git a/include/dsd.h b/include/dsd.h +index 0b47dee..f459528 100644 +--- a/include/dsd.h ++++ b/include/dsd.h +@@ -437,8 +437,8 @@ typedef struct + //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 ++ short s_l4[36][160]; //quad sample for up to a P25p2 4V ++ short s_r4[36][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 +@@ -654,6 +654,7 @@ typedef struct + int p2_vch_chan_num; //vch channel number (0 or 1, not the 0-11 TS) + int ess_b[2][96]; //external storage for ESS_B fragments + int fourv_counter[2]; //external reference counter for ESS_B fragment collection ++ int voice_counter[2]; //external reference counter for 18V x 2 P25p2 Superframe + int p2_is_lcch; //flag to tell us when a frame is lcch and not sacch + + //iden freq storage for frequency calculations +@@ -926,6 +927,7 @@ void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot); //floa + void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state); //short stereo mix + void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state); //short stereo mix 3v2 DMR + void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state); //short stereo mix 4v2 P25p2 ++void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state); //short stereo mix 18V Superframe + void upsampleS (short invalue, short prev, short outbuf[6]); //upsample 8k to 48k short + // + void openAudioOutDevice (dsd_opts * opts, int speed); +diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c +index a836afc..5eaf3c4 100644 +--- a/src/dsd_audio2.c ++++ b/src/dsd_audio2.c +@@ -906,8 +906,31 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state) + //CHEAT: Using the slot on/off, use that to set encL or encR back on + //as a simple way to turn off voice synthesis in a particular slot + //its not really 'disabled', we just aren't playing it +- if (opts->slot1_on == 0) encL = 1; +- if (opts->slot2_on == 0) encR = 1; ++ // if (opts->slot1_on == 0) encL = 1; ++ // if (opts->slot2_on == 0) encR = 1; ++ ++ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only ++ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default ++ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well ++ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (opts->slot_preference == 0 && state->dmrburstL == 16 && encL == 0) //slot 1 is preferred, and voice in slot 1 ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (opts->slot_preference == 1 && state->dmrburstR == 16 && encR == 0) //slot 2 is preferred, and voice in slot 2 ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ else if (state->dmrburstL == 16 && state->dmrburstR != 16 && encL == 0) //voice in left, no voice in right ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (state->dmrburstR == 16 && state->dmrburstL != 16 && encR == 0) //voice in right, no voice in left ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels) ++ ++ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback ++ { ++ encL = 1; ++ encR = 1; ++ } + + //WIP: Mute if on B list (or not W list) + char modeL[8]; +@@ -944,12 +967,37 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state) + if (strcmp(modeL, "B") == 0) encL = 1; + if (strcmp(modeR, "B") == 0) encR = 1; + ++ //check to see if we need to enable slot and toggle slot preference here ++ //this method will always favor slot 2 (this is a patch anyways, so....meh) ++ if (strcmp(modeL, "A") == 0) ++ { ++ opts->slot1_on = 1; ++ opts->slot_preference = 0; ++ } ++ if (strcmp(modeR, "A") == 0) ++ { ++ opts->slot2_on = 1; ++ opts->slot_preference = 1; ++ } ++ + //if TG Hold in place, mute anything but that TG #132 +- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1; +- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1; +- //likewise, override and unmute if TG hold matches TG +- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0; +- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0; ++ if (state->tg_hold != 0 && state->tg_hold != TGL) ++ encL = 1; ++ if (state->tg_hold != 0 && state->tg_hold != TGR) ++ encR = 1; ++ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference) ++ if (state->tg_hold != 0 && state->tg_hold == TGL) ++ { ++ encL = 0; ++ opts->slot1_on = 1; ++ opts->slot_preference = 0; ++ } ++ if (state->tg_hold != 0 && state->tg_hold == TGR) ++ { ++ encR = 0; ++ opts->slot2_on = 1; ++ opts->slot_preference = 1; ++ } + + //interleave left and right channels from the short storage area + for (i = 0; i < 160; i++) +@@ -1092,8 +1140,31 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state) + //CHEAT: Using the slot on/off, use that to set encL or encR back on + //as a simple way to turn off voice synthesis in a particular slot + //its not really 'disabled', we just aren't playing it +- if (opts->slot1_on == 0) encL = 1; +- if (opts->slot2_on == 0) encR = 1; ++ // if (opts->slot1_on == 0) encL = 1; ++ // if (opts->slot2_on == 0) encR = 1; ++ ++ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only ++ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default ++ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well ++ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1 ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2 ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels) ++ ++ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback ++ { ++ encL = 1; ++ encR = 1; ++ } + + //WIP: Mute if on B list (or not W list) + char modeL[8]; +@@ -1130,12 +1201,37 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state) + if (strcmp(modeL, "B") == 0) encL = 1; + if (strcmp(modeR, "B") == 0) encR = 1; + ++ //check to see if we need to enable slot and toggle slot preference here ++ //this method will always favor slot 2 (this is a patch anyways, so....meh) ++ if (strcmp(modeL, "A") == 0) ++ { ++ opts->slot1_on = 1; ++ opts->slot_preference = 0; ++ } ++ if (strcmp(modeR, "A") == 0) ++ { ++ opts->slot2_on = 1; ++ opts->slot_preference = 1; ++ } ++ + //if TG Hold in place, mute anything but that TG #132 +- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1; +- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1; +- //likewise, override and unmute if TG hold matches TG +- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0; +- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0; ++ if (state->tg_hold != 0 && state->tg_hold != TGL) ++ encL = 1; ++ if (state->tg_hold != 0 && state->tg_hold != TGR) ++ encR = 1; ++ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference) ++ if (state->tg_hold != 0 && state->tg_hold == TGL) ++ { ++ encL = 0; ++ opts->slot1_on = 1; ++ opts->slot_preference = 0; ++ } ++ if (state->tg_hold != 0 && state->tg_hold == TGR) ++ { ++ encR = 0; ++ opts->slot2_on = 1; ++ opts->slot_preference = 1; ++ } + + //interleave left and right channels from the short storage area + for (i = 0; i < 160; i++) +@@ -1238,6 +1334,226 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state) + + } + ++//short stereo mix 18v superframe ++void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state) ++{ ++ ++ //NOTE: This will run once every superframe during a sacch field ++ //exact implementation to be determined ++ ++ int i, j; ++ uint8_t encL, encR; ++ ++ short stereo_sf[18][320]; //8k 2-channel stereo interleave mix for full superframe ++ // memset (stereo_sf, 1, 18*sizeof(short)); //I don't think 18*sizeof(short) was large enough, should probably be 18*320*sizeof(short) ++ memset (stereo_sf, 1, sizeof(stereo_sf)); ++ ++ short empty[320]; ++ 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 ++ ++ //CHEAT: Using the slot on/off, use that to set encL or encR back on ++ //as a simple way to turn off voice synthesis in a particular slot ++ //its not really 'disabled', we just aren't playing it ++ // if (opts->slot1_on == 0) encL = 1; ++ // if (opts->slot2_on == 0) encR = 1; ++ ++ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only ++ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default ++ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well ++ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1 ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2 ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right ++ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right ++ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left ++ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left ++ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels) ++ ++ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback ++ { ++ encL = 1; ++ encR = 1; ++ } ++ ++ //WIP: Mute if on B list (or not W list) ++ char modeL[8]; ++ sprintf (modeL, "%s", ""); ++ char modeR[8]; ++ sprintf (modeR, "%s", ""); ++ ++ int TGL = state->lasttg; ++ int TGR = state->lasttgR; ++ ++ //if we are using allow/whitelist mode, then write 'B' to mode for block ++ //comparison below will look for an 'A' to write to mode if it is allowed ++ if (opts->trunk_use_allow_list == 1) ++ { ++ sprintf (modeL, "%s", "B"); ++ sprintf (modeR, "%s", "B"); ++ } ++ ++ for (i = 0; i < state->group_tally; i++) ++ { ++ if (state->group_array[i].groupNumber == TGL) ++ { ++ strcpy (modeL, state->group_array[i].groupMode); ++ // break; //need to keep going to check other potential slot group ++ } ++ if (state->group_array[i].groupNumber == TGR) ++ { ++ strcpy (modeR, state->group_array[i].groupMode); ++ // break; //need to keep going to check other potential slot group ++ } ++ } ++ ++ //flag either left or right as 'enc' to mute if B ++ if (strcmp(modeL, "B") == 0) encL = 1; ++ if (strcmp(modeR, "B") == 0) encR = 1; ++ ++ //check to see if we need to enable slot and toggle slot preference here ++ //this method will always favor slot 2 (this is a patch anyways, so....meh) ++ if (strcmp(modeL, "A") == 0) ++ { ++ opts->slot1_on = 1; ++ opts->slot_preference = 0; ++ } ++ if (strcmp(modeR, "A") == 0) ++ { ++ opts->slot2_on = 1; ++ opts->slot_preference = 1; ++ } ++ ++ //if TG Hold in place, mute anything but that TG #132 ++ if (state->tg_hold != 0 && state->tg_hold != TGL) ++ encL = 1; ++ if (state->tg_hold != 0 && state->tg_hold != TGR) ++ encR = 1; ++ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference) ++ if (state->tg_hold != 0 && state->tg_hold == TGL) ++ { ++ encL = 0; ++ opts->slot1_on = 1; ++ opts->slot_preference = 0; ++ } ++ if (state->tg_hold != 0 && state->tg_hold == TGR) ++ { ++ encR = 0; ++ opts->slot2_on = 1; ++ opts->slot_preference = 1; ++ } ++ ++ //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions ++ if (encL && encR) ++ goto SS18_END; ++ ++ //interleave left and right channels from the short storage area ++ for (j = 0; j < 18; j++) ++ { ++ for (i = 0; i < 160; i++) ++ { ++ if (!encL) ++ stereo_sf[j][i*2+0] = state->s_l4[j][i]; ++ if (!encR) ++ stereo_sf[j][i*2+1] = state->s_r4[j][i]; ++ } ++ } ++ ++ if (opts->audio_out_type == 0) //Pulse Audio ++ { ++ for (j = 0; j < 18; j++) ++ { ++ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely ++ pa_simple_write(opts->pulse_digi_dev_out, stereo_sf[j], 320*2, NULL); ++ } ++ } ++ ++ if (opts->audio_out_type == 8) //UDP Audio ++ { ++ for (j = 0; j < 18; j++) ++ { ++ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely ++ udp_socket_blaster (opts, state, 320*2, stereo_sf[j]); ++ } ++ } ++ ++ ++ if (opts->audio_out_type == 1 || opts->audio_out_type == 2) //STDOUT or OSS 8k/2channel ++ { ++ for (j = 0; j < 18; j++) ++ { ++ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely ++ write (opts->audio_out_fd, stereo_sf[j], 320*2); ++ } ++ } ++ ++ SS18_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; ++ } ++ ++} ++ + //largely borrowed from Boatbod OP25 (simplified single tone ID version) + void soft_tonef (float samp[160], int n, int ID, int AD) + { +diff --git a/src/dsd_main.c b/src/dsd_main.c +index 1d2616b..02590a6 100644 +--- a/src/dsd_main.c ++++ b/src/dsd_main.c +@@ -382,6 +382,8 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5 + } + state->fourv_counter[0] = 0; + state->fourv_counter[1] = 0; ++ state->voice_counter[0] = 0; ++ state->voice_counter[1] = 0; + + //values displayed in ncurses terminal + // state->p25_vc_freq[0] = 0; +@@ -745,7 +747,7 @@ initOpts (dsd_opts * opts) + //slot preference is used during OSS audio playback to + //prefer one tdma voice slot over another when both are playing back + //this is a fix to OSS 48k/1 output +- opts->slot_preference = 0; //default prefer slot 1 -- state->currentslot = 0; ++ opts->slot_preference = 2; //default prefer slot 1 -- state->currentslot = 0; + + //hardset slots to synthesize + opts->slot1_on = 1; +@@ -941,6 +943,8 @@ initState (dsd_state * state) + } + state->fourv_counter[0] = 0; + state->fourv_counter[1] = 0; ++ state->voice_counter[0] = 0; ++ state->voice_counter[1] = 0; + + state->K = 0; + state->R = 0; +diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c +index 4646e77..fc3f28b 100644 +--- a/src/dsd_ncurses.c ++++ b/src/dsd_ncurses.c +@@ -2568,11 +2568,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + { + printw ("| Voice Error: [%i][%i] Slot 1 (1)", state->errs, state->errs2); + if (opts->slot1_on == 0) printw (" OFF"); +- if (opts->slot1_on == 1) printw (" ON"); ++ if (opts->slot1_on == 1) printw (" ON"); if (opts->slot_preference == 0) printw (" *Preferred"); + printw ("\n"); + printw ("| Voice Error: [%i][%i] Slot 2 (2)", state->errsR, state->errs2R); + if (opts->slot2_on == 0) printw (" OFF"); +- if (opts->slot2_on == 1) printw (" ON"); ++ if (opts->slot2_on == 1) printw (" ON"); if (opts->slot_preference == 1) printw (" *Preferred"); + printw ("\n"); + } + printw ("------------------------------------------------------------------------------\n"); +@@ -3654,8 +3654,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + //switching, but want to control each seperately plz + if (opts->slot1_on == 1) + { +- opts->slot1_on = 0; +- opts->slot_preference = 1; //slot 2 ++ opts->slot1_on = 0; if (opts->slot_preference == 0) opts->slot_preference = 2; ++ // opts->slot_preference = 1; //slot 2 + //clear any previously buffered audio + state->audio_out_float_buf_p = state->audio_out_float_buf + 100; + state->audio_out_buf_p = state->audio_out_buf + 100; +@@ -3680,8 +3680,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + //switching, but want to control each seperately plz + if (opts->slot2_on == 1) + { +- opts->slot2_on = 0; +- opts->slot_preference = 0; //slot 1 ++ opts->slot2_on = 0; if (opts->slot_preference == 1) opts->slot_preference = 2; ++ // opts->slot_preference = 0; //slot 1 + //clear any previously buffered audio + state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100; + state->audio_out_buf_pR = state->audio_out_bufR + 100; +@@ -3701,6 +3701,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) + } + } + ++ if (c == 51) //'3' key, cycle slot preferences ++ { ++ if (opts->slot_preference < 2) ++ opts->slot_preference++; ++ else opts->slot_preference = 0; ++ } ++ + if (c == 43) //+ key, increment audio_gain + { + +diff --git a/src/p25p2_frame.c b/src/p25p2_frame.c +index c391eba..99a4840 100644 +--- a/src/p25p2_frame.c ++++ b/src/p25p2_frame.c +@@ -490,18 +490,27 @@ void process_4V (dsd_opts * opts, dsd_state * state) + // else state->dmrburstR = 21; + // } + // #endif ++ ++ //unsure of the best location for these counter resets ++ if (state->voice_counter[0] >= 18) ++ state->voice_counter[0] = 0; ++ ++ if (state->voice_counter[1] >= 18) ++ state->voice_counter[1] = 0; + + 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_l4[0], state->s_l, sizeof(state->s_l)); ++ memcpy(state->s_l4[(state->voice_counter[0]++)%18], 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_r4[0], state->s_r, sizeof(state->s_r)); ++ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru)); + } + +@@ -509,13 +518,15 @@ void process_4V (dsd_opts * opts, dsd_state * state) + 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_l4[1], state->s_l, sizeof(state->s_l)); ++ memcpy(state->s_l4[(state->voice_counter[0]++)%18], 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_r4[1], state->s_r, sizeof(state->s_r)); ++ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru)); + } + +@@ -523,13 +534,15 @@ void process_4V (dsd_opts * opts, dsd_state * state) + 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_l4[2], state->s_l, sizeof(state->s_l)); ++ memcpy(state->s_l4[(state->voice_counter[0]++)%18], 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_r4[2], state->s_r, sizeof(state->s_r)); ++ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru)); + } + +@@ -537,13 +550,15 @@ void process_4V (dsd_opts * opts, dsd_state * state) + 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_l4[3], state->s_l, sizeof(state->s_l)); ++ memcpy(state->s_l4[(state->voice_counter[0]++)%18], 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_r4[3], state->s_r, sizeof(state->s_r)); ++ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[3], state->s_ru, sizeof(state->s_ru)); + } + +@@ -709,17 +724,26 @@ void process_2V (dsd_opts * opts, dsd_state * state) + // } + // #endif + ++ //unsure of the best location for these counter resets ++ if (state->voice_counter[0] >= 18) ++ state->voice_counter[0] = 0; ++ ++ if (state->voice_counter[1] >= 18) ++ state->voice_counter[1] = 0; ++ + 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_l4[0], state->s_l, sizeof(state->s_l)); ++ memcpy(state->s_l4[(state->voice_counter[0]++)%18], 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_r4[0], state->s_r, sizeof(state->s_r)); ++ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru)); + } + +@@ -727,17 +751,19 @@ void process_2V (dsd_opts * opts, dsd_state * state) + 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_l4[1], state->s_l, sizeof(state->s_l)); ++ memcpy(state->s_l4[(state->voice_counter[0]++)%18], 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_r4[1], state->s_r, sizeof(state->s_r)); ++ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r)); + memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru)); + } +- ++ // if (state->currentslot == 0) state->voice_counter[0] = 0; if (state->currentslot == 1) state->voice_counter[1] = 0; + process_ESS(opts, state); + + //reset drop bytes after a 2V +@@ -930,6 +956,8 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state) + state->p2_is_lcch = 0; + state->fourv_counter[0] = 0; + state->fourv_counter[1] = 0; ++ state->voice_counter[0] = 0; ++ state->voice_counter[1] = 0; + + goto END; + } +@@ -949,8 +977,32 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state) + if (sacch == 0 && ts_counter & 1 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000) + playSynthesizedVoiceFS4 (opts, state); + +- if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) +- playSynthesizedVoiceSS4 (opts, state); ++ // if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) ++ // playSynthesizedVoiceSS4 (opts, state); ++ ++ // fprintf (stderr, " VCH0: %d;", state->voice_counter[0]); //debug ++ // fprintf (stderr, " VCH1: %d;", state->voice_counter[1]); //debug ++ ++ //this works, but may still have an element of 'dual voice stutter' which was my initial complaint, but shouldn't 'lag' during trunking operations (hopefully) ++ if ( (state->voice_counter[0] >= 18 || state->voice_counter[1] >= 18 ) && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1 ++ { ++ playSynthesizedVoiceSS18 (opts, state); ++ state->voice_counter[0] = 0; //reset ++ state->voice_counter[1] = 0; //reset ++ } ++ ++ //these two will work, but NOT at the same time on dual voice ++ // if (state->voice_counter[0] >= 18 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1 ++ // { ++ // playSynthesizedVoiceSS18 (opts, state); ++ // state->voice_counter[0] = 0; //reset ++ // } ++ ++ // if (state->voice_counter[1] >= 18 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1 ++ // { ++ // playSynthesizedVoiceSS18 (opts, state); ++ // state->voice_counter[1] = 0; //reset ++ // } + + //debug: fix burst indicator for ncurses if marginal signal + // if (voice) +diff --git a/src/p25p2_xcch.c b/src/p25p2_xcch.c +index 101d1e4..847fe71 100644 +--- a/src/p25p2_xcch.c ++++ b/src/p25p2_xcch.c +@@ -122,6 +122,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180] + { + //reset fourv_counter and dropbyte on PTT + state->fourv_counter[0] = 0; ++ state->voice_counter[0] = 0; + state->dropL = 256; + + state->dmrburstL = 20; +@@ -171,6 +172,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180] + { + //reset fourv_counter and dropbyte on PTT + state->fourv_counter[1] = 0; ++ state->voice_counter[1] = 0; + state->dropR = 256; + state->payload_algidR = 0; //zero this out as well + +@@ -230,6 +232,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180] + { + + state->fourv_counter[0] = 0; ++ state->voice_counter[0] = 0; + state->dropL = 256; + state->dmrburstL = 23; + state->payload_algid = 0; +@@ -258,6 +261,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180] + { + + state->fourv_counter[1] = 0; ++ state->voice_counter[1] = 0; + state->dropR = 256; + state->dmrburstR = 23; + state->payload_algidR = 0; +@@ -498,6 +502,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156] + { + //reset fourv_counter and dropbyte on PTT + state->fourv_counter[0] = 0; ++ state->voice_counter[0] = 0; + state->dropL = 256; + + state->dmrburstL = 20; +@@ -538,6 +543,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156] + { + //reset fourv_counter and dropbyte on PTT + state->fourv_counter[1] = 0; ++ state->voice_counter[1] = 0; + state->dropR = 256; + + state->dmrburstR = 20; +@@ -594,6 +600,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156] + { + + state->fourv_counter[0] = 0; ++ state->voice_counter[0] = 0; + state->dropL = 256; + state->dmrburstL = 23; + state->payload_algid = 0; //zero this out as well +@@ -622,6 +629,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156] + { + + state->fourv_counter[1] = 0; ++ state->voice_counter[1] = 0; + state->dropR = 256; + state->dmrburstR = 23; + state->payload_algidR = 0; //zero this out as well +@@ -723,6 +731,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156] + state->payload_keyid = 0; + state->dmrburstL = 24; + state->fourv_counter[0] = 0; ++ state->voice_counter[0] = 0; + state->lastsrc = 0; + state->lasttg = 0; + +@@ -733,6 +742,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156] + state->payload_keyidR = 0; + state->dmrburstR = 24; + state->fourv_counter[1] = 0; ++ state->voice_counter[1] = 0; + state->lastsrcR = 0; + state->lasttgR = 0; +