diff --git a/plugins/channeltx/modatv/atvmod.cpp b/plugins/channeltx/modatv/atvmod.cpp index 5a04b7159..6aba0a00f 100644 --- a/plugins/channeltx/modatv/atvmod.cpp +++ b/plugins/channeltx/modatv/atvmod.cpp @@ -72,6 +72,8 @@ ATVMod::ATVMod() : m_config.m_rfBandwidth = 1000000; m_config.m_atvModInput = ATVModInputHBars; m_config.m_atvStd = ATVStdPAL625; + m_config.m_nbLines = 625; + m_config.m_fps = 25; m_SSBFilter = new fftfilt(0, m_config.m_rfBandwidth / m_config.m_outputSampleRate, m_ssbFftLen); m_SSBFilterBuffer = new Complex[m_ssbFftLen>>1]; // filter returns data exactly half of its size @@ -101,6 +103,8 @@ void ATVMod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real rfOppBandwidth, ATVStd atvStd, + int nbLines, + int fps, ATVModInput atvModInput, Real uniformLevel, ATVModulation atvModulation, @@ -114,6 +118,8 @@ void ATVMod::configure(MessageQueue* messageQueue, rfBandwidth, rfOppBandwidth, atvStd, + nbLines, + fps, atvModInput, uniformLevel, atvModulation, @@ -520,6 +526,8 @@ bool ATVMod::handleMessage(const Message& cmd) m_config.m_rfOppBandwidth = cfg.getRFOppBandwidth(); m_config.m_atvModInput = cfg.getATVModInput(); m_config.m_atvStd = cfg.getATVStd(); + m_config.m_nbLines = cfg.getNbLines(); + m_config.m_fps = cfg.getFPS(); m_config.m_uniformLevel = cfg.getUniformLevel(); m_config.m_atvModulation = cfg.getModulation(); m_config.m_videoPlayLoop = cfg.getVideoPlayLoop(); @@ -534,6 +542,8 @@ bool ATVMod::handleMessage(const Message& cmd) << " m_rfBandwidth: " << m_config.m_rfBandwidth << " m_rfOppBandwidth: " << m_config.m_rfOppBandwidth << " m_atvStd: " << (int) m_config.m_atvStd + << " m_nbLines: " << m_config.m_nbLines + << " m_fps: " << m_config.m_fps << " m_atvModInput: " << (int) m_config.m_atvModInput << " m_uniformLevel: " << m_config.m_uniformLevel << " m_atvModulation: " << (int) m_config.m_atvModulation @@ -639,10 +649,13 @@ void ATVMod::apply(bool force) { if ((m_config.m_outputSampleRate != m_running.m_outputSampleRate) || (m_config.m_atvStd != m_running.m_atvStd) + || (m_config.m_nbLines != m_running.m_nbLines) + || (m_config.m_fps != m_running.m_fps) || (m_config.m_rfBandwidth != m_running.m_rfBandwidth) || (m_config.m_atvModulation != m_running.m_atvModulation) || force) { - int rateUnits = getSampleRateUnits(m_config.m_atvStd); + int rateUnits, nbPointsPerRateUnit; + getBaseValues(m_config.m_nbLines * m_config.m_fps, rateUnits, nbPointsPerRateUnit); m_tvSampleRate = (m_config.m_outputSampleRate / rateUnits) * rateUnits; // make sure working sample rate is a multiple of rate units m_settingsMutex.lock(); @@ -673,10 +686,12 @@ void ATVMod::apply(bool force) getOutputMessageQueue()->push(report); } - if ((m_config.m_outputSampleRate != m_running.m_outputSampleRate) || - (m_config.m_rfOppBandwidth != m_running.m_rfOppBandwidth) || - (m_config.m_rfBandwidth != m_running.m_rfBandwidth) || - (m_config.m_atvStd != m_running.m_atvStd) || force) // difference in TV standard may have changed TV sample rate + if ((m_config.m_outputSampleRate != m_running.m_outputSampleRate) + || (m_config.m_rfOppBandwidth != m_running.m_rfOppBandwidth) + || (m_config.m_rfBandwidth != m_running.m_rfBandwidth) + || (m_config.m_nbLines != m_running.m_nbLines) // difference in line period may have changed TV sample rate + || (m_config.m_fps != m_running.m_fps) // + || force) { m_settingsMutex.lock(); @@ -701,6 +716,8 @@ void ATVMod::apply(bool force) m_running.m_rfOppBandwidth = m_config.m_rfOppBandwidth; m_running.m_atvModInput = m_config.m_atvModInput; m_running.m_atvStd = m_config.m_atvStd; + m_running.m_nbLines = m_config.m_nbLines; + m_running.m_fps = m_config.m_fps; m_running.m_uniformLevel = m_config.m_uniformLevel; m_running.m_atvModulation = m_config.m_atvModulation; m_running.m_videoPlayLoop = m_config.m_videoPlayLoop; @@ -710,23 +727,18 @@ void ATVMod::apply(bool force) m_running.m_invertedVideo = m_config.m_invertedVideo; } -int ATVMod::getSampleRateUnits(ATVStd std) +void ATVMod::getBaseValues(int linesPerSecond, int& sampleRateUnits, int& nbPointsPerRateUnit) { - switch(std) + int i = 0; + + for (; i < 100; i++) { - case ATVStd405: - return 729000; // 72 * 10125 - break; - case ATVStdPAL525: - return 1008000; // 64 * 15750 - break; - case ATVStd525L20F: - return 735000; // 70 * 10500 - break; - case ATVStdPAL625: - default: - return 1000000; // 64 * 15625 Exact MS/s - us + if (((100+i) * linesPerSecond) % 1000 == 0) + break; } + + nbPointsPerRateUnit = (i == 100) ? 100 : 100+i; + sampleRateUnits = nbPointsPerRateUnit * linesPerSecond; } float ATVMod::getRFBandwidthDivisor(ATVModulation modulation) @@ -748,95 +760,51 @@ float ATVMod::getRFBandwidthDivisor(ATVModulation modulation) void ATVMod::applyStandard() { - int rateUnits = getSampleRateUnits(m_config.m_atvStd); + int rateUnits, nbPointsPerRateUnit; + getBaseValues(m_config.m_nbLines * m_config.m_fps, rateUnits, nbPointsPerRateUnit); m_pointsPerTU = m_tvSampleRate / rateUnits; // TV sample rate is already set at a multiple of rate units + m_pointsPerSync = (uint32_t) roundf(4.7f * m_pointsPerTU); // normal sync pulse (4.7 us / rateUnits) + m_pointsPerBP = (uint32_t) roundf(4.7f * m_pointsPerTU); // back porch (4.7 us / rateUnits) + m_pointsPerFP = (uint32_t) roundf(1.5f * m_pointsPerTU); // front porch (1.5 us / rateUnits) + m_pointsPerFSync = (uint32_t) roundf(2.3f * m_pointsPerTU); // equalizing pulse (2.3 us / rateUnits) + m_pointsPerImgLine = nbPointsPerRateUnit * m_pointsPerTU - m_pointsPerSync - m_pointsPerBP - m_pointsPerFP; + m_nbHorizPoints = nbPointsPerRateUnit * m_pointsPerTU; // full line + m_pointsPerHBar = m_pointsPerImgLine / m_nbBars; + m_linesPerVBar = m_nbImageLines2 / m_nbBars; + m_hBarIncrement = m_spanLevel / (float) m_nbBars; + m_vBarIncrement = m_spanLevel / (float) m_nbBars; + + m_nbLines = m_config.m_nbLines; + m_nbLines2 = (m_nbLines / 2) + 1; + m_fps = m_config.m_fps * 1.0f; + switch(m_config.m_atvStd) { - case ATVStd405: // Follows loosely the 405 lines standard - m_pointsPerSync = (uint32_t) roundf(4.7f * m_pointsPerTU); // normal sync pulse (4.7/0.729 us) - m_pointsPerBP = (uint32_t) roundf(4.7f * m_pointsPerTU); // back porch (4.7/0.729 us) - m_pointsPerFP = (uint32_t) roundf(1.5f * m_pointsPerTU); // front porch (1.5/0.729 us) - m_pointsPerFSync = (uint32_t) roundf(2.3f * m_pointsPerTU); // equalizing pulse (2.3/0.729 us) - // what is left in a 72/0.729 us line for the image - m_pointsPerImgLine = 72 * m_pointsPerTU - m_pointsPerSync - m_pointsPerBP - m_pointsPerFP; - m_nbLines = 405; - m_nbLines2 = 203; - m_nbImageLines = 390; - m_nbImageLines2 = 195; + case ATVStd405: // Follows loosely the 405 lines standard + // what is left in a 64 us line for the image + m_nbImageLines = m_nbLines - 15; // lines less the total number of sync lines + m_nbImageLines2 = m_nbImageLines / 2; m_interlaced = true; - m_nbHorizPoints = 72 * m_pointsPerTU; // full line - m_nbSyncLinesHead = 5; + m_nbSyncLinesHead = 5; // number of sync lines on the top of a frame m_nbBlankLines = 7; // yields 376 lines (195 - 7) * 2 - m_pointsPerHBar = m_pointsPerImgLine / m_nbBars; - m_linesPerVBar = m_nbImageLines2 / m_nbBars; - m_hBarIncrement = m_spanLevel / (float) m_nbBars; - m_vBarIncrement = m_spanLevel / (float) m_nbBars; - m_fps = 25.0f; break; case ATVStdPAL525: // Follows PAL-M standard - m_pointsPerSync = (uint32_t) roundf(4.7f * m_pointsPerTU); // normal sync pulse (4.7/1.008 us) - m_pointsPerBP = (uint32_t) roundf(4.7f * m_pointsPerTU); // back porch (4.7/1.008 us) - m_pointsPerFP = (uint32_t) roundf(1.5f * m_pointsPerTU); // front porch (1.5/1.008 us) - m_pointsPerFSync = (uint32_t) roundf(2.3f * m_pointsPerTU); // equalizing pulse (2.3/1.008 us) // what is left in a 64/1.008 us line for the image - m_pointsPerImgLine = 64 * m_pointsPerTU - m_pointsPerSync - m_pointsPerBP - m_pointsPerFP; - m_nbLines = 525; - m_nbLines2 = 263; - m_nbImageLines = 510; - m_nbImageLines2 = 255; + m_nbImageLines = m_nbLines - 15; + m_nbImageLines2 = m_nbImageLines / 2; m_interlaced = true; - m_nbHorizPoints = 64 * m_pointsPerTU; // full line m_nbSyncLinesHead = 5; m_nbBlankLines = 15; // yields 480 lines (255 - 15) * 2 - m_pointsPerHBar = m_pointsPerImgLine / m_nbBars; - m_linesPerVBar = m_nbImageLines2 / m_nbBars; - m_hBarIncrement = m_spanLevel / (float) m_nbBars; - m_vBarIncrement = m_spanLevel / (float) m_nbBars; - m_fps = 30.0f; - break; - case ATVStd525L20F: // PAL M based 20 FPS - m_pointsPerSync = (uint32_t) roundf(4.7f * m_pointsPerTU); // normal sync pulse (4.7/0.735 us) - m_pointsPerBP = (uint32_t) roundf(4.7f * m_pointsPerTU); // back porch (4.7/0.735 us) - m_pointsPerFP = (uint32_t) roundf(2.3f * m_pointsPerTU); // front porch (2.3/0.735 us) - m_pointsPerFSync = (uint32_t) roundf(2.3f * m_pointsPerTU); // equalizing pulse (2.3/0.735 us) - // what is left in a 70/0.735 us line for the image - m_pointsPerImgLine = 70 * m_pointsPerTU - m_pointsPerSync - m_pointsPerBP - m_pointsPerFP; - m_nbLines = 525; - m_nbLines2 = 263; - m_nbImageLines = 510; - m_nbImageLines2 = 255; - m_interlaced = true; - m_nbHorizPoints = 70 * m_pointsPerTU; // full line - m_nbSyncLinesHead = 5; - m_nbBlankLines = 15; // yields 480 lines (255 - 15) * 2 - m_pointsPerHBar = m_pointsPerImgLine / m_nbBars; - m_linesPerVBar = m_nbImageLines2 / m_nbBars; - m_hBarIncrement = m_spanLevel / (float) m_nbBars; - m_vBarIncrement = m_spanLevel / (float) m_nbBars; - m_fps = 20.0f; break; case ATVStdPAL625: // Follows PAL-B/G/H standard default: - m_pointsPerSync = (uint32_t) roundf(4.7f * m_pointsPerTU); // normal sync pulse (4.7 us) - m_pointsPerBP = (uint32_t) roundf(4.7f * m_pointsPerTU); // back porch (4.7 us) - m_pointsPerFP = (uint32_t) roundf(1.5f * m_pointsPerTU); // front porch (1.5 us) - m_pointsPerFSync = (uint32_t) roundf(2.3f * m_pointsPerTU); // equalizing pulse (2.3 us) // what is left in a 64 us line for the image - m_pointsPerImgLine = 64 * m_pointsPerTU - m_pointsPerSync - m_pointsPerBP - m_pointsPerFP; - m_nbLines = 625; - m_nbLines2 = 313; - m_nbImageLines = 610; - m_nbImageLines2 = 305; + m_nbImageLines = m_nbLines - 15; + m_nbImageLines2 = m_nbImageLines / 2; m_interlaced = true; - m_nbHorizPoints = 64 * m_pointsPerTU; // full line m_nbSyncLinesHead = 5; m_nbBlankLines = 17; // yields 576 lines (305 - 17) * 2 - m_pointsPerHBar = m_pointsPerImgLine / m_nbBars; - m_linesPerVBar = m_nbImageLines2 / m_nbBars; - m_hBarIncrement = m_spanLevel / (float) m_nbBars; - m_vBarIncrement = m_spanLevel / (float) m_nbBars; - m_fps = 25.0f; } if (m_imageOK) diff --git a/plugins/channeltx/modatv/atvmod.h b/plugins/channeltx/modatv/atvmod.h index 9b8f2f119..e635d36c0 100644 --- a/plugins/channeltx/modatv/atvmod.h +++ b/plugins/channeltx/modatv/atvmod.h @@ -333,6 +333,8 @@ public: Real rfBandwidth, Real rfOppBandwidth, ATVStd atvStd, + int nbLines, + int fps, ATVModInput atvModInput, Real uniformLevel, ATVModulation atvModulation, @@ -352,7 +354,7 @@ public: void getCameraNumbers(std::vector& numbers); - static int getSampleRateUnits(ATVStd std); + static void getBaseValues(int linesPerSecond, int& sampleRateUnits, int& nbPointsPerRateUnit); static float getRFBandwidthDivisor(ATVModulation modulation); signals: @@ -374,6 +376,8 @@ private: Real getRFOppBandwidth() const { return m_rfOppBandwidth; } ATVStd getATVStd() const { return m_atvStd; } ATVModInput getATVModInput() const { return m_atvModInput; } + int getNbLines() const { return m_nbLines; } + int getFPS() const { return m_fps; } Real getUniformLevel() const { return m_uniformLevel; } ATVModulation getModulation() const { return m_atvModulation; } bool getVideoPlayLoop() const { return m_videoPlayLoop; } @@ -386,6 +390,8 @@ private: Real rfBandwidth, Real rfOppBandwidth, ATVStd atvStd, + int nbLines, + int fps, ATVModInput atvModInput, Real uniformLevel, ATVModulation atvModulation, @@ -399,6 +405,8 @@ private: rfBandwidth, rfOppBandwidth, atvStd, + nbLines, + fps, atvModInput, uniformLevel, atvModulation, @@ -413,6 +421,8 @@ private: Real m_rfBandwidth; Real m_rfOppBandwidth; ATVStd m_atvStd; + int m_nbLines; + int m_fps; ATVModInput m_atvModInput; Real m_uniformLevel; ATVModulation m_atvModulation; @@ -426,6 +436,8 @@ private: Real rfBandwidth, Real rfOppBandwidth, ATVStd atvStd, + int nbLines, + int fps, ATVModInput atvModInput, Real uniformLevel, ATVModulation atvModulation, @@ -438,6 +450,8 @@ private: m_rfBandwidth(rfBandwidth), m_rfOppBandwidth(rfOppBandwidth), m_atvStd(atvStd), + m_nbLines(nbLines), + m_fps(fps), m_atvModInput(atvModInput), m_uniformLevel(uniformLevel), m_atvModulation(atvModulation), @@ -484,6 +498,8 @@ private: Real m_rfBandwidth; //!< Bandwidth of modulated signal or direct sideband for SSB / vestigial SSB Real m_rfOppBandwidth; //!< Bandwidth of opposite sideband for vestigial SSB ATVStd m_atvStd; //!< Standard + int m_nbLines; //!< Number of lines per full frame + int m_fps; //!< Number of frames per second ATVModInput m_atvModInput; //!< Input source type Real m_uniformLevel; //!< Percentage between black and white for uniform screen display ATVModulation m_atvModulation; //!< RF modulation type @@ -499,6 +515,8 @@ private: m_rfBandwidth(0), m_rfOppBandwidth(0), m_atvStd(ATVStdPAL625), + m_nbLines(625), + m_fps(25), m_atvModInput(ATVModInputHBars), m_uniformLevel(0.5f), m_atvModulation(ATVModulationAM), diff --git a/plugins/channeltx/modatv/atvmodgui.cpp b/plugins/channeltx/modatv/atvmodgui.cpp index 90e3fcdfb..74442e0c5 100644 --- a/plugins/channeltx/modatv/atvmodgui.cpp +++ b/plugins/channeltx/modatv/atvmodgui.cpp @@ -241,6 +241,44 @@ void ATVModGUI::setRFFiltersSlidersRange(int sampleRate) } } +int ATVModGUI::getNbLines() +{ + switch(ui->nbLines->currentIndex()) + { + case 1: + return 525; + break; + case 2: + return 405; + break; + case 0: + default: + return 625; + break; + } +} + +int ATVModGUI::getFPS() +{ + switch(ui->fps->currentIndex()) + { + case 0: + return 30; + break; + case 2: + return 20; + break; + case 3: + return 16; + break; + case 1: + default: + return 25; + break; + } + +} + void ATVModGUI::handleSourceMessages() { Message* message; @@ -365,6 +403,17 @@ void ATVModGUI::on_rfOppBW_valueChanged(int value) applySettings(); } +void ATVModGUI::on_nbLines_currentIndexChanged(int index) +{ + applySettings(); +} + +void ATVModGUI::on_fps_currentIndexChanged(int index) +{ + applySettings(); +} + + void ATVModGUI::on_standard_currentIndexChanged(int index) { applySettings(); @@ -580,6 +629,8 @@ void ATVModGUI::applySettings() ui->rfBW->value() * m_rfSliderDivisor * 1.0f, ui->rfOppBW->value() * m_rfSliderDivisor * 1.0f, (ATVMod::ATVStd) ui->standard->currentIndex(), + getNbLines(), + getFPS(), (ATVMod::ATVModInput) ui->inputSelect->currentIndex(), ui->uniformLevel->value() / 100.0f, (ATVMod::ATVModulation) ui->modulation->currentIndex(), diff --git a/plugins/channeltx/modatv/atvmodgui.h b/plugins/channeltx/modatv/atvmodgui.h index c2d3eebcd..61d8d27b7 100644 --- a/plugins/channeltx/modatv/atvmodgui.h +++ b/plugins/channeltx/modatv/atvmodgui.h @@ -66,6 +66,8 @@ private slots: void on_modulation_currentIndexChanged(int index); void on_rfBW_valueChanged(int value); void on_rfOppBW_valueChanged(int value); + void on_nbLines_currentIndexChanged(int index); + void on_fps_currentIndexChanged(int index); void on_standard_currentIndexChanged(int index); void on_invertVideo_clicked(); void on_uniformLevel_valueChanged(int value); @@ -121,6 +123,8 @@ private: void updateWithStreamData(); void updateWithStreamTime(); void setRFFiltersSlidersRange(int sampleRate); + int getNbLines(); + int getFPS(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/modatv/atvmodgui.ui b/plugins/channeltx/modatv/atvmodgui.ui index 8fddcdd33..8eb76f621 100644 --- a/plugins/channeltx/modatv/atvmodgui.ui +++ b/plugins/channeltx/modatv/atvmodgui.ui @@ -6,7 +6,7 @@ 0 0 - 490 + 619 364 @@ -39,7 +39,7 @@ 0 10 - 480 + 611 341 @@ -391,23 +391,106 @@ - + + + L: + + + + + + + + 50 + 16777215 + + - TV standard + Lines per full frame - PAL625L + 625 - PAL525L + 525 - 525L20F + 405 + + + + + + + + F: + + + + + + + + 45 + 16777215 + + + + Frames per second + + + + 30 + + + + + 25 + + + + + 20 + + + + + 16 + + + + + + + + S: + + + + + + + + 70 + 16777215 + + + + TV standard scheme + + + + PAL625 + + + + + PAL525 @@ -417,6 +500,13 @@ + + + + Qt::Vertical + + +