WAV: Re-enable -w option for single file .wav for all decoded speech;

This commit is contained in:
lwvmobile
2025-08-16 10:22:31 -04:00
parent c7b25c60af
commit 21c02acd8c
6 changed files with 163 additions and 31 deletions

View File

@@ -317,7 +317,8 @@ typedef struct
float audio_gainR;
float audio_gainA;
int audio_out;
int dmr_stereo_wav;
int dmr_stereo_wav; //per-call wav file use (rename later)
int static_wav_file; //single static wav file for decoding duration
char wav_out_dir[512];
char wav_out_file[1024];
char wav_out_fileR[1024];
@@ -1171,6 +1172,7 @@ void openMbeOutFileR (dsd_opts * opts, dsd_state * state); //tdma slot 2
void openWavOutFile (dsd_opts * opts, dsd_state * state);
void openWavOutFileL (dsd_opts * opts, dsd_state * state);
void openWavOutFileR (dsd_opts * opts, dsd_state * state);
void openWavOutFileLR (dsd_opts * opts, dsd_state * state); //stereo wav file for tdma decoded speech
void openWavOutFileRaw (dsd_opts * opts, dsd_state * state);
SNDFILE * open_wav_file (char * dir, char * temp_filename, uint16_t sample_rate, uint8_t ext);
SNDFILE * close_wav_file(SNDFILE * wav_file);

View File

@@ -828,6 +828,31 @@ void playSynthesizedVoiceMS (dsd_opts * opts, dsd_state * state)
if (opts->audio_out_type == 1 || opts->audio_out_type == 2 || opts->audio_out_type == 5) //STDOUT or OSS
write (opts->audio_out_fd, mono_samp, len*2);
//this one needs testing w/ 48000 OSS output when audio is not split
if (opts->wav_out_f != NULL && opts->static_wav_file == 1)
{
//convert to stereo for new static wav file setup
short ss[320];
memset (ss, 0, sizeof(ss));
if (len == 160)
{
for (i = 0; i < 160; i++)
{
ss[(i*2)+0] = mono_samp[i];
ss[(i*2)+1] = mono_samp[i];
}
}
else if (len == 960)
{
for (i = 0; i < 160; i++)
{
ss[(i*2)+0] = mono_samp[i*6]; //grab every 6th sample to downsample
ss[(i*2)+1] = mono_samp[i*6]; //grab every 6th sample to downsample
}
}
sf_write_short(opts->wav_out_f, ss, 320);
}
MS_END:
//run cleanup since we pulled stuff from processAudio
@@ -889,6 +914,31 @@ void playSynthesizedVoiceMSR (dsd_opts * opts, dsd_state * state)
if (opts->audio_out_type == 1 || opts->audio_out_type == 2 || opts->audio_out_type == 5) //STDOUT or OSS
write (opts->audio_out_fd, mono_samp, len*2);
//this one needs testing w/ 48000 OSS output when audio is not split
if (opts->wav_out_f != NULL && opts->static_wav_file == 1)
{
//convert to stereo for new static wav file setup
short ss[320];
memset (ss, 0, sizeof(ss));
if (len == 160)
{
for (i = 0; i < 160; i++)
{
ss[(i*2)+0] = mono_samp[i];
ss[(i*2)+1] = mono_samp[i];
}
}
else if (len == 960)
{
for (i = 0; i < 160; i++)
{
ss[(i*2)+0] = mono_samp[i*6]; //grab every 6th sample to downsample
ss[(i*2)+1] = mono_samp[i*6]; //grab every 6th sample to downsample
}
}
sf_write_short(opts->wav_out_f, ss, 320);
}
MS_ENDR:
//run cleanup since we pulled stuff from processAudioR
@@ -1008,6 +1058,8 @@ void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state)
if (opts->audio_out_type == 1 || opts->audio_out_type == 2) //STDOUT or OSS 8k/2
write (opts->audio_out_fd, stereo_samp1, 320*2);
if (opts->wav_out_f != NULL && opts->static_wav_file == 1)
sf_write_short(opts->wav_out_f, stereo_samp1, 320);
SSM_END:
@@ -1358,6 +1410,13 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
write (opts->audio_out_fd, stereo_samp3, 320*2);
}
if (opts->wav_out_f != NULL && opts->static_wav_file == 1)
{
sf_write_short(opts->wav_out_f, stereo_samp1, 320);
sf_write_short(opts->wav_out_f, stereo_samp2, 320);
sf_write_short(opts->wav_out_f, stereo_samp3, 320);
}
SS3_END:
//run cleanup since we pulled stuff from processAudio
@@ -1611,6 +1670,18 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
write (opts->audio_out_fd, stereo_samp4, 320*2);
}
if (opts->wav_out_f != NULL && opts->static_wav_file == 1)
{
sf_write_short(opts->wav_out_f, stereo_samp1, 320);
sf_write_short(opts->wav_out_f, stereo_samp2, 320);
//only write these two if not a single 2v or double 2v
if (memcmp(empty, stereo_samp3, sizeof(empty)) != 0)
sf_write_short(opts->wav_out_f, stereo_samp3, 320);
if (memcmp(empty, stereo_samp4, sizeof(empty)) != 0)
sf_write_short(opts->wav_out_f, stereo_samp4, 320);
}
SS4_END:
//run cleanup since we pulled stuff from processAudio
@@ -1915,6 +1986,15 @@ void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state)
}
}
if (opts->wav_out_f != NULL && opts->static_wav_file == 1)
{
for (j = 0; j < 18; j++)
{
if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0)
sf_write_short(opts->wav_out_f, stereo_sf[j], 320);
}
}
SS18_END:
//run cleanup since we pulled stuff from processAudio

View File

@@ -213,16 +213,21 @@ void watchdog_event_history (dsd_opts * opts, dsd_state * state, uint8_t slot)
event_struct->Event_History_Items[0].write = 1; //written, or pushed at this point
if (slot == 0 && opts->wav_out_f != NULL)
if (opts->static_wav_file == 0)
{
opts->wav_out_f = close_and_rename_wav_file(opts->wav_out_f, opts->wav_out_file, opts->wav_out_dir, event_struct);
opts->wav_out_f = open_wav_file(opts->wav_out_dir, opts->wav_out_file, 8000, 0);
}
else if (slot == 1 && opts->wav_out_fR != NULL)
{
opts->wav_out_fR = close_and_rename_wav_file(opts->wav_out_fR, opts->wav_out_fileR, opts->wav_out_dir, event_struct);
opts->wav_out_fR = open_wav_file(opts->wav_out_dir, opts->wav_out_fileR, 8000, 0);
if (slot == 0 && opts->wav_out_f != NULL)
{
opts->wav_out_f = close_and_rename_wav_file(opts->wav_out_f, opts->wav_out_file, opts->wav_out_dir, event_struct);
opts->wav_out_f = open_wav_file(opts->wav_out_dir, opts->wav_out_file, 8000, 0);
}
else if (slot == 1 && opts->wav_out_fR != NULL)
{
opts->wav_out_fR = close_and_rename_wav_file(opts->wav_out_fR, opts->wav_out_fileR, opts->wav_out_dir, event_struct);
opts->wav_out_fR = open_wav_file(opts->wav_out_dir, opts->wav_out_fileR, 8000, 0);
}
}
push_event_history (event_struct);

View File

@@ -641,6 +641,23 @@ void openWavOutFileR (dsd_opts * opts, dsd_state * state)
}
}
void openWavOutFileLR (dsd_opts * opts, dsd_state * state)
{
UNUSED(state);
SF_INFO info;
info.samplerate = 8000; //8000
info.channels = 2; //2 channel for stereo output
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file
if (opts->wav_out_f == NULL)
{
fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file);
return;
}
}
void openWavOutFileRaw (dsd_opts * opts, dsd_state * state)
{
UNUSED(state);

View File

@@ -674,6 +674,7 @@
opts->wav_out_raw = NULL;
opts->dmr_stereo_wav = 0; //flag for per call dmr stereo wav recordings
opts->static_wav_file = 0; //single static wav file for decoding duration
//opts->wav_out_fd = -1;
opts->serial_baud = 115200;
sprintf (opts->serial_dev, "/dev/ttyUSB0");
@@ -1439,7 +1440,7 @@
printf (" -g <float> Audio Digital Output Gain (Default: 0 = Auto; )\n");
printf (" (Manual: 1 = 2%%; 50 = 100%%)\n");
printf (" -n <float> Audio Analog Output Gain (Default: 0 = Auto; 0-100%% )\n");
//printf (" -w <file> Output synthesized speech to a .wav file, FDMA modes only.\n"); //disabled
printf (" -w <file> Output synthesized speech to a .wav file, FDMA modes only.\n");
printf (" -6 <file> Output raw audio .wav file (48K/1). (WARNING! Large File Sizes 1 Hour ~= 360 MB)\n");
printf (" -7 <dir> Create/Use Custom directory for Per Call decoded .wav file saving.\n");
printf (" (Use ./folder for Nested Directory!)\n");
@@ -1781,10 +1782,27 @@
watchdog_event_history(opts, state, 1);
watchdog_event_current(opts, state, 1);
if (opts->wav_out_f != NULL)
opts->wav_out_f = close_and_rename_wav_file(opts->wav_out_f, opts->wav_out_file, opts->wav_out_dir, &state->event_history_s[0]);
if (opts->wav_out_fR != NULL)
opts->wav_out_fR = close_and_rename_wav_file(opts->wav_out_fR, opts->wav_out_fileR, opts->wav_out_dir, &state->event_history_s[1]);
if (opts->static_wav_file == 0)
{
if (opts->wav_out_f != NULL)
opts->wav_out_f = close_and_rename_wav_file(opts->wav_out_f, opts->wav_out_file, opts->wav_out_dir, &state->event_history_s[0]);
if (opts->wav_out_fR != NULL)
opts->wav_out_fR = close_and_rename_wav_file(opts->wav_out_fR, opts->wav_out_fileR, opts->wav_out_dir, &state->event_history_s[1]);
}
else if (opts->static_wav_file == 1)
{
if (opts->wav_out_f != NULL)
opts->wav_out_f = close_wav_file(opts->wav_out_f);
//this one needed?
if (opts->wav_out_fR != NULL)
opts->wav_out_fR = close_wav_file(opts->wav_out_fR);
}
if (opts->wav_out_raw != NULL)
opts->wav_out_raw = close_wav_file(opts->wav_out_raw);
@@ -2391,13 +2409,14 @@
}
break;
// case 'w': //disabled
// strncpy(opts.wav_out_file, optarg, 1023);
// opts.wav_out_file[1023] = '\0';
// fprintf (stderr,"Writing + Appending decoded audio to file %s\n", opts.wav_out_file);
// opts.dmr_stereo_wav = 0;
// openWavOutFile (&opts, &state);
// break;
case 'w': //experimental re-enabling (needs thorough testing)
strncpy(opts.wav_out_file, optarg, 1023);
opts.wav_out_file[1023] = '\0';
fprintf (stderr,"Writing + Appending decoded audio to file %s\n", opts.wav_out_file);
opts.dmr_stereo_wav = 0;
opts.static_wav_file = 1;
openWavOutFileLR (&opts, &state);
break;
case '6':
strncpy(opts.wav_out_file_raw, optarg, 1023);

View File

@@ -1410,14 +1410,23 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); //P25p1 FDMA 8k/1 channel -f1 switch
}
//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))
{
writeSynthesizedVoice (opts, state);
}
//static wav file saving, if using old method (fallback if issues arise, but disable all in dsd_audio2.c)
// if (opts->static_wav_file == 1 && opts->wav_out_f != NULL)
// {
// if (state->currentslot == 0)
// {
// if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0)
// writeSynthesizedVoice (opts, state);
// }
// else if (state->currentslot == 1)
// {
// if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0)
// writeSynthesizedVoiceR (opts, state);
// }
// }
//per call can only be used when ncurses terminal is active since we use its call history matrix for when to record
if (opts->dmr_stereo_wav == 1 && opts->dmr_stereo == 1 && state->currentslot == 0) //opts->use_ncurses_terminal == 1 &&
//per call wav file writing for slot 1
if (opts->dmr_stereo_wav == 1 && opts->dmr_stereo == 1 && state->currentslot == 0)
{
if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0)
{
@@ -1426,8 +1435,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
}
}
//per call can only be used when ncurses terminal is active since we use its call history matrix for when to record
if (opts->dmr_stereo_wav == 1 && opts->dmr_stereo == 1 && state->currentslot == 1) //opts->use_ncurses_terminal == 1 &&
//per call wav file writing for slot 2
if (opts->dmr_stereo_wav == 1 && opts->dmr_stereo == 1 && state->currentslot == 1)
{
if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0)
{