diff --git a/modules/radio/src/main.cpp b/modules/radio/src/main.cpp index 61e091c..7a365f8 100644 --- a/modules/radio/src/main.cpp +++ b/modules/radio/src/main.cpp @@ -95,7 +95,14 @@ MOD_EXPORT void _DRAW_MENU_(RadioContext_t* ctx) { ctx->sigPath.setDemodulator(SigPath::DEMOD_LSB, ctx->bandWidth); API->setVFOReference(ctx->name, mod::API_t::REF_UPPER); } - if (ImGui::RadioButton(CONCAT("RAW##_", ctx->name), ctx->demod == 7) && ctx->demod != 7) { ctx->demod = 7; }; + if (ImGui::RadioButton(CONCAT("RAW##_", ctx->name), ctx->demod == 7) && ctx->demod != 7) { + ctx->demod = 7; + ctx->bandWidth = 10000; + ctx->bandWidthMin = 3000; + ctx->bandWidthMax = 10000; + ctx->sigPath.setDemodulator(SigPath::DEMOD_RAW, ctx->bandWidth); + API->setVFOReference(ctx->name, mod::API_t::REF_CENTER); + }; ImGui::Columns(1, CONCAT("EndRadioModeColumns##_", ctx->name), false); ImGui::EndGroup(); diff --git a/modules/radio/src/path.cpp b/modules/radio/src/path.cpp index 2609e7c..5fd332c 100644 --- a/modules/radio/src/path.cpp +++ b/modules/radio/src/path.cpp @@ -28,10 +28,13 @@ void SigPath::init(std::string vfoName, uint64_t sampleRate, int blockSize, dsp: bandwidth = 200000; // TODO: Set default VFO options + // TODO: ajust deemphasis for different output sample rates + // TODO: Add a mono to stereo for different modes demod.init(input, 100000, 200000, 800); amDemod.init(input, 50); ssbDemod.init(input, 6000, 3000, 22); + cpx2stereo.init(input, 22); audioResamp.init(&demod.output, 200000, 48000, 800); deemp.init(&audioResamp.output, 800, 50e-6, 48000); @@ -77,6 +80,9 @@ void SigPath::setDemodulator(int demId, float bandWidth) { else if (_demod == DEMOD_DSB) { ssbDemod.stop(); } + else if (_demod == DEMOD_RAW) { + cpx2stereo.stop(); + } else { spdlog::error("UNIMPLEMENTED DEMODULATOR IN SigPath::setDemodulator (stop)"); } @@ -145,6 +151,14 @@ void SigPath::setDemodulator(int demId, float bandWidth) { deemp.bypass = true; ssbDemod.start(); } + else if (demId == DEMOD_RAW) { + API->setVFOSampleRate(vfoName, 10000, bandwidth); + cpx2stereo.setBlockSize(API->getVFOOutputBlockSize(vfoName)); + //audioResamp.setInput(&cpx2stereo.output); + audioBw = std::min(bandwidth, outputSampleRate / 2.0f); + audioResamp.setInputSampleRate(10000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); + cpx2stereo.start(); + } else { spdlog::error("UNIMPLEMENTED DEMODULATOR IN SigPath::setDemodulator (start): {0}", demId); } @@ -207,6 +221,9 @@ void SigPath::setBandwidth(float bandWidth) { ssbDemod.setBandwidth(bandwidth); ssbDemod.start(); } + else if (_demod == DEMOD_RAW) { + // Notbing to change + } else { spdlog::error("UNIMPLEMENTED DEMODULATOR IN SigPath::setBandwidth"); } diff --git a/modules/radio/src/path.h b/modules/radio/src/path.h index cac9824..63cee57 100644 --- a/modules/radio/src/path.h +++ b/modules/radio/src/path.h @@ -30,6 +30,7 @@ public: DEMOD_USB, DEMOD_LSB, DEMOD_DSB, + DEMOD_RAW, _DEMOD_COUNT }; @@ -52,9 +53,11 @@ private: dsp::FMDemodulator demod; dsp::AMDemodulator amDemod; dsp::SSBDemod ssbDemod; + dsp::ComplexToStereo cpx2stereo; // Audio output - dsp::FloatFIRResampler audioResamp; + dsp::MonoToStereo m2s; + dsp::FIRResampler audioResamp; std::string vfoName; diff --git a/root/config.json b/root/config.json index e072419..93f423d 100644 --- a/root/config.json +++ b/root/config.json @@ -3,25 +3,25 @@ "Radio": { "device": "Speakers (Realtek High Definiti", "sampleRate": 48000.0, - "volume": 0.32258063554763794 + "volume": 0.4354838728904724 } }, "bandPlan": "General", "bandPlanEnabled": true, "fftHeight": 300, - "frequency": 99000000, + "frequency": 91000000, "max": 0.0, "maximized": false, "menuWidth": 300, - "min": -52.20588302612305, + "min": -70.0, "showWaterfall": true, "source": "HackRF One #0 901868dc282c8f8b", "sourceSettings": { "HackRF One #0 901868dc282c8f8b": { "gains": { "AMP": 0.0, - "LNA": 24.503000259399414, - "VGA": 16.229999542236328 + "LNA": 0.0, + "VGA": 0.0 }, "sampleRate": 8000000 } diff --git a/root/sdrpp_0.2.5_alpha_preview.zip b/root/sdrpp_0.2.5_alpha_preview.zip new file mode 100644 index 0000000..99c3377 Binary files /dev/null and b/root/sdrpp_0.2.5_alpha_preview.zip differ diff --git a/root_dev/config.json b/root_dev/config.json index 9b753d4..142d286 100644 --- a/root_dev/config.json +++ b/root_dev/config.json @@ -3,13 +3,13 @@ "Radio": { "device": "Speakers (Realtek High Definiti", "sampleRate": 48000.0, - "volume": 0.2956989109516144 + "volume": 0.4032258093357086 } }, "bandPlan": "General", "bandPlanEnabled": true, "fftHeight": 300, - "frequency": 103184112, + "frequency": 100100000, "max": 0.0, "maximized": false, "menuWidth": 300, @@ -27,7 +27,7 @@ } }, "windowSize": { - "h": 720, + "h": 725, "w": 1280 } } \ No newline at end of file diff --git a/root_dev/module_list.json b/root_dev/module_list.json index f7d192f..63dd7fa 100644 --- a/root_dev/module_list.json +++ b/root_dev/module_list.json @@ -1,4 +1,4 @@ { - "Radio": "./modules/radio.dll", - "Recorder": "./modules/recorder.dll" + "Radio": "../build/modules/radio/Release/radio.dll", + "Recorder": "../build/modules/recorder/Release/recorder.dll" } \ No newline at end of file diff --git a/src/dsp/block.h b/src/dsp/block.h new file mode 100644 index 0000000..644d821 --- /dev/null +++ b/src/dsp/block.h @@ -0,0 +1,121 @@ +#pragma once +#include +#include + +namespace dsp { + template + class Block { + public: + Block(std::vector inBs, std::vector outBs, D* inst, void (*workerFunc)(D* _this)) { + derived = inst; + worker = workerFunc; + inputBlockSize = inBs; + outputBlockSize = outBs; + in.reserve(IC); + out.reserve(OC); + for (int i = 0; i < IC; i++) { + in.push_back(NULL); + } + for (int i = 0; i < OC; i++) { + out.push_back(new stream(outBs[i] * 2)); + } + } + + void start() { + if (running) { + return; + } + running = true; + startHandler(); + workerThread = std::thread(worker, derived); + } + + void stop() { + if (!running) { + return; + } + stopHandler(); + for (auto is : in) { + is->stopReader(); + } + for (auto os : out) { + os->stopWriter(); + } + workerThread.join(); + + for (auto is : in) { + is->clearReadStop(); + } + for (auto os : out) { + os->clearWriteStop(); + } + running = false; + } + + virtual void setBlockSize(int blockSize) { + if (running) { + return; + } + for (int i = 0; i < IC; i++) { + in[i]->setMaxLatency(blockSize * 2); + inputBlockSize[i] = blockSize; + } + for (int i = 0; i < OC; i++) { + out[i]->setMaxLatency(blockSize * 2); + outputBlockSize[i] = blockSize; + } + } + + std::vector*> out; + + protected: + virtual void startHandler() {} + virtual void stopHandler() {} + std::vector*> in; + std::vector inputBlockSize; + std::vector outputBlockSize; + bool running = false; + + private: + void (*worker)(D* _this); + std::thread workerThread; + D* derived; + + }; + + + class DemoMultiplier : public Block { + public: + DemoMultiplier() : Block({2}, {1}, this, worker) {} + + void init(stream* a, stream* b, int blockSize) { + in[0] = a; + in[1] = b; + inputBlockSize[0] = blockSize; + inputBlockSize[1] = blockSize; + out[0]->setMaxLatency(blockSize * 2); + outputBlockSize[0] = blockSize; + } + + private: + static void worker(DemoMultiplier* _this) { + int blockSize = _this->inputBlockSize[0]; + stream* inA = _this->in[0]; + stream* inB = _this->in[1]; + stream* out = _this->out[0]; + complex_t* aBuf = (complex_t*)volk_malloc(sizeof(complex_t) * blockSize, volk_get_alignment()); + complex_t* bBuf = (complex_t*)volk_malloc(sizeof(complex_t) * blockSize, volk_get_alignment()); + complex_t* outBuf = (complex_t*)volk_malloc(sizeof(complex_t) * blockSize, volk_get_alignment()); + while (true) { + if (inA->read(aBuf, blockSize) < 0) { break; }; + if (inB->read(bBuf, blockSize) < 0) { break; }; + volk_32fc_x2_multiply_32fc((lv_32fc_t*)outBuf, (lv_32fc_t*)aBuf, (lv_32fc_t*)bBuf, blockSize); + if (out->write(outBuf, blockSize) < 0) { break; }; + } + volk_free(aBuf); + volk_free(bBuf); + volk_free(outBuf); + } + + }; +}; \ No newline at end of file diff --git a/src/dsp/correction.h b/src/dsp/correction.h index b93bbb1..1db9ea1 100644 --- a/src/dsp/correction.h +++ b/src/dsp/correction.h @@ -86,4 +86,73 @@ namespace dsp { std::thread _workerThread; bool running = false; }; + + class ComplexToStereo { + public: + ComplexToStereo() { + + } + + ComplexToStereo(stream* input, int bufferSize) : output(bufferSize * 2) { + _in = input; + _bufferSize = bufferSize; + } + + void init(stream* input, int bufferSize) { + output.init(bufferSize * 2); + _in = input; + _bufferSize = bufferSize; + } + + void start() { + if (running) { + return; + } + _workerThread = std::thread(_worker, this); + running = true; + } + + void stop() { + if (!running) { + return; + } + _in->stopReader(); + output.stopWriter(); + _workerThread.join(); + _in->clearReadStop(); + output.clearWriteStop(); + running = false; + } + + void setBlockSize(int blockSize) { + if (running) { + return; + } + _bufferSize = blockSize; + output.setMaxLatency(blockSize * 2); + } + + stream output; + + private: + static void _worker(ComplexToStereo* _this) { + complex_t* inBuf = new complex_t[_this->_bufferSize]; + StereoFloat_t* outBuf = new StereoFloat_t[_this->_bufferSize]; + while (true) { + if (_this->_in->read(inBuf, _this->_bufferSize) < 0) { break; }; + for (int i = 0; i < _this->_bufferSize; i++) { + outBuf[i].l = inBuf[i].i; + outBuf[i].r = inBuf[i].q; + } + if (_this->output.write(outBuf, _this->_bufferSize) < 0) { break; }; + } + delete[] inBuf; + delete[] outBuf; + } + + stream* _in; + int _bufferSize; + std::thread _workerThread; + bool running = false; + }; }; \ No newline at end of file diff --git a/src/dsp/resampling.h b/src/dsp/resampling.h index f5ce64b..ad8f5b5 100644 --- a/src/dsp/resampling.h +++ b/src/dsp/resampling.h @@ -189,202 +189,389 @@ namespace dsp { bool running = false; }; + // class FIRResampler { + // public: + // FIRResampler() { + + // } + + // void init(stream* in, float inputSampleRate, float outputSampleRate, int blockSize, float passBand = -1.0f, float transWidth = -1.0f) { + // _input = in; + // _outputSampleRate = outputSampleRate; + // _inputSampleRate = inputSampleRate; + // int _gcd = std::gcd((int)inputSampleRate, (int)outputSampleRate); + // _interp = outputSampleRate / _gcd; + // _decim = inputSampleRate / _gcd; + // _blockSize = blockSize; + // outputBlockSize = (blockSize * _interp) / _decim; + // output.init(outputBlockSize * 2); + + // float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); + // if (passBand > 0.0f && transWidth > 0.0f) { + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, passBand, transWidth); + // } + // else { + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, cutoff, cutoff); + // } + // } + + // void start() { + // if (running) { + // return; + // } + // _workerThread = std::thread(_worker, this); + // running = true; + // } + + // void stop() { + // if (!running) { + // return; + // } + // _input->stopReader(); + // output.stopWriter(); + // _workerThread.join(); + // _input->clearReadStop(); + // output.clearWriteStop(); + // running = false; + // } + + // void setInputSampleRate(float inputSampleRate, int blockSize = -1, float passBand = -1.0f, float transWidth = -1.0f) { + // stop(); + // _inputSampleRate = inputSampleRate; + // int _gcd = std::gcd((int)inputSampleRate, (int)_outputSampleRate); + // _interp = _outputSampleRate / _gcd; + // _decim = inputSampleRate / _gcd; + + // float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); + // if (passBand > 0.0f && transWidth > 0.0f) { + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, passBand, transWidth); + // } + // else { + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, cutoff, cutoff); + // } + + // if (blockSize > 0) { + // _blockSize = blockSize; + // } + // outputBlockSize = (_blockSize * _interp) / _decim; + // output.setMaxLatency(outputBlockSize * 2); + // start(); + // } + + // void setOutputSampleRate(float outputSampleRate, float passBand = -1.0f, float transWidth = -1.0f) { + // stop(); + // _outputSampleRate = outputSampleRate; + // int _gcd = std::gcd((int)_inputSampleRate, (int)outputSampleRate); + // _interp = outputSampleRate / _gcd; + // _decim = _inputSampleRate / _gcd; + // outputBlockSize = (_blockSize * _interp) / _decim; + // output.setMaxLatency(outputBlockSize * 2); + + // float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); + // if (passBand > 0.0f && transWidth > 0.0f) { + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, passBand, transWidth); + // } + // else { + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, cutoff, cutoff); + // } + + // start(); + // } + + // void setFilterParams(float passBand, float transWidth) { + // stop(); + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, passBand, transWidth); + // start(); + // } + + // void setBlockSize(int blockSize) { + // stop(); + // _blockSize = blockSize; + // outputBlockSize = (_blockSize * _interp) / _decim; + // output.setMaxLatency(outputBlockSize * 2); + // start(); + // } + + // void setInput(stream* input) { + // if (running) { + // return; + // } + // _input = input; + // } + + // int getOutputBlockSize() { + // return outputBlockSize; + // } + + // stream output; + + // private: + // static void _worker(FIRResampler* _this) { + // complex_t* inBuf = new complex_t[_this->_blockSize]; + // complex_t* outBuf = new complex_t[_this->outputBlockSize]; + + // int inCount = _this->_blockSize; + // int outCount = _this->outputBlockSize; + + // int interp = _this->_interp; + // int decim = _this->_decim; + // float correction = interp;//(float)sqrt((float)interp); + + // int tapCount = _this->_taps.size(); + // float* taps = new float[tapCount]; + // for (int i = 0; i < tapCount; i++) { + // taps[i] = _this->_taps[i] * correction; + // } + + // complex_t* delayBuf = new complex_t[tapCount]; + + // complex_t* delayStart = &inBuf[std::max(inCount - tapCount, 0)]; + // int delaySize = tapCount * sizeof(complex_t); + // complex_t* delayBufEnd = &delayBuf[std::max(tapCount - inCount, 0)]; + // int moveSize = std::min(inCount, tapCount - inCount) * sizeof(complex_t); + // int inSize = inCount * sizeof(complex_t); + + // int afterInterp = inCount * interp; + // int outIndex = 0; + // while (true) { + // if (_this->_input->read(inBuf, inCount) < 0) { break; }; + // for (int i = 0; outIndex < outCount; i += decim) { + // outBuf[outIndex].i = 0; + // outBuf[outIndex].q = 0; + // for (int j = i % interp; j < tapCount; j += interp) { + // outBuf[outIndex].i += GET_FROM_RIGHT_BUF(inBuf, delayBuf, tapCount, (i - j) / interp).i * taps[j]; + // outBuf[outIndex].q += GET_FROM_RIGHT_BUF(inBuf, delayBuf, tapCount, (i - j) / interp).q * taps[j]; + // } + // outIndex++; + // } + // outIndex = 0; + // if (tapCount > inCount) { + // memmove(delayBuf, delayBufEnd, moveSize); + // memcpy(delayBufEnd, delayStart, inSize); + // } + // else { + // memcpy(delayBuf, delayStart, delaySize); + // } + + // if (_this->output.write(outBuf, _this->outputBlockSize) < 0) { break; }; + // } + // delete[] inBuf; + // delete[] outBuf; + // delete[] delayBuf; + // delete[] taps; + // } + + // std::thread _workerThread; + + // stream* _input; + // std::vector _taps; + // int _interp; + // int _decim; + // int outputBlockSize; + // float _outputSampleRate; + // float _inputSampleRate; + // int _blockSize; + // bool running = false; + // }; + + // class FloatFIRResampler { + // public: + // FloatFIRResampler() { + + // } + + // void init(stream* in, float inputSampleRate, float outputSampleRate, int blockSize, float passBand = -1.0f, float transWidth = -1.0f) { + // _input = in; + // _outputSampleRate = outputSampleRate; + // _inputSampleRate = inputSampleRate; + // int _gcd = std::gcd((int)inputSampleRate, (int)outputSampleRate); + // _interp = outputSampleRate / _gcd; + // _decim = inputSampleRate / _gcd; + // _blockSize = blockSize; + // outputBlockSize = (blockSize * _interp) / _decim; + // output.init(outputBlockSize * 2); + + // float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); + // if (passBand > 0.0f && transWidth > 0.0f) { + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, passBand, transWidth); + // } + // else { + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, cutoff, cutoff); + // } + // } + + // void start() { + // if (running) { + // return; + // } + // _workerThread = std::thread(_worker, this); + // running = true; + // } + + // void stop() { + // if (!running) { + // return; + // } + // _input->stopReader(); + // output.stopWriter(); + // _workerThread.join(); + // _input->clearReadStop(); + // output.clearWriteStop(); + // running = false; + // } + + // void setInputSampleRate(float inputSampleRate, int blockSize = -1, float passBand = -1.0f, float transWidth = -1.0f) { + // stop(); + // _inputSampleRate = inputSampleRate; + // int _gcd = std::gcd((int)inputSampleRate, (int)_outputSampleRate); + // _interp = _outputSampleRate / _gcd; + // _decim = inputSampleRate / _gcd; + + // float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); + // if (passBand > 0.0f && transWidth > 0.0f) { + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, passBand, transWidth); + // } + // else { + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, cutoff, cutoff); + // } + + // if (blockSize > 0) { + // _blockSize = blockSize; + // } + // outputBlockSize = (blockSize * _interp) / _decim; + // output.setMaxLatency(outputBlockSize * 2); + // start(); + // } + + // void setOutputSampleRate(float outputSampleRate, float passBand = -1.0f, float transWidth = -1.0f) { + // stop(); + // _outputSampleRate = outputSampleRate; + // int _gcd = std::gcd((int)_inputSampleRate, (int)outputSampleRate); + // _interp = outputSampleRate / _gcd; + // _decim = _inputSampleRate / _gcd; + // outputBlockSize = (_blockSize * _interp) / _decim; + // output.setMaxLatency(outputBlockSize * 2); + + // float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); + // if (passBand > 0.0f && transWidth > 0.0f) { + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, passBand, transWidth); + // } + // else { + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, cutoff, cutoff); + // } + + // start(); + // } + + // void setFilterParams(float passBand, float transWidth) { + // stop(); + // dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, passBand, transWidth); + // start(); + // } + + // void setBlockSize(int blockSize) { + // stop(); + // _blockSize = blockSize; + // outputBlockSize = (_blockSize * _interp) / _decim; + // output.setMaxLatency(outputBlockSize * 2); + // start(); + // } + + // void setInput(stream* input) { + // if (running) { + // return; + // } + // _input = input; + // } + + // int getOutputBlockSize() { + // return outputBlockSize; + // } + + // stream output; + + // private: + // static void _worker(FloatFIRResampler* _this) { + // float* inBuf = new float[_this->_blockSize]; + // float* outBuf = new float[_this->outputBlockSize]; + + // int inCount = _this->_blockSize; + // int outCount = _this->outputBlockSize; + + // int interp = _this->_interp; + // int decim = _this->_decim; + // float correction = interp;//(float)sqrt((float)interp); + + // int tapCount = _this->_taps.size(); + // float* taps = new float[tapCount]; + // for (int i = 0; i < tapCount; i++) { + // taps[i] = _this->_taps[i] * correction; + // } + + // float* delayBuf = new float[tapCount]; + + // float* delayStart = &inBuf[std::max(inCount - tapCount, 0)]; + // int delaySize = tapCount * sizeof(float); + // float* delayBufEnd = &delayBuf[std::max(tapCount - inCount, 0)]; + // int moveSize = std::min(inCount, tapCount - inCount) * sizeof(float); + // int inSize = inCount * sizeof(float); + + // int afterInterp = inCount * interp; + // int outIndex = 0; + // while (true) { + // if (_this->_input->read(inBuf, inCount) < 0) { break; }; + + + // for (int i = 0; outIndex < outCount; i += decim) { + // outBuf[outIndex] = 0; + // for (int j = (i % interp); j < tapCount; j += interp) { + // outBuf[outIndex] += GET_FROM_RIGHT_BUF(inBuf, delayBuf, tapCount, (i - j) / interp) * taps[j]; + // } + // outIndex++; + // } + + + + // outIndex = 0; + // if (tapCount > inCount) { + // memmove(delayBuf, delayBufEnd, moveSize); + // memcpy(delayBufEnd, delayStart, inSize); + // } + // else { + // memcpy(delayBuf, delayStart, delaySize); + // } + + // if (_this->output.write(outBuf, _this->outputBlockSize) < 0) { break; }; + // } + // delete[] inBuf; + // delete[] outBuf; + // delete[] delayBuf; + // } + + // std::thread _workerThread; + + // stream* _input; + // std::vector _taps; + // int _interp; + // int _decim; + // int outputBlockSize; + // float _outputSampleRate; + // float _inputSampleRate; + // int _blockSize; + // bool running = false; + // }; + + + + + template class FIRResampler { public: FIRResampler() { } - void init(stream* in, float inputSampleRate, float outputSampleRate, int blockSize, float passBand = -1.0f, float transWidth = -1.0f) { - _input = in; - _outputSampleRate = outputSampleRate; - _inputSampleRate = inputSampleRate; - int _gcd = std::gcd((int)inputSampleRate, (int)outputSampleRate); - _interp = outputSampleRate / _gcd; - _decim = inputSampleRate / _gcd; - _blockSize = blockSize; - outputBlockSize = (blockSize * _interp) / _decim; - output.init(outputBlockSize * 2); - - float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); - if (passBand > 0.0f && transWidth > 0.0f) { - dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, passBand, transWidth); - } - else { - dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, cutoff, cutoff); - } - } - - void start() { - if (running) { - return; - } - _workerThread = std::thread(_worker, this); - running = true; - } - - void stop() { - if (!running) { - return; - } - _input->stopReader(); - output.stopWriter(); - _workerThread.join(); - _input->clearReadStop(); - output.clearWriteStop(); - running = false; - } - - void setInputSampleRate(float inputSampleRate, int blockSize = -1, float passBand = -1.0f, float transWidth = -1.0f) { - stop(); - _inputSampleRate = inputSampleRate; - int _gcd = std::gcd((int)inputSampleRate, (int)_outputSampleRate); - _interp = _outputSampleRate / _gcd; - _decim = inputSampleRate / _gcd; - - float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); - if (passBand > 0.0f && transWidth > 0.0f) { - dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, passBand, transWidth); - } - else { - dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, cutoff, cutoff); - } - - if (blockSize > 0) { - _blockSize = blockSize; - } - outputBlockSize = (_blockSize * _interp) / _decim; - output.setMaxLatency(outputBlockSize * 2); - start(); - } - - void setOutputSampleRate(float outputSampleRate, float passBand = -1.0f, float transWidth = -1.0f) { - stop(); - _outputSampleRate = outputSampleRate; - int _gcd = std::gcd((int)_inputSampleRate, (int)outputSampleRate); - _interp = outputSampleRate / _gcd; - _decim = _inputSampleRate / _gcd; - outputBlockSize = (_blockSize * _interp) / _decim; - output.setMaxLatency(outputBlockSize * 2); - - float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); - if (passBand > 0.0f && transWidth > 0.0f) { - dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, passBand, transWidth); - } - else { - dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, cutoff, cutoff); - } - - start(); - } - - void setFilterParams(float passBand, float transWidth) { - stop(); - dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, passBand, transWidth); - start(); - } - - void setBlockSize(int blockSize) { - stop(); - _blockSize = blockSize; - outputBlockSize = (_blockSize * _interp) / _decim; - output.setMaxLatency(outputBlockSize * 2); - start(); - } - - void setInput(stream* input) { - if (running) { - return; - } - _input = input; - } - - int getOutputBlockSize() { - return outputBlockSize; - } - - stream output; - - private: - static void _worker(FIRResampler* _this) { - complex_t* inBuf = new complex_t[_this->_blockSize]; - complex_t* outBuf = new complex_t[_this->outputBlockSize]; - - int inCount = _this->_blockSize; - int outCount = _this->outputBlockSize; - - int interp = _this->_interp; - int decim = _this->_decim; - float correction = interp;//(float)sqrt((float)interp); - - int tapCount = _this->_taps.size(); - float* taps = new float[tapCount]; - for (int i = 0; i < tapCount; i++) { - taps[i] = _this->_taps[i] * correction; - } - - complex_t* delayBuf = new complex_t[tapCount]; - - complex_t* delayStart = &inBuf[std::max(inCount - tapCount, 0)]; - int delaySize = tapCount * sizeof(complex_t); - complex_t* delayBufEnd = &delayBuf[std::max(tapCount - inCount, 0)]; - int moveSize = std::min(inCount, tapCount - inCount) * sizeof(complex_t); - int inSize = inCount * sizeof(complex_t); - - int afterInterp = inCount * interp; - int outIndex = 0; - while (true) { - if (_this->_input->read(inBuf, inCount) < 0) { break; }; - for (int i = 0; outIndex < outCount; i += decim) { - outBuf[outIndex].i = 0; - outBuf[outIndex].q = 0; - for (int j = i % interp; j < tapCount; j += interp) { - outBuf[outIndex].i += GET_FROM_RIGHT_BUF(inBuf, delayBuf, tapCount, (i - j) / interp).i * taps[j]; - outBuf[outIndex].q += GET_FROM_RIGHT_BUF(inBuf, delayBuf, tapCount, (i - j) / interp).q * taps[j]; - } - outIndex++; - } - outIndex = 0; - if (tapCount > inCount) { - memmove(delayBuf, delayBufEnd, moveSize); - memcpy(delayBufEnd, delayStart, inSize); - } - else { - memcpy(delayBuf, delayStart, delaySize); - } - - if (_this->output.write(outBuf, _this->outputBlockSize) < 0) { break; }; - } - delete[] inBuf; - delete[] outBuf; - delete[] delayBuf; - delete[] taps; - } - - std::thread _workerThread; - - stream* _input; - std::vector _taps; - int _interp; - int _decim; - int outputBlockSize; - float _outputSampleRate; - float _inputSampleRate; - int _blockSize; - bool running = false; - }; - - - - - - class FloatFIRResampler { - public: - FloatFIRResampler() { - - } - - void init(stream* in, float inputSampleRate, float outputSampleRate, int blockSize, float passBand = -1.0f, float transWidth = -1.0f) { + void init(stream* in, float inputSampleRate, float outputSampleRate, int blockSize, float passBand = -1.0f, float transWidth = -1.0f) { _input = in; _outputSampleRate = outputSampleRate; _inputSampleRate = inputSampleRate; @@ -492,19 +679,21 @@ namespace dsp { return outputBlockSize; } - stream output; + stream output; private: - static void _worker(FloatFIRResampler* _this) { - float* inBuf = new float[_this->_blockSize]; - float* outBuf = new float[_this->outputBlockSize]; + + // Float worker + static void _worker(FIRResampler* _this) { + T* inBuf = new T[_this->_blockSize]; + T* outBuf = new T[_this->outputBlockSize]; int inCount = _this->_blockSize; int outCount = _this->outputBlockSize; int interp = _this->_interp; int decim = _this->_decim; - float correction = interp;//(float)sqrt((float)interp); + float correction = interp; int tapCount = _this->_taps.size(); float* taps = new float[tapCount]; @@ -512,29 +701,39 @@ namespace dsp { taps[i] = _this->_taps[i] * correction; } - float* delayBuf = new float[tapCount]; + T* delayBuf = new T[tapCount]; - float* delayStart = &inBuf[std::max(inCount - tapCount, 0)]; - int delaySize = tapCount * sizeof(float); - float* delayBufEnd = &delayBuf[std::max(tapCount - inCount, 0)]; - int moveSize = std::min(inCount, tapCount - inCount) * sizeof(float); - int inSize = inCount * sizeof(float); + T* delayStart = &inBuf[std::max(inCount - tapCount, 0)]; + int delaySize = tapCount * sizeof(T); + T* delayBufEnd = &delayBuf[std::max(tapCount - inCount, 0)]; + int moveSize = std::min(inCount, tapCount - inCount) * sizeof(T); + int inSize = inCount * sizeof(T); int afterInterp = inCount * interp; int outIndex = 0; while (true) { if (_this->_input->read(inBuf, inCount) < 0) { break; }; - - for (int i = 0; outIndex < outCount; i += decim) { - outBuf[outIndex] = 0; - for (int j = (i % interp); j < tapCount; j += interp) { - outBuf[outIndex] += GET_FROM_RIGHT_BUF(inBuf, delayBuf, tapCount, (i - j) / interp) * taps[j]; + if constexpr (std::is_same_v) { + for (int i = 0; outIndex < outCount; i += decim) { + outBuf[outIndex] = 0; + for (int j = (i % interp); j < tapCount; j += interp) { + outBuf[outIndex] += GET_FROM_RIGHT_BUF(inBuf, delayBuf, tapCount, (i - j) / interp) * taps[j]; + } + outIndex++; + } + } + if constexpr (std::is_same_v) { + for (int i = 0; outIndex < outCount; i += decim) { + outBuf[outIndex].i = 0; + outBuf[outIndex].q = 0; + for (int j = i % interp; j < tapCount; j += interp) { + outBuf[outIndex].i += GET_FROM_RIGHT_BUF(inBuf, delayBuf, tapCount, (i - j) / interp).i * taps[j]; + outBuf[outIndex].q += GET_FROM_RIGHT_BUF(inBuf, delayBuf, tapCount, (i - j) / interp).q * taps[j]; + } + outIndex++; } - outIndex++; } - - outIndex = 0; if (tapCount > inCount) { @@ -553,8 +752,7 @@ namespace dsp { } std::thread _workerThread; - - stream* _input; + stream* _input; std::vector _taps; int _interp; int _decim; @@ -565,211 +763,196 @@ namespace dsp { bool running = false; }; + // class FloatPolyphaseFIRResampler { + // public: + // FloatPolyphaseFIRResampler() { + // } + // void init(stream* in, float inputSampleRate, float outputSampleRate, int blockSize, float passBand = -1.0f, float transWidth = -1.0f) { + // _input = in; + // _outputSampleRate = outputSampleRate; + // _inputSampleRate = inputSampleRate; + // int _gcd = std::gcd((int)inputSampleRate, (int)outputSampleRate); + // _interp = outputSampleRate / _gcd; + // _decim = inputSampleRate / _gcd; + // _blockSize = blockSize; + // outputBlockSize = (blockSize * _interp) / _decim; + // output.init(outputBlockSize * 2); + // float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); + // if (passBand > 0.0f && transWidth > 0.0f) { + // dsp::BlackmanWindow(_taps, _outputSampleRate, passBand, transWidth, _interp - 1); + // } + // else { + // dsp::BlackmanWindow(_taps, _outputSampleRate, cutoff, cutoff, _interp - 1); + // } + // } + // void start() { + // if (running) { + // return; + // } + // _workerThread = std::thread(_worker, this); + // running = true; + // } + // void stop() { + // if (!running) { + // return; + // } + // _input->stopReader(); + // output.stopWriter(); + // _workerThread.join(); + // _input->clearReadStop(); + // output.clearWriteStop(); + // running = false; + // } + // void setInputSampleRate(float inputSampleRate, int blockSize = -1, float passBand = -1.0f, float transWidth = -1.0f) { + // stop(); + // _inputSampleRate = inputSampleRate; + // int _gcd = std::gcd((int)inputSampleRate, (int)_outputSampleRate); + // _interp = _outputSampleRate / _gcd; + // _decim = inputSampleRate / _gcd; + // float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); + // if (passBand > 0.0f && transWidth > 0.0f) { + // dsp::BlackmanWindow(_taps, _outputSampleRate, passBand, transWidth, _interp - 1); + // } + // else { + // dsp::BlackmanWindow(_taps,_outputSampleRate, cutoff, cutoff, _interp - 1); + // } + // if (blockSize > 0) { + // _blockSize = blockSize; + // } + // outputBlockSize = (blockSize * _interp) / _decim; + // output.setMaxLatency(outputBlockSize * 2); + // start(); + // } + // void setOutputSampleRate(float outputSampleRate, float passBand = -1.0f, float transWidth = -1.0f) { + // stop(); + // _outputSampleRate = outputSampleRate; + // int _gcd = std::gcd((int)_inputSampleRate, (int)outputSampleRate); + // _interp = outputSampleRate / _gcd; + // _decim = _inputSampleRate / _gcd; + // outputBlockSize = (_blockSize * _interp) / _decim; + // output.setMaxLatency(outputBlockSize * 2); - - - - - - class FloatPolyphaseFIRResampler { - public: - FloatPolyphaseFIRResampler() { - - } - - void init(stream* in, float inputSampleRate, float outputSampleRate, int blockSize, float passBand = -1.0f, float transWidth = -1.0f) { - _input = in; - _outputSampleRate = outputSampleRate; - _inputSampleRate = inputSampleRate; - int _gcd = std::gcd((int)inputSampleRate, (int)outputSampleRate); - _interp = outputSampleRate / _gcd; - _decim = inputSampleRate / _gcd; - _blockSize = blockSize; - outputBlockSize = (blockSize * _interp) / _decim; - output.init(outputBlockSize * 2); - - float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); - if (passBand > 0.0f && transWidth > 0.0f) { - dsp::BlackmanWindow(_taps, _outputSampleRate, passBand, transWidth, _interp - 1); - } - else { - dsp::BlackmanWindow(_taps, _outputSampleRate, cutoff, cutoff, _interp - 1); - } - } - - void start() { - if (running) { - return; - } - _workerThread = std::thread(_worker, this); - running = true; - } - - void stop() { - if (!running) { - return; - } - _input->stopReader(); - output.stopWriter(); - _workerThread.join(); - _input->clearReadStop(); - output.clearWriteStop(); - running = false; - } - - void setInputSampleRate(float inputSampleRate, int blockSize = -1, float passBand = -1.0f, float transWidth = -1.0f) { - stop(); - _inputSampleRate = inputSampleRate; - int _gcd = std::gcd((int)inputSampleRate, (int)_outputSampleRate); - _interp = _outputSampleRate / _gcd; - _decim = inputSampleRate / _gcd; - - float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); - if (passBand > 0.0f && transWidth > 0.0f) { - dsp::BlackmanWindow(_taps, _outputSampleRate, passBand, transWidth, _interp - 1); - } - else { - dsp::BlackmanWindow(_taps,_outputSampleRate, cutoff, cutoff, _interp - 1); - } - - if (blockSize > 0) { - _blockSize = blockSize; - } - outputBlockSize = (blockSize * _interp) / _decim; - output.setMaxLatency(outputBlockSize * 2); - start(); - } - - void setOutputSampleRate(float outputSampleRate, float passBand = -1.0f, float transWidth = -1.0f) { - stop(); - _outputSampleRate = outputSampleRate; - int _gcd = std::gcd((int)_inputSampleRate, (int)outputSampleRate); - _interp = outputSampleRate / _gcd; - _decim = _inputSampleRate / _gcd; - outputBlockSize = (_blockSize * _interp) / _decim; - output.setMaxLatency(outputBlockSize * 2); - - float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); - if (passBand > 0.0f && transWidth > 0.0f) { - dsp::BlackmanWindow(_taps, _outputSampleRate, passBand, transWidth, _interp - 1); - } - else { - dsp::BlackmanWindow(_taps, _outputSampleRate, cutoff, cutoff, _interp - 1); - } + // float cutoff = std::min(_outputSampleRate / 2.0f, _inputSampleRate / 2.0f); + // if (passBand > 0.0f && transWidth > 0.0f) { + // dsp::BlackmanWindow(_taps, _outputSampleRate, passBand, transWidth, _interp - 1); + // } + // else { + // dsp::BlackmanWindow(_taps, _outputSampleRate, cutoff, cutoff, _interp - 1); + // } - start(); - } + // start(); + // } - void setFilterParams(float passBand, float transWidth) { - stop(); - dsp::BlackmanWindow(_taps, _outputSampleRate, passBand, transWidth, _interp - 1); - start(); - } + // void setFilterParams(float passBand, float transWidth) { + // stop(); + // dsp::BlackmanWindow(_taps, _outputSampleRate, passBand, transWidth, _interp - 1); + // start(); + // } - void setBlockSize(int blockSize) { - stop(); - _blockSize = blockSize; - outputBlockSize = (_blockSize * _interp) / _decim; - output.setMaxLatency(outputBlockSize * 2); - start(); - } + // void setBlockSize(int blockSize) { + // stop(); + // _blockSize = blockSize; + // outputBlockSize = (_blockSize * _interp) / _decim; + // output.setMaxLatency(outputBlockSize * 2); + // start(); + // } - void setInput(stream* input) { - if (running) { - return; - } - _input = input; - } + // void setInput(stream* input) { + // if (running) { + // return; + // } + // _input = input; + // } - int getOutputBlockSize() { - return outputBlockSize; - } + // int getOutputBlockSize() { + // return outputBlockSize; + // } - stream output; + // stream output; - private: - static void _worker(FloatPolyphaseFIRResampler* _this) { - float* inBuf = new float[_this->_blockSize]; - float* outBuf = new float[_this->outputBlockSize]; + // private: + // static void _worker(FloatPolyphaseFIRResampler* _this) { + // float* inBuf = new float[_this->_blockSize]; + // float* outBuf = new float[_this->outputBlockSize]; - int inCount = _this->_blockSize; - int outCount = _this->outputBlockSize; + // int inCount = _this->_blockSize; + // int outCount = _this->outputBlockSize; - int interp = _this->_interp; - int decim = _this->_decim; - float correction = interp;//(float)sqrt((float)interp); + // int interp = _this->_interp; + // int decim = _this->_decim; + // float correction = interp;//(float)sqrt((float)interp); - int tapCount = _this->_taps.size(); - float* taps = new float[tapCount]; - for (int i = 0; i < tapCount; i++) { - taps[i] = _this->_taps[i] * correction; - } + // int tapCount = _this->_taps.size(); + // float* taps = new float[tapCount]; + // for (int i = 0; i < tapCount; i++) { + // taps[i] = _this->_taps[i] * correction; + // } - float* delayBuf = new float[tapCount]; + // float* delayBuf = new float[tapCount]; - float* delayStart = &inBuf[std::max(inCount - tapCount, 0)]; - int delaySize = tapCount * sizeof(float); - float* delayBufEnd = &delayBuf[std::max(tapCount - inCount, 0)]; - int moveSize = std::min(inCount, tapCount - inCount) * sizeof(float); - int inSize = inCount * sizeof(float); + // float* delayStart = &inBuf[std::max(inCount - tapCount, 0)]; + // int delaySize = tapCount * sizeof(float); + // float* delayBufEnd = &delayBuf[std::max(tapCount - inCount, 0)]; + // int moveSize = std::min(inCount, tapCount - inCount) * sizeof(float); + // int inSize = inCount * sizeof(float); - int afterInterp = inCount * interp; - int outIndex = 0; + // int afterInterp = inCount * interp; + // int outIndex = 0; - tapCount -= interp - 1; + // tapCount -= interp - 1; - while (true) { - if (_this->_input->read(inBuf, inCount) < 0) { break; }; + // while (true) { + // if (_this->_input->read(inBuf, inCount) < 0) { break; }; - for (int i = 0; i < outCount; i++) { - outBuf[i] = 0; - int filterId = (i * decim) % interp; - int inputId = (i * decim) / interp; - for (int j = 0; j < tapCount; j++) { - outBuf[i] += GET_FROM_RIGHT_BUF(inBuf, delayBuf, tapCount, inputId - j) * taps[j + filterId]; - } - } + // for (int i = 0; i < outCount; i++) { + // outBuf[i] = 0; + // int filterId = (i * decim) % interp; + // int inputId = (i * decim) / interp; + // for (int j = 0; j < tapCount; j++) { + // outBuf[i] += GET_FROM_RIGHT_BUF(inBuf, delayBuf, tapCount, inputId - j) * taps[j + filterId]; + // } + // } - if (tapCount > inCount) { - memmove(delayBuf, delayBufEnd, moveSize); - memcpy(delayBufEnd, delayStart, inSize); - } - else { - memcpy(delayBuf, delayStart, delaySize); - } + // if (tapCount > inCount) { + // memmove(delayBuf, delayBufEnd, moveSize); + // memcpy(delayBufEnd, delayStart, inSize); + // } + // else { + // memcpy(delayBuf, delayStart, delaySize); + // } - if (_this->output.write(outBuf, _this->outputBlockSize) < 0) { break; }; - } - delete[] inBuf; - delete[] outBuf; - delete[] delayBuf; - } + // if (_this->output.write(outBuf, _this->outputBlockSize) < 0) { break; }; + // } + // delete[] inBuf; + // delete[] outBuf; + // delete[] delayBuf; + // } - std::thread _workerThread; + // std::thread _workerThread; - stream* _input; - std::vector _taps; - int _interp; - int _decim; - int outputBlockSize; - float _outputSampleRate; - float _inputSampleRate; - int _blockSize; - bool running = false; - }; + // stream* _input; + // std::vector _taps; + // int _interp; + // int _decim; + // int outputBlockSize; + // float _outputSampleRate; + // float _inputSampleRate; + // int _blockSize; + // bool running = false; + // }; }; \ No newline at end of file diff --git a/src/dsp/types.h b/src/dsp/types.h index 09b4430..5de461b 100644 --- a/src/dsp/types.h +++ b/src/dsp/types.h @@ -4,10 +4,52 @@ namespace dsp { struct complex_t { float q; float i; + + complex_t operator+(complex_t& c) { + complex_t res; + res.i = c.i + i; + res.q = c.q + q; + return res; + } + + complex_t operator-(complex_t& c) { + complex_t res; + res.i = i - c.i; + res.q = q - c.q; + return res; + } + + complex_t operator*(float& f) { + complex_t res; + res.i = i * f; + res.q = q * f; + return res; + } }; struct StereoFloat_t { float l; float r; + + StereoFloat_t operator+(StereoFloat_t& s) { + StereoFloat_t res; + res.l = s.l + l; + res.r = s.r + r; + return res; + } + + StereoFloat_t operator-(StereoFloat_t& s) { + StereoFloat_t res; + res.l = l - s.l; + res.r = r - s.r; + return res; + } + + StereoFloat_t operator*(float& f) { + StereoFloat_t res; + res.l = l * f; + res.r = r * f; + return res; + } }; }; \ No newline at end of file diff --git a/src/dsp/vfo.h b/src/dsp/vfo.h index bbcf7e0..312c612 100644 --- a/src/dsp/vfo.h +++ b/src/dsp/vfo.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace dsp { class VFO { @@ -22,7 +23,8 @@ namespace dsp { lo.init(offset, inputSampleRate, blockSize); mixer.init(in, &lo.output, blockSize); - resamp.init(&mixer.output, inputSampleRate, outputSampleRate, blockSize, _bandWidth * 0.8f, _bandWidth); + //resamp.init(&mixer.output, inputSampleRate, outputSampleRate, blockSize, _bandWidth * 0.8f, _bandWidth); + resamp.init(mixer.out[0], inputSampleRate, outputSampleRate, blockSize, _bandWidth * 0.8f, _bandWidth); } void start() { @@ -87,8 +89,10 @@ namespace dsp { private: SineSource lo; - Multiplier mixer; - FIRResampler resamp; + //Multiplier mixer; + DemoMultiplier mixer; + FIRResampler resamp; + DecimatingFIRFilter filter; stream* _input; float _outputSampleRate; diff --git a/src/io/soapy.h b/src/io/soapy.h index f72f5c9..ac1311f 100644 --- a/src/io/soapy.h +++ b/src/io/soapy.h @@ -12,7 +12,7 @@ namespace io { SoapyWrapper() { SoapySDR::registerLogHandler(_logHandler); SoapySDR::Device::make(""); - + output.init(64000); currentGains = new float[1]; refresh(); diff --git a/src/main.cpp b/src/main.cpp index 9cd9672..765f428 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,6 +14,8 @@ #include #include +#include + #define STB_IMAGE_RESIZE_IMPLEMENTATION #include @@ -22,7 +24,7 @@ #endif // Comment to build a normal release -// #define DEV_BUILD +#define DEV_BUILD bool maximized = false; bool fullScreen = false; @@ -40,6 +42,7 @@ static void maximized_callback(GLFWwindow* window, int n) { } } +// main int main() { #ifdef _WIN32 //FreeConsole(); @@ -48,7 +51,7 @@ int main() { spdlog::info("SDR++ v" VERSION_STR); #ifdef DEV_BUILD - config::setRootDirectory("../root"); + config::setRootDirectory("../root_dev"); #elif _WIN32 config::setRootDirectory("."); #else @@ -134,6 +137,27 @@ int main() { style::setDarkStyle(); + + // ==================================================== + // glfwPollEvents(); + // ImGui_ImplOpenGL3_NewFrame(); + // ImGui_ImplGlfw_NewFrame(); + // ImGui::NewFrame(); + + // ImGui::ShowDemoWindow(); + + // ImGui::Render(); + // int display_w, display_h; + // glfwGetFramebufferSize(window, &display_w, &display_h); + // glViewport(0, 0, display_w, display_h); + // glClearColor(0.0666f, 0.0666f, 0.0666f, 1.0f); + // //glClearColor(0.9f, 0.9f, 0.9f, 1.0f); + // glClear(GL_COLOR_BUFFER_BIT); + // ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + + // glfwSwapBuffers(window); + // ==================================================== + spdlog::info("Loading icons"); icons::load(); diff --git a/src/main_window.cpp b/src/main_window.cpp index a243995..8c9f450 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -216,8 +216,8 @@ void windowInit() { // Bandwidth ajustment // CW and RAW modes; // Bring VFO to a visible place when changing sample rate if it's smaller - - // Have a proper root directory + // Add save config for modules + // Do VFO in two steps: First sample rate conversion, then filtering // And a module add/remove/change order menu // get rid of watchers and use if() instead diff --git a/src/waterfall.h b/src/waterfall.h index ef7e005..e7d21aa 100644 --- a/src/waterfall.h +++ b/src/waterfall.h @@ -33,6 +33,7 @@ namespace ImGui { float lowerOffset; float upperOffset; float bandwidth; + float snapInterval; int reference = REF_CENTER; ImVec2 rectMin;