added Spectrum component with many options

tweaked Waveform, added some ffmpeg logging, made generic widget functions
This commit is contained in:
tassaron 2017-07-30 13:04:02 -04:00
parent db1ea1fc4e
commit b6b45d1270
8 changed files with 959 additions and 71 deletions

View File

@ -4,9 +4,11 @@
'''
from PyQt5 import uic, QtCore, QtWidgets
import os
import sys
import time
from toolkit.frame import BlankFrame
from toolkit import getWidgetValue, setWidgetValue, connectWidget
class ComponentMetaclass(type(QtCore.QObject)):
@ -273,14 +275,9 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass):
widgets['spinBox'].extend(
self.page.findChildren(QtWidgets.QDoubleSpinBox)
)
for widget in widgets['lineEdit']:
widget.textChanged.connect(self.update)
for widget in widgets['checkBox']:
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)
for widgetList in widgets.values():
for widget in widgetList:
connectWidget(widget, self.update)
def update(self):
'''
@ -289,15 +286,7 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass):
Call super() at the END if you need to subclass this.
'''
for attr, widget in self._trackedWidgets.items():
if type(widget) == QtWidgets.QLineEdit:
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())
setattr(self, attr, getWidgetValue(widget))
if not self.core.openingProject:
self.parent.drawPreview()
saveValueStore = self.savePreset()
@ -313,19 +302,10 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass):
self.currentPreset = presetName \
if presetName is not None else presetDict['preset']
for attr, widget in self._trackedWidgets.items():
val = presetDict[
attr if attr not in self._presetNames
key = attr if attr not in self._presetNames \
else self._presetNames[attr]
]
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)
val = presetDict[key]
setWidgetValue(widget, val)
def savePreset(self):
saveValueStore = {}
@ -420,24 +400,30 @@ class ComponentError(RuntimeError):
prevErrors = []
lastTime = time.time()
def __init__(self, caller, name):
print('##### ComponentError by %s: %s' % (caller.name, name))
def __init__(self, caller, name, msg=None):
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:
ComponentError.prevErrors.pop()
ComponentError.prevErrors.insert(0, name)
curTime = time.time()
if name in ComponentError.prevErrors[1:] \
and curTime - ComponentError.lastTime < 1.0:
# Don't create multiple windows for quickly repeated messages
return
ComponentError.lastTime = time.time()
from toolkit import formatTraceback
import sys
if sys.exc_info()[0] is not None:
string = (
"%s component's %s encountered %s %s: %s" % (
"%s component (#%s): %s encountered %s %s: %s" % (
caller.__class__.name,
str(caller.compPos),
name,
'an' if any([
sys.exc_info()[0].__name__.startswith(vowel)

239
src/components/spectrum.py Normal file
View File

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

582
src/components/spectrum.ui Normal file
View File

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

View File

@ -8,7 +8,9 @@ import subprocess
from component import Component
from toolkit.frame import BlankFrame, scale
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):
@ -112,6 +114,8 @@ class Component(Component):
if not duration:
return
startPt = duration / 3
if startPt + 3 > duration:
startPt += startPt - 3
command = [
self.core.FFMPEG_BIN,
@ -154,29 +158,43 @@ class Component(Component):
hexcolor = QColor(*self.color).name()
opacity = "{0:.1f}".format(self.opacity / 100)
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 [
'-filter_complex',
'%s%s%s'
'showwaves=r=30:s=%sx%s:mode=%s:colors=%s@%s:scale=%s%s%s [v1]; '
'[v1] scale=%s:%s%s,setpts=2.0*PTS [v]' % (
'aevalsrc=sin(1*2*PI*t)*sin(880*2*PI*t),'
if preview and genericPreview else '[0:a] ',
'compand=.3|.3:1|1:-90/-60|-60/-40|-40/-30|-20/-20:6:0:-90:0.2'
',' if self.compress and not preview else (
'compand=gain=5,' if self.compress else ''
),
'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,
'%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 and self.mode < 3 else '',
filter_,
', drawbox=x=(iw-w)/2:y=(ih-h)/2:w=iw:h=4:color=%s@%s' % (
hexcolor, opacity
) if self.mode < 2 else '',
', hflip' if self.mirror else'',
w, h,
', trim=duration=%s' % "{0:.3f}".format(startPt + 1)
', trim=duration=%s' % "{0:.3f}".format(startPt + 3)
if preview else '',
),
'-map', '[v]',

View File

@ -66,12 +66,17 @@
</item>
<item>
<property name="text">
<string>P2p</string>
<string>Point</string>
</property>
</item>
<item>
<property name="text">
<string>Point</string>
<string>Frequency Bar</string>
</property>
</item>
<item>
<property name="text">
<string>Frequency Line</string>
</property>
</item>
</widget>
@ -180,12 +185,16 @@
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Wave Color</string>
<string>Color</string>
</property>
</widget>
</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>
<widget class="QPushButton" name="pushButton_color">
@ -244,10 +253,10 @@
<string>%</string>
</property>
<property name="minimum">
<number>10</number>
<number>0</number>
</property>
<property name="maximum">
<number>400</number>
<number>100</number>
</property>
<property name="value">
<number>100</number>

View File

@ -581,7 +581,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.showMessage(
msg=msg,
detail=detail,
icon='Warning',
icon='Critical',
)
def changeEncodingStatus(self, status):

View File

@ -113,3 +113,46 @@ def formatTraceback(tb=None):
import sys
tb = sys.exc_info()[2]
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()

View File

@ -37,7 +37,6 @@ class FfmpegVideo:
self.frameNo = -1
self.currentFrame = 'None'
self.map_ = None
self.debug = False
if 'loopVideo' in kwargs and kwargs['loopVideo']:
self.loopValue = '-1'
@ -48,8 +47,6 @@ class FfmpegVideo:
kwargs['filter_'].insert(0, '-filter_complex')
else:
kwargs['filter_'] = None
if 'debug' in kwargs:
self.debug = True
self.command = [
core.Core.FFMPEG_BIN,
@ -90,16 +87,15 @@ class FfmpegVideo:
self.frameBuffer.task_done()
def fillBuffer(self):
if self.debug:
print(" ".join([word for word in self.command]))
err = sys.__stdout__
else:
err = subprocess.DEVNULL
self.pipe = openPipe(
self.command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE,
stderr=err, bufsize=10**8
)
logFilename = os.path.join(
core.Core.dataDir, 'extra_%s.log' % str(self.component.compPos))
with open(logFilename, 'w') as log:
log.write(" ".join(self.command) + '\n\n')
with open(logFilename, 'a') as log:
self.pipe = openPipe(
self.command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE,
stderr=log, bufsize=10**8
)
while True:
if self.parent.canceled:
break
@ -111,10 +107,18 @@ class FfmpegVideo:
self.frameBuffer.put((self.frameNo-1, self.lastFrame))
continue
except AttributeError:
FfmpegVideo.threadError = ComponentError(self.component, 'video')
FfmpegVideo.threadError = ComponentError(
self.component, 'video',
"Video seemed playable but wasn't."
)
break
self.currentFrame = self.pipe.stdout.read(self.chunkSize)
try:
self.currentFrame = self.pipe.stdout.read(self.chunkSize)
except ValueError:
FfmpegVideo.threadError = ComponentError(
self.component, 'video')
if len(self.currentFrame) != 0:
self.frameBuffer.put((self.frameNo, self.currentFrame))
self.lastFrame = self.currentFrame
@ -446,3 +450,10 @@ def readAudioFile(filename, videoWorker):
completeAudioArray = completeAudioArrayCopy
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,'
)