#pragma once #include #include #include #include #include #include #define GET_FROM_RIGHT_BUF(buffer, delayLine, delayLineSz, n) (((n) < 0) ? delayLine[(delayLineSz) + (n)] : buffer[(n)]) namespace dsp { inline void BlackmanWindow(std::vector& taps, float sampleRate, float cutoff, float transWidth, int addedTaps = 0) { taps.clear(); float fc = cutoff / sampleRate; if (fc > 1.0f) { fc = 1.0f; } int _M = (4.0f / (transWidth / sampleRate)) + (float)addedTaps; if (_M < 4) { _M = 4; } if (_M % 2 == 0) { _M++; } float M = _M; float sum = 0.0f; float val; for (int i = 0; i < _M; i++) { 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; } } class DecimatingFIRFilter { public: DecimatingFIRFilter() { } DecimatingFIRFilter(stream* input, std::vector taps, int blockSize, float decim) { output.init((blockSize * 2) / decim); _in = input; _blockSize = blockSize; _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 init(stream* input, std::vector& taps, int blockSize, float decim) { output.init((blockSize * 2) / decim); _in = input; _blockSize = blockSize; _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& taps) { if (running) { return; } _tapCount = taps.size(); delete[] _taps; delete[] delayBuf; _taps = new float[_tapCount]; delayBuf = new complex_t[_tapCount]; for (int i = 0; i < _tapCount; i++) { _taps[i] = taps[i]; delayBuf[i].i = 0; delayBuf[i].q = 0; } } void setInput(stream* input) { if (running) { return; } _in = input; } void setDecimation(float decimation) { if (running) { return; } _decim = decimation; output.setMaxLatency((_blockSize * 2) / _decim); } void setBlockSize(int blockSize) { if (running) { return; } _blockSize = blockSize; output.setMaxLatency(getOutputBlockSize() * 2); } int getOutputBlockSize() { return _blockSize / _decim; } stream output; private: static void _worker(DecimatingFIRFilter* _this) { 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->_blockSize - (_this->_tapCount - 1)]; int delaySize = (_this->_tapCount - 1) * sizeof(complex_t); int blockSize = _this->_blockSize; int outBufferLength = outputSize * sizeof(complex_t); int tapCount = _this->_tapCount; int decim = _this->_decim; complex_t* delayBuf = _this->delayBuf; int id = 0; while (true) { if (_this->_in->read(inBuf, blockSize) < 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 < blockSize; i += decim) { if (i < t) { outBuf[id].i += tap * delayBuf[delayOff + i].i; outBuf[id].q += tap * delayBuf[delayOff + i].q; } else { outBuf[id].i += tap * inBuf[i - t].i; outBuf[id].q += tap * inBuf[i - t].q; } id++; } } memcpy(delayBuf, delayStart, delaySize); if (_this->output.write(outBuf, outputSize) < 0) { break; }; } delete[] inBuf; delete[] outBuf; } stream* _in; complex_t* delayBuf; int _blockSize; int _tapCount = 0; float _decim; std::thread _workerThread; float* _taps; bool running; }; class FloatDecimatingFIRFilter { public: FloatDecimatingFIRFilter() { } FloatDecimatingFIRFilter(stream* input, std::vector taps, int blockSize, float decim) { output.init((blockSize * 2) / decim); _in = input; _blockSize = blockSize; _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* input, std::vector& taps, int blockSize, float decim) { output.init((blockSize * 2) / decim); _in = input; _blockSize = blockSize; _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() { 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& taps) { if (running) { return; } _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]; delayBuf[i] = 0; } } void setInput(stream* input) { if (running) { return; } _in = input; } void setDecimation(float decimation) { if (running) { return; } _decim = decimation; output.setMaxLatency((_blockSize * 2) / _decim); } void setBlockSize(int blockSize) { if (running) { return; } _blockSize = blockSize; output.setMaxLatency((_blockSize * 2) / _decim); } int getOutputBlockSize() { return _blockSize / _decim; } stream output; private: static void _worker(FloatDecimatingFIRFilter* _this) { 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->_blockSize - (_this->_tapCount - 1)]; int delaySize = (_this->_tapCount - 1) * sizeof(float); int blockSize = _this->_blockSize; 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, blockSize) < 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 < blockSize; 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* _in; float* delayBuf; int _blockSize; int _tapCount = 0; float _decim; std::thread _workerThread; float* _taps; bool running; }; class FMDeemphasis { public: FMDeemphasis() { } FMDeemphasis(stream* input, int bufferSize, float tau, float sampleRate) : output(bufferSize * 2) { _in = input; _bufferSize = bufferSize; bypass = false; _tau = tau; _sampleRate = sampleRate; } void init(stream* input, int bufferSize, float tau, float sampleRate) { output.init(bufferSize * 2); _in = input; _bufferSize = bufferSize; bypass = false; _tau = tau; _sampleRate = sampleRate; } void start() { if (running) { return; } _workerThread = std::thread(_worker, this); running = true; } void stop() { if (!running) { return; } _in->stopReader(); output.stopWriter(); _workerThread.join(); _in->clearReadStop(); output.clearWriteStop(); running = false; } void setBlockSize(int blockSize) { if (running) { return; } _bufferSize = blockSize; output.setMaxLatency(blockSize * 2); } void setSamplerate(float sampleRate) { if (running) { return; } _sampleRate = sampleRate; } void setTau(float tau) { if (running) { return; } _tau = tau; } stream output; bool bypass; private: static void _worker(FMDeemphasis* _this) { float* inBuf = new float[_this->_bufferSize]; float* outBuf = new float[_this->_bufferSize]; int count = _this->_bufferSize; float lastOut = 0.0f; float dt = 1.0f / _this->_sampleRate; float alpha = dt / (_this->_tau + dt); while (true) { if (_this->_in->read(inBuf, count) < 0) { break; }; if (_this->bypass) { if (_this->output.write(inBuf, count) < 0) { break; }; continue; } if (isnan(lastOut)) { lastOut = 0.0f; } outBuf[0] = (alpha * inBuf[0]) + ((1-alpha) * lastOut); for (int i = 1; i < count; i++) { outBuf[i] = (alpha * inBuf[i]) + ((1 - alpha) * outBuf[i - 1]); } lastOut = outBuf[count - 1]; if (_this->output.write(outBuf, count) < 0) { break; }; } delete[] inBuf; delete[] outBuf; } stream* _in; int _bufferSize; std::thread _workerThread; bool running = false; float _sampleRate; float _tau; }; };