diff --git a/plugins/channelrx/demodatv/CMakeLists.txt b/plugins/channelrx/demodatv/CMakeLists.txt
index 7cc6a5237..e92bc546e 100644
--- a/plugins/channelrx/demodatv/CMakeLists.txt
+++ b/plugins/channelrx/demodatv/CMakeLists.txt
@@ -2,6 +2,7 @@ project(atv)
set(atv_SOURCES
atvdemod.cpp
+ atvdemodsettings.cpp
atvdemodgui.cpp
atvdemodplugin.cpp
atvscreen.cpp
@@ -10,6 +11,7 @@ set(atv_SOURCES
set(atv_HEADERS
atvdemod.h
+ atvdemodsettings.h
atvdemodgui.h
atvdemodplugin.h
atvscreen.h
diff --git a/plugins/channelrx/demodatv/atvdemodsettings.cpp b/plugins/channelrx/demodatv/atvdemodsettings.cpp
new file mode 100644
index 000000000..16b65cba3
--- /dev/null
+++ b/plugins/channelrx/demodatv/atvdemodsettings.cpp
@@ -0,0 +1,392 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+
+#include "dsp/dspengine.h"
+#include "util/simpleserializer.h"
+#include "settings/serializable.h"
+#include "atvdemodsettings.h"
+
+ATVDemodSettings::ATVDemodSettings() :
+ m_channelMarker(0)
+{
+ resetToDefaults();
+}
+
+void ATVDemodSettings::resetToDefaults()
+{
+ m_lineTimeFactor = 0;
+ m_topTimeFactor = 0;
+ m_fpsIndex = 1; // 25 FPS
+ m_halfImage = false; // m_fltRatioOfRowsToDisplay = 1.0
+ m_RFBandwidthFactor = 10;
+ m_OppBandwidthFactor = 10;
+ m_nbLinesIndex = 1; // 625 lines
+
+ m_intFrequencyOffset = 0;
+ m_enmModulation = ATV_FM1;
+ m_fltRFBandwidth = 0;
+ m_fltRFOppBandwidth = 0;
+ m_blnFFTFiltering = false;
+ m_blndecimatorEnable = false;
+ m_fltBFOFrequency = 0.0f;
+ m_fmDeviation = 0.5f;
+
+ m_intSampleRate = 0;
+ m_enmATVStandard = ATVStdPAL625;
+ m_intNumberOfLines = 625;
+ m_fltLineDuration = 0.0f;
+ m_fltTopDuration = 0.0f;
+ m_fltFramePerS = 25.0f;
+ m_fltRatioOfRowsToDisplay = 1.0f;
+ m_fltVoltLevelSynchroTop = 0.0f;
+ m_fltVoltLevelSynchroBlack = 1.0f;
+ m_blnHSync = false;
+ m_blnVSync = false;
+ m_blnInvertVideo = false;
+ m_intVideoTabIndex = 0;
+
+ m_intTVSampleRate = 0;
+ m_intNumberSamplePerLine = 0;
+
+ m_rgbColor = QColor(255, 255, 255).rgb();
+ m_title = "ATV Demodulator";
+ m_udpAddress = "127.0.0.1";
+ m_udpPort = 9999;
+}
+
+QByteArray ATVDemodSettings::serialize() const
+{
+ SimpleSerializer s(1);
+
+ s.writeS32(1, m_intFrequencyOffset);
+ s.writeU32(2, m_rgbColor);
+ s.writeS32(3, roundf(m_fltVoltLevelSynchroTop*1000.0)); // mV
+ s.writeS32(4, roundf(m_fltVoltLevelSynchroBlack*1000.0)); // mV
+ s.writeS32(5, m_lineTimeFactor); // added UI
+ s.writeS32(6, m_topTimeFactor); // added UI
+ s.writeS32(7, m_enmModulation);
+ s.writeS32(8, m_fpsIndex); // added UI
+ s.writeBool(9, m_blnHSync);
+ s.writeBool(10,m_blnVSync);
+ s.writeBool(11, m_halfImage); // added UI
+ s.writeS32(12, m_RFBandwidthFactor); // added UI
+ s.writeS32(13, m_OppBandwidthFactor); // added UI
+ s.writeS32(14, roundf(m_fltBFOFrequency));
+ s.writeBool(15, m_blnInvertVideo);
+ s.writeS32(16, m_nbLinesIndex); // added UI
+ s.writeS32(17, roundf(m_fmDeviation * 500.0));
+ s.writeS32(18, m_enmATVStandard);
+
+ if (m_channelMarker) {
+ s.writeBlob(19, m_channelMarker->serialize());
+ }
+
+ s.writeString(20, m_title);
+
+ return s.final();
+}
+
+bool ATVDemodSettings::deserialize(const QByteArray& arrData)
+{
+ SimpleDeserializer d(arrData);
+
+ if (!d.isValid())
+ {
+ resetToDefaults();
+ return false;
+ }
+
+ if (d.getVersion() == 1)
+ {
+ QByteArray bytetmp;
+ int tmp;
+
+ d.readS32(1, &m_intFrequencyOffset, 0);
+ // TODO: rgb color
+ d.readS32(3, &tmp, 100);
+ m_fltVoltLevelSynchroTop = tmp / 1000.0f;
+ d.readS32(4, &tmp, 310);
+ m_fltVoltLevelSynchroBlack = tmp / 1000.0f;
+ d.readS32(5, &m_lineTimeFactor, 0); // added UI
+ d.readS32(6, &m_topTimeFactor, 0); // added UI
+ d.readS32(7, &tmp, 0);
+ m_enmModulation = static_cast(tmp);
+ d.readS32(8, &m_fpsIndex, 1); // added UI
+ d.readBool(9, &m_blnHSync, false);
+ d.readBool(10, &m_blnVSync, false);
+ d.readBool(11, &m_halfImage, false); // added UI
+ d.readS32(12, &m_RFBandwidthFactor, 10); // added UI
+ d.readS32(13, &m_OppBandwidthFactor, 10); // added UI
+ d.readS32(14, &tmp, 10);
+ m_fltBFOFrequency = static_cast(tmp);
+ d.readBool(15, &m_blnInvertVideo, false);
+ d.readS32(16, &m_nbLinesIndex, 1); // added UI
+ d.readS32(17, &tmp, 250);
+ m_fmDeviation = tmp / 500.0f;
+ d.readS32(18, &tmp, 1);
+ m_enmATVStandard = static_cast(tmp);
+
+ // TODO: calculate values from UI values
+
+ return true;
+ }
+ else
+ {
+ resetToDefaults();
+ return false;
+ }
+}
+
+int ATVDemodSettings::getEffectiveSampleRate()
+{
+ return m_blndecimatorEnable ? m_intTVSampleRate : m_intSampleRate;
+}
+
+
+float ATVDemodSettings::getFps(int fpsIndex)
+{
+ switch(fpsIndex)
+ {
+ case 0:
+ return 30.0f;
+ break;
+ case 2:
+ return 20.0f;
+ break;
+ case 3:
+ return 16.0f;
+ break;
+ case 4:
+ return 12.0f;
+ break;
+ case 5:
+ return 10.0f;
+ break;
+ case 6:
+ return 8.0f;
+ break;
+ case 7:
+ return 5.0f;
+ break;
+ case 8:
+ return 2.0f;
+ break;
+ case 9:
+ return 1.0f;
+ break;
+ case 1:
+ default:
+ return 25.0f;
+ break;
+ }
+}
+
+int ATVDemodSettings::getFpsIndex(float fps)
+{
+ int fpsi = roundf(fps);
+
+ if (fpsi <= 1) {
+ return 9;
+ } else if (fps <= 2) {
+ return 8;
+ } else if (fps <= 5) {
+ return 7;
+ } else if (fps <= 8) {
+ return 6;
+ } else if (fps <= 10) {
+ return 5;
+ } else if (fps <= 12) {
+ return 4;
+ } else if (fps <= 16) {
+ return 3;
+ } else if (fps <= 20) {
+ return 2;
+ } else if (fps <= 25) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int ATVDemodSettings::getNumberOfLines(int nbLinesIndex)
+{
+ switch(nbLinesIndex)
+ {
+ case 0:
+ return 640;
+ break;
+ case 2:
+ return 525;
+ break;
+ case 3:
+ return 480;
+ break;
+ case 4:
+ return 405;
+ break;
+ case 5:
+ return 360;
+ break;
+ case 6:
+ return 343;
+ break;
+ case 7:
+ return 240;
+ break;
+ case 8:
+ return 180;
+ break;
+ case 9:
+ return 120;
+ break;
+ case 10:
+ return 90;
+ break;
+ case 11:
+ return 60;
+ break;
+ case 12:
+ return 32;
+ break;
+ case 1:
+ default:
+ return 625;
+ break;
+ }
+}
+
+int ATVDemodSettings::getNumberOfLinesIndex(int nbLines)
+{
+ if (nbLines <= 32) {
+ return 12;
+ } else if (nbLines <= 60) {
+ return 11;
+ } else if (nbLines <= 90) {
+ return 10;
+ } else if (nbLines <= 120) {
+ return 9;
+ } else if (nbLines <= 180) {
+ return 8;
+ } else if (nbLines <= 240) {
+ return 7;
+ } else if (nbLines <= 343) {
+ return 6;
+ } else if (nbLines <= 360) {
+ return 5;
+ } else if (nbLines <= 405) {
+ return 4;
+ } else if (nbLines <= 480) {
+ return 3;
+ } else if (nbLines <= 525) {
+ return 2;
+ } else if (nbLines <= 625) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+float ATVDemodSettings::getNominalLineTime(int nbLinesIndex, int fpsIndex)
+{
+ float fps = getFps(fpsIndex);
+ int nbLines = getNumberOfLines(nbLinesIndex);
+
+ return 1.0f / (nbLines * fps);
+}
+
+/**
+ * calculates m_fltLineTimeMultiplier
+ */
+void ATVDemodSettings::lineTimeUpdate()
+{
+ float nominalLineTime = getNominalLineTime(m_nbLinesIndex, m_fpsIndex);
+ int lineTimeScaleFactor = (int) std::log10(nominalLineTime);
+
+ if (getEffectiveSampleRate() == 0) {
+ m_fltLineTimeMultiplier = std::pow(10.0, lineTimeScaleFactor-3);
+ } else {
+ m_fltLineTimeMultiplier = 1.0f / getEffectiveSampleRate();
+ }
+}
+
+float ATVDemodSettings::getLineTime()
+{
+ return getNominalLineTime(m_nbLinesIndex, m_fpsIndex) + m_fltLineTimeMultiplier * m_lineTimeFactor;
+}
+
+int ATVDemodSettings::getLineTimeFactor()
+{
+ return roundf((m_fltLineDuration - getNominalLineTime(m_nbLinesIndex, m_fpsIndex)) / m_fltLineTimeMultiplier);
+}
+
+/**
+ * calculates m_fltTopTimeMultiplier
+ */
+void ATVDemodSettings::topTimeUpdate()
+{
+ float nominalTopTime = getNominalLineTime(m_nbLinesIndex, m_fpsIndex) * (4.7f / 64.0f);
+ int topTimeScaleFactor = (int) std::log10(nominalTopTime);
+
+ if (getEffectiveSampleRate() == 0) {
+ m_fltTopTimeMultiplier = std::pow(10.0, topTimeScaleFactor-3);
+ } else {
+ m_fltTopTimeMultiplier = 1.0f / getEffectiveSampleRate();
+ }
+}
+
+float ATVDemodSettings::getTopTime()
+{
+ return getNominalLineTime(m_nbLinesIndex, m_fpsIndex) * (4.7f / 64.0f) + m_fltTopTimeMultiplier * m_topTimeFactor;
+}
+
+int ATVDemodSettings::getTopTimeFactor()
+{
+ return roundf((m_fltTopDuration - getNominalLineTime(m_nbLinesIndex, m_fpsIndex) * (4.7f / 64.0f)) / m_fltLineTimeMultiplier);
+}
+
+void ATVDemodSettings::convertFromUIValues()
+{
+ lineTimeUpdate();
+ m_fltLineDuration = getLineTime();
+ topTimeUpdate();
+ m_fltTopDuration = getTopTime();
+ m_fltRFBandwidth = m_RFBandwidthFactor * getRFSliderDivisor() * 1.0f;
+ m_fltRFOppBandwidth = m_OppBandwidthFactor * getRFSliderDivisor() * 1.0f;
+ m_fltFramePerS = getFps(m_fpsIndex);
+ m_intNumberOfLines = getNumberOfLines(m_nbLinesIndex);
+}
+
+void ATVDemodSettings::convertToUIValues()
+{
+ m_lineTimeFactor = getTopTimeFactor();
+ m_topTimeFactor = getTopTimeFactor();
+ m_RFBandwidthFactor = roundf(m_fltRFBandwidth / getRFSliderDivisor());
+ m_RFBandwidthFactor = m_RFBandwidthFactor < 1 ? 1 : m_RFBandwidthFactor;
+ m_OppBandwidthFactor = roundf(m_fltRFOppBandwidth / getRFSliderDivisor());
+ m_fpsIndex = getFpsIndex(m_fltFramePerS);
+ m_nbLinesIndex = getNumberOfLinesIndex(m_intNumberOfLines);
+}
+
+int ATVDemodSettings::getRFSliderDivisor()
+{
+ int sampleRate = getEffectiveSampleRate();
+ int scaleFactor = (int) std::log10(sampleRate/2);
+ return std::pow(10.0, scaleFactor-1);
+}
+
+
diff --git a/plugins/channelrx/demodatv/atvdemodsettings.h b/plugins/channelrx/demodatv/atvdemodsettings.h
new file mode 100644
index 000000000..f72f8e9d7
--- /dev/null
+++ b/plugins/channelrx/demodatv/atvdemodsettings.h
@@ -0,0 +1,125 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef PLUGINS_CHANNELRX_DEMODATV_ATVDEMODSETTINGS_H_
+#define PLUGINS_CHANNELRX_DEMODATV_ATVDEMODSETTINGS_H_
+
+#include
+#include
+#include
+
+struct Serializable;
+
+struct ATVDemodSettings
+{
+ enum ATVModulation {
+ ATV_FM1, //!< Classical frequency modulation with discriminator #1
+ ATV_FM2, //!< Classical frequency modulation with discriminator #2
+ ATV_FM3, //!< Classical frequency modulation with phase derivative discriminator
+ ATV_AM, //!< Classical amplitude modulation
+ ATV_USB, //!< AM with vestigial lower side band (main signal is in the upper side)
+ ATV_LSB //!< AM with vestigial upper side band (main signal is in the lower side)
+ };
+
+ enum ATVStd
+ {
+ ATVStdPAL625,
+ ATVStdPAL525,
+ ATVStd405,
+ ATVStdShortInterleaved,
+ ATVStdShort,
+ ATVStdHSkip
+ };
+
+ // Added fields that correspond directly to UI inputs
+ int m_lineTimeFactor; //!< added: +/- 100 something
+ int m_topTimeFactor; //!< added: +/- 30 something
+ int m_fpsIndex; //!< added: FPS list index
+ bool m_halfImage; //!< added: true => m_fltRatioOfRowsToDisplay = 0.5, false => m_fltRatioOfRowsToDisplay = 1.0
+ int m_RFBandwidthFactor; //!< added: [1:100]
+ int m_OppBandwidthFactor; //!< added: [0:100]
+ int m_nbLinesIndex; //!< added: #lines list index
+
+ // Former RF
+ int m_intFrequencyOffset;
+ ATVModulation m_enmModulation;
+ float m_fltRFBandwidth;
+ float m_fltRFOppBandwidth;
+ bool m_blnFFTFiltering;
+ bool m_blndecimatorEnable;
+ float m_fltBFOFrequency;
+ float m_fmDeviation;
+
+ // Former
+ int m_intSampleRate;
+ ATVStd m_enmATVStandard;
+ int m_intNumberOfLines;
+ float m_fltLineDuration;
+ float m_fltTopDuration;
+ float m_fltFramePerS;
+ float m_fltRatioOfRowsToDisplay;
+ float m_fltVoltLevelSynchroTop;
+ float m_fltVoltLevelSynchroBlack;
+ bool m_blnHSync;
+ bool m_blnVSync;
+ bool m_blnInvertVideo;
+ int m_intVideoTabIndex;
+
+ // Former private
+ int m_intTVSampleRate;
+ int m_intNumberSamplePerLine;
+
+ // new
+ quint32 m_rgbColor;
+ QString m_title;
+ QString m_udpAddress;
+ uint16_t m_udpPort;
+ Serializable *m_channelMarker;
+
+ ATVDemodSettings();
+ void resetToDefaults();
+ void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+
+ int getEffectiveSampleRate();
+ float getLineTime();
+ int getLineTimeFactor();
+ float getTopTime();
+ int getTopTimeFactor();
+ int getRFSliderDivisor();
+
+ void convertFromUIValues();
+ void convertToUIValues();
+
+ static float getFps(int fpsIndex);
+ static int getNumberOfLines(int nbLinesIndex);
+ static int getFpsIndex(float fps);
+ static int getNumberOfLinesIndex(int nbLines);
+ static float getNominalLineTime(int nbLinesIndex, int fpsIndex);
+
+private:
+ void lineTimeUpdate();
+ void topTimeUpdate();
+
+ float m_fltLineTimeMultiplier;
+ float m_fltTopTimeMultiplier;
+ int m_rfSliderDivisor;
+};
+
+
+
+#endif /* PLUGINS_CHANNELRX_DEMODATV_ATVDEMODSETTINGS_H_ */