added Spectrum component with many options
tweaked Waveform, added some ffmpeg logging, made generic widget functions
This commit is contained in:
parent
db1ea1fc4e
commit
b6b45d1270
|
@ -4,9 +4,11 @@
|
||||||
'''
|
'''
|
||||||
from PyQt5 import uic, QtCore, QtWidgets
|
from PyQt5 import uic, QtCore, QtWidgets
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from toolkit.frame import BlankFrame
|
from toolkit.frame import BlankFrame
|
||||||
|
from toolkit import getWidgetValue, setWidgetValue, connectWidget
|
||||||
|
|
||||||
|
|
||||||
class ComponentMetaclass(type(QtCore.QObject)):
|
class ComponentMetaclass(type(QtCore.QObject)):
|
||||||
|
@ -273,14 +275,9 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass):
|
||||||
widgets['spinBox'].extend(
|
widgets['spinBox'].extend(
|
||||||
self.page.findChildren(QtWidgets.QDoubleSpinBox)
|
self.page.findChildren(QtWidgets.QDoubleSpinBox)
|
||||||
)
|
)
|
||||||
for widget in widgets['lineEdit']:
|
for widgetList in widgets.values():
|
||||||
widget.textChanged.connect(self.update)
|
for widget in widgetList:
|
||||||
for widget in widgets['checkBox']:
|
connectWidget(widget, self.update)
|
||||||
widget.stateChanged.connect(self.update)
|
|
||||||
for widget in widgets['spinBox']:
|
|
||||||
widget.valueChanged.connect(self.update)
|
|
||||||
for widget in widgets['comboBox']:
|
|
||||||
widget.currentIndexChanged.connect(self.update)
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
'''
|
'''
|
||||||
|
@ -289,15 +286,7 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass):
|
||||||
Call super() at the END if you need to subclass this.
|
Call super() at the END if you need to subclass this.
|
||||||
'''
|
'''
|
||||||
for attr, widget in self._trackedWidgets.items():
|
for attr, widget in self._trackedWidgets.items():
|
||||||
if type(widget) == QtWidgets.QLineEdit:
|
setattr(self, attr, getWidgetValue(widget))
|
||||||
setattr(self, attr, widget.text())
|
|
||||||
elif type(widget) == QtWidgets.QSpinBox \
|
|
||||||
or type(widget) == QtWidgets.QDoubleSpinBox:
|
|
||||||
setattr(self, attr, widget.value())
|
|
||||||
elif type(widget) == QtWidgets.QCheckBox:
|
|
||||||
setattr(self, attr, widget.isChecked())
|
|
||||||
elif type(widget) == QtWidgets.QComboBox:
|
|
||||||
setattr(self, attr, widget.currentIndex())
|
|
||||||
if not self.core.openingProject:
|
if not self.core.openingProject:
|
||||||
self.parent.drawPreview()
|
self.parent.drawPreview()
|
||||||
saveValueStore = self.savePreset()
|
saveValueStore = self.savePreset()
|
||||||
|
@ -313,19 +302,10 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass):
|
||||||
self.currentPreset = presetName \
|
self.currentPreset = presetName \
|
||||||
if presetName is not None else presetDict['preset']
|
if presetName is not None else presetDict['preset']
|
||||||
for attr, widget in self._trackedWidgets.items():
|
for attr, widget in self._trackedWidgets.items():
|
||||||
val = presetDict[
|
key = attr if attr not in self._presetNames \
|
||||||
attr if attr not in self._presetNames
|
|
||||||
else self._presetNames[attr]
|
else self._presetNames[attr]
|
||||||
]
|
val = presetDict[key]
|
||||||
if type(widget) == QtWidgets.QLineEdit:
|
setWidgetValue(widget, val)
|
||||||
widget.setText(val)
|
|
||||||
elif type(widget) == QtWidgets.QSpinBox \
|
|
||||||
or type(widget) == QtWidgets.QDoubleSpinBox:
|
|
||||||
widget.setValue(val)
|
|
||||||
elif type(widget) == QtWidgets.QCheckBox:
|
|
||||||
widget.setChecked(val)
|
|
||||||
elif type(widget) == QtWidgets.QComboBox:
|
|
||||||
widget.setCurrentIndex(val)
|
|
||||||
|
|
||||||
def savePreset(self):
|
def savePreset(self):
|
||||||
saveValueStore = {}
|
saveValueStore = {}
|
||||||
|
@ -420,24 +400,30 @@ class ComponentError(RuntimeError):
|
||||||
prevErrors = []
|
prevErrors = []
|
||||||
lastTime = time.time()
|
lastTime = time.time()
|
||||||
|
|
||||||
def __init__(self, caller, name):
|
def __init__(self, caller, name, msg=None):
|
||||||
print('##### ComponentError by %s: %s' % (caller.name, name))
|
if msg is None and sys.exc_info()[0] is not None:
|
||||||
|
msg = str(sys.exc_info()[1])
|
||||||
|
else:
|
||||||
|
msg = 'Unknown error.'
|
||||||
|
print("##### ComponentError by %s's %s: %s" % (
|
||||||
|
caller.name, name, msg))
|
||||||
|
|
||||||
|
# Don't create multiple windows for quickly repeated messages
|
||||||
if len(ComponentError.prevErrors) > 1:
|
if len(ComponentError.prevErrors) > 1:
|
||||||
ComponentError.prevErrors.pop()
|
ComponentError.prevErrors.pop()
|
||||||
ComponentError.prevErrors.insert(0, name)
|
ComponentError.prevErrors.insert(0, name)
|
||||||
curTime = time.time()
|
curTime = time.time()
|
||||||
if name in ComponentError.prevErrors[1:] \
|
if name in ComponentError.prevErrors[1:] \
|
||||||
and curTime - ComponentError.lastTime < 1.0:
|
and curTime - ComponentError.lastTime < 1.0:
|
||||||
# Don't create multiple windows for quickly repeated messages
|
|
||||||
return
|
return
|
||||||
ComponentError.lastTime = time.time()
|
ComponentError.lastTime = time.time()
|
||||||
|
|
||||||
from toolkit import formatTraceback
|
from toolkit import formatTraceback
|
||||||
import sys
|
|
||||||
if sys.exc_info()[0] is not None:
|
if sys.exc_info()[0] is not None:
|
||||||
string = (
|
string = (
|
||||||
"%s component's %s encountered %s %s: %s" % (
|
"%s component (#%s): %s encountered %s %s: %s" % (
|
||||||
caller.__class__.name,
|
caller.__class__.name,
|
||||||
|
str(caller.compPos),
|
||||||
name,
|
name,
|
||||||
'an' if any([
|
'an' if any([
|
||||||
sys.exc_info()[0].__name__.startswith(vowel)
|
sys.exc_info()[0].__name__.startswith(vowel)
|
||||||
|
|
|
@ -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
|
|
@ -0,0 +1,582 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>586</width>
|
||||||
|
<height>197</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>197</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Type</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBox_filterType">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Spectrum</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Histogram</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Vector Scope</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Musical Scale</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Phase</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_9">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>5</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_xTitleAlign">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>X</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinBox_x">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>80</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>-10000</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>10000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_yTitleAlign">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Y</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinBox_y">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>80</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="baseSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>-10000</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>10000</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkBox_compress">
|
||||||
|
<property name="text">
|
||||||
|
<string>Compress</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkBox_mono">
|
||||||
|
<property name="text">
|
||||||
|
<string>Mono</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkBox_mirror">
|
||||||
|
<property name="text">
|
||||||
|
<string>Mirror</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Scale</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinBox_scale">
|
||||||
|
<property name="buttonSymbols">
|
||||||
|
<enum>QAbstractSpinBox::UpDownArrows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string>%</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>400</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QStackedWidget" name="stackedWidget">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="autoFillBackground">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="page">
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>561</width>
|
||||||
|
<height>72</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SetMaximumSize</enum>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SetDefaultConstraint</enum>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_textColor">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>31</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Window</string>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBox_window">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>hann</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>gauss</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>tukey</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>dolph</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>cauchy</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>parzen</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>poisson</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>rect</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>bartlett</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>hanning</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>hamming</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>blackman</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>welch</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>flattop</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>bharris</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>bnuttall</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>lanczos</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Amplitude</string>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBox_amplitude">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Square root</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cubic root</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>4thrt</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>5thrt</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Linear</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Logarithmic</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>10</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Color </string>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBox_color">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Channel</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Intensity</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Rainbow</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Moreland</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Nebulae</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Fire</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Fiery</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Fruit</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cool</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>10</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="page_2"/>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>10</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -8,7 +8,9 @@ import subprocess
|
||||||
from component import Component
|
from component import Component
|
||||||
from toolkit.frame import BlankFrame, scale
|
from toolkit.frame import BlankFrame, scale
|
||||||
from toolkit import checkOutput, rgbFromString, pickColor
|
from toolkit import checkOutput, rgbFromString, pickColor
|
||||||
from toolkit.ffmpeg import openPipe, closePipe, getAudioDuration, FfmpegVideo
|
from toolkit.ffmpeg import (
|
||||||
|
openPipe, closePipe, getAudioDuration, FfmpegVideo, exampleSound
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Component(Component):
|
class Component(Component):
|
||||||
|
@ -112,6 +114,8 @@ class Component(Component):
|
||||||
if not duration:
|
if not duration:
|
||||||
return
|
return
|
||||||
startPt = duration / 3
|
startPt = duration / 3
|
||||||
|
if startPt + 3 > duration:
|
||||||
|
startPt += startPt - 3
|
||||||
|
|
||||||
command = [
|
command = [
|
||||||
self.core.FFMPEG_BIN,
|
self.core.FFMPEG_BIN,
|
||||||
|
@ -154,29 +158,43 @@ class Component(Component):
|
||||||
hexcolor = QColor(*self.color).name()
|
hexcolor = QColor(*self.color).name()
|
||||||
opacity = "{0:.1f}".format(self.opacity / 100)
|
opacity = "{0:.1f}".format(self.opacity / 100)
|
||||||
genericPreview = self.settings.value("pref_genericPreview")
|
genericPreview = self.settings.value("pref_genericPreview")
|
||||||
|
if self.mode < 3:
|
||||||
|
filter_ = 'showwaves=r=%s:s=%sx%s:mode=%s:colors=%s@%s:scale=%s' % (
|
||||||
|
self.settings.value("outputFrameRate"),
|
||||||
|
self.settings.value("outputWidth"),
|
||||||
|
self.settings.value("outputHeight"),
|
||||||
|
self.page.comboBox_mode.currentText().lower()
|
||||||
|
if self.mode != 3 else 'p2p',
|
||||||
|
hexcolor, opacity, amplitude,
|
||||||
|
)
|
||||||
|
elif self.mode > 2:
|
||||||
|
filter_ = (
|
||||||
|
'showfreqs=s=%sx%s:mode=%s:colors=%s@%s'
|
||||||
|
':ascale=%s:fscale=%s' % (
|
||||||
|
self.settings.value("outputWidth"),
|
||||||
|
self.settings.value("outputHeight"),
|
||||||
|
'line' if self.mode == 4 else 'bar',
|
||||||
|
hexcolor, opacity, amplitude,
|
||||||
|
'log' if self.mono else 'lin'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'-filter_complex',
|
'-filter_complex',
|
||||||
'%s%s%s'
|
'%s%s%s'
|
||||||
'showwaves=r=30:s=%sx%s:mode=%s:colors=%s@%s:scale=%s%s%s [v1]; '
|
'%s%s%s [v1]; '
|
||||||
'[v1] scale=%s:%s%s,setpts=2.0*PTS [v]' % (
|
'[v1] scale=%s:%s%s [v]' % (
|
||||||
'aevalsrc=sin(1*2*PI*t)*sin(880*2*PI*t),'
|
exampleSound() if preview and genericPreview else '[0:a] ',
|
||||||
if preview and genericPreview else '[0:a] ',
|
'compand=gain=4,' if self.compress else '',
|
||||||
'compand=.3|.3:1|1:-90/-60|-60/-40|-40/-30|-20/-20:6:0:-90:0.2'
|
'aformat=channel_layouts=mono,'
|
||||||
',' if self.compress and not preview else (
|
if self.mono and self.mode < 3 else '',
|
||||||
'compand=gain=5,' if self.compress else ''
|
filter_,
|
||||||
),
|
|
||||||
'aformat=channel_layouts=mono,' if self.mono else '',
|
|
||||||
self.settings.value("outputWidth"),
|
|
||||||
self.settings.value("outputHeight"),
|
|
||||||
str(self.page.comboBox_mode.currentText()).lower(),
|
|
||||||
hexcolor, opacity, amplitude,
|
|
||||||
', drawbox=x=(iw-w)/2:y=(ih-h)/2:w=iw:h=4:color=%s@%s' % (
|
', drawbox=x=(iw-w)/2:y=(ih-h)/2:w=iw:h=4:color=%s@%s' % (
|
||||||
hexcolor, opacity
|
hexcolor, opacity
|
||||||
) if self.mode < 2 else '',
|
) if self.mode < 2 else '',
|
||||||
', hflip' if self.mirror else'',
|
', hflip' if self.mirror else'',
|
||||||
w, h,
|
w, h,
|
||||||
', trim=duration=%s' % "{0:.3f}".format(startPt + 1)
|
', trim=duration=%s' % "{0:.3f}".format(startPt + 3)
|
||||||
if preview else '',
|
if preview else '',
|
||||||
),
|
),
|
||||||
'-map', '[v]',
|
'-map', '[v]',
|
||||||
|
|
|
@ -66,12 +66,17 @@
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>P2p</string>
|
<string>Point</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Point</string>
|
<string>Frequency Bar</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Frequency Line</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -180,12 +185,16 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Wave Color</string>
|
<string>Color</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="lineEdit_color"/>
|
<widget class="QLineEdit" name="lineEdit_color">
|
||||||
|
<property name="inputMethodHints">
|
||||||
|
<set>Qt::ImhNone</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_color">
|
<widget class="QPushButton" name="pushButton_color">
|
||||||
|
@ -244,10 +253,10 @@
|
||||||
<string>%</string>
|
<string>%</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<number>10</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>400</number>
|
<number>100</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<number>100</number>
|
<number>100</number>
|
||||||
|
|
|
@ -581,7 +581,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
self.showMessage(
|
self.showMessage(
|
||||||
msg=msg,
|
msg=msg,
|
||||||
detail=detail,
|
detail=detail,
|
||||||
icon='Warning',
|
icon='Critical',
|
||||||
)
|
)
|
||||||
|
|
||||||
def changeEncodingStatus(self, status):
|
def changeEncodingStatus(self, status):
|
||||||
|
|
|
@ -113,3 +113,46 @@ def formatTraceback(tb=None):
|
||||||
import sys
|
import sys
|
||||||
tb = sys.exc_info()[2]
|
tb = sys.exc_info()[2]
|
||||||
return 'Traceback:\n%s' % "\n".join(traceback.format_tb(tb))
|
return 'Traceback:\n%s' % "\n".join(traceback.format_tb(tb))
|
||||||
|
|
||||||
|
|
||||||
|
def connectWidget(widget, func):
|
||||||
|
if type(widget) == QtWidgets.QLineEdit:
|
||||||
|
widget.textChanged.connect(func)
|
||||||
|
elif type(widget) == QtWidgets.QSpinBox \
|
||||||
|
or type(widget) == QtWidgets.QDoubleSpinBox:
|
||||||
|
widget.valueChanged.connect(func)
|
||||||
|
elif type(widget) == QtWidgets.QCheckBox:
|
||||||
|
widget.stateChanged.connect(func)
|
||||||
|
elif type(widget) == QtWidgets.QComboBox:
|
||||||
|
widget.currentIndexChanged.connect(func)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def setWidgetValue(widget, val):
|
||||||
|
'''Generic setValue method for use with any typical QtWidget'''
|
||||||
|
if type(widget) == QtWidgets.QLineEdit:
|
||||||
|
widget.setText(val)
|
||||||
|
elif type(widget) == QtWidgets.QSpinBox \
|
||||||
|
or type(widget) == QtWidgets.QDoubleSpinBox:
|
||||||
|
widget.setValue(val)
|
||||||
|
elif type(widget) == QtWidgets.QCheckBox:
|
||||||
|
widget.setChecked(val)
|
||||||
|
elif type(widget) == QtWidgets.QComboBox:
|
||||||
|
widget.setCurrentIndex(val)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def getWidgetValue(widget):
|
||||||
|
if type(widget) == QtWidgets.QLineEdit:
|
||||||
|
return widget.text()
|
||||||
|
elif type(widget) == QtWidgets.QSpinBox \
|
||||||
|
or type(widget) == QtWidgets.QDoubleSpinBox:
|
||||||
|
return widget.value()
|
||||||
|
elif type(widget) == QtWidgets.QCheckBox:
|
||||||
|
return widget.isChecked()
|
||||||
|
elif type(widget) == QtWidgets.QComboBox:
|
||||||
|
return widget.currentIndex()
|
||||||
|
|
|
@ -37,7 +37,6 @@ class FfmpegVideo:
|
||||||
self.frameNo = -1
|
self.frameNo = -1
|
||||||
self.currentFrame = 'None'
|
self.currentFrame = 'None'
|
||||||
self.map_ = None
|
self.map_ = None
|
||||||
self.debug = False
|
|
||||||
|
|
||||||
if 'loopVideo' in kwargs and kwargs['loopVideo']:
|
if 'loopVideo' in kwargs and kwargs['loopVideo']:
|
||||||
self.loopValue = '-1'
|
self.loopValue = '-1'
|
||||||
|
@ -48,8 +47,6 @@ class FfmpegVideo:
|
||||||
kwargs['filter_'].insert(0, '-filter_complex')
|
kwargs['filter_'].insert(0, '-filter_complex')
|
||||||
else:
|
else:
|
||||||
kwargs['filter_'] = None
|
kwargs['filter_'] = None
|
||||||
if 'debug' in kwargs:
|
|
||||||
self.debug = True
|
|
||||||
|
|
||||||
self.command = [
|
self.command = [
|
||||||
core.Core.FFMPEG_BIN,
|
core.Core.FFMPEG_BIN,
|
||||||
|
@ -90,15 +87,14 @@ class FfmpegVideo:
|
||||||
self.frameBuffer.task_done()
|
self.frameBuffer.task_done()
|
||||||
|
|
||||||
def fillBuffer(self):
|
def fillBuffer(self):
|
||||||
if self.debug:
|
logFilename = os.path.join(
|
||||||
print(" ".join([word for word in self.command]))
|
core.Core.dataDir, 'extra_%s.log' % str(self.component.compPos))
|
||||||
err = sys.__stdout__
|
with open(logFilename, 'w') as log:
|
||||||
else:
|
log.write(" ".join(self.command) + '\n\n')
|
||||||
err = subprocess.DEVNULL
|
with open(logFilename, 'a') as log:
|
||||||
|
|
||||||
self.pipe = openPipe(
|
self.pipe = openPipe(
|
||||||
self.command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE,
|
self.command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE,
|
||||||
stderr=err, bufsize=10**8
|
stderr=log, bufsize=10**8
|
||||||
)
|
)
|
||||||
while True:
|
while True:
|
||||||
if self.parent.canceled:
|
if self.parent.canceled:
|
||||||
|
@ -111,10 +107,18 @@ class FfmpegVideo:
|
||||||
self.frameBuffer.put((self.frameNo-1, self.lastFrame))
|
self.frameBuffer.put((self.frameNo-1, self.lastFrame))
|
||||||
continue
|
continue
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
FfmpegVideo.threadError = ComponentError(self.component, 'video')
|
FfmpegVideo.threadError = ComponentError(
|
||||||
|
self.component, 'video',
|
||||||
|
"Video seemed playable but wasn't."
|
||||||
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
try:
|
||||||
self.currentFrame = self.pipe.stdout.read(self.chunkSize)
|
self.currentFrame = self.pipe.stdout.read(self.chunkSize)
|
||||||
|
except ValueError:
|
||||||
|
FfmpegVideo.threadError = ComponentError(
|
||||||
|
self.component, 'video')
|
||||||
|
|
||||||
if len(self.currentFrame) != 0:
|
if len(self.currentFrame) != 0:
|
||||||
self.frameBuffer.put((self.frameNo, self.currentFrame))
|
self.frameBuffer.put((self.frameNo, self.currentFrame))
|
||||||
self.lastFrame = self.currentFrame
|
self.lastFrame = self.currentFrame
|
||||||
|
@ -446,3 +450,10 @@ def readAudioFile(filename, videoWorker):
|
||||||
completeAudioArray = completeAudioArrayCopy
|
completeAudioArray = completeAudioArrayCopy
|
||||||
|
|
||||||
return (completeAudioArray, duration)
|
return (completeAudioArray, duration)
|
||||||
|
|
||||||
|
|
||||||
|
def exampleSound():
|
||||||
|
return (
|
||||||
|
'aevalsrc=tan(random(1)*PI*t)*sin(random(0)*2*PI*t),'
|
||||||
|
'apulsator=offset_l=0.5:offset_r=0.5,'
|
||||||
|
)
|
||||||
|
|
Reference in New Issue