new stuff

This commit is contained in:
Ryzerth 2020-06-15 15:53:45 +02:00
parent 7120e848ef
commit fa2f6a0a9b
14 changed files with 1067 additions and 151 deletions

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.9)
project(sdrpp)
# Compiler config
set(CMAKE_CXX_FLAGS "-O2")
set(CMAKE_CXX_FLAGS "-OFast /std:c++17")
# HackRF
include_directories(sdrpp "C:/Program Files/PothosSDR/include/libhackrf/")

View File

@ -3,6 +3,28 @@
#include <cdsp/stream.h>
#include <cdsp/types.h>
#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)
{
float abs_y = fabs(y)+1e-10;
float r, angle;
if (x>=0)
{
r = (x - abs_y) / (x + abs_y);
angle = FAST_ATAN2_COEF1 - FAST_ATAN2_COEF1 * r;
}
else
{
r = (x + abs_y) / (abs_y - x);
angle = FAST_ATAN2_COEF2 - FAST_ATAN2_COEF1 * r;
}
if (y < 0) {
return -angle;
}
return angle;
}
namespace cdsp {
class FMDemodulator {
@ -12,6 +34,7 @@ namespace cdsp {
}
FMDemodulator(stream<complex_t>* in, float deviation, long sampleRate, int bufferSize) : output(bufferSize * 2) {
running = false;
_input = in;
_bufferSize = bufferSize;
_phase = 0.0f;
@ -20,6 +43,7 @@ namespace cdsp {
void init(stream<complex_t>* in, float deviation, long sampleRate, int bufferSize) {
output.init(bufferSize * 2);
running = false;
_input = in;
_bufferSize = bufferSize;
_phase = 0.0f;
@ -27,9 +51,25 @@ namespace cdsp {
}
void start() {
if (running) {
return;
}
running = true;
_workerThread = std::thread(_worker, this);
}
void stop() {
if (!running) {
return;
}
_input->stopReader();
output.stopWriter();
_workerThread.join();
running = false;
_input->clearReadStop();
output.clearWriteStop();
}
stream<float> output;
private:
@ -39,21 +79,98 @@ namespace cdsp {
float diff = 0;
float currentPhase = 0;
while (true) {
_this->_input->read(inBuf, _this->_bufferSize);
if (_this->_input->read(inBuf, _this->_bufferSize) < 0) { return; };
for (int i = 0; i < _this->_bufferSize; i++) {
currentPhase = atan2f(inBuf[i].i, inBuf[i].q);
currentPhase = fast_arctan2(inBuf[i].i, inBuf[i].q);
diff = currentPhase - _this->_phase;
if (diff > 3.1415926535f) { diff -= 2 * 3.1415926535f; }
else if (diff <= -3.1415926535f) { diff += 2 * 3.1415926535f; }
outBuf[i] = diff / _this->_phasorSpeed;
_this->_phase = currentPhase;
}
_this->output.write(outBuf, _this->_bufferSize);
if (_this->output.write(outBuf, _this->_bufferSize) < 0) { return; };
}
}
stream<complex_t>* _input;
bool running;
int _bufferSize;
float _phase;
float _phasorSpeed;
std::thread _workerThread;
};
class AMDemodulator {
public:
AMDemodulator() {
}
AMDemodulator(stream<complex_t>* in, int bufferSize) : output(bufferSize * 2) {
running = false;
_input = in;
_bufferSize = bufferSize;
}
void init(stream<complex_t>* in, int bufferSize) {
output.init(bufferSize * 2);
running = false;
_input = in;
_bufferSize = bufferSize;
}
void start() {
if (running) {
return;
}
running = true;
_workerThread = std::thread(_worker, this);
}
void stop() {
if (!running) {
return;
}
_input->stopReader();
output.stopWriter();
_workerThread.join();
running = false;
_input->clearReadStop();
output.clearWriteStop();
}
stream<float> output;
private:
static void _worker(AMDemodulator* _this) {
complex_t* inBuf = new complex_t[_this->_bufferSize];
float* outBuf = new float[_this->_bufferSize];
float min, max, amp;
while (true) {
if (_this->_input->read(inBuf, _this->_bufferSize) < 0) { return; };
min = INFINITY;
max = 0.0f;
for (int i = 0; i < _this->_bufferSize; i++) {
outBuf[i] = sqrt((inBuf[i].i*inBuf[i].i) + (inBuf[i].q*inBuf[i].q));
if (outBuf[i] < min) {
min = outBuf[i];
}
if (outBuf[i] > max) {
max = outBuf[i];
}
}
amp = (max - min);
for (int i = 0; i < _this->_bufferSize; i++) {
outBuf[i] = (outBuf[i] - min) / (max - min);
}
if (_this->output.write(outBuf, _this->_bufferSize) < 0) { return; };
}
}
stream<complex_t>* _input;
bool running;
int _bufferSize;
std::thread _workerThread;
};
};

View File

@ -4,78 +4,338 @@
#include <cdsp/types.h>
#include <vector>
#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<float>& 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;
}
}
namespace cdsp {
class FIRFilter {
class DecimatingFIRFilter {
public:
FIRFilter() {
DecimatingFIRFilter() {
}
FIRFilter(stream<complex_t>* input, std::vector<float> taps, int bufferSize) : output(bufferSize * 2) {
_in = input;
_bufferSize = bufferSize;
_tapCount = taps.size();
delayBuf = new complex_t[_tapCount];
_taps = taps;
}
void init(stream<complex_t>* input, std::vector<float> taps, int bufferSize) {
DecimatingFIRFilter(stream<complex_t>* input, std::vector<float> taps, int bufferSize, float decim) : output(bufferSize * 2) {
output.init(bufferSize * 2);
_in = input;
_bufferSize = bufferSize;
_tapCount = taps.size();
delayBuf = new complex_t[_tapCount];
_taps = taps;
_taps = new float[_tapCount];
for (int i = 0; i < _tapCount; i++) {
_taps[i] = taps[i];
}
_decim = decim;
for (int i = 0; i < _tapCount; i++) {
delayBuf[i].i = 0.0f;
delayBuf[i].q = 0.0f;
}
running = false;
}
void init(stream<complex_t>* input, std::vector<float>& taps, int bufferSize, float decim) {
output.init(bufferSize * 2);
_in = input;
_bufferSize = bufferSize;
_tapCount = taps.size();
delayBuf = new complex_t[_tapCount];
_taps = new float[_tapCount];
for (int i = 0; i < _tapCount; i++) {
_taps[i] = taps[i];
}
_decim = decim;
for (int i = 0; i < _tapCount; i++) {
delayBuf[i].i = 0.0f;
delayBuf[i].q = 0.0f;
}
running = false;
}
void start() {
if (running) {
return;
}
running = true;
_workerThread = std::thread(_worker, this);
}
void stop() {
if (!running) {
return;
}
_in->stopReader();
output.stopWriter();
_workerThread.join();
_in->clearReadStop();
output.clearWriteStop();
running = false;
}
void setTaps(std::vector<float>& taps) {
if (running) {
return;
}
_tapCount = taps.size();
delete[] _taps;
_taps = new float[_tapCount];
for (int i = 0; i < _tapCount; i++) {
_taps[i] = taps[i];
}
}
void setInput(stream<complex_t>* input) {
if (running) {
return;
}
_in = input;
}
void setDecimation(float decimation) {
if (running) {
return;
}
_decim = decimation;
}
void setBufferSize(int bufferSize) {
if (running) {
return;
}
_bufferSize = bufferSize;
}
stream<complex_t> output;
private:
static void _worker(FIRFilter* _this) {
static void _worker(DecimatingFIRFilter* _this) {
int outputSize = _this->_bufferSize / _this->_decim;
complex_t* inBuf = new complex_t[_this->_bufferSize];
complex_t* outBuf = new complex_t[_this->_bufferSize];
complex_t* outBuf = new complex_t[outputSize];
float tap = 0.0f;
int delayOff;
void* delayStart = &inBuf[_this->_bufferSize - (_this->_tapCount - 1)];
int delaySize = (_this->_tapCount - 1) * sizeof(complex_t);
int bufferSize = _this->_bufferSize;
int outBufferLength = outputSize * sizeof(complex_t);
int tapCount = _this->_tapCount;
int decim = _this->_decim;
complex_t* delayBuf = _this->delayBuf;
int id = 0;
while (true) {
_this->_in->read(inBuf, _this->_bufferSize);
for (int i = _this->_tapCount; i < _this->_bufferSize - _this->_tapCount; i++) {
outBuf[i].i = 0.0f;
outBuf[i].q = 0.0f;
}
for (int t = 0; t < _this->_tapCount; t++) {
if (_this->_in->read(inBuf, bufferSize) < 0) { break; };
memset(outBuf, 0, outBufferLength);
for (int t = 0; t < tapCount; t++) {
tap = _this->_taps[t];
if (tap == 0.0f) {
continue;
}
for (int i = 0; i < t; i++) {
outBuf[i].i += tap * _this->delayBuf[_this->_tapCount - t - 1].i;
outBuf[i].q += tap * _this->delayBuf[_this->_tapCount - t - 1].q;
}
for (int i = t; i < _this->_bufferSize; i++) {
outBuf[i].i += tap * inBuf[i - t].i;
outBuf[i].q += tap * inBuf[i - t].q;
delayOff = tapCount - t;
id = 0;
for (int i = 0; i < bufferSize; i += decim) {
if (i < t) {
outBuf[id].i += tap * delayBuf[delayOff + i].i;
outBuf[id].q += tap * delayBuf[delayOff + i].q;
id++;
continue;
}
outBuf[id].i += tap * inBuf[i - t].i;
outBuf[id].q += tap * inBuf[i - t].q;
id++;
}
}
// for (int i = _this->_tapCount; i < _this->_bufferSize - _this->_tapCount; i++) {
// outBuf[i].i /= (float)_this->_tapCount;
// outBuf[i].q /= (float)_this->_tapCount;
// }
memcpy(_this->delayBuf, &inBuf[_this->_bufferSize - _this->_tapCount], _this->_tapCount * sizeof(complex_t));
_this->output.write(outBuf, _this->_bufferSize);
memcpy(delayBuf, delayStart, delaySize);
if (_this->output.write(outBuf, outputSize) < 0) { break; };
}
delete[] inBuf;
delete[] outBuf;
}
stream<complex_t>* _in;
complex_t* delayBuf;
int _bufferSize;
int _tapCount = 0;
std::vector<float> _taps;
float _decim;
std::thread _workerThread;
float* _taps;
bool running;
};
class FloatDecimatingFIRFilter {
public:
FloatDecimatingFIRFilter() {
}
FloatDecimatingFIRFilter(stream<float>* input, std::vector<float> taps, int bufferSize, float decim) : output(bufferSize * 2) {
output.init(bufferSize * 2);
_in = input;
_bufferSize = bufferSize;
_tapCount = taps.size();
delayBuf = new float[_tapCount];
_taps = new float[_tapCount];
for (int i = 0; i < _tapCount; i++) {
_taps[i] = taps[i];
}
_decim = decim;
for (int i = 0; i < _tapCount; i++) {
delayBuf[i] = 0.0f;
}
running = false;
}
void init(stream<float>* input, std::vector<float>& taps, int bufferSize, float decim) {
output.init(bufferSize * 2);
_in = input;
_bufferSize = bufferSize;
_tapCount = taps.size();
delayBuf = new float[_tapCount];
_taps = new float[_tapCount];
for (int i = 0; i < _tapCount; i++) {
_taps[i] = taps[i];
}
_decim = decim;
for (int i = 0; i < _tapCount; i++) {
delayBuf[i] = 0.0f;
}
running = false;
}
void start() {
running = true;
_workerThread = std::thread(_worker, this);
}
void stop() {
_in->stopReader();
output.stopWriter();
_workerThread.join();
_in->clearReadStop();
output.clearWriteStop();
running = false;
}
void setTaps(std::vector<float>& taps) {
if (running) {
return;
}
_tapCount = taps.size();
delete[] _taps;
_taps = new float[_tapCount];
for (int i = 0; i < _tapCount; i++) {
_taps[i] = taps[i];
}
}
void setInput(stream<float>* input) {
if (running) {
return;
}
_in = input;
}
void setDecimation(float decimation) {
if (running) {
return;
}
_decim = decimation;
}
stream<float> output;
private:
static void _worker(FloatDecimatingFIRFilter* _this) {
int outputSize = _this->_bufferSize / _this->_decim;
float* inBuf = new float[_this->_bufferSize];
float* outBuf = new float[outputSize];
float tap = 0.0f;
int delayOff;
void* delayStart = &inBuf[_this->_bufferSize - (_this->_tapCount - 1)];
int delaySize = (_this->_tapCount - 1) * sizeof(float);
int bufferSize = _this->_bufferSize;
int outBufferLength = outputSize * sizeof(float);
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; };
memset(outBuf, 0, outBufferLength);
for (int t = 0; t < tapCount; t++) {
tap = _this->_taps[t];
if (tap == 0.0f) {
continue;
}
delayOff = tapCount - t;
id = 0;
for (int i = 0; i < bufferSize; i += decim) {
if (i < t) {
outBuf[id] += tap * delayBuf[delayOff + i];
id++;
continue;
}
outBuf[id] += tap * inBuf[i - t];
id++;
}
}
memcpy(delayBuf, delayStart, delaySize);
if (_this->output.write(outBuf, outputSize) < 0) { break; };
}
delete[] inBuf;
delete[] outBuf;
}
stream<float>* _in;
float* delayBuf;
int _bufferSize;
int _tapCount = 0;
float _decim;
std::thread _workerThread;
float* _taps;
bool running;
};
class DCBiasRemover {
public:
@ -173,4 +433,46 @@ namespace cdsp {
std::thread _workerThread;
void (*_handler)(complex_t*);
};
class Splitter {
public:
Splitter() {
}
Splitter(stream<complex_t>* input, int bufferSize) {
_in = input;
_bufferSize = bufferSize;
output_a.init(bufferSize);
output_b.init(bufferSize);
}
void init(stream<complex_t>* input, int bufferSize) {
_in = input;
_bufferSize = bufferSize;
output_a.init(bufferSize);
output_b.init(bufferSize);
}
void start() {
_workerThread = std::thread(_worker, this);
}
stream<complex_t> output_a;
stream<complex_t> 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<complex_t>* _in;
int _bufferSize;
std::thread _workerThread;
};
};

View File

@ -92,19 +92,41 @@ namespace cdsp {
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<complex_t> output;
@ -119,13 +141,16 @@ namespace cdsp {
outBuf[i].q = cos(_this->_phase);
}
_this->_phase = fmodf(_this->_phase, 2.0f * 3.1415926535);
_this->output.write(outBuf, _this->_bufferSize);
if (_this->output.write(outBuf, _this->_bufferSize) < 0) { break; };
}
delete[] outBuf;
}
int _bufferSize;
float _phasorSpeed;
float _phase;
long _sampleRate;
std::thread _workerThread;
bool running;
};
};

View File

@ -2,6 +2,7 @@
#include <thread>
#include <cdsp/stream.h>
#include <cdsp/types.h>
#include <cdsp/fast_math.h>
namespace cdsp {
class Multiplier {
@ -16,10 +17,35 @@ namespace cdsp {
_bufferSize = bufferSize;
}
void init(stream<complex_t>* a, stream<complex_t>* 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<complex_t> output;
private:
@ -28,19 +54,17 @@ namespace cdsp {
complex_t* bBuf = new complex_t[_this->_bufferSize];
complex_t* outBuf = new complex_t[_this->_bufferSize];
while (true) {
_this->_a->read(aBuf, _this->_bufferSize);
_this->_b->read(bBuf, _this->_bufferSize);
for (int i = 0; i < _this->_bufferSize; i++) {
outBuf[i].i = (aBuf[i].q * bBuf[i].i) + (bBuf[i].q * aBuf[i].i); // BC + AD
outBuf[i].q = (aBuf[i].q * bBuf[i].q) - (aBuf[i].i * bBuf[i].i);
}
_this->output.write(outBuf, _this->_bufferSize);
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<complex_t>* _a;
stream<complex_t>* _b;
int _bufferSize;
bool running = false;
std::thread _workerThread;
};
};

View File

@ -7,6 +7,10 @@
namespace cdsp {
class FMModulator {
public:
FMModulator() {
}
FMModulator(stream<float>* in, float deviation, long sampleRate, int bufferSize) : output(bufferSize * 2) {
_input = in;
_bufferSize = bufferSize;
@ -14,6 +18,14 @@ namespace cdsp {
_phasorSpeed = (2 * 3.1415926535) / (sampleRate / deviation);
}
void init(stream<float>* 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);
}

View File

@ -2,20 +2,66 @@
#include <thread>
#include <cdsp/stream.h>
#include <cdsp/types.h>
#include <cdsp/filter.h>
#include <numeric>
namespace cdsp {
class Interpolator {
public:
Interpolator() {
}
Interpolator(stream<float>* in, float interpolation, int bufferSize) : output(bufferSize * 2) {
_input = in;
_interpolation = interpolation;
_bufferSize = bufferSize;
running = false;
}
void init(stream<float>* 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<float>* in) {
if (running) {
return;
}
_input = in;
}
stream<float> output;
private:
@ -23,62 +69,116 @@ namespace cdsp {
float* inBuf = new float[(int)((float)_this->_bufferSize / _this->_interpolation)];
float* outBuf = new float[_this->_bufferSize];
while (true) {
_this->_input->read(inBuf, (int)((float)_this->_bufferSize / _this->_interpolation));
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)];
}
_this->output.write(outBuf, _this->_bufferSize);
if (_this->output.write(outBuf, _this->_bufferSize) < 0) { break; };
}
delete[] inBuf;
delete[] outBuf;
}
stream<float>* _input;
int _bufferSize;
float _interpolation;
std::thread _workerThread;
bool running;
};
class IQInterpolator {
public:
IQInterpolator() {
}
IQInterpolator(stream<complex_t>* in, float interpolation, int bufferSize) : output(bufferSize * 2) {
_input = in;
_interpolation = interpolation;
_bufferSize = bufferSize;
running = false;
}
void init(stream<complex_t>* 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<complex_t> output;
private:
static void _worker(IQInterpolator* _this) {
complex_t* inBuf = new complex_t[(int)((float)_this->_bufferSize / _this->_interpolation)];
complex_t* outBuf = new complex_t[_this->_bufferSize];
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) {
_this->_input->read(inBuf, (int)((float)_this->_bufferSize / _this->_interpolation));
for (int i = 0; i < _this->_bufferSize; i++) {
if (_this->_input->read(inBuf, _this->_bufferSize) < 0) { break; };
for (int i = 0; i < outCount; i++) {
outBuf[i] = inBuf[(int)((float)i / _this->_interpolation)];
}
_this->output.write(outBuf, _this->_bufferSize);
if (_this->output.write(outBuf, _this->_bufferSize) < 0) { break; };
}
delete[] inBuf;
delete[] outBuf;
}
stream<complex_t>* _input;
int _bufferSize;
float _interpolation;
std::thread _workerThread;
bool running;
};
class BlockDecimator {
public:
BlockDecimator() {
}
BlockDecimator(stream<complex_t>* in, int skip, int bufferSize) : output(bufferSize * 2) {
_input = in;
_skip = skip;
_bufferSize = bufferSize;
}
void init(stream<complex_t>* in, int skip, int bufferSize) {
output.init(bufferSize * 2);
_input = in;
_skip = skip;
_bufferSize = bufferSize;
}
void start() {
_workerThread = std::thread(_worker, this);
}
@ -99,4 +199,119 @@ namespace cdsp {
int _skip;
std::thread _workerThread;
};
class FractionalResampler {
public:
FractionalResampler() {
}
void init(stream<float>* input, float inputSampleRate, float outputSampleRate, int bufferSize, float customCutoff = INFINITY) {
_input = input;
float lowestFreq = std::min<float>(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<float>(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<float>(_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<float>* input) {
if (running) {
return;
}
_input = input;
if (_interp != 1) {
interpolator.setInput(input);
decimator.setInput(&interpolator.output);
}
else {
decimator.setInput(input);
}
}
stream<float>* output;
private:
Interpolator interpolator;
FloatDecimatingFIRFilter decimator;
std::vector<float> decimTaps;
stream<float>* _input;
int _interp;
int _decim;
int _bufferSize;
float _inputSampleRate;
float _outputSampleRate;
bool running;
};
};

View File

@ -13,6 +13,8 @@ namespace cdsp {
stream(int size) {
_buffer = new T[size];
_stopReader = false;
_stopWriter = false;
this->size = size;
writec = 0;
readc = size - 1;
@ -20,15 +22,27 @@ namespace cdsp {
void init(int size) {
_buffer = new T[size];
_stopReader = false;
_stopWriter = false;
this->size = size;
writec = 0;
readc = size - 1;
}
void read(T* data, int len) {
int read(T* data, int len) {
int dataRead = 0;
while (dataRead < len) {
int canRead = waitUntilReadable();
if (canRead < 0) {
if (_stopReader) {
printf("Stop reader set");
}
else {
printf("Stop not set");
}
clearReadStop();
return -1;
}
int toRead = std::min(canRead, len - dataRead);
int len1 = (toRead >= (size - readc) ? (size - readc) : (toRead));
@ -45,10 +59,14 @@ namespace cdsp {
}
}
void readAndSkip(T* data, int len, int skip) {
int readAndSkip(T* data, int len, int skip) {
int dataRead = 0;
while (dataRead < len) {
int canRead = waitUntilReadable();
if (canRead < 0) {
clearReadStop();
return -1;
}
int toRead = std::min(canRead, len - dataRead);
int len1 = (toRead >= (size - readc) ? (size - readc) : (toRead));
@ -85,7 +103,10 @@ namespace cdsp {
return canRead;
}
std::unique_lock<std::mutex> lck(writec_mtx);
canReadVar.wait(lck, [=](){ return (this->readable(false) > 0); });
canReadVar.wait(lck, [=](){ return ((this->readable(false) > 0) || this->getReadStop()); });
if (this->getReadStop()) {
return -1;
}
return this->readable(false);
}
@ -100,10 +121,14 @@ namespace cdsp {
return readable - 1;
}
void write(T* data, int len) {
int write(T* data, int len) {
int dataWrite = 0;
while (dataWrite < len) {
int canWrite = waitUntilWriteable();
if (canWrite < 0) {
clearWriteStop();
return -1;
}
int toWrite = std::min(canWrite, len - dataWrite);
int len1 = (toWrite >= (size - writec) ? (size - writec) : (toWrite));
@ -118,6 +143,7 @@ namespace cdsp {
writec_mtx.unlock();
canReadVar.notify_one();
}
return len;
}
int waitUntilWriteable() {
@ -126,7 +152,10 @@ namespace cdsp {
return canWrite;
}
std::unique_lock<std::mutex> lck(readc_mtx);
canWriteVar.wait(lck, [=](){ return (this->writeable(false) > 0); });
canWriteVar.wait(lck, [=](){ return ((this->writeable(false) > 0) || this->getWriteStop()); });
if (this->getWriteStop()) {
return -1;
}
return this->writeable(false);
}
@ -141,11 +170,39 @@ namespace cdsp {
return writeable - 1;
}
void stopReader() {
_stopReader = true;
canReadVar.notify_one();
}
void stopWriter() {
_stopWriter = true;
canWriteVar.notify_one();
}
bool getReadStop() {
return _stopReader;
}
bool getWriteStop() {
return _stopWriter;
}
void clearReadStop() {
_stopReader = false;
}
void clearWriteStop() {
_stopWriter = false;
}
private:
T* _buffer;
int size;
int readc;
int writec;
bool _stopReader;
bool _stopWriter;
std::mutex readc_mtx;
std::mutex writec_mtx;
std::condition_variable canReadVar;

View File

@ -70,7 +70,7 @@ int main() {
glfwGetWindowSize(window, &wwidth, &wheight);
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(ImVec2(wwidth, wheight));
ImGui::Begin("", NULL, WINDOW_FLAGS);
ImGui::Begin("Main", NULL, WINDOW_FLAGS);
drawWindow();

View File

@ -19,75 +19,84 @@ ImGui::WaterFall wtf;
hackrf_device* dev;
fftwf_complex *fft_in, *fft_out;
fftwf_plan p;
float* tempData;
int fftSize = 8192 * 8;
bool dcbias = true;
cdsp::HackRFSource src;
SignalPath sigPath;
std::vector<float> _data;
std::vector<float> fftTaps;
void fftHandler(cdsp::complex_t* samples) {
fftwf_execute(p);
int half = fftSize / 2;
for (int i = 0; i < half; i++) {
_data.push_back(log10(std::abs(std::complex<float>(fft_out[half + i][0], fft_out[half + i][1])) / (float)fftSize) * 10.0f);
}
for (int i = 0; i < half; i++) {
_data.push_back(log10(std::abs(std::complex<float>(fft_out[i][0], fft_out[i][1])) / (float)fftSize) * 10.0f);
}
for (int i = 5; i < fftSize; i++) {
_data[i] = (_data[i - 4] + _data[i - 3] + _data[i - 2] + _data[i - 1] + _data[i]) / 5.0f;
}
wtf.pushFFT(_data, fftSize);
_data.clear();
}
void windowInit() {
int fftSize = 8192;
wtf.bandWidth = 8000000;
int sampleRate = 2000000;
wtf.bandWidth = sampleRate;
wtf.range = 500000;
wtf.centerFrequency = 90500000;
printf("fft taps: %d\n", fftTaps.size());
fft_in = (fftwf_complex*) fftw_malloc(sizeof(fftw_complex) * fftSize);
fft_out = (fftwf_complex*) fftw_malloc(sizeof(fftw_complex) * fftSize);
fft_in = (fftwf_complex*) fftw_malloc(sizeof(fftwf_complex) * fftSize);
fft_out = (fftwf_complex*) fftw_malloc(sizeof(fftwf_complex) * fftSize);
p = fftwf_plan_dft_1d(fftSize, fft_in, fft_out, FFTW_FORWARD, FFTW_ESTIMATE);
worker = std::thread([=]() {
std::vector<float> data;
printf("Starting DSP Thread!\n");
printf("Starting DSP Thread!\n");
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 -1;
}
hackrf_set_freq(dev, 98000000);
//hackrf_set_txvga_gain(dev, 10);
hackrf_set_amp_enable(dev, 0);
hackrf_set_lna_gain(dev, 24);
hackrf_set_vga_gain(dev, 20);
hackrf_set_sample_rate(dev, 8000000);
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);
cdsp::HackRFSource src(dev, 64000);
cdsp::DCBiasRemover bias(&src.output, 64000);
cdsp::ComplexSineSource sinsrc(4000000.0f, 8000000, 64000);
cdsp::BlockDecimator dec(&bias.output, 566603 - fftSize, fftSize);
cdsp::Multiplier mul(&dec.output, &sinsrc.output, fftSize);
src.start();
bias.start();
sinsrc.start();
dec.start();
mul.start();
src.init(dev, 64000);
while (true) {
mul.output.read((cdsp::complex_t*)fft_in, fftSize);
fftwf_execute(p);
for (int i = 0; i < fftSize ; i++) {
data.push_back(log10(std::abs(std::complex<float>(fft_out[i][0], fft_out[i][1])) / (float)fftSize) * 10.0f);
}
for (int i = 5; i < fftSize; i++) {
data[i] = (data[i - 3] + data[i - 2] + data[i - 1] + data[i]) / 4.0f;
}
bias.bypass = !dcbias;
wtf.pushFFT(data, fftSize);
data.clear();
}
});
sigPath.init(sampleRate, 20, fftSize, &src.output, (cdsp::complex_t*)fft_in, fftHandler);
sigPath.start();
}
int Current = 0;
bool showExample = false;
int freq = 98000;
int _freq = 98000;
int freq = 90500;
int _freq = 90500;
bool state = false;
bool mulstate = true;
float vfoFreq = 92000000.0f;
float lastVfoFreq = 92000000.0f;
float volume = 1.0f;
float lastVolume = 1.0f;
void drawWindow() {
if (freq != _freq) {
@ -96,6 +105,16 @@ void drawWindow() {
hackrf_set_freq(dev, freq * 1000);
}
if (vfoFreq != lastVfoFreq) {
lastVfoFreq = vfoFreq;
sigPath.setVFOFrequency(vfoFreq - (freq * 1000));
}
if (volume != lastVolume) {
lastVolume = volume;
sigPath.setVolume(volume);
}
if (ImGui::BeginMenuBar())
{
@ -130,7 +149,16 @@ void drawWindow() {
if (ImGui::CollapsingHeader("Source")) {
ImGui::Combo("Source", &Current, "HackRF One\0RTL-SDR");
//ImGui::Combo("Source", &Current, "HackRF One\0RTL-SDR");
ImGui::SliderFloat("Volume", &volume, 0.0f, 1.0f);
if (ImGui::Button("Start") && !state) {
state = true;
src.start();
}
if (ImGui::Button("Stop") && state) {
state = false;
src.stop();
}
}
if (ImGui::CollapsingHeader("Radio")) {
@ -165,6 +193,13 @@ void drawWindow() {
if(ImGui::CollapsingHeader("Debug")) {
ImGui::Text("Frame time: %.3f ms/frame", 1000.0f / ImGui::GetIO().Framerate);
ImGui::Text("Framerate: %.1f FPS", ImGui::GetIO().Framerate);
if (ImGui::Button("FM demod")) {
sigPath.setDemodulator(SignalPath::DEMOD_FM);
}
if (ImGui::Button("AM demod")) {
sigPath.setDemodulator(SignalPath::DEMOD_AM);
}
}
ImGui::EndChild();
@ -173,6 +208,6 @@ void drawWindow() {
ImGui::NextColumn();
ImGui::BeginChild("Waterfall");
wtf.draw();
wtf.draw(&vfoFreq);
ImGui::EndChild();
}

View File

@ -1,20 +1,100 @@
#include <signal_path.h>
SignalPath::SignalPath(cdsp::stream<cdsp::complex_t>* source, float sampleRate, float fftRate, int fftSize, cdsp::complex_t* fftBuffer, void fftHandler(cdsp::complex_t*)) :
dcBiasRemover(source, 64000),
fftBlockDec(&dcBiasRemover.output, (sampleRate / fftRate) - fftSize, fftSize),
fftSineSource(sampleRate / 2.0f, sampleRate, fftSize),
fftMul(&fftBlockDec.output, &fftSineSource.output, fftSize),
fftHandler(&fftMul.output, fftBuffer, fftSize, fftHandler) {
SignalPath::SignalPath() {
}
std::vector<float> iftaps;
std::vector<float> ataps;
void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, cdsp::stream<cdsp::complex_t>* input, cdsp::complex_t* fftBuffer, void fftHandler(cdsp::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);
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);
demod.init(mainVFO.output, 100000, 200000, 800);
amDemod.init(mainVFO.output, 800);
audioResamp.init(&demod.output, 200000, 40000, 800, 20000);
audio.init(audioResamp.output, 160);
}
void SignalPath::setVFOFrequency(long frequency) {
mainVFO.setOffset(frequency);
}
void SignalPath::setVolume(float volume) {
audio.setVolume(volume);
}
void SignalPath::setDemodulator(int demId) {
if (demId < 0 || demId >= _DEMOD_COUNT) {
return;
}
audioResamp.stop();
// Stop current demodulator
if (_demod == DEMOD_FM) {
printf("Stopping FM demodulator\n");
demod.stop();
}
else if (_demod == DEMOD_AM) {
printf("Stopping AM demodulator\n");
amDemod.stop();
}
_demod = demId;
// Set input of the audio resampler
if (demId == DEMOD_FM) {
printf("Starting FM demodulator\n");
mainVFO.setBandwidth(200000);
audioResamp.setInput(&demod.output);
audioResamp.setInputSampleRate(200000);
demod.start();
}
else if (demId == DEMOD_AM) {
printf("Starting AM demodulator\n");
mainVFO.setBandwidth(12000);
audioResamp.setInput(&amDemod.output);
audioResamp.setInputSampleRate(12000);
amDemod.start();
}
audioResamp.start();
}
void SignalPath::start() {
dcBiasRemover.start();
split.start();
fftBlockDec.start();
fftSineSource.start();
fftMul.start();
fftHandler.start();
fftHandlerSink.start();
mainVFO.start();
demod.start();
audioResamp.start();
audio.start();
}

View File

@ -3,24 +3,50 @@
#include <cdsp/resampling.h>
#include <cdsp/generator.h>
#include <cdsp/math.h>
#include <cdsp/demodulation.h>
#include <cdsp/audio.h>
#include <vfo.h>
class SignalPath {
public:
SignalPath();
SignalPath(cdsp::stream<cdsp::complex_t>* source, float sampleRate, float fftRate, int fftSize, cdsp::complex_t* fftBuffer, void fftHandler(cdsp::complex_t*));
void init(uint64_t sampleRate, int fftRate, int fftSize, cdsp::stream<cdsp::complex_t>* input, cdsp::complex_t* fftBuffer, void fftHandler(cdsp::complex_t*));
void start();
void setSampleRate(float sampleRate);
void setDCBiasCorrection(bool enabled);
void setFFTRate(float rate);
void setVFOFrequency(long frequency);
void setVolume(float volume);
void setDemodulator(int demod);
enum {
DEMOD_FM,
DEMOD_AM,
_DEMOD_COUNT
};
private:
cdsp::DCBiasRemover dcBiasRemover;
cdsp::Splitter split;
// FFT
cdsp::BlockDecimator fftBlockDec;
cdsp::ComplexSineSource fftSineSource;
cdsp::Multiplier fftMul;
cdsp::HandlerSink fftHandler;
cdsp::HandlerSink fftHandlerSink;
// VFO
VFO mainVFO;
cdsp::FMDemodulator demod;
cdsp::AMDemodulator amDemod;
//cdsp::FloatDecimatingFIRFilter audioDecFilt;
cdsp::FractionalResampler audioResamp;
cdsp::AudioSink audio;
float sampleRate;
float fftRate;
int fftSize;
int _demod;
};

View File

@ -19,7 +19,17 @@ const float COLOR_MAP[][3] = {
{0x00, 0x00, 0x20}
};
bool isInArea(ImVec2 pos, ImVec2 min, ImVec2 max) {
return (pos.x >= min.x && pos.y >= min.y && pos.x < max.x && pos.y < max.y);
}
namespace ImGui {
uint32_t* img = NULL;
int lastW = 0;
int lastH = 0;
WaterFall::WaterFall() {
std::vector<float> base;
for (int i = 0; i < 1024; i++) {
@ -30,17 +40,19 @@ namespace ImGui {
glGenTextures(1, &textureId);
}
void WaterFall::drawFFT(ImGuiWindow* window, int width, int height, ImVec2 pos) {
float lineHeight = (float)(height - 20 - 30) / 7.0f;
void WaterFall::drawFFT(ImGuiWindow* window, int width, int height, ImVec2 pos, float* vfo) {
float lines = 6.0f;
int w = width - 10;
float lineHeight = (float)(height - 20 - 30) / lines;
char buf[100];
int fftWidth = width - 50;
// Vertical scale
for (int i = 0; i < 8; i++) {
for (int i = 0; i < (lines + 1); i++) {
sprintf(buf, "%d", -i * 10);
ImVec2 txtSz = ImGui::CalcTextSize(buf);
window->DrawList->AddText(ImVec2(pos.x + 30 - txtSz.x, pos.y + (i * lineHeight) + 2), IM_COL32( 255, 255, 255, 255 ), buf);
if (i == 7) {
if (i == lines) { // Last line
window->DrawList->AddLine(ImVec2(pos.x + 40, pos.y + (i * lineHeight) + 10),
ImVec2(pos.x + width - 10, pos.y + (i * lineHeight) + 10),
IM_COL32( 255, 255, 255, 255 ), 1.0f);
@ -60,24 +72,30 @@ namespace ImGui {
int count = 0;
for (; start < end; start += range) {
window->DrawList->AddLine(ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40, pos.y + 10),
ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40, pos.y + (7 * lineHeight) + 10),
ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40, pos.y + (lines * lineHeight) + 10),
IM_COL32( 70, 70, 70, 255 ), 1.0f);
window->DrawList->AddLine(ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40, pos.y + (7 * lineHeight) + 10),
ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40, pos.y + (7 * lineHeight) + 20),
window->DrawList->AddLine(ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40, pos.y + (lines * lineHeight) + 10),
ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40, pos.y + (lines * lineHeight) + 20),
IM_COL32( 255, 255, 255, 255 ), 1.0f);
sprintf(buf, "%.1fM", start / 1000000.0f);
ImVec2 txtSz = ImGui::CalcTextSize(buf);
window->DrawList->AddText(ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40 - (txtSz.x / 2.0f), pos.y + (7 * lineHeight) + 25), IM_COL32( 255, 255, 255, 255 ), buf);
window->DrawList->AddText(ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40 - (txtSz.x / 2.0f), pos.y + (lines * lineHeight) + 25), IM_COL32( 255, 255, 255, 255 ), buf);
count++;
}
int dataCount = fftBuffer[0].size();
float multiplier = (float)dataCount / (float)fftWidth;
if (lastW != w) {
if (fftDrawBuffer != NULL) {
delete[] fftDrawBuffer;
}
fftDrawBuffer = new float[fftWidth];
}
for (int i = 1; i < fftWidth; i++) {
float a = (fftBuffer[0][(int)((float)(i - 1) * multiplier)] / 10.0f) * lineHeight;
float b = (fftBuffer[0][(int)((float)i * multiplier)] / 10.0f) * lineHeight;
@ -86,7 +104,7 @@ namespace ImGui {
IM_COL32( 0, 255, 255, 255 ), 1.0f);
window->DrawList->AddLine(ImVec2(pos.x + i + 39, pos.y - a),
ImVec2(pos.x + i + 39, pos.y + (7.0f * lineHeight) + 9),
ImVec2(pos.x + i + 39, pos.y + (lines * lineHeight) + 9),
IM_COL32( 0, 255, 255, 50 ), 1.0f);
}
@ -94,17 +112,24 @@ namespace ImGui {
// ImVec2(pos.x + (i * spacing) + 40, pos.y - b),
// IM_COL32( 0, 255, 255, 255 ), 1.0f);
window->DrawList->AddLine(ImVec2(pos.x + 40, pos.y + 10), ImVec2(pos.x + 40, pos.y + (7 * lineHeight) + 10), IM_COL32( 255, 255, 255, 255 ), 1.0f);
window->DrawList->AddLine(ImVec2(pos.x + 40, pos.y + 10), ImVec2(pos.x + 40, pos.y + (lines * lineHeight) + 10), IM_COL32( 255, 255, 255, 255 ), 1.0f);
ImVec2 mPos = ImGui::GetMousePos();
window->DrawList->AddRectFilled(ImVec2(mPos.x - 20, pos.y + 1), ImVec2(mPos.x + 20, pos.y + (7 * lineHeight) + 10), IM_COL32( 255, 255, 255, 50 ));
window->DrawList->AddLine(ImVec2(mPos.x, pos.y + 1), ImVec2(mPos.x, pos.y + (7 * lineHeight) + 10), IM_COL32( 255, 0, 0, 255 ), 1.0f);
// window->DrawList->AddRectFilled(ImVec2(mPos.x - 20, pos.y + 11), ImVec2(mPos.x + 20, pos.y + (lines * lineHeight) + 10), IM_COL32( 255, 255, 255, 50 ));
// window->DrawList->AddLine(ImVec2(mPos.x, pos.y + 11), ImVec2(mPos.x, pos.y + (lines * lineHeight) + 10), IM_COL32( 255, 0, 0, 255 ), 1.0f);
float vfoPos = (((*vfo - centerFrequency) + (bandWidth / 2.0f)) / bandWidth) * (float)fftWidth + 40;
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && isInArea(mPos, ImVec2(pos.x + 40, pos.y + 10), ImVec2(pos.x + fftWidth + 40, pos.y + (lines * lineHeight) + 10))) {
*vfo = (((((mPos.x - pos.x) - 40) / (float)fftWidth) * bandWidth) - (bandWidth / 2.0f)) + centerFrequency;
//*vfo = roundf(*vfo / 100000.0f) * 100000.0f;
}
window->DrawList->AddRectFilled(ImVec2(pos.x + vfoPos - 20, pos.y + 11), ImVec2(pos.x + vfoPos + 20, pos.y + (lines * lineHeight) + 10), IM_COL32( 255, 255, 255, 50 ));
window->DrawList->AddLine(ImVec2(pos.x + vfoPos, pos.y + 11), ImVec2(pos.x + vfoPos, pos.y + (lines * lineHeight) + 10), IM_COL32( 255, 0, 0, 255 ), 1.0f);
}
uint32_t mapColor(float val) {
float mapped = MAP_VAL(-50.0f, 0.0f, 0, 12, val);
float mapped = MAP_VAL(-50.0f, -15.0f, 0, 12, val);
mapped = std::max<float>(mapped, 0.0f);
mapped = std::min<float>(mapped, 12.0f);
int floored = floorf(mapped);
@ -119,10 +144,6 @@ namespace ImGui {
return ((uint32_t)255 << 24) | ((uint32_t)b << 16) | ((uint32_t)g << 8) | (uint32_t)r;
}
uint32_t* img = NULL;
int lastW = 0;
int lastH = 0;
void WaterFall::drawWaterfall(ImGuiWindow* window, int width, int height, ImVec2 pos) {
int w = width - 10;
int h = height;
@ -131,6 +152,7 @@ namespace ImGui {
bool newSize = false;
if (lastW != w || lastH != h) {
newSize = true;
lastW = w;
lastH = h;
@ -175,7 +197,7 @@ namespace ImGui {
window->DrawList->AddImage((void*)(intptr_t)textureId, ImVec2(pos.x + 40, pos.y), ImVec2(pos.x + w, pos.y + h));
}
void WaterFall::draw() {
void WaterFall::draw(float* vfo) {
ImGuiWindow* window = GetCurrentWindow();
ImVec2 vMin = ImGui::GetWindowContentRegionMin();
ImVec2 vMax = ImGui::GetWindowContentRegionMax();
@ -190,10 +212,10 @@ namespace ImGui {
window->DrawList->AddLine(ImVec2(vMin.x, vMin.y + 300), ImVec2(vMin.x + width, vMin.y + 300), IM_COL32( 50, 50, 50, 255 ), 1.0f);
buf_mtx.lock();
if (fftBuffer.size() > height - 302) {
if (fftBuffer.size() > height) {
fftBuffer.resize(height - 302);
}
drawFFT(window, width, 300, vMin);
drawFFT(window, width, 300, vMin, vfo);
drawWaterfall(window, width - 2, height - 302, ImVec2(vMin.x + 1, vMin.y + 301));
buf_mtx.unlock();
}
@ -202,6 +224,7 @@ namespace ImGui {
buf_mtx.lock();
fftBuffer.insert(fftBuffer.begin(), data);
newSamples = true;
fftDrawBuffer = NULL;
buf_mtx.unlock();
}
};

View File

@ -10,7 +10,7 @@ namespace ImGui {
public:
WaterFall();
void draw();
void draw(float* vfo);
void pushFFT(std::vector<float> data, int n);
float centerFrequency;
@ -19,14 +19,14 @@ namespace ImGui {
private:
void drawWaterfall(ImGuiWindow* window, int width, int height, ImVec2 pos);
void drawFFT(ImGuiWindow* window, int width, int height, ImVec2 pos);
void drawFFT(ImGuiWindow* window, int width, int height, ImVec2 pos, float* vfo);
std::vector<std::vector<float>> fftBuffer;
bool newSamples;
std::mutex buf_mtx;
GLuint textureId;
uint8_t* pixelBuffer;
float* fftDrawBuffer;
};
};