1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-13 11:51:47 -05:00

ATV Modulator: implemented independent number of lines and FPS settings

This commit is contained in:
f4exb 2017-03-21 03:56:01 +01:00
parent cba85d2ef1
commit f9f0c53168
5 changed files with 228 additions and 97 deletions

View File

@ -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)

View File

@ -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<int>& 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),

View File

@ -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(),

View File

@ -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*);

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>490</width>
<width>619</width>
<height>364</height>
</rect>
</property>
@ -39,7 +39,7 @@
<rect>
<x>0</x>
<y>10</y>
<width>480</width>
<width>611</width>
<height>341</height>
</rect>
</property>
@ -391,23 +391,106 @@
<item>
<layout class="QHBoxLayout" name="recordFileSelectLayout">
<item>
<widget class="QComboBox" name="standard">
<widget class="QLabel" name="nbLinesLabel">
<property name="text">
<string>L:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="nbLines">
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>TV standard</string>
<string>Lines per full frame</string>
</property>
<item>
<property name="text">
<string>PAL625L</string>
<string>625</string>
</property>
</item>
<item>
<property name="text">
<string>PAL525L</string>
<string>525</string>
</property>
</item>
<item>
<property name="text">
<string>525L20F</string>
<string>405</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="fpsLabel">
<property name="text">
<string>F:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="fps">
<property name="maximumSize">
<size>
<width>45</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Frames per second</string>
</property>
<item>
<property name="text">
<string>30</string>
</property>
</item>
<item>
<property name="text">
<string>25</string>
</property>
</item>
<item>
<property name="text">
<string>20</string>
</property>
</item>
<item>
<property name="text">
<string>16</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="standardLabel">
<property name="text">
<string>S:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="standard">
<property name="maximumSize">
<size>
<width>70</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>TV standard scheme</string>
</property>
<item>
<property name="text">
<string>PAL625</string>
</property>
</item>
<item>
<property name="text">
<string>PAL525</string>
</property>
</item>
<item>
@ -417,6 +500,13 @@
</item>
</widget>
</item>
<item>
<widget class="Line" name="line_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="inputSelect">
<property name="toolTip">