initial commit

This commit is contained in:
Ryzerth
2020-06-10 04:13:56 +02:00
commit 8e1c6e9da6
36 changed files with 41895 additions and 0 deletions

47
src/cdsp/demodulation.h Normal file
View File

@@ -0,0 +1,47 @@
#pragma once
#include <thread>
#include <cdsp/stream.h>
#include <cdsp/types.h>
namespace cdsp {
class FMDemodulator {
public:
FMDemodulator(stream<complex_t>* in, float deviation, long sampleRate, int bufferSize) : output(bufferSize * 2) {
_input = in;
_bufferSize = bufferSize;
_phase = 0.0f;
_phasorSpeed = (2 * 3.1415926535) / (sampleRate / deviation);
}
void start() {
_workerThread = std::thread(_worker, this);
}
stream<float> output;
private:
static void _worker(FMDemodulator* _this) {
complex_t* inBuf = new complex_t[_this->_bufferSize];
float* outBuf = new float[_this->_bufferSize];
float diff = 0;
float currentPhase = 0;
while (true) {
_this->_input->read(inBuf, _this->_bufferSize);
for (int i = 0; i < _this->_bufferSize; i++) {
currentPhase = atan2f(inBuf[i].i, inBuf[i].q);
diff = currentPhase - _this->_phase;
outBuf[i] = diff / _this->_phasorSpeed;
_this->_phase = currentPhase;
}
_this->output.write(outBuf, _this->_bufferSize);
}
}
stream<complex_t>* _input;
int _bufferSize;
float _phase;
float _phasorSpeed;
std::thread _workerThread;
};
};

127
src/cdsp/fft_math.h Normal file
View File

@@ -0,0 +1,127 @@
#pragma once
// Code by: Stellaris
#include <cmath>
#include <complex>
#include <cassert>
#include <cdsp/types.h>
#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();

84
src/cdsp/file.h Normal file
View File

@@ -0,0 +1,84 @@
#pragma once
#include <thread>
#include <cdsp/stream.h>
#include <cdsp/types.h>
#include <fstream>
namespace cdsp {
#pragma pack(push, 1)
struct audio_sample_t {
int16_t l;
int16_t r;
};
#pragma pack(pop)
class RawFileSource {
public:
RawFileSource(std::string path, int bufferSize) : output(bufferSize * 2) {
_bufferSize = bufferSize;
_file = std::ifstream(path.c_str(), std::ios::in | std::ios::binary);
}
void start() {
_workerThread = std::thread(_worker, this);
}
stream<float> 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(std::string path, stream<float>* 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<float>* _input;
std::thread _workerThread;
};
};

105
src/cdsp/filter.h Normal file
View File

@@ -0,0 +1,105 @@
#pragma once
#include <thread>
#include <cdsp/stream.h>
#include <cdsp/types.h>
#include <vector>
namespace cdsp {
class FIRFilter {
public:
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 start() {
_workerThread = std::thread(_worker, this);
}
stream<complex_t> output;
private:
static void _worker(FIRFilter* _this) {
complex_t* inBuf = new complex_t[_this->_bufferSize];
complex_t* outBuf = new complex_t[_this->_bufferSize];
float tap = 0.0f;
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++) {
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;
}
}
// 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);
}
}
stream<complex_t>* _in;
complex_t* delayBuf;
int _bufferSize;
int _tapCount = 0;
std::vector<float> _taps;
std::thread _workerThread;
};
class DCBiasRemover {
public:
DCBiasRemover(stream<complex_t>* input, int bufferSize) : output(bufferSize * 2) {
_in = input;
_bufferSize = bufferSize;
}
void start() {
_workerThread = std::thread(_worker, this);
}
stream<complex_t> output;
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);
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<complex_t>* _in;
int _bufferSize;
std::thread _workerThread;
};
};

100
src/cdsp/generator.h Normal file
View File

@@ -0,0 +1,100 @@
#pragma once
#include <thread>
#include <cdsp/stream.h>
#include <cdsp/types.h>
namespace cdsp {
class SineSource {
public:
SineSource(float frequency, long sampleRate, int bufferSize) : output(bufferSize * 2) {
_bufferSize = bufferSize;
_phasorSpeed = (2 * 3.1415926535) / (sampleRate / frequency);
_phase = 0;
}
void start() {
_workerThread = std::thread(_worker, this);
}
stream<float> 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(float frequency, long sampleRate, int bufferSize) : output(bufferSize * 2) {
_bufferSize = bufferSize;
}
void start() {
_workerThread = std::thread(_worker, this);
}
stream<float> 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(float frequency, long sampleRate, int bufferSize) : output(bufferSize * 2) {
_bufferSize = bufferSize;
_phasorSpeed = (2 * 3.1415926535) / (sampleRate / frequency);
_phase = 0;
}
void start() {
_workerThread = std::thread(_worker, this);
}
stream<complex_t> 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);
_this->output.write(outBuf, _this->_bufferSize);
}
}
int _bufferSize;
float _phasorSpeed;
float _phase;
std::thread _workerThread;
};
};

152
src/cdsp/hackrf.h Normal file
View File

@@ -0,0 +1,152 @@
#pragma once
#include <thread>
#include <cdsp/stream.h>
#include <cdsp/types.h>
#include <fstream>
#include <hackrf.h>
#include <Windows.h>
namespace cdsp {
#pragma pack(push, 1)
struct hackrf_sample_t {
int8_t q;
int8_t i;
};
#pragma pack(pop)
class Complex2HackRF {
public:
Complex2HackRF(stream<complex_t>* in, int bufferSize) : output(bufferSize * 2) {
_input = in;
_bufferSize = bufferSize;
}
stream<hackrf_sample_t> 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<complex_t>* _input;
std::thread _workerThread;
};
class HackRF2Complex {
public:
HackRF2Complex(stream<complex_t>* out, int bufferSize) : input(bufferSize * 2) {
_output = out;
_bufferSize = bufferSize;
}
void start() {
_workerThread = std::thread(_worker, this);
}
stream<hackrf_sample_t> 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<complex_t>* _output;
std::thread _workerThread;
};
class HackRFSink {
public:
HackRFSink(hackrf_device* dev, int bufferSize, stream<complex_t>* input) : gen(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<complex_t>* _input;
hackrf_device* _dev;
};
class HackRFSource {
public:
HackRFSource(hackrf_device* dev, int bufferSize) : output(bufferSize * 2), gen(&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<complex_t> 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;
};
};

42
src/cdsp/math.h Normal file
View File

@@ -0,0 +1,42 @@
#pragma once
#include <thread>
#include <cdsp/stream.h>
#include <cdsp/types.h>
namespace cdsp {
class Multiplier {
public:
Multiplier(stream<complex_t>* a, stream<complex_t>* b, int bufferSize) : output(bufferSize * 2) {
_a = a;
_b = b;
_bufferSize = bufferSize;
}
void start() {
_workerThread = std::thread(_worker, this);
}
stream<complex_t> 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) {
_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);
}
}
stream<complex_t>* _a;
stream<complex_t>* _b;
int _bufferSize;
std::thread _workerThread;
};
};

45
src/cdsp/modulation.h Normal file
View File

@@ -0,0 +1,45 @@
#pragma once
#include <thread>
#include <cdsp/stream.h>
#include <cdsp/types.h>
#include <cmath>
namespace cdsp {
class FMModulator {
public:
FMModulator(stream<float>* in, float deviation, long sampleRate, int bufferSize) : output(bufferSize * 2) {
_input = in;
_bufferSize = bufferSize;
_phase = 0.0f;
_phasorSpeed = (2 * 3.1415926535) / (sampleRate / deviation);
}
void start() {
_workerThread = std::thread(_worker, this);
}
stream<complex_t> 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<float>* _input;
int _bufferSize;
float _phase;
float _phasorSpeed;
std::thread _workerThread;
};
};

102
src/cdsp/resampling.h Normal file
View File

@@ -0,0 +1,102 @@
#pragma once
#include <thread>
#include <cdsp/stream.h>
#include <cdsp/types.h>
namespace cdsp {
class Interpolator {
public:
Interpolator(stream<float>* in, float interpolation, int bufferSize) : output(bufferSize * 2) {
_input = in;
_interpolation = interpolation;
_bufferSize = bufferSize;
}
void start() {
_workerThread = std::thread(_worker, this);
}
stream<float> 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) {
_this->_input->read(inBuf, (int)((float)_this->_bufferSize / _this->_interpolation));
for (int i = 0; i < _this->_bufferSize; i++) {
outBuf[i] = inBuf[(int)((float)i / _this->_interpolation)];
}
_this->output.write(outBuf, _this->_bufferSize);
}
}
stream<float>* _input;
int _bufferSize;
float _interpolation;
std::thread _workerThread;
};
class IQInterpolator {
public:
IQInterpolator(stream<complex_t>* in, float interpolation, int bufferSize) : output(bufferSize * 2) {
_input = in;
_interpolation = interpolation;
_bufferSize = bufferSize;
}
void start() {
_workerThread = std::thread(_worker, this);
}
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];
while (true) {
_this->_input->read(inBuf, (int)((float)_this->_bufferSize / _this->_interpolation));
for (int i = 0; i < _this->_bufferSize; i++) {
outBuf[i] = inBuf[(int)((float)i / _this->_interpolation)];
}
_this->output.write(outBuf, _this->_bufferSize);
}
}
stream<complex_t>* _input;
int _bufferSize;
float _interpolation;
std::thread _workerThread;
};
class BlockDecimator {
public:
BlockDecimator(stream<complex_t>* in, int skip, int bufferSize) : output(bufferSize * 2) {
_input = in;
_skip = skip;
_bufferSize = bufferSize;
}
void start() {
_workerThread = std::thread(_worker, this);
}
stream<complex_t> 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<complex_t>* _input;
int _bufferSize;
int _skip;
std::thread _workerThread;
};
};

144
src/cdsp/stream.h Normal file
View File

@@ -0,0 +1,144 @@
#pragma once
#include <condition_variable>
#include <algorithm>
#include <math.h>
namespace cdsp {
template <class T>
class stream {
public:
stream(int size) {
_buffer = new T[size];
this->size = size;
writec = 0;
readc = size - 1;
//printf("Stream init\n");
}
void read(T* data, int len) {
int dataRead = 0;
while (dataRead < len) {
int canRead = waitUntilReadable();
int toRead = std::min(canRead, len - dataRead);
int len1 = (toRead >= (size - readc) ? (size - readc) : (toRead));
memcpy(&data[dataRead], &_buffer[readc], len1 * sizeof(T));
if (len1 < toRead) {
memcpy(&data[dataRead + len1], _buffer, (toRead - len1) * sizeof(T));
}
dataRead += toRead;
readc_mtx.lock();
readc = (readc + toRead) % size;
readc_mtx.unlock();
canWriteVar.notify_one();
}
}
void readAndSkip(T* data, int len, int skip) {
int dataRead = 0;
while (dataRead < len) {
int canRead = waitUntilReadable();
int toRead = std::min(canRead, len - dataRead);
int len1 = (toRead >= (size - readc) ? (size - readc) : (toRead));
memcpy(&data[dataRead], &_buffer[readc], len1 * sizeof(T));
if (len1 < toRead) {
memcpy(&data[dataRead + len1], _buffer, (toRead - len1) * sizeof(T));
}
dataRead += toRead;
readc_mtx.lock();
readc = (readc + toRead) % size;
readc_mtx.unlock();
canWriteVar.notify_one();
}
// Skip
dataRead = 0;
while (dataRead < skip) {
int canRead = waitUntilReadable();
int toRead = std::min(canRead, skip - dataRead);
dataRead += toRead;
readc_mtx.lock();
readc = (readc + toRead) % size;
readc_mtx.unlock();
canWriteVar.notify_one();
}
}
int waitUntilReadable() {
int canRead = readable();
if (canRead > 0) {
return canRead;
}
std::unique_lock<std::mutex> lck(writec_mtx);
canReadVar.wait(lck, [=](){ return (this->readable(false) > 0); });
return this->readable(false);
}
int readable(bool lock = true) {
if (lock) { writec_mtx.lock(); }
int _wc = writec;
if (lock) { writec_mtx.unlock(); }
int readable = (_wc - readc) % this->size;
if (_wc < readc) {
readable = (this->size + readable);
}
return readable - 1;
}
void write(T* data, int len) {
int dataWrite = 0;
while (dataWrite < len) {
int canWrite = waitUntilWriteable();
int toWrite = std::min(canWrite, len - dataWrite);
int len1 = (toWrite >= (size - writec) ? (size - writec) : (toWrite));
memcpy(&_buffer[writec], &data[dataWrite], len1 * sizeof(T));
if (len1 < toWrite) {
memcpy(_buffer, &data[dataWrite + len1], (toWrite - len1) * sizeof(T));
}
dataWrite += toWrite;
writec_mtx.lock();
writec = (writec + toWrite) % size;
writec_mtx.unlock();
canReadVar.notify_one();
}
}
int waitUntilWriteable() {
int canWrite = writeable();
if (canWrite > 0) {
return canWrite;
}
std::unique_lock<std::mutex> lck(readc_mtx);
canWriteVar.wait(lck, [=](){ return (this->writeable(false) > 0); });
return this->writeable(false);
}
int writeable(bool lock = true) {
if (lock) { readc_mtx.lock(); }
int _rc = readc;
if (lock) { readc_mtx.unlock(); }
int writeable = (_rc - writec) % this->size;
if (_rc < writec) {
writeable = (this->size + writeable);
}
return writeable - 1;
}
private:
T* _buffer;
int size;
int readc;
int writec;
std::mutex readc_mtx;
std::mutex writec_mtx;
std::condition_variable canReadVar;
std::condition_variable canWriteVar;
};
};

8
src/cdsp/types.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
namespace cdsp {
struct complex_t {
float q;
float i;
};
};