mirror of
				https://github.com/AlexandreRouma/SDRPlusPlus.git
				synced 2025-11-04 10:49:11 +01:00 
			
		
		
		
	Added back the digital demodulators
This commit is contained in:
		
							
								
								
									
										6
									
								
								.github/workflows/build_all.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/build_all.yml
									
									
									
									
										vendored
									
									
								
							@@ -58,7 +58,7 @@ jobs:
 | 
			
		||||
 | 
			
		||||
        - name: Prepare CMake
 | 
			
		||||
          working-directory: ${{runner.workspace}}/build
 | 
			
		||||
          run: cmake "$Env:GITHUB_WORKSPACE" "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=OFF
 | 
			
		||||
          run: cmake "$Env:GITHUB_WORKSPACE" "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
 | 
			
		||||
 | 
			
		||||
        - name: Build
 | 
			
		||||
          working-directory: ${{runner.workspace}}/build
 | 
			
		||||
@@ -106,7 +106,7 @@ jobs:
 | 
			
		||||
 | 
			
		||||
        - name: Prepare CMake
 | 
			
		||||
          working-directory: ${{runner.workspace}}/build
 | 
			
		||||
          run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=OFF -DOPT_BUILD_SOAPY_SOURCE=OFF -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=OFF -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
 | 
			
		||||
          run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=OFF -DOPT_BUILD_SOAPY_SOURCE=OFF -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
 | 
			
		||||
 | 
			
		||||
        - name: Build
 | 
			
		||||
          working-directory: ${{runner.workspace}}/build
 | 
			
		||||
@@ -309,7 +309,7 @@ jobs:
 | 
			
		||||
        
 | 
			
		||||
        - name: Prepare CMake
 | 
			
		||||
          working-directory: ${{runner.workspace}}/build
 | 
			
		||||
          run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=OFF
 | 
			
		||||
          run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
 | 
			
		||||
 | 
			
		||||
        - name: Build
 | 
			
		||||
          working-directory: ${{runner.workspace}}/build
 | 
			
		||||
 
 | 
			
		||||
@@ -51,8 +51,8 @@ option(OPT_BUILD_NEW_PORTAUDIO_SINK "Build the new PortAudio Sink Module (Depend
 | 
			
		||||
# Decoders
 | 
			
		||||
option(OPT_BUILD_FALCON9_DECODER "Build the falcon9 live decoder (Dependencies: ffplay)" OFF)
 | 
			
		||||
option(OPT_BUILD_KG_SSTV_DECODER "Build the M17 decoder module (no dependencies required)" OFF)
 | 
			
		||||
option(OPT_BUILD_M17_DECODER "Build the M17 decoder module (no dependencies required)" OFF)
 | 
			
		||||
option(OPT_BUILD_METEOR_DEMODULATOR "Build the meteor demodulator module (no dependencies required)" OFF)
 | 
			
		||||
option(OPT_BUILD_M17_DECODER "Build the M17 decoder module (Dependencies: codec2)" OFF)
 | 
			
		||||
option(OPT_BUILD_METEOR_DEMODULATOR "Build the meteor demodulator module (no dependencies required)" ON)
 | 
			
		||||
option(OPT_BUILD_RADIO "Main audio modulation decoder (AM, FM, SSB, etc...)" ON)
 | 
			
		||||
option(OPT_BUILD_WEATHER_SAT_DECODER "Build the HRPT decoder module (no dependencies required)" OFF)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										199
									
								
								core/src/dsp/clock_recovery/mm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								core/src/dsp/clock_recovery/mm.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,199 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "../processor.h"
 | 
			
		||||
#include "../loop/phase_control_loop.h"
 | 
			
		||||
#include "../taps/windowed_sinc.h"
 | 
			
		||||
#include "../multirate/polyphase_bank.h"
 | 
			
		||||
#include "../math/step.h"
 | 
			
		||||
 | 
			
		||||
namespace dsp::clock_recovery {
 | 
			
		||||
    template<class T>
 | 
			
		||||
    class MM : public Processor<T, T> {
 | 
			
		||||
        using base_type = Processor<T, T> ;
 | 
			
		||||
    public:
 | 
			
		||||
        MM() {}
 | 
			
		||||
 | 
			
		||||
        MM(stream<T>* in, double omega, double omegaGain, double muGain, double omegaRelLimit, int interpPhaseCount = 128, int interpTapCount = 8) { init(in, omega, omegaGain, muGain, omegaRelLimit, interpPhaseCount, interpTapCount); }
 | 
			
		||||
 | 
			
		||||
        ~MM() {
 | 
			
		||||
            if (!base_type::_block_init) { return; }
 | 
			
		||||
            base_type::stop();
 | 
			
		||||
            dsp::multirate::freePolyphaseBank(interpBank);
 | 
			
		||||
            buffer::free(buffer);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void init(stream<T>* in, double omega, double omegaGain, double muGain, double omegaRelLimit, int interpPhaseCount = 128, int interpTapCount = 8) {
 | 
			
		||||
            _omega = omega;
 | 
			
		||||
            _omegaGain = omegaGain;
 | 
			
		||||
            _muGain = muGain;
 | 
			
		||||
            _omegaRelLimit = omegaRelLimit;
 | 
			
		||||
            _interpPhaseCount = interpPhaseCount;
 | 
			
		||||
            _interpTapCount = interpTapCount;
 | 
			
		||||
 | 
			
		||||
            pcl.init(_muGain, _omegaGain, 0.0, 0.0, 1.0, _omega, _omega * (1.0 - omegaRelLimit), _omega * (1.0 + omegaRelLimit));
 | 
			
		||||
            generateInterpTaps();
 | 
			
		||||
            buffer = buffer::alloc<T>(STREAM_BUFFER_SIZE + _interpTapCount);
 | 
			
		||||
            bufStart = &buffer[_interpTapCount - 1];
 | 
			
		||||
        
 | 
			
		||||
            base_type::init(in);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setOmega(double omega) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            base_type::tempStop();
 | 
			
		||||
            _omega = omega;
 | 
			
		||||
            offset = 0;
 | 
			
		||||
            pcl.phase = 0.0f;
 | 
			
		||||
            pcl.freq = _omega;
 | 
			
		||||
            pcl.setFreqLimits(_omega * (1.0 - _omegaRelLimit), _omega * (1.0 + _omegaRelLimit));
 | 
			
		||||
            base_type::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setOmegaGain(double omegaGain) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            _omegaGain = omegaGain;
 | 
			
		||||
            pcl.setCoefficients(_muGain, _omegaGain);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setMuGain(double muGain) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            _muGain = muGain;
 | 
			
		||||
            pcl.setCoefficients(_muGain, _omegaGain);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setOmegaRelLimit(double omegaRelLimit) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            _omegaRelLimit = omegaRelLimit;
 | 
			
		||||
            pcl.setFreqLimits(_omega * (1.0 - _omegaRelLimit), _omega * (1.0 + _omegaRelLimit));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setInterpParams(int interpPhaseCount, int interpTapCount) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            base_type::tempStop();
 | 
			
		||||
            _interpPhaseCount = interpPhaseCount;
 | 
			
		||||
            _interpTapCount = interpTapCount;
 | 
			
		||||
            dsp::multirate::freePolyphaseBank(interpBank);
 | 
			
		||||
            buffer::free(buffer);
 | 
			
		||||
            generateInterpTaps();
 | 
			
		||||
            buffer = buffer::alloc<T>(STREAM_BUFFER_SIZE + _interpTapCount);
 | 
			
		||||
            bufStart = &buffer[_interpTapCount - 1];
 | 
			
		||||
            base_type::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void reset() {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            base_type::tempStop();
 | 
			
		||||
            offset = 0;
 | 
			
		||||
            pcl.phase = 0.0f;
 | 
			
		||||
            pcl.freq = _omega;
 | 
			
		||||
            lastOut = 0.0f;
 | 
			
		||||
            _p_0T = { 0.0f, 0.0f }; _p_1T = { 0.0f, 0.0f }; _p_2T = { 0.0f, 0.0f };
 | 
			
		||||
            _c_0T = { 0.0f, 0.0f }; _c_1T = { 0.0f, 0.0f }; _c_2T = { 0.0f, 0.0f };
 | 
			
		||||
            base_type::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline int process(int count, const T* in, T* out) {
 | 
			
		||||
            // Copy data to work buffer
 | 
			
		||||
            memcpy(bufStart, in, count * sizeof(T));
 | 
			
		||||
 | 
			
		||||
            // Process all samples
 | 
			
		||||
            int outCount = 0;
 | 
			
		||||
            while (offset < count) {
 | 
			
		||||
                float error;
 | 
			
		||||
                T outVal;
 | 
			
		||||
 | 
			
		||||
                // Calculate new output value
 | 
			
		||||
                int phase = std::clamp<int>(floorf(pcl.phase * (float)_interpPhaseCount), 0, _interpPhaseCount - 1);
 | 
			
		||||
                if constexpr (std::is_same_v<T, float>) {
 | 
			
		||||
                    volk_32f_x2_dot_prod_32f(&outVal, &buffer[offset], interpBank.phases[phase], _interpTapCount);
 | 
			
		||||
                }
 | 
			
		||||
                if constexpr (std::is_same_v<T, complex_t>) {
 | 
			
		||||
                    volk_32fc_32f_dot_prod_32fc((lv_32fc_t*)&outVal, (lv_32fc_t*)&buffer[offset], interpBank.phases[phase], _interpTapCount);
 | 
			
		||||
                }
 | 
			
		||||
                out[outCount++] = outVal;
 | 
			
		||||
 | 
			
		||||
                // Calculate symbol phase error
 | 
			
		||||
                if constexpr (std::is_same_v<T, float>) {
 | 
			
		||||
                    error = (math::step(lastOut) * outVal) - (lastOut * math::step(outVal));
 | 
			
		||||
                    lastOut = outVal;
 | 
			
		||||
                }
 | 
			
		||||
                if constexpr (std::is_same_v<T, complex_t>) {
 | 
			
		||||
                    // Propagate delay
 | 
			
		||||
                    _p_2T = _p_1T;
 | 
			
		||||
                    _p_1T = _p_0T;
 | 
			
		||||
                    _c_2T = _c_1T;
 | 
			
		||||
                    _c_1T = _c_0T;
 | 
			
		||||
 | 
			
		||||
                    // Update the T0 values
 | 
			
		||||
                    _p_0T = outVal;
 | 
			
		||||
                    _c_0T = math::step(outVal);
 | 
			
		||||
 | 
			
		||||
                    // Error
 | 
			
		||||
                    error = (((_p_0T - _p_2T) * _c_1T.conj()) - ((_c_0T - _c_2T) * _p_1T.conj())).re;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Clamp symbol phase error
 | 
			
		||||
                if (error > 1.0f) { error = 1.0f; }
 | 
			
		||||
                if (error < -1.0f) { error = -1.0f; }
 | 
			
		||||
 | 
			
		||||
                // Advance symbol offset and phase
 | 
			
		||||
                pcl.advance(error);
 | 
			
		||||
                float delta = floorf(pcl.phase);
 | 
			
		||||
                offset += delta;
 | 
			
		||||
                pcl.phase -= delta;
 | 
			
		||||
            }
 | 
			
		||||
            offset -= count;
 | 
			
		||||
 | 
			
		||||
            // Update delay buffer
 | 
			
		||||
            memmove(buffer, &buffer[count], (_interpTapCount - 1) * sizeof(T));
 | 
			
		||||
 | 
			
		||||
            return outCount;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int run() {
 | 
			
		||||
            int count = base_type::_in->read();
 | 
			
		||||
            if (count < 0) { return -1; }
 | 
			
		||||
 | 
			
		||||
            int outCount = process(count, base_type::_in->readBuf, base_type::out.writeBuf);
 | 
			
		||||
 | 
			
		||||
            // Swap if some data was generated
 | 
			
		||||
            base_type::_in->flush();
 | 
			
		||||
            if (outCount) {
 | 
			
		||||
                if (!base_type::out.swap(outCount)) { return -1; }
 | 
			
		||||
            }
 | 
			
		||||
            return outCount;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
        void generateInterpTaps() {
 | 
			
		||||
            double bw = 0.5 / (double)_interpPhaseCount;
 | 
			
		||||
            dsp::tap<float> lp = dsp::taps::windowedSinc<float>(_interpPhaseCount * _interpTapCount, dsp::math::freqToOmega(bw, 1.0), dsp::window::nuttall, _interpPhaseCount);
 | 
			
		||||
            interpBank = dsp::multirate::buildPolyphaseBank<float>(_interpPhaseCount, lp);
 | 
			
		||||
            taps::free(lp);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        dsp::multirate::PolyphaseBank<float> interpBank;
 | 
			
		||||
        loop::PhaseControlLoop<double, false> pcl;
 | 
			
		||||
 | 
			
		||||
        double _omega;
 | 
			
		||||
        double _omegaGain;
 | 
			
		||||
        double _muGain;
 | 
			
		||||
        double _omegaRelLimit;
 | 
			
		||||
        int _interpPhaseCount;
 | 
			
		||||
        int _interpTapCount;
 | 
			
		||||
 | 
			
		||||
        // Previous output storage
 | 
			
		||||
        float lastOut = 0.0f;
 | 
			
		||||
        complex_t _p_0T = { 0.0f, 0.0f }, _p_1T = { 0.0f, 0.0f }, _p_2T = { 0.0f, 0.0f };
 | 
			
		||||
        complex_t _c_0T = { 0.0f, 0.0f }, _c_1T = { 0.0f, 0.0f }, _c_2T = { 0.0f, 0.0f };
 | 
			
		||||
 | 
			
		||||
        int offset = 0;
 | 
			
		||||
        T* buffer;
 | 
			
		||||
        T* bufStart;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										162
									
								
								core/src/dsp/demod/gmsk.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								core/src/dsp/demod/gmsk.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "quadrature.h"
 | 
			
		||||
#include "../taps/root_raised_cosine.h"
 | 
			
		||||
#include "../filter/fir.h"
 | 
			
		||||
#include "../clock_recovery/mm.h"
 | 
			
		||||
 | 
			
		||||
namespace dsp::demod {
 | 
			
		||||
    // Note: I don't like how this demodulator reuses 90% of the code from the PSK demod. Same will be for the PM demod...
 | 
			
		||||
    class GMSK : public Processor<complex_t, float> {
 | 
			
		||||
        using base_type = Processor<complex_t, float>;
 | 
			
		||||
    public:
 | 
			
		||||
        GMSK() {}
 | 
			
		||||
 | 
			
		||||
        GMSK(stream<complex_t>* in, double symbolrate, double samplerate, double deviation, int rrcTapCount, double rrcBeta, double omegaGain, double muGain, double omegaRelLimit = 0.01) {
 | 
			
		||||
            init(in, symbolrate, samplerate, deviation, rrcTapCount, rrcBeta, omegaGain, muGain);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ~GMSK() {
 | 
			
		||||
            if (!base_type::_block_init) { return; }
 | 
			
		||||
            base_type::stop();
 | 
			
		||||
            taps::free(rrcTaps);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void init(stream<complex_t>* in, double symbolrate, double samplerate, double deviation, int rrcTapCount, double rrcBeta, double omegaGain, double muGain, double omegaRelLimit = 0.01) {
 | 
			
		||||
            _symbolrate = symbolrate;
 | 
			
		||||
            _samplerate = samplerate;
 | 
			
		||||
            _deviation = deviation;
 | 
			
		||||
            _rrcTapCount = rrcTapCount;
 | 
			
		||||
            _rrcBeta = rrcBeta;
 | 
			
		||||
            
 | 
			
		||||
            demod.init(NULL, _deviation, _samplerate);
 | 
			
		||||
            rrcTaps = taps::rootRaisedCosine<float>(_rrcTapCount, _rrcBeta, _symbolrate, _samplerate);
 | 
			
		||||
            rrc.init(NULL, rrcTaps);
 | 
			
		||||
            recov.init(NULL, _samplerate / _symbolrate,  omegaGain, muGain, omegaRelLimit);
 | 
			
		||||
 | 
			
		||||
            demod.out.free();
 | 
			
		||||
            rrc.out.free();
 | 
			
		||||
            recov.out.free();
 | 
			
		||||
 | 
			
		||||
            base_type::init(in);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setSymbolrate(double symbolrate) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            base_type::tempStop();
 | 
			
		||||
            _symbolrate = symbolrate;
 | 
			
		||||
            taps::free(rrcTaps);
 | 
			
		||||
            rrcTaps = taps::rootRaisedCosine<float>(_rrcTapCount, _rrcBeta, _symbolrate, _samplerate);
 | 
			
		||||
            rrc.setTaps(rrcTaps);
 | 
			
		||||
            recov.setOmega(_samplerate / _symbolrate);
 | 
			
		||||
            base_type::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setSamplerate(double samplerate) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            base_type::tempStop();
 | 
			
		||||
            _samplerate = samplerate;
 | 
			
		||||
            demod.setDeviation(_deviation, _samplerate);
 | 
			
		||||
            taps::free(rrcTaps);
 | 
			
		||||
            rrcTaps = taps::rootRaisedCosine<float>(_rrcTapCount, _rrcBeta, _symbolrate, _samplerate);
 | 
			
		||||
            rrc.setTaps(rrcTaps);
 | 
			
		||||
            recov.setOmega(_samplerate / _symbolrate);
 | 
			
		||||
            base_type::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setDeviation(double deviation) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            _deviation = deviation;
 | 
			
		||||
            demod.setDeviation(_deviation, _samplerate);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setRRCParams(int rrcTapCount, double rrcBeta) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            base_type::tempStop();
 | 
			
		||||
            _rrcTapCount = rrcTapCount;
 | 
			
		||||
            _rrcBeta = rrcBeta;
 | 
			
		||||
            taps::free(rrcTaps);
 | 
			
		||||
            rrcTaps = taps::rootRaisedCosine<float>(_rrcTapCount, _rrcBeta, _symbolrate, _samplerate);
 | 
			
		||||
            base_type::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setRRCTapCount(int rrcTapCount) {
 | 
			
		||||
            setRRCParams(rrcTapCount, _rrcBeta);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setRRCBeta(int rrcBeta) {
 | 
			
		||||
            setRRCParams(_rrcTapCount, rrcBeta);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setMMParams(double omegaGain, double muGain, double omegaRelLimit = 0.01) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            recov.setOmegaGain(omegaGain);
 | 
			
		||||
            recov.setMuGain(muGain);
 | 
			
		||||
            recov.setOmegaRelLimit(omegaRelLimit);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setOmegaGain(double omegaGain) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            recov.setOmegaGain(omegaGain);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setMuGain(double muGain) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            recov.setMuGain(muGain);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setOmegaRelLimit(double omegaRelLimit) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            recov.setOmegaRelLimit(omegaRelLimit);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void reset() {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            base_type::tempStop();
 | 
			
		||||
            demod.reset();
 | 
			
		||||
            rrc.reset();
 | 
			
		||||
            recov.reset();
 | 
			
		||||
            base_type::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline int process(int count, complex_t* in, float* out) {
 | 
			
		||||
            demod.process(count, in, out);
 | 
			
		||||
            rrc.process(count, out, out);
 | 
			
		||||
            return recov.process(count, out, out);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int run() {
 | 
			
		||||
            int count = base_type::_in->read();
 | 
			
		||||
            if (count < 0) { return -1; }
 | 
			
		||||
 | 
			
		||||
            int outCount = process(count, base_type::_in->readBuf, base_type::out.writeBuf);
 | 
			
		||||
 | 
			
		||||
            // Swap if some data was generated
 | 
			
		||||
            base_type::_in->flush();
 | 
			
		||||
            if (outCount) {
 | 
			
		||||
                if (!base_type::out.swap(outCount)) { return -1; }
 | 
			
		||||
            }
 | 
			
		||||
            return outCount;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
        double _symbolrate;
 | 
			
		||||
        double _samplerate;
 | 
			
		||||
        double _deviation;
 | 
			
		||||
        int _rrcTapCount;
 | 
			
		||||
        double _rrcBeta;
 | 
			
		||||
 | 
			
		||||
        Quadrature demod;
 | 
			
		||||
        tap<float> rrcTaps;
 | 
			
		||||
        filter::FIR<float, float> rrc;
 | 
			
		||||
        clock_recovery::MM<float> recov;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										170
									
								
								core/src/dsp/demod/psk.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								core/src/dsp/demod/psk.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,170 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "../taps/root_raised_cosine.h"
 | 
			
		||||
#include "../filter/fir.h"
 | 
			
		||||
#include "../loop/fast_agc.h"
 | 
			
		||||
#include "../loop/costas.h"
 | 
			
		||||
#include "../clock_recovery/mm.h"
 | 
			
		||||
 | 
			
		||||
namespace dsp::demod {
 | 
			
		||||
    template<int ORDER>
 | 
			
		||||
    class PSK : public Processor<complex_t, complex_t> {
 | 
			
		||||
        using base_type = Processor<complex_t, complex_t>;
 | 
			
		||||
    public:
 | 
			
		||||
        PSK() {}
 | 
			
		||||
 | 
			
		||||
        PSK(stream<complex_t>* in, double symbolrate, double samplerate, int rrcTapCount, double rrcBeta, double agcRate, double costasBandwidth, double omegaGain, double muGain, double omegaRelLimit = 0.01) {
 | 
			
		||||
            init(in, symbolrate, samplerate, rrcTapCount, rrcBeta, agcRate, costasBandwidth, omegaGain, muGain);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ~PSK() {
 | 
			
		||||
            if (!base_type::_block_init) { return; }
 | 
			
		||||
            base_type::stop();
 | 
			
		||||
            taps::free(rrcTaps);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void init(stream<complex_t>* in, double symbolrate, double samplerate, int rrcTapCount, double rrcBeta, double agcRate, double costasBandwidth, double omegaGain, double muGain, double omegaRelLimit = 0.01) {
 | 
			
		||||
            _symbolrate = symbolrate;
 | 
			
		||||
            _samplerate = samplerate;
 | 
			
		||||
            _rrcTapCount = rrcTapCount;
 | 
			
		||||
            _rrcBeta = rrcBeta;
 | 
			
		||||
            
 | 
			
		||||
            rrcTaps = taps::rootRaisedCosine<float>(_rrcTapCount, _rrcBeta, _symbolrate, _samplerate);
 | 
			
		||||
            rrc.init(NULL, rrcTaps);
 | 
			
		||||
            agc.init(NULL, 1.0, 10e6, agcRate);
 | 
			
		||||
            costas.init(NULL, costasBandwidth);
 | 
			
		||||
            recov.init(NULL, _samplerate / _symbolrate,  omegaGain, muGain, omegaRelLimit);
 | 
			
		||||
 | 
			
		||||
            rrc.out.free();
 | 
			
		||||
            agc.out.free();
 | 
			
		||||
            costas.out.free();
 | 
			
		||||
            recov.out.free();
 | 
			
		||||
 | 
			
		||||
            base_type::init(in);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setSymbolrate(double symbolrate) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            base_type::tempStop();
 | 
			
		||||
            _symbolrate = symbolrate;
 | 
			
		||||
            taps::free(rrcTaps);
 | 
			
		||||
            rrcTaps = taps::rootRaisedCosine<float>(_rrcTapCount, _rrcBeta, _symbolrate, _samplerate);
 | 
			
		||||
            rrc.setTaps(rrcTaps);
 | 
			
		||||
            recov.setOmega(_samplerate / _symbolrate);
 | 
			
		||||
            base_type::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setSamplerate(double samplerate) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            base_type::tempStop();
 | 
			
		||||
            _samplerate = samplerate;
 | 
			
		||||
            taps::free(rrcTaps);
 | 
			
		||||
            rrcTaps = taps::rootRaisedCosine<float>(_rrcTapCount, _rrcBeta, _symbolrate, _samplerate);
 | 
			
		||||
            rrc.setTaps(rrcTaps);
 | 
			
		||||
            recov.setOmega(_samplerate / _symbolrate);
 | 
			
		||||
            base_type::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setRRCParams(int rrcTapCount, double rrcBeta) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            base_type::tempStop();
 | 
			
		||||
            _rrcTapCount = rrcTapCount;
 | 
			
		||||
            _rrcBeta = rrcBeta;
 | 
			
		||||
            taps::free(rrcTaps);
 | 
			
		||||
            rrcTaps = taps::rootRaisedCosine<float>(_rrcTapCount, _rrcBeta, _symbolrate, _samplerate);
 | 
			
		||||
            base_type::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setRRCTapCount(int rrcTapCount) {
 | 
			
		||||
            setRRCParams(rrcTapCount, _rrcBeta);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setRRCBeta(int rrcBeta) {
 | 
			
		||||
            setRRCParams(_rrcTapCount, rrcBeta);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setAGCRate(double agcRate) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            agc.setRate(agcRate);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setCostasBandwidth(double bandwidth) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            costas.setBandwidth(bandwidth);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setMMParams(double omegaGain, double muGain, double omegaRelLimit = 0.01) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            recov.setOmegaGain(omegaGain);
 | 
			
		||||
            recov.setMuGain(muGain);
 | 
			
		||||
            recov.setOmegaRelLimit(omegaRelLimit);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setOmegaGain(double omegaGain) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            recov.setOmegaGain(omegaGain);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setMuGain(double muGain) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            recov.setMuGain(muGain);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setOmegaRelLimit(double omegaRelLimit) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            recov.setOmegaRelLimit(omegaRelLimit);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void reset() {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            base_type::tempStop();
 | 
			
		||||
            rrc.reset();
 | 
			
		||||
            agc.reset();
 | 
			
		||||
            costas.reset();
 | 
			
		||||
            recov.reset();
 | 
			
		||||
            base_type::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline int process(int count, const complex_t* in, complex_t* out) {
 | 
			
		||||
            rrc.process(count, in, out);
 | 
			
		||||
            agc.process(count, out, out);
 | 
			
		||||
            costas.process(count, out, out);
 | 
			
		||||
            return recov.process(count, out, out);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int run() {
 | 
			
		||||
            int count = base_type::_in->read();
 | 
			
		||||
            if (count < 0) { return -1; }
 | 
			
		||||
 | 
			
		||||
            int outCount = process(count, base_type::_in->readBuf, base_type::out.writeBuf);
 | 
			
		||||
 | 
			
		||||
            // Swap if some data was generated
 | 
			
		||||
            base_type::_in->flush();
 | 
			
		||||
            if (outCount) {
 | 
			
		||||
                if (!base_type::out.swap(outCount)) { return -1; }
 | 
			
		||||
            }
 | 
			
		||||
            return outCount;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
        double _symbolrate;
 | 
			
		||||
        double _samplerate;
 | 
			
		||||
        int _rrcTapCount;
 | 
			
		||||
        double _rrcBeta;
 | 
			
		||||
 | 
			
		||||
        tap<float> rrcTaps;
 | 
			
		||||
        filter::FIR<complex_t, float> rrc;
 | 
			
		||||
        loop::FastAGC<complex_t> agc;
 | 
			
		||||
        loop::Costas<ORDER> costas;
 | 
			
		||||
        clock_recovery::MM<complex_t> recov;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										100
									
								
								core/src/dsp/loop/fast_agc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								core/src/dsp/loop/fast_agc.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "../processor.h"
 | 
			
		||||
 | 
			
		||||
namespace dsp::loop {
 | 
			
		||||
    template <class T>
 | 
			
		||||
    class FastAGC : public Processor<T, T> {
 | 
			
		||||
        using base_type = Processor<T, T>;
 | 
			
		||||
    public:
 | 
			
		||||
        FastAGC() {}
 | 
			
		||||
 | 
			
		||||
        FastAGC(stream<T>* in, double setPoint, double maxGain, double rate, double initGain = 1.0) { init(in, setPoint, maxGain, rate, initGain); }
 | 
			
		||||
 | 
			
		||||
        void init(stream<T>* in, double setPoint, double maxGain, double rate, double initGain = 1.0) {
 | 
			
		||||
            _setPoint = setPoint;
 | 
			
		||||
            _maxGain = maxGain;
 | 
			
		||||
            _rate = rate;
 | 
			
		||||
            _initGain = initGain;
 | 
			
		||||
 | 
			
		||||
            _gain = _initGain;
 | 
			
		||||
 | 
			
		||||
            base_type::init(in);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setSetPoint(double setPoint) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            _setPoint = setPoint;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setMaxGain(double maxGain) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            _maxGain = maxGain;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setRate(double rate) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            _rate = rate;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setInitGain(double initGain) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            _initGain = initGain;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setGain(double gain) {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            _gain = gain;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void reset() {
 | 
			
		||||
            assert(base_type::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
 | 
			
		||||
            _gain = _initGain;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline int process(int count, T* in, T* out) {
 | 
			
		||||
            for (int i = 0; i < count; i++) {
 | 
			
		||||
                // Output scaled input
 | 
			
		||||
                out[i] = in[i] * _gain;
 | 
			
		||||
 | 
			
		||||
                // Calculate output amplitude
 | 
			
		||||
                float amp;
 | 
			
		||||
                if constexpr (std::is_same_v<T, float>) {
 | 
			
		||||
                    amp = fabsf(out[i]);
 | 
			
		||||
                }
 | 
			
		||||
                if constexpr (std::is_same_v<T, complex_t>) {
 | 
			
		||||
                    amp = out[i].amplitude();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Update and clamp gain
 | 
			
		||||
                _gain += (_setPoint - amp) * _rate;
 | 
			
		||||
                if (_gain > _maxGain) { _gain = _maxGain; }
 | 
			
		||||
            }
 | 
			
		||||
            return count;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int run() {
 | 
			
		||||
            int count = base_type::_in->read();
 | 
			
		||||
            if (count < 0) { return -1; }
 | 
			
		||||
 | 
			
		||||
            process(count, base_type::_in->readBuf, base_type::out.writeBuf);
 | 
			
		||||
 | 
			
		||||
            base_type::_in->flush();
 | 
			
		||||
            if (!base_type::out.swap(count)) { return -1; }
 | 
			
		||||
            return count;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
        float _gain;
 | 
			
		||||
        float _setPoint;
 | 
			
		||||
        float _rate;
 | 
			
		||||
        float _maxGain;
 | 
			
		||||
        float _initGain;
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
#include "../types.h"
 | 
			
		||||
 | 
			
		||||
namespace dsp::loop {
 | 
			
		||||
    template<class T>
 | 
			
		||||
    template<class T, bool CLAMP_PHASE = true>
 | 
			
		||||
    class PhaseControlLoop {
 | 
			
		||||
    public:
 | 
			
		||||
        PhaseControlLoop() {}
 | 
			
		||||
@@ -62,7 +62,7 @@ namespace dsp::loop {
 | 
			
		||||
 | 
			
		||||
            // Increment and clamp phase
 | 
			
		||||
            phase += freq + (_alpha * error);
 | 
			
		||||
            clampPhase();
 | 
			
		||||
            if constexpr(CLAMP_PHASE) { clampPhase(); }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        T freq;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,18 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "../types.h"
 | 
			
		||||
 | 
			
		||||
namespace dsp::math {
 | 
			
		||||
    template <class T>
 | 
			
		||||
    inline T step(T x) {
 | 
			
		||||
        return (x > 0.0) ? 1.0 : -1.0;
 | 
			
		||||
        // TODO: Switch to cursed bit manipulation instead!
 | 
			
		||||
        if constexpr (std::is_same_v<T, complex_t>) {
 | 
			
		||||
            return { (x.re > 0.0f) ? 1.0f : -1.0f, (x.im > 0.0f) ? 1.0f : -1.0f };
 | 
			
		||||
        }
 | 
			
		||||
        else if constexpr (std::is_same_v<T, stereo_t>) {
 | 
			
		||||
            return { (x.l > 0.0f) ? 1.0f : -1.0f, (x.r > 0.0f) ? 1.0f : -1.0f };
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            return (x > 0.0) ? 1.0 : -1.0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								core/src/dsp/routing/doubler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								core/src/dsp/routing/doubler.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "../sink.h"
 | 
			
		||||
 | 
			
		||||
namespace dsp::routing {
 | 
			
		||||
    template <class T>
 | 
			
		||||
    class Doubler : public Sink<T> {
 | 
			
		||||
        using base_type = Sink<T>;
 | 
			
		||||
    public:
 | 
			
		||||
        Doubler() {}
 | 
			
		||||
 | 
			
		||||
        Doubler(stream<T>* in) { init(in); }
 | 
			
		||||
 | 
			
		||||
        void init(stream<T>* in) {
 | 
			
		||||
            base_type::registerOutput(&outA);
 | 
			
		||||
            base_type::registerOutput(&outB);
 | 
			
		||||
            base_type::init(in);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int run() {
 | 
			
		||||
            int count = base_type::_in->read();
 | 
			
		||||
            if (count < 0) { return -1; }
 | 
			
		||||
 | 
			
		||||
            memcpy(outA.writeBuf, base_type::_in->readBuf, count * sizeof(T));
 | 
			
		||||
            memcpy(outB.writeBuf, base_type::_in->readBuf, count * sizeof(T));
 | 
			
		||||
            if (!outA.swap(count)) {
 | 
			
		||||
                base_type::_in->flush();
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
            if (!outB.swap(count)) {
 | 
			
		||||
                base_type::_in->flush();
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            base_type::_in->flush();
 | 
			
		||||
 | 
			
		||||
            return count;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        stream<T> outA;
 | 
			
		||||
        stream<T> outB;
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
#include "tap.h"
 | 
			
		||||
#include "../math/constants.h"
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
namespace dsp::taps {
 | 
			
		||||
    template<class T>
 | 
			
		||||
    inline tap<T> rootRaisedCosine(int count, double beta, double Ts) {
 | 
			
		||||
        // Allocate taps
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,11 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <dsp/block.h>
 | 
			
		||||
#include <dsp/hier_block.h>
 | 
			
		||||
#include <dsp/sink/null_sink.h>
 | 
			
		||||
#include <dsp/demod/gmsk.h>
 | 
			
		||||
#include <dsp/routing/doubler.h>
 | 
			
		||||
#include <volk/volk.h>
 | 
			
		||||
#include <codec2.h>
 | 
			
		||||
#include <dsp/demodulator.h>
 | 
			
		||||
#include <golay24.h>
 | 
			
		||||
#include <lsf_decode.h>
 | 
			
		||||
 | 
			
		||||
@@ -86,7 +89,7 @@ const uint8_t M17_PUNCTURING_P2[12] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 };
 | 
			
		||||
static const correct_convolutional_polynomial_t correct_conv_m17_polynomial[] = { 0b11001, 0b10111 };
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
    class M17Slice4FSK : public generic_block<M17Slice4FSK> {
 | 
			
		||||
    class M17Slice4FSK : public block {
 | 
			
		||||
    public:
 | 
			
		||||
        M17Slice4FSK() {}
 | 
			
		||||
 | 
			
		||||
@@ -94,19 +97,19 @@ namespace dsp {
 | 
			
		||||
 | 
			
		||||
        void init(stream<float>* in) {
 | 
			
		||||
            _in = in;
 | 
			
		||||
            generic_block<M17Slice4FSK>::registerInput(_in);
 | 
			
		||||
            generic_block<M17Slice4FSK>::registerOutput(&out);
 | 
			
		||||
            generic_block<M17Slice4FSK>::_block_init = true;
 | 
			
		||||
            block::registerInput(_in);
 | 
			
		||||
            block::registerOutput(&out);
 | 
			
		||||
            block::_block_init = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setInput(stream<float>* in) {
 | 
			
		||||
            assert(generic_block<M17Slice4FSK>::_block_init);
 | 
			
		||||
            std::lock_guard<std::mutex> lck(generic_block<M17Slice4FSK>::ctrlMtx);
 | 
			
		||||
            generic_block<M17Slice4FSK>::tempStop();
 | 
			
		||||
            generic_block<M17Slice4FSK>::unregisterInput(_in);
 | 
			
		||||
            assert(block::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(block::ctrlMtx);
 | 
			
		||||
            block::tempStop();
 | 
			
		||||
            block::unregisterInput(_in);
 | 
			
		||||
            _in = in;
 | 
			
		||||
            generic_block<M17Slice4FSK>::registerInput(_in);
 | 
			
		||||
            generic_block<M17Slice4FSK>::tempStart();
 | 
			
		||||
            block::registerInput(_in);
 | 
			
		||||
            block::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int run() {
 | 
			
		||||
@@ -132,15 +135,15 @@ namespace dsp {
 | 
			
		||||
        stream<float>* _in;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class M17FrameDemux : public generic_block<M17FrameDemux> {
 | 
			
		||||
    class M17FrameDemux : public block {
 | 
			
		||||
    public:
 | 
			
		||||
        M17FrameDemux() {}
 | 
			
		||||
 | 
			
		||||
        M17FrameDemux(stream<uint8_t>* in) { init(in); }
 | 
			
		||||
 | 
			
		||||
        ~M17FrameDemux() {
 | 
			
		||||
            if (!generic_block<M17FrameDemux>::_block_init) { return; }
 | 
			
		||||
            generic_block<M17FrameDemux>::stop();
 | 
			
		||||
            if (!block::_block_init) { return; }
 | 
			
		||||
            block::stop();
 | 
			
		||||
            delete[] delay;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -149,22 +152,22 @@ namespace dsp {
 | 
			
		||||
 | 
			
		||||
            delay = new uint8_t[STREAM_BUFFER_SIZE];
 | 
			
		||||
 | 
			
		||||
            generic_block<M17FrameDemux>::registerInput(_in);
 | 
			
		||||
            generic_block<M17FrameDemux>::registerOutput(&linkSetupOut);
 | 
			
		||||
            generic_block<M17FrameDemux>::registerOutput(&lichOut);
 | 
			
		||||
            generic_block<M17FrameDemux>::registerOutput(&streamOut);
 | 
			
		||||
            generic_block<M17FrameDemux>::registerOutput(&packetOut);
 | 
			
		||||
            generic_block<M17FrameDemux>::_block_init = true;
 | 
			
		||||
            block::registerInput(_in);
 | 
			
		||||
            block::registerOutput(&linkSetupOut);
 | 
			
		||||
            block::registerOutput(&lichOut);
 | 
			
		||||
            block::registerOutput(&streamOut);
 | 
			
		||||
            block::registerOutput(&packetOut);
 | 
			
		||||
            block::_block_init = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setInput(stream<uint8_t>* in) {
 | 
			
		||||
            assert(generic_block<M17FrameDemux>::_block_init);
 | 
			
		||||
            std::lock_guard<std::mutex> lck(generic_block<M17FrameDemux>::ctrlMtx);
 | 
			
		||||
            generic_block<M17FrameDemux>::tempStop();
 | 
			
		||||
            generic_block<M17FrameDemux>::unregisterInput(_in);
 | 
			
		||||
            assert(block::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(block::ctrlMtx);
 | 
			
		||||
            block::tempStop();
 | 
			
		||||
            block::unregisterInput(_in);
 | 
			
		||||
            _in = in;
 | 
			
		||||
            generic_block<M17FrameDemux>::registerInput(_in);
 | 
			
		||||
            generic_block<M17FrameDemux>::tempStart();
 | 
			
		||||
            block::registerInput(_in);
 | 
			
		||||
            block::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int run() {
 | 
			
		||||
@@ -268,15 +271,15 @@ namespace dsp {
 | 
			
		||||
        int outCount = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class M17LSFDecoder : public generic_block<M17LSFDecoder> {
 | 
			
		||||
    class M17LSFDecoder : public block {
 | 
			
		||||
    public:
 | 
			
		||||
        M17LSFDecoder() {}
 | 
			
		||||
 | 
			
		||||
        M17LSFDecoder(stream<uint8_t>* in, void (*handler)(M17LSF& lsf, void* ctx), void* ctx) { init(in, handler, ctx); }
 | 
			
		||||
 | 
			
		||||
        ~M17LSFDecoder() {
 | 
			
		||||
            if (!generic_block<M17LSFDecoder>::_block_init) { return; }
 | 
			
		||||
            generic_block<M17LSFDecoder>::stop();
 | 
			
		||||
            if (!block::_block_init) { return; }
 | 
			
		||||
            block::stop();
 | 
			
		||||
            correct_convolutional_destroy(conv);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -287,18 +290,18 @@ namespace dsp {
 | 
			
		||||
 | 
			
		||||
            conv = correct_convolutional_create(2, 5, correct_conv_m17_polynomial);
 | 
			
		||||
 | 
			
		||||
            generic_block<M17LSFDecoder>::registerInput(_in);
 | 
			
		||||
            generic_block<M17LSFDecoder>::_block_init = true;
 | 
			
		||||
            block::registerInput(_in);
 | 
			
		||||
            block::_block_init = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setInput(stream<uint8_t>* in) {
 | 
			
		||||
            assert(generic_block<M17LSFDecoder>::_block_init);
 | 
			
		||||
            std::lock_guard<std::mutex> lck(generic_block<M17LSFDecoder>::ctrlMtx);
 | 
			
		||||
            generic_block<M17LSFDecoder>::tempStop();
 | 
			
		||||
            generic_block<M17LSFDecoder>::unregisterInput(_in);
 | 
			
		||||
            assert(block::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(block::ctrlMtx);
 | 
			
		||||
            block::tempStop();
 | 
			
		||||
            block::unregisterInput(_in);
 | 
			
		||||
            _in = in;
 | 
			
		||||
            generic_block<M17LSFDecoder>::registerInput(_in);
 | 
			
		||||
            generic_block<M17LSFDecoder>::tempStart();
 | 
			
		||||
            block::registerInput(_in);
 | 
			
		||||
            block::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int run() {
 | 
			
		||||
@@ -346,15 +349,15 @@ namespace dsp {
 | 
			
		||||
        correct_convolutional* conv;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class M17PayloadFEC : public generic_block<M17PayloadFEC> {
 | 
			
		||||
    class M17PayloadFEC : public block {
 | 
			
		||||
    public:
 | 
			
		||||
        M17PayloadFEC() {}
 | 
			
		||||
 | 
			
		||||
        M17PayloadFEC(stream<uint8_t>* in) { init(in); }
 | 
			
		||||
 | 
			
		||||
        ~M17PayloadFEC() {
 | 
			
		||||
            if (!generic_block<M17PayloadFEC>::_block_init) { return; }
 | 
			
		||||
            generic_block<M17PayloadFEC>::stop();
 | 
			
		||||
            if (!block::_block_init) { return; }
 | 
			
		||||
            block::stop();
 | 
			
		||||
            correct_convolutional_destroy(conv);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -363,19 +366,19 @@ namespace dsp {
 | 
			
		||||
 | 
			
		||||
            conv = correct_convolutional_create(2, 5, correct_conv_m17_polynomial);
 | 
			
		||||
 | 
			
		||||
            generic_block<M17PayloadFEC>::registerInput(_in);
 | 
			
		||||
            generic_block<M17PayloadFEC>::registerOutput(&out);
 | 
			
		||||
            generic_block<M17PayloadFEC>::_block_init = true;
 | 
			
		||||
            block::registerInput(_in);
 | 
			
		||||
            block::registerOutput(&out);
 | 
			
		||||
            block::_block_init = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setInput(stream<uint8_t>* in) {
 | 
			
		||||
            assert(generic_block<M17PayloadFEC>::_block_init);
 | 
			
		||||
            std::lock_guard<std::mutex> lck(generic_block<M17PayloadFEC>::ctrlMtx);
 | 
			
		||||
            generic_block<M17PayloadFEC>::tempStop();
 | 
			
		||||
            generic_block<M17PayloadFEC>::unregisterInput(_in);
 | 
			
		||||
            assert(block::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(block::ctrlMtx);
 | 
			
		||||
            block::tempStop();
 | 
			
		||||
            block::unregisterInput(_in);
 | 
			
		||||
            _in = in;
 | 
			
		||||
            generic_block<M17PayloadFEC>::registerInput(_in);
 | 
			
		||||
            generic_block<M17PayloadFEC>::tempStart();
 | 
			
		||||
            block::registerInput(_in);
 | 
			
		||||
            block::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int run() {
 | 
			
		||||
@@ -419,15 +422,15 @@ namespace dsp {
 | 
			
		||||
        correct_convolutional* conv;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class M17Codec2Decode : public generic_block<M17Codec2Decode> {
 | 
			
		||||
    class M17Codec2Decode : public block {
 | 
			
		||||
    public:
 | 
			
		||||
        M17Codec2Decode() {}
 | 
			
		||||
 | 
			
		||||
        M17Codec2Decode(stream<uint8_t>* in) { init(in); }
 | 
			
		||||
 | 
			
		||||
        ~M17Codec2Decode() {
 | 
			
		||||
            if (!generic_block<M17Codec2Decode>::_block_init) { return; }
 | 
			
		||||
            generic_block<M17Codec2Decode>::stop();
 | 
			
		||||
            if (!block::_block_init) { return; }
 | 
			
		||||
            block::stop();
 | 
			
		||||
            codec2_destroy(codec);
 | 
			
		||||
            delete[] int16Audio;
 | 
			
		||||
            delete[] floatAudio;
 | 
			
		||||
@@ -442,19 +445,19 @@ namespace dsp {
 | 
			
		||||
            int16Audio = new int16_t[sampsPerC2FrameDouble];
 | 
			
		||||
            floatAudio = new float[sampsPerC2FrameDouble];
 | 
			
		||||
 | 
			
		||||
            generic_block<M17Codec2Decode>::registerInput(_in);
 | 
			
		||||
            generic_block<M17Codec2Decode>::registerOutput(&out);
 | 
			
		||||
            generic_block<M17Codec2Decode>::_block_init = true;
 | 
			
		||||
            block::registerInput(_in);
 | 
			
		||||
            block::registerOutput(&out);
 | 
			
		||||
            block::_block_init = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setInput(stream<uint8_t>* in) {
 | 
			
		||||
            assert(generic_block<M17Codec2Decode>::_block_init);
 | 
			
		||||
            std::lock_guard<std::mutex> lck(generic_block<M17Codec2Decode>::ctrlMtx);
 | 
			
		||||
            generic_block<M17Codec2Decode>::tempStop();
 | 
			
		||||
            generic_block<M17Codec2Decode>::unregisterInput(_in);
 | 
			
		||||
            assert(block::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(block::ctrlMtx);
 | 
			
		||||
            block::tempStop();
 | 
			
		||||
            block::unregisterInput(_in);
 | 
			
		||||
            _in = in;
 | 
			
		||||
            generic_block<M17Codec2Decode>::registerInput(_in);
 | 
			
		||||
            generic_block<M17Codec2Decode>::tempStart();
 | 
			
		||||
            block::registerInput(_in);
 | 
			
		||||
            block::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int run() {
 | 
			
		||||
@@ -490,7 +493,7 @@ namespace dsp {
 | 
			
		||||
        int sampsPerC2FrameDouble = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class M17LICHDecoder : public generic_block<M17LICHDecoder> {
 | 
			
		||||
    class M17LICHDecoder : public block {
 | 
			
		||||
    public:
 | 
			
		||||
        M17LICHDecoder() {}
 | 
			
		||||
 | 
			
		||||
@@ -500,18 +503,18 @@ namespace dsp {
 | 
			
		||||
            _in = in;
 | 
			
		||||
            _handler = handler;
 | 
			
		||||
            _ctx = ctx;
 | 
			
		||||
            generic_block<M17LICHDecoder>::registerInput(_in);
 | 
			
		||||
            generic_block<M17LICHDecoder>::_block_init = true;
 | 
			
		||||
            block::registerInput(_in);
 | 
			
		||||
            block::_block_init = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setInput(stream<uint8_t>* in) {
 | 
			
		||||
            assert(generic_block<M17LICHDecoder>::_block_init);
 | 
			
		||||
            std::lock_guard<std::mutex> lck(generic_block<M17LICHDecoder>::ctrlMtx);
 | 
			
		||||
            generic_block<M17LICHDecoder>::tempStop();
 | 
			
		||||
            generic_block<M17LICHDecoder>::unregisterInput(_in);
 | 
			
		||||
            assert(block::_block_init);
 | 
			
		||||
            std::lock_guard<std::recursive_mutex> lck(block::ctrlMtx);
 | 
			
		||||
            block::tempStop();
 | 
			
		||||
            block::unregisterInput(_in);
 | 
			
		||||
            _in = in;
 | 
			
		||||
            generic_block<M17LICHDecoder>::registerInput(_in);
 | 
			
		||||
            generic_block<M17LICHDecoder>::tempStart();
 | 
			
		||||
            block::registerInput(_in);
 | 
			
		||||
            block::tempStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int run() {
 | 
			
		||||
@@ -590,7 +593,7 @@ namespace dsp {
 | 
			
		||||
        int lastId = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class M17Decoder : public generic_hier_block<M17Decoder> {
 | 
			
		||||
    class M17Decoder : public hier_block {
 | 
			
		||||
    public:
 | 
			
		||||
        M17Decoder() {}
 | 
			
		||||
 | 
			
		||||
@@ -601,11 +604,8 @@ namespace dsp {
 | 
			
		||||
        void init(stream<complex_t>* input, float sampleRate, void (*handler)(M17LSF& lsf, void* ctx), void* ctx) {
 | 
			
		||||
            _sampleRate = sampleRate;
 | 
			
		||||
 | 
			
		||||
            demod.init(input, _sampleRate, M17_DEVIATION);
 | 
			
		||||
            rrc.init(31, _sampleRate, M17_BAUDRATE, M17_RRC_ALPHA);
 | 
			
		||||
            fir.init(&demod.out, &rrc);
 | 
			
		||||
            recov.init(&fir.out, _sampleRate / M17_BAUDRATE, 1e-6f, 0.01f, 0.01f);
 | 
			
		||||
            doubler.init(&recov.out);
 | 
			
		||||
            demod.init(input, M17_BAUDRATE, sampleRate, M17_DEVIATION, 31, M17_RRC_ALPHA, 1e-6f, 0.01f, 0.01f);
 | 
			
		||||
            doubler.init(&demod.out);
 | 
			
		||||
            slice.init(&doubler.outA);
 | 
			
		||||
            demux.init(&slice.out);
 | 
			
		||||
            lsfFEC.init(&demux.linkSetupOut, handler, ctx);
 | 
			
		||||
@@ -618,24 +618,22 @@ namespace dsp {
 | 
			
		||||
            diagOut = &doubler.outB;
 | 
			
		||||
            out = &decodeAudio.out;
 | 
			
		||||
 | 
			
		||||
            generic_hier_block<M17Decoder>::registerBlock(&demod);
 | 
			
		||||
            generic_hier_block<M17Decoder>::registerBlock(&fir);
 | 
			
		||||
            generic_hier_block<M17Decoder>::registerBlock(&recov);
 | 
			
		||||
            generic_hier_block<M17Decoder>::registerBlock(&doubler);
 | 
			
		||||
            generic_hier_block<M17Decoder>::registerBlock(&slice);
 | 
			
		||||
            generic_hier_block<M17Decoder>::registerBlock(&demux);
 | 
			
		||||
            generic_hier_block<M17Decoder>::registerBlock(&lsfFEC);
 | 
			
		||||
            generic_hier_block<M17Decoder>::registerBlock(&payloadFEC);
 | 
			
		||||
            generic_hier_block<M17Decoder>::registerBlock(&decodeLICH);
 | 
			
		||||
            generic_hier_block<M17Decoder>::registerBlock(&decodeAudio);
 | 
			
		||||
            hier_block::registerBlock(&demod);
 | 
			
		||||
            hier_block::registerBlock(&doubler);
 | 
			
		||||
            hier_block::registerBlock(&slice);
 | 
			
		||||
            hier_block::registerBlock(&demux);
 | 
			
		||||
            hier_block::registerBlock(&lsfFEC);
 | 
			
		||||
            hier_block::registerBlock(&payloadFEC);
 | 
			
		||||
            hier_block::registerBlock(&decodeLICH);
 | 
			
		||||
            hier_block::registerBlock(&decodeAudio);
 | 
			
		||||
 | 
			
		||||
            generic_hier_block<M17Decoder>::registerBlock(&ns2);
 | 
			
		||||
            hier_block::registerBlock(&ns2);
 | 
			
		||||
 | 
			
		||||
            generic_hier_block<M17Decoder>::_block_init = true;
 | 
			
		||||
            hier_block::_block_init = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setInput(stream<complex_t>* input) {
 | 
			
		||||
            assert(generic_hier_block<M17Decoder>::_block_init);
 | 
			
		||||
            assert(hier_block::_block_init);
 | 
			
		||||
            demod.setInput(input);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -643,11 +641,8 @@ namespace dsp {
 | 
			
		||||
        stream<stereo_t>* out = NULL;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        FloatFMDemod demod;
 | 
			
		||||
        RRCTaps rrc;
 | 
			
		||||
        FIR<float> fir;
 | 
			
		||||
        MMClockRecovery<float> recov;
 | 
			
		||||
        StreamDoubler<float> doubler;
 | 
			
		||||
        demod::GMSK demod;
 | 
			
		||||
        routing::Doubler<float> doubler;
 | 
			
		||||
        M17Slice4FSK slice;
 | 
			
		||||
        M17FrameDemux demux;
 | 
			
		||||
        M17LSFDecoder lsfFEC;
 | 
			
		||||
@@ -655,7 +650,7 @@ namespace dsp {
 | 
			
		||||
        M17LICHDecoder decodeLICH;
 | 
			
		||||
        M17Codec2Decode decodeAudio;
 | 
			
		||||
 | 
			
		||||
        NullSink<uint8_t> ns2;
 | 
			
		||||
        dsp::sink::Null<uint8_t> ns2;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        float _sampleRate;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,14 +6,10 @@
 | 
			
		||||
#include <signal_path/signal_path.h>
 | 
			
		||||
#include <module.h>
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
#include <dsp/pll.h>
 | 
			
		||||
#include <dsp/stream.h>
 | 
			
		||||
#include <dsp/demodulator.h>
 | 
			
		||||
#include <dsp/window.h>
 | 
			
		||||
#include <dsp/resampling.h>
 | 
			
		||||
#include <dsp/processing.h>
 | 
			
		||||
#include <dsp/routing.h>
 | 
			
		||||
#include <dsp/sink.h>
 | 
			
		||||
#include <dsp/buffer/reshaper.h>
 | 
			
		||||
#include <dsp/multirate/rational_resampler.h>
 | 
			
		||||
#include <dsp/sink/handler_sink.h>
 | 
			
		||||
#include <gui/widgets/folder_select.h>
 | 
			
		||||
#include <gui/widgets/symbol_diagram.h>
 | 
			
		||||
#include <m17dsp.h>
 | 
			
		||||
@@ -61,12 +57,7 @@ public:
 | 
			
		||||
 | 
			
		||||
        // Initialize DSP here
 | 
			
		||||
        decoder.init(vfo->output, INPUT_SAMPLE_RATE, lsfHandler, this);
 | 
			
		||||
 | 
			
		||||
        resampWin.init(4000, 4000, audioSampRate);
 | 
			
		||||
        resamp.init(decoder.out, &resampWin, 8000, audioSampRate);
 | 
			
		||||
        resampWin.setSampleRate(8000 * resamp.getInterpolation());
 | 
			
		||||
        resamp.updateWindow(&resampWin);
 | 
			
		||||
 | 
			
		||||
        resamp.init(decoder.out, 8000, audioSampRate);
 | 
			
		||||
        reshape.init(decoder.diagOut, 480, 0);
 | 
			
		||||
        diagHandler.init(&reshape.out, _diagHandler, this);
 | 
			
		||||
 | 
			
		||||
@@ -250,11 +241,8 @@ private:
 | 
			
		||||
        M17DecoderModule* _this = (M17DecoderModule*)ctx;
 | 
			
		||||
        // TODO: If too slow, change all demods here and not when setting
 | 
			
		||||
        _this->audioSampRate = sampleRate;
 | 
			
		||||
        _this->resampWin.setCutoff(std::min<float>(sampleRate / 2, 4000));
 | 
			
		||||
        _this->resamp.tempStop();
 | 
			
		||||
        _this->resamp.setOutSampleRate(sampleRate);
 | 
			
		||||
        _this->resampWin.setSampleRate(8000 * _this->resamp.getInterpolation());
 | 
			
		||||
        _this->resamp.updateWindow(&_this->resampWin);
 | 
			
		||||
        _this->resamp.setOutSamplerate(sampleRate);
 | 
			
		||||
        _this->resamp.tempStart();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -273,11 +261,9 @@ private:
 | 
			
		||||
 | 
			
		||||
    dsp::M17Decoder decoder;
 | 
			
		||||
 | 
			
		||||
    dsp::Reshaper<float> reshape;
 | 
			
		||||
    dsp::HandlerSink<float> diagHandler;
 | 
			
		||||
 | 
			
		||||
    dsp::filter_window::BlackmanWindow resampWin;
 | 
			
		||||
    dsp::PolyphaseResampler<dsp::stereo_t> resamp;
 | 
			
		||||
    dsp::buffer::Reshaper<float> reshape;
 | 
			
		||||
    dsp::sink::Handler<float> diagHandler;
 | 
			
		||||
    dsp::multirate::RationalResampler<dsp::stereo_t> resamp;
 | 
			
		||||
 | 
			
		||||
    ImGui::SymbolDiagram diag;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,14 +6,10 @@
 | 
			
		||||
#include <signal_path/signal_path.h>
 | 
			
		||||
#include <module.h>
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
#include <dsp/pll.h>
 | 
			
		||||
#include <dsp/stream.h>
 | 
			
		||||
#include <dsp/demodulator.h>
 | 
			
		||||
#include <dsp/window.h>
 | 
			
		||||
#include <dsp/resampling.h>
 | 
			
		||||
#include <dsp/processing.h>
 | 
			
		||||
#include <dsp/routing.h>
 | 
			
		||||
#include <dsp/sink.h>
 | 
			
		||||
#include <dsp/demod/psk.h>
 | 
			
		||||
#include <dsp/routing/splitter.h>
 | 
			
		||||
#include <dsp/buffer/reshaper.h>
 | 
			
		||||
#include <dsp/sink/handler_sink.h>
 | 
			
		||||
#include <meteor_demodulator_interface.h>
 | 
			
		||||
#include <gui/widgets/folder_select.h>
 | 
			
		||||
#include <gui/widgets/constellation_diagram.h>
 | 
			
		||||
@@ -60,8 +56,8 @@ public:
 | 
			
		||||
        config.release(created);
 | 
			
		||||
 | 
			
		||||
        vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 150000, INPUT_SAMPLE_RATE, 150000, 150000, true);
 | 
			
		||||
        demod.init(vfo->output, INPUT_SAMPLE_RATE, 72000.0f, 32, 0.6f, 0.1f, 0.005f);
 | 
			
		||||
        split.init(demod.out);
 | 
			
		||||
        demod.init(vfo->output, 72000.0f, INPUT_SAMPLE_RATE, 33, 0.6f, 0.1f, 0.005f, (0.01 * 0.01) / 4.0, 0.01);
 | 
			
		||||
        split.init(&demod.out);
 | 
			
		||||
        split.bindStream(&symSinkStream);
 | 
			
		||||
        split.bindStream(&sinkStream);
 | 
			
		||||
        reshape.init(&symSinkStream, 1024, (72000 / 30) - 1024);
 | 
			
		||||
@@ -220,14 +216,14 @@ private:
 | 
			
		||||
 | 
			
		||||
    // DSP Chain
 | 
			
		||||
    VFOManager::VFO* vfo;
 | 
			
		||||
    dsp::PSKDemod<4, false> demod;
 | 
			
		||||
    dsp::Splitter<dsp::complex_t> split;
 | 
			
		||||
    dsp::demod::PSK<4> demod;
 | 
			
		||||
    dsp::routing::Splitter<dsp::complex_t> split;
 | 
			
		||||
 | 
			
		||||
    dsp::stream<dsp::complex_t> symSinkStream;
 | 
			
		||||
    dsp::stream<dsp::complex_t> sinkStream;
 | 
			
		||||
    dsp::Reshaper<dsp::complex_t> reshape;
 | 
			
		||||
    dsp::HandlerSink<dsp::complex_t> symSink;
 | 
			
		||||
    dsp::HandlerSink<dsp::complex_t> sink;
 | 
			
		||||
    dsp::buffer::Reshaper<dsp::complex_t> reshape;
 | 
			
		||||
    dsp::sink::Handler<dsp::complex_t> symSink;
 | 
			
		||||
    dsp::sink::Handler<dsp::complex_t> sink;
 | 
			
		||||
 | 
			
		||||
    ImGui::ConstellationDiagram constDiagram;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ cp inc/* /usr/include/
 | 
			
		||||
cd SDRPlusPlus
 | 
			
		||||
mkdir build
 | 
			
		||||
cd build
 | 
			
		||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=OFF
 | 
			
		||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
 | 
			
		||||
make VERBOSE=1 -j2
 | 
			
		||||
 | 
			
		||||
cd ..
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ cp inc/* /usr/include/
 | 
			
		||||
cd SDRPlusPlus
 | 
			
		||||
mkdir build
 | 
			
		||||
cd build
 | 
			
		||||
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=OFF
 | 
			
		||||
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
 | 
			
		||||
make VERBOSE=1 -j2
 | 
			
		||||
 | 
			
		||||
cd ..
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ cp inc/* /usr/include/
 | 
			
		||||
cd SDRPlusPlus
 | 
			
		||||
mkdir build
 | 
			
		||||
cd build
 | 
			
		||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=OFF
 | 
			
		||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
 | 
			
		||||
make VERBOSE=1 -j2
 | 
			
		||||
 | 
			
		||||
cd ..
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ echo 'Cflags: -I/usr/include/codec2' >> /usr/share/pkgconfig/codec2.pc
 | 
			
		||||
cd SDRPlusPlus
 | 
			
		||||
mkdir build
 | 
			
		||||
cd build
 | 
			
		||||
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_OVERRIDE_STD_FILESYSTEM=ON -DOPT_BUILD_M17_DECODER=OFF
 | 
			
		||||
cmake .. -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_BLADERF_SOURCE=OFF -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_OVERRIDE_STD_FILESYSTEM=ON -DOPT_BUILD_M17_DECODER=ON
 | 
			
		||||
make VERBOSE=1 -j2
 | 
			
		||||
 | 
			
		||||
# Generate package
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ cp inc/* /usr/include/
 | 
			
		||||
cd SDRPlusPlus
 | 
			
		||||
mkdir build
 | 
			
		||||
cd build
 | 
			
		||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=OFF
 | 
			
		||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
 | 
			
		||||
make VERBOSE=1 -j2
 | 
			
		||||
 | 
			
		||||
cd ..
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ cp inc/* /usr/include/
 | 
			
		||||
cd SDRPlusPlus
 | 
			
		||||
mkdir build
 | 
			
		||||
cd build
 | 
			
		||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=OFF
 | 
			
		||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
 | 
			
		||||
make VERBOSE=1 -j2
 | 
			
		||||
 | 
			
		||||
cd ..
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ cp inc/* /usr/include/
 | 
			
		||||
cd SDRPlusPlus
 | 
			
		||||
mkdir build
 | 
			
		||||
cd build
 | 
			
		||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=OFF
 | 
			
		||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
 | 
			
		||||
make VERBOSE=1 -j2
 | 
			
		||||
 | 
			
		||||
cd ..
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ cp inc/* /usr/include/
 | 
			
		||||
cd SDRPlusPlus
 | 
			
		||||
mkdir build
 | 
			
		||||
cd build
 | 
			
		||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=OFF
 | 
			
		||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
 | 
			
		||||
make VERBOSE=1 -j2
 | 
			
		||||
 | 
			
		||||
cd ..
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										69
									
								
								root/res/bandplans/qo-100.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								root/res/bandplans/qo-100.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "QO-100",
 | 
			
		||||
    "country_name": "Worldwide",
 | 
			
		||||
    "country_code": "--",
 | 
			
		||||
    "author_name": "Ryzerth",
 | 
			
		||||
    "author_url": "https://github.com/AlexandreRouma",
 | 
			
		||||
    "bands": [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Beacon",
 | 
			
		||||
            "type": "broadcast",
 | 
			
		||||
            "start": 10489500000,
 | 
			
		||||
            "end": 10489505000
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "CW",
 | 
			
		||||
            "type": "amateur",
 | 
			
		||||
            "start": 10489505000,
 | 
			
		||||
            "end": 10489540000
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "NB Digi",
 | 
			
		||||
            "type": "amateur",
 | 
			
		||||
            "start": 10489540000,
 | 
			
		||||
            "end": 10489580000
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Digi",
 | 
			
		||||
            "type": "amateur",
 | 
			
		||||
            "start": 10489580000,
 | 
			
		||||
            "end": 10489650000
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "SSB",
 | 
			
		||||
            "type": "amateur",
 | 
			
		||||
            "start": 10489650000,
 | 
			
		||||
            "end": 10489745000
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Beacon",
 | 
			
		||||
            "type": "broadcast",
 | 
			
		||||
            "start": 10489745000,
 | 
			
		||||
            "end": 10489755000
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "SSB",
 | 
			
		||||
            "type": "amateur",
 | 
			
		||||
            "start": 10489755000,
 | 
			
		||||
            "end": 10489850000
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Emergency",
 | 
			
		||||
            "type": "amateur",
 | 
			
		||||
            "start": 10489850000,
 | 
			
		||||
            "end": 10489870000
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Mixed/Contest",
 | 
			
		||||
            "type": "amateur",
 | 
			
		||||
            "start": 10489870000,
 | 
			
		||||
            "end": 10489990000
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Beacon",
 | 
			
		||||
            "type": "broadcast",
 | 
			
		||||
            "start": 10489990000,
 | 
			
		||||
            "end": 10490000000
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user