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;
This commit is contained in:
lwvmobile
2025-08-23 20:31:32 -04:00
parent b3b943d330
commit bd75c1ab83
4 changed files with 98 additions and 16 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}