From f6fbc8d2423ac5ae683a7613b53648db3e02e323 Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 9 Jul 2017 14:31:19 -0400 Subject: a basic Sound component for mixing sounds to be greatly expanded... --- src/component.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'src/component.py') diff --git a/src/component.py b/src/component.py index 648a6d6..306072c 100644 --- a/src/component.py +++ b/src/component.py @@ -48,14 +48,18 @@ class Component(QtCore.QObject): if presetName is not None else presetDict['preset'] def preFrameRender(self, **kwargs): - ''' Triggered only before a video is exported (video_thread.py) + ''' + Triggered only before a video is exported (video_thread.py) self.worker = the video thread worker self.completeAudioArray = a list of audio samples self.sampleSize = number of audio samples per video frame self.progressBarUpdate = signal to set progress bar number self.progressBarSetText = signal to set progress bar text - Use the latter two signals to update the MainWindow if needed + Use the latter two signals to update the MainWindow if needed for a long initialization procedure (i.e., for a visualizer) + + Return a list of properties to signify if your component is + non-animated ('static') or returns sound ('audio'). ''' for var, value in kwargs.items(): exec('self.%s = value' % var) @@ -135,8 +139,8 @@ class Component(QtCore.QObject): return page def update(self): - super().update() self.parent.drawPreview() + super().update() def previewRender(self, previewWorker): width = int(previewWorker.core.settings.value('outputWidth')) @@ -153,9 +157,17 @@ class Component(QtCore.QObject): image = BlankFrame(width, height) return image + def audio(self): + \''' + Return audio to mix into master as a string (path to audio file), + or an object that returns raw audio data [future feature]. + \''' + @classmethod def names(cls): - # Alternative names for renaming a component between project files + \''' + Alternative names for renaming a component between project files. + \''' return [] ''' -- cgit v1.2.3 From 4c3920e6309b4e67e3d8d809dd0b5b6cd245fd0c Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 9 Jul 2017 21:27:29 -0400 Subject: separated creation of ffmpeg command for future use to sllow editing the command before starting the export --- src/component.py | 10 +++-- src/components/color.py | 3 +- src/components/image.py | 3 +- src/components/sound.py | 4 +- src/components/text.py | 3 +- src/core.py | 93 ++++++++++++++++++++++++++++++++++++++++ src/video_thread.py | 110 +++++------------------------------------------- 7 files changed, 116 insertions(+), 110 deletions(-) (limited to 'src/component.py') diff --git a/src/component.py b/src/component.py index 306072c..7c2f753 100644 --- a/src/component.py +++ b/src/component.py @@ -27,6 +27,13 @@ class Component(QtCore.QObject): # change this number to identify new versions of a component return 1 + def properties(self): + ''' + Return a list of properties to signify if your component is + non-animated ('static') or returns sound ('audio'). + ''' + return [] + def cancel(self): # please stop any lengthy process in response to this variable self.canceled = True @@ -57,9 +64,6 @@ class Component(QtCore.QObject): self.progressBarSetText = signal to set progress bar text Use the latter two signals to update the MainWindow if needed for a long initialization procedure (i.e., for a visualizer) - - Return a list of properties to signify if your component is - non-animated ('static') or returns sound ('audio'). ''' for var, value in kwargs.items(): exec('self.%s = value' % var) diff --git a/src/components/color.py b/src/components/color.py index b87f3e9..82b45b3 100644 --- a/src/components/color.py +++ b/src/components/color.py @@ -117,8 +117,7 @@ class Component(Component): height = int(previewWorker.core.settings.value('outputHeight')) return self.drawFrame(width, height) - def preFrameRender(self, **kwargs): - super().preFrameRender(**kwargs) + def properties(self): return ['static'] def frameRender(self, layerNo, frameNo): diff --git a/src/components/image.py b/src/components/image.py index 55fa6dd..94dcb83 100644 --- a/src/components/image.py +++ b/src/components/image.py @@ -46,8 +46,7 @@ class Component(Component): height = int(previewWorker.core.settings.value('outputHeight')) return self.drawFrame(width, height) - def preFrameRender(self, **kwargs): - super().preFrameRender(**kwargs) + def properties(self): return ['static'] def frameRender(self, layerNo, frameNo): diff --git a/src/components/sound.py b/src/components/sound.py index d3589b3..1f43c83 100644 --- a/src/components/sound.py +++ b/src/components/sound.py @@ -31,7 +31,9 @@ class Component(Component): return self.frameRender(self.compPos, 0) def preFrameRender(self, **kwargs): - # super().preFrameRender(**kwargs) + pass + + def properties(self): return ['static', 'audio'] def audio(self): diff --git a/src/components/text.py b/src/components/text.py index 2b1884f..fb6a90e 100644 --- a/src/components/text.py +++ b/src/components/text.py @@ -119,8 +119,7 @@ class Component(Component): height = int(previewWorker.core.settings.value('outputHeight')) return self.addText(width, height) - def preFrameRender(self, **kwargs): - super().preFrameRender(**kwargs) + def properties(self): return ['static'] def frameRender(self, layerNo, frameNo): diff --git a/src/core.py b/src/core.py index db430d1..3d64c3b 100644 --- a/src/core.py +++ b/src/core.py @@ -460,6 +460,99 @@ class Core: except sp.CalledProcessError: return "avconv" + def createFfmpegCommand(self, inputFile, outputFile): + ''' + Constructs the major ffmpeg command used to export the video + ''' + + # Test if user has libfdk_aac + encoders = toolkit.checkOutput( + "%s -encoders -hide_banner" % self.FFMPEG_BIN, shell=True + ) + encoders = encoders.decode("utf-8") + + acodec = self.settings.value('outputAudioCodec') + + options = self.encoder_options + containerName = self.settings.value('outputContainer') + vcodec = self.settings.value('outputVideoCodec') + vbitrate = str(self.settings.value('outputVideoBitrate'))+'k' + acodec = self.settings.value('outputAudioCodec') + abitrate = str(self.settings.value('outputAudioBitrate'))+'k' + + for cont in options['containers']: + if cont['name'] == containerName: + container = cont['container'] + break + + vencoders = options['video-codecs'][vcodec] + aencoders = options['audio-codecs'][acodec] + + for encoder in vencoders: + if encoder in encoders: + vencoder = encoder + break + + for encoder in aencoders: + if encoder in encoders: + aencoder = encoder + break + + ffmpegCommand = [ + self.FFMPEG_BIN, + '-thread_queue_size', '512', + '-y', # overwrite the output file if it already exists. + + # INPUT VIDEO + '-f', 'rawvideo', + '-vcodec', 'rawvideo', + '-s', '%sx%s' % ( + self.settings.value('outputWidth'), + self.settings.value('outputHeight'), + ), + '-pix_fmt', 'rgba', + '-r', self.settings.value('outputFrameRate'), + '-i', '-', # the video input comes from a pipe + '-an', # the video input has no sound + + # INPUT SOUND + '-i', inputFile + ] + + extraAudio = [ + comp.audio() for comp in self.selectedComponents + if 'audio' in comp.properties() + ] + if extraAudio: + for extraInputFile in extraAudio: + ffmpegCommand.extend([ + '-i', extraInputFile + ]) + ffmpegCommand.extend([ + '-filter_complex', + 'amix=inputs=%s:duration=longest:dropout_transition=3' % str( + len(extraAudio) + 1 + ) + ]) + + ffmpegCommand.extend([ + # OUTPUT + '-vcodec', vencoder, + '-acodec', aencoder, + '-b:v', vbitrate, + '-b:a', abitrate, + '-pix_fmt', self.settings.value('outputVideoFormat'), + '-preset', self.settings.value('outputPreset'), + '-f', container + ]) + + if acodec == 'aac': + ffmpegCommand.append('-strict') + ffmpegCommand.append('-2') + + ffmpegCommand.append(outputFile) + return ffmpegCommand + def readAudioFile(self, filename, parent): command = [self.FFMPEG_BIN, '-i', filename] diff --git a/src/video_thread.py b/src/video_thread.py index bd94be3..dde71da 100644 --- a/src/video_thread.py +++ b/src/video_thread.py @@ -33,8 +33,8 @@ class Worker(QtCore.QObject): def __init__(self, parent=None): QtCore.QObject.__init__(self) - self.core = core.Core() - self.core.settings = parent.settings + self.core = parent.core + self.settings = parent.core.settings self.modules = parent.core.modules self.parent = parent parent.videoTask.connect(self.createVideo) @@ -114,8 +114,8 @@ class Worker(QtCore.QObject): self.components = components self.outputFile = outputFile self.extraAudio = [] - self.width = int(self.core.settings.value('outputWidth')) - self.height = int(self.core.settings.value('outputHeight')) + self.width = int(self.settings.value('outputWidth')) + self.height = int(self.settings.value('outputHeight')) self.compositeQueue = Queue() self.compositeQueue.maxsize = 20 @@ -128,7 +128,7 @@ class Worker(QtCore.QObject): self.progressBarUpdate.emit(progressBarValue) # =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ - # READ AUDIO AND INITIALIZE COMPONENTS + # READ AUDIO, INITIALIZE COMPONENTS, OPEN A PIPE TO FFMPEG # =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ self.progressBarSetText.emit("Loading audio file...") @@ -143,8 +143,7 @@ class Worker(QtCore.QObject): self.staticComponents = {} numComps = len(self.components) for compNo, comp in enumerate(self.components): - properties = None - properties = comp.preFrameRender( + comp.preFrameRender( worker=self, completeAudioArray=self.completeAudioArray, sampleSize=self.sampleSize, @@ -152,101 +151,12 @@ class Worker(QtCore.QObject): progressBarSetText=self.progressBarSetText ) - if properties: - if 'static' in properties: - self.staticComponents[compNo] = \ - comp.frameRender(compNo, 0).copy() - if 'audio' in properties: - self.extraAudio.append(comp.audio()) + if 'static' in comp.properties(): + self.staticComponents[compNo] = \ + comp.frameRender(compNo, 0).copy() - # =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ - # DEDUCE ENCODERS - # =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ - - # test if user has libfdk_aac - encoders = checkOutput( - "%s -encoders -hide_banner" % self.core.FFMPEG_BIN, shell=True - ) - encoders = encoders.decode("utf-8") - - acodec = self.core.settings.value('outputAudioCodec') - - options = self.core.encoder_options - containerName = self.core.settings.value('outputContainer') - vcodec = self.core.settings.value('outputVideoCodec') - vbitrate = str(self.core.settings.value('outputVideoBitrate'))+'k' - acodec = self.core.settings.value('outputAudioCodec') - abitrate = str(self.core.settings.value('outputAudioBitrate'))+'k' - - for cont in options['containers']: - if cont['name'] == containerName: - container = cont['container'] - break - - vencoders = options['video-codecs'][vcodec] - aencoders = options['audio-codecs'][acodec] - - for encoder in vencoders: - if encoder in encoders: - vencoder = encoder - break - - for encoder in aencoders: - if encoder in encoders: - aencoder = encoder - break - - # =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ - # CREATE PIPE TO FFMPEG - # =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~ - - ffmpegCommand = [ - self.core.FFMPEG_BIN, - '-thread_queue_size', '512', - '-y', # overwrite the output file if it already exists. - - # INPUT VIDEO - '-f', 'rawvideo', - '-vcodec', 'rawvideo', - '-s', str(self.width)+'x'+str(self.height), # size of one frame - '-pix_fmt', 'rgba', - '-r', self.core.settings.value('outputFrameRate'), - '-i', '-', # the video input comes from a pipe - '-an', # the video input has no sound - - # INPUT SOUND - '-i', inputFile - ] - - if self.extraAudio: - for extraInputFile in self.extraAudio: - ffmpegCommand.extend([ - '-i', extraInputFile - ]) - ffmpegCommand.extend([ - '-filter_complex', - 'amix=inputs=%s:duration=longest:dropout_transition=3' % str( - len(self.extraAudio) + 1 - ) - ]) - - ffmpegCommand.extend([ - # OUTPUT - '-vcodec', vencoder, - '-acodec', aencoder, - '-b:v', vbitrate, - '-b:a', abitrate, - '-pix_fmt', self.core.settings.value('outputVideoFormat'), - '-preset', self.core.settings.value('outputPreset'), - '-f', container - ]) + ffmpegCommand = self.core.createFfmpegCommand(inputFile, outputFile) print(ffmpegCommand) - - if acodec == 'aac': - ffmpegCommand.append('-strict') - ffmpegCommand.append('-2') - - ffmpegCommand.append(outputFile) self.out_pipe = openPipe( ffmpegCommand, stdin=sp.PIPE, stdout=sys.stdout, stderr=sys.stdout ) -- cgit v1.2.3 From 2e37dafd7036973a315b525f131850a6fb6d0b35 Mon Sep 17 00:00:00 2001 From: tassaron Date: Tue, 11 Jul 2017 06:06:22 -0400 Subject: fixed various bugs --- src/component.py | 9 ++++++++- src/components/image.py | 10 +++++++++- src/components/sound.py | 8 ++++---- src/components/text.py | 10 +++++----- src/components/video.py | 21 +++++++++++++++++++++ src/components/video.ui | 17 +++++++++-------- src/core.py | 4 ++-- src/mainwindow.py | 4 ++++ src/preview_thread.py | 26 ++++++++++++-------------- src/video_thread.py | 9 +++++++++ 10 files changed, 83 insertions(+), 35 deletions(-) (limited to 'src/component.py') diff --git a/src/component.py b/src/component.py index 7c2f753..eea82d7 100644 --- a/src/component.py +++ b/src/component.py @@ -30,10 +30,17 @@ class Component(QtCore.QObject): def properties(self): ''' Return a list of properties to signify if your component is - non-animated ('static') or returns sound ('audio'). + non-animated ('static'), returns sound ('audio'), or has + encountered an error in configuration ('error'). ''' return [] + def error(self): + ''' + Return a string containing an error message, or None for a default. + ''' + return + def cancel(self): # please stop any lengthy process in response to this variable self.canceled = True diff --git a/src/components/image.py b/src/components/image.py index 94dcb83..07abc3f 100644 --- a/src/components/image.py +++ b/src/components/image.py @@ -47,7 +47,15 @@ class Component(Component): return self.drawFrame(width, height) def properties(self): - return ['static'] + props = ['static'] + if not os.path.exists(self.imagePath): + props.append('error') + return props + + def error(self): + if not os.path.exists(self.imagePath): + return "The image path selected on " \ + "layer %s no longer exists!" % str(self.compPos) def frameRender(self, layerNo, frameNo): width = int(self.worker.core.settings.value('outputWidth')) diff --git a/src/components/sound.py b/src/components/sound.py index 1f43c83..9c114a8 100644 --- a/src/components/sound.py +++ b/src/components/sound.py @@ -28,7 +28,7 @@ class Component(Component): def previewRender(self, previewWorker): width = int(previewWorker.core.settings.value('outputWidth')) height = int(previewWorker.core.settings.value('outputHeight')) - return self.frameRender(self.compPos, 0) + return BlankFrame(width, height) def preFrameRender(self, **kwargs): pass @@ -37,7 +37,7 @@ class Component(Component): return ['static', 'audio'] def audio(self): - return self.sound + return (self.sound, {}) def pickSound(self): sndDir = self.settings.value("componentDir", os.path.expanduser("~")) @@ -50,8 +50,8 @@ class Component(Component): self.update() def frameRender(self, layerNo, frameNo): - width = int(self.core.settings.value('outputWidth')) - height = int(self.core.settings.value('outputHeight')) + width = int(self.settings.value('outputWidth')) + height = int(self.settings.value('outputHeight')) return BlankFrame(width, height) def loadPreset(self, pr, presetName=None): diff --git a/src/components/text.py b/src/components/text.py index fb6a90e..ed50064 100644 --- a/src/components/text.py +++ b/src/components/text.py @@ -75,15 +75,15 @@ class Component(Component): '''Returns true x, y after considering alignment settings''' fm = QtGui.QFontMetrics(self.titleFont) if self.alignment == 0: # Left - x = self.xPosition + x = int(self.xPosition) if self.alignment == 1: # Middle offset = fm.width(self.title)/2 - x = self.xPosition - offset + x = int(self.xPosition - offset) if self.alignment == 2: # Right offset = fm.width(self.title) - x = self.xPosition - offset + x = int(self.xPosition - offset) return x, self.yPosition def loadPreset(self, pr, presetName=None): @@ -128,12 +128,12 @@ class Component(Component): return self.addText(width, height) def addText(self, width, height): - x, y = self.getXY() - image = FramePainter(width, height) + image = FramePainter(width, height) self.titleFont.setPixelSize(self.fontSize) image.setFont(self.titleFont) image.setPen(self.textColor) + x, y = self.getXY() image.drawText(x, y, self.title) return image.finalize() diff --git a/src/components/video.py b/src/components/video.py index e6890e0..5303e3a 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -123,6 +123,7 @@ class Component(Component): page.pushButton_video.clicked.connect(self.pickVideo) page.checkBox_loop.stateChanged.connect(self.update) page.checkBox_distort.stateChanged.connect(self.update) + page.checkBox_useAudio.stateChanged.connect(self.update) page.spinBox_scale.valueChanged.connect(self.update) page.spinBox_x.valueChanged.connect(self.update) page.spinBox_y.valueChanged.connect(self.update) @@ -133,6 +134,7 @@ class Component(Component): def update(self): self.videoPath = self.page.lineEdit_video.text() self.loopVideo = self.page.checkBox_loop.isChecked() + self.useAudio = self.page.checkBox_useAudio.isChecked() self.distort = self.page.checkBox_distort.isChecked() self.scale = self.page.spinBox_scale.value() self.xPosition = self.page.spinBox_x.value() @@ -151,6 +153,23 @@ class Component(Component): else: return frame + def properties(self): + props = [] + if self.useAudio: + # props.append('audio') + pass + if not os.path.exists(self.videoPath): + props.append('error') + return props + + def error(self): + if not os.path.exists(self.videoPath): + return "The video path selected on " \ + "layer %s no longer exists!" % str(self.compPos) + + def audio(self): + return (self.videoPath, {}) + def preFrameRender(self, **kwargs): super().preFrameRender(**kwargs) width = int(self.worker.core.settings.value('outputWidth')) @@ -175,6 +194,7 @@ class Component(Component): super().loadPreset(pr, presetName) self.page.lineEdit_video.setText(pr['video']) self.page.checkBox_loop.setChecked(pr['loop']) + self.page.checkBox_useAudio.setChecked(pr['useAudio']) self.page.checkBox_distort.setChecked(pr['distort']) self.page.spinBox_scale.setValue(pr['scale']) self.page.spinBox_x.setValue(pr['x']) @@ -185,6 +205,7 @@ class Component(Component): 'preset': self.currentPreset, 'video': self.videoPath, 'loop': self.loopVideo, + 'useAudio': self.useAudio, 'distort': self.distort, 'scale': self.scale, 'x': self.xPosition, diff --git a/src/components/video.ui b/src/components/video.ui index f05e8a5..97b7d6f 100644 --- a/src/components/video.ui +++ b/src/components/video.ui @@ -190,16 +190,20 @@ - + + + Use Audio + + + + + Qt::Horizontal - - QSizePolicy::Fixed - - 5 + 40 20 @@ -256,9 +260,6 @@ - - - diff --git a/src/core.py b/src/core.py index 3d64c3b..450e43b 100644 --- a/src/core.py +++ b/src/core.py @@ -524,7 +524,7 @@ class Core: if 'audio' in comp.properties() ] if extraAudio: - for extraInputFile in extraAudio: + for extraInputFile, params in extraAudio: ffmpegCommand.extend([ '-i', extraInputFile ]) @@ -532,7 +532,7 @@ class Core: '-filter_complex', 'amix=inputs=%s:duration=longest:dropout_transition=3' % str( len(extraAudio) + 1 - ) + ), ]) ffmpegCommand.extend([ diff --git a/src/mainwindow.py b/src/mainwindow.py index 3cd45d6..d21ba0a 100644 --- a/src/mainwindow.py +++ b/src/mainwindow.py @@ -713,6 +713,10 @@ class MainWindow(QtWidgets.QMainWindow): def saveCurrentProject(self): if self.currentProject: self.core.createProjectFile(self.currentProject, self.window) + try: + os.remove(self.autosavePath) + except FileNotFoundError: + pass self.updateWindowTitle() else: self.openSaveProjectDialog() diff --git a/src/preview_thread.py b/src/preview_thread.py index a72845b..fb3b792 100644 --- a/src/preview_thread.py +++ b/src/preview_thread.py @@ -25,8 +25,8 @@ class Worker(QtCore.QObject): self.parent = parent self.core = self.parent.core self.queue = queue - self.core.settings = parent.settings - self.stackedWidget = parent.window.stackedWidget + self.width = int(self.core.settings.value('outputWidth')) + self.height = int(self.core.settings.value('outputHeight')) # create checkerboard background to represent transparency self.background = FloodFrame(1920, 1080, (0, 0, 0, 0)) @@ -50,10 +50,10 @@ class Worker(QtCore.QObject): except Empty: continue - width = int(self.core.settings.value('outputWidth')) - height = int(self.core.settings.value('outputHeight')) + if self.background.width != self.width: + self.background = self.background.resize( + (self.width, self.height)) frame = self.background.copy() - frame = frame.resize((width, height)) components = nextPreviewInformation["components"] for component in reversed(components): @@ -63,23 +63,21 @@ class Worker(QtCore.QObject): ) except ValueError as e: + errMsg = "Bad frame returned by %s's preview renderer. " \ + "%s. This is a fatal error." % ( + str(component), str(e).capitalize() + ) + print(errMsg) self.parent.showMessage( - msg="Bad frame returned by %s's previewRender method. " - "This is a fatal error." % - str(component), + msg=errMsg, detail=str(e), icon='Warning', parent=None # MainWindow is in a different thread ) - self.imageCreated.emit( - QtGui.QImage(ImageQt( - FloodFrame(width, height, (0, 0, 0, 0)) - )) - ) self.error.emit() break else: - self.imageCreated.emit(ImageQt(frame)) + self.imageCreated.emit(QtGui.QImage(ImageQt(frame))) except Empty: True diff --git a/src/video_thread.py b/src/video_thread.py index dde71da..b00d512 100644 --- a/src/video_thread.py +++ b/src/video_thread.py @@ -151,6 +151,15 @@ class Worker(QtCore.QObject): progressBarSetText=self.progressBarSetText ) + if 'error' in comp.properties(): + self.canceled = True + errMsg = "Component #%s encountered an error!" % compNo \ + if comp.error() is None else comp.error() + self.parent.showMessage( + msg=errMsg, + icon='Warning', + parent=None # MainWindow is in a different thread + ) if 'static' in comp.properties(): self.staticComponents[compNo] = \ comp.frameRender(compNo, 0).copy() -- cgit v1.2.3 From cbbb7876155cdb057b0d779cb8ab7bc1f31116b0 Mon Sep 17 00:00:00 2001 From: tassaron Date: Thu, 13 Jul 2017 21:59:23 -0400 Subject: components automatically drawPreview & save currentPreset this makes a Component easier to program. also more comments --- src/component.py | 36 ++++++++++++++++++++++-------------- src/components/color.py | 1 - src/components/image.py | 2 +- src/components/original.py | 2 +- src/components/sound.py | 1 - src/components/text.py | 2 +- src/components/video.py | 2 +- src/core.py | 1 + src/presetmanager.py | 1 + 9 files changed, 28 insertions(+), 20 deletions(-) (limited to 'src/component.py') diff --git a/src/component.py b/src/component.py index eea82d7..2b297d1 100644 --- a/src/component.py +++ b/src/component.py @@ -24,7 +24,9 @@ class Component(QtCore.QObject): return self.__doc__ def version(self): - # change this number to identify new versions of a component + ''' + Change this number to identify new versions of a component + ''' return 1 def properties(self): @@ -42,15 +44,22 @@ class Component(QtCore.QObject): return def cancel(self): - # please stop any lengthy process in response to this variable + ''' + Stop any lengthy process in response to this variable + ''' self.canceled = True def reset(self): self.canceled = False def update(self): - self.modified.emit(self.compPos, self.savePreset()) - # read your widget values, then call super().update() + ''' + Read your widget values from self.page, then call super().update() + ''' + self.parent.drawPreview() + saveValueStore = self.savePreset() + saveValueStore['preset'] = self.currentPreset + self.modified.emit(self.compPos, saveValueStore) def loadPreset(self, presetDict, presetName): ''' @@ -72,8 +81,8 @@ class Component(QtCore.QObject): Use the latter two signals to update the MainWindow if needed for a long initialization procedure (i.e., for a visualizer) ''' - for var, value in kwargs.items(): - exec('self.%s = value' % var) + for key, value in kwargs.items(): + setattr(self, key, value) def command(self, arg): ''' @@ -143,16 +152,11 @@ class Component(QtCore.QObject): def widget(self, parent): self.parent = parent - page = uic.loadUi(os.path.join( - os.path.dirname(os.path.realpath(__file__)), 'example.ui')) + page = self.loadUi('example.ui') # --- connect widget signals here --- self.page = page return page - def update(self): - self.parent.drawPreview() - super().update() - def previewRender(self, previewWorker): width = int(previewWorker.core.settings.value('outputWidth')) height = int(previewWorker.core.settings.value('outputHeight')) @@ -170,8 +174,12 @@ class Component(QtCore.QObject): def audio(self): \''' - Return audio to mix into master as a string (path to audio file), - or an object that returns raw audio data [future feature]. + Return audio to mix into master as a tuple with two elements: + The first element can be: + - A string (path to audio file), + - Or an object that returns audio data through a pipe + The second element must be a dictionary of ffmpeg parameters + to apply to the input stream. \''' @classmethod diff --git a/src/components/color.py b/src/components/color.py index da3bcf9..ef4dd95 100644 --- a/src/components/color.py +++ b/src/components/color.py @@ -110,7 +110,6 @@ class Component(Component): self.page.pushButton_color2.setEnabled(False) self.page.fillWidget.setCurrentIndex(self.fillType) - self.parent.drawPreview() super().update() def previewRender(self, previewWorker): diff --git a/src/components/image.py b/src/components/image.py index 6a70424..c0d1c0d 100644 --- a/src/components/image.py +++ b/src/components/image.py @@ -38,7 +38,7 @@ class Component(Component): self.yPosition = self.page.spinBox_y.value() self.stretched = self.page.checkBox_stretch.isChecked() self.mirror = self.page.checkBox_mirror.isChecked() - self.parent.drawPreview() + super().update() def previewRender(self, previewWorker): diff --git a/src/components/original.py b/src/components/original.py index 3599c30..f5776a4 100644 --- a/src/components/original.py +++ b/src/components/original.py @@ -51,7 +51,7 @@ class Component(Component): self.visColor = self.RGBFromString(self.page.lineEdit_visColor.text()) self.scale = self.page.spinBox_scale.value() self.y = self.page.spinBox_y.value() - self.parent.drawPreview() + super().update() def loadPreset(self, pr, presetName=None): diff --git a/src/components/sound.py b/src/components/sound.py index 2ffb682..fedc32b 100644 --- a/src/components/sound.py +++ b/src/components/sound.py @@ -69,7 +69,6 @@ class Component(Component): def savePreset(self): return { - 'preset': self.currentPreset, 'sound': self.sound, } diff --git a/src/components/text.py b/src/components/text.py index c52bdc5..19460e5 100644 --- a/src/components/text.py +++ b/src/components/text.py @@ -69,7 +69,7 @@ class Component(Component): btnStyle = "QPushButton { background-color : %s; outline: none; }" \ % QColor(*self.textColor).name() self.page.pushButton_textColor.setStyleSheet(btnStyle) - self.parent.drawPreview() + super().update() def getXY(self): diff --git a/src/components/video.py b/src/components/video.py index 8861d70..8aa1420 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -140,7 +140,7 @@ class Component(Component): self.scale = self.page.spinBox_scale.value() self.xPosition = self.page.spinBox_x.value() self.yPosition = self.page.spinBox_y.value() - self.parent.drawPreview() + super().update() def previewRender(self, previewWorker): diff --git a/src/core.py b/src/core.py index 3f0a6ad..2500fa6 100644 --- a/src/core.py +++ b/src/core.py @@ -414,6 +414,7 @@ class Core: f.write('[Components]\n') for comp in self.selectedComponents: saveValueStore = comp.savePreset() + saveValueStore['preset'] = comp.currentPreset f.write('%s\n' % str(comp)) f.write('%s\n' % str(comp.version())) f.write('%s\n' % toolkit.presetToString(saveValueStore)) diff --git a/src/presetmanager.py b/src/presetmanager.py index 40aa73f..0028203 100644 --- a/src/presetmanager.py +++ b/src/presetmanager.py @@ -160,6 +160,7 @@ class PresetManager(QtWidgets.QDialog): selectedComponents[index].currentPreset = newName saveValueStore = \ selectedComponents[index].savePreset() + saveValueStore['preset'] = newName componentName = str(selectedComponents[index]).strip() vers = selectedComponents[index].version() self.createNewPreset( -- cgit v1.2.3