mirror of
https://github.com/AlexandreRouma/dsp2.git
synced 2026-04-18 06:52:42 +00:00
progress
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.vscode/
|
||||
build/
|
||||
.old/
|
||||
.old/
|
||||
unfinished/
|
||||
@@ -9,7 +9,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE "/")
|
||||
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE /std:c++20)
|
||||
|
||||
|
||||
if (MSVC)
|
||||
# Lib path
|
||||
target_link_directories(${PROJECT_NAME} PUBLIC "C:/Program Files/PothosSDR/lib/")
|
||||
|
||||
112
dsp/block.cpp
112
dsp/block.cpp
@@ -1,112 +0,0 @@
|
||||
#include "block.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace dsp {
|
||||
Block::Block() {}
|
||||
|
||||
Block::~Block() {
|
||||
// Stop the worker
|
||||
stop();
|
||||
}
|
||||
|
||||
void Block::start() {
|
||||
// Acquire worker variables
|
||||
std::lock_guard<std::mutex> lck(workerMtx);
|
||||
|
||||
// Do nothing if the block is already running
|
||||
if (_running) { return; }
|
||||
|
||||
// Mark as running
|
||||
_running = true;
|
||||
|
||||
// Start the worker thread
|
||||
workerThread = std::thread(&Block::worker, this);
|
||||
}
|
||||
|
||||
void Block::stop() {
|
||||
// Acquire worker variables
|
||||
std::lock_guard<std::mutex> lck(workerMtx);
|
||||
|
||||
// Do nothing if the block is not running
|
||||
if (!_running) { return; }
|
||||
|
||||
// Set the receive stop flag on all input streams
|
||||
for (const auto& input : inputs) {
|
||||
input->stopReceiver();
|
||||
}
|
||||
|
||||
// Set the send stop flag on all output streams
|
||||
for (const auto& output : outputs) {
|
||||
output->stopSender();
|
||||
}
|
||||
|
||||
// Wait for the thread to exist
|
||||
if (workerThread.joinable()) { workerThread.join(); }
|
||||
|
||||
// Clear the receive stop flag on all input streams
|
||||
for (const auto& input : inputs) {
|
||||
input->clearRecvStop();
|
||||
}
|
||||
|
||||
// Clear the send stop flag on all output streams
|
||||
for (const auto& output : outputs) {
|
||||
output->clearSendStop();
|
||||
}
|
||||
|
||||
// Mark as not running
|
||||
_running = false;
|
||||
}
|
||||
|
||||
bool Block::running() const {
|
||||
// Acquire worker variables
|
||||
std::lock_guard<std::mutex> lck(workerMtx);
|
||||
|
||||
// Return run state
|
||||
return _running;
|
||||
}
|
||||
|
||||
void Block::registerInput(StopNotifier* input) {
|
||||
// Acquire worker variables
|
||||
std::lock_guard<std::mutex> lck(workerMtx);
|
||||
|
||||
// Save to the input list
|
||||
inputs.push_back(input);
|
||||
}
|
||||
|
||||
void Block::unregisterInput(StopNotifier* input) {
|
||||
// Acquire worker variables
|
||||
std::lock_guard<std::mutex> lck(workerMtx);
|
||||
|
||||
// Find the notifier
|
||||
auto it = std::find(inputs.begin(), inputs.end(), input);
|
||||
if (it == inputs.end()) { return; }
|
||||
|
||||
// Remove it from the list
|
||||
inputs.erase(it);
|
||||
}
|
||||
|
||||
void Block::registerOutput(StopNotifier* output) {
|
||||
// Acquire worker variables
|
||||
std::lock_guard<std::mutex> lck(workerMtx);
|
||||
|
||||
// Save to the output list
|
||||
outputs.push_back(output);
|
||||
}
|
||||
|
||||
void Block::unregisterOutput(StopNotifier* output) {
|
||||
// Acquire worker variables
|
||||
std::lock_guard<std::mutex> lck(workerMtx);
|
||||
|
||||
// Find the notifier
|
||||
auto it = std::find(outputs.begin(), outputs.end(), output);
|
||||
if (it == outputs.end()) { return; }
|
||||
|
||||
// Remove it from the list
|
||||
inputs.erase(it);
|
||||
}
|
||||
|
||||
void Block::worker() {
|
||||
// Call the run function repeatedly
|
||||
while (run());
|
||||
}
|
||||
}
|
||||
107
dsp/block.h
107
dsp/block.h
@@ -1,107 +0,0 @@
|
||||
#pragma once
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace dsp {
|
||||
/**
|
||||
* Interface to be used by any blocking class (stream, mailbox, etc...) to allow cancelling an operation.
|
||||
*/
|
||||
class StopNotifier {
|
||||
public:
|
||||
/**
|
||||
* Notify the sending thread that it should stop.
|
||||
*/
|
||||
virtual void stopSender() = 0;
|
||||
|
||||
/**
|
||||
* Clear the sender stop flag to allow restarting the sender thread.
|
||||
*/
|
||||
virtual void clearSendStop() = 0;
|
||||
|
||||
/**
|
||||
* Notify the receiving thread that it should stop.
|
||||
*/
|
||||
virtual void stopReceiver() = 0;
|
||||
|
||||
/**
|
||||
* Clear the receiver stop flag to allow restarting the sender thread.
|
||||
*/
|
||||
virtual void clearRecvStop() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* General DSP block class handling the worker thread start/stop operations.
|
||||
* All input and output stop notifiers (usually streams) of the derived blocks must be registered using the appropriate functions.
|
||||
* This class is thread-safe.
|
||||
*/
|
||||
class Block {
|
||||
public:
|
||||
// Default constructor
|
||||
Block();
|
||||
|
||||
// Destructor
|
||||
virtual ~Block();
|
||||
|
||||
/**
|
||||
* Start the block's worker thread.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Stop the block's worker thread.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Check wether or not the block's worker thread is running.
|
||||
*/
|
||||
bool running() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Register an input stop notifier.
|
||||
* @param input Input stop notifier to register.
|
||||
*/
|
||||
void registerInput(StopNotifier* input);
|
||||
|
||||
/**
|
||||
* Unregister an input stop notifier.
|
||||
* @param input Input stop notifier to unregister.
|
||||
*/
|
||||
void unregisterInput(StopNotifier* input);
|
||||
|
||||
/**
|
||||
* Register an output stop notifier.
|
||||
* @param input Output stop notifier to register.
|
||||
*/
|
||||
void registerOutput(StopNotifier* output);
|
||||
|
||||
/**
|
||||
* Unregister an output stop notifier.
|
||||
* @param input Output stop notifier to unregister.
|
||||
*/
|
||||
void unregisterOutput(StopNotifier* output);
|
||||
|
||||
// TODO: Pause/Resume for when inputs/outputs change to avoid needing to restart a thread
|
||||
|
||||
/**
|
||||
* Run the DSP code.
|
||||
* @return False if the worker thread should stop. True otherwise.
|
||||
*/
|
||||
virtual bool run() = 0;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Worker thread function.
|
||||
*/
|
||||
void worker();
|
||||
|
||||
// Worker variables
|
||||
mutable std::mutex workerMtx;
|
||||
std::thread workerThread;
|
||||
std::vector<StopNotifier*> inputs;
|
||||
std::vector<StopNotifier*> outputs;
|
||||
bool _running = false;
|
||||
};
|
||||
}
|
||||
@@ -25,10 +25,10 @@ namespace dsp {
|
||||
template <class T>
|
||||
Buffer<T>::Buffer(const Buffer<T>& b) {
|
||||
// Allocate buffer
|
||||
realloc(b.count);
|
||||
realloc(b.capacity);
|
||||
|
||||
// Copy data over
|
||||
memcpy(buffer, b.buffer, b.count * sizeof(T));
|
||||
memcpy(buffer, b.buffer, b.capacity * sizeof(T));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -55,6 +55,9 @@ namespace dsp {
|
||||
|
||||
// Copy over the data
|
||||
memcpy(buffer, b.buffer, capacity * sizeof(T));
|
||||
|
||||
// Return self
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -69,22 +72,26 @@ namespace dsp {
|
||||
// Neutralize the original
|
||||
b.buffer = NULL;
|
||||
b.capacity = 0;
|
||||
|
||||
// Return self
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Buffer<T>::realloc(size_t size, ReallocBehavior behavior) {
|
||||
// Select the desired behavior
|
||||
T* newbuf;
|
||||
switch (behavior) {
|
||||
case REALLOC_DISCARD:
|
||||
// Free the current buffer
|
||||
volk_free(buffer);
|
||||
|
||||
// Allocate a new buffer
|
||||
buffer = volk_malloc(size * sizeof(T));
|
||||
buffer = (T*)volk_malloc(size * sizeof(T), volk_get_alignment());
|
||||
break;
|
||||
case REALLOC_KEEP:
|
||||
// Allocate a new buffer
|
||||
T* newbuf = volk_malloc(size * sizeof(T));
|
||||
newbuf = (T*)volk_malloc(size * sizeof(T), volk_get_alignment());
|
||||
|
||||
// Copy the existing data
|
||||
memcpy(newbuf, buffer, std::min<size_t>(capacity, size));
|
||||
@@ -97,13 +104,15 @@ namespace dsp {
|
||||
volk_free(buffer);
|
||||
|
||||
// Allocate a new buffer
|
||||
buffer = volk_malloc(size * sizeof(T));
|
||||
buffer = (T*)volk_malloc(size * sizeof(T), volk_get_alignment());
|
||||
|
||||
// Zero-out the new buffer
|
||||
memset(buffer, 0, size);
|
||||
break;
|
||||
case REALLOC_KEEP_AND_ZERO:
|
||||
|
||||
// TODO
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the current capacity
|
||||
|
||||
@@ -55,6 +55,8 @@ namespace dsp {
|
||||
re = b;
|
||||
}
|
||||
|
||||
// TODO: Define in-place operators
|
||||
|
||||
/**
|
||||
* Real component.
|
||||
*/
|
||||
|
||||
5
dsp/constants.h
Normal file
5
dsp/constants.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include <math.h>
|
||||
|
||||
#define DSP_PI ((float)3.141592653589793)
|
||||
#define DSP_SQRT2 ((float)1.414213562373095)
|
||||
@@ -1,94 +0,0 @@
|
||||
#include "fm.h"
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
namespace dsp::demod {
|
||||
FM_s::FM_s() {}
|
||||
|
||||
FM_s::FM_s(float deviation, float samplerate) {
|
||||
// Save the settings
|
||||
this->deviation = deviation;
|
||||
this->samplerate = samplerate;
|
||||
|
||||
// Update the normalization factor
|
||||
normFact = samplerate / (2.0f * M_PI * deviation);
|
||||
}
|
||||
|
||||
float FM_s::getDeviation() const {
|
||||
// Acquire the settings mutex
|
||||
std::lock_guard<std::recursive_mutex> lck(settingsMtx);
|
||||
|
||||
// Return the deviation
|
||||
return deviation;
|
||||
}
|
||||
|
||||
void FM_s::setDeviation(float deviation) {
|
||||
// Acquire the settings mutex
|
||||
std::lock_guard<std::recursive_mutex> lck(settingsMtx);
|
||||
|
||||
// Update the deviation
|
||||
this->deviation = deviation;
|
||||
|
||||
// Update the normalization factor
|
||||
normFact = samplerate / (2.0f * M_PI * deviation);
|
||||
}
|
||||
|
||||
float FM_s::getSamplerate() const {
|
||||
// Acquire the settings mutex
|
||||
std::lock_guard<std::recursive_mutex> lck(settingsMtx);
|
||||
|
||||
// Return the samplerate
|
||||
return samplerate;
|
||||
}
|
||||
|
||||
void FM_s::setSamplerate(float samplerate) {
|
||||
// Acquire the settings mutex
|
||||
std::lock_guard<std::recursive_mutex> lck(settingsMtx);
|
||||
|
||||
// Update the samplerate
|
||||
this->samplerate = samplerate;
|
||||
|
||||
// Update the normalization factor
|
||||
normFact = samplerate / (2.0f * M_PI * deviation);
|
||||
}
|
||||
|
||||
void FM_s::reset() {
|
||||
// Acquire the settings mutex
|
||||
std::lock_guard<std::recursive_mutex> lck(settingsMtx);
|
||||
|
||||
// Set the current phase to zero
|
||||
phase = 0.0f;
|
||||
}
|
||||
|
||||
int FM_s::process(const Complex* in, float* out, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
// Get the current phase
|
||||
float cphase = in[i].phase();
|
||||
|
||||
// Compute the difference with the last phase
|
||||
// TODO
|
||||
//out[i] = math::normalizePhase(cphase - phase) * normFact;
|
||||
|
||||
// Save the current phase for the next iteration
|
||||
phase = cphase;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
FM::FM() {}
|
||||
|
||||
FM::FM(float deviation, float samplerate) :
|
||||
FM_s(deviation, samplerate),
|
||||
ProcessorAsync(this)
|
||||
{}
|
||||
|
||||
FM::FM(Stream<Complex>* in, float deviation, float samplerate) :
|
||||
FM_s(deviation, samplerate),
|
||||
ProcessorAsync(this, in)
|
||||
{}
|
||||
|
||||
FM::FM(Stream<Complex>* in, Stream<float>* out, float deviation, float samplerate) :
|
||||
FM_s(deviation, samplerate),
|
||||
ProcessorAsync(this, in, out)
|
||||
{}
|
||||
}
|
||||
100
dsp/demod/fm.h
100
dsp/demod/fm.h
@@ -1,100 +0,0 @@
|
||||
#pragma once
|
||||
#include "../processor.h"
|
||||
#include "../complex.h"
|
||||
|
||||
namespace dsp::demod {
|
||||
/**
|
||||
* FM demodulator (Synchronous).
|
||||
* This class is thread-safe except for `process()`.
|
||||
*/
|
||||
class FM_s : public ProcessorSync<Complex, float> {
|
||||
public:
|
||||
// Default constructor
|
||||
FM_s();
|
||||
|
||||
/**
|
||||
* Create an FM demodulator.
|
||||
* @param deviation Deviation of the FM signal in Hz.
|
||||
* @param samplerate Samplerate of the signal in Hz.
|
||||
*/
|
||||
FM_s(float deviation, float samplerate);
|
||||
|
||||
/**
|
||||
* Get the deviation.
|
||||
* @return Deviation of the FM signal in Hz.
|
||||
*/
|
||||
float getDeviation() const;
|
||||
|
||||
/**
|
||||
* Set the deviation.
|
||||
* @param deviation Deviation of the FM signal in Hz.
|
||||
*/
|
||||
void setDeviation(float deviation);
|
||||
|
||||
/**
|
||||
* Get the samplerate.
|
||||
* @return Samplerate of the signal in Hz.
|
||||
*/
|
||||
float getSamplerate() const;
|
||||
|
||||
/**
|
||||
* Set the samplerate.
|
||||
* @param deviation Samplerate of the signal in Hz.
|
||||
*/
|
||||
void setSamplerate(float samplerate);
|
||||
|
||||
/**
|
||||
* Reset the state of the demodulator.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Demodulate a FM-modulated signal. A lock must be acquired using `getLock()` prior to invoking if settings could be set from another thread.
|
||||
* @param in Modulated signal buffer.
|
||||
* @param out Demodulated signal buffer.
|
||||
* @param count Number of samples in the input buffer.
|
||||
* @return Number of samples in the output buffer. Will always be equal to the number of samples in the input buffer.
|
||||
*/
|
||||
int process(const Complex* in, float* out, int count);
|
||||
|
||||
private:
|
||||
float deviation = 0.0f;
|
||||
float samplerate = 0.0f;
|
||||
float normFact = 1.0f;
|
||||
float phase = 0.0f;
|
||||
};
|
||||
|
||||
/**
|
||||
* FM demodulator.
|
||||
* This class is thread-safe.
|
||||
*/
|
||||
class FM : public FM_s, public ProcessorAsync<Complex, float> {
|
||||
public:
|
||||
// Default constructor
|
||||
FM();
|
||||
|
||||
/**
|
||||
* Create an FM demodulator.
|
||||
* @param deviation Deviation of the FM signal in Hz.
|
||||
* @param samplerate Samplerate of the signal in Hz.
|
||||
*/
|
||||
FM(float deviation, float samplerate);
|
||||
|
||||
/**
|
||||
* Create an FM demodulator.
|
||||
* @param in Modulated signal stream.
|
||||
* @param deviation Deviation of the FM signal in Hz.
|
||||
* @param samplerate Samplerate of the signal in Hz.
|
||||
*/
|
||||
FM(Stream<Complex>* in, float deviation, float samplerate);
|
||||
|
||||
/**
|
||||
* Create an FM demodulator.
|
||||
* @param in Modulated signal stream.
|
||||
* @param out Demodulated signal stream.
|
||||
* @param deviation Deviation of the FM signal in Hz.
|
||||
* @param samplerate Samplerate of the signal in Hz.
|
||||
*/
|
||||
FM(Stream<Complex>* in, Stream<float>* out, float deviation, float samplerate);
|
||||
};
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
#pragma once
|
||||
#include "../processor.h"
|
||||
#include "../taps.h"
|
||||
|
||||
namespace dsp::filter {
|
||||
/**
|
||||
* Finite Inpulse Response filter (Synchronous).
|
||||
* This class is thread-safe except for `process()`.
|
||||
*/
|
||||
template <class SAMP_T, class TAPS_T>
|
||||
class FIR_s : public ProcessorSync<SAMP_T, SAMP_T> {
|
||||
public:
|
||||
/**
|
||||
* Create a FIR filter.
|
||||
* @param taps Filter taps.
|
||||
*/
|
||||
FIR_s(const Taps<TAPS_T>& taps);
|
||||
|
||||
/**
|
||||
* Get the filter taps.
|
||||
* @return Filter taps.
|
||||
*/
|
||||
Taps<TAPS_T> getTaps();
|
||||
|
||||
/**
|
||||
* Set the filter taps.
|
||||
* @param taps Filter taps.
|
||||
*/
|
||||
void setTaps(const Taps<TAPS_T>& taps);
|
||||
|
||||
/**
|
||||
* Reset the state of the filter.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Filter samples.
|
||||
* @param in Input sample buffer.
|
||||
* @param out Filtered sample buffer.
|
||||
* @param count Number of samples in the input buffer.
|
||||
* @return Number of samples in the output buffer. Will always be equal to the number of samples in the input buffer.
|
||||
*/
|
||||
int process(const SAMP_T* in, SAMP_T* out, int count);
|
||||
|
||||
private:
|
||||
Taps<TAPS_T> taps;
|
||||
};
|
||||
|
||||
/**
|
||||
* Finite Inpulse Response filter.
|
||||
* This class is thread-safe except for `process()`.
|
||||
*/
|
||||
template <class SAMP_T, class TAPS_T>
|
||||
class FIR : public FIR_s<SAMP_T, TAPS_T>, public ProcessorAsync<SAMP_T, SAMP_T> {
|
||||
public:
|
||||
/**
|
||||
* Create a FIR filter.
|
||||
* @param taps Filter taps.
|
||||
*/
|
||||
FIR(const Taps<TAPS_T>& taps);
|
||||
|
||||
/**
|
||||
* Create a FIR filter.
|
||||
* @param in Input samples.
|
||||
* @param taps Filter taps.
|
||||
*/
|
||||
FIR(Stream<SAMP_T>* in, const Taps<TAPS_T>& taps);
|
||||
|
||||
/**
|
||||
* Create a FIR filter.
|
||||
* @param in Input samples.
|
||||
* @param in Filtered samples.
|
||||
* @param taps Filter taps.
|
||||
*/
|
||||
FIR(Stream<SAMP_T>* in, Stream<SAMP_T>* out, const Taps<TAPS_T>& taps);
|
||||
};
|
||||
}
|
||||
164
dsp/processor.h
164
dsp/processor.h
@@ -1,164 +0,0 @@
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include "block.h"
|
||||
#include "stream.h"
|
||||
|
||||
namespace dsp {
|
||||
// TODO: Deal with the fact that always locking will be slow in hier blocks...
|
||||
|
||||
/**
|
||||
* Class representing a DSP kernel taking one input and one output.
|
||||
* Dervied classes must be thread-safe by locking the provided `settingsMtx` mutex in any function changing settings.
|
||||
*/
|
||||
template <class IN, class OUT>
|
||||
class ProcessorKernel {
|
||||
public:
|
||||
// Destructor
|
||||
virtual ~ProcessorKernel() {}
|
||||
|
||||
// TODO: Copy/Move Constructor/Operator
|
||||
|
||||
/**
|
||||
* Acquire a lock to the settings of the kernel. Mandatory if settings are changed in a different thread than the processing function.
|
||||
* @return Lock to the settings of the block.
|
||||
*/
|
||||
inline std::lock_guard<std::recursive_mutex> getLock() const {
|
||||
return std::lock_guard<std::recursive_mutex>(settingsMtx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process samples. This function is NOT thread-safe.
|
||||
* @param in Input buffer.
|
||||
* @param out Output buffer.
|
||||
* @param count Number of samples in the input buffer.
|
||||
* @return Number of samples in the output buffer.
|
||||
*/
|
||||
virtual int process(const IN* in, OUT* out, int count) = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Mutex to be used for kernel settings.
|
||||
*/
|
||||
mutable std::recursive_mutex settingsMtx;
|
||||
};
|
||||
|
||||
template <class IN, class OUT>
|
||||
class ProcessorBlock : public Block {
|
||||
public:
|
||||
// Default constructor
|
||||
ProcessorBlock() {
|
||||
// TODO: Maybe something to do to prevent bad shit if started?
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
ProcessorBlock(ProcessorSync<IN, OUT>* proc) {
|
||||
// Save the pointer to the processor
|
||||
this->proc = proc;
|
||||
|
||||
// Set the streams
|
||||
setInput(NULL);
|
||||
setOutput(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
ProcessorBlock(ProcessorSync<IN, OUT>* proc, Stream<IN>* in) {
|
||||
// Save the pointer to the processor
|
||||
this->proc = proc;
|
||||
|
||||
// Set the streams
|
||||
setInput(in);
|
||||
setOutput(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
ProcessorBlock(ProcessorSync<IN, OUT>* proc, Stream<IN>* in, Stream<OUT>* out) {
|
||||
// Save the pointer to the processor
|
||||
this->proc = proc;
|
||||
|
||||
// Set the streams
|
||||
setInput(in);
|
||||
setOutput(out);
|
||||
}
|
||||
|
||||
// Destructor
|
||||
virtual ~ProcessorBlock() {}
|
||||
|
||||
/**
|
||||
* Set the input stream.
|
||||
* @param in Input stream.
|
||||
*/
|
||||
void setInput(Stream<IN>* in) {
|
||||
// TODO: Lock
|
||||
|
||||
// If the current input if it already was registered
|
||||
unregisterInput(_in);
|
||||
|
||||
// TODO: Manage allocating and freeing streams
|
||||
|
||||
// Update the input
|
||||
_in = in;
|
||||
|
||||
// Register the new input
|
||||
registerInput(_in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output stream.
|
||||
* @param in Output stream.
|
||||
*/
|
||||
void setOutput(Stream<OUT>* out) {
|
||||
// TODO: Lock
|
||||
|
||||
// If the current output if it already was registered
|
||||
unregisterOutput(_out);
|
||||
|
||||
// TODO: Manage allocating and freeing streams
|
||||
|
||||
// Update the output
|
||||
_out = out;
|
||||
|
||||
// Register the new output
|
||||
registerOutput(_out);
|
||||
}
|
||||
|
||||
Stream<IN>* in() const {
|
||||
// TODO: Lock
|
||||
return _in;
|
||||
}
|
||||
|
||||
Stream<OUT>* out() const {
|
||||
// TODO: Lock
|
||||
return _out;
|
||||
}
|
||||
|
||||
private:
|
||||
bool run() {
|
||||
// Read samples
|
||||
auto bufSet = _in->recv();
|
||||
if (!bufSet.samples) { return true; }
|
||||
|
||||
// Process samples
|
||||
{
|
||||
auto lck = proc->getLock();
|
||||
proc->process(NULL/*TODO*/, NULL/*TODO*/, 0/*TODO*/);
|
||||
}
|
||||
|
||||
// TODO: Write samples
|
||||
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
ProcessorKernel<IN, OUT>* proc;
|
||||
Stream<IN>* _in = NULL;
|
||||
Stream<OUT>* _out = NULL;
|
||||
bool ownInput = false;
|
||||
bool ownOutput = false;
|
||||
};
|
||||
}
|
||||
28
dsp/stream.h
28
dsp/stream.h
@@ -1,7 +1,33 @@
|
||||
#pragma once
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include "block.h"
|
||||
//#include "block.h"
|
||||
|
||||
/**
|
||||
* Interface to be used by any blocking class (stream, mailbox, etc...) to allow cancelling an operation.
|
||||
*/
|
||||
class StopNotifier {
|
||||
public:
|
||||
/**
|
||||
* Notify the sending thread that it should stop.
|
||||
*/
|
||||
virtual void stopSender() = 0;
|
||||
|
||||
/**
|
||||
* Clear the sender stop flag to allow restarting the sender thread.
|
||||
*/
|
||||
virtual void clearSendStop() = 0;
|
||||
|
||||
/**
|
||||
* Notify the receiving thread that it should stop.
|
||||
*/
|
||||
virtual void stopReceiver() = 0;
|
||||
|
||||
/**
|
||||
* Clear the receiver stop flag to allow restarting the sender thread.
|
||||
*/
|
||||
virtual void clearRecvStop() = 0;
|
||||
};
|
||||
|
||||
namespace dsp {
|
||||
/**
|
||||
|
||||
@@ -8,7 +8,6 @@ namespace dsp {
|
||||
template <class T>
|
||||
Taps<T>::Taps(const T* taps, size_t count) : Buffer<T>(taps, count) {}
|
||||
|
||||
template class Buffer<float>;
|
||||
template class Buffer<double>;
|
||||
template class Buffer<Complex>;
|
||||
template class Taps<float>;
|
||||
template class Taps<Complex>;
|
||||
}
|
||||
@@ -1,16 +1,68 @@
|
||||
#include "window.h"
|
||||
#include "complex.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace dsp {
|
||||
Window::Window() {
|
||||
// Define the window with the default error
|
||||
define();
|
||||
}
|
||||
|
||||
Window::Window(const Window& b) {
|
||||
// Copy the definition
|
||||
def = b.def;
|
||||
}
|
||||
|
||||
Window::Window(Window&& b) {
|
||||
// Move the definition
|
||||
def = std::move(b.def);
|
||||
}
|
||||
|
||||
Window::~Window() {}
|
||||
|
||||
void Window::generate(float* data, size_t len) const {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
Window& Window::operator=(const Window& b) {
|
||||
// Copy the definition
|
||||
def = b.def;
|
||||
}
|
||||
|
||||
Window& Window::operator=(Window&& b) {
|
||||
// Move the definition
|
||||
def = std::move(b.def);
|
||||
}
|
||||
|
||||
void Window::generate(float* data, size_t len) const {
|
||||
// Compute the linear map ratio
|
||||
float ratio = 1.0f / ((float)(len + 1));
|
||||
|
||||
// Iterate over all taps
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
// Evaluate the window at the adimensional parameter
|
||||
data[i] = def(((float)(i + 1)) * ratio);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Window::apply(T* data, size_t len) const {
|
||||
// TODO
|
||||
// Compute the linear map ratio
|
||||
float ratio = 1.0f / ((float)(len + 1));
|
||||
|
||||
// Iterate over all taps
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
// Evaluate the window at the adimensional parameter
|
||||
data[i] *= def(((float)(i + 1)) * ratio);
|
||||
}
|
||||
}
|
||||
template void Window::apply(float* data, size_t len) const;
|
||||
//template void Window::apply(Complex* data, size_t len) const;
|
||||
|
||||
void Window::define() {
|
||||
// Ensure an error is thrown if the undefined window is used
|
||||
def = Window::undefined;
|
||||
}
|
||||
|
||||
float Window::undefined(float x) {
|
||||
// Called when a window function was not defined
|
||||
throw std::runtime_error("Undefined window");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
41
dsp/window.h
41
dsp/window.h
@@ -1,20 +1,37 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
// TODO: Make something better, this sucks to use
|
||||
|
||||
#include <functional>
|
||||
namespace dsp {
|
||||
/**
|
||||
* Window function.
|
||||
* This class is NOT thread-safe.
|
||||
*/
|
||||
class Window {
|
||||
public:
|
||||
// Default constructor
|
||||
Window();
|
||||
|
||||
// Copy constructor
|
||||
Window(const Window& b);
|
||||
|
||||
// Move constructor
|
||||
Window(Window&& b);
|
||||
|
||||
// Virtual destructor
|
||||
virtual ~Window();
|
||||
|
||||
// Copy assignement operator
|
||||
Window& operator=(const Window& b);
|
||||
|
||||
// Move assignement operator
|
||||
Window& operator=(Window&& b);
|
||||
|
||||
/**
|
||||
* Compute the value of the window function.
|
||||
* @param x Point at which to compute the window at. Must be bounded between 0 and 1.
|
||||
* @return Value of the window bounded between 0 and 1.
|
||||
*/
|
||||
virtual float operator()(float x) const = 0;
|
||||
inline float operator()(float x) { return def(x); }
|
||||
|
||||
/**
|
||||
* Generate a window of a given length.
|
||||
@@ -30,5 +47,21 @@ namespace dsp {
|
||||
*/
|
||||
template <class T>
|
||||
void apply(T* data, size_t len) const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Define the window function by setting the `def` member.
|
||||
* MUST be overriden by all window functions.
|
||||
*/
|
||||
virtual void define();
|
||||
|
||||
/**
|
||||
* The window function itself.
|
||||
* This member MUST be initialized by all window functions.
|
||||
*/
|
||||
std::function<float(float)> def;
|
||||
|
||||
private:
|
||||
static float undefined(float x);
|
||||
};
|
||||
}
|
||||
5
dsp/window/all.h
Normal file
5
dsp/window/all.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include "hann.h"
|
||||
#include "rectangular.h"
|
||||
#include "triangular.h"
|
||||
#include "welch.h"
|
||||
15
dsp/window/hann.cpp
Normal file
15
dsp/window/hann.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "hann.h"
|
||||
#include "../constants.h"
|
||||
|
||||
namespace dsp::window {
|
||||
Hann::Hann() {
|
||||
define();
|
||||
}
|
||||
|
||||
void Hann::define() {
|
||||
def = [](float x) {
|
||||
float y = sinf(DSP_PI*x);
|
||||
return y*y;
|
||||
};
|
||||
}
|
||||
}
|
||||
12
dsp/window/hann.h
Normal file
12
dsp/window/hann.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "../window.h"
|
||||
|
||||
namespace dsp::window {
|
||||
class Hann : public Window {
|
||||
public:
|
||||
Hann();
|
||||
|
||||
private:
|
||||
void define();
|
||||
};
|
||||
}
|
||||
11
dsp/window/rectangular.cpp
Normal file
11
dsp/window/rectangular.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "rectangular.h"
|
||||
|
||||
namespace dsp::window {
|
||||
Rectangular::Rectangular() {
|
||||
define();
|
||||
}
|
||||
|
||||
void Rectangular::define() {
|
||||
def = [](float x) { return 1.0f; };
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,9 @@
|
||||
namespace dsp::window {
|
||||
class Rectangular : public Window {
|
||||
public:
|
||||
/**
|
||||
* Compute the value of the window function.
|
||||
* @param x Point at which to compute the window at. Must be bounded between 0 and 1.
|
||||
* @return Value of the window bounded between 0 and 1.
|
||||
*/
|
||||
inline float operator()(float x) const { return 1.0f; }
|
||||
Rectangular();
|
||||
|
||||
private:
|
||||
void define();
|
||||
};
|
||||
}
|
||||
12
dsp/window/triangular.cpp
Normal file
12
dsp/window/triangular.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "triangular.h"
|
||||
#include <math.h>
|
||||
|
||||
namespace dsp::window {
|
||||
Triangular::Triangular() {
|
||||
define();
|
||||
}
|
||||
|
||||
void Triangular::define() {
|
||||
def = [](float x) { return 1.0f - fabsf(2.0f*x - 1.0f); };
|
||||
}
|
||||
}
|
||||
12
dsp/window/triangular.h
Normal file
12
dsp/window/triangular.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "../window.h"
|
||||
|
||||
namespace dsp::window {
|
||||
class Triangular : public Window {
|
||||
public:
|
||||
Triangular();
|
||||
|
||||
private:
|
||||
void define();
|
||||
};
|
||||
}
|
||||
14
dsp/window/welch.cpp
Normal file
14
dsp/window/welch.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "welch.h"
|
||||
|
||||
namespace dsp::window {
|
||||
Welch::Welch() {
|
||||
define();
|
||||
}
|
||||
|
||||
void Welch::define() {
|
||||
def = [](float x) {
|
||||
float y = 2.0f*x - 1.0f;
|
||||
return 1.0f - y*y;
|
||||
};
|
||||
}
|
||||
}
|
||||
12
dsp/window/welch.h
Normal file
12
dsp/window/welch.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "../window.h"
|
||||
|
||||
namespace dsp::window {
|
||||
class Welch : public Window {
|
||||
public:
|
||||
Welch();
|
||||
|
||||
private:
|
||||
void define();
|
||||
};
|
||||
}
|
||||
30
src/main.cpp
30
src/main.cpp
@@ -1,18 +1,26 @@
|
||||
#include <stdio.h>
|
||||
#include "dsp/buffer.h"
|
||||
#include "dsp/taps.h"
|
||||
#include "dsp/complex.h"
|
||||
#include <volk/volk.h>
|
||||
#include "dsp/window.h"
|
||||
#include "dsp/window/all.h"
|
||||
|
||||
void testFunc(const float* buf, size_t len) {
|
||||
|
||||
};
|
||||
void testFunc(dsp::Window win) {
|
||||
printf("win(0.0) = %f\n", win(0.0));
|
||||
printf("win(0.5) = %f\n", win(0.5));
|
||||
printf("win(1.0) = %f\n", win(1.0));
|
||||
}
|
||||
|
||||
int main() {
|
||||
float* test;
|
||||
dsp::Taps<float> taps;
|
||||
try {
|
||||
testFunc(dsp::window::Hann());
|
||||
|
||||
testFunc(((const dsp::Taps<float>&)taps).data(), taps.size());
|
||||
dsp::Window win = dsp::window::Triangular();
|
||||
dsp::Window win2 = dsp::window::Hann();
|
||||
|
||||
return 0;
|
||||
win = dsp::window::Hann();
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fprintf(stderr, "ERROR: %s\n", e.what());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user