From 1d83a2b247f8e83bbce802a272ffa165bbc6333f Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Tue, 8 Oct 2024 15:25:45 +0200 Subject: Get fixed_point working with USRP --- src/FormatConverter.cpp | 135 +++++++++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 47 deletions(-) (limited to 'src/FormatConverter.cpp') diff --git a/src/FormatConverter.cpp b/src/FormatConverter.cpp index e8e76ed..9e59a4a 100644 --- a/src/FormatConverter.cpp +++ b/src/FormatConverter.cpp @@ -39,6 +39,14 @@ FormatConverter::FormatConverter(const std::string& format) : m_format(format) { } +FormatConverter::~FormatConverter() +{ + etiLog.level(debug) << "FormatConverter: " + << m_num_clipped_samples.load() << + " clipped samples"; +} + + /* Expect the input samples to be in the correct range for the required format */ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) { @@ -47,71 +55,101 @@ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) size_t num_clipped_samples = 0; - size_t sizeIn = dataIn->getLength() / sizeof(float); - float* in = reinterpret_cast(dataIn->getData()); - - if (m_format == "s16") { - dataOut->setLength(sizeIn * sizeof(int16_t)); - int16_t* out = reinterpret_cast(dataOut->getData()); - - for (size_t i = 0; i < sizeIn; i++) { - if (in[i] < INT16_MIN) { - out[i] = INT16_MIN; - num_clipped_samples++; - } - else if (in[i] > INT16_MAX) { - out[i] = INT16_MAX; - num_clipped_samples++; - } - else { - out[i] = in[i]; + bool source_is_complexf = m_format != "fixedpoint"; + + if (source_is_complexf) { + size_t sizeIn = dataIn->getLength() / sizeof(float); + float* in = reinterpret_cast(dataIn->getData()); + + if (m_format == "s16") { + dataOut->setLength(sizeIn * sizeof(int16_t)); + int16_t* out = reinterpret_cast(dataOut->getData()); + + for (size_t i = 0; i < sizeIn; i++) { + if (in[i] < INT16_MIN) { + out[i] = INT16_MIN; + num_clipped_samples++; + } + else if (in[i] > INT16_MAX) { + out[i] = INT16_MAX; + num_clipped_samples++; + } + else { + out[i] = in[i]; + } } } - } - else if (m_format == "u8") { - dataOut->setLength(sizeIn * sizeof(int8_t)); - uint8_t* out = reinterpret_cast(dataOut->getData()); + else if (m_format == "u8") { + dataOut->setLength(sizeIn * sizeof(int8_t)); + uint8_t* out = reinterpret_cast(dataOut->getData()); + + for (size_t i = 0; i < sizeIn; i++) { + const auto samp = in[i] + 128.0f; + if (samp < 0) { + out[i] = 0; + num_clipped_samples++; + } + else if (samp > UINT8_MAX) { + out[i] = UINT8_MAX; + num_clipped_samples++; + } + else { + out[i] = samp; + } - for (size_t i = 0; i < sizeIn; i++) { - const auto samp = in[i] + 128.0f; - if (samp < 0) { - out[i] = 0; - num_clipped_samples++; } - else if (samp > UINT8_MAX) { - out[i] = UINT8_MAX; - num_clipped_samples++; - } - else { - out[i] = samp; + } + else if (m_format == "s8") { + dataOut->setLength(sizeIn * sizeof(int8_t)); + int8_t* out = reinterpret_cast(dataOut->getData()); + + for (size_t i = 0; i < sizeIn; i++) { + if (in[i] < INT8_MIN) { + out[i] = INT8_MIN; + num_clipped_samples++; + } + else if (in[i] > INT8_MAX) { + out[i] = INT8_MAX; + num_clipped_samples++; + } + else { + out[i] = in[i]; + } } - } + else { + throw std::runtime_error("FormatConverter: Invalid format " + m_format); + } + } - else if (m_format == "s8") { - dataOut->setLength(sizeIn * sizeof(int8_t)); - int8_t* out = reinterpret_cast(dataOut->getData()); + else { + // Output is always sc16, because that's what UHD accepts + + using fixed_t = complexfix::value_type; + size_t sizeIn = dataIn->getLength() / sizeof(fixed_t); + fixed_t* in = reinterpret_cast(dataIn->getData()); + + dataOut->setLength(sizeIn * sizeof(int16_t)); + int16_t* out = reinterpret_cast(dataOut->getData()); for (size_t i = 0; i < sizeIn; i++) { - if (in[i] < INT8_MIN) { - out[i] = INT8_MIN; + const auto v = (in[i] * 2).raw_value(); + + if (v < INT16_MIN) { + out[i] = INT16_MIN; num_clipped_samples++; } - else if (in[i] > INT8_MAX) { - out[i] = INT8_MAX; + else if (v > INT16_MAX) { + out[i] = INT16_MAX; num_clipped_samples++; } else { - out[i] = in[i]; + out[i] = (int16_t)v; } } } - else { - throw std::runtime_error("FormatConverter: Invalid format " + m_format); - } m_num_clipped_samples.store(num_clipped_samples); - return dataOut->getLength(); } @@ -129,7 +167,10 @@ size_t FormatConverter::get_num_clipped_samples() const size_t FormatConverter::get_format_size(const std::string& format) { // Returns 2*sizeof(SAMPLE_TYPE) because we have I + Q - if (format == "s16") { + if (format == "fixedpoint") { + return 4; + } + else if (format == "s16") { return 4; } else if (format == "u8") { -- cgit v1.2.3 From 933021ed44e6c1bd2cf1dee91fc033c145c061af Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Tue, 29 Oct 2024 22:55:41 +0100 Subject: Change to 16-bit fixed point --- Makefile.am | 2 +- src/Buffer.h | 4 +- src/DabMod.cpp | 3 +- src/DabModulator.cpp | 15 ++++-- src/FormatConverter.cpp | 121 ++++++++++++++++++------------------------------ src/OfdmGenerator.cpp | 30 ++++++------ src/PhaseReference.cpp | 4 +- 7 files changed, 79 insertions(+), 100 deletions(-) (limited to 'src/FormatConverter.cpp') diff --git a/Makefile.am b/Makefile.am index 47d6f43..87d553a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,7 +35,7 @@ endif bin_PROGRAMS = odr-dabmod -KISS_FLAGS=-DFIXED_POINT=32 +KISS_FLAGS=-DFIXED_POINT=16 odr_dabmod_CFLAGS = -Wall -Isrc -Ilib -Ikiss \ $(GITVERSION_FLAGS) $(KISS_FLAGS) odr_dabmod_CXXFLAGS = -Wall -Isrc -Ilib -Ikiss \ diff --git a/src/Buffer.h b/src/Buffer.h index 711b804..f6c94e0 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -37,7 +37,9 @@ #include "fpm/fixed.hpp" typedef std::complex complexf; -typedef std::complex complexfix; + +using fixed_16 = fpm::fixed; +typedef std::complex complexfix; /* Buffer is a container for a byte array, which is memory-aligned * to 32 bytes for SSE performance. diff --git a/src/DabMod.cpp b/src/DabMod.cpp index b745271..4726df9 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -313,7 +313,6 @@ static shared_ptr prepare_output(mod_settings_t& s) else if (s.useDexterOutput) { /* We normalise specifically range [-32768; 32767] */ s.normalise = 32767.0f / normalise_factor; - if (s.fixedPoint) throw runtime_error("dexter fixed_point unsupported"); s.sdr_device_config.sampleRate = s.outputRate; auto dexterdevice = make_shared(s.sdr_device_config); output = make_shared(s.sdr_device_config, dexterdevice); @@ -448,7 +447,7 @@ int launch_modulator(int argc, char* argv[]) std::string output_format; if (mod_settings.fixedPoint) { - output_format = "fixedpoint"; + output_format = ""; //fixed point is native sc16, no converter needed } else if (mod_settings.useFileOutput and (mod_settings.fileOutputFormat == "s8" or diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index 757b01f..5f01725 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -178,11 +178,16 @@ int DabModulator::process(Buffer* dataOut) shared_ptr tii; shared_ptr tiiRef; try { - tii = make_shared( - m_settings.dabMode, - m_settings.tiiConfig); - rcs.enrol(tii.get()); - tiiRef = make_shared(mode, m_settings.fixedPoint); + if (m_settings.fixedPoint) { + etiLog.level(warn) << "TII does not yet support fixed point"; + } + else { + tii = make_shared( + m_settings.dabMode, + m_settings.tiiConfig); + rcs.enrol(tii.get()); + tiiRef = make_shared(mode, m_settings.fixedPoint); + } } catch (const TIIError& e) { etiLog.level(error) << "Could not initialise TII: " << e.what(); diff --git a/src/FormatConverter.cpp b/src/FormatConverter.cpp index 9e59a4a..a52f501 100644 --- a/src/FormatConverter.cpp +++ b/src/FormatConverter.cpp @@ -55,99 +55,68 @@ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) size_t num_clipped_samples = 0; - bool source_is_complexf = m_format != "fixedpoint"; - - if (source_is_complexf) { - size_t sizeIn = dataIn->getLength() / sizeof(float); - float* in = reinterpret_cast(dataIn->getData()); - - if (m_format == "s16") { - dataOut->setLength(sizeIn * sizeof(int16_t)); - int16_t* out = reinterpret_cast(dataOut->getData()); - - for (size_t i = 0; i < sizeIn; i++) { - if (in[i] < INT16_MIN) { - out[i] = INT16_MIN; - num_clipped_samples++; - } - else if (in[i] > INT16_MAX) { - out[i] = INT16_MAX; - num_clipped_samples++; - } - else { - out[i] = in[i]; - } - } - } - else if (m_format == "u8") { - dataOut->setLength(sizeIn * sizeof(int8_t)); - uint8_t* out = reinterpret_cast(dataOut->getData()); - - for (size_t i = 0; i < sizeIn; i++) { - const auto samp = in[i] + 128.0f; - if (samp < 0) { - out[i] = 0; - num_clipped_samples++; - } - else if (samp > UINT8_MAX) { - out[i] = UINT8_MAX; - num_clipped_samples++; - } - else { - out[i] = samp; - } + size_t sizeIn = dataIn->getLength() / sizeof(float); + float* in = reinterpret_cast(dataIn->getData()); + + if (m_format == "s16") { + dataOut->setLength(sizeIn * sizeof(int16_t)); + int16_t* out = reinterpret_cast(dataOut->getData()); + for (size_t i = 0; i < sizeIn; i++) { + if (in[i] < INT16_MIN) { + out[i] = INT16_MIN; + num_clipped_samples++; } - } - else if (m_format == "s8") { - dataOut->setLength(sizeIn * sizeof(int8_t)); - int8_t* out = reinterpret_cast(dataOut->getData()); - - for (size_t i = 0; i < sizeIn; i++) { - if (in[i] < INT8_MIN) { - out[i] = INT8_MIN; - num_clipped_samples++; - } - else if (in[i] > INT8_MAX) { - out[i] = INT8_MAX; - num_clipped_samples++; - } - else { - out[i] = in[i]; - } + else if (in[i] > INT16_MAX) { + out[i] = INT16_MAX; + num_clipped_samples++; + } + else { + out[i] = in[i]; } } - else { - throw std::runtime_error("FormatConverter: Invalid format " + m_format); - } - } - else { - // Output is always sc16, because that's what UHD accepts + else if (m_format == "u8") { + dataOut->setLength(sizeIn * sizeof(int8_t)); + uint8_t* out = reinterpret_cast(dataOut->getData()); - using fixed_t = complexfix::value_type; - size_t sizeIn = dataIn->getLength() / sizeof(fixed_t); - fixed_t* in = reinterpret_cast(dataIn->getData()); + for (size_t i = 0; i < sizeIn; i++) { + const auto samp = in[i] + 128.0f; + if (samp < 0) { + out[i] = 0; + num_clipped_samples++; + } + else if (samp > UINT8_MAX) { + out[i] = UINT8_MAX; + num_clipped_samples++; + } + else { + out[i] = samp; + } - dataOut->setLength(sizeIn * sizeof(int16_t)); - int16_t* out = reinterpret_cast(dataOut->getData()); + } + } + else if (m_format == "s8") { + dataOut->setLength(sizeIn * sizeof(int8_t)); + int8_t* out = reinterpret_cast(dataOut->getData()); for (size_t i = 0; i < sizeIn; i++) { - const auto v = (in[i] * 2).raw_value(); - - if (v < INT16_MIN) { - out[i] = INT16_MIN; + if (in[i] < INT8_MIN) { + out[i] = INT8_MIN; num_clipped_samples++; } - else if (v > INT16_MAX) { - out[i] = INT16_MAX; + else if (in[i] > INT8_MAX) { + out[i] = INT8_MAX; num_clipped_samples++; } else { - out[i] = (int16_t)v; + out[i] = in[i]; } } } + else { + throw std::runtime_error("FormatConverter: Invalid format " + m_format); + } m_num_clipped_samples.store(num_clipped_samples); return dataOut->getLength(); diff --git a/src/OfdmGenerator.cpp b/src/OfdmGenerator.cpp index 62a0ee5..4f6eeb9 100644 --- a/src/OfdmGenerator.cpp +++ b/src/OfdmGenerator.cpp @@ -633,8 +633,8 @@ OfdmGeneratorDEXTER::OfdmGeneratorDEXTER(size_t nbSymbols, PDEBUG(" myZeroDst: %u\n", myZeroDst); PDEBUG(" myZeroSize: %u\n", myZeroSize); - const int N = mySpacing; // The size of the FFT - const size_t nbytes = N * sizeof(complexfix); + const size_t nbytes = mySpacing * sizeof(complexfix); + fprintf(stderr, "sizeof(complexfix)=%zu\n", sizeof(complexfix)); #define IIO_ENSURE(expr, err) { \ if (!(expr)) { \ @@ -721,17 +721,6 @@ int OfdmGeneratorDEXTER::process(Buffer* const dataIn, Buffer* dataOut) throw std::runtime_error("OfdmGenerator::process incorrect iio buffer size!"); } - ptrdiff_t p_inc = iio_buffer_step(m_buf_out); - if (p_inc != 1) { - throw std::runtime_error("OfdmGenerator::process Wrong p_inc"); - } - - const uint8_t *fft_out = (const uint8_t*)iio_buffer_first(m_buf_out, m_channel_out); - const uint8_t *fft_out_end = (const uint8_t*)iio_buffer_end(m_buf_out); - if (((fft_out_end - fft_out) != (ssize_t)(mySpacing * sizeof(complexfix))) != 0) { - throw std::runtime_error("OfdmGenerator::process fft_out length invalid!"); - } - complexfix *fft_in = reinterpret_cast(iio_buffer_start(m_buf_in)); fft_in[0] = static_cast(0); @@ -758,6 +747,21 @@ int OfdmGeneratorDEXTER::process(Buffer* const dataIn, Buffer* dataOut) throw std::runtime_error("OfdmGenerator::process error refilling IIO buffer!"); } + fprintf(stderr, "IIO refill %zd\n", nbytes_rx); + + ptrdiff_t p_inc = iio_buffer_step(m_buf_out); + if (p_inc != 1) { + throw std::runtime_error("OfdmGenerator::process Wrong p_inc"); + } + + const uint8_t *fft_out = (const uint8_t*)iio_buffer_first(m_buf_out, m_channel_out); + const uint8_t *fft_out_end = (const uint8_t*)iio_buffer_end(m_buf_out); + if ((fft_out_end - fft_out) != (ssize_t)(mySpacing * sizeof(complexfix))) { + fprintf(stderr, "FFT_OUT: %p %p %zu %zu\n", + fft_out, fft_out_end, (fft_out_end - fft_out), mySpacing * sizeof(complexfix)); + throw std::runtime_error("OfdmGenerator::process fft_out length invalid!"); + } + memcpy(out, fft_out, mySpacing * sizeof(complexfix)); in += myNbCarriers; diff --git a/src/PhaseReference.cpp b/src/PhaseReference.cpp index d7b89bf..e2fb9a9 100644 --- a/src/PhaseReference.cpp +++ b/src/PhaseReference.cpp @@ -137,8 +137,8 @@ complexf PhaseRefGen::convert(uint8_t data) { template <> complexfix PhaseRefGen::convert(uint8_t data) { - constexpr auto one = fpm::fixed_16_16{1}; - constexpr auto zero = fpm::fixed_16_16{0}; + constexpr auto one = fixed_16{1}; + constexpr auto zero = fixed_16{0}; const complexfix value[] = { complexfix(one, zero), -- cgit v1.2.3 From f1a3db6d7dc1461bcf4a8933a77267698fdffd30 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Tue, 29 Oct 2024 23:52:22 +0100 Subject: Rework fixed point config setting --- src/Buffer.h | 1 + src/ConfigParser.cpp | 24 ++++++- src/ConfigParser.h | 8 ++- src/DabMod.cpp | 18 +++--- src/DabModulator.cpp | 96 +++++++++++++++------------- src/FormatConverter.cpp | 142 +++++++++++++++++++++++++----------------- src/FormatConverter.h | 9 ++- src/GuardIntervalInserter.cpp | 23 ++++--- src/GuardIntervalInserter.h | 5 +- src/OfdmGenerator.cpp | 24 ++++--- 10 files changed, 213 insertions(+), 137 deletions(-) (limited to 'src/FormatConverter.cpp') diff --git a/src/Buffer.h b/src/Buffer.h index f6c94e0..bf3b5f4 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -40,6 +40,7 @@ typedef std::complex complexf; using fixed_16 = fpm::fixed; typedef std::complex complexfix; +typedef std::complex complexfix_wide; /* Buffer is a container for a byte array, which is memory-aligned * to 32 bytes for SSE performance. diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index a48f7e7..5d9f6f3 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -65,6 +65,27 @@ static GainMode parse_gainmode(const std::string &gainMode_setting) throw std::runtime_error("Configuration error"); } +static FFTEngine parse_fft_engine(const std::string &fft_engine_setting) +{ + string fft_engine_minuscule(fft_engine_setting); + std::transform(fft_engine_minuscule.begin(), fft_engine_minuscule.end(), + fft_engine_minuscule.begin(), ::tolower); + + if (fft_engine_minuscule == "fftw") { + return FFTEngine::FFTW; + } + else if (fft_engine_minuscule == "kiss") { + return FFTEngine::KISS; + } + else if (fft_engine_minuscule == "dexter") { + return FFTEngine::DEXTER; + } + + cerr << "Modulator fft_engine setting '" << fft_engine_setting << + "' not recognised." << endl; + throw std::runtime_error("Configuration error"); +} + static void parse_configfile( const std::string& configuration_file, mod_settings_t& mod_settings) @@ -154,7 +175,8 @@ static void parse_configfile( mod_settings.showProcessTime); // modulator parameters: - mod_settings.fixedPoint = pt.GetInteger("modulator.fixed_point", mod_settings.fixedPoint); + const string fft_engine_setting = pt.Get("modulator.fft_engine", "fftw"); + mod_settings.fftEngine = parse_fft_engine(fft_engine_setting); const string gainMode_setting = pt.Get("modulator.gainmode", "var"); mod_settings.gainMode = parse_gainmode(gainMode_setting); diff --git a/src/ConfigParser.h b/src/ConfigParser.h index f3a2af9..3bacfdd 100644 --- a/src/ConfigParser.h +++ b/src/ConfigParser.h @@ -36,6 +36,12 @@ #include "TII.h" #include "output/SDRDevice.h" +enum class FFTEngine { + FFTW, // floating point in software + KISS, // fixed-point in software + DEXTER // fixed-point in FPGA +}; + struct mod_settings_t { std::string startupCheck; @@ -51,7 +57,7 @@ struct mod_settings_t { bool useLimeOutput = false; bool useBladeRFOutput = false; - bool fixedPoint = false; + FFTEngine fftEngine = FFTEngine::FFTW; size_t outputRate = 2048000; size_t clockRate = 0; diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 4726df9..361e0d4 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -252,7 +252,7 @@ static shared_ptr prepare_output(mod_settings_t& s) shared_ptr output; if (s.useFileOutput) { - if (s.fixedPoint) { + if (s.fftEngine != FFTEngine::FFTW) { // Intentionally ignore fileOutputFormat, it is always sc16 output = make_shared(s.outputName, s.fileOutputShowMetadata); } @@ -292,7 +292,7 @@ static shared_ptr prepare_output(mod_settings_t& s) else if (s.useUHDOutput) { s.normalise = 1.0f / normalise_factor; s.sdr_device_config.sampleRate = s.outputRate; - s.sdr_device_config.fixedPoint = s.fixedPoint; + s.sdr_device_config.fixedPoint = (s.fftEngine != FFTEngine::FFTW); auto uhddevice = make_shared(s.sdr_device_config); output = make_shared(s.sdr_device_config, uhddevice); rcs.enrol((Output::SDR*)output.get()); @@ -303,7 +303,7 @@ static shared_ptr prepare_output(mod_settings_t& s) /* We normalise the same way as for the UHD output */ s.normalise = 1.0f / normalise_factor; s.sdr_device_config.sampleRate = s.outputRate; - if (s.fixedPoint) throw runtime_error("soapy fixed_point unsupported"); + if (s.fftEngine != FFTEngine::FFTW) throw runtime_error("soapy fixed_point unsupported"); auto soapydevice = make_shared(s.sdr_device_config); output = make_shared(s.sdr_device_config, soapydevice); rcs.enrol((Output::SDR*)output.get()); @@ -323,7 +323,7 @@ static shared_ptr prepare_output(mod_settings_t& s) else if (s.useLimeOutput) { /* We normalise the same way as for the UHD output */ s.normalise = 1.0f / normalise_factor; - if (s.fixedPoint) throw runtime_error("limesdr fixed_point unsupported"); + if (s.fftEngine != FFTEngine::FFTW) throw runtime_error("limesdr fixed_point unsupported"); s.sdr_device_config.sampleRate = s.outputRate; auto limedevice = make_shared(s.sdr_device_config); output = make_shared(s.sdr_device_config, limedevice); @@ -334,7 +334,7 @@ static shared_ptr prepare_output(mod_settings_t& s) else if (s.useBladeRFOutput) { /* We normalise specifically for the BladeRF output : range [-2048; 2047] */ s.normalise = 2047.0f / normalise_factor; - if (s.fixedPoint) throw runtime_error("bladerf fixed_point unsupported"); + if (s.fftEngine != FFTEngine::FFTW) throw runtime_error("bladerf fixed_point unsupported"); s.sdr_device_config.sampleRate = s.outputRate; auto bladerfdevice = make_shared(s.sdr_device_config); output = make_shared(s.sdr_device_config, bladerfdevice); @@ -424,7 +424,7 @@ int launch_modulator(int argc, char* argv[]) rcs.enrol(&m); // Neither KISS FFT used for fixedpoint nor the FFT Accelerator used for DEXTER need planning. - if (not (mod_settings.fixedPoint or mod_settings.useDexterOutput)) { + if (mod_settings.fftEngine == FFTEngine::FFTW) { // This is mostly useful on ARM systems where FFTW planning takes some time. If we do it here // it will be done before the modulator starts up etiLog.level(debug) << "Running FFTW planning..."; @@ -446,9 +446,13 @@ int launch_modulator(int argc, char* argv[]) } std::string output_format; - if (mod_settings.fixedPoint) { + if (mod_settings.fftEngine == FFTEngine::KISS) { output_format = ""; //fixed point is native sc16, no converter needed } + else if (mod_settings.fftEngine == FFTEngine::DEXTER) { + output_format = "s16"; // FPGA FFT Engine outputs s32 + } + // else FFTW, i.e. floating point else if (mod_settings.useFileOutput and (mod_settings.fileOutputFormat == "s8" or mod_settings.fileOutputFormat == "u8" or diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index 5f01725..4cbd0f5 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -142,13 +142,14 @@ int DabModulator::process(Buffer* dataOut) auto cifMux = make_shared(m_etiSource); auto cifPart = make_shared(mode); - auto cifMap = make_shared(m_nbCarriers, m_settings.fixedPoint); - auto cifRef = make_shared(mode, m_settings.fixedPoint); - auto cifFreq = make_shared(mode, m_settings.fixedPoint); - auto cifDiff = make_shared(m_nbCarriers, m_settings.fixedPoint); + const bool fixedPoint = m_settings.fftEngine != FFTEngine::FFTW; + auto cifMap = make_shared(m_nbCarriers, fixedPoint); + auto cifRef = make_shared(mode, fixedPoint); + auto cifFreq = make_shared(mode, fixedPoint); + auto cifDiff = make_shared(m_nbCarriers, fixedPoint); auto cifNull = make_shared(m_nbCarriers, - m_settings.fixedPoint ? sizeof(complexfix) : sizeof(complexf)); + fixedPoint ? sizeof(complexfix) : sizeof(complexf)); auto cifSig = make_shared(); // TODO this needs a review @@ -178,7 +179,7 @@ int DabModulator::process(Buffer* dataOut) shared_ptr tii; shared_ptr tiiRef; try { - if (m_settings.fixedPoint) { + if (fixedPoint) { etiLog.level(warn) << "TII does not yet support fixed point"; } else { @@ -186,7 +187,7 @@ int DabModulator::process(Buffer* dataOut) m_settings.dabMode, m_settings.tiiConfig); rcs.enrol(tii.get()); - tiiRef = make_shared(mode, m_settings.fixedPoint); + tiiRef = make_shared(mode, fixedPoint); } } catch (const TIIError& e) { @@ -195,40 +196,43 @@ int DabModulator::process(Buffer* dataOut) shared_ptr cifOfdm; - if (m_settings.useDexterOutput) { - cifOfdm = make_shared( - (1 + m_nbSymbols), - m_nbCarriers, - m_spacing, - m_settings.enableCfr, - m_settings.cfrClip, - m_settings.cfrErrorClip); - } - else if (m_settings.fixedPoint) { - cifOfdm = make_shared( - (1 + m_nbSymbols), - m_nbCarriers, - m_spacing, - m_settings.enableCfr, - m_settings.cfrClip, - m_settings.cfrErrorClip); - } - else { - auto ofdm = make_shared( - (1 + m_nbSymbols), - m_nbCarriers, - m_spacing, - m_settings.enableCfr, - m_settings.cfrClip, - m_settings.cfrErrorClip); - - rcs.enrol(ofdm.get()); - cifOfdm = ofdm; + switch (m_settings.fftEngine) { + case FFTEngine::FFTW: + { + auto ofdm = make_shared( + (1 + m_nbSymbols), + m_nbCarriers, + m_spacing, + m_settings.enableCfr, + m_settings.cfrClip, + m_settings.cfrErrorClip); + rcs.enrol(ofdm.get()); + cifOfdm = ofdm; + } + break; + case FFTEngine::KISS: + cifOfdm = make_shared( + (1 + m_nbSymbols), + m_nbCarriers, + m_spacing, + m_settings.enableCfr, + m_settings.cfrClip, + m_settings.cfrErrorClip); + break; + case FFTEngine::DEXTER: + cifOfdm = make_shared( + (1 + m_nbSymbols), + m_nbCarriers, + m_spacing, + m_settings.enableCfr, + m_settings.cfrClip, + m_settings.cfrErrorClip); + break; } shared_ptr cifGain; - if (not m_settings.fixedPoint) { + if (not fixedPoint) { cifGain = make_shared( m_spacing, m_settings.gainMode, @@ -241,12 +245,12 @@ int DabModulator::process(Buffer* dataOut) auto cifGuard = make_shared( m_nbSymbols, m_spacing, m_nullSize, m_symSize, - m_settings.ofdmWindowOverlap, m_settings.fixedPoint); + m_settings.ofdmWindowOverlap, m_settings.fftEngine); rcs.enrol(cifGuard.get()); shared_ptr cifFilter; if (not m_settings.filterTapsFilename.empty()) { - if (m_settings.fixedPoint) throw std::runtime_error("fixed point doesn't support fir filter"); + if (fixedPoint) throw std::runtime_error("fixed point doesn't support fir filter"); cifFilter = make_shared(m_settings.filterTapsFilename); rcs.enrol(cifFilter.get()); @@ -254,7 +258,7 @@ int DabModulator::process(Buffer* dataOut) shared_ptr cifPoly; if (not m_settings.polyCoefFilename.empty()) { - if (m_settings.fixedPoint) throw std::runtime_error("fixed point doesn't support predistortion"); + if (fixedPoint) throw std::runtime_error("fixed point doesn't support predistortion"); cifPoly = make_shared(m_settings.polyCoefFilename, m_settings.polyNumThreads); @@ -263,7 +267,7 @@ int DabModulator::process(Buffer* dataOut) shared_ptr cifRes; if (m_settings.outputRate != 2048000) { - if (m_settings.fixedPoint) throw std::runtime_error("fixed point doesn't support resampler"); + if (fixedPoint) throw std::runtime_error("fixed point doesn't support resampler"); cifRes = make_shared( 2048000, @@ -271,11 +275,13 @@ int DabModulator::process(Buffer* dataOut) m_spacing); } - if (not m_format.empty()) { - // This handles both complexf and fixedpoint: - // Convert from complexfix to interleaved int16_t I/Q - m_formatConverter = make_shared(m_format); + if (m_settings.fftEngine == FFTEngine::FFTW and not m_format.empty()) { + m_formatConverter = make_shared(false, m_format); + } + else if (m_settings.fftEngine == FFTEngine::DEXTER) { + m_formatConverter = make_shared(true, m_format); } + // KISS is already in s16 m_output = make_shared(dataOut); diff --git a/src/FormatConverter.cpp b/src/FormatConverter.cpp index a52f501..1821442 100644 --- a/src/FormatConverter.cpp +++ b/src/FormatConverter.cpp @@ -34,9 +34,10 @@ #include #include -FormatConverter::FormatConverter(const std::string& format) : +FormatConverter::FormatConverter(bool input_is_complexfix_wide, const std::string& format_out) : ModCodec(), - m_format(format) + m_input_complexfix_wide(input_is_complexfix_wide), + m_format_out(format_out) { } FormatConverter::~FormatConverter() @@ -55,67 +56,95 @@ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) size_t num_clipped_samples = 0; - size_t sizeIn = dataIn->getLength() / sizeof(float); - float* in = reinterpret_cast(dataIn->getData()); - if (m_format == "s16") { - dataOut->setLength(sizeIn * sizeof(int16_t)); - int16_t* out = reinterpret_cast(dataOut->getData()); - - for (size_t i = 0; i < sizeIn; i++) { - if (in[i] < INT16_MIN) { - out[i] = INT16_MIN; - num_clipped_samples++; - } - else if (in[i] > INT16_MAX) { - out[i] = INT16_MAX; - num_clipped_samples++; - } - else { - out[i] = in[i]; + if (m_input_complexfix_wide) { + size_t sizeIn = dataIn->getLength() / sizeof(int32_t); + int32_t* in = reinterpret_cast(dataIn->getData()); + if (m_format_out == "s16") { + dataOut->setLength(sizeIn * sizeof(int16_t)); + int16_t* out = reinterpret_cast(dataOut->getData()); + + for (size_t i = 0; i < sizeIn; i++) { + if (in[i] < INT16_MIN) { + out[i] = INT16_MIN; + num_clipped_samples++; + } + else if (in[i] > INT16_MAX) { + out[i] = INT16_MAX; + num_clipped_samples++; + } + else { + out[i] = in[i]; + } } } - } - else if (m_format == "u8") { - dataOut->setLength(sizeIn * sizeof(int8_t)); - uint8_t* out = reinterpret_cast(dataOut->getData()); - - for (size_t i = 0; i < sizeIn; i++) { - const auto samp = in[i] + 128.0f; - if (samp < 0) { - out[i] = 0; - num_clipped_samples++; - } - else if (samp > UINT8_MAX) { - out[i] = UINT8_MAX; - num_clipped_samples++; - } - else { - out[i] = samp; - } - + else { + throw std::runtime_error("FormatConverter: Invalid fix format " + m_format_out); } } - else if (m_format == "s8") { - dataOut->setLength(sizeIn * sizeof(int8_t)); - int8_t* out = reinterpret_cast(dataOut->getData()); - - for (size_t i = 0; i < sizeIn; i++) { - if (in[i] < INT8_MIN) { - out[i] = INT8_MIN; - num_clipped_samples++; + else { + size_t sizeIn = dataIn->getLength() / sizeof(float); + float* in = reinterpret_cast(dataIn->getData()); + + if (m_format_out == "s16") { + dataOut->setLength(sizeIn * sizeof(int16_t)); + int16_t* out = reinterpret_cast(dataOut->getData()); + + for (size_t i = 0; i < sizeIn; i++) { + if (in[i] < INT16_MIN) { + out[i] = INT16_MIN; + num_clipped_samples++; + } + else if (in[i] > INT16_MAX) { + out[i] = INT16_MAX; + num_clipped_samples++; + } + else { + out[i] = in[i]; + } } - else if (in[i] > INT8_MAX) { - out[i] = INT8_MAX; - num_clipped_samples++; + } + else if (m_format_out == "u8") { + dataOut->setLength(sizeIn * sizeof(int8_t)); + uint8_t* out = reinterpret_cast(dataOut->getData()); + + for (size_t i = 0; i < sizeIn; i++) { + const auto samp = in[i] + 128.0f; + if (samp < 0) { + out[i] = 0; + num_clipped_samples++; + } + else if (samp > UINT8_MAX) { + out[i] = UINT8_MAX; + num_clipped_samples++; + } + else { + out[i] = samp; + } + } - else { - out[i] = in[i]; + } + else if (m_format_out == "s8") { + dataOut->setLength(sizeIn * sizeof(int8_t)); + int8_t* out = reinterpret_cast(dataOut->getData()); + + for (size_t i = 0; i < sizeIn; i++) { + if (in[i] < INT8_MIN) { + out[i] = INT8_MIN; + num_clipped_samples++; + } + else if (in[i] > INT8_MAX) { + out[i] = INT8_MAX; + num_clipped_samples++; + } + else { + out[i] = in[i]; + } } } - } - else { - throw std::runtime_error("FormatConverter: Invalid format " + m_format); + else { + throw std::runtime_error("FormatConverter: Invalid format " + m_format_out); + } } m_num_clipped_samples.store(num_clipped_samples); @@ -136,10 +165,7 @@ size_t FormatConverter::get_num_clipped_samples() const size_t FormatConverter::get_format_size(const std::string& format) { // Returns 2*sizeof(SAMPLE_TYPE) because we have I + Q - if (format == "fixedpoint") { - return 4; - } - else if (format == "s16") { + if (format == "s16") { return 4; } else if (format == "u8") { diff --git a/src/FormatConverter.h b/src/FormatConverter.h index 27ca0b1..1ed2283 100644 --- a/src/FormatConverter.h +++ b/src/FormatConverter.h @@ -41,8 +41,10 @@ class FormatConverter : public ModCodec public: static size_t get_format_size(const std::string& format); - // Allowed formats: s8, u8 and s16 - FormatConverter(const std::string& format); + // floating-point input allows output formats: s8, u8 and s16 + // complexfix_wide input allows output formats: s16 + // complexfix input is already in s16, and needs no converter + FormatConverter(bool input_is_complexfix_wide, const std::string& format_out); virtual ~FormatConverter(); int process(Buffer* const dataIn, Buffer* dataOut); @@ -51,7 +53,8 @@ class FormatConverter : public ModCodec size_t get_num_clipped_samples() const; private: - std::string m_format; + bool m_input_complexfix_wide; + std::string m_format_out; std::atomic m_num_clipped_samples = 0; }; diff --git a/src/GuardIntervalInserter.cpp b/src/GuardIntervalInserter.cpp index 4e22367..7061e47 100644 --- a/src/GuardIntervalInserter.cpp +++ b/src/GuardIntervalInserter.cpp @@ -49,10 +49,10 @@ GuardIntervalInserter::GuardIntervalInserter( size_t nullSize, size_t symSize, size_t& windowOverlap, - bool fixedPoint) : + FFTEngine fftEngine) : ModCodec(), RemoteControllable("guardinterval"), - m_fixedPoint(fixedPoint), + m_fftEngine(fftEngine), m_params(nbSymbols, spacing, nullSize, symSize, windowOverlap) { if (nullSize == 0) { @@ -277,15 +277,18 @@ int do_process(const GuardIntervalInserter::Params& p, Buffer* const dataIn, Buf int GuardIntervalInserter::process(Buffer* const dataIn, Buffer* dataOut) { - if (m_fixedPoint) { - if (m_params.windowOverlap) { - throw std::runtime_error("fixed point and ofdm windowing not supported"); - } - return do_process(m_params, dataIn, dataOut); - } - else { - return do_process(m_params, dataIn, dataOut); + switch (m_fftEngine) { + case FFTEngine::FFTW: + return do_process(m_params, dataIn, dataOut); + case FFTEngine::KISS: + if (m_params.windowOverlap) { + throw std::runtime_error("fixed point and ofdm windowing not supported"); + } + return do_process(m_params, dataIn, dataOut); + case FFTEngine::DEXTER: + return do_process(m_params, dataIn, dataOut); } + throw std::logic_error("Unhandled fftEngine variant"); } void GuardIntervalInserter::set_parameter( diff --git a/src/GuardIntervalInserter.h b/src/GuardIntervalInserter.h index 380142e..8d329ff 100644 --- a/src/GuardIntervalInserter.h +++ b/src/GuardIntervalInserter.h @@ -30,6 +30,7 @@ # include #endif +#include "ConfigParser.h" #include "ModPlugin.h" #include "RemoteControl.h" #include @@ -51,7 +52,7 @@ class GuardIntervalInserter : public ModCodec, public RemoteControllable size_t nullSize, size_t symSize, size_t& windowOverlap, - bool fixedPoint); + FFTEngine fftEngine); virtual ~GuardIntervalInserter() {} @@ -84,7 +85,7 @@ class GuardIntervalInserter : public ModCodec, public RemoteControllable protected: void update_window(size_t new_window_overlap); - bool m_fixedPoint; + FFTEngine m_fftEngine; Params m_params; diff --git a/src/OfdmGenerator.cpp b/src/OfdmGenerator.cpp index 4f6eeb9..11f5bf1 100644 --- a/src/OfdmGenerator.cpp +++ b/src/OfdmGenerator.cpp @@ -633,8 +633,8 @@ OfdmGeneratorDEXTER::OfdmGeneratorDEXTER(size_t nbSymbols, PDEBUG(" myZeroDst: %u\n", myZeroDst); PDEBUG(" myZeroSize: %u\n", myZeroSize); - const size_t nbytes = mySpacing * sizeof(complexfix); - fprintf(stderr, "sizeof(complexfix)=%zu\n", sizeof(complexfix)); + const size_t nbytes_in = mySpacing * sizeof(complexfix); + const size_t nbytes_out = mySpacing * 2 * sizeof(int32_t); #define IIO_ENSURE(expr, err) { \ if (!(expr)) { \ @@ -651,12 +651,12 @@ OfdmGeneratorDEXTER::OfdmGeneratorDEXTER(size_t nbSymbols, iio_channel_enable(m_channel_in); iio_channel_enable(m_channel_out); - m_buf_in = iio_device_create_buffer(m_dev_in, nbytes, false); + m_buf_in = iio_device_create_buffer(m_dev_in, nbytes_in, false); if (!m_buf_in) { throw std::runtime_error("OfdmGeneratorDEXTER could not create in buffer"); } - m_buf_out = iio_device_create_buffer(m_dev_out, nbytes, false); + m_buf_out = iio_device_create_buffer(m_dev_out, nbytes_out, false); if (!m_buf_out) { throw std::runtime_error("OfdmGeneratorDEXTER could not create out buffer"); } @@ -692,13 +692,13 @@ OfdmGeneratorDEXTER::~OfdmGeneratorDEXTER() int OfdmGeneratorDEXTER::process(Buffer* const dataIn, Buffer* dataOut) { - dataOut->setLength(myNbSymbols * mySpacing * sizeof(complexfix)); + dataOut->setLength(myNbSymbols * mySpacing * sizeof(complexfix_wide)); complexfix *in = reinterpret_cast(dataIn->getData()); - complexfix *out = reinterpret_cast(dataOut->getData()); + complexfix_wide *out = reinterpret_cast(dataOut->getData()); size_t sizeIn = dataIn->getLength() / sizeof(complexfix); - size_t sizeOut = dataOut->getLength() / sizeof(complexfix); + size_t sizeOut = dataOut->getLength() / sizeof(complexfix_wide); if (sizeIn != myNbSymbols * myNbCarriers) { PDEBUG("Nb symbols: %zu\n", myNbSymbols); @@ -754,15 +754,19 @@ int OfdmGeneratorDEXTER::process(Buffer* const dataIn, Buffer* dataOut) throw std::runtime_error("OfdmGenerator::process Wrong p_inc"); } + // The FFT Accelerator takes 16-bit I + 16-bit Q, and outputs 32-bit I and 32-bit Q. + // The formatconvert will take care of this const uint8_t *fft_out = (const uint8_t*)iio_buffer_first(m_buf_out, m_channel_out); const uint8_t *fft_out_end = (const uint8_t*)iio_buffer_end(m_buf_out); - if ((fft_out_end - fft_out) != (ssize_t)(mySpacing * sizeof(complexfix))) { + constexpr size_t sizeof_out_iq = sizeof(complexfix_wide); + if ((fft_out_end - fft_out) != (ssize_t)(mySpacing * sizeof_out_iq)) { fprintf(stderr, "FFT_OUT: %p %p %zu %zu\n", - fft_out, fft_out_end, (fft_out_end - fft_out), mySpacing * sizeof(complexfix)); + fft_out, fft_out_end, (fft_out_end - fft_out), + mySpacing * sizeof_out_iq); throw std::runtime_error("OfdmGenerator::process fft_out length invalid!"); } - memcpy(out, fft_out, mySpacing * sizeof(complexfix)); + memcpy(out, fft_out, mySpacing * sizeof_out_iq); in += myNbCarriers; out += mySpacing; -- cgit v1.2.3 From 4057beacd02eab820ccf3b7c0633f1c8a0918e24 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Wed, 6 Nov 2024 20:05:57 +0100 Subject: FormatConverter: Renormalise for DEXTER --- src/FormatConverter.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/FormatConverter.cpp') diff --git a/src/FormatConverter.cpp b/src/FormatConverter.cpp index 1821442..0821191 100644 --- a/src/FormatConverter.cpp +++ b/src/FormatConverter.cpp @@ -65,16 +65,17 @@ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) int16_t* out = reinterpret_cast(dataOut->getData()); for (size_t i = 0; i < sizeIn; i++) { - if (in[i] < INT16_MIN) { + const int32_t val = in[i] >> 7; + if (val < INT16_MIN) { out[i] = INT16_MIN; num_clipped_samples++; } - else if (in[i] > INT16_MAX) { + else if (val > INT16_MAX) { out[i] = INT16_MAX; num_clipped_samples++; } else { - out[i] = in[i]; + out[i] = val; } } } -- cgit v1.2.3 From 767d69622770a4bb886f527eaa2e1e2a15a71309 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 11 Nov 2024 09:42:47 +0100 Subject: Use ARM NEON in FormatConverter --- src/Buffer.h | 2 +- src/CicEqualizer.h | 3 --- src/FormatConverter.cpp | 43 ++++++++++++++++++++++++++++++++++--------- src/Utils.cpp | 3 +++ 4 files changed, 38 insertions(+), 13 deletions(-) (limited to 'src/FormatConverter.cpp') diff --git a/src/Buffer.h b/src/Buffer.h index d5aa802..2c2a65e 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -43,7 +43,7 @@ typedef std::complex complexfix; typedef std::complex complexfix_wide; /* Buffer is a container for a byte array, which is memory-aligned - * to 32 bytes for SSE performance. + * to 32 bytes for SIMD performance. * * The allocation/freeing of the data is handled internally. */ diff --git a/src/CicEqualizer.h b/src/CicEqualizer.h index 70c3ae9..4510d0c 100644 --- a/src/CicEqualizer.h +++ b/src/CicEqualizer.h @@ -29,9 +29,6 @@ #include #include -#ifdef __SSE__ -# include -#endif class CicEqualizer : public ModCodec { diff --git a/src/FormatConverter.cpp b/src/FormatConverter.cpp index 0821191..94dfa2c 100644 --- a/src/FormatConverter.cpp +++ b/src/FormatConverter.cpp @@ -28,11 +28,15 @@ #include "FormatConverter.h" #include "PcDebug.h" +#include "Log.h" -#include -#include #include +#include #include +#include +#if defined(__ARM_NEON) +#include +#endif FormatConverter::FormatConverter(bool input_is_complexfix_wide, const std::string& format_out) : ModCodec(), @@ -42,9 +46,16 @@ FormatConverter::FormatConverter(bool input_is_complexfix_wide, const std::strin FormatConverter::~FormatConverter() { - etiLog.level(debug) << "FormatConverter: " - << m_num_clipped_samples.load() << - " clipped samples"; + if ( +#if defined(__ARM_NEON) + not m_input_complexfix_wide +#else + true +#endif + ) { + etiLog.level(debug) << "FormatConverter: " << + m_num_clipped_samples.load() << " clipped"; + } } @@ -56,16 +67,29 @@ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) size_t num_clipped_samples = 0; - if (m_input_complexfix_wide) { size_t sizeIn = dataIn->getLength() / sizeof(int32_t); - int32_t* in = reinterpret_cast(dataIn->getData()); if (m_format_out == "s16") { dataOut->setLength(sizeIn * sizeof(int16_t)); + const int32_t *in = reinterpret_cast(dataIn->getData()); int16_t* out = reinterpret_cast(dataOut->getData()); + constexpr int shift = 7; + +#if defined(__ARM_NEON) + if (sizeIn % 4 != 0) { + throw std::logic_error("Unexpected length not multiple of 4"); + } + + for (size_t i = 0; i < sizeIn; i += 4) { + int32x4_t input_vec = vld1q_s32(&in[i]); + // Apply shift right, saturate on conversion to int16_t + int16x4_t output_vec = vqshrn_n_s32(input_vec, shift); + vst1_s16(&out[i], output_vec); + } +#else for (size_t i = 0; i < sizeIn; i++) { - const int32_t val = in[i] >> 7; + const int32_t val = in[i] >> shift; if (val < INT16_MIN) { out[i] = INT16_MIN; num_clipped_samples++; @@ -78,6 +102,7 @@ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) out[i] = val; } } +#endif } else { throw std::runtime_error("FormatConverter: Invalid fix format " + m_format_out); @@ -85,7 +110,7 @@ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) } else { size_t sizeIn = dataIn->getLength() / sizeof(float); - float* in = reinterpret_cast(dataIn->getData()); + const float* in = reinterpret_cast(dataIn->getData()); if (m_format_out == "s16") { dataOut->setLength(sizeIn * sizeof(int16_t)); diff --git a/src/Utils.cpp b/src/Utils.cpp index 0065bc1..f54122c 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -62,6 +62,9 @@ static void printHeader() #endif #if defined(__SSE__) "SSE " << +#endif +#if defined(__ARM_NEON) + "NEON " << #endif "\n"; } -- cgit v1.2.3 From 8cabf783285d4bba1c87152f1c8044160dca8fe1 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Tue, 19 Nov 2024 14:47:33 +0100 Subject: Increase amplitude of DEXTER output --- src/FormatConverter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/FormatConverter.cpp') diff --git a/src/FormatConverter.cpp b/src/FormatConverter.cpp index 94dfa2c..517f26e 100644 --- a/src/FormatConverter.cpp +++ b/src/FormatConverter.cpp @@ -74,7 +74,7 @@ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) const int32_t *in = reinterpret_cast(dataIn->getData()); int16_t* out = reinterpret_cast(dataOut->getData()); - constexpr int shift = 7; + constexpr int shift = 6; #if defined(__ARM_NEON) if (sizeIn % 4 != 0) { -- cgit v1.2.3