From b6b45d12702f18f041acf65b0d5e34714835ecb4 Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 30 Jul 2017 13:04:02 -0400 Subject: added Spectrum component with many options tweaked Waveform, added some ffmpeg logging, made generic widget functions --- src/components/spectrum.py | 239 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 src/components/spectrum.py (limited to 'src/components/spectrum.py') diff --git a/src/components/spectrum.py b/src/components/spectrum.py new file mode 100644 index 0000000..261d9cc --- /dev/null +++ b/src/components/spectrum.py @@ -0,0 +1,239 @@ +from PIL import Image +from PyQt5 import QtGui, QtCore, QtWidgets +from PyQt5.QtGui import QColor +import os +import math +import subprocess +import time + +from component import Component +from toolkit.frame import BlankFrame, scale +from toolkit import checkOutput, rgbFromString, pickColor, connectWidget +from toolkit.ffmpeg import ( + openPipe, closePipe, getAudioDuration, FfmpegVideo, exampleSound +) + + +class Component(Component): + name = 'Spectrum' + version = '1.0.0' + + def widget(self, *args): + self.color = (255, 255, 255) + self.previewFrame = None + super().widget(*args) + self.chunkSize = 4 * self.width * self.height + self.changedOptions = True + + if hasattr(self.parent, 'window'): + # update preview when audio file changes (if genericPreview is off) + self.parent.window.lineEdit_audioFile.textChanged.connect( + self.update + ) + + self.trackWidgets( + { + 'filterType': self.page.comboBox_filterType, + 'window': self.page.comboBox_window, + 'amplitude': self.page.comboBox_amplitude, + 'x': self.page.spinBox_x, + 'y': self.page.spinBox_y, + 'mirror': self.page.checkBox_mirror, + 'scale': self.page.spinBox_scale, + 'color': self.page.comboBox_color, + 'compress': self.page.checkBox_compress, + 'mono': self.page.checkBox_mono, + } + ) + for widget in self._trackedWidgets.values(): + connectWidget(widget, lambda: self.changed()) + + def changed(self): + self.changedOptions = True + + def update(self): + count = self.page.stackedWidget.count() + i = self.page.comboBox_filterType.currentIndex() + self.page.stackedWidget.setCurrentIndex(i if i < count else count - 1) + super().update() + + def previewRender(self): + changedSize = self.updateChunksize() + if not changedSize \ + and not self.changedOptions \ + and self.previewFrame is not None: + return self.previewFrame + + frame = self.getPreviewFrame() + self.changedOptions = False + if not frame: + self.previewFrame = None + return BlankFrame(self.width, self.height) + else: + self.previewFrame = frame + return frame + + def preFrameRender(self, **kwargs): + super().preFrameRender(**kwargs) + self.updateChunksize() + w, h = scale(self.scale, self.width, self.height, str) + self.video = FfmpegVideo( + inputPath=self.audioFile, + filter_=self.makeFfmpegFilter(), + width=w, height=h, + chunkSize=self.chunkSize, + frameRate=int(self.settings.value("outputFrameRate")), + parent=self.parent, component=self, + ) + + def frameRender(self, frameNo): + if FfmpegVideo.threadError is not None: + raise FfmpegVideo.threadError + return self.finalizeFrame(self.video.frame(frameNo)) + + def postFrameRender(self): + closePipe(self.video.pipe) + + def getPreviewFrame(self): + genericPreview = self.settings.value("pref_genericPreview") + startPt = 0 + if not genericPreview: + inputFile = self.parent.window.lineEdit_audioFile.text() + if not inputFile or not os.path.exists(inputFile): + return + duration = getAudioDuration(inputFile) + if not duration: + return + startPt = duration / 3 + + command = [ + self.core.FFMPEG_BIN, + '-thread_queue_size', '512', + '-r', self.settings.value("outputFrameRate"), + '-ss', "{0:.3f}".format(startPt), + '-i', + os.path.join(self.core.wd, 'background.png') + if genericPreview else inputFile, + '-f', 'image2pipe', + '-pix_fmt', 'rgba', + ] + command.extend(self.makeFfmpegFilter(preview=True, startPt=startPt)) + command.extend([ + '-an', + '-s:v', '%sx%s' % scale(self.scale, self.width, self.height, str), + '-codec:v', 'rawvideo', '-', + '-frames:v', '1', + ]) + logFilename = os.path.join( + self.core.dataDir, 'preview_%s.log' % str(self.compPos)) + with open(logFilename, 'w') as log: + log.write(" ".join(command) + '\n\n') + with open(logFilename, 'a') as log: + pipe = openPipe( + command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, + stderr=log, bufsize=10**8 + ) + byteFrame = pipe.stdout.read(self.chunkSize) + closePipe(pipe) + + frame = self.finalizeFrame(byteFrame) + return frame + + def makeFfmpegFilter(self, preview=False, startPt=0): + w, h = scale(self.scale, self.width, self.height, str) + if self.amplitude == 0: + amplitude = 'sqrt' + elif self.amplitude == 1: + amplitude = 'cbrt' + elif self.amplitude == 2: + amplitude = '4thrt' + elif self.amplitude == 3: + amplitude = '5thrt' + elif self.amplitude == 4: + amplitude = 'lin' + elif self.amplitude == 5: + amplitude = 'log' + color = self.page.comboBox_color.currentText().lower() + genericPreview = self.settings.value("pref_genericPreview") + + if self.filterType == 0: # Spectrum + filter_ = ( + 'showspectrum=s=%sx%s:slide=scroll:win_func=%s:' + 'color=%s:scale=%s' % ( + self.settings.value("outputWidth"), + self.settings.value("outputHeight"), + self.page.comboBox_window.currentText(), + color, amplitude, + ) + ) + elif self.filterType == 1: # Histogram + filter_ = ( + 'ahistogram=r=%s:s=%sx%s:dmode=separate' % ( + self.settings.value("outputFrameRate"), + self.settings.value("outputWidth"), + self.settings.value("outputHeight"), + ) + ) + elif self.filterType == 2: # Vector Scope + filter_ = ( + 'avectorscope=s=%sx%s:draw=line:m=polar:scale=log' % ( + self.settings.value("outputWidth"), + self.settings.value("outputHeight"), + ) + ) + elif self.filterType == 3: # Musical Scale + filter_ = ( + 'showcqt=r=%s:s=%sx%s:count=30:text=0' % ( + self.settings.value("outputFrameRate"), + self.settings.value("outputWidth"), + self.settings.value("outputHeight"), + ) + ) + elif self.filterType == 4: # Phase + filter_ = ( + 'aphasemeter=r=%s:s=%sx%s:mpc=white:video=1[atrash][vtmp]; ' + '[atrash] anullsink; [vtmp] null' % ( + self.settings.value("outputFrameRate"), + self.settings.value("outputWidth"), + self.settings.value("outputHeight"), + ) + ) + + return [ + '-filter_complex', + '%s%s%s%s%s [v1]; ' + '[v1] scale=%s:%s%s [v]' % ( + exampleSound() if preview and genericPreview else '[0:a] ', + 'compand=gain=4,' if self.compress else '', + 'aformat=channel_layouts=mono,' if self.mono else '', + filter_, + ', hflip' if self.mirror else'', + w, h, + ', trim=start=%s:end=%s' % ( + "{0:.3f}".format(startPt + 15), + "{0:.3f}".format(startPt + 15.5) + ) if preview else '', + ), + '-map', '[v]', + ] + + def updateChunksize(self): + width, height = scale(self.scale, self.width, self.height, int) + oldChunkSize = int(self.chunkSize) + self.chunkSize = 4 * width * height + changed = self.chunkSize != oldChunkSize + return changed + + def finalizeFrame(self, imageData): + image = Image.frombytes( + 'RGBA', + scale(self.scale, self.width, self.height, int), + imageData + ) + if self.scale != 100 \ + or self.x != 0 or self.y != 0: + frame = BlankFrame(self.width, self.height) + frame.paste(image, box=(self.x, self.y)) + else: + frame = image + return frame -- cgit v1.2.3 From 65420ce2855a24d54755a7a47804c2fb5f6d427e Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 30 Jul 2017 21:29:06 -0400 Subject: more options for the Spectrum component --- src/component.py | 2 +- src/components/spectrum.py | 99 ++++++++---- src/components/spectrum.ui | 370 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 437 insertions(+), 34 deletions(-) (limited to 'src/components/spectrum.py') diff --git a/src/component.py b/src/component.py index 1a5a5a4..36ad9d3 100644 --- a/src/component.py +++ b/src/component.py @@ -427,7 +427,7 @@ class ComponentError(RuntimeError): name, 'an' if any([ sys.exc_info()[0].__name__.startswith(vowel) - for vowel in ('A', 'I') + for vowel in ('A', 'I', 'U', 'O', 'E') ]) else 'a', sys.exc_info()[0].__name__, str(sys.exc_info()[1]) diff --git a/src/components/spectrum.py b/src/components/spectrum.py index 261d9cc..d1ad297 100644 --- a/src/components/spectrum.py +++ b/src/components/spectrum.py @@ -1,6 +1,5 @@ from PIL import Image from PyQt5 import QtGui, QtCore, QtWidgets -from PyQt5.QtGui import QColor import os import math import subprocess @@ -8,7 +7,7 @@ import time from component import Component from toolkit.frame import BlankFrame, scale -from toolkit import checkOutput, rgbFromString, pickColor, connectWidget +from toolkit import checkOutput, connectWidget from toolkit.ffmpeg import ( openPipe, closePipe, getAudioDuration, FfmpegVideo, exampleSound ) @@ -19,7 +18,6 @@ class Component(Component): version = '1.0.0' def widget(self, *args): - self.color = (255, 255, 255) self.previewFrame = None super().widget(*args) self.chunkSize = 4 * self.width * self.height @@ -35,14 +33,22 @@ class Component(Component): { 'filterType': self.page.comboBox_filterType, 'window': self.page.comboBox_window, - 'amplitude': self.page.comboBox_amplitude, + 'mode': self.page.comboBox_mode, + 'amplitude': self.page.comboBox_amplitude0, + 'amplitude1': self.page.comboBox_amplitude1, + 'amplitude2': self.page.comboBox_amplitude2, + 'display': self.page.comboBox_display, + 'zoom': self.page.spinBox_zoom, + 'tc': self.page.spinBox_tc, 'x': self.page.spinBox_x, 'y': self.page.spinBox_y, 'mirror': self.page.checkBox_mirror, + 'draw': self.page.checkBox_draw, 'scale': self.page.spinBox_scale, 'color': self.page.comboBox_color, 'compress': self.page.checkBox_compress, 'mono': self.page.checkBox_mono, + 'hue': self.page.spinBox_hue, } ) for widget in self._trackedWidgets.values(): @@ -52,9 +58,8 @@ class Component(Component): self.changedOptions = True def update(self): - count = self.page.stackedWidget.count() - i = self.page.comboBox_filterType.currentIndex() - self.page.stackedWidget.setCurrentIndex(i if i < count else count - 1) + self.page.stackedWidget.setCurrentIndex( + self.page.comboBox_filterType.currentIndex()) super().update() def previewRender(self): @@ -141,25 +146,26 @@ class Component(Component): def makeFfmpegFilter(self, preview=False, startPt=0): w, h = scale(self.scale, self.width, self.height, str) - if self.amplitude == 0: - amplitude = 'sqrt' - elif self.amplitude == 1: - amplitude = 'cbrt' - elif self.amplitude == 2: - amplitude = '4thrt' - elif self.amplitude == 3: - amplitude = '5thrt' - elif self.amplitude == 4: - amplitude = 'lin' - elif self.amplitude == 5: - amplitude = 'log' color = self.page.comboBox_color.currentText().lower() genericPreview = self.settings.value("pref_genericPreview") if self.filterType == 0: # Spectrum + if self.amplitude == 0: + amplitude = 'sqrt' + elif self.amplitude == 1: + amplitude = 'cbrt' + elif self.amplitude == 2: + amplitude = '4thrt' + elif self.amplitude == 3: + amplitude = '5thrt' + elif self.amplitude == 4: + amplitude = 'lin' + elif self.amplitude == 5: + amplitude = 'log' filter_ = ( 'showspectrum=s=%sx%s:slide=scroll:win_func=%s:' - 'color=%s:scale=%s' % ( + 'color=%s:scale=%s,' + 'colorkey=color=black:similarity=0.1:blend=0.5' % ( self.settings.value("outputWidth"), self.settings.value("outputHeight"), self.page.comboBox_window.currentText(), @@ -167,32 +173,61 @@ class Component(Component): ) ) elif self.filterType == 1: # Histogram + if self.amplitude1 == 0: + amplitude = 'log' + elif self.amplitude1 == 1: + amplitude = 'lin' + if self.display == 0: + display = 'log' + elif self.display == 1: + display = 'sqrt' + elif self.display == 2: + display = 'cbrt' + elif self.display == 3: + display = 'lin' + elif self.display == 4: + display = 'rlog' filter_ = ( - 'ahistogram=r=%s:s=%sx%s:dmode=separate' % ( + 'ahistogram=r=%s:s=%sx%s:dmode=separate:ascale=%s:scale=%s' % ( self.settings.value("outputFrameRate"), self.settings.value("outputWidth"), self.settings.value("outputHeight"), + amplitude, display ) ) elif self.filterType == 2: # Vector Scope + if self.amplitude2 == 0: + amplitude = 'log' + elif self.amplitude2 == 1: + amplitude = 'sqrt' + elif self.amplitude2 == 2: + amplitude = 'cbrt' + elif self.amplitude2 == 3: + amplitude = 'lin' + m = self.page.comboBox_mode.currentText() filter_ = ( - 'avectorscope=s=%sx%s:draw=line:m=polar:scale=log' % ( + 'avectorscope=s=%sx%s:draw=%s:m=%s:scale=%s:zoom=%s' % ( self.settings.value("outputWidth"), self.settings.value("outputHeight"), + 'line'if self.draw else 'dot', + m, amplitude, str(self.zoom), ) ) elif self.filterType == 3: # Musical Scale filter_ = ( - 'showcqt=r=%s:s=%sx%s:count=30:text=0' % ( + 'showcqt=r=%s:s=%sx%s:count=30:text=0:tc=%s,' + 'colorkey=color=black:similarity=0.1:blend=0.5 ' % ( self.settings.value("outputFrameRate"), self.settings.value("outputWidth"), self.settings.value("outputHeight"), + str(self.tc), ) ) elif self.filterType == 4: # Phase filter_ = ( - 'aphasemeter=r=%s:s=%sx%s:mpc=white:video=1[atrash][vtmp]; ' - '[atrash] anullsink; [vtmp] null' % ( + 'aphasemeter=r=%s:s=%sx%s:video=1 [atrash][vtmp1]; ' + '[atrash] anullsink; ' + '[vtmp1] colorkey=color=black:similarity=0.1:blend=0.5 ' % ( self.settings.value("outputFrameRate"), self.settings.value("outputWidth"), self.settings.value("outputHeight"), @@ -201,18 +236,22 @@ class Component(Component): return [ '-filter_complex', - '%s%s%s%s%s [v1]; ' - '[v1] scale=%s:%s%s [v]' % ( + '%s%s%s%s [v1]; ' + '[v1] %sscale=%s:%s%s%s%s [v]' % ( exampleSound() if preview and genericPreview else '[0:a] ', 'compand=gain=4,' if self.compress else '', 'aformat=channel_layouts=mono,' if self.mono else '', filter_, - ', hflip' if self.mirror else'', + 'hflip, ' if self.mirror else '', w, h, + ', hue=h=%s:s=10' % str(self.hue) if self.hue > 0 else '', ', trim=start=%s:end=%s' % ( - "{0:.3f}".format(startPt + 15), - "{0:.3f}".format(startPt + 15.5) + "{0:.3f}".format(startPt + 12), + "{0:.3f}".format(startPt + 12.5) ) if preview else '', + ', convolution=-2 -1 0 -1 1 1 0 1 2:-2 -1 0 -1 1 1 0 1 2:-2 ' + '-1 0 -1 1 1 0 1 2:-2 -1 0 -1 1 1 0 1 2' + if self.filterType == 3 else '' ), '-map', '[v]', ] diff --git a/src/components/spectrum.ui b/src/components/spectrum.ui index 59ca0b8..c6a8a15 100644 --- a/src/components/spectrum.ui +++ b/src/components/spectrum.ui @@ -31,6 +31,9 @@ 4 + + + @@ -208,6 +211,26 @@ + + + + Hue + + + 4 + + + + + + + ° + + + 359 + + + @@ -272,7 +295,7 @@ 0 0 561 - 72 + 66 @@ -415,7 +438,7 @@ - + Square root @@ -554,7 +577,348 @@ - + + + + + -1 + -1 + 561 + 31 + + + + + + + + + + 0 + 0 + + + + Display Scale + + + 4 + + + + + + + + Logarithmic + + + + + Square root + + + + + Cubic root + + + + + Linear + + + + + Reverse Log + + + + + + + + + 0 + 0 + + + + Amplitude + + + 4 + + + + + + + + Logarithmic + + + + + Linear + + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 40 + 20 + + + + + + + + + + + + + + -1 + -1 + 585 + 64 + + + + + + + + + Mode + + + + + + + + lissajous + + + + + lissajous_xy + + + + + polar + + + + + + + + + 0 + 0 + + + + Amplitude + + + 4 + + + + + + + + Linear + + + + + Square root + + + + + Cubic root + + + + + Logarithmic + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + Zoom + + + 4 + + + + + + + 1 + + + 10 + + + + + + + Line + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + 0 + 0 + 561 + 31 + + + + + + + + + + 0 + 0 + + + + Timeclamp + + + 4 + + + + + + + s + + + 3 + + + 0.002000000000000 + + + 1.000000000000000 + + + 0.010000000000000 + + + 0.017000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + 0 + 0 + 551 + 31 + + + + + + + + + -- cgit v1.2.3 From a472246dab69d0676c3c78ecd61659e432c960b4 Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 30 Jul 2017 21:59:42 -0400 Subject: crop aphasermeter so it scales to look bigger --- src/components/spectrum.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/components/spectrum.py') diff --git a/src/components/spectrum.py b/src/components/spectrum.py index d1ad297..8ab8404 100644 --- a/src/components/spectrum.py +++ b/src/components/spectrum.py @@ -227,7 +227,8 @@ class Component(Component): filter_ = ( 'aphasemeter=r=%s:s=%sx%s:video=1 [atrash][vtmp1]; ' '[atrash] anullsink; ' - '[vtmp1] colorkey=color=black:similarity=0.1:blend=0.5 ' % ( + '[vtmp1] colorkey=color=black:similarity=0.1:blend=0.5, ' + 'crop=in_w/8:in_h:(in_w/8)*7:0 '% ( self.settings.value("outputFrameRate"), self.settings.value("outputWidth"), self.settings.value("outputHeight"), -- cgit v1.2.3 From 5784cdbcf87556b61519782cd1fc27065ffbc631 Mon Sep 17 00:00:00 2001 From: tassaron Date: Tue, 1 Aug 2017 21:57:36 -0400 Subject: x/y pixel values update to match output resolution --- src/component.py | 39 ++++++++++++++++++++++++++++++++++++--- src/components/color.py | 3 +++ src/components/image.py | 3 +++ src/components/original.py | 2 ++ src/components/spectrum.py | 3 +++ src/components/text.py | 19 +++++++++++-------- src/components/video.py | 3 +++ src/components/waveform.py | 3 +++ src/mainwindow.py | 5 ++++- 9 files changed, 68 insertions(+), 12 deletions(-) (limited to 'src/components/spectrum.py') diff --git a/src/component.py b/src/component.py index d47aeae..5dfe2ab 100644 --- a/src/component.py +++ b/src/component.py @@ -6,6 +6,7 @@ from PyQt5 import uic, QtCore, QtWidgets from PyQt5.QtGui import QColor import os import sys +import math import time from toolkit.frame import BlankFrame @@ -176,7 +177,9 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): self._presetNames = {} self._commandArgs = {} self._colorWidgets = {} + self._colorFuncs = {} self._relativeWidgets = {} + self._relativeValues = {} self._lockedProperties = None self._lockedError = None @@ -291,14 +294,44 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): ''' for attr, widget in self._trackedWidgets.items(): if attr in self._colorWidgets: + # Color Widgets: text stored as tuple & update the button color rgbTuple = rgbFromString(widget.text()) - setattr(self, attr, rgbTuple) btnStyle = ( "QPushButton { background-color : %s; outline: none; }" - % QColor(*rgbTuple).name() - ) + % QColor(*rgbTuple).name()) self._colorWidgets[attr].setStyleSheet(btnStyle) + setattr(self, attr, rgbTuple) + + elif attr in self._relativeWidgets: + # Relative widgets: number scales to fit export resolution + if self._relativeWidgets[attr] == 'x': + dimension = self.width + else: + dimension = self.height + try: + oldUserValue = getattr(self, attr) + except AttributeError: + oldUserValue = self._trackedWidgets[attr].value() + newUserValue = self._trackedWidgets[attr].value() + newRelativeVal = newUserValue / dimension + + if attr in self._relativeValues: + if oldUserValue == newUserValue: + oldRelativeVal = self._relativeValues[attr] + if oldRelativeVal != newRelativeVal: + # Float changed without pixel value changing, which + # means the pixel value needs to be updated + self._trackedWidgets[attr].blockSignals(True) + self._trackedWidgets[attr].setValue( + math.ceil(dimension * oldRelativeVal)) + self._trackedWidgets[attr].blockSignals(False) + if oldUserValue != newUserValue \ + or attr not in self._relativeValues: + self._relativeValues[attr] = newRelativeVal + setattr(self, attr, self._trackedWidgets[attr].value()) + else: + # Normal tracked widget setattr(self, attr, getWidgetValue(widget)) if not self.core.openingProject: diff --git a/src/components/color.py b/src/components/color.py index d6fffc6..703caca 100644 --- a/src/components/color.py +++ b/src/components/color.py @@ -60,6 +60,9 @@ class Component(Component): }, colorWidgets={ 'color1': self.page.pushButton_color1, 'color2': self.page.pushButton_color2, + }, relativeWidgets={ + 'x': 'x', + 'y': 'y', }, ) diff --git a/src/components/image.py b/src/components/image.py index a96f127..2ffa5a1 100644 --- a/src/components/image.py +++ b/src/components/image.py @@ -28,6 +28,9 @@ class Component(Component): 'imagePath': 'image', 'xPosition': 'x', 'yPosition': 'y', + }, relativeWidgets={ + 'xPosition': 'x', + 'yPosition': 'y', }, ) diff --git a/src/components/original.py b/src/components/original.py index 950ac7b..67e3239 100644 --- a/src/components/original.py +++ b/src/components/original.py @@ -40,6 +40,8 @@ class Component(Component): 'y': self.page.spinBox_y, }, colorWidgets={ 'visColor': self.page.pushButton_visColor, + }, relativeWidgets={ + 'y': 'y', }) def previewRender(self): diff --git a/src/components/spectrum.py b/src/components/spectrum.py index 8ab8404..2cc641d 100644 --- a/src/components/spectrum.py +++ b/src/components/spectrum.py @@ -49,6 +49,9 @@ class Component(Component): 'compress': self.page.checkBox_compress, 'mono': self.page.checkBox_mono, 'hue': self.page.spinBox_hue, + }, relativeWidgets={ + 'x': 'x', + 'y': 'y', } ) for widget in self._trackedWidgets.values(): diff --git a/src/components/text.py b/src/components/text.py index 1fe3467..0f87038 100644 --- a/src/components/text.py +++ b/src/components/text.py @@ -17,15 +17,12 @@ class Component(Component): def widget(self, *args): super().widget(*args) - height = int(self.settings.value('outputHeight')) - width = int(self.settings.value('outputWidth')) + # height = int(self.settings.value('outputHeight')) + # width = int(self.settings.value('outputWidth')) self.textColor = (255, 255, 255) self.title = 'Text' self.alignment = 1 - self.fontSize = height / 13.5 - fm = QtGui.QFontMetrics(self.titleFont) - self.xPosition = width / 2 - fm.width(self.title)/2 - self.yPosition = height / 2 * 1.036 + self.fontSize = self.height / 13.5 self.page.comboBox_textAlign.addItem("Left") self.page.comboBox_textAlign.addItem("Middle") @@ -35,8 +32,11 @@ class Component(Component): self.page.lineEdit_title.setText(self.title) self.page.comboBox_textAlign.setCurrentIndex(int(self.alignment)) self.page.spinBox_fontSize.setValue(int(self.fontSize)) - self.page.spinBox_xTextAlign.setValue(int(self.xPosition)) - self.page.spinBox_yTextAlign.setValue(int(self.yPosition)) + + fm = QtGui.QFontMetrics(self.titleFont) + self.page.spinBox_xTextAlign.setValue( + self.width / 2 - fm.width(self.title)/2) + self.page.spinBox_yTextAlign.setValue(self.height / 2 * 1.036) self.page.fontComboBox_titleFont.currentFontChanged.connect( self.update @@ -50,6 +50,9 @@ class Component(Component): 'yPosition': self.page.spinBox_yTextAlign, }, colorWidgets={ 'textColor': self.page.pushButton_textColor, + }, relativeWidgets={ + 'xPosition': 'x', + 'yPosition': 'y', }) def update(self): diff --git a/src/components/video.py b/src/components/video.py index 6cd16e5..3569d17 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -38,6 +38,9 @@ class Component(Component): 'loopVideo': 'loop', 'xPosition': 'x', 'yPosition': 'y', + }, relativeWidgets={ + 'xPosition': 'x', + 'yPosition': 'y', } ) diff --git a/src/components/waveform.py b/src/components/waveform.py index 9c3cf86..a25116b 100644 --- a/src/components/waveform.py +++ b/src/components/waveform.py @@ -41,6 +41,9 @@ class Component(Component): 'mono': self.page.checkBox_mono, }, colorWidgets={ 'color': self.page.pushButton_color, + }, relativeWidgets={ + 'x': 'x', + 'y': 'y', } ) diff --git a/src/mainwindow.py b/src/mainwindow.py index d9e95e2..1c8806d 100644 --- a/src/mainwindow.py +++ b/src/mainwindow.py @@ -644,9 +644,12 @@ class MainWindow(QtWidgets.QMainWindow): def updateResolution(self): resIndex = int(self.window.comboBox_resolution.currentIndex()) res = Core.resolutions[resIndex].split('x') + changed = res[0] != self.settings.value("outputWidth") self.settings.setValue('outputWidth', res[0]) self.settings.setValue('outputHeight', res[1]) - self.drawPreview() + if changed: + for i in range(len(self.core.selectedComponents)): + self.core.updateComponent(i) def drawPreview(self, force=False, **kwargs): '''Use autosave keyword arg to force saving or not saving if needed''' -- cgit v1.2.3 From 6611492b30a7daf7bdbe77f6e12f9d322bdd90c1 Mon Sep 17 00:00:00 2001 From: tassaron Date: Thu, 3 Aug 2017 00:44:46 -0400 Subject: relative gradients & last good frame used for preview errors --- src/components/color.py | 5 +++++ src/components/spectrum.py | 15 ++++++++++----- src/components/text.py | 2 -- src/components/video.py | 15 ++++----------- src/components/waveform.py | 15 ++++++++++----- 5 files changed, 29 insertions(+), 23 deletions(-) (limited to 'src/components/spectrum.py') diff --git a/src/components/color.py b/src/components/color.py index 2b100d9..f5d618e 100644 --- a/src/components/color.py +++ b/src/components/color.py @@ -65,6 +65,11 @@ class Component(Component): 'y': 'y', 'sizeWidth': 'x', 'sizeHeight': 'y', + 'RG_start': 'x', + 'LG_start': 'x', + 'RG_end': 'x', + 'LG_end': 'x', + 'RG_centre': 'x', }, ) diff --git a/src/components/spectrum.py b/src/components/spectrum.py index 2cc641d..9a0c59a 100644 --- a/src/components/spectrum.py +++ b/src/components/spectrum.py @@ -20,6 +20,7 @@ class Component(Component): def widget(self, *args): self.previewFrame = None super().widget(*args) + self._image = BlankFrame(self.width, self.height) self.chunkSize = 4 * self.width * self.height self.changedOptions = True @@ -268,11 +269,15 @@ class Component(Component): return changed def finalizeFrame(self, imageData): - image = Image.frombytes( - 'RGBA', - scale(self.scale, self.width, self.height, int), - imageData - ) + try: + image = Image.frombytes( + 'RGBA', + scale(self.scale, self.width, self.height, int), + imageData + ) + self._image = image + except ValueError: + image = self._image if self.scale != 100 \ or self.x != 0 or self.y != 0: frame = BlankFrame(self.width, self.height) diff --git a/src/components/text.py b/src/components/text.py index be4de4a..2a5d433 100644 --- a/src/components/text.py +++ b/src/components/text.py @@ -17,8 +17,6 @@ class Component(Component): def widget(self, *args): super().widget(*args) - # height = int(self.settings.value('outputHeight')) - # width = int(self.settings.value('outputWidth')) self.textColor = (255, 255, 255) self.title = 'Text' self.alignment = 1 diff --git a/src/components/video.py b/src/components/video.py index 3569d17..2cd67c6 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -16,12 +16,12 @@ class Component(Component): def widget(self, *args): self.videoPath = '' - self.badVideo = False self.badAudio = False self.x = 0 self.y = 0 self.loopVideo = False super().widget(*args) + self._image = BlankFrame(self.width, self.height) self.page.pushButton_video.clicked.connect(self.pickVideo) self.trackWidgets( { @@ -70,8 +70,6 @@ class Component(Component): if not self.videoPath: self.lockError("There is no video selected.") - elif self.badVideo: - self.lockError("Could not identify an audio stream in this video.") elif not os.path.exists(self.videoPath): self.lockError("The video selected does not exist!") elif os.path.realpath(self.videoPath) == os.path.realpath(outputFile): @@ -199,14 +197,10 @@ class Component(Component): 'RGBA', scale(self.scale, self.width, self.height, int), imageData) - + self._image = image except ValueError: - print( - '### BAD VIDEO SELECTED ###\n' - 'Video will not export with these settings' - ) - self.badVideo = True - return BlankFrame(self.width, self.height) + # use last good frame + image = self._image if self.scale != 100 \ or self.xPosition != 0 or self.yPosition != 0: @@ -214,5 +208,4 @@ class Component(Component): frame.paste(image, box=(self.xPosition, self.yPosition)) else: frame = image - self.badVideo = False return frame diff --git a/src/components/waveform.py b/src/components/waveform.py index a25116b..526e6fb 100644 --- a/src/components/waveform.py +++ b/src/components/waveform.py @@ -19,6 +19,7 @@ class Component(Component): def widget(self, *args): super().widget(*args) + self._image = BlankFrame(self.width, self.height) self.page.lineEdit_color.setText('255,255,255') @@ -178,11 +179,15 @@ class Component(Component): self.chunkSize = 4 * width * height def finalizeFrame(self, imageData): - image = Image.frombytes( - 'RGBA', - scale(self.scale, self.width, self.height, int), - imageData - ) + try: + image = Image.frombytes( + 'RGBA', + scale(self.scale, self.width, self.height, int), + imageData + ) + self._image = image + except ValueError: + image = self._image if self.scale != 100 \ or self.x != 0 or self.y != 0: frame = BlankFrame(self.width, self.height) -- cgit v1.2.3 From 219e846984bb10e9674432fa7aeac4157635c743 Mon Sep 17 00:00:00 2001 From: tassaron Date: Thu, 3 Aug 2017 12:16:57 -0400 Subject: relativeWidgets might as well be a list --- src/component.py | 5 +--- src/components/color.py | 63 +++++++++++++++++++++------------------------- src/components/image.py | 36 ++++++++++++-------------- src/components/original.py | 6 ++--- src/components/spectrum.py | 47 ++++++++++++++++------------------ src/components/text.py | 8 +++--- src/components/video.py | 37 +++++++++++++-------------- src/components/waveform.py | 35 ++++++++++++-------------- 8 files changed, 106 insertions(+), 131 deletions(-) (limited to 'src/components/spectrum.py') diff --git a/src/component.py b/src/component.py index 5dfe2ab..c5bc44b 100644 --- a/src/component.py +++ b/src/component.py @@ -304,10 +304,7 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass): elif attr in self._relativeWidgets: # Relative widgets: number scales to fit export resolution - if self._relativeWidgets[attr] == 'x': - dimension = self.width - else: - dimension = self.height + dimension = self.width try: oldUserValue = getattr(self, attr) except AttributeError: diff --git a/src/components/color.py b/src/components/color.py index f5d618e..5d1233e 100644 --- a/src/components/color.py +++ b/src/components/color.py @@ -37,41 +37,34 @@ class Component(Component): self.page.comboBox_fill.addItem(label) self.page.comboBox_fill.setCurrentIndex(0) - self.trackWidgets( - { - 'x': self.page.spinBox_x, - 'y': self.page.spinBox_y, - 'sizeWidth': self.page.spinBox_width, - 'sizeHeight': self.page.spinBox_height, - 'trans': self.page.checkBox_trans, - 'spread': self.page.comboBox_spread, - 'stretch': self.page.checkBox_stretch, - 'RG_start': self.page.spinBox_radialGradient_start, - 'LG_start': self.page.spinBox_linearGradient_start, - 'RG_end': self.page.spinBox_radialGradient_end, - 'LG_end': self.page.spinBox_linearGradient_end, - 'RG_centre': self.page.spinBox_radialGradient_spread, - 'fillType': self.page.comboBox_fill, - 'color1': self.page.lineEdit_color1, - 'color2': self.page.lineEdit_color2, - }, presetNames={ - 'sizeWidth': 'width', - 'sizeHeight': 'height', - }, colorWidgets={ - 'color1': self.page.pushButton_color1, - 'color2': self.page.pushButton_color2, - }, relativeWidgets={ - 'x': 'x', - 'y': 'y', - 'sizeWidth': 'x', - 'sizeHeight': 'y', - 'RG_start': 'x', - 'LG_start': 'x', - 'RG_end': 'x', - 'LG_end': 'x', - 'RG_centre': 'x', - }, - ) + self.trackWidgets({ + 'x': self.page.spinBox_x, + 'y': self.page.spinBox_y, + 'sizeWidth': self.page.spinBox_width, + 'sizeHeight': self.page.spinBox_height, + 'trans': self.page.checkBox_trans, + 'spread': self.page.comboBox_spread, + 'stretch': self.page.checkBox_stretch, + 'RG_start': self.page.spinBox_radialGradient_start, + 'LG_start': self.page.spinBox_linearGradient_start, + 'RG_end': self.page.spinBox_radialGradient_end, + 'LG_end': self.page.spinBox_linearGradient_end, + 'RG_centre': self.page.spinBox_radialGradient_spread, + 'fillType': self.page.comboBox_fill, + 'color1': self.page.lineEdit_color1, + 'color2': self.page.lineEdit_color2, + }, presetNames={ + 'sizeWidth': 'width', + 'sizeHeight': 'height', + }, colorWidgets={ + 'color1': self.page.pushButton_color1, + 'color2': self.page.pushButton_color2, + }, relativeWidgets=[ + 'x', 'y', + 'sizeWidth', 'sizeHeight', + 'LG_start', 'LG_end', + 'RG_start', 'RG_end', 'RG_centre', + ]) def update(self): fillType = self.page.comboBox_fill.currentIndex() diff --git a/src/components/image.py b/src/components/image.py index 2ffa5a1..19c4796 100644 --- a/src/components/image.py +++ b/src/components/image.py @@ -13,26 +13,22 @@ class Component(Component): def widget(self, *args): super().widget(*args) self.page.pushButton_image.clicked.connect(self.pickImage) - self.trackWidgets( - { - 'imagePath': self.page.lineEdit_image, - 'scale': self.page.spinBox_scale, - 'rotate': self.page.spinBox_rotate, - 'color': self.page.spinBox_color, - 'xPosition': self.page.spinBox_x, - 'yPosition': self.page.spinBox_y, - 'stretched': self.page.checkBox_stretch, - 'mirror': self.page.checkBox_mirror, - }, - presetNames={ - 'imagePath': 'image', - 'xPosition': 'x', - 'yPosition': 'y', - }, relativeWidgets={ - 'xPosition': 'x', - 'yPosition': 'y', - }, - ) + self.trackWidgets({ + 'imagePath': self.page.lineEdit_image, + 'scale': self.page.spinBox_scale, + 'rotate': self.page.spinBox_rotate, + 'color': self.page.spinBox_color, + 'xPosition': self.page.spinBox_x, + 'yPosition': self.page.spinBox_y, + 'stretched': self.page.checkBox_stretch, + }, presetNames={ + 'mirror': self.page.checkBox_mirror, + 'imagePath': 'image', + 'xPosition': 'x', + 'yPosition': 'y', + }, relativeWidgets=[ + 'xPosition', 'yPosition', + ]) def previewRender(self): return self.drawFrame(self.width, self.height) diff --git a/src/components/original.py b/src/components/original.py index 67e3239..f886374 100644 --- a/src/components/original.py +++ b/src/components/original.py @@ -40,9 +40,9 @@ class Component(Component): 'y': self.page.spinBox_y, }, colorWidgets={ 'visColor': self.page.pushButton_visColor, - }, relativeWidgets={ - 'y': 'y', - }) + }, relativeWidgets=[ + 'y', + ]) def previewRender(self): spectrum = numpy.fromfunction( diff --git a/src/components/spectrum.py b/src/components/spectrum.py index 9a0c59a..666e20a 100644 --- a/src/components/spectrum.py +++ b/src/components/spectrum.py @@ -30,31 +30,28 @@ class Component(Component): self.update ) - self.trackWidgets( - { - 'filterType': self.page.comboBox_filterType, - 'window': self.page.comboBox_window, - 'mode': self.page.comboBox_mode, - 'amplitude': self.page.comboBox_amplitude0, - 'amplitude1': self.page.comboBox_amplitude1, - 'amplitude2': self.page.comboBox_amplitude2, - 'display': self.page.comboBox_display, - 'zoom': self.page.spinBox_zoom, - 'tc': self.page.spinBox_tc, - 'x': self.page.spinBox_x, - 'y': self.page.spinBox_y, - 'mirror': self.page.checkBox_mirror, - 'draw': self.page.checkBox_draw, - 'scale': self.page.spinBox_scale, - 'color': self.page.comboBox_color, - 'compress': self.page.checkBox_compress, - 'mono': self.page.checkBox_mono, - 'hue': self.page.spinBox_hue, - }, relativeWidgets={ - 'x': 'x', - 'y': 'y', - } - ) + self.trackWidgets({ + 'filterType': self.page.comboBox_filterType, + 'window': self.page.comboBox_window, + 'mode': self.page.comboBox_mode, + 'amplitude': self.page.comboBox_amplitude0, + 'amplitude1': self.page.comboBox_amplitude1, + 'amplitude2': self.page.comboBox_amplitude2, + 'display': self.page.comboBox_display, + 'zoom': self.page.spinBox_zoom, + 'tc': self.page.spinBox_tc, + 'x': self.page.spinBox_x, + 'y': self.page.spinBox_y, + 'mirror': self.page.checkBox_mirror, + 'draw': self.page.checkBox_draw, + 'scale': self.page.spinBox_scale, + 'color': self.page.comboBox_color, + 'compress': self.page.checkBox_compress, + 'mono': self.page.checkBox_mono, + 'hue': self.page.spinBox_hue, + }, relativeWidgets=[ + 'x', 'y', + ]) for widget in self._trackedWidgets.values(): connectWidget(widget, lambda: self.changed()) diff --git a/src/components/text.py b/src/components/text.py index 2a5d433..b7c244e 100644 --- a/src/components/text.py +++ b/src/components/text.py @@ -48,11 +48,9 @@ class Component(Component): 'yPosition': self.page.spinBox_yTextAlign, }, colorWidgets={ 'textColor': self.page.pushButton_textColor, - }, relativeWidgets={ - 'xPosition': 'x', - 'yPosition': 'y', - 'fontSize': 'y', - }) + }, relativeWidgets=[ + 'xPosition', 'yPosition', 'fontSize', + ]) def update(self): self.titleFont = self.page.fontComboBox_titleFont.currentFont() diff --git a/src/components/video.py b/src/components/video.py index 2cd67c6..b6bdd52 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -23,26 +23,23 @@ class Component(Component): super().widget(*args) self._image = BlankFrame(self.width, self.height) self.page.pushButton_video.clicked.connect(self.pickVideo) - self.trackWidgets( - { - 'videoPath': self.page.lineEdit_video, - 'loopVideo': self.page.checkBox_loop, - 'useAudio': self.page.checkBox_useAudio, - 'distort': self.page.checkBox_distort, - 'scale': self.page.spinBox_scale, - 'volume': self.page.spinBox_volume, - 'xPosition': self.page.spinBox_x, - 'yPosition': self.page.spinBox_y, - }, presetNames={ - 'videoPath': 'video', - 'loopVideo': 'loop', - 'xPosition': 'x', - 'yPosition': 'y', - }, relativeWidgets={ - 'xPosition': 'x', - 'yPosition': 'y', - } - ) + self.trackWidgets({ + 'videoPath': self.page.lineEdit_video, + 'loopVideo': self.page.checkBox_loop, + 'useAudio': self.page.checkBox_useAudio, + 'distort': self.page.checkBox_distort, + 'scale': self.page.spinBox_scale, + 'volume': self.page.spinBox_volume, + 'xPosition': self.page.spinBox_x, + 'yPosition': self.page.spinBox_y, + }, presetNames={ + 'videoPath': 'video', + 'loopVideo': 'loop', + 'xPosition': 'x', + 'yPosition': 'y', + }, relativeWidgets=[ + 'xPosition', 'yPosition', + ]) def update(self): if self.page.checkBox_useAudio.isChecked(): diff --git a/src/components/waveform.py b/src/components/waveform.py index 526e6fb..71cbcac 100644 --- a/src/components/waveform.py +++ b/src/components/waveform.py @@ -28,25 +28,22 @@ class Component(Component): self.update ) - self.trackWidgets( - { - 'color': self.page.lineEdit_color, - 'mode': self.page.comboBox_mode, - 'amplitude': self.page.comboBox_amplitude, - 'x': self.page.spinBox_x, - 'y': self.page.spinBox_y, - 'mirror': self.page.checkBox_mirror, - 'scale': self.page.spinBox_scale, - 'opacity': self.page.spinBox_opacity, - 'compress': self.page.checkBox_compress, - 'mono': self.page.checkBox_mono, - }, colorWidgets={ - 'color': self.page.pushButton_color, - }, relativeWidgets={ - 'x': 'x', - 'y': 'y', - } - ) + self.trackWidgets({ + 'color': self.page.lineEdit_color, + 'mode': self.page.comboBox_mode, + 'amplitude': self.page.comboBox_amplitude, + 'x': self.page.spinBox_x, + 'y': self.page.spinBox_y, + 'mirror': self.page.checkBox_mirror, + 'scale': self.page.spinBox_scale, + 'opacity': self.page.spinBox_opacity, + 'compress': self.page.checkBox_compress, + 'mono': self.page.checkBox_mono, + }, colorWidgets={ + 'color': self.page.pushButton_color, + }, relativeWidgets=[ + 'x', 'y', + ]) def previewRender(self): self.updateChunksize() -- cgit v1.2.3