diff --git a/include/dsd.h b/include/dsd.h index 8d9ba14..2fc9278 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -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); diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c index 94afa34..e06a2fe 100644 --- a/src/dsd_audio2.c +++ b/src/dsd_audio2.c @@ -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 diff --git a/src/dsd_events.c b/src/dsd_events.c index f97ff1b..8e8add6 100644 --- a/src/dsd_events.c +++ b/src/dsd_events.c @@ -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); diff --git a/src/dsd_file.c b/src/dsd_file.c index 5b50a81..d315f54 100644 --- a/src/dsd_file.c +++ b/src/dsd_file.c @@ -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); diff --git a/src/dsd_main.c b/src/dsd_main.c index 77ca7a8..2a65d70 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -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 Audio Digital Output Gain (Default: 0 = Auto; )\n"); printf (" (Manual: 1 = 2%%; 50 = 100%%)\n"); printf (" -n Audio Analog Output Gain (Default: 0 = Auto; 0-100%% )\n"); - //printf (" -w Output synthesized speech to a .wav file, FDMA modes only.\n"); //disabled + printf (" -w Output synthesized speech to a .wav file, FDMA modes only.\n"); printf (" -6 Output raw audio .wav file (48K/1). (WARNING! Large File Sizes 1 Hour ~= 360 MB)\n"); printf (" -7 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); diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index e9d59be..1630b68 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -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) {