From 4ee04d09ed0cfd8fcaeed55406b53506e84b0ecd Mon Sep 17 00:00:00 2001 From: Jamie Vital Date: Wed, 27 Nov 2024 17:27:12 -0500 Subject: [PATCH] Several critical patches - SatDump has been incorrectly reading and writing all cs16 recordings (except for ziq2). Reason: scaling was done incorrectly. This means all old cs16 recordings from SatDump are scaled slightly incorrectly, but data can still be recovered from them - Add support for CS32 and CS32 wavs for interoperability - Fix crash when invalid wav is loaded --- README.md | 6 +- .../generic/module_generic_analog_demod.cpp | 4 +- .../noaa_apt/module_noaa_apt_decoder.cpp | 4 +- .../noaa_apt/module_noaa_apt_demod.cpp | 2 +- src-cli/record.cpp | 2 +- src-core/common/detect_header.cpp | 42 ++- src-core/common/dsp/io/baseband_interface.h | 271 +++++------------- src-core/common/dsp/io/baseband_type.cpp | 11 +- src-core/common/dsp/io/baseband_type.h | 1 + src-core/common/dsp/io/file_sink.cpp | 113 +++++++- src-core/common/dsp/io/file_sink.h | 62 +--- src-core/common/wav.cpp | 4 +- src-core/common/ziq.cpp | 4 +- .../modules/demod/module_xfsk_burst_demod.cpp | 2 +- src-interface/recorder/recorder.cpp | 12 +- src-ui/main.cpp | 2 +- 16 files changed, 245 insertions(+), 297 deletions(-) diff --git a/README.md b/README.md index 387ef47e6..2a3c5f3b7 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Quick-Start : ``` Usage : satdump [pipeline_id] [input_level] [input_file] [output_file_or_directory] [additional options as required] Extra options (examples. Any parameter used in modules can be used here) : - --samplerate [baseband_samplerate] --baseband_format [cf32/cs16/cs8/cu8] --dc_block --iq_swap + --samplerate [baseband_samplerate] --baseband_format [cf32/cs32/cs16/cs8/cu8] --dc_block --iq_swap Sample command : satdump metop_ahrpt baseband /home/user/metop_baseband.cs16 metop_output_directory --samplerate 6e6 --baseband_format cs16 ``` @@ -58,7 +58,7 @@ You can find a list of Satellite pipelines and their parameters [Here](https://d ``` Usage : satdump live [pipeline_id] [output_file_or_directory] [additional options as required] Extra options (examples. Any parameter used in modules or sources can be used here) : - --samplerate [baseband_samplerate] --baseband_format [cf32/cs16/cs8/w8] --dc_block --iq_swap + --samplerate [baseband_samplerate] --baseband_format [cf32/cs32/cs16/cs8/w8] --dc_block --iq_swap --source [airspy/rtlsdr/etc] --gain 20 --bias As well as --timeout in seconds Sample command : @@ -72,7 +72,7 @@ You can find a list of all SDR Options [Here](https://docs.satdump.org/sdr_optio ``` Usage : satdump record [output_baseband (without extension!)] [additional options as required] Extra options (examples. Any parameter used in sources can be used here) : - --samplerate [baseband_samplerate] --baseband_format [cf32/cs16/cs8/cu8/w16] --dc_block --iq_swap + --samplerate [baseband_samplerate] --baseband_format [cf32/cs32/cs16/cs8/cu8/w16] --dc_block --iq_swap --source [airspy/rtlsdr/etc] --gain 20 --bias As well as --timeout in seconds Sample command : diff --git a/plugins/analog_support/generic/module_generic_analog_demod.cpp b/plugins/analog_support/generic/module_generic_analog_demod.cpp index f20f025dd..eaf08b2af 100644 --- a/plugins/analog_support/generic/module_generic_analog_demod.cpp +++ b/plugins/analog_support/generic/module_generic_analog_demod.cpp @@ -144,7 +144,7 @@ namespace generic_analog work_buffer_float[i] = -1.0f; } - volk_32f_s32f_convert_16i(output_wav_buffer, (float *)work_buffer_float, 65535 * 0.68, nout); + volk_32f_s32f_convert_16i(output_wav_buffer, (float *)work_buffer_float, 32767, nout); int final_out = audio::AudioSink::resample_s16(output_wav_buffer, output_wav_buffer_resamp, d_symbolrate, audio_samplerate, nout, 1); if (enable_audio && play_audio) @@ -172,7 +172,7 @@ namespace generic_analog qua->output_stream->readBuf[i] = -1.0f; } - volk_32f_s32f_convert_16i(output_wav_buffer, (float *)qua->output_stream->readBuf, 65535 * 0.68, dat_size); + volk_32f_s32f_convert_16i(output_wav_buffer, (float *)qua->output_stream->readBuf, 32767, dat_size); int final_out = audio::AudioSink::resample_s16(output_wav_buffer, output_wav_buffer_resamp, d_symbolrate, audio_samplerate, dat_size, 1); if (enable_audio && play_audio) diff --git a/plugins/analog_support/noaa_apt/module_noaa_apt_decoder.cpp b/plugins/analog_support/noaa_apt/module_noaa_apt_decoder.cpp index 7b9356162..8cb0ddf8c 100644 --- a/plugins/analog_support/noaa_apt/module_noaa_apt_decoder.cpp +++ b/plugins/analog_support/noaa_apt/module_noaa_apt_decoder.cpp @@ -179,12 +179,12 @@ namespace noaa_apt if (is_stereo) { for (int i = 0; i < buffer_size / 2; i++) - input_stream->writeBuf[i] = s16_buf[i * 2] / 65535.0; + input_stream->writeBuf[i] = s16_buf[i * 2] / 32767.0f; input_stream->swap(buffer_size / 2); } else { - volk_16i_s32f_convert_32f_u((float *)input_stream->writeBuf, (const int16_t *)s16_buf, 65535, buffer_size); + volk_16i_s32f_convert_32f_u((float *)input_stream->writeBuf, (const int16_t *)s16_buf, 32767, buffer_size); input_stream->swap(buffer_size); } diff --git a/plugins/analog_support/noaa_apt/module_noaa_apt_demod.cpp b/plugins/analog_support/noaa_apt/module_noaa_apt_demod.cpp index 44e5b80c5..09bf7c471 100644 --- a/plugins/analog_support/noaa_apt/module_noaa_apt_demod.cpp +++ b/plugins/analog_support/noaa_apt/module_noaa_apt_demod.cpp @@ -111,7 +111,7 @@ namespace noaa_apt qua->output_stream->readBuf[i] = -1.0f; } - volk_32f_s32f_convert_16i(output_wav_buffer, (float *)qua->output_stream->readBuf, 65535 * 0.68, dat_size); + volk_32f_s32f_convert_16i(output_wav_buffer, (float *)qua->output_stream->readBuf, 32767, dat_size); if (enable_audio && play_audio) audio_sink->push_samples(output_wav_buffer, dat_size); diff --git a/src-cli/record.cpp b/src-cli/record.cpp index 86858d233..a2f477fe7 100644 --- a/src-cli/record.cpp +++ b/src-cli/record.cpp @@ -24,7 +24,7 @@ int main_record(int argc, char *argv[]) { logger->error("Usage : " + std::string(argv[0]) + " record [output_baseband (without extension!)] [additional options as required]"); logger->error("Extra options (examples. Any parameter used in sources can be used here) :"); - logger->error(" --samplerate [baseband_samplerate] --baseband_format [cf32/cs16/cs8/cu8/wav16/ziq] --dc_block --iq_swap"); + logger->error(" --samplerate [baseband_samplerate] --baseband_format [cf32/cs32/cs16/cs8/cu8/wav16/ziq] --dc_block --iq_swap"); logger->error(" --source [airspy/rtlsdr/etc] --gain 20 --bias"); logger->error("As well as --timeout in seconds"); logger->error("Sample command :"); diff --git a/src-core/common/detect_header.cpp b/src-core/common/detect_header.cpp index f23e7dac5..bfcbba0d7 100644 --- a/src-core/common/detect_header.cpp +++ b/src-core/common/detect_header.cpp @@ -17,22 +17,44 @@ HeaderInfo try_parse_header(std::string file) if (wav::isValidWav(wav::parseHeaderFromFileWav(file))) { logger->debug("File is wav!"); - info.samplerate = wav::parseHeaderFromFileWav(file).samplerate; - if (wav::parseHeaderFromFileWav(file).bits_per_sample == 8) - info.type = "cu8"; - else if (wav::parseHeaderFromFileWav(file).bits_per_sample == 16) - info.type = "cs16"; + wav::WavHeader wav_header = wav::parseHeaderFromFileWav(file); + info.samplerate = wav_header.samplerate; info.valid = true; + if (wav_header.bits_per_sample == 8 && wav_header.audio_Format == 1) + info.type = "cu8"; + else if (wav_header.bits_per_sample == 16 && wav_header.audio_Format == 1) + info.type = "cs16"; + else if (wav_header.bits_per_sample == 32 && wav_header.audio_Format == 1) + info.type = "cs32"; + else if (wav_header.bits_per_sample == 32 && wav_header.audio_Format == 3) + info.type = "cf32"; + else + { + info.valid = false; + logger->warn("Unsupported WAV format! Bits per sample: %hu, Format: %hu", + wav_header.bits_per_sample, wav_header.audio_Format); + } } else if (wav::isValidRF64(wav::parseHeaderFromFileWav(file))) { + wav::RF64Header rf64_header = wav::parseHeaderFromFileRF64(file); logger->debug("File is RF64!"); - info.samplerate = wav::parseHeaderFromFileRF64(file).samplerate; - if (wav::parseHeaderFromFileRF64(file).bits_per_sample == 8) - info.type = "cu8"; - else if (wav::parseHeaderFromFileRF64(file).bits_per_sample == 16) - info.type = "cs16"; + info.samplerate = rf64_header.samplerate; info.valid = true; + if (rf64_header.bits_per_sample == 8 && rf64_header.audio_Format == 1) + info.type = "cu8"; + else if (rf64_header.bits_per_sample == 16 && rf64_header.audio_Format == 1) + info.type = "cs16"; + else if (rf64_header.bits_per_sample == 32 && rf64_header.audio_Format == 1) + info.type = "cs32"; + else if (rf64_header.bits_per_sample == 32 && rf64_header.audio_Format == 3) + info.type = "cf32"; + else + { + info.valid = false; + logger->warn("Unsupported RF64 format! Bits per sample: %hu, Format: %hu", + rf64_header.bits_per_sample, rf64_header.audio_Format); + } } #ifdef BUILD_ZIQ else if (ziq::isValidZIQ(file)) diff --git a/src-core/common/dsp/io/baseband_interface.h b/src-core/common/dsp/io/baseband_interface.h index 917729933..5fdc328f6 100644 --- a/src-core/common/dsp/io/baseband_interface.h +++ b/src-core/common/dsp/io/baseband_interface.h @@ -35,9 +35,10 @@ namespace dsp BasebandType format; // Buffers - int16_t *buffer_i16; - int8_t *buffer_i8; - uint8_t *buffer_u8; + int32_t *buffer_s32 = nullptr; + int16_t *buffer_s16 = nullptr; + int8_t *buffer_s8 = nullptr; + uint8_t *buffer_u8 = nullptr; #ifdef BUILD_ZIQ std::shared_ptr ziqReader; @@ -50,16 +51,16 @@ namespace dsp public: BasebandReader() { - buffer_i16 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); - buffer_i8 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); - buffer_u8 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); } ~BasebandReader() { - volk_free(buffer_i16); - volk_free(buffer_i8); - volk_free(buffer_u8); + if (buffer_s8 != nullptr) + volk_free(buffer_s8); + if (buffer_s16 != nullptr) + volk_free(buffer_s16); + if (buffer_s32 != nullptr) + volk_free(buffer_s32); } // Set the file you want to work on @@ -80,7 +81,53 @@ namespace dsp is_rf64 |= wav::isValidRF64(wav::parseHeaderFromFileWav(file_path)); } - this->format = format; + if (this->format != format) + { + // Free old buffer + if (this->format == CS_8 && buffer_s8 != nullptr) + { + volk_free(buffer_s8); + buffer_s8 = nullptr; + } + else if (this->format == CU_8 && buffer_u8 != nullptr) + { + volk_free(buffer_u8); + buffer_u8 = nullptr; + } + else if ((this->format == CS_16 || this->format == WAV_16) && buffer_s16 != nullptr) + { + volk_free(buffer_s16); + buffer_s16 = nullptr; + } + else if (this->format == CS_32 && buffer_s32 != nullptr) + { + volk_free(buffer_s32); + buffer_s32 = nullptr; + } +#ifdef BUILD_ZIQ2 + else if (this->format == ZIQ2 && buffer_s8 != nullptr) + { + volk_free(buffer_s8); + buffer_s8 = nullptr; + } +#endif + + // Alloc new buffer + if (format == CS_8) + buffer_s8 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); + else if (format == CU_8) + buffer_u8 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); + else if (format == CS_16 || format == WAV_16) + buffer_s16 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); + else if (format == CS_32) + buffer_s32 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); +#ifdef BUILD_ZIQ2 + else if (format == ZIQ2) + buffer_s8 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); +#endif + this->format = format; + } + input_file = std::ifstream(file_path, std::ios::binary); #ifdef BUILD_ZIQ @@ -126,15 +173,19 @@ namespace dsp input_file.read((char *)output_buffer, buffer_size * sizeof(complex_t)); break; - case WAV_16: - case CS_16: - input_file.read((char *)buffer_i16, buffer_size * sizeof(int16_t) * 2); - volk_16i_s32f_convert_32f_u((float *)output_buffer, (const int16_t *)buffer_i16, 65535, buffer_size * 2); + case CS_32: + input_file.read((char*)buffer_s32, buffer_size * sizeof(int32_t) * 2); + volk_32i_s32f_convert_32f_u((float *)output_buffer, (const int32_t*)buffer_s32, 2147483647, buffer_size * 2); + break; + + case WAV_16: case CS_16: + input_file.read((char*)buffer_s16, buffer_size * sizeof(int16_t) * 2); + volk_16i_s32f_convert_32f_u((float *)output_buffer, (const int16_t*)buffer_s16, 32767, buffer_size * 2); break; case CS_8: - input_file.read((char *)buffer_i8, buffer_size * sizeof(int8_t) * 2); - volk_8i_s32f_convert_32f_u((float *)output_buffer, (const int8_t *)buffer_i8, 127, buffer_size * 2); + input_file.read((char *)buffer_s8, buffer_size * sizeof(int8_t) * 2); + volk_8i_s32f_convert_32f_u((float *)output_buffer, (const int8_t *)buffer_s8, 127, buffer_size * 2); break; case CU_8: @@ -222,6 +273,10 @@ namespace dsp samplesize = sizeof(complex_t); break; + case CS_32: + samplesize = sizeof(int32_t) * 2; + break; + case WAV_16: case CS_16: samplesize = sizeof(int16_t) * 2; @@ -257,188 +312,4 @@ namespace dsp return false; } }; - - class BasebandWriter - { - private: - std::mutex rec_mutex; - - BasebandType d_sample_format; - - std::ofstream output_file; - - uint64_t current_size_out = 0; - uint64_t current_size_out_raw = 0; - - int8_t *buffer_s8; - int16_t *buffer_s16; - - int bit_depth = 0; - -#ifdef BUILD_ZIQ - ziq::ziq_cfg ziqcfg; - std::shared_ptr ziqWriter; -#endif - - float *mag_buffer = nullptr; - - std::unique_ptr wav_writer; - - bool should_work = false; - - public: - BasebandWriter() - { - buffer_s8 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); - buffer_s16 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); - } - - ~BasebandWriter() - { - volk_free(buffer_s8); - volk_free(buffer_s16); - if (mag_buffer != nullptr) - volk_free(mag_buffer); - } - - void set_output_sample_type(BasebandType sample_format) - { - d_sample_format = sample_format; - } - - std::string start_recording(std::string path_without_ext, uint64_t samplerate, int depth = 0, bool override_filename = false) // Depth is only for compressed non-raw formats - { - rec_mutex.lock(); - - bit_depth = depth; - - std::string finalt; - if (d_sample_format == CF_32) - finalt = path_without_ext + ".cf32"; - else if (d_sample_format == CS_16) - finalt = path_without_ext + ".cs16"; - else if (d_sample_format == CS_8) - finalt = path_without_ext + ".cs8"; - else if (d_sample_format == WAV_16) - finalt = path_without_ext + ".wav"; -#ifdef BUILD_ZIQ - else if (d_sample_format == ZIQ) - finalt = path_without_ext + ".ziq"; -#endif -#ifdef BUILD_ZIQ2 - else if (d_sample_format == ZIQ2) - finalt = path_without_ext + ".ziq"; -#endif - if (override_filename) - finalt = path_without_ext; - - current_size_out = 0; - current_size_out_raw = 0; - - output_file = std::ofstream(finalt, std::ios::binary); - - if (d_sample_format == WAV_16) - { - wav_writer = std::make_unique(output_file); - wav_writer->write_header(samplerate, 2); - } - -#ifdef BUILD_ZIQ - if (d_sample_format == ZIQ) - { - ziqcfg.is_compressed = true; - ziqcfg.bits_per_sample = depth; - ziqcfg.samplerate = samplerate; - ziqcfg.annotation = ""; - - ziqWriter = std::make_shared(ziqcfg, output_file); - } -#endif -#ifdef BUILD_ZIQ2 - if (d_sample_format == ZIQ2) - { - int sz = ziq2::ziq2_write_file_hdr((uint8_t *)buffer_s8, samplerate); - output_file.write((char *)buffer_s8, sz); - - if (mag_buffer == nullptr) - mag_buffer = create_volk_buffer(STREAM_BUFFER_SIZE); - } -#endif - - should_work = true; - rec_mutex.unlock(); - - return finalt; - } - - uint64_t get_written() - { - return current_size_out; - } - - uint64_t get_written_raw() - { - return current_size_out_raw; - } - - void stop_recording() - { - if (d_sample_format == WAV_16) - wav_writer->finish_header(get_written()); - - rec_mutex.lock(); - should_work = false; - current_size_out = 0; - current_size_out_raw = 0; - output_file.close(); - rec_mutex.unlock(); - } - - void feed_samples(complex_t *samples, int nsamples) - { - if (nsamples <= 0 || !should_work) - return; - - rec_mutex.lock(); - if (should_work) - { - if (d_sample_format == CF_32) - { - output_file.write((char *)samples, nsamples * sizeof(complex_t)); - current_size_out += nsamples * sizeof(complex_t); - } - else if (d_sample_format == CS_16 || d_sample_format == WAV_16) - { - volk_32f_s32f_convert_16i(buffer_s16, (float *)samples, 65535, nsamples * 2); - output_file.write((char *)buffer_s16, nsamples * sizeof(int16_t) * 2); - current_size_out += nsamples * sizeof(int16_t) * 2; - } - else if (d_sample_format == CS_8) - { - volk_32f_s32f_convert_8i(buffer_s8, (float *)samples, 127, nsamples * 2); - output_file.write((char *)buffer_s8, nsamples * sizeof(int8_t) * 2); - current_size_out += nsamples * sizeof(int8_t) * 2; - } -#ifdef BUILD_ZIQ - else if (d_sample_format == ZIQ) - { - current_size_out += ziqWriter->write(samples, nsamples); - current_size_out_raw += (ziqcfg.bits_per_sample / 4) * nsamples; - } -#endif -#ifdef BUILD_ZIQ2 - else if (d_sample_format == ZIQ2) - { - int sz = ziq2::ziq2_write_iq_pkt((uint8_t *)buffer_s8, samples, mag_buffer, nsamples, bit_depth); - output_file.write((char *)buffer_s8, sz); - current_size_out += sz; - } -#endif - - output_file.flush(); - } - - rec_mutex.unlock(); - } - }; } diff --git a/src-core/common/dsp/io/baseband_type.cpp b/src-core/common/dsp/io/baseband_type.cpp index 2503371a6..b338e9390 100644 --- a/src-core/common/dsp/io/baseband_type.cpp +++ b/src-core/common/dsp/io/baseband_type.cpp @@ -31,6 +31,7 @@ namespace dsp static const std::vector play_fwd_lut = { CF_32, + CS_32, CS_16, CS_8, CU_8, @@ -44,6 +45,7 @@ namespace dsp static const std::vector record_fwd_lut = { CF_32, + CS_32, CS_16, CS_8, WAV_16, @@ -68,6 +70,9 @@ namespace dsp case CF_32: return "cf32"; break; + case CS_32: + return "cs32"; + break; case CS_16: return "cs16"; break; @@ -97,7 +102,9 @@ namespace dsp void BasebandType::from_string(const std::string &s) { - if (s == "cs16" || s == "s16") + if (s == "cs32" || s == "s32") + type = CS_32; + else if (s == "cs16" || s == "s16") type = CS_16; else if (s == "cs8" || s == "s8") type = CS_8; @@ -124,6 +131,7 @@ namespace dsp int selected = play_rev_lut.at(*this); bool ret = ImGui::Combo(label, &selected, "cf32\0" + "cs32\0" "cs16\0" "cs8\0" "cu8\0" @@ -147,6 +155,7 @@ namespace dsp int selected = record_rev_lut.at(*this); bool ret = ImGui::Combo(label, &selected, "cf32\0" + "cs32\0" "cs16\0" "cs8\0" "wav16\0" diff --git a/src-core/common/dsp/io/baseband_type.h b/src-core/common/dsp/io/baseband_type.h index c12941bf4..e44a8e706 100644 --- a/src-core/common/dsp/io/baseband_type.h +++ b/src-core/common/dsp/io/baseband_type.h @@ -7,6 +7,7 @@ namespace dsp enum BasebandTypeEnum { CF_32, + CS_32, CS_16, CS_8, CU_8, diff --git a/src-core/common/dsp/io/file_sink.cpp b/src-core/common/dsp/io/file_sink.cpp index 9e4f0f45d..1c314f807 100644 --- a/src-core/common/dsp/io/file_sink.cpp +++ b/src-core/common/dsp/io/file_sink.cpp @@ -5,18 +5,115 @@ namespace dsp FileSinkBlock::FileSinkBlock(std::shared_ptr> input) : Block(input) { - buffer_s8 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); - buffer_s16 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); } FileSinkBlock::~FileSinkBlock() { - volk_free(buffer_s8); - volk_free(buffer_s16); + if(buffer_s8 != nullptr) + volk_free(buffer_s8); + if(buffer_s16 != nullptr) + volk_free(buffer_s16); + if (buffer_s32 != nullptr) + volk_free(buffer_s32); if (mag_buffer != nullptr) volk_free(mag_buffer); } + void FileSinkBlock::set_output_sample_type(BasebandType sample_format) + { + if (d_sample_format == sample_format) + return; + + // Free old buffer + if (d_sample_format == CS_8 && buffer_s8 != nullptr) + { + volk_free(buffer_s8); + buffer_s8 = nullptr; + } + else if ((d_sample_format == CS_16 || d_sample_format == WAV_16) && buffer_s16 != nullptr) + { + volk_free(buffer_s16); + buffer_s16 = nullptr; + } + else if (d_sample_format == CS_32 && buffer_s32 != nullptr) + { + volk_free(buffer_s32); + buffer_s32 = nullptr; + } +#ifdef BUILD_ZIQ2 + else if (d_sample_format == ZIQ2 && buffer_s8 != nullptr) + { + volk_free(buffer_s8); + buffer_s8 = nullptr; + } +#endif + + // Alloc new buffer + if (sample_format == CS_8) + buffer_s8 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); + else if (sample_format == CS_16 || sample_format == WAV_16) + buffer_s16 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); + else if (sample_format == CS_32) + buffer_s32 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); +#ifdef BUILD_ZIQ2 + else if (sample_format == ZIQ2) + buffer_s8 = create_volk_buffer(STREAM_BUFFER_SIZE * 2); +#endif + + d_sample_format = sample_format; + } + + std::string FileSinkBlock::start_recording(std::string path_without_ext, uint64_t samplerate, bool override_filename) + { + rec_mutex.lock(); + + std::string finalt; + finalt = path_without_ext + "." + (std::string)d_sample_format; + if (override_filename) + finalt = path_without_ext; + + current_size_out = 0; + current_size_out_raw = 0; + + output_file = std::ofstream(finalt, std::ios::binary); + + if (d_sample_format == WAV_16) + { + wav_writer = std::make_unique(output_file); + wav_writer->write_header(samplerate, 2); + } + +#ifdef BUILD_ZIQ + if (d_sample_format == ZIQ) + { + ziqcfg.is_compressed = true; + ziqcfg.bits_per_sample = d_sample_format.ziq_depth; + ziqcfg.samplerate = samplerate; + ziqcfg.annotation = ""; + + ziqWriter = std::make_shared(ziqcfg, output_file); + } +#endif +#ifdef BUILD_ZIQ2 + if (d_sample_format == ZIQ2) + { + int sz = ziq2::ziq2_write_file_hdr((uint8_t*)buffer_s8, samplerate); + output_file.write((char*)buffer_s8, sz); + + if (mag_buffer == nullptr) + mag_buffer = create_volk_buffer(STREAM_BUFFER_SIZE); + } +#endif + + if (!std::filesystem::exists(finalt)) + logger->error("We have created the output baseband file, but it does not exist! There may be a permission issue! File : " + finalt); + + should_work = true; + rec_mutex.unlock(); + + return finalt; + } + void FileSinkBlock::work() { int nsamples = input_stream->read(); @@ -34,9 +131,15 @@ namespace dsp output_file.write((char *)input_stream->readBuf, nsamples * sizeof(complex_t)); current_size_out += nsamples * sizeof(complex_t); } + else if (d_sample_format == CS_32) + { + volk_32f_s32f_convert_32i(buffer_s32, (float*)input_stream->readBuf, 2147483647, nsamples * 2); + output_file.write((char*)buffer_s32, nsamples * sizeof(int32_t) * 2); + current_size_out += nsamples * sizeof(int32_t) * 2; + } else if (d_sample_format == CS_16 || d_sample_format == WAV_16) { - volk_32f_s32f_convert_16i(buffer_s16, (float *)input_stream->readBuf, 65535, nsamples * 2); + volk_32f_s32f_convert_16i(buffer_s16, (float *)input_stream->readBuf, 32767, nsamples * 2); output_file.write((char *)buffer_s16, nsamples * sizeof(int16_t) * 2); current_size_out += nsamples * sizeof(int16_t) * 2; } diff --git a/src-core/common/dsp/io/file_sink.h b/src-core/common/dsp/io/file_sink.h index b9329825a..c62c02c59 100644 --- a/src-core/common/dsp/io/file_sink.h +++ b/src-core/common/dsp/io/file_sink.h @@ -28,8 +28,9 @@ namespace dsp uint64_t current_size_out = 0; uint64_t current_size_out_raw = 0; - int8_t *buffer_s8; - int16_t *buffer_s16; + int8_t *buffer_s8 = nullptr; + int16_t *buffer_s16 = nullptr; + int32_t *buffer_s32 = nullptr; #ifdef BUILD_ZIQ ziq::ziq_cfg ziqcfg; @@ -44,61 +45,8 @@ namespace dsp FileSinkBlock(std::shared_ptr> input); ~FileSinkBlock(); - void set_output_sample_type(BasebandType sample_format) - { - d_sample_format = sample_format; - } - - std::string start_recording(std::string path_without_ext, uint64_t samplerate, bool override_filename = false) - { - rec_mutex.lock(); - - std::string finalt; - finalt = path_without_ext + "." + (std::string)d_sample_format; - if (override_filename) - finalt = path_without_ext; - - current_size_out = 0; - current_size_out_raw = 0; - - output_file = std::ofstream(finalt, std::ios::binary); - - if (d_sample_format == WAV_16) - { - wav_writer = std::make_unique(output_file); - wav_writer->write_header(samplerate, 2); - } - -#ifdef BUILD_ZIQ - if (d_sample_format == ZIQ) - { - ziqcfg.is_compressed = true; - ziqcfg.bits_per_sample = d_sample_format.ziq_depth; - ziqcfg.samplerate = samplerate; - ziqcfg.annotation = ""; - - ziqWriter = std::make_shared(ziqcfg, output_file); - } -#endif -#ifdef BUILD_ZIQ2 - if (d_sample_format == ZIQ2) - { - int sz = ziq2::ziq2_write_file_hdr((uint8_t *)buffer_s8, samplerate); - output_file.write((char *)buffer_s8, sz); - - if (mag_buffer == nullptr) - mag_buffer = create_volk_buffer(STREAM_BUFFER_SIZE); - } -#endif - - if (!std::filesystem::exists(finalt)) - logger->error("We have created the output baseband file, but it does not exist! There may be a permission issue! File : " + finalt); - - should_work = true; - rec_mutex.unlock(); - - return finalt; - } + void set_output_sample_type(BasebandType sample_format); + std::string start_recording(std::string path_without_ext, uint64_t samplerate, bool override_filename = false); uint64_t get_written() { diff --git a/src-core/common/wav.cpp b/src-core/common/wav.cpp index 9750a8eb1..c49ca8d6f 100644 --- a/src-core/common/wav.cpp +++ b/src-core/common/wav.cpp @@ -260,9 +260,9 @@ namespace wav md.timestamp = timegm(&timeS); std::string ext = std::filesystem::path(filepath).extension().string(); - if (ext == ".cf32" || ext == ".cs16" || ext == ".cs8") + if (ext == ".cf32" || ext == ".cs32" || ext == ".cs16" || ext == ".cs8") md.baseband_format = ext.substr(1); - else if (ext == ".f32" || ext == ".s16" || ext == ".s8") // Later, this should input REAL and not complex! + else if (ext == ".f32" || ext == ".s32" || ext == ".s16" || ext == ".s8") // Later, this should input REAL and not complex! md.baseband_format = "c" + ext.substr(1); if (ext != ".wav") md.samplerate = samp; diff --git a/src-core/common/ziq.cpp b/src-core/common/ziq.cpp index a00705e95..c1ccde13b 100644 --- a/src-core/common/ziq.cpp +++ b/src-core/common/ziq.cpp @@ -83,7 +83,7 @@ namespace ziq } else if (cfg.bits_per_sample == 16) { - volk_32f_s32f_convert_16i(buffer_i16, (float *)input, 65535, size * 2); + volk_32f_s32f_convert_16i(buffer_i16, (float *)input, 32767, size * 2); if (cfg.is_compressed) { @@ -286,7 +286,7 @@ namespace ziq stream.read((char *)buffer_i16, size * 2 * sizeof(int16_t)); } - volk_16i_s32f_convert_32f_u((float *)output, (const int16_t *)buffer_i16, 65535, size * 2); + volk_16i_s32f_convert_32f_u((float *)output, (const int16_t *)buffer_i16, 32767, size * 2); } else if (cfg.bits_per_sample == 32) { diff --git a/src-core/modules/demod/module_xfsk_burst_demod.cpp b/src-core/modules/demod/module_xfsk_burst_demod.cpp index e5b95a59e..9dd2e0aba 100644 --- a/src-core/modules/demod/module_xfsk_burst_demod.cpp +++ b/src-core/modules/demod/module_xfsk_burst_demod.cpp @@ -144,7 +144,7 @@ namespace demod continue; } - volk_32f_s32f_convert_16i(output_wav_buffer, (float *)agc2->output_stream->readBuf, 65535 * 0.2, dat_size); + volk_32f_s32f_convert_16i(output_wav_buffer, (float *)agc2->output_stream->readBuf, 65535 * 0.2, dat_size); //TODO - 65535 is incorrect; use 32767 and fix percent appropriately audio_sink->push_samples(output_wav_buffer, dat_size); diff --git a/src-interface/recorder/recorder.cpp b/src-interface/recorder/recorder.cpp index a56d37fa6..d74fb9d19 100644 --- a/src-interface/recorder/recorder.cpp +++ b/src-interface/recorder/recorder.cpp @@ -555,19 +555,13 @@ namespace satdump int timeleft; switch (baseband_format) { - case dsp::CF_32: + case dsp::CF_32: case dsp::CS_32: timeleft = estimated_available / (8 * get_samplerate()); break; - case dsp::CS_16: + case dsp::CS_16: case dsp::WAV_16: timeleft = estimated_available / (4 * get_samplerate()); break; - case dsp::WAV_16: - timeleft = estimated_available / (4 * get_samplerate()); - break; - case dsp::CS_8: - timeleft = estimated_available / (2 * get_samplerate()); - break; - case dsp::CU_8: + case dsp::CS_8: case dsp::CU_8: timeleft = estimated_available / (2 * get_samplerate()); break; default: diff --git a/src-ui/main.cpp b/src-ui/main.cpp index b56ee1baf..e2088b452 100644 --- a/src-ui/main.cpp +++ b/src-ui/main.cpp @@ -44,7 +44,7 @@ int main(int argc, char *argv[]) { logger->error("Usage : " + std::string(argv[0]) + " [downlink] [input_level] [input_file] [output_file_or_directory] [additional options as required]"); logger->error("Extra options (examples. Any parameter used in modules can be used here) :"); - logger->error(" --samplerate [baseband_samplerate] --baseband_format [cf32/cs16/cs8/wav16] --dc_block --iq_swap"); + logger->error(" --samplerate [baseband_samplerate] --baseband_format [cf32/cs32/cs16/cs8/wav16] --dc_block --iq_swap"); } else satdump::processing::is_processing = true;