From bd75c1ab83152496897b50bc1b72f2945c750d8f Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Sat, 23 Aug 2025 20:31:32 -0400 Subject: [PATCH] MBE: Prepare for changes to P25p1 ESS in SDRTrunk .mbe files (version, ks application); #298 MBE: Make tweaks to audio and wav file handling, allow writing to static wav files even if audio out device is NULL (writeSynthesizedVoiceMS); DSTAR: Fix Issue with DSTAR where double writes would occur in single static .wav files; --- include/dsd.h | 1 + src/dsd_audio.c | 36 ++++++++++++++++++++++++ src/dsd_file.c | 73 +++++++++++++++++++++++++++++++++++++++---------- src/dsd_mbe2.c | 4 ++- 4 files changed, 98 insertions(+), 16 deletions(-) diff --git a/include/dsd.h b/include/dsd.h index c9e2c54..4514c09 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -1126,6 +1126,7 @@ 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 writeSynthesizedVoiceMS (dsd_opts * opts, dsd_state * state); //short mono to stereo wav file void playSynthesizedVoice (dsd_opts * opts, dsd_state * state); //short mono output slot 1 void playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state); //short mono output slot 2 //new float stuff diff --git a/src/dsd_audio.c b/src/dsd_audio.c index 282c234..4f67a84 100644 --- a/src/dsd_audio.c +++ b/src/dsd_audio.c @@ -650,6 +650,42 @@ void writeSynthesizedVoiceR (dsd_opts * opts, dsd_state * state) } +//short Mono to Stereo version for new static .wav files in stereo format for TDMA +void writeSynthesizedVoiceMS (dsd_opts * opts, dsd_state * state) +{ + int n; + short aout_buf[160]; + short *aout_buf_p; + + aout_buf_p = aout_buf; + state->audio_out_temp_buf_p = state->audio_out_temp_buf; + + for (n = 0; n < 160; n++) + { + if (*state->audio_out_temp_buf_p > (float) 32767) + { + *state->audio_out_temp_buf_p = (float) 32767; + } + else if (*state->audio_out_temp_buf_p < (float) -32768) + { + *state->audio_out_temp_buf_p = (float) -32768; + } + *aout_buf_p = (short) *state->audio_out_temp_buf_p; + aout_buf_p++; + state->audio_out_temp_buf_p++; + } + + short ss[320]; + for (n = 0; n < 160; n++) + { + ss[(n*2)+0] = aout_buf[n]; + ss[(n*2)+1] = aout_buf[n]; + } + + sf_write_short(opts->wav_out_f, ss, 320); + +} + void writeRawSample (dsd_opts * opts, dsd_state * state, short sample) { UNUSED(state); diff --git a/src/dsd_file.c b/src/dsd_file.c index da04ce7..e4871f5 100644 --- a/src/dsd_file.c +++ b/src/dsd_file.c @@ -1012,14 +1012,21 @@ uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str if (opts->wav_out_f != NULL && opts->dmr_stereo_wav == 1) writeSynthesizedVoice (opts, state); - //NOTE: Static Wav file is handled inside of playSynthesizedVoiceMS, - //but if using -o null to mute audio, then the static file will not contain audio - //TODO: Fix above to allow audio in wav even if not put out to speakers? + //static wav file + if (opts->wav_out_f != NULL && opts->static_wav_file == 1) + writeSynthesizedVoiceMS (opts, state); + //to make the static wav file work, I had to write a work around + //to either play audio from left only when writing wav files, + //or to play from both speakers if not doing either per-call or static wav if (opts->audio_out == 1 && opts->floating_point == 0) - playSynthesizedVoiceMS (opts, state); + { + if (opts->static_wav_file == 1 || opts->dmr_stereo_wav == 1) + playSynthesizedVoice (opts, state); + else playSynthesizedVoiceMS (opts, state); + } - if (opts->floating_point == 1) + if (opts->audio_out == 1 && opts->floating_point == 1) { memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); playSynthesizedVoiceFM (opts, state); @@ -1123,14 +1130,21 @@ uint16_t imbe_str_to_decode(dsd_opts * opts, dsd_state * state, char * imbe_str, if (opts->wav_out_f != NULL && opts->dmr_stereo_wav == 1) writeSynthesizedVoice (opts, state); - //NOTE: Static Wav file is handled inside of playSynthesizedVoiceMS, - //but if using -o null to mute audio, then the static file will not contain audio - //TODO: Fix above to allow audio in wav even if not put out to speakers? + //static wav file + if (opts->wav_out_f != NULL && opts->static_wav_file == 1) + writeSynthesizedVoiceMS (opts, state); + //to make the static wav file work, I had to write a work around + //to either play audio from left only when writing wav files, + //or to play from both speakers if not doing either per-call or static wav if (opts->audio_out == 1 && opts->floating_point == 0) - playSynthesizedVoiceMS (opts, state); + { + if (opts->static_wav_file == 1 || opts->dmr_stereo_wav == 1) + playSynthesizedVoice (opts, state); + else playSynthesizedVoiceMS (opts, state); + } - if (opts->floating_point == 1) + if (opts->audio_out == 1 && opts->floating_point == 1) { memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); playSynthesizedVoiceFM (opts, state); @@ -1161,6 +1175,7 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state) size_t source_size; int8_t protocol = -1; + uint16_t version = 1; //any .mbe file that does not have a version field should be considered version 1 uint32_t source = 0; uint32_t target = 0; int8_t gi = -1; @@ -1191,7 +1206,7 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state) uint8_t ks[3000]; memset (ks, 0, sizeof(ks)); uint16_t ks_idx = 0; //keystream index value - //P25p1 IMBE / IV out of order execution on .mbe files (luckily, AMBE is not affected) + //P25p1 IMBE / IV out of order execution on .mbe files (fixed in version 2 of .mbe file) uint8_t ks_i[3000]; memset (ks_i, 0, sizeof(ks_i)); uint16_t ks_idx_i = 808; //keystream index value IMBE (start at 808 for out of order ESS) int imbe_counter = 0; //count IMBE frames for when to skip 2 bytes of ks and juggle keystreams @@ -1215,6 +1230,21 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state) //debug print current str_buffer // fprintf (stderr, "%s", str_buffer); + if (strncmp ("version", str_buffer, 7) == 0) + { + str_buffer = strtok(NULL, " : \""); //next value after any : "" string + + version = strtol (str_buffer, NULL, 10); + + //debug set value + if (opts->payload == 1) + fprintf (stderr, "\n Version: %d;", version); + + //debug print current str_buffer + // fprintf (stderr, "\n Version: %s", str_buffer); + + } + //compare and set items accordingly if (strncmp ("protocol", str_buffer, 8) == 0) { @@ -1437,7 +1467,7 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state) //reverse lfsr on IV and create keystream with that as well //due to out of order execution on P25p1 ESS sync. - if (protocol == 1) + if (protocol == 1 && version == 1) { reverse_lfsr_64_to_len (opts, kiv+5, 64); @@ -1461,6 +1491,9 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state) //to properly decrypt the initial frame, and then juggle the //keystreams in code to provide a smooth decryption session of P25p1. + //Update: There is a pull request available now, and using a version value, + //we will be able to do either format (ESS out of order vs ESS in correct order) + //reset ks_idx to 0 ks_idx = 0; @@ -1484,14 +1517,16 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state) imbe_counter++; //36 hex characters on 'hex' which is the IMBE interleaved C codewords - ks_idx_i = imbe_str_to_decode(opts, state, str_buffer, ks_i, ks_idx_i, is_enc, ks_available); + if (version == 1) + ks_idx_i = imbe_str_to_decode(opts, state, str_buffer, ks_i, ks_idx_i, is_enc, ks_available); + else ks_idx = imbe_str_to_decode(opts, state, str_buffer, ks, ks_idx, is_enc, ks_available); //skip LSD bits in-between these two IMBE voice frames if (imbe_counter == 8 || imbe_counter == 17) ks_idx_i += 16; - //juggle keystreams and reset the I counter - if (imbe_counter == 9) + //juggle keystreams and reset the I counter (if version 1) + if (imbe_counter == 9 && version == 1) { memcpy (ks_i, ks, sizeof(ks_i)); ks_idx_i = 0; @@ -1499,6 +1534,14 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state) //debug // fprintf (stderr, " LDU2;"); } + //reset keystream idx after frame 18 + else if (imbe_counter == 18 && version == 2) + { + ks_idx = 0; + + //debug + // fprintf (stderr, " LDU2;"); + } //debug // fprintf (stderr, " # %02d; KS_IDX_I: %04d;", imbe_counter, ks_idx_i); diff --git a/src/dsd_mbe2.c b/src/dsd_mbe2.c index 35542a3..6c4a00d 100644 --- a/src/dsd_mbe2.c +++ b/src/dsd_mbe2.c @@ -123,9 +123,11 @@ void soft_mbe (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char amb if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2) playSynthesizedVoiceFS(opts, state); - if (opts->wav_out_f != NULL) + if (opts->wav_out_f != NULL && opts->dmr_stereo_wav == 1) writeSynthesizedVoice (opts, state); + //single wav file handled by playSynthesizedVoiceMS + if (opts->mbe_out_f != NULL) saveAmbe2450Data (opts, state, ambe_d); }