2022-12-04 02:10:34 +01:00

181 lines
5.0 KiB
C++

#include <config.h>
#include <core.h>
#include <filesystem>
#include <gui/gui.h>
#include <gui/style.h>
#include <gui/widgets/image.h>
#include <imgui.h>
#include <module.h>
#include <signal_path/signal_path.h>
#include <dsp/demod/quadrature.h>
#include <dsp/sink/handler_sink.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str())
SDRPP_MOD_INFO{/* Name: */ "atv_decoder",
/* Description: */ "ATV decoder for SDR++",
/* Author: */ "Ryzerth",
/* Version: */ 0, 1, 0,
/* Max instances */ -1};
#define SAMPLE_RATE (625.0f * 720.0f * 25.0f)
class ATVDecoderModule : public ModuleManager::Instance {
public:
ATVDecoderModule(std::string name) : img(720, 625) {
this->name = name;
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 8000000.0f, SAMPLE_RATE, SAMPLE_RATE, SAMPLE_RATE, true);
demod.init(vfo->output, SAMPLE_RATE, SAMPLE_RATE / 2.0f);
sink.init(&demod.out, handler, this);
demod.start();
sink.start();
gui::menu.registerEntry(name, menuHandler, this, this);
}
~ATVDecoderModule() {
if (vfo) {
sigpath::vfoManager.deleteVFO(vfo);
}
demod.stop();
gui::menu.removeEntry(name);
}
void postInit() {}
void enable() { enabled = true; }
void disable() { enabled = false; }
bool isEnabled() { return enabled; }
private:
static void menuHandler(void *ctx) {
ATVDecoderModule *_this = (ATVDecoderModule *)ctx;
if (!_this->enabled) {
style::beginDisabled();
}
ImGui::FillWidth();
_this->img.draw();
ImGui::LeftLabel("Sync");
ImGui::FillWidth();
ImGui::SliderFloat("##syncLvl", &_this->sync_level, -2, 2);
ImGui::LeftLabel("Min");
ImGui::FillWidth();
ImGui::SliderFloat("##minLvl", &_this->minLvl, -1.0, 1.0);
ImGui::LeftLabel("Span");
ImGui::FillWidth();
ImGui::SliderFloat("##spanLvl", &_this->spanLvl, 0, 1.0);
if (!_this->enabled) {
style::endDisabled();
}
}
static void handler(float *data, int count, void *ctx) {
ATVDecoderModule *_this = (ATVDecoderModule *)ctx;
uint8_t *buf = (uint8_t *)_this->img.buffer;
float val;
float imval;
int pos = 0;
for (int i = 0; i < count; i++) {
val = data[i];
// Sync
if (val < _this->sync_level) {
_this->sync_count++;
}
else {
if (_this->sync_count >= 300) {
_this->short_sync = 0;
}
else if (_this->sync_count >= 33) {
if (_this->short_sync == 5) {
_this->even_field = false;
_this->ypos = 0;
_this->img.swap();
buf = (uint8_t *)_this->img.buffer;
}
else if (_this->short_sync == 4) {
_this->even_field = true;
_this->ypos = 0;
}
_this->xpos = 0;
_this->short_sync = 0;
}
else if (_this->sync_count >= 15) {
_this->short_sync++;
}
_this->sync_count = 0;
}
// Draw
imval = std::clamp<float>((val - _this->minLvl) * 255.0 / _this->spanLvl, 0, 255);
if (_this->even_field) {
pos = ((720 * _this->ypos * 2) + _this->xpos) * 4;
}
else {
pos = ((720 * (_this->ypos * 2 + 1)) + _this->xpos) * 4;
}
buf[pos] = imval;
buf[pos + 1] = imval;
buf[pos + 2] = imval;
buf[pos + 3] = imval;
// Image logic
_this->xpos++;
if (_this->xpos >= 720) {
_this->ypos++;
_this->xpos = 0;
}
if (_this->ypos >= 312) {
_this->ypos = 0;
_this->xpos = 0;
_this->even_field = !_this->even_field;
if (_this->even_field) {
_this->img.swap();
buf = (uint8_t *)_this->img.buffer;
}
}
}
}
std::string name;
bool enabled = true;
VFOManager::VFO *vfo = NULL;
dsp::demod::Quadrature demod;
dsp::sink::Handler<float> sink;
int xpos = 0;
int ypos = 0;
bool even_field = false;
float sync_level = -0.3f;
int sync_count = 0;
int short_sync = 0;
float minLvl = 0.0f;
float spanLvl = 1.0f;
ImGui::ImageDisplay img;
};
MOD_EXPORT void _INIT_() {}
MOD_EXPORT ModuleManager::Instance *_CREATE_INSTANCE_(std::string name) { return new ATVDecoderModule(name); }
MOD_EXPORT void _DELETE_INSTANCE_(void *instance) { delete (ATVDecoderModule *)instance; }
MOD_EXPORT void _END_() {}