Skip to content

Commit

Permalink
Add scrollbars around image and filter params to vhs tune, add format…
Browse files Browse the repository at this point in the history
… selection to command line option
  • Loading branch information
oyvindln committed Nov 13, 2023
1 parent 707b40d commit 1cb66cf
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 65 deletions.
119 changes: 68 additions & 51 deletions filter_tune/filter_tune.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
QScrollArea,
QSlider,
QSpinBox,
QStyleFactory,
QSizePolicy,
QTableWidgetItem,
QTextEdit,
Expand Down Expand Up @@ -136,6 +135,7 @@ def __init__(self, system, tape_format, fs, logger):
def change_format(self, system, tape_format, fs, logger):
self.fs = fs
self.sys_params, self.rf_params = get_format_params(system, tape_format, logger)
self.tape_format = tape_format
# TODO: THis default should be set elsewhere
self.sys_params["track_ire0_offset"] = self.sys_params.get(
"track_ire0_offset", [0, 0]
Expand All @@ -157,7 +157,7 @@ class VHStune(QDialog):
curFrameNr = 1
totalFrames = 2

def __init__(self, logger, parent=None):
def __init__(self, tape_format, logger, parent=None):
super(VHStune, self).__init__(
parent,
Qt.Window
Expand All @@ -167,21 +167,23 @@ def __init__(self, logger, parent=None):
)
self._logger = logger

self._format_params = FormatParams("PAL", "VHS", SAMPLE_RATE, logger)
self._format_params = FormatParams("PAL", tape_format, SAMPLE_RATE, logger)

self.originalPalette = QApplication.palette()

self.makeFilterParams()
self.createControlsGroupBox()
self.createFilterGroupBox()
self.createStyleGroupBox()
self.createRightArea()

mainLayout = QGridLayout()
leftLayout = QVBoxLayout()
leftLayout.addStrut(370)
# controls_area = QScrollArea(self.controlsGroupBox)
leftLayout.addWidget(self.controlsGroupBox)
leftLayout.addWidget(self.filterGroupBox)
leftLayout.addWidget(self.styleGroupBox)
filters_area = QScrollArea()
filters_area.setWidget(self.filterGroupBox)
leftLayout.addWidget(filters_area)
mainLayout.addLayout(leftLayout, 0, 0)
mainLayout.addLayout(self.rightLayout, 0, 1)
mainLayout.setRowStretch(0, 1)
Expand All @@ -198,6 +200,32 @@ def makeFilterParams(self):
rf_params = self._format_params.rf_params
self.filter_params = {
# "deemph_enable": { "value": True, "step": None, "desc": "Enable deemphasis", "onchange": [ self.applyFilter, self.drawImage ] },
"video_lpf_freq": {
"value": rf_params["video_lpf_freq"],
"step": 5000,
"min": 1000000,
"max": 8000000,
"desc": "Video low pass filter corner freq ({:.0f} Hz):",
"onchange": [
self.calcDeemphFilter,
self.applyDeemphFilter,
self.applyNLSVHSFilter,
self.drawImage,
],
},
"video_lpf_order": {
"value": rf_params["video_lpf_order"],
"step": 1,
"min": 1,
"max": 4,
"desc": "Video low pass filter order ({:.2f}):",
"onchange": [
self.calcDeemphFilter,
self.applyDeemphFilter,
self.applyNLSVHSFilter,
self.drawImage,
],
},
"deemph_mid": {
"value": rf_params["deemph_mid"],
"step": 5000,
Expand Down Expand Up @@ -246,7 +274,7 @@ def makeFilterParams(self):
"nonlinear_deemph_showonly": {
"value": False,
"step": None,
"desc": "Show only subtracted non-linear deemphasis part",
"desc": "Show only subtracted NL deemphasis part",
"onchange": [self.drawImage],
},
"nonlinear_highpass_freq": {
Expand Down Expand Up @@ -463,14 +491,24 @@ def loadImage(self):
pos += BLOCK_LEN - 2048

def calcDeemphFilter(self):
self.deemphFilter = compute_video_filters.gen_video_main_deemp_fft(
self.filter_params["deemph_gain"]["value"],
self.filter_params["deemph_mid"]["value"],
self.filter_params["deemph_q"]["value"],
self._format_params.fs,
(_, lpf) = compute_video_filters.gen_video_lpf(
self.filter_params["video_lpf_freq"]["value"],
self.filter_params["video_lpf_order"]["value"],
self._format_params.fs / 2.0,
BLOCK_LEN,
)

self.deemphFilter = (
compute_video_filters.gen_video_main_deemp_fft(
self.filter_params["deemph_gain"]["value"],
self.filter_params["deemph_mid"]["value"],
self.filter_params["deemph_q"]["value"],
self._format_params.fs,
BLOCK_LEN,
)
* lpf
)

def calcNLHPFilter(self):
self.NLHPFilter = compute_video_filters.gen_nonlinear_bandpass(
None,
Expand Down Expand Up @@ -627,15 +665,16 @@ def drawImage(self):
transformMode=Qt.FastTransformation,
)
self.dispLabel.setPixmap(pixmap)
self.dispLabel.resize(pixmap.width(), pixmap.height())

def createRightArea(self):
self.rightLayout = QGridLayout()
# scroll = QScrollArea()
# scroll.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
self.dispLabel = QLabel()
self.dispLabel.setSizePolicy(
QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding
)
self.dispLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
# self._disp_label_layout = QVBoxLayout()
# self.dispLabel.setLayout(self._disp_label_layout)
# scroll.setWidget(self.dispLabel)
self.frameSlider = QSlider(Qt.Horizontal, self)

Expand Down Expand Up @@ -665,7 +704,10 @@ def createRightArea(self):
btnLayout.addWidget(stepFwdBtn)
btnLayout.addWidget(skipFwdBtn)
# self.rightLayout.addWidget(scroll, 0, 0)
self.rightLayout.addWidget(self.dispLabel, 0, 0)
self._disp_scroll_area = QScrollArea()
self._disp_scroll_area.setWidget(self.dispLabel)

self.rightLayout.addWidget(self._disp_scroll_area, 0, 0)
self.rightLayout.addWidget(self.frameSlider, 1, 0)
self.rightLayout.addLayout(btnLayout, 2, 0)
self.rightLayout.setRowStretch(0, 1)
Expand All @@ -690,7 +732,9 @@ def createControlsGroupBox(self):

self.systemComboBox = QComboBox()
supported_tape_formats_list = list(supported_tape_formats)
index_of_vhs = supported_tape_formats_list.index("VHS")
index_of_vhs = supported_tape_formats_list.index(
self._format_params.tape_format
)
self.systemComboBox.addItems(supported_tape_formats_list)
self.systemComboBox.setCurrentIndex(index_of_vhs)
self.systemComboBox.currentIndexChanged.connect(self._change_format)
Expand Down Expand Up @@ -738,7 +782,8 @@ def createControlsGroupBox(self):

self.displayWidthSlider = QSlider(Qt.Horizontal, self.controlsGroupBox)
self.displayWidthSlider.setRange(1, 200)
self.displayWidthSlider.setValue(50)
self.displayWidthSlider.setValue(100)
self.displayWidthSlider.setTracking(False)
self.displayWidthSlider.setTickPosition(QSlider.TicksBelow)
self.displayWidthSlider.valueChanged.connect(self.drawImage)

Expand All @@ -751,6 +796,7 @@ def createControlsGroupBox(self):
self.displayHeightSlider = QSlider(Qt.Horizontal, self.controlsGroupBox)
self.displayHeightSlider.setRange(1, 5)
self.displayHeightSlider.setValue(1)
self.displayHeightSlider.setTracking(False)
self.displayHeightSlider.setTickPosition(QSlider.TicksBelow)
self.displayHeightSlider.valueChanged.connect(self.drawImage)

Expand Down Expand Up @@ -799,44 +845,15 @@ def createFilterGroupBox(self):
layout.addStretch(1)
self.filterGroupBox.setLayout(layout)

def createStyleGroupBox(self):
self.styleGroupBox = QGroupBox("Style")
layout = QVBoxLayout()

styleComboBox = QComboBox()
styleComboBox.addItems(QStyleFactory.keys())

styleLabel = QLabel("&Style:")
styleLabel.setBuddy(styleComboBox)

self.useStylePaletteCheckBox = QCheckBox("&Use style's standard palette")
self.useStylePaletteCheckBox.setChecked(True)

styleComboBox.activated[str].connect(self.changeStyle)
self.useStylePaletteCheckBox.toggled.connect(self.changePalette)

layout.addWidget(styleLabel)
layout.addWidget(styleComboBox)
layout.addWidget(self.useStylePaletteCheckBox)

self.styleGroupBox.setLayout(layout)

def changeStyle(self, styleName):
QApplication.setStyle(QStyleFactory.create(styleName))
self.changePalette()

def changePalette(self):
if self.useStylePaletteCheckBox.isChecked():
QApplication.setPalette(QApplication.style().standardPalette())
else:
QApplication.setPalette(self.originalPalette)


def main():
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
app = QApplication(sys.argv)
logger = logging.getLogger("vhstune")
vhsTune = VHStune(logger)
tape_format = "VHS"
if len(sys.argv) > 1:
tape_format = sys.argv[1]
vhsTune = VHStune(tape_format, logger)
vhsTune.show()
pos = vhsTune.pos()
if pos.x() < 0 or pos.y() < 0:
Expand Down
10 changes: 7 additions & 3 deletions vhsdecode/compute_video_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,21 @@ def gen_video_main_deemp_fft(gain, mid, Q, freq_hz, block_len):
filter_deemp = filtfft((db, da), block_len, whole=False)
return filter_deemp


def gen_video_lpf(rf_params, nyquist_hz, block_len):
def gen_video_lpf(corner_freq, order, nyquist_hz, block_len):
"""Generate real-value fir and fft post-demodulation low pass filters from parameters"""
video_lpf = sps.butter(
rf_params["video_lpf_order"], rf_params["video_lpf_freq"] / nyquist_hz, "low"
order, corner_freq / nyquist_hz, "low"
)

video_lpf_fft = filtfft(video_lpf, block_len, False)
return (video_lpf, video_lpf_fft)


def gen_video_lpf_params(rf_params, nyquist_hz, block_len):
"""Generate real-value fir and fft post-demodulation low pass filters from parameters"""
return gen_video_lpf(rf_params["video_lpf_freq"], rf_params["video_lpf_order"], nyquist_hz, block_len)


def gen_nonlinear_bandpass_params(rf_params, nyquist_hz, block_len):
"""Generate bandpass or highpass real-value fft filter used for non-linear filtering."""
upper_freq = rf_params.get("nonlinear_bandpass_upper", None)
Expand Down
25 changes: 14 additions & 11 deletions vhsdecode/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from vhsdecode.nonlinear_filter import sub_deemphasis
from vhsdecode.compute_video_filters import (
gen_video_main_deemp_fft_params,
gen_video_lpf,
gen_video_lpf_params,
gen_nonlinear_bandpass_params,
create_sub_emphasis_params,
)
Expand Down Expand Up @@ -906,7 +906,7 @@ def _computevideofilters_b(self):
# Video (luma) main de-emphasis
filter_deemp = gen_video_main_deemp_fft_params(DP, self.freq_hz, self.blocklen)

(video_lpf, filter_video_lpf) = gen_video_lpf(
(video_lpf, filter_video_lpf) = gen_video_lpf_params(
DP, self.freq_hz_half, self.blocklen
)

Expand Down Expand Up @@ -1037,15 +1037,6 @@ def demodblock(
# FM demodulator
demod = unwrap_hilbert(hilbert, self.freq_hz).real

if self._chroma_trap:
# applies the Subcarrier trap
demod = self.chromaTrap.work(demod)

# Disabled if sharpness level is zero (default).
if self._video_eq:
# applies the video EQ
demod = self._video_eq.filter_video(demod)

# If there are obviously out of bounds values, do an extra demod on a diffed waveform and
# replace the spikes with data from the diffed demod.
if not self._disable_diff_demod:
Expand All @@ -1063,6 +1054,18 @@ def demodblock(
# more
if False:
demod = smooth_spikes(demod, check_value * 2.2)

# Disabled if sharpness level is zero (default).
# TODO: This should be done after the deemphasis steps
if self._video_eq:
# applies the video EQ
demod = self._video_eq.filter_video(demod)

# TODO: This should be done after the deemphasis steps
if self._chroma_trap:
# applies the Subcarrier trap
demod = self.chromaTrap.work(demod)

# applies main deemphasis filter
demod_fft = npfft.rfft(demod)
out_video_fft = demod_fft * self.Filters["FVideo"]
Expand Down

0 comments on commit 1cb66cf

Please sign in to comment.