From b78c2cf4150ebec16368704e51196e176386a91c Mon Sep 17 00:00:00 2001 From: Ryzerth Date: Mon, 22 Jun 2020 16:45:57 +0200 Subject: [PATCH] rewrote DSP --- CMakeLists.txt | 10 +- lib/SoapySDR.lib | Bin 0 -> 162504 bytes src/cdsp/fast_math.h | 84 ---- src/cdsp/fft_math.h | 127 ------ src/cdsp/file.h | 104 ----- src/cdsp/generator.h | 156 ------- src/cdsp/hackrf.h | 194 -------- src/cdsp/math.h | 70 --- src/cdsp/modulation.h | 57 --- src/cdsp/resampling.h | 317 ------------- src/dsp/correction.h | 63 +++ .../demodulation.h => dsp/demodulator.h} | 78 ++-- src/{cdsp => dsp}/filter.h | 259 +++-------- src/dsp/math.h | 85 ++++ src/dsp/resampling.h | 425 ++++++++++++++++++ src/dsp/routing.h | 49 ++ src/dsp/sink.h | 118 +++++ src/dsp/source.h | 82 ++++ src/{cdsp => dsp}/stream.h | 23 +- src/{cdsp => dsp}/types.h | 2 +- src/dsp/vfo.h | 158 +++++++ src/{cdsp => io}/audio.h | 12 +- src/io/soapy.h | 106 +++++ src/main.cpp | 1 + src/main_window.cpp | 87 ++-- src/signal_path.cpp | 28 +- src/signal_path.h | 43 +- src/vfo.cpp | 104 ----- src/vfo.h | 43 -- 29 files changed, 1331 insertions(+), 1554 deletions(-) create mode 100644 lib/SoapySDR.lib delete mode 100644 src/cdsp/fast_math.h delete mode 100644 src/cdsp/fft_math.h delete mode 100644 src/cdsp/file.h delete mode 100644 src/cdsp/generator.h delete mode 100644 src/cdsp/hackrf.h delete mode 100644 src/cdsp/math.h delete mode 100644 src/cdsp/modulation.h delete mode 100644 src/cdsp/resampling.h create mode 100644 src/dsp/correction.h rename src/{cdsp/demodulation.h => dsp/demodulator.h} (66%) rename src/{cdsp => dsp}/filter.h (57%) create mode 100644 src/dsp/math.h create mode 100644 src/dsp/resampling.h create mode 100644 src/dsp/routing.h create mode 100644 src/dsp/sink.h create mode 100644 src/dsp/source.h rename src/{cdsp => dsp}/stream.h (92%) rename src/{cdsp => dsp}/types.h (80%) create mode 100644 src/dsp/vfo.h rename src/{cdsp => io}/audio.h (90%) create mode 100644 src/io/soapy.h delete mode 100644 src/vfo.cpp delete mode 100644 src/vfo.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 45bca06d..43ad028d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,13 +2,21 @@ cmake_minimum_required(VERSION 3.9) project(sdrpp) # Compiler config -set(CMAKE_CXX_FLAGS "-OFast /std:c++17") +set(CMAKE_CXX_FLAGS "-O2 /std:c++17") # HackRF include_directories(sdrpp "C:/Program Files/PothosSDR/include/libhackrf/") link_directories(sdrpp "C:/Program Files/PothosSDR/lib/") link_libraries(hackrf) +# Volk +include_directories(sdrpp "C:/Program Files/PothosSDR/include/volk/") +link_libraries(volk) + +# SoapySDR +include_directories(sdrpp "C:/Program Files/PothosSDR/include/") +link_libraries(SoapySDR) + # Main code include_directories(sdrpp "src/") include_directories(sdrpp "src/imgui") diff --git a/lib/SoapySDR.lib b/lib/SoapySDR.lib new file mode 100644 index 0000000000000000000000000000000000000000..3c34688f6e90f09d5fa8a2a965522623d63cff5d GIT binary patch literal 162504 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 -#else -#include -#endif - -#include - - -inline void cm_mul(__m128& ab, const __m128& xy) -{ - //const __m128 aa = _mm_shuffle_ps(ab, ab, _MM_SHUFFLE(2, 2, 0, 0)); - const __m128 aa = _mm_moveldup_ps(ab); - const __m128 bb = _mm_movehdup_ps(ab); - //const __m128 bb = _mm_shuffle_ps(ab, ab, _MM_SHUFFLE(3, 3, 1, 1)); - const __m128 yx = _mm_shuffle_ps(xy, xy, _MM_SHUFFLE(2, 3, 0, 1)); - - const __m128 tmp = _mm_addsub_ps(_mm_mul_ps(aa, xy), _mm_mul_ps(bb, yx)); - ab = tmp; -} - -inline void do_mul(cdsp::complex_t* a, const cdsp::complex_t* b, int n) -{ - const int vector_size = 16; - int simd_iterations = n - (n % vector_size); - //assert(simd_iterations % vector_size == 0); - - for (int i = 0; i < simd_iterations; i += vector_size) - { - //__builtin_prefetch(a + i*4 + 64, 0); - //__builtin_prefetch(b + i*4 + 64, 0); - - __m128 vec_a = _mm_load_ps((float*)&a[i]); - __m128 vec_b = _mm_load_ps((float*)&b[i]); - - __m128 vec_a2 = _mm_load_ps((float*)&a[i+2]); - __m128 vec_b2 = _mm_load_ps((float*)&b[i+2]); - - __m128 vec_a3 = _mm_load_ps((float*)&a[i+4]); - __m128 vec_b3 = _mm_load_ps((float*)&b[i+4]); - - __m128 vec_a4 = _mm_load_ps((float*)&a[i+6]); - __m128 vec_b4 = _mm_load_ps((float*)&b[i+6]); - - __m128 vec_a5 = _mm_load_ps((float*)&a[i+8]); - __m128 vec_b5 = _mm_load_ps((float*)&b[i+8]); - - __m128 vec_a6 = _mm_load_ps((float*)&a[i+10]); - __m128 vec_b6 = _mm_load_ps((float*)&b[i+10]); - - __m128 vec_a7 = _mm_load_ps((float*)&a[i+12]); - __m128 vec_b7 = _mm_load_ps((float*)&b[i+12]); - - __m128 vec_a8 = _mm_load_ps((float*)&a[i+14]); - __m128 vec_b8 = _mm_load_ps((float*)&b[i+14]); - - cm_mul(vec_a, vec_b); - _mm_store_ps((float*)&a[i], vec_a); - cm_mul(vec_a2, vec_b2); - _mm_store_ps((float*)&a[i+2], vec_a2); - cm_mul(vec_a3, vec_b3); - _mm_store_ps((float*)&a[i+4], vec_a3); - cm_mul(vec_a4, vec_b4); - _mm_store_ps((float*)&a[i+6], vec_a4); - - cm_mul(vec_a5, vec_b5); - _mm_store_ps((float*)&a[i+8], vec_a5); - cm_mul(vec_a6, vec_b6); - _mm_store_ps((float*)&a[i+10], vec_a6); - cm_mul(vec_a7, vec_b7); - _mm_store_ps((float*)&a[i+12], vec_a7); - cm_mul(vec_a8, vec_b8); - _mm_store_ps((float*)&a[i+14], vec_a8); - } - - // finish with scalar - for (int i = simd_iterations; i < n; i++) - { - cdsp::complex_t cm; - cm.q = a[i].q*b[i].q - a[i].i*b[i].i; - cm.i = a[i].q*b[i].i + b[i].q*a[i].i; - a[i] = cm; - } -} \ No newline at end of file diff --git a/src/cdsp/fft_math.h b/src/cdsp/fft_math.h deleted file mode 100644 index 1ec6193b..00000000 --- a/src/cdsp/fft_math.h +++ /dev/null @@ -1,127 +0,0 @@ -#pragma once - -// Code by: Stellaris - -#include -#include -#include -#include - -#define M_PI 3.14159265359 - -#define R2(n) n, n + 2*64, n + 1*64, n + 3*64 -#define R4(n) R2(n), R2(n + 2*16), R2(n + 1*16), R2(n + 3*16) -#define R6(n) R4(n), R4(n + 2*4 ), R4(n + 1*4 ), R4(n + 3*4 ) - -// Lookup table that store the reverse of each table -uint8_t lut[256] = { R6(0), R6(2), R6(1), R6(3) }; - -inline uint16_t reverse_16(uint16_t val) -{ - uint8_t lo = lut[val&0xFF]; - uint8_t hi = lut[(val>>8)&0xFF]; - - return (lo << 8) | hi; -} - -static size_t reverse_bits(size_t x, int n) { - size_t result = 0; - for (int i = 0; i < n; i++, x >>= 1) - result = (result << 1) | (x & 1U); - return result; -} - -// struct complex -// { -// float re; -// float im; -// }; - -inline void bit_reverse_swap_aos(cdsp::complex_t* data, int n) -{ - assert(n < 65536); // only up to 16-bit size - int power2 = 0; - for (size_t temp = n; temp > 1U; temp >>= 1) - power2++; - - power2 = 16 - power2; - - for (int i = 0; i < n; i++) { - int j = reverse_16(i << power2); - if (j > i) { - std::swap(data[i], data[j]); - } - } -} - -struct trig_table -{ - float* cos_table; - float* sin_table; -}; -trig_table tables[14]; - -trig_table get_trig_table(int power2) -{ - assert(power2 < 14); - trig_table& table = tables[power2]; - if (table.cos_table == 0) - { - int n = 1 << (power2); - - table.cos_table = (float*)malloc((n/2) * sizeof(float)); - table.sin_table = (float*)malloc((n/2) * sizeof(float)); - - for (size_t i = 0; i < n / 2; i++) { - table.cos_table[i] = cos(2 * M_PI * i / n); - table.sin_table[i] = sin(2 * M_PI * i / n); - } - } - - return table; -} - -void fft_aos(cdsp::complex_t* data, int n) { - - int power2 = 0; - for (size_t temp = n; temp > 1U; temp >>= 1) - power2++; - - float* cos_table; float* sin_table; - trig_table table = get_trig_table(power2); - cos_table = table.cos_table; sin_table = table.sin_table; - - size_t size = (n / 2) * sizeof(float); - - // Bit-reversed addressing permutation - bit_reverse_swap_aos(data, n); - - // Cooley-Tukey decimation-in-time radix-2 FFT - for (size_t size = 2; size <= n; size *= 2) { - size_t halfsize = size / 2; - size_t tablestep = n / size; - for (size_t i = 0; i < n; i += size) { - for (size_t j = i, k = 0; j < i + halfsize; j++, k += tablestep) { - size_t l = j + halfsize; - float tpre = data[l].q * cos_table[k] + data[l].i * sin_table[k]; - float tpim = data[l].i * cos_table[k] - data[l].q * sin_table[k]; - data[l].q = data[j].q - tpre; - data[l].i = data[j].i - tpim; - data[j].q += tpre; - data[j].i += tpim; - } - } - } -} - -// for (int i = 0; i < 327680; i++) { -// complex cm; -// cm.q = complexes[i].q*sineGen[i].q - complexes[i].i*sineGen[i].i; -// cm.i = complexes[i].q*sineGen[i].i + sineGen[i].q*complexes[i].i; -// complexes[i] = cm; -// } - -// ImGui::Begin("FFT"); -// ImGui::PlotLines("I", [](void*data, int idx) { return ((float*)data)[idx]; }, endData, 1024, 0, 0, -1, 12, ImVec2(1024, 200)); -// ImGui::InputFloat("Freq", &frequency, 100000.0f, 100000.0f); -// ImGui::End(); \ No newline at end of file diff --git a/src/cdsp/file.h b/src/cdsp/file.h deleted file mode 100644 index ad57bd33..00000000 --- a/src/cdsp/file.h +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace cdsp { - #pragma pack(push, 1) - struct audio_sample_t { - int16_t l; - int16_t r; - }; - #pragma pack(pop) - - class RawFileSource { - public: - RawFileSource() { - - } - - RawFileSource(std::string path, int bufferSize) : output(bufferSize * 2) { - _bufferSize = bufferSize; - _file = std::ifstream(path.c_str(), std::ios::in | std::ios::binary); - } - - void init(std::string path, int bufferSize) { - output.init(bufferSize * 2); - _bufferSize = bufferSize; - _file = std::ifstream(path.c_str(), std::ios::in | std::ios::binary); - } - - void start() { - _workerThread = std::thread(_worker, this); - } - - stream output; - - private: - static void _worker(RawFileSource* _this) { - audio_sample_t* inBuf = new audio_sample_t[_this->_bufferSize]; - float* outBuf = new float[_this->_bufferSize]; - while (true) { - //printf("%d\n", _this->_bufferSize * sizeof(audio_sample_t)); - _this->_file.read((char*)inBuf, _this->_bufferSize * sizeof(audio_sample_t)); - for (int i = 0; i < _this->_bufferSize; i++) { - outBuf[i] = ((float)inBuf[i].l + (float)inBuf[i].r) / (float)0xFFFF; - } - //printf("Writing file samples\n"); - _this->output.write(outBuf, _this->_bufferSize); - } - } - - int _bufferSize; - std::ifstream _file; - std::thread _workerThread; - }; - - - - - class RawFileSink { - public: - RawFileSink() { - - } - - RawFileSink(std::string path, stream* in, int bufferSize) { - _bufferSize = bufferSize; - _input = in; - _file = std::ofstream(path.c_str(), std::ios::out | std::ios::binary); - } - - void init(std::string path, stream* in, int bufferSize) { - _bufferSize = bufferSize; - _input = in; - _file = std::ofstream(path.c_str(), std::ios::out | std::ios::binary); - } - - void start() { - _workerThread = std::thread(_worker, this); - } - - private: - static void _worker(RawFileSink* _this) { - float* inBuf = new float[_this->_bufferSize]; - audio_sample_t* outBuf = new audio_sample_t[_this->_bufferSize]; - while (true) { - //printf("%d\n", _this->_bufferSize * sizeof(audio_sample_t)); - _this->_input->read(inBuf, _this->_bufferSize); - for (int i = 0; i < _this->_bufferSize; i++) { - outBuf[i].l = inBuf[i] * 0x7FFF; - outBuf[i].r = outBuf[i].l; - } - //printf("Writing file samples\n"); - _this->_file.write((char*)outBuf, _this->_bufferSize * sizeof(audio_sample_t)); - } - } - - int _bufferSize; - std::ofstream _file; - stream* _input; - std::thread _workerThread; - }; -}; \ No newline at end of file diff --git a/src/cdsp/generator.h b/src/cdsp/generator.h deleted file mode 100644 index d64c0818..00000000 --- a/src/cdsp/generator.h +++ /dev/null @@ -1,156 +0,0 @@ -#pragma once -#include -#include -#include - -namespace cdsp { - class SineSource { - public: - SineSource() { - - } - - SineSource(float frequency, long sampleRate, int bufferSize) : output(bufferSize * 2) { - _bufferSize = bufferSize; - _phasorSpeed = (2 * 3.1415926535) / (sampleRate / frequency); - _phase = 0; - } - - void init(float frequency, long sampleRate, int bufferSize) { - output.init(bufferSize * 2); - _bufferSize = bufferSize; - _phasorSpeed = (2 * 3.1415926535) / (sampleRate / frequency); - _phase = 0; - } - - void start() { - _workerThread = std::thread(_worker, this); - } - - stream output; - - private: - static void _worker(SineSource* _this) { - float* outBuf = new float[_this->_bufferSize]; - while (true) { - for (int i = 0; i < _this->_bufferSize; i++) { - _this->_phase += _this->_phasorSpeed; - outBuf[i] = cos(_this->_phase); - } - _this->_phase = fmodf(_this->_phase, 2.0f * 3.1415926535); - _this->output.write(outBuf, _this->_bufferSize); - } - } - - int _bufferSize; - float _phasorSpeed; - float _phase; - std::thread _workerThread; - }; - - class RandomSource { - public: - RandomSource() { - - } - - RandomSource(float frequency, long sampleRate, int bufferSize) : output(bufferSize * 2) { - _bufferSize = bufferSize; - } - - void init(float frequency, long sampleRate, int bufferSize) { - output.init(bufferSize * 2); - _bufferSize = bufferSize; - } - - void start() { - _workerThread = std::thread(_worker, this); - } - - stream output; - - private: - static void _worker(RandomSource* _this) { - float* outBuf = new float[_this->_bufferSize]; - while (true) { - for (int i = 0; i < _this->_bufferSize; i++) { - outBuf[i] = ((float)rand() / ((float)RAND_MAX / 2.0f)) - 1.0f; - } - _this->output.write(outBuf, _this->_bufferSize); - } - } - - int _bufferSize; - std::thread _workerThread; - }; - - class ComplexSineSource { - public: - ComplexSineSource() { - - } - - ComplexSineSource(float frequency, long sampleRate, int bufferSize) : output(bufferSize * 2) { - _bufferSize = bufferSize; - _sampleRate = sampleRate; - _phasorSpeed = (2 * 3.1415926535) / (sampleRate / frequency); - _phase = 0; - running = false; - } - - void init(float frequency, long sampleRate, int bufferSize) { - output.init(bufferSize * 2); - _sampleRate = sampleRate; - _bufferSize = bufferSize; - _phasorSpeed = (2 * 3.1415926535) / (sampleRate / frequency); - _phase = 0; - running = false; - } - - void start() { - if (running) { - return; - } - _workerThread = std::thread(_worker, this); - running = true; - } - - void stop() { - if (!running) { - return; - } - output.stopWriter(); - _workerThread.join(); - output.clearWriteStop(); - running = false; - } - - void setFrequency(float frequency) { - _phasorSpeed = (2 * 3.1415926535) / (_sampleRate / frequency); - } - - stream output; - - private: - static void _worker(ComplexSineSource* _this) { - complex_t* outBuf = new complex_t[_this->_bufferSize]; - while (true) { - for (int i = 0; i < _this->_bufferSize; i++) { - _this->_phase += _this->_phasorSpeed; - outBuf[i].i = sin(_this->_phase); - outBuf[i].q = cos(_this->_phase); - } - _this->_phase = fmodf(_this->_phase, 2.0f * 3.1415926535); - if (_this->output.write(outBuf, _this->_bufferSize) < 0) { break; }; - } - delete[] outBuf; - } - - int _bufferSize; - float _phasorSpeed; - float _phase; - long _sampleRate; - std::thread _workerThread; - bool running; - }; -}; \ No newline at end of file diff --git a/src/cdsp/hackrf.h b/src/cdsp/hackrf.h deleted file mode 100644 index 329e1478..00000000 --- a/src/cdsp/hackrf.h +++ /dev/null @@ -1,194 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -namespace cdsp { - #pragma pack(push, 1) - struct hackrf_sample_t { - int8_t q; - int8_t i; - }; - #pragma pack(pop) - - class Complex2HackRF { - public: - Complex2HackRF() { - - } - - Complex2HackRF(stream* in, int bufferSize) : output(bufferSize * 2) { - _input = in; - _bufferSize = bufferSize; - } - - void init(stream* in, int bufferSize) { - output.init(bufferSize * 2); - _input = in; - _bufferSize = bufferSize; - } - - stream output; - - void start() { - _workerThread = std::thread(_worker, this); - } - - private: - static void _worker(Complex2HackRF* _this) { - complex_t* inBuf = new complex_t[_this->_bufferSize]; - hackrf_sample_t* outBuf = new hackrf_sample_t[_this->_bufferSize]; - while (true) { - _this->_input->read(inBuf, _this->_bufferSize); - for (int i = 0; i < _this->_bufferSize; i++) { - outBuf[i].i = inBuf[i].i * 127.0f; - outBuf[i].q = inBuf[i].q * 127.0f; - } - _this->output.write(outBuf, _this->_bufferSize); - } - } - - int _bufferSize; - stream* _input; - std::thread _workerThread; - }; - - class HackRF2Complex { - public: - HackRF2Complex() { - - } - - HackRF2Complex(stream* out, int bufferSize) : input(bufferSize * 2) { - _output = out; - _bufferSize = bufferSize; - } - - void init(stream* out, int bufferSize) { - input.init(bufferSize * 2); - _output = out; - _bufferSize = bufferSize; - } - - void start() { - _workerThread = std::thread(_worker, this); - } - - stream input; - - private: - static void _worker(HackRF2Complex* _this) { - hackrf_sample_t* inBuf = new hackrf_sample_t[_this->_bufferSize]; - complex_t* outBuf = new complex_t[_this->_bufferSize]; - while (true) { - - _this->input.read(inBuf, _this->_bufferSize); - for (int i = 0; i < _this->_bufferSize; i++) { - outBuf[i].i = (float)inBuf[i].i / 127.0f; - outBuf[i].q = (float)inBuf[i].q / 127.0f; - } - _this->_output->write(outBuf, _this->_bufferSize); - } - } - - int _bufferSize; - stream* _output; - std::thread _workerThread; - }; - - class HackRFSink { - public: - HackRFSink() { - - } - - HackRFSink(hackrf_device* dev, int bufferSize, stream* input) : gen(input, bufferSize) { - _input = input; - _dev = dev; - gen.start(); - } - - void init(hackrf_device* dev, int bufferSize, stream* input) { - gen.init(input, bufferSize); - _input = input; - _dev = dev; - gen.start(); - } - - void start() { - streaming = true; - hackrf_start_tx(_dev, _worker, this); - } - - void stop() { - streaming = false; - Sleep(500); - hackrf_stop_tx(_dev); - } - - private: - static int _worker(hackrf_transfer* transfer) { - if (!((HackRFSink*)transfer->tx_ctx)->streaming) { - return -1; - } - hackrf_sample_t* buf = (hackrf_sample_t*)transfer->buffer; - ((HackRFSink*)transfer->tx_ctx)->gen.output.read(buf, transfer->buffer_length / 2); - return 0; - } - - Complex2HackRF gen; - bool streaming; - stream* _input; - hackrf_device* _dev; - }; - - class HackRFSource { - public: - HackRFSource() { - - } - - HackRFSource(hackrf_device* dev, int bufferSize) : output(bufferSize * 2), gen(&output, bufferSize) { - _dev = dev; - gen.start(); - } - - void init(hackrf_device* dev, int bufferSize) { - output.init(bufferSize * 2); - gen.init(&output, bufferSize); - _dev = dev; - gen.start(); - } - - void start() { - streaming = true; - hackrf_start_rx(_dev, _worker, this); - } - - void stop() { - streaming = false; - Sleep(500); - hackrf_stop_rx(_dev); - } - - stream output; - - private: - static int _worker(hackrf_transfer* transfer) { - if (!((HackRFSource*)transfer->rx_ctx)->streaming) { - return -1; - } - hackrf_sample_t* buf = (hackrf_sample_t*)transfer->buffer; - //printf("Writing samples\n"); - ((HackRFSource*)transfer->rx_ctx)->gen.input.write(buf, transfer->buffer_length / 2); - return 0; - } - - HackRF2Complex gen; - bool streaming; - hackrf_device* _dev; - }; -}; \ No newline at end of file diff --git a/src/cdsp/math.h b/src/cdsp/math.h deleted file mode 100644 index f9a810fa..00000000 --- a/src/cdsp/math.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace cdsp { - class Multiplier { - public: - Multiplier() { - - } - - Multiplier(stream* a, stream* b, int bufferSize) : output(bufferSize * 2) { - _a = a; - _b = b; - _bufferSize = bufferSize; - } - - void init(stream* a, stream* b, int bufferSize) { - output.init(bufferSize * 2); - _a = a; - _b = b; - _bufferSize = bufferSize; - } - - void start() { - if (running) { - return; - } - running = true; - _workerThread = std::thread(_worker, this); - } - - void stop() { - if (!running) { - return; - } - _a->stopReader(); - _b->stopReader(); - output.stopWriter(); - _workerThread.join(); - running = false; - _a->clearReadStop(); - _b->clearReadStop(); - output.clearWriteStop(); - } - - stream output; - - private: - static void _worker(Multiplier* _this) { - complex_t* aBuf = new complex_t[_this->_bufferSize]; - complex_t* bBuf = new complex_t[_this->_bufferSize]; - complex_t* outBuf = new complex_t[_this->_bufferSize]; - while (true) { - if (_this->_a->read(aBuf, _this->_bufferSize) < 0) { printf("A Received stop signal\n"); return; }; - if (_this->_b->read(bBuf, _this->_bufferSize) < 0) { printf("B Received stop signal\n"); return; }; - do_mul(aBuf, bBuf, _this->_bufferSize); - if (_this->output.write(aBuf, _this->_bufferSize) < 0) { printf("OUT Received stop signal\n"); return; }; - } - } - - stream* _a; - stream* _b; - int _bufferSize; - bool running = false; - std::thread _workerThread; - }; -}; \ No newline at end of file diff --git a/src/cdsp/modulation.h b/src/cdsp/modulation.h deleted file mode 100644 index d1421187..00000000 --- a/src/cdsp/modulation.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace cdsp { - class FMModulator { - public: - FMModulator() { - - } - - FMModulator(stream* in, float deviation, long sampleRate, int bufferSize) : output(bufferSize * 2) { - _input = in; - _bufferSize = bufferSize; - _phase = 0.0f; - _phasorSpeed = (2 * 3.1415926535) / (sampleRate / deviation); - } - - void init(stream* in, float deviation, long sampleRate, int bufferSize) { - output.init(bufferSize * 2); - _input = in; - _bufferSize = bufferSize; - _phase = 0.0f; - _phasorSpeed = (2 * 3.1415926535) / (sampleRate / deviation); - } - - void start() { - _workerThread = std::thread(_worker, this); - } - - stream output; - - private: - static void _worker(FMModulator* _this) { - float* inBuf = new float[_this->_bufferSize]; - complex_t* outBuf = new complex_t[_this->_bufferSize]; - while (true) { - _this->_input->read(inBuf, _this->_bufferSize); - for (int i = 0; i < _this->_bufferSize; i++) { - _this->_phase += inBuf[i] * _this->_phasorSpeed; - outBuf[i].i = std::sinf(_this->_phase); - outBuf[i].q = std::cosf(_this->_phase); - } - _this->_phase = fmodf(_this->_phase, 2.0f * 3.1415926535); - _this->output.write(outBuf, _this->_bufferSize); - } - } - - stream* _input; - int _bufferSize; - float _phase; - float _phasorSpeed; - std::thread _workerThread; - }; -}; \ No newline at end of file diff --git a/src/cdsp/resampling.h b/src/cdsp/resampling.h deleted file mode 100644 index 458d3998..00000000 --- a/src/cdsp/resampling.h +++ /dev/null @@ -1,317 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - - -namespace cdsp { - class Interpolator { - public: - Interpolator() { - - } - - Interpolator(stream* in, float interpolation, int bufferSize) : output(bufferSize * 2) { - _input = in; - _interpolation = interpolation; - _bufferSize = bufferSize; - running = false; - } - - void init(stream* in, float interpolation, int bufferSize) { - output.init(bufferSize * 2); - _input = in; - _interpolation = interpolation; - _bufferSize = bufferSize; - running = false; - } - - void start() { - if (running) { - return; - } - running = true; - _workerThread = std::thread(_worker, this); - } - - void stop() { - if (!running) { - return; - } - running = false; - _input->stopReader(); - output.stopWriter(); - _workerThread.join(); - _input->clearReadStop(); - output.clearWriteStop(); - } - - void setInterpolation(float interpolation) { - if (running) { - return; - } - _interpolation = interpolation; - } - - void setInput(stream* in) { - if (running) { - return; - } - _input = in; - } - - stream output; - - private: - static void _worker(Interpolator* _this) { - float* inBuf = new float[(int)((float)_this->_bufferSize / _this->_interpolation)]; - float* outBuf = new float[_this->_bufferSize]; - while (true) { - if (_this->_input->read(inBuf, (int)((float)_this->_bufferSize / _this->_interpolation)) < 0) { break; }; - for (int i = 0; i < _this->_bufferSize; i++) { - outBuf[i] = inBuf[(int)((float)i / _this->_interpolation)]; - } - if (_this->output.write(outBuf, _this->_bufferSize) < 0) { break; }; - } - delete[] inBuf; - delete[] outBuf; - } - - stream* _input; - int _bufferSize; - float _interpolation; - std::thread _workerThread; - bool running; - }; - - - class IQInterpolator { - public: - IQInterpolator() { - - } - - IQInterpolator(stream* in, float interpolation, int bufferSize) : output(bufferSize * 2) { - _input = in; - _interpolation = interpolation; - _bufferSize = bufferSize; - running = false; - } - - void init(stream* in, float interpolation, int bufferSize) { - output.init(bufferSize * 2); - _input = in; - _interpolation = interpolation; - _bufferSize = bufferSize; - running = false; - } - - 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 setInterpolation(float interpolation) { - if (running) { - return; - } - _interpolation = interpolation; - } - - stream output; - - private: - static void _worker(IQInterpolator* _this) { - complex_t* inBuf = new complex_t[_this->_bufferSize]; - complex_t* outBuf = new complex_t[_this->_bufferSize * _this->_interpolation]; - int outCount = _this->_bufferSize * _this->_interpolation; - while (true) { - if (_this->_input->read(inBuf, _this->_bufferSize) < 0) { break; }; - for (int i = 0; i < outCount; i++) { - outBuf[i] = inBuf[(int)((float)i / _this->_interpolation)]; - } - if (_this->output.write(outBuf, _this->_bufferSize) < 0) { break; }; - } - delete[] inBuf; - delete[] outBuf; - } - - stream* _input; - int _bufferSize; - float _interpolation; - std::thread _workerThread; - bool running; - }; - - class BlockDecimator { - public: - BlockDecimator() { - - } - - BlockDecimator(stream* in, int skip, int bufferSize) : output(bufferSize * 2) { - _input = in; - _skip = skip; - _bufferSize = bufferSize; - } - - void init(stream* in, int skip, int bufferSize) { - output.init(bufferSize * 2); - _input = in; - _skip = skip; - _bufferSize = bufferSize; - } - - void start() { - _workerThread = std::thread(_worker, this); - } - - stream output; - - private: - static void _worker(BlockDecimator* _this) { - complex_t* buf = new complex_t[_this->_bufferSize]; - while (true) { - _this->_input->readAndSkip(buf, _this->_bufferSize, _this->_skip); - _this->output.write(buf, _this->_bufferSize); - } - } - - stream* _input; - int _bufferSize; - int _skip; - std::thread _workerThread; - }; - - class FractionalResampler { - public: - FractionalResampler() { - - } - - void init(stream* input, float inputSampleRate, float outputSampleRate, int bufferSize, float customCutoff = INFINITY) { - _input = input; - float lowestFreq = std::min(inputSampleRate, outputSampleRate); - int _gcd = std::gcd((int)inputSampleRate, (int)outputSampleRate); - _interp = outputSampleRate / _gcd; - _decim = inputSampleRate / _gcd; - _inputSampleRate = inputSampleRate; - _outputSampleRate = outputSampleRate; - running = false; - - interpolator.init(input, _interp, bufferSize); - - BlackmanWindow(decimTaps, inputSampleRate * _interp, lowestFreq / 2.0f, lowestFreq / 2.0f); - - if (_interp != 1) { - printf("FR Interpolation needed\n"); - decimator.init(&interpolator.output, decimTaps, bufferSize * _interp, _decim); - } - else { - decimator.init(input, decimTaps, bufferSize, _decim); - printf("FR Interpolation NOT needed: %d %d %d\n", bufferSize / _decim, _decim, _interp); - } - - output = &decimator.output; - } - - void start() { - if (_interp != 1) { - interpolator.start(); - } - decimator.start(); - running = true; - } - - void stop() { - interpolator.stop(); - decimator.stop(); - running = false; - } - - void setInputSampleRate(float inputSampleRate) { - if (running) { - return; - } - float lowestFreq = std::min(inputSampleRate, _outputSampleRate); - int _gcd = std::gcd((int)inputSampleRate, (int)_outputSampleRate); - _interp = _outputSampleRate / _gcd; - _decim = inputSampleRate / _gcd; - - // TODO: Add checks from VFO to remove the need to stop both - interpolator.setInterpolation(_interp); - decimator.setDecimation(_decim); - if (_interp != 1) { - decimator.setInput(&interpolator.output); - } - else { - decimator.setInput(_input); - } - } - - void setOutputSampleRate(float outputSampleRate) { - if (running) { - return; - } - float lowestFreq = std::min(_inputSampleRate, outputSampleRate); - int _gcd = std::gcd((int)_inputSampleRate, (int)outputSampleRate); - _interp = outputSampleRate / _gcd; - _decim = _inputSampleRate / _gcd; - - // TODO: Add checks from VFO to remove the need to stop both - interpolator.setInterpolation(_interp); - decimator.setDecimation(_decim); - if (_interp != 1) { - decimator.setInput(&interpolator.output); - } - else { - decimator.setInput(_input); - } - } - - void setInput(stream* input) { - if (running) { - return; - } - _input = input; - if (_interp != 1) { - interpolator.setInput(input); - decimator.setInput(&interpolator.output); - } - else { - decimator.setInput(input); - } - } - - stream* output; - - private: - Interpolator interpolator; - FloatDecimatingFIRFilter decimator; - std::vector decimTaps; - stream* _input; - int _interp; - int _decim; - int _bufferSize; - float _inputSampleRate; - float _outputSampleRate; - bool running; - }; -}; \ No newline at end of file diff --git a/src/dsp/correction.h b/src/dsp/correction.h new file mode 100644 index 00000000..f1c4f9ee --- /dev/null +++ b/src/dsp/correction.h @@ -0,0 +1,63 @@ +#pragma once +#include +#include +#include +#include + +namespace dsp { + class DCBiasRemover { + public: + DCBiasRemover() { + + } + + DCBiasRemover(stream* input, int bufferSize) : output(bufferSize * 2) { + _in = input; + _bufferSize = bufferSize; + bypass = false; + } + + void init(stream* input, int bufferSize) { + output.init(bufferSize * 2); + _in = input; + _bufferSize = bufferSize; + bypass = false; + } + + void start() { + _workerThread = std::thread(_worker, this); + } + + stream output; + bool bypass; + + private: + static void _worker(DCBiasRemover* _this) { + complex_t* buf = new complex_t[_this->_bufferSize]; + float ibias = 0.0f; + float qbias = 0.0f; + while (true) { + _this->_in->read(buf, _this->_bufferSize); + if (_this->bypass) { + _this->output.write(buf, _this->_bufferSize); + continue; + } + for (int i = 0; i < _this->_bufferSize; i++) { + ibias += buf[i].i; + qbias += buf[i].q; + } + ibias /= _this->_bufferSize; + qbias /= _this->_bufferSize; + for (int i = 0; i < _this->_bufferSize; i++) { + buf[i].i -= ibias; + buf[i].q -= qbias; + } + _this->output.write(buf, _this->_bufferSize); + } + } + + stream* _in; + int _bufferSize; + std::thread _workerThread; + }; +}; \ No newline at end of file diff --git a/src/cdsp/demodulation.h b/src/dsp/demodulator.h similarity index 66% rename from src/cdsp/demodulation.h rename to src/dsp/demodulator.h index e4ab95d7..cef14e78 100644 --- a/src/cdsp/demodulation.h +++ b/src/dsp/demodulator.h @@ -1,13 +1,17 @@ #pragma once #include -#include -#include +#include +#include + +/* + TODO: + - Add a sample rate ajustment function to all demodulators +*/ #define FAST_ATAN2_COEF1 3.1415926535f / 4.0f #define FAST_ATAN2_COEF2 3.0f * FAST_ATAN2_COEF1 -inline float fast_arctan2(float y, float x) -{ +inline float fast_arctan2(float y, float x) { float abs_y = fabs(y)+1e-10; float r, angle; if (x>=0) @@ -26,26 +30,26 @@ inline float fast_arctan2(float y, float x) return angle; } -namespace cdsp { +namespace dsp { class FMDemodulator { public: FMDemodulator() { } - FMDemodulator(stream* in, float deviation, long sampleRate, int bufferSize) : output(bufferSize * 2) { + FMDemodulator(stream* in, float deviation, long sampleRate, int blockSize) : output(blockSize * 2) { running = false; _input = in; - _bufferSize = bufferSize; + _blockSize = blockSize; _phase = 0.0f; _phasorSpeed = (2 * 3.1415926535) / (sampleRate / deviation); } - void init(stream* in, float deviation, long sampleRate, int bufferSize) { - output.init(bufferSize * 2); + void init(stream* in, float deviation, long sampleRate, int blockSize) { + output.init(blockSize * 2); running = false; _input = in; - _bufferSize = bufferSize; + _blockSize = blockSize; _phase = 0.0f; _phasorSpeed = (2 * 3.1415926535) / (sampleRate / deviation); } @@ -70,17 +74,25 @@ namespace cdsp { output.clearWriteStop(); } + void setBlockSize(int blockSize) { + if (running) { + return; + } + _blockSize = blockSize; + output.setMaxLatency(_blockSize * 2); + } + stream output; private: static void _worker(FMDemodulator* _this) { - complex_t* inBuf = new complex_t[_this->_bufferSize]; - float* outBuf = new float[_this->_bufferSize]; + complex_t* inBuf = new complex_t[_this->_blockSize]; + float* outBuf = new float[_this->_blockSize]; float diff = 0; float currentPhase = 0; while (true) { - if (_this->_input->read(inBuf, _this->_bufferSize) < 0) { return; }; - for (int i = 0; i < _this->_bufferSize; i++) { + if (_this->_input->read(inBuf, _this->_blockSize) < 0) { return; }; + for (int i = 0; i < _this->_blockSize; i++) { currentPhase = fast_arctan2(inBuf[i].i, inBuf[i].q); diff = currentPhase - _this->_phase; if (diff > 3.1415926535f) { diff -= 2 * 3.1415926535f; } @@ -88,13 +100,13 @@ namespace cdsp { outBuf[i] = diff / _this->_phasorSpeed; _this->_phase = currentPhase; } - if (_this->output.write(outBuf, _this->_bufferSize) < 0) { return; }; + if (_this->output.write(outBuf, _this->_blockSize) < 0) { return; }; } } stream* _input; bool running; - int _bufferSize; + int _blockSize; float _phase; float _phasorSpeed; std::thread _workerThread; @@ -107,17 +119,17 @@ namespace cdsp { } - AMDemodulator(stream* in, int bufferSize) : output(bufferSize * 2) { + AMDemodulator(stream* in, int blockSize) : output(blockSize * 2) { running = false; _input = in; - _bufferSize = bufferSize; + _blockSize = blockSize; } - void init(stream* in, int bufferSize) { - output.init(bufferSize * 2); + void init(stream* in, int blockSize) { + output.init(blockSize * 2); running = false; _input = in; - _bufferSize = bufferSize; + _blockSize = blockSize; } void start() { @@ -140,18 +152,26 @@ namespace cdsp { output.clearWriteStop(); } + void setBlockSize(int blockSize) { + if (running) { + return; + } + _blockSize = blockSize; + output.setMaxLatency(_blockSize * 2); + } + stream output; private: static void _worker(AMDemodulator* _this) { - complex_t* inBuf = new complex_t[_this->_bufferSize]; - float* outBuf = new float[_this->_bufferSize]; + complex_t* inBuf = new complex_t[_this->_blockSize]; + float* outBuf = new float[_this->_blockSize]; float min, max, amp; while (true) { - if (_this->_input->read(inBuf, _this->_bufferSize) < 0) { return; }; + if (_this->_input->read(inBuf, _this->_blockSize) < 0) { break; }; min = INFINITY; max = 0.0f; - for (int i = 0; i < _this->_bufferSize; i++) { + for (int i = 0; i < _this->_blockSize; i++) { outBuf[i] = sqrt((inBuf[i].i*inBuf[i].i) + (inBuf[i].q*inBuf[i].q)); if (outBuf[i] < min) { min = outBuf[i]; @@ -161,16 +181,18 @@ namespace cdsp { } } amp = (max - min); - for (int i = 0; i < _this->_bufferSize; i++) { + for (int i = 0; i < _this->_blockSize; i++) { outBuf[i] = (outBuf[i] - min) / (max - min); } - if (_this->output.write(outBuf, _this->_bufferSize) < 0) { return; }; + if (_this->output.write(outBuf, _this->_blockSize) < 0) { break; }; } + delete[] inBuf; + delete[] outBuf; } stream* _input; bool running; - int _bufferSize; + int _blockSize; std::thread _workerThread; }; }; \ No newline at end of file diff --git a/src/cdsp/filter.h b/src/dsp/filter.h similarity index 57% rename from src/cdsp/filter.h rename to src/dsp/filter.h index 1b56cdb4..575529a5 100644 --- a/src/cdsp/filter.h +++ b/src/dsp/filter.h @@ -1,41 +1,40 @@ #pragma once #include -#include -#include +#include +#include #include +#include #define GET_FROM_RIGHT_BUF(buffer, delayLine, delayLineSz, n) (((n) < 0) ? delayLine[(delayLineSz) + (n)] : buffer[(n)]) -#define M_PI 3.1415926535f - -inline void BlackmanWindow(std::vector& taps, float sampleRate, float cutoff, float transWidth) { - taps.clear(); - float fc = cutoff / sampleRate; - int _M = 4.0f / (transWidth / sampleRate); - if (_M % 2 == 0) { _M++; } - float M = _M; - float sum = 0.0f; - for (int i = 0; i < _M; i++) { - float val = (sin(2.0f * M_PI * fc * ((float)i - (M / 2))) / ((float)i - (M / 2))) * (0.42f - (0.5f * cos(2.0f * M_PI / M)) + (0.8f * cos(4.0f * M_PI / M))); - taps.push_back(val); - sum += val; +namespace dsp { + inline void BlackmanWindow(std::vector& taps, float sampleRate, float cutoff, float transWidth) { + taps.clear(); + float fc = cutoff / sampleRate; + int _M = 4.0f / (transWidth / sampleRate); + if (_M % 2 == 0) { _M++; } + float M = _M; + float sum = 0.0f; + for (int i = 0; i < _M; i++) { + float val = (sin(2.0f * M_PI * fc * ((float)i - (M / 2))) / ((float)i - (M / 2))) * (0.42f - (0.5f * cos(2.0f * M_PI / M)) + (0.8f * cos(4.0f * M_PI / M))); + taps.push_back(val); + sum += val; + } + for (int i = 0; i < M; i++) { + taps[i] /= sum; + } } - for (int i = 0; i < M; i++) { - taps[i] /= sum; - } -} -namespace cdsp { class DecimatingFIRFilter { public: DecimatingFIRFilter() { } - DecimatingFIRFilter(stream* input, std::vector taps, int bufferSize, float decim) : output(bufferSize * 2) { - output.init(bufferSize * 2); + DecimatingFIRFilter(stream* input, std::vector taps, int blockSize, float decim) : output(blockSize * 2) { + output.init(blockSize * 2); _in = input; - _bufferSize = bufferSize; + _blockSize = blockSize; _tapCount = taps.size(); delayBuf = new complex_t[_tapCount]; @@ -54,10 +53,10 @@ namespace cdsp { running = false; } - void init(stream* input, std::vector& taps, int bufferSize, float decim) { - output.init(bufferSize * 2); + void init(stream* input, std::vector& taps, int blockSize, float decim) { + output.init(blockSize * 2); _in = input; - _bufferSize = bufferSize; + _blockSize = blockSize; _tapCount = taps.size(); delayBuf = new complex_t[_tapCount]; @@ -101,8 +100,11 @@ namespace cdsp { return; } _tapCount = taps.size(); + printf("[%d]\n", _tapCount); delete[] _taps; + delete[] delayBuf; _taps = new float[_tapCount]; + delayBuf = new complex_t[_tapCount]; for (int i = 0; i < _tapCount; i++) { _taps[i] = taps[i]; } @@ -120,28 +122,30 @@ namespace cdsp { return; } _decim = decimation; + output.setMaxLatency((_blockSize * 2) / _decim); } - void setBufferSize(int bufferSize) { + void setBlockSize(int blockSize) { if (running) { return; } - _bufferSize = bufferSize; + _blockSize = blockSize; + output.setMaxLatency((_blockSize * 2) / _decim); } stream output; private: static void _worker(DecimatingFIRFilter* _this) { - int outputSize = _this->_bufferSize / _this->_decim; - complex_t* inBuf = new complex_t[_this->_bufferSize]; + int outputSize = _this->_blockSize / _this->_decim; + complex_t* inBuf = new complex_t[_this->_blockSize]; complex_t* outBuf = new complex_t[outputSize]; float tap = 0.0f; int delayOff; - void* delayStart = &inBuf[_this->_bufferSize - (_this->_tapCount - 1)]; + void* delayStart = &inBuf[_this->_blockSize - (_this->_tapCount - 1)]; int delaySize = (_this->_tapCount - 1) * sizeof(complex_t); - int bufferSize = _this->_bufferSize; + int blockSize = _this->_blockSize; int outBufferLength = outputSize * sizeof(complex_t); int tapCount = _this->_tapCount; int decim = _this->_decim; @@ -149,7 +153,7 @@ namespace cdsp { int id = 0; while (true) { - if (_this->_in->read(inBuf, bufferSize) < 0) { break; }; + if (_this->_in->read(inBuf, blockSize) < 0) { break; }; memset(outBuf, 0, outBufferLength); for (int t = 0; t < tapCount; t++) { @@ -161,7 +165,7 @@ namespace cdsp { delayOff = tapCount - t; id = 0; - for (int i = 0; i < bufferSize; i += decim) { + for (int i = 0; i < blockSize; i += decim) { if (i < t) { outBuf[id].i += tap * delayBuf[delayOff + i].i; outBuf[id].q += tap * delayBuf[delayOff + i].q; @@ -182,7 +186,7 @@ namespace cdsp { stream* _in; complex_t* delayBuf; - int _bufferSize; + int _blockSize; int _tapCount = 0; float _decim; std::thread _workerThread; @@ -190,16 +194,17 @@ namespace cdsp { bool running; }; + class FloatDecimatingFIRFilter { public: FloatDecimatingFIRFilter() { } - FloatDecimatingFIRFilter(stream* input, std::vector taps, int bufferSize, float decim) : output(bufferSize * 2) { - output.init(bufferSize * 2); + FloatDecimatingFIRFilter(stream* input, std::vector taps, int blockSize, float decim) : output(blockSize * 2) { + output.init(blockSize * 2); _in = input; - _bufferSize = bufferSize; + _blockSize = blockSize; _tapCount = taps.size(); delayBuf = new float[_tapCount]; @@ -217,10 +222,10 @@ namespace cdsp { running = false; } - void init(stream* input, std::vector& taps, int bufferSize, float decim) { - output.init(bufferSize * 2); + void init(stream* input, std::vector& taps, int blockSize, float decim) { + output.init(blockSize * 2); _in = input; - _bufferSize = bufferSize; + _blockSize = blockSize; _tapCount = taps.size(); delayBuf = new float[_tapCount]; @@ -239,11 +244,17 @@ namespace cdsp { } void start() { + if (running) { + return; + } running = true; _workerThread = std::thread(_worker, this); } void stop() { + if (!running) { + return; + } _in->stopReader(); output.stopWriter(); _workerThread.join(); @@ -258,7 +269,9 @@ namespace cdsp { } _tapCount = taps.size(); delete[] _taps; + delete[] delayBuf; _taps = new float[_tapCount]; + delayBuf = new float[_tapCount]; for (int i = 0; i < _tapCount; i++) { _taps[i] = taps[i]; } @@ -276,29 +289,38 @@ namespace cdsp { return; } _decim = decimation; + output.setMaxLatency((_blockSize * 2) / _decim); + } + + void setBlockSize(int blockSize) { + if (running) { + return; + } + _blockSize = blockSize; + output.setMaxLatency((_blockSize * 2) / _decim); } stream output; private: static void _worker(FloatDecimatingFIRFilter* _this) { - int outputSize = _this->_bufferSize / _this->_decim; - float* inBuf = new float[_this->_bufferSize]; + int outputSize = _this->_blockSize / _this->_decim; + float* inBuf = new float[_this->_blockSize]; float* outBuf = new float[outputSize]; float tap = 0.0f; int delayOff; - void* delayStart = &inBuf[_this->_bufferSize - (_this->_tapCount - 1)]; + void* delayStart = &inBuf[_this->_blockSize - (_this->_tapCount - 1)]; int delaySize = (_this->_tapCount - 1) * sizeof(float); - int bufferSize = _this->_bufferSize; - int outBufferLength = outputSize * sizeof(float); + int blockSize = _this->_blockSize; + int outBufferLength = outputSize * sizeof(complex_t); int tapCount = _this->_tapCount; int decim = _this->_decim; float* delayBuf = _this->delayBuf; int id = 0; while (true) { - if (_this->_in->read(inBuf, bufferSize) < 0) { break; }; + if (_this->_in->read(inBuf, blockSize) < 0) { break; }; memset(outBuf, 0, outBufferLength); for (int t = 0; t < tapCount; t++) { @@ -310,7 +332,7 @@ namespace cdsp { delayOff = tapCount - t; id = 0; - for (int i = 0; i < bufferSize; i += decim) { + for (int i = 0; i < blockSize; i += decim) { if (i < t) { outBuf[id] += tap * delayBuf[delayOff + i]; id++; @@ -329,150 +351,11 @@ namespace cdsp { stream* _in; float* delayBuf; - int _bufferSize; + int _blockSize; int _tapCount = 0; float _decim; std::thread _workerThread; float* _taps; bool running; }; - - class DCBiasRemover { - public: - DCBiasRemover() { - - } - - DCBiasRemover(stream* input, int bufferSize) : output(bufferSize * 2) { - _in = input; - _bufferSize = bufferSize; - bypass = false; - } - - void init(stream* input, int bufferSize) { - output.init(bufferSize * 2); - _in = input; - _bufferSize = bufferSize; - bypass = false; - } - - void start() { - _workerThread = std::thread(_worker, this); - } - - stream output; - bool bypass; - - private: - static void _worker(DCBiasRemover* _this) { - complex_t* buf = new complex_t[_this->_bufferSize]; - float ibias = 0.0f; - float qbias = 0.0f; - while (true) { - _this->_in->read(buf, _this->_bufferSize); - if (_this->bypass) { - _this->output.write(buf, _this->_bufferSize); - continue; - } - for (int i = 0; i < _this->_bufferSize; i++) { - ibias += buf[i].i; - qbias += buf[i].q; - } - ibias /= _this->_bufferSize; - qbias /= _this->_bufferSize; - for (int i = 0; i < _this->_bufferSize; i++) { - buf[i].i -= ibias; - buf[i].q -= qbias; - } - _this->output.write(buf, _this->_bufferSize); - } - } - - stream* _in; - int _bufferSize; - std::thread _workerThread; - }; - - class HandlerSink { - public: - HandlerSink() { - - } - - HandlerSink(stream* input, complex_t* buffer, int bufferSize, void handler(complex_t*)) { - _in = input; - _bufferSize = bufferSize; - _buffer = buffer; - _handler = handler; - } - - void init(stream* input, complex_t* buffer, int bufferSize, void handler(complex_t*)) { - _in = input; - _bufferSize = bufferSize; - _buffer = buffer; - _handler = handler; - } - - void start() { - _workerThread = std::thread(_worker, this); - } - - bool bypass; - - private: - static void _worker(HandlerSink* _this) { - while (true) { - _this->_in->read(_this->_buffer, _this->_bufferSize); - _this->_handler(_this->_buffer); - } - } - - stream* _in; - int _bufferSize; - complex_t* _buffer; - std::thread _workerThread; - void (*_handler)(complex_t*); - }; - - class Splitter { - public: - Splitter() { - - } - - Splitter(stream* input, int bufferSize) { - _in = input; - _bufferSize = bufferSize; - output_a.init(bufferSize); - output_b.init(bufferSize); - } - - void init(stream* input, int bufferSize) { - _in = input; - _bufferSize = bufferSize; - output_a.init(bufferSize); - output_b.init(bufferSize); - } - - void start() { - _workerThread = std::thread(_worker, this); - } - - stream output_a; - stream output_b; - - private: - static void _worker(Splitter* _this) { - complex_t* buf = new complex_t[_this->_bufferSize]; - while (true) { - _this->_in->read(buf, _this->_bufferSize); - _this->output_a.write(buf, _this->_bufferSize); - _this->output_b.write(buf, _this->_bufferSize); - } - } - - stream* _in; - int _bufferSize; - std::thread _workerThread; - }; }; \ No newline at end of file diff --git a/src/dsp/math.h b/src/dsp/math.h new file mode 100644 index 00000000..e8fdbdc3 --- /dev/null +++ b/src/dsp/math.h @@ -0,0 +1,85 @@ +#pragma once +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.1415926535f +#endif + +namespace dsp { + class Multiplier { + public: + Multiplier() { + + } + + Multiplier(stream* a, stream* b, int blockSize) : output(blockSize * 2) { + _a = a; + _b = b; + _blockSize = blockSize; + } + + void init(stream* a, stream* b, int blockSize) { + output.init(blockSize * 2); + _a = a; + _b = b; + _blockSize = blockSize; + } + + void start() { + if (running) { + return; + } + running = true; + _workerThread = std::thread(_worker, this); + } + + void stop() { + if (!running) { + return; + } + _a->stopReader(); + _b->stopReader(); + output.stopWriter(); + _workerThread.join(); + running = false; + _a->clearReadStop(); + _b->clearReadStop(); + output.clearWriteStop(); + } + + void setBlockSize(int blockSize) { + if (running) { + return; + } + _blockSize = blockSize; + output.setMaxLatency(blockSize * 2); + } + + stream output; + + private: + static void _worker(Multiplier* _this) { + complex_t* aBuf = (complex_t*)volk_malloc(sizeof(complex_t) * _this->_blockSize, volk_get_alignment()); + complex_t* bBuf = (complex_t*)volk_malloc(sizeof(complex_t) * _this->_blockSize, volk_get_alignment()); + complex_t* outBuf = (complex_t*)volk_malloc(sizeof(complex_t) * _this->_blockSize, volk_get_alignment()); + while (true) { + if (_this->_a->read(aBuf, _this->_blockSize) < 0) { break; }; + if (_this->_b->read(bBuf, _this->_blockSize) < 0) { break; }; + volk_32fc_x2_multiply_32fc((lv_32fc_t*)outBuf, (lv_32fc_t*)aBuf, (lv_32fc_t*)bBuf, _this->_blockSize); + if (_this->output.write(outBuf, _this->_blockSize) < 0) { break; }; + } + volk_free(aBuf); + volk_free(bBuf); + volk_free(outBuf); + } + + stream* _a; + stream* _b; + int _blockSize; + bool running = false; + std::thread _workerThread; + }; +}; \ No newline at end of file diff --git a/src/dsp/resampling.h b/src/dsp/resampling.h new file mode 100644 index 00000000..eb8e1b6f --- /dev/null +++ b/src/dsp/resampling.h @@ -0,0 +1,425 @@ +#pragma once +#include +#include +#include +#include +#include + + +namespace dsp { + template + class Interpolator { + public: + Interpolator() { + + } + + Interpolator(stream* in, float interpolation, int blockSize) : output(blockSize * interpolation * 2) { + _input = in; + _interpolation = interpolation; + _blockSize = blockSize; + } + + void init(stream* in, float interpolation, int blockSize) { + output.init(blockSize * 2); + _input = in; + _interpolation = interpolation; + _blockSize = blockSize; + } + + 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 setInterpolation(float interpolation) { + if (running) { + return; + } + _interpolation = interpolation; + output.setMaxLatency(_blockSize * _interpolation * 2); + } + + void setBlockSize(int blockSize) { + if (running) { + return; + } + _blockSize = blockSize; + output.setMaxLatency(_blockSize * _interpolation * 2); + } + + void setInput(stream* input) { + if (running) { + return; + } + _input = input; + } + + stream output; + + private: + static void _worker(Interpolator* _this) { + T* inBuf = new T[_this->_blockSize]; + T* outBuf = new T[_this->_blockSize * _this->_interpolation]; + int outCount = _this->_blockSize * _this->_interpolation; + while (true) { + if (_this->_input->read(inBuf, _this->_blockSize) < 0) { break; }; + for (int i = 0; i < outCount; i++) { + outBuf[i] = inBuf[(int)((float)i / _this->_interpolation)]; + } + if (_this->output.write(outBuf, outCount) < 0) { break; }; + } + delete[] inBuf; + delete[] outBuf; + } + + stream* _input; + int _blockSize; + float _interpolation; + std::thread _workerThread; + bool running = false; + }; + + class BlockDecimator { + public: + BlockDecimator() { + + } + + BlockDecimator(stream* in, int skip, int blockSize) : output(blockSize * 2) { + _input = in; + _skip = skip; + _blockSize = blockSize; + } + + void init(stream* in, int skip, int blockSize) { + output.init(blockSize * 2); + _input = in; + _skip = skip; + _blockSize = blockSize; + } + + void start() { + if (running) { + return; + } + _workerThread = std::thread(_worker, this); + } + + void stop() { + if (!running) { + return; + } + _input->stopReader(); + output.stopWriter(); + _workerThread.join(); + _input->clearReadStop(); + output.clearWriteStop(); + running = false; + } + + void setBlockSize(int blockSize) { + if (running) { + return; + } + _blockSize = blockSize; + output.setMaxLatency(blockSize * 2); + } + + void setSkip(int skip) { + if (running) { + return; + } + _skip = skip; + } + + stream output; + + private: + static void _worker(BlockDecimator* _this) { + complex_t* buf = new complex_t[_this->_blockSize]; + while (true) { + _this->_input->readAndSkip(buf, _this->_blockSize, _this->_skip); + _this->output.write(buf, _this->_blockSize); + } + } + + stream* _input; + int _blockSize; + int _skip; + std::thread _workerThread; + bool running = false; + }; + + class Resampler { + public: + Resampler() { + + } + + void init(stream* in, float inputSampleRate, float outputSampleRate, float bandWidth, int blockSize) { + _input = in; + _outputSampleRate = outputSampleRate; + _inputSampleRate = inputSampleRate; + int _gcd = std::gcd((int)inputSampleRate, (int)outputSampleRate); + _interp = outputSampleRate / _gcd; + _decim = inputSampleRate / _gcd; + _blockSize = blockSize; + output = &decim.output; + + dsp::BlackmanWindow(_taps, inputSampleRate * _interp, outputSampleRate / 2.0f, outputSampleRate / 2.0f); + + interp.init(in, _interp, blockSize); + if (_interp == 1) { + decim.init(in, _taps, blockSize, _decim); + } + else { + decim.init(&interp.output, _taps, blockSize * _interp, _decim); + } + } + + void start() { + if (_interp != 1) { + interp.start(); + } + decim.start(); + running = true; + } + + void stop() { + interp.stop(); + decim.stop(); + running = false; + } + + void setInputSampleRate(float inputSampleRate, int blockSize = -1) { + stop(); + _inputSampleRate = inputSampleRate; + int _gcd = std::gcd((int)inputSampleRate, (int)_outputSampleRate); + _interp = _outputSampleRate / _gcd; + _decim = inputSampleRate / _gcd; + + dsp::BlackmanWindow(_taps, inputSampleRate * _interp, _outputSampleRate / 2.0f, _outputSampleRate / 2.0f); + decim.setTaps(_taps); + + interp.setInterpolation(_interp); + decim.setDecimation(_decim); + if (blockSize > 0) { + _blockSize = blockSize; + interp.setBlockSize(_blockSize); + } + decim.setBlockSize(_blockSize * _interp); + + if (_interp == 1) { + decim.setInput(_input); + } + else { + decim.setInput(&interp.output); + interp.start(); + } + start(); + } + + void setOutputSampleRate(float outputSampleRate) { + stop(); + _outputSampleRate = outputSampleRate; + int _gcd = std::gcd((int)_inputSampleRate, (int)outputSampleRate); + _interp = outputSampleRate / _gcd; + _decim = _inputSampleRate / _gcd; + + dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, outputSampleRate / 2.0f, outputSampleRate / 2.0f); + decim.setTaps(_taps); + + interp.setInterpolation(_interp); + decim.setDecimation(_decim); + decim.setBlockSize(_blockSize * _interp); + + if (_interp == 1) { + decim.setInput(_input); + } + else { + decim.setInput(&interp.output); + } + start(); + } + + void setBlockSize(int blockSize) { + stop(); + _blockSize = blockSize; + interp.setBlockSize(_blockSize); + decim.setBlockSize(_blockSize * _interp); + start(); + } + + void setInput(stream* input) { + if (running) { + return; + } + _input = input; + interp.setInput(_input); + if (_interp == 1) { + decim.setInput(_input); + } + } + + stream* output; + + private: + Interpolator interp; + DecimatingFIRFilter decim; + stream* _input; + + std::vector _taps; + int _interp; + int _decim; + float _outputSampleRate; + float _inputSampleRate; + float _blockSize; + bool running = false; + }; + + + + class FloatResampler { + public: + FloatResampler() { + + } + + void init(stream* in, float inputSampleRate, float outputSampleRate, float bandWidth, int blockSize) { + _input = in; + _outputSampleRate = outputSampleRate; + _inputSampleRate = inputSampleRate; + int _gcd = std::gcd((int)inputSampleRate, (int)outputSampleRate); + _interp = outputSampleRate / _gcd; + _decim = inputSampleRate / _gcd; + _blockSize = blockSize; + output = &decim.output; + + dsp::BlackmanWindow(_taps, inputSampleRate * _interp, outputSampleRate / 2.0f, outputSampleRate / 2.0f); + + interp.init(in, _interp, blockSize); + if (_interp == 1) { + decim.init(in, _taps, blockSize, _decim); + } + else { + decim.init(&interp.output, _taps, blockSize * _interp, _decim); + } + } + + void start() { + if (_interp != 1) { + interp.start(); + } + decim.start(); + running = true; + } + + void stop() { + interp.stop(); + decim.stop(); + running = false; + } + + void setInputSampleRate(float inputSampleRate, int blockSize = -1) { + stop(); + _inputSampleRate = inputSampleRate; + int _gcd = std::gcd((int)inputSampleRate, (int)_outputSampleRate); + _interp = _outputSampleRate / _gcd; + _decim = inputSampleRate / _gcd; + + dsp::BlackmanWindow(_taps, inputSampleRate * _interp, _outputSampleRate / 2.0f, _outputSampleRate / 2.0f); + decim.setTaps(_taps); + + interp.setInterpolation(_interp); + decim.setDecimation(_decim); + if (blockSize > 0) { + _blockSize = blockSize; + interp.setBlockSize(_blockSize); + } + decim.setBlockSize(_blockSize * _interp); + + if (_interp == 1) { + decim.setInput(_input); + } + else { + decim.setInput(&interp.output); + } + start(); + } + + void setOutputSampleRate(float outputSampleRate) { + stop(); + _outputSampleRate = outputSampleRate; + int _gcd = std::gcd((int)_inputSampleRate, (int)outputSampleRate); + _interp = outputSampleRate / _gcd; + _decim = _inputSampleRate / _gcd; + + dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, outputSampleRate / 2.0f, outputSampleRate / 2.0f); + decim.setTaps(_taps); + + interp.setInterpolation(_interp); + decim.setDecimation(_decim); + decim.setBlockSize(_blockSize * _interp); + + if (_interp == 1) { + decim.setInput(_input); + } + else { + decim.setInput(&interp.output); + } + start(); + } + + void setBlockSize(int blockSize) { + stop(); + _blockSize = blockSize; + interp.setBlockSize(_blockSize); + decim.setBlockSize(_blockSize * _interp); + start(); + } + + void setInput(stream* input) { + if (running) { + return; + } + _input = input; + interp.setInput(_input); + if (_interp == 1) { + decim.setInput(_input); + } + } + + stream* output; + + private: + Interpolator interp; + FloatDecimatingFIRFilter decim; + stream* _input; + + std::vector _taps; + int _interp; + int _decim; + float _outputSampleRate; + float _inputSampleRate; + float _blockSize; + bool running = false; + }; + + +}; \ No newline at end of file diff --git a/src/dsp/routing.h b/src/dsp/routing.h new file mode 100644 index 00000000..e1d61f29 --- /dev/null +++ b/src/dsp/routing.h @@ -0,0 +1,49 @@ +#pragma once +#include +#include +#include +#include + +namespace dsp { + class Splitter { + public: + Splitter() { + + } + + Splitter(stream* input, int bufferSize) { + _in = input; + _bufferSize = bufferSize; + output_a.init(bufferSize); + output_b.init(bufferSize); + } + + void init(stream* input, int bufferSize) { + _in = input; + _bufferSize = bufferSize; + output_a.init(bufferSize); + output_b.init(bufferSize); + } + + void start() { + _workerThread = std::thread(_worker, this); + } + + stream output_a; + stream output_b; + + private: + static void _worker(Splitter* _this) { + complex_t* buf = new complex_t[_this->_bufferSize]; + while (true) { + _this->_in->read(buf, _this->_bufferSize); + _this->output_a.write(buf, _this->_bufferSize); + _this->output_b.write(buf, _this->_bufferSize); + } + } + + stream* _in; + int _bufferSize; + std::thread _workerThread; + }; +}; \ No newline at end of file diff --git a/src/dsp/sink.h b/src/dsp/sink.h new file mode 100644 index 00000000..e585a796 --- /dev/null +++ b/src/dsp/sink.h @@ -0,0 +1,118 @@ +#pragma once +#include +#include +#include +#include + +namespace dsp { + class HandlerSink { + public: + HandlerSink() { + + } + + HandlerSink(stream* input, complex_t* buffer, int bufferSize, void handler(complex_t*)) { + _in = input; + _bufferSize = bufferSize; + _buffer = buffer; + _handler = handler; + } + + void init(stream* input, complex_t* buffer, int bufferSize, void handler(complex_t*)) { + _in = input; + _bufferSize = bufferSize; + _buffer = buffer; + _handler = handler; + } + + void start() { + _workerThread = std::thread(_worker, this); + } + + bool bypass; + + private: + static void _worker(HandlerSink* _this) { + while (true) { + _this->_in->read(_this->_buffer, _this->_bufferSize); + _this->_handler(_this->_buffer); + } + } + + stream* _in; + int _bufferSize; + complex_t* _buffer; + std::thread _workerThread; + void (*_handler)(complex_t*); + }; + + class NullSink { + public: + NullSink() { + + } + + NullSink(stream* input, int bufferSize) { + _in = input; + _bufferSize = bufferSize; + } + + void init(stream* input, int bufferSize) { + _in = input; + _bufferSize = bufferSize; + } + + void start() { + _workerThread = std::thread(_worker, this); + } + + bool bypass; + + private: + static void _worker(NullSink* _this) { + complex_t* buf = new complex_t[_this->_bufferSize]; + while (true) { + _this->_in->read(buf, _this->_bufferSize); + } + } + + stream* _in; + int _bufferSize; + std::thread _workerThread; + }; + + class FloatNullSink { + public: + FloatNullSink() { + + } + + FloatNullSink(stream* input, int bufferSize) { + _in = input; + _bufferSize = bufferSize; + } + + void init(stream* input, int bufferSize) { + _in = input; + _bufferSize = bufferSize; + } + + void start() { + _workerThread = std::thread(_worker, this); + } + + bool bypass; + + private: + static void _worker(FloatNullSink* _this) { + float* buf = new float[_this->_bufferSize]; + while (true) { + _this->_in->read(buf, _this->_bufferSize); + } + } + + stream* _in; + int _bufferSize; + std::thread _workerThread; + }; +}; \ No newline at end of file diff --git a/src/dsp/source.h b/src/dsp/source.h new file mode 100644 index 00000000..ac12a5ef --- /dev/null +++ b/src/dsp/source.h @@ -0,0 +1,82 @@ +#pragma once +#include +#include +#include +#include + +namespace dsp { + class SineSource { + public: + SineSource() { + + } + + SineSource(float frequency, long sampleRate, int blockSize) : output(blockSize * 2) { + _blockSize = blockSize; + _sampleRate = sampleRate; + _phasorSpeed = (2 * 3.1415926535) / (sampleRate / frequency); + _phase = 0; + } + + void init(float frequency, long sampleRate, int blockSize) { + output.init(blockSize * 2); + _sampleRate = sampleRate; + _blockSize = blockSize; + _phasorSpeed = (2 * 3.1415926535) / (sampleRate / frequency); + _phase = 0; + } + + void start() { + if (running) { + return; + } + _workerThread = std::thread(_worker, this); + running = true; + } + + void stop() { + if (!running) { + return; + } + output.stopWriter(); + _workerThread.join(); + output.clearWriteStop(); + running = false; + } + + void setFrequency(float frequency) { + _phasorSpeed = (2 * 3.1415926535) / (_sampleRate / frequency); + } + + void setBlockSize(int blockSize) { + if (running) { + return; + } + _blockSize = blockSize; + } + + stream output; + + private: + static void _worker(SineSource* _this) { + complex_t* outBuf = new complex_t[_this->_blockSize]; + while (true) { + for (int i = 0; i < _this->_blockSize; i++) { + _this->_phase += _this->_phasorSpeed; + outBuf[i].i = sin(_this->_phase); + outBuf[i].q = cos(_this->_phase); + } + _this->_phase = fmodf(_this->_phase, 2.0f * 3.1415926535); + if (_this->output.write(outBuf, _this->_blockSize) < 0) { break; }; + } + delete[] outBuf; + } + + int _blockSize; + float _phasorSpeed; + float _phase; + long _sampleRate; + std::thread _workerThread; + bool running = false; + }; +}; \ No newline at end of file diff --git a/src/cdsp/stream.h b/src/dsp/stream.h similarity index 92% rename from src/cdsp/stream.h rename to src/dsp/stream.h index 5b363487..21daf512 100644 --- a/src/cdsp/stream.h +++ b/src/dsp/stream.h @@ -3,7 +3,9 @@ #include #include -namespace cdsp { +#define STREAM_BUF_SZ 1000000 + +namespace dsp { template class stream { public: @@ -11,20 +13,22 @@ namespace cdsp { } - stream(int size) { + stream(int maxLatency) { + size = STREAM_BUF_SZ; _buffer = new T[size]; _stopReader = false; _stopWriter = false; - this->size = size; + this->maxLatency = maxLatency; writec = 0; readc = size - 1; } - void init(int size) { + void init(int maxLatency) { + size = STREAM_BUF_SZ; _buffer = new T[size]; _stopReader = false; _stopWriter = false; - this->size = size; + this->maxLatency = maxLatency; writec = 0; readc = size - 1; } @@ -57,6 +61,7 @@ namespace cdsp { readc_mtx.unlock(); canWriteVar.notify_one(); } + return len; } int readAndSkip(T* data, int len, int skip) { @@ -95,6 +100,7 @@ namespace cdsp { readc_mtx.unlock(); canWriteVar.notify_one(); } + return len; } int waitUntilReadable() { @@ -167,7 +173,7 @@ namespace cdsp { if (_rc < writec) { writeable = (this->size + writeable); } - return writeable - 1; + return std::min(writeable - 1, maxLatency - readable(false) - 1); } void stopReader() { @@ -196,11 +202,16 @@ namespace cdsp { _stopWriter = false; } + void setMaxLatency(int maxLatency) { + this->maxLatency = maxLatency; + } + private: T* _buffer; int size; int readc; int writec; + int maxLatency; bool _stopReader; bool _stopWriter; std::mutex readc_mtx; diff --git a/src/cdsp/types.h b/src/dsp/types.h similarity index 80% rename from src/cdsp/types.h rename to src/dsp/types.h index 0ff92ca8..bc7347f9 100644 --- a/src/cdsp/types.h +++ b/src/dsp/types.h @@ -1,6 +1,6 @@ #pragma once -namespace cdsp { +namespace dsp { struct complex_t { float q; float i; diff --git a/src/dsp/vfo.h b/src/dsp/vfo.h new file mode 100644 index 00000000..9b9c9ef5 --- /dev/null +++ b/src/dsp/vfo.h @@ -0,0 +1,158 @@ +#pragma once +#include +#include +#include +#include + +namespace dsp { + class VFO { + public: + VFO() { + + } + + void init(stream* in, float inputSampleRate, float outputSampleRate, float bandWidth, float offset, int blockSize) { + _input = in; + _outputSampleRate = outputSampleRate; + _inputSampleRate = inputSampleRate; + int _gcd = std::gcd((int)inputSampleRate, (int)outputSampleRate); + _interp = outputSampleRate / _gcd; + _decim = inputSampleRate / _gcd; + _bandWidth = bandWidth; + _blockSize = blockSize; + output = &decim.output; + + dsp::BlackmanWindow(_taps, inputSampleRate * _interp, bandWidth / 2.0f, bandWidth / 2.0f); + + lo.init(offset, inputSampleRate, blockSize); + mixer.init(in, &lo.output, blockSize); + interp.init(&mixer.output, _interp, blockSize); + if (_interp == 1) { + decim.init(&mixer.output, _taps, blockSize, _decim); + } + else { + decim.init(&interp.output, _taps, blockSize * _interp, _decim); + } + } + + void start() { + lo.start(); + mixer.start(); + if (_interp != 1) { + printf("UH OH INTERPOLATOR STARTED :/\n"); + interp.start(); + } + decim.start(); + } + + void stop() { + lo.stop(); + mixer.stop(); + interp.stop(); + decim.stop(); + } + + void setInputSampleRate(float inputSampleRate, int blockSize = -1) { + interp.stop(); + decim.stop(); + + _inputSampleRate = inputSampleRate; + int _gcd = std::gcd((int)inputSampleRate, (int)_outputSampleRate); + _interp = _outputSampleRate / _gcd; + _decim = inputSampleRate / _gcd; + + dsp::BlackmanWindow(_taps, inputSampleRate * _interp, _bandWidth / 2.0f, _bandWidth / 2.0f); + + interp.setInterpolation(_interp); + decim.setDecimation(_decim); + if (blockSize > 0) { + lo.stop(); + mixer.stop(); + _blockSize = blockSize; + lo.setBlockSize(_blockSize); + mixer.setBlockSize(_blockSize); + interp.setBlockSize(_blockSize); + lo.start(); + mixer.start(); + } + decim.setBlockSize(_blockSize * _interp); + + if (_interp == 1) { + decim.setInput(&mixer.output); + } + else { + decim.setInput(&interp.output); + interp.start(); + } + decim.start(); + } + + void setOutputSampleRate(float outputSampleRate, float bandWidth = -1) { + interp.stop(); + decim.stop(); + + if (bandWidth > 0) { + _bandWidth = bandWidth; + } + + _outputSampleRate = outputSampleRate; + int _gcd = std::gcd((int)_inputSampleRate, (int)outputSampleRate); + _interp = outputSampleRate / _gcd; + _decim = _inputSampleRate / _gcd; + + dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, _bandWidth / 2.0f, _bandWidth / 2.0f); + decim.setTaps(_taps); + + interp.setInterpolation(_interp); + decim.setDecimation(_decim); + decim.setBlockSize(_blockSize * _interp); + + if (_interp == 1) { + decim.setInput(&mixer.output); + } + else { + decim.setInput(&interp.output); + interp.start(); + } + decim.start(); + } + + void setBandwidth(float bandWidth) { + decim.stop(); + dsp::BlackmanWindow(_taps, _inputSampleRate * _interp, _bandWidth / 2.0f, _bandWidth / 2.0f); + decim.setTaps(_taps); + decim.start(); + } + + void setOffset(float offset) { + lo.setFrequency(-offset); + } + + void setBlockSize(int blockSize) { + stop(); + _blockSize = blockSize; + lo.setBlockSize(_blockSize); + mixer.setBlockSize(_blockSize); + interp.setBlockSize(_blockSize); + decim.setBlockSize(_blockSize * _interp); + start(); + } + + stream* output; + + private: + SineSource lo; + Multiplier mixer; + Interpolator interp; + DecimatingFIRFilter decim; + stream* _input; + + std::vector _taps; + int _interp; + int _decim; + float _outputSampleRate; + float _inputSampleRate; + float _bandWidth; + float _blockSize; + }; +}; \ No newline at end of file diff --git a/src/cdsp/audio.h b/src/io/audio.h similarity index 90% rename from src/cdsp/audio.h rename to src/io/audio.h index bc82ee1b..25b4c637 100644 --- a/src/cdsp/audio.h +++ b/src/io/audio.h @@ -1,18 +1,18 @@ #pragma once #include -#include -#include +#include +#include #include #include -namespace cdsp { +namespace io { class AudioSink { public: AudioSink() { } - AudioSink(stream* in, int bufferSize) { + AudioSink(dsp::stream* in, int bufferSize) { _bufferSize = bufferSize; _input = in; buffer = new float[_bufferSize * 2]; @@ -20,7 +20,7 @@ namespace cdsp { Pa_Initialize(); } - void init(stream* in, int bufferSize) { + void init(dsp::stream* in, int bufferSize) { _bufferSize = bufferSize; _input = in; buffer = new float[_bufferSize * 2]; @@ -67,7 +67,7 @@ namespace cdsp { } int _bufferSize; - stream* _input; + dsp::stream* _input; float* buffer; float _volume; PaStream *stream; diff --git a/src/io/soapy.h b/src/io/soapy.h new file mode 100644 index 00000000..9e7f6216 --- /dev/null +++ b/src/io/soapy.h @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include + +namespace io { + class SoapyWrapper { + public: + SoapyWrapper() { + output.init(64000); + refresh(); + setDevice(devList[0]); + } + + void start() { + if (running) { + return; + } + dev = SoapySDR::Device::make(args); + _stream = dev->setupStream(SOAPY_SDR_RX, "CF32"); + dev->activateStream(_stream); + running = true; + _workerThread = std::thread(_worker, this); + } + + void stop() { + if (!running) { + return; + } + running = false; + dev->deactivateStream(_stream); + dev->closeStream(_stream); + _workerThread.join(); + SoapySDR::Device::unmake(dev); + } + + void refresh() { + if (running) { + return; + } + + devList = SoapySDR::Device::enumerate(); + txtDevList = ""; + for (int i = 0; i < devList.size(); i++) { + txtDevList += devList[i]["label"]; + txtDevList += '\0'; + } + } + + void setDevice(SoapySDR::Kwargs devArgs) { + if (running) { + return; + } + args = devArgs; + dev = SoapySDR::Device::make(devArgs); + txtSampleRateList = ""; + sampleRates = dev->listSampleRates(SOAPY_SDR_RX, 0); + for (int i = 0; i < sampleRates.size(); i++) { + txtSampleRateList += std::to_string((int)sampleRates[i]); + txtSampleRateList += '\0'; + } + } + + void setSampleRate(float sampleRate) { + if (running) { + return; + } + dev->setSampleRate(SOAPY_SDR_RX, 0, sampleRate); + } + + void setFrequency(float freq) { + dev->setFrequency(SOAPY_SDR_RX, 0, freq); + } + + bool isRunning() { + return running; + } + + SoapySDR::KwargsList devList; + std::string txtDevList; + std::vector sampleRates; + std::string txtSampleRateList; + + dsp::stream output; + + private: + static void _worker(SoapyWrapper* _this) { + dsp::complex_t* buf = new dsp::complex_t[32000]; + int flags = 0; + long long timeMs = 0; + while (_this->running) { + _this->dev->readStream(_this->_stream, (void**)&buf, 32000, flags, timeMs); + _this->output.write(buf, 32000); + } + printf("Read worker terminated\n"); + delete[] buf; + } + + SoapySDR::Kwargs args; + SoapySDR::Device* dev; + SoapySDR::Stream* _stream; + std::thread _workerThread; + bool running = false; + }; +}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index cb876fc8..cd113792 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,7 @@ #include #include + #ifdef _WIN32 #include #endif diff --git a/src/main_window.cpp b/src/main_window.cpp index a7a8190c..7e7f8c6b 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -1,22 +1,20 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include #include #include -#include -#include +#include +#include #include #include #include +#include std::thread worker; std::mutex fft_mtx; ImGui::WaterFall wtf; -hackrf_device* dev; fftwf_complex *fft_in, *fft_out; fftwf_plan p; float* tempData; @@ -25,11 +23,13 @@ int fftSize = 8192 * 8; bool dcbias = true; -cdsp::HackRFSource src; +io::SoapyWrapper soapy; + +//dsp::HackRFSource src; SignalPath sigPath; std::vector _data; std::vector fftTaps; -void fftHandler(cdsp::complex_t* samples) { +void fftHandler(dsp::complex_t* samples) { fftwf_execute(p); int half = fftSize / 2; @@ -61,29 +61,34 @@ void windowInit() { printf("Starting DSP Thread!\n"); - hackrf_init(); - hackrf_device_list_t* list = hackrf_device_list(); + // hackrf_init(); + // hackrf_device_list_t* list = hackrf_device_list(); - int err = hackrf_device_list_open(list, 0, &dev); - if (err != 0) { - printf("Error while opening HackRF: %d\n", err); - return; - } - hackrf_set_freq(dev, 90500000); - //hackrf_set_txvga_gain(dev, 10); - hackrf_set_amp_enable(dev, 1); - hackrf_set_lna_gain(dev, 24); - hackrf_set_vga_gain(dev, 20); - hackrf_set_baseband_filter_bandwidth(dev, sampleRate); - hackrf_set_sample_rate(dev, sampleRate); + // int err = hackrf_device_list_open(list, 0, &dev); + // if (err != 0) { + // printf("Error while opening HackRF: %d\n", err); + // return; + // } + // hackrf_set_freq(dev, 90500000); + // //hackrf_set_txvga_gain(dev, 10); + // hackrf_set_amp_enable(dev, 1); + // hackrf_set_lna_gain(dev, 24); + // hackrf_set_vga_gain(dev, 20); + // hackrf_set_baseband_filter_bandwidth(dev, sampleRate); + // hackrf_set_sample_rate(dev, sampleRate); - src.init(dev, 64000); + //src.init(dev, 64000); - sigPath.init(sampleRate, 20, fftSize, &src.output, (cdsp::complex_t*)fft_in, fftHandler); + sigPath.init(sampleRate, 20, fftSize, &soapy.output, (dsp::complex_t*)fft_in, fftHandler); sigPath.start(); } -int Current = 0; +int devId = 0; +int _devId = -1; + +int srId = 0; +int _srId = -1; + bool showExample = false; int freq = 90500; @@ -102,7 +107,8 @@ void drawWindow() { if (freq != _freq) { _freq = freq; wtf.centerFrequency = freq * 1000; - hackrf_set_freq(dev, freq * 1000); + soapy.setFrequency(freq * 1000); + //hackrf_set_freq(dev, freq * 1000); } if (vfoFreq != lastVfoFreq) { @@ -115,6 +121,15 @@ void drawWindow() { sigPath.setVolume(volume); } + if (devId != _devId) { + _devId = devId; + soapy.setDevice(soapy.devList[devId]); + } + + if (srId != _srId) { + soapy.setSampleRate(soapy.sampleRates[srId]); + } + if (ImGui::BeginMenuBar()) { @@ -148,16 +163,22 @@ void drawWindow() { ImGui::BeginChild("Left Column"); if (ImGui::CollapsingHeader("Source")) { - - //ImGui::Combo("Source", &Current, "HackRF One\0RTL-SDR"); - ImGui::SliderFloat("Volume", &volume, 0.0f, 1.0f); + ImGui::PushItemWidth(ImGui::GetWindowSize().x); + ImGui::Combo("##_0_", &devId, soapy.txtDevList.c_str()); + ImGui::Combo("##_1_", &srId, soapy.txtSampleRateList.c_str()); + + ImGui::SliderFloat("##_2_", &volume, 0.0f, 1.0f, ""); if (ImGui::Button("Start") && !state) { state = true; - src.start(); + soapy.start(); } + ImGui::SameLine(); if (ImGui::Button("Stop") && state) { state = false; - src.stop(); + soapy.stop(); + } + if (ImGui::Button("Refresh")) { + soapy.refresh(); } } diff --git a/src/signal_path.cpp b/src/signal_path.cpp index 747d7b4c..aa933d4e 100644 --- a/src/signal_path.cpp +++ b/src/signal_path.cpp @@ -4,26 +4,17 @@ SignalPath::SignalPath() { } -std::vector iftaps; -std::vector ataps; - -void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, cdsp::stream* input, cdsp::complex_t* fftBuffer, void fftHandler(cdsp::complex_t*)) { +void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream* input, dsp::complex_t* fftBuffer, void fftHandler(dsp::complex_t*)) { this->sampleRate = sampleRate; this->fftRate = fftRate; this->fftSize = fftSize; - BlackmanWindow(iftaps, sampleRate, 100000, 200000); - BlackmanWindow(ataps, 200000, 20000, 10000); - // for (int i = 0; i < iftaps.size(); i++) { // printf("%f\n", iftaps[i]); // } _demod = DEMOD_FM; - printf("%d\n", iftaps.size()); - printf("%d\n", ataps.size()); - dcBiasRemover.init(input, 32000); dcBiasRemover.bypass = true; split.init(&dcBiasRemover.output, 32000); @@ -31,13 +22,15 @@ void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, cdsp::strea fftBlockDec.init(&split.output_a, (sampleRate / fftRate) - fftSize, fftSize); fftHandlerSink.init(&fftBlockDec.output, fftBuffer, fftSize, fftHandler); - mainVFO.init(&split.output_b, 0, sampleRate, 200000, 32000); + mainVFO.init(&split.output_b, sampleRate, 200000, 200000, 0, 32000); demod.init(mainVFO.output, 100000, 200000, 800); - amDemod.init(mainVFO.output, 800); + amDemod.init(mainVFO.output, 50); - audioResamp.init(&demod.output, 200000, 40000, 800, 20000); + audioResamp.init(&demod.output, 200000, 40000, 20000, 800); audio.init(audioResamp.output, 160); + + ns.init(mainVFO.output, 800); } void SignalPath::setVFOFrequency(long frequency) { @@ -69,16 +62,16 @@ void SignalPath::setDemodulator(int demId) { // Set input of the audio resampler if (demId == DEMOD_FM) { printf("Starting FM demodulator\n"); - mainVFO.setBandwidth(200000); + mainVFO.setOutputSampleRate(200000, 200000); audioResamp.setInput(&demod.output); - audioResamp.setInputSampleRate(200000); + audioResamp.setInputSampleRate(200000, 800); demod.start(); } else if (demId == DEMOD_AM) { printf("Starting AM demodulator\n"); - mainVFO.setBandwidth(12000); + mainVFO.setOutputSampleRate(12500, 12500); audioResamp.setInput(&amDemod.output); - audioResamp.setInputSampleRate(12000); + audioResamp.setInputSampleRate(12500, 50); amDemod.start(); } @@ -94,6 +87,7 @@ void SignalPath::start() { mainVFO.start(); demod.start(); + //ns.start(); audioResamp.start(); audio.start(); diff --git a/src/signal_path.h b/src/signal_path.h index aa79e40e..01e77f72 100644 --- a/src/signal_path.h +++ b/src/signal_path.h @@ -1,16 +1,19 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include class SignalPath { public: SignalPath(); - void init(uint64_t sampleRate, int fftRate, int fftSize, cdsp::stream* input, cdsp::complex_t* fftBuffer, void fftHandler(cdsp::complex_t*)); + void init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream* input, dsp::complex_t* fftBuffer, void fftHandler(dsp::complex_t*)); void start(); void setSampleRate(float sampleRate); void setDCBiasCorrection(bool enabled); @@ -28,22 +31,26 @@ public: }; private: - cdsp::DCBiasRemover dcBiasRemover; - cdsp::Splitter split; + dsp::DCBiasRemover dcBiasRemover; + dsp::Splitter split; // FFT - cdsp::BlockDecimator fftBlockDec; - cdsp::HandlerSink fftHandlerSink; + dsp::BlockDecimator fftBlockDec; + dsp::HandlerSink fftHandlerSink; // VFO - VFO mainVFO; + dsp::VFO mainVFO; - cdsp::FMDemodulator demod; - cdsp::AMDemodulator amDemod; + // Demodulators + dsp::FMDemodulator demod; + dsp::AMDemodulator amDemod; - //cdsp::FloatDecimatingFIRFilter audioDecFilt; - cdsp::FractionalResampler audioResamp; - cdsp::AudioSink audio; + // Audio output + dsp::FloatResampler audioResamp; + io::AudioSink audio; + + // DEBUG + dsp::NullSink ns; float sampleRate; float fftRate; diff --git a/src/vfo.cpp b/src/vfo.cpp deleted file mode 100644 index 5611fdcd..00000000 --- a/src/vfo.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include - -VFO::VFO() { - -} - -void VFO::init(cdsp::stream* input, float offset, float inputSampleRate, float bandWidth, int bufferSize) { - _input = input; - outputSampleRate = ceilf(bandWidth / OUTPUT_SR_ROUND) * OUTPUT_SR_ROUND; - _inputSampleRate = inputSampleRate; - int _gcd = std::gcd((int)inputSampleRate, (int)outputSampleRate); - _interp = outputSampleRate / _gcd; - _decim = inputSampleRate / _gcd; - _bandWidth = bandWidth; - _bufferSize = bufferSize; - lo.init(offset, inputSampleRate, bufferSize); - mixer.init(&lo.output, input, bufferSize); - interp.init(&mixer.output, _interp, bufferSize); - - BlackmanWindow(decimTaps, inputSampleRate * _interp, bandWidth / 2.0f, bandWidth / 2.0f); - - if (_interp != 1) { - printf("Interpolation needed\n"); - decFir.init(&interp.output, decimTaps, bufferSize * _interp, _decim); - } - else { - decFir.init(&mixer.output, decimTaps, bufferSize, _decim); - printf("Interpolation NOT needed: %d %d %d\n", bufferSize / _decim, _decim, _interp); - } - - output = &decFir.output; -} - - -void VFO::start() { - lo.start(); - mixer.start(); - if (_interp != 1) { - interp.start(); - } - decFir.start(); -} - -void VFO::stop() { - // TODO: Stop LO - mixer.stop(); - interp.stop(); - decFir.stop(); -} - - -void VFO::setOffset(float freq) { - lo.setFrequency(-freq); -} - -void VFO::setBandwidth(float bandWidth) { - if (bandWidth == _bandWidth) { - return; - } - outputSampleRate = ceilf(bandWidth / OUTPUT_SR_ROUND) * OUTPUT_SR_ROUND; - int _gcd = std::gcd((int)_inputSampleRate, (int)outputSampleRate); - int interpol = outputSampleRate / _gcd; - int decim = _inputSampleRate / _gcd; - _bandWidth = bandWidth; - - BlackmanWindow(decimTaps, _inputSampleRate * _interp, bandWidth / 2, bandWidth); - - decFir.stop(); - decFir.setTaps(decimTaps); - decFir.setDecimation(decim); - - if (interpol != _interp) { - interp.stop(); - if (interpol == 1) { - decFir.setBufferSize(_bufferSize); - decFir.setInput(&mixer.output); - } - else if (_interp == 1) { - decFir.setInput(&interp.output); - decFir.setBufferSize(_bufferSize * _interp); - interp.setInterpolation(interpol); - interp.start(); - } - else { - decFir.setBufferSize(_bufferSize * _interp); - interp.setInterpolation(interpol); - interp.start(); - } - } - - _interp = interpol; - _decim = decim; - - decFir.start(); -} - -void VFO::setSampleRate(int sampleRate) { - -} - -int VFO::getOutputSampleRate() { - return outputSampleRate; -} \ No newline at end of file diff --git a/src/vfo.h b/src/vfo.h deleted file mode 100644 index 9f9c9cd6..00000000 --- a/src/vfo.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once -#include -#include -#include -#include - -// Round up to next 5KHz multiple frequency -#define OUTPUT_SR_ROUND 5000.0f - -class VFO { -public: - VFO(); - void init(cdsp::stream* input, float offset, float sampleRate, float bandWidth, int bufferSize); - - void start(); - void stop(); - - void setOffset(float freq); - void setBandwidth(float bandwidth); - void setSampleRate(int sampleRate); - - int getOutputSampleRate(); - - cdsp::stream* output; - -private: - cdsp::ComplexSineSource lo; - cdsp::Multiplier mixer; - cdsp::IQInterpolator interp; - cdsp::DecimatingFIRFilter decFir; - - std::vector decimTaps; - - int _interp; - int _decim; - float _inputSampleRate; - float _outputSampleRate; - float _bandWidth; - int _bufferSize; - int outputSampleRate; - - cdsp::stream* _input; -}; \ No newline at end of file