aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDH42017-06-06 10:14:39 -0500
committerDH42017-06-06 10:14:39 -0500
commit231af74ea2b247bd73fcdfc44657b7fea2ab1620 (patch)
tree0ac0d11a5cdd0b70ed4e82b55cae80db76078cc2
parent0948afd6e8b0cf29cf4bdf570e48350caa225c0a (diff)
Code cleanup
-rw-r--r--command.py122
-rw-r--r--components/__base__.py44
-rw-r--r--components/color.py55
-rw-r--r--components/image.py24
-rw-r--r--components/original.py78
-rw-r--r--components/text.py23
-rw-r--r--components/video.py74
-rw-r--r--core.py203
-rw-r--r--main.py693
-rw-r--r--mainwindow.py586
-rw-r--r--preview_thread.py91
-rw-r--r--video_thread.py68
12 files changed, 1126 insertions, 935 deletions
diff --git a/command.py b/command.py
new file mode 100644
index 0000000..a610d8c
--- /dev/null
+++ b/command.py
@@ -0,0 +1,122 @@
+# FIXME: commandline functionality broken until we decide how to implement it
+'''
+class Command(QtCore.QObject):
+
+ videoTask = QtCore.pyqtSignal(str, str, str, list)
+
+ def __init__(self):
+ QtCore.QObject.__init__(self)
+ self.modules = []
+ self.selectedComponents = []
+
+ import argparse
+ self.parser = argparse.ArgumentParser(
+ description='Create a visualization for an audio file')
+ self.parser.add_argument(
+ '-i', '--input', dest='input', help='input audio file', required=True)
+ self.parser.add_argument(
+ '-o', '--output', dest='output',
+ help='output video file', required=True)
+ self.parser.add_argument(
+ '-b', '--background', dest='bgimage',
+ help='background image file', required=True)
+ self.parser.add_argument(
+ '-t', '--text', dest='text', help='title text', required=True)
+ self.parser.add_argument(
+ '-f', '--font', dest='font', help='title font', required=False)
+ self.parser.add_argument(
+ '-s', '--fontsize', dest='fontsize',
+ help='title font size', required=False)
+ self.parser.add_argument(
+ '-c', '--textcolor', dest='textcolor',
+ help='title text color in r,g,b format', required=False)
+ self.parser.add_argument(
+ '-C', '--viscolor', dest='viscolor',
+ help='visualization color in r,g,b format', required=False)
+ self.parser.add_argument(
+ '-x', '--xposition', dest='xposition',
+ help='x position', required=False)
+ self.parser.add_argument(
+ '-y', '--yposition', dest='yposition',
+ help='y position', required=False)
+ self.parser.add_argument(
+ '-a', '--alignment', dest='alignment',
+ help='title alignment', required=False,
+ type=int, choices=[0, 1, 2])
+ self.args = self.parser.parse_args()
+
+ self.settings = QSettings('settings.ini', QSettings.IniFormat)
+ LoadDefaultSettings(self)
+
+ # load colours as tuples from comma-separated strings
+ self.textColor = core.Core.RGBFromString(
+ self.settings.value("textColor", '255, 255, 255'))
+ self.visColor = core.Core.RGBFromString(
+ self.settings.value("visColor", '255, 255, 255'))
+ if self.args.textcolor:
+ self.textColor = core.Core.RGBFromString(self.args.textcolor)
+ if self.args.viscolor:
+ self.visColor = core.Core.RGBFromString(self.args.viscolor)
+
+ # font settings
+ if self.args.font:
+ self.font = QFont(self.args.font)
+ else:
+ self.font = QFont(self.settings.value("titleFont", QFont()))
+
+ if self.args.fontsize:
+ self.fontsize = int(self.args.fontsize)
+ else:
+ self.fontsize = int(self.settings.value("fontSize", 35))
+ if self.args.alignment:
+ self.alignment = int(self.args.alignment)
+ else:
+ self.alignment = int(self.settings.value("alignment", 0))
+
+ if self.args.xposition:
+ self.textX = int(self.args.xposition)
+ else:
+ self.textX = int(self.settings.value("xPosition", 70))
+
+ if self.args.yposition:
+ self.textY = int(self.args.yposition)
+ else:
+ self.textY = int(self.settings.value("yPosition", 375))
+
+ ffmpeg_cmd = self.settings.value("ffmpeg_cmd", expanduser("~"))
+
+ self.videoThread = QtCore.QThread(self)
+ self.videoWorker = video_thread.Worker(self)
+
+ self.videoWorker.moveToThread(self.videoThread)
+ self.videoWorker.videoCreated.connect(self.videoCreated)
+
+ self.videoThread.start()
+ self.videoTask.emit(self.args.bgimage,
+ self.args.text,
+ self.font,
+ self.fontsize,
+ self.alignment,
+ self.textX,
+ self.textY,
+ self.textColor,
+ self.visColor,
+ self.args.input,
+ self.args.output,
+ self.selectedComponents)
+
+ def videoCreated(self):
+ self.videoThread.quit()
+ self.videoThread.wait()
+ self.cleanUp()
+
+ def cleanUp(self):
+ self.settings.setValue("titleFont", self.font.toString())
+ self.settings.setValue("alignment", str(self.alignment))
+ self.settings.setValue("fontSize", str(self.fontsize))
+ self.settings.setValue("xPosition", str(self.textX))
+ self.settings.setValue("yPosition", str(self.textY))
+ self.settings.setValue("visColor", '%s,%s,%s' % self.visColor)
+ self.settings.setValue("textColor", '%s,%s,%s' % self.textColor)
+ sys.exit(0)
+'''
diff --git a/components/__base__.py b/components/__base__.py
index f564aad..94ac6f2 100644
--- a/components/__base__.py
+++ b/components/__base__.py
@@ -1,5 +1,6 @@
from PyQt4 import QtGui
+
class Component:
def __str__(self):
return self.__doc__
@@ -14,7 +15,7 @@ class Component:
def reset(self):
self.canceled = False
-
+
def preFrameRender(self, **kwargs):
for var, value in kwargs.items():
exec('self.%s = value' % var)
@@ -22,32 +23,35 @@ class Component:
def pickColor(self):
color = QtGui.QColorDialog.getColor()
if color.isValid():
- RGBstring = '%s,%s,%s' % (str(color.red()), str(color.green()), str(color.blue()))
- btnStyle = "QPushButton { background-color : %s; outline: none; }" % color.name()
+ RGBstring = '%s,%s,%s' % (
+ str(color.red()), str(color.green()), str(color.blue()))
+ btnStyle = "QPushButton{background-color: %s; outline: none;}" \
+ % color.name()
return RGBstring, btnStyle
else:
return None, None
def RGBFromString(self, string):
- ''' turns an RGB string like "255, 255, 255" into a tuple '''
- try:
- tup = tuple([int(i) for i in string.split(',')])
- if len(tup) != 3:
- raise ValueError
- for i in tup:
- if i > 255 or i < 0:
- raise ValueError
- return tup
- except:
- return (255, 255, 255)
+ ''' turns an RGB string like "255, 255, 255" into a tuple '''
+ try:
+ tup = tuple([int(i) for i in string.split(',')])
+ if len(tup) != 3:
+ raise ValueError
+ for i in tup:
+ if i > 255 or i < 0:
+ raise ValueError
+ return tup
+ except:
+ return (255, 255, 255)
'''
### Reference methods for creating a new component
### (Inherit from this class and define these)
-
+
def widget(self, parent):
self.parent = parent
- page = uic.loadUi(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'example.ui'))
+ page = uic.loadUi(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), 'example.ui'))
# connect widgets signals
self.page = page
return page
@@ -55,13 +59,13 @@ class Component:
def update(self):
# read widget values
self.parent.drawPreview()
-
+
def previewRender(self, previewWorker):
width = int(previewWorker.core.settings.value('outputWidth'))
height = int(previewWorker.core.settings.value('outputHeight'))
image = Image.new("RGBA", (width, height), (0,0,0,0))
return image
-
+
def frameRender(self, moduleNo, frameNo):
width = int(self.worker.core.settings.value('outputWidth'))
height = int(self.worker.core.settings.value('outputHeight'))
@@ -70,10 +74,10 @@ class Component:
def loadPreset(self, presetDict):
# update widgets using a preset dict
-
+
def savePreset(self):
return {}
-
+
def cancel(self):
self.canceled = True
diff --git a/components/color.py b/components/color.py
index c2a49e2..b050fbd 100644
--- a/components/color.py
+++ b/components/color.py
@@ -4,31 +4,39 @@ from PyQt4.QtGui import QColor
import os
from . import __base__
+
class Component(__base__.Component):
'''Color'''
def widget(self, parent):
self.parent = parent
- page = uic.loadUi(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'color.ui'))
-
- self.color1 = (0,0,0)
- self.color2 = (133,133,133)
+ page = uic.loadUi(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), 'color.ui'))
+
+ self.color1 = (0, 0, 0)
+ self.color2 = (133, 133, 133)
self.x = 0
self.y = 0
-
+
page.lineEdit_color1.setText('%s,%s,%s' % self.color1)
page.lineEdit_color2.setText('%s,%s,%s' % self.color2)
- page.pushButton_color1.clicked.connect(lambda: self.pickColor(1))
- btnStyle = "QPushButton { background-color : %s; outline: none; }" % QColor(*self.color1).name()
+
+ btnStyle = "QPushButton { background-color : %s; outline: none; }" \
+ % QColor(*self.color1).name()
+
+ btnStyle = "QPushButton { background-color : %s; outline: none; }" \
+ % QColor(*self.color2).name()
+
page.pushButton_color1.setStyleSheet(btnStyle)
- page.pushButton_color2.clicked.connect(lambda: self.pickColor(2))
- btnStyle = "QPushButton { background-color : %s; outline: none; }" % QColor(*self.color2).name()
page.pushButton_color2.setStyleSheet(btnStyle)
+ page.pushButton_color1.clicked.connect(lambda: self.pickColor(1))
+ page.pushButton_color2.clicked.connect(lambda: self.pickColor(2))
+
# disable color #2 until non-default 'fill' option gets changed
page.lineEdit_color2.setDisabled(True)
page.pushButton_color2.setDisabled(True)
page.spinBox_x.setValue(self.x)
page.spinBox_x.setValue(self.y)
-
+
page.lineEdit_color1.textChanged.connect(self.update)
page.lineEdit_color2.textChanged.connect(self.update)
page.spinBox_x.valueChanged.connect(self.update)
@@ -42,39 +50,44 @@ class Component(__base__.Component):
self.x = self.page.spinBox_x.value()
self.y = self.page.spinBox_y.value()
self.parent.drawPreview()
-
+
def previewRender(self, previewWorker):
width = int(previewWorker.core.settings.value('outputWidth'))
height = int(previewWorker.core.settings.value('outputHeight'))
return self.drawFrame(width, height)
-
+
def preFrameRender(self, **kwargs):
super().preFrameRender(**kwargs)
return ['static']
-
+
def frameRender(self, moduleNo, arrayNo, frameNo):
width = int(self.worker.core.settings.value('outputWidth'))
height = int(self.worker.core.settings.value('outputHeight'))
return self.drawFrame(width, height)
-
+
def drawFrame(self, width, height):
- r,g,b = self.color1
+ r, g, b = self.color1
return Image.new("RGBA", (width, height), (r, g, b, 255))
def loadPreset(self, pr):
self.page.lineEdit_color1.setText('%s,%s,%s' % pr['color1'])
self.page.lineEdit_color2.setText('%s,%s,%s' % pr['color2'])
- btnStyle = "QPushButton { background-color : %s; outline: none; }" % QColor(*pr['color1']).name()
+
+ btnStyle = "QPushButton { background-color : %s; outline: none; }" \
+ % QColor(*pr['color1']).name()
+
+ btnStyle = "QPushButton { background-color : %s; outline: none; }" \
+ % QColor(*pr['color2']).name()
+
self.page.pushButton_color1.setStyleSheet(btnStyle)
- btnStyle = "QPushButton { background-color : %s; outline: none; }" % QColor(*pr['color2']).name()
self.page.pushButton_color2.setStyleSheet(btnStyle)
-
+
def savePreset(self):
return {
- 'color1' : self.color1,
- 'color2' : self.color2,
+ 'color1': self.color1,
+ 'color2': self.color2,
}
-
+
def pickColor(self, num):
RGBstring, btnStyle = super().pickColor()
if not RGBstring:
diff --git a/components/image.py b/components/image.py
index ffbb117..f9a92ca 100644
--- a/components/image.py
+++ b/components/image.py
@@ -3,26 +3,28 @@ from PyQt4 import uic, QtGui, QtCore
import os
from . import __base__
+
class Component(__base__.Component):
'''Image'''
def widget(self, parent):
self.parent = parent
self.settings = parent.settings
- page = uic.loadUi(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'image.ui'))
+ page = uic.loadUi(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), 'image.ui'))
self.imagePath = ''
self.x = 0
self.y = 0
-
+
page.lineEdit_image.textChanged.connect(self.update)
page.pushButton_image.clicked.connect(self.pickImage)
-
+
self.page = page
return page
def update(self):
self.imagePath = self.page.lineEdit_image.text()
self.parent.drawPreview()
-
+
def previewRender(self, previewWorker):
width = int(previewWorker.core.settings.value('outputWidth'))
height = int(previewWorker.core.settings.value('outputHeight'))
@@ -36,9 +38,9 @@ class Component(__base__.Component):
width = int(self.worker.core.settings.value('outputWidth'))
height = int(self.worker.core.settings.value('outputHeight'))
return self.drawFrame(width, height)
-
+
def drawFrame(self, width, height):
- frame = Image.new("RGBA", (width, height), (0,0,0,0))
+ frame = Image.new("RGBA", (width, height), (0, 0, 0, 0))
if self.imagePath and os.path.exists(self.imagePath):
image = Image.open(self.imagePath)
if image.size != (width, height):
@@ -48,16 +50,16 @@ class Component(__base__.Component):
def loadPreset(self, pr):
self.page.lineEdit_image.setText(pr['image'])
-
+
def savePreset(self):
return {
- 'image' : self.imagePath,
+ 'image': self.imagePath,
}
-
+
def pickImage(self):
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~"))
- filename = QtGui.QFileDialog.getOpenFileName(self.page,
- "Choose Image", imgDir, "Image Files (*.jpg *.png)")
+ filename = QtGui.QFileDialog.getOpenFileName(
+ self.page, "Choose Image", imgDir, "Image Files (*.jpg *.png)")
if filename:
self.settings.setValue("backgroundDir", os.path.dirname(filename))
self.page.lineEdit_image.setText(filename)
diff --git a/components/original.py b/components/original.py
index b0a7579..4d0e83b 100644
--- a/components/original.py
+++ b/components/original.py
@@ -2,7 +2,8 @@ import numpy
from PIL import Image, ImageDraw
from PyQt4 import uic, QtGui
from PyQt4.QtGui import QColor
-import os, random
+import os
+import random
from . import __base__
import time
from copy import copy
@@ -12,24 +13,25 @@ class Component(__base__.Component):
'''Original Audio Visualization'''
def widget(self, parent):
self.parent = parent
- self.visColor = (255,255,255)
+ self.visColor = (255, 255, 255)
- page = uic.loadUi(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'original.ui'))
+ page = uic.loadUi(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), 'original.ui'))
page.comboBox_visLayout.addItem("Classic")
page.comboBox_visLayout.addItem("Split")
page.comboBox_visLayout.addItem("Bottom")
- #visLayoutValue = int(self.settings.value('visLayout'))
page.comboBox_visLayout.setCurrentIndex(0)
page.comboBox_visLayout.currentIndexChanged.connect(self.update)
page.lineEdit_visColor.setText('%s,%s,%s' % self.visColor)
page.pushButton_visColor.clicked.connect(lambda: self.pickColor())
- btnStyle = "QPushButton { background-color : %s; outline: none; }" % QColor(*self.visColor).name()
+ btnStyle = "QPushButton { background-color : %s; outline: none; }" \
+ % QColor(*self.visColor).name()
page.pushButton_visColor.setStyleSheet(btnStyle)
page.lineEdit_visColor.textChanged.connect(self.update)
self.page = page
self.canceled = False
return page
-
+
def update(self):
self.layout = self.page.comboBox_visLayout.currentIndex()
self.visColor = self.RGBFromString(self.page.lineEdit_visColor.text())
@@ -37,21 +39,25 @@ class Component(__base__.Component):
def loadPreset(self, pr):
self.page.lineEdit_visColor.setText('%s,%s,%s' % pr['visColor'])
- btnStyle = "QPushButton { background-color : %s; outline: none; }" % QColor(*pr['visColor']).name()
+ btnStyle = "QPushButton { background-color : %s; outline: none; }" \
+ % QColor(*pr['visColor']).name()
self.page.pushButton_visColor.setStyleSheet(btnStyle)
self.page.comboBox_visLayout.setCurrentIndex(pr['layout'])
-
+
def savePreset(self):
- return { 'layout' : self.layout,
- 'visColor' : self.visColor,
- }
+ return {
+ 'layout': self.layout,
+ 'visColor': self.visColor,
+ }
def previewRender(self, previewWorker):
- spectrum = numpy.fromfunction(lambda x: 0.008*(x-128)**2, (255,), dtype="int16")
+ spectrum = numpy.fromfunction(
+ lambda x: 0.008*(x-128)**2, (255,), dtype="int16")
width = int(previewWorker.core.settings.value('outputWidth'))
height = int(previewWorker.core.settings.value('outputHeight'))
- return self.drawBars(width, height, spectrum, self.visColor, self.layout)
-
+ return self.drawBars(
+ width, height, spectrum, self.visColor, self.layout)
+
def preFrameRender(self, **kwargs):
super().preFrameRender(**kwargs)
self.smoothConstantDown = 0.08
@@ -64,19 +70,24 @@ class Component(__base__.Component):
for i in range(0, len(self.completeAudioArray), self.sampleSize):
if self.canceled:
break
- self.lastSpectrum = self.transformData(i, self.completeAudioArray, self.sampleSize,
- self.smoothConstantDown, self.smoothConstantUp, self.lastSpectrum)
+ self.lastSpectrum = self.transformData(
+ i, self.completeAudioArray, self.sampleSize,
+ self.smoothConstantDown, self.smoothConstantUp,
+ self.lastSpectrum)
self.spectrumArray[i] = copy(self.lastSpectrum)
progress = int(100*(i/len(self.completeAudioArray)))
if progress >= 100:
progress = 100
- pStr = "Analyzing audio: "+ str(progress) +'%'
+ pStr = "Analyzing audio: "+str(progress)+'%'
self.progressBarSetText.emit(pStr)
self.progressBarUpdate.emit(int(progress))
-
+
def frameRender(self, moduleNo, arrayNo, frameNo):
- return self.drawBars(self.width, self.height, self.spectrumArray[arrayNo], self.visColor, self.layout)
+ return self.drawBars(
+ self.width, self.height,
+ self.spectrumArray[arrayNo],
+ self.visColor, self.layout)
def pickColor(self):
RGBstring, btnStyle = super().pickColor()
@@ -85,14 +96,17 @@ class Component(__base__.Component):
self.page.lineEdit_visColor.setText(RGBstring)
self.page.pushButton_visColor.setStyleSheet(btnStyle)
- def transformData(self, i, completeAudioArray, sampleSize, smoothConstantDown, smoothConstantUp, lastSpectrum):
+ def transformData(
+ self, i, completeAudioArray, sampleSize,
+ smoothConstantDown, smoothConstantUp, lastSpectrum):
if len(completeAudioArray) < (i + sampleSize):
sampleSize = len(completeAudioArray) - i
window = numpy.hanning(sampleSize)
data = completeAudioArray[i:i+sampleSize][::1] * window
paddedSampleSize = 2048
- paddedData = numpy.pad(data, (0, paddedSampleSize - sampleSize), 'constant')
+ paddedData = numpy.pad(
+ data, (0, paddedSampleSize - sampleSize), 'constant')
spectrum = numpy.fft.fft(paddedData)
sample_rate = 44100
frequencies = numpy.fft.fftfreq(len(spectrum), 1./sample_rate)
@@ -106,8 +120,13 @@ class Component(__base__.Component):
y[numpy.isinf(y)] = 0
if lastSpectrum is not None:
- lastSpectrum[y < lastSpectrum] = y[y < lastSpectrum] * smoothConstantDown + lastSpectrum[y < lastSpectrum] * (1 - smoothConstantDown)
- lastSpectrum[y >= lastSpectrum] = y[y >= lastSpectrum] * smoothConstantUp + lastSpectrum[y >= lastSpectrum] * (1 - smoothConstantUp)
+ lastSpectrum[y < lastSpectrum] = \
+ y[y < lastSpectrum] * smoothConstantDown + \
+ lastSpectrum[y < lastSpectrum] * (1 - smoothConstantDown)
+
+ lastSpectrum[y >= lastSpectrum] = \
+ y[y >= lastSpectrum] * smoothConstantUp + \
+ lastSpectrum[y >= lastSpectrum] * (1 - smoothConstantUp)
else:
lastSpectrum = y
@@ -120,7 +139,7 @@ class Component(__base__.Component):
bF = width / 64
bH = bF / 2
bQ = bF / 4
- imTop = Image.new("RGBA", (width, height),(0,0,0,0))
+ imTop = Image.new("RGBA", (width, height), (0, 0, 0, 0))
draw = ImageDraw.Draw(imTop)
r, g, b = color
color2 = (r, g, b, 125)
@@ -128,12 +147,17 @@ class Component(__base__.Component):
bP = height / 1200
for j in range(0, 63):
- draw.rectangle((bH + j * bF, vH+bQ, bH + j * bF + bF, vH + bQ - spectrum[j * 4] * bP - bH), fill=color2)
- draw.rectangle((bH + bQ + j * bF, vH , bH + bQ + j * bF + bH, vH - spectrum[j * 4] * bP), fill=color)
+ draw.rectangle((
+ bH + j * bF, vH+bQ, bH + j * bF + bF, vH + bQ -
+ spectrum[j * 4] * bP - bH), fill=color2)
+
+ draw.rectangle((
+ bH + bQ + j * bF, vH, bH + bQ + j * bF + bH, vH -
+ spectrum[j * 4] * bP), fill=color)
imBottom = imTop.transpose(Image.FLIP_TOP_BOTTOM)
- im = Image.new("RGBA", (width, height),(0,0,0,0))
+ im = Image.new("RGBA", (width, height), (0, 0, 0, 0))
if layout == 0:
y = 0 - int(height/100*43)
diff --git a/components/text.py b/components/text.py
index 56a9502..6cdc0dd 100644
--- a/components/text.py
+++ b/components/text.py
@@ -25,9 +25,7 @@ class Component(__base__.Component):
self.yPosition = height / 2 * 1.036
page = uic.loadUi(os.path.join(
- os.path.dirname(os.path.realpath(__file__)),
- 'text.ui'
- ))
+ os.path.dirname(os.path.realpath(__file__)), 'text.ui'))
page.comboBox_textAlign.addItem("Left")
page.comboBox_textAlign.addItem("Middle")
page.comboBox_textAlign.addItem("Right")
@@ -61,7 +59,8 @@ class Component(__base__.Component):
self.fontSize = self.page.spinBox_fontSize.value()
self.xPosition = self.page.spinBox_xTextAlign.value()
self.yPosition = self.page.spinBox_yTextAlign.value()
- self.textColor = self.RGBFromString(self.page.lineEdit_textColor.text())
+ self.textColor = self.RGBFromString(
+ self.page.lineEdit_textColor.text())
self.parent.drawPreview()
def getXY(self):
@@ -95,14 +94,14 @@ class Component(__base__.Component):
def savePreset(self):
return {
- 'title': self.title,
- 'titleFont': self.titleFont.toString(),
- 'alignment': self.alignment,
- 'fontSize': self.fontSize,
- 'xPosition': self.xPosition,
- 'yPosition': self.yPosition,
- 'textColor': self.textColor
- }
+ 'title': self.title,
+ 'titleFont': self.titleFont.toString(),
+ 'alignment': self.alignment,
+ 'fontSize': self.fontSize,
+ 'xPosition': self.xPosition,
+ 'yPosition': self.yPosition,
+ 'textColor': self.textColor
+ }
def previewRender(self, previewWorker):
width = int(previewWorker.core.settings.value('outputWidth'))
diff --git a/components/video.py b/components/video.py
index de91264..67a96dd 100644
--- a/components/video.py
+++ b/components/video.py
@@ -1,12 +1,18 @@
from PIL import Image, ImageDraw
from PyQt4 import uic, QtGui, QtCore
-import os, subprocess, threading
+import os
+import subprocess
+import threading
from queue import PriorityQueue
from . import __base__
+
class Video:
'''Video Component Frame-Fetcher'''
- def __init__(self, ffmpeg, videoPath, width, height, frameRate, chunkSize, parent, loopVideo):
+ def __init__(
+ self, ffmpeg, videoPath, width, height,
+ frameRate, chunkSize, parent, loopVideo):
+
self.parent = parent
self.chunkSize = chunkSize
self.size = (width, height)
@@ -27,15 +33,18 @@ class Video:
'-filter:v', 'scale='+str(width)+':'+str(height),
'-vcodec', 'rawvideo', '-',
]
-
+
self.frameBuffer = PriorityQueue()
self.frameBuffer.maxsize = int(frameRate)
self.finishedFrames = {}
-
- self.thread = threading.Thread(target=self.fillBuffer, name=self.__doc__)
+
+ self.thread = threading.Thread(
+ target=self.fillBuffer,
+ name=self.__doc__
+ )
self.thread.daemon = True
self.thread.start()
-
+
def frame(self, num):
while True:
if num in self.finishedFrames:
@@ -44,9 +53,12 @@ class Video:
i, image = self.frameBuffer.get()
self.finishedFrames[i] = image
self.frameBuffer.task_done()
-
- def fillBuffer(self):
- self.pipe = subprocess.Popen(self.command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8)
+
+ def fillBuffer(self):
+ self.pipe = subprocess.Popen(
+ self.command, stdout=subprocess.PIPE,
+ stderr=subprocess.DEVNULL, bufsize=10**8
+ )
while True:
if self.parent.canceled:
break
@@ -58,26 +70,29 @@ class Video:
continue
self.currentFrame = self.pipe.stdout.read(self.chunkSize)
- #print('creating frame #%s' % str(self.frameNo))
if len(self.currentFrame) != 0:
self.frameBuffer.put((self.frameNo, self.currentFrame))
self.lastFrame = self.currentFrame
+
class Component(__base__.Component):
'''Video'''
def widget(self, parent):
self.parent = parent
self.settings = parent.settings
- page = uic.loadUi(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'video.ui'))
+ page = uic.loadUi(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ 'video.ui'
+ ))
self.videoPath = ''
self.x = 0
self.y = 0
self.loopVideo = False
-
+
page.lineEdit_video.textChanged.connect(self.update)
page.pushButton_video.clicked.connect(self.pickVideo)
page.checkBox_loop.stateChanged.connect(self.update)
-
+
self.page = page
return page
@@ -85,46 +100,50 @@ class Component(__base__.Component):
self.videoPath = self.page.lineEdit_video.text()
self.loopVideo = self.page.checkBox_loop.isChecked()
self.parent.drawPreview()
-
+
def previewRender(self, previewWorker):
width = int(previewWorker.core.settings.value('outputWidth'))
height = int(previewWorker.core.settings.value('outputHeight'))
self.chunkSize = 4*width*height
frame = self.getPreviewFrame(width, height)
if not frame:
- return Image.new("RGBA", (width, height),(0,0,0,0))
+ return Image.new("RGBA", (width, height), (0, 0, 0, 0))
else:
return frame
-
+
def preFrameRender(self, **kwargs):
super().preFrameRender(**kwargs)
width = int(self.worker.core.settings.value('outputWidth'))
height = int(self.worker.core.settings.value('outputHeight'))
self.chunkSize = 4*width*height
- self.video = Video(self.parent.core.FFMPEG_BIN, self.videoPath,
+ self.video = Video(
+ self.parent.core.FFMPEG_BIN, self.videoPath,
width, height, self.settings.value("outputFrameRate"),
- self.chunkSize, self.parent, self.loopVideo)
-
+ self.chunkSize, self.parent, self.loopVideo
+ )
+
def frameRender(self, moduleNo, arrayNo, frameNo):
return self.video.frame(frameNo)
def loadPreset(self, pr):
self.page.lineEdit_video.setText(pr['video'])
-
+
def savePreset(self):
return {
- 'video' : self.videoPath,
+ 'video': self.videoPath,
}
-
+
def pickVideo(self):
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~"))
- filename = QtGui.QFileDialog.getOpenFileName(self.page,
- "Choose Video", imgDir, "Video Files (*.mp4 *.mov)")
+ filename = QtGui.QFileDialog.getOpenFileName(
+ self.page, "Choose Video",
+ imgDir, "Video Files (*.mp4 *.mov)"
+ )
if filename:
self.settings.setValue("backgroundDir", os.path.dirname(filename))
self.page.lineEdit_video.setText(filename)
self.update()
-
+
def getPreviewFrame(self, width, height):
if not self.videoPath or not os.path.exists(self.videoPath):
return
@@ -139,7 +158,10 @@ class Component(__base__.Component):
'-ss', '90',
'-vframes', '1',
]
- pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8)
+ pipe = subprocess.Popen(
+ command, stdout=subprocess.PIPE,
+ stderr=subprocess.DEVNULL, bufsize=10**8
+ )
byteFrame = pipe.stdout.read(self.chunkSize)
image = Image.frombytes('RGBA', (width, height), byteFrame)
pipe.stdout.close()
diff --git a/core.py b/core.py
index 99403f1..8ea884b 100644
--- a/core.py
+++ b/core.py
@@ -1,4 +1,6 @@
-import sys, io, os
+import sys
+import io
+import os
from PyQt4 import QtCore, QtGui, uic
from os.path import expanduser
import subprocess as sp
@@ -10,103 +12,106 @@ import atexit
import time
from collections import OrderedDict
+
class Core():
- def __init__(self):
- self.FFMPEG_BIN = self.findFfmpeg()
- self.tempDir = os.path.join(tempfile.gettempdir(), 'audio-visualizer-python-data')
- if not os.path.exists(self.tempDir):
- os.makedirs(self.tempDir)
- atexit.register(self.deleteTempDir)
-
- def findFfmpeg(self):
- if sys.platform == "win32":
- return "ffmpeg.exe"
- else:
- try:
- with open(os.devnull, "w") as f:
- sp.check_call(['ffmpeg', '-version'], stdout=f, stderr=f)
- return "ffmpeg"
- except:
- return "avconv"
-
- def readAudioFile(self, filename, parent):
- command = [ self.FFMPEG_BIN,
- '-i', filename]
-
- try:
- fileInfo = sp.check_output(command, stderr=sp.STDOUT, shell=False)
- except sp.CalledProcessError as ex:
- fileInfo = ex.output
- pass
-
- info = fileInfo.decode("utf-8").split('\n')
- for line in info:
- if 'Duration' in line:
- d = line.split(',')[0]
- d = d.split(' ')[3]
- d = d.split(':')
- duration = float(d[0])*3600 + float(d[1])*60 + float(d[2])
-
- command = [ self.FFMPEG_BIN,
- '-i', filename,
- '-f', 's16le',
- '-acodec', 'pcm_s16le',
- '-ar', '44100', # ouput will have 44100 Hz
- '-ac', '1', # mono (set to '2' for stereo)
- '-']
- in_pipe = sp.Popen(command, stdout=sp.PIPE, stderr=sp.DEVNULL, bufsize=10**8)
-
- completeAudioArray = numpy.empty(0, dtype="int16")
-
- progress = 0
- lastPercent = None
- while True:
- if self.canceled:
- break
- # read 2 seconds of audio
- progress = progress + 4
- raw_audio = in_pipe.stdout.read(88200*4)
- if len(raw_audio) == 0:
- break
- audio_array = numpy.fromstring(raw_audio, dtype="int16")
- completeAudioArray = numpy.append(completeAudioArray, audio_array)
-
- percent = int(100*(progress/duration))
- if percent >= 100:
- percent = 100
-
- if lastPercent != percent:
- string = 'Loading audio file: '+str(percent)+'%'
- parent.progressBarSetText.emit(string)
- parent.progressBarUpdate.emit(percent)
-
- lastPercent = percent
-
-
- in_pipe.kill()
- in_pipe.wait()
-
- # add 0s the end
- completeAudioArrayCopy = numpy.zeros(len(completeAudioArray) + 44100, dtype="int16")
- completeAudioArrayCopy[:len(completeAudioArray)] = completeAudioArray
- completeAudioArray = completeAudioArrayCopy
-
- return completeAudioArray
-
- def deleteTempDir(self):
- try:
- rmtree(self.tempDir)
- except FileNotFoundError:
- pass
-
- def cancel(self):
- self.canceled = True
-
- def reset(self):
- self.canceled = False
-
- @staticmethod
- def stringOrderedDict(dictionary):
- sorted_ = OrderedDict(sorted(dictionary.items(), key=lambda t: t[0]))
- return repr(sorted_)
+ def __init__(self):
+ self.FFMPEG_BIN = self.findFfmpeg()
+ self.tempDir = os.path.join(
+ tempfile.gettempdir(), 'audio-visualizer-python-data')
+ if not os.path.exists(self.tempDir):
+ os.makedirs(self.tempDir)
+ atexit.register(self.deleteTempDir)
+
+ def findFfmpeg(self):
+ if sys.platform == "win32":
+ return "ffmpeg.exe"
+ else:
+ try:
+ with open(os.devnull, "w") as f:
+ sp.check_call(['ffmpeg', '-version'], stdout=f, stderr=f)
+ return "ffmpeg"
+ except:
+ return "avconv"
+
+ def readAudioFile(self, filename, parent):
+ command = [self.FFMPEG_BIN, '-i', filename]
+
+ try:
+ fileInfo = sp.check_output(command, stderr=sp.STDOUT, shell=False)
+ except sp.CalledProcessError as ex:
+ fileInfo = ex.output
+ pass
+
+ info = fileInfo.decode("utf-8").split('\n')
+ for line in info:
+ if 'Duration' in line:
+ d = line.split(',')[0]
+ d = d.split(' ')[3]
+ d = d.split(':')
+ duration = float(d[0])*3600 + float(d[1])*60 + float(d[2])
+
+ command = [
+ self.FFMPEG_BIN,
+ '-i', filename,
+ '-f', 's16le',
+ '-acodec', 'pcm_s16le',
+ '-ar', '44100', # ouput will have 44100 Hz
+ '-ac', '1', # mono (set to '2' for stereo)
+ '-']
+ in_pipe = sp.Popen(
+ command, stdout=sp.PIPE, stderr=sp.DEVNULL, bufsize=10**8)
+
+ completeAudioArray = numpy.empty(0, dtype="int16")
+
+ progress = 0
+ lastPercent = None
+ while True:
+ if self.canceled:
+ break
+ # read 2 seconds of audio
+ progress = progress + 4
+ raw_audio = in_pipe.stdout.read(88200*4)
+ if len(raw_audio) == 0:
+ break
+ audio_array = numpy.fromstring(raw_audio, dtype="int16")
+ completeAudioArray = numpy.append(completeAudioArray, audio_array)
+
+ percent = int(100*(progress/duration))
+ if percent >= 100:
+ percent = 100
+
+ if lastPercent != percent:
+ string = 'Loading audio file: '+str(percent)+'%'
+ parent.progressBarSetText.emit(string)
+ parent.progressBarUpdate.emit(percent)
+
+ lastPercent = percent
+
+ in_pipe.kill()
+ in_pipe.wait()
+
+ # add 0s the end
+ completeAudioArrayCopy = numpy.zeros(
+ len(completeAudioArray) + 44100, dtype="int16")
+ completeAudioArrayCopy[:len(completeAudioArray)] = completeAudioArray
+ completeAudioArray = completeAudioArrayCopy
+
+ return completeAudioArray
+
+ def deleteTempDir(self):
+ try:
+ rmtree(self.tempDir)
+ except FileNotFoundError:
+ pass
+
+ def cancel(self):
+ self.canceled = True
+
+ def reset(self):
+ self.canceled = False
+
+ @staticmethod
+ def stringOrderedDict(dictionary):
+ sorted_ = OrderedDict(sorted(dictionary.items(), key=lambda t: t[0]))
+ return repr(sorted_)
diff --git a/main.py b/main.py
index c75a7f7..78c1d9b 100644
--- a/main.py
+++ b/main.py
@@ -1,668 +1,67 @@
-import sys, io, os, shutil, atexit, string, signal, filecmp, time
-from os.path import expanduser
-from queue import Queue
from importlib import import_module
from collections import OrderedDict
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import QSettings, QModelIndex, Qt
-from PyQt4.QtGui import QDesktopServices, QMenu
+from PyQt4 import QtGui, uic
+from PyQt4.QtCore import Qt
+import sys
+import io
+import os
+import atexit
+import signal
-import preview_thread, core, video_thread
+import core
+import preview_thread
+import video_thread
+from mainwindow import *
-# FIXME: commandline functionality broken until we decide how to implement it
-'''
-class Command(QtCore.QObject):
-
- videoTask = QtCore.pyqtSignal(str, str, str, list)
-
- def __init__(self):
- QtCore.QObject.__init__(self)
- self.modules = []
- self.selectedComponents = []
-
- import argparse
- self.parser = argparse.ArgumentParser(description='Create a visualization for an audio file')
- self.parser.add_argument('-i', '--input', dest='input', help='input audio file', required=True)
- self.parser.add_argument('-o', '--output', dest='output', help='output video file', required=True)
- self.parser.add_argument('-b', '--background', dest='bgimage', help='background image file', required=True)
- self.parser.add_argument('-t', '--text', dest='text', help='title text', required=True)
- self.parser.add_argument('-f', '--font', dest='font', help='title font', required=False)
- self.parser.add_argument('-s', '--fontsize', dest='fontsize', help='title font size', required=False)
- self.parser.add_argument('-c', '--textcolor', dest='textcolor', help='title text color in r,g,b format', required=False)
- self.parser.add_argument('-C', '--viscolor', dest='viscolor', help='visualization color in r,g,b format', required=False)
- self.parser.add_argument('-x', '--xposition', dest='xposition', help='x position', required=False)
- self.parser.add_argument('-y', '--yposition', dest='yposition', help='y position', required=False)
- self.parser.add_argument('-a', '--alignment', dest='alignment', help='title alignment', required=False, type=int, choices=[0, 1, 2])
- self.args = self.parser.parse_args()
-
- self.settings = QSettings('settings.ini', QSettings.IniFormat)
- LoadDefaultSettings(self)
-
- # load colours as tuples from comma-separated strings
- self.textColor = core.Core.RGBFromString(self.settings.value("textColor", '255, 255, 255'))
- self.visColor = core.Core.RGBFromString(self.settings.value("visColor", '255, 255, 255'))
- if self.args.textcolor:
- self.textColor = core.Core.RGBFromString(self.args.textcolor)
- if self.args.viscolor:
- self.visColor = core.Core.RGBFromString(self.args.viscolor)
-
- # font settings
- if self.args.font:
- self.font = QFont(self.args.font)
- else:
- self.font = QFont(self.settings.value("titleFont", QFont()))
-
- if self.args.fontsize:
- self.fontsize = int(self.args.fontsize)
- else:
- self.fontsize = int(self.settings.value("fontSize", 35))
- if self.args.alignment:
- self.alignment = int(self.args.alignment)
- else:
- self.alignment = int(self.settings.value("alignment", 0))
-
- if self.args.xposition:
- self.textX = int(self.args.xposition)
- else:
- self.textX = int(self.settings.value("xPosition", 70))
-
- if self.args.yposition:
- self.textY = int(self.args.yposition)
- else:
- self.textY = int(self.settings.value("yPosition", 375))
-
- ffmpeg_cmd = self.settings.value("ffmpeg_cmd", expanduser("~"))
-
- self.videoThread = QtCore.QThread(self)
- self.videoWorker = video_thread.Worker(self)
-
- self.videoWorker.moveToThread(self.videoThread)
- self.videoWorker.videoCreated.connect(self.videoCreated)
-
- self.videoThread.start()
- self.videoTask.emit(self.args.bgimage,
- self.args.text,
- self.font,
- self.fontsize,
- self.alignment,
- self.textX,
- self.textY,
- self.textColor,
- self.visColor,
- self.args.input,
- self.args.output,
- self.selectedComponents)
-
- def videoCreated(self):
- self.videoThread.quit()
- self.videoThread.wait()
- self.cleanUp()
-
- def cleanUp(self):
- self.settings.setValue("titleFont", self.font.toString())
- self.settings.setValue("alignment", str(self.alignment))
- self.settings.setValue("fontSize", str(self.fontsize))
- self.settings.setValue("xPosition", str(self.textX))
- self.settings.setValue("yPosition", str(self.textY))
- self.settings.setValue("visColor", '%s,%s,%s' % self.visColor)
- self.settings.setValue("textColor", '%s,%s,%s' % self.textColor)
- sys.exit(0)
-'''
-
-class PreviewWindow(QtGui.QLabel):
- def __init__(self, parent, img):
- super(PreviewWindow, self).__init__()
- self.parent = parent
- self.setFrameStyle(QtGui.QFrame.StyledPanel)
- self.pixmap = QtGui.QPixmap(img)
-
- def paintEvent(self, event):
- size = self.size()
- painter = QtGui.QPainter(self)
- point = QtCore.QPoint(0,0)
- scaledPix = self.pixmap.scaled(size, Qt.KeepAspectRatio, transformMode = Qt.SmoothTransformation)
- # start painting the label from left upper corner
- point.setX((size.width() - scaledPix.width())/2)
- point.setY((size.height() - scaledPix.height())/2)
- #print point.x(), ' ', point.y()
- painter.drawPixmap(point, scaledPix)
-
- def changePixmap(self, img):
- self.pixmap = QtGui.QPixmap(img)
- self.repaint()
-
-class Main(QtCore.QObject):
-
- newTask = QtCore.pyqtSignal(list)
- processTask = QtCore.pyqtSignal()
- videoTask = QtCore.pyqtSignal(str, str, list)
-
- def __init__(self, window):
- QtCore.QObject.__init__(self)
-
- # print('main thread id: {}'.format(QtCore.QThread.currentThreadId()))
- self.window = window
- self.core = core.Core()
- self.pages = []
- self.selectedComponents = []
- self.lastAutosave = time.time()
-
- # create data directory, load/create settings
- self.dataDir = QDesktopServices.storageLocation(QDesktopServices.DataLocation)
- self.autosavePath = os.path.join(self.dataDir, 'autosave.avp')
- self.presetDir = os.path.join(self.dataDir, 'presets')
- self.settings = QSettings(os.path.join(self.dataDir, 'settings.ini'), QSettings.IniFormat)
- LoadDefaultSettings(self)
- if not os.path.exists(self.dataDir):
- os.makedirs(self.dataDir)
- for neededDirectory in (self.presetDir, self.settings.value("projectDir")):
- if not os.path.exists(neededDirectory):
- os.mkdir(neededDirectory)
-
- #
- self.previewQueue = Queue()
- self.previewThread = QtCore.QThread(self)
- self.previewWorker = preview_thread.Worker(self, self.previewQueue)
- self.previewWorker.moveToThread(self.previewThread)
- self.previewWorker.imageCreated.connect(self.showPreviewImage)
- self.previewThread.start()
-
- self.timer = QtCore.QTimer(self)
- self.timer.timeout.connect(self.processTask.emit)
- self.timer.start(500)
-
- # begin decorating the window and connecting events
- window.toolButton_selectAudioFile.clicked.connect(self.openInputFileDialog)
- window.toolButton_selectOutputFile.clicked.connect(self.openOutputFileDialog)
- window.progressBar_createVideo.setValue(0)
- window.pushButton_createVideo.clicked.connect(self.createAudioVisualisation)
- window.pushButton_Cancel.clicked.connect(self.stopVideo)
- window.setWindowTitle("Audio Visualizer")
-
- self.previewWindow = PreviewWindow(self, os.path.join(os.path.dirname(os.path.realpath(__file__)), "background.png"))
- window.verticalLayout_previewWrapper.addWidget(self.previewWindow)
-
- self.modules = self.findComponents()
- self.compMenu = QMenu()
- for i, comp in enumerate(self.modules):
- action = self.compMenu.addAction(comp.Component.__doc__)
- action.triggered[()].connect( lambda item=i: self.insertComponent(item))
-
- self.window.pushButton_addComponent.setMenu(self.compMenu)
- window.listWidget_componentList.clicked.connect(lambda _: self.changeComponentWidget())
-
- self.window.pushButton_removeComponent.clicked.connect(lambda _: self.removeComponent())
-
- currentRes = str(self.settings.value('outputWidth'))+'x'+str(self.settings.value('outputHeight'))
- for i, res in enumerate(self.resolutions):
- window.comboBox_resolution.addItem(res)
- if res == currentRes:
- currentRes = i
- window.comboBox_resolution.setCurrentIndex(currentRes)
- window.comboBox_resolution.currentIndexChanged.connect(self.updateResolution)
-
- self.window.pushButton_listMoveUp.clicked.connect(self.moveComponentUp)
- self.window.pushButton_listMoveDown.clicked.connect(self.moveComponentDown)
-
- self.window.pushButton_savePreset.clicked.connect(self.openSavePresetDialog)
- self.window.comboBox_openPreset.currentIndexChanged.connect(self.openPreset)
- self.window.pushButton_saveAs.clicked.connect(self.openSaveProjectDialog)
- self.window.pushButton_saveProject.clicked.connect(self.saveCurrentProject)
- self.window.pushButton_openProject.clicked.connect(self.openOpenProjectDialog)
-
- # show the window and load current project
- window.show()
- self.currentProject = self.settings.value("currentProject")
- if self.currentProject and os.path.exists(self.autosavePath) \
- and filecmp.cmp(self.autosavePath, self.currentProject):
- # delete autosave if it's identical to the project
- os.remove(self.autosavePath)
-
- if self.currentProject and os.path.exists(self.autosavePath):
- ch = self.showMessage("Restore unsaved changes in project '%s'?" % os.path.basename(self.currentProject)[:-4], True)
- if ch:
- os.remove(self.currentProject)
- os.rename(self.autosavePath, self.currentProject)
- else:
- os.remove(self.autosavePath)
-
- self.openProject(self.currentProject)
- self.drawPreview()
-
- def cleanUp(self):
- self.timer.stop()
- self.previewThread.quit()
- self.previewThread.wait()
- self.autosave()
-
- def autosave(self):
- if time.time() - self.lastAutosave >= 1.0:
- if os.path.exists(self.autosavePath):
- os.remove(self.autosavePath)
- self.createProjectFile(self.autosavePath)
- self.lastAutosave = time.time()
-
- def openInputFileDialog(self):
- inputDir = self.settings.value("inputDir", expanduser("~"))
-
- fileName = QtGui.QFileDialog.getOpenFileName(self.window,
- "Open Music File", inputDir, "Music Files (*.mp3 *.wav *.ogg *.fla *.aac)");
-
- if not fileName == "":
- self.settings.setValue("inputDir", os.path.dirname(fileName))
- self.window.lineEdit_audioFile.setText(fileName)
-
- def openOutputFileDialog(self):
- outputDir = self.settings.value("outputDir", expanduser("~"))
-
- fileName = QtGui.QFileDialog.getSaveFileName(self.window,
- "Set Output Video File", outputDir, "Video Files (*.mp4 *.mov *.mkv *.avi *.webm *.flv)");
-
- if not fileName == "":
- self.settings.setValue("outputDir", os.path.dirname(fileName))
- self.window.lineEdit_outputFile.setText(fileName)
-
- def stopVideo(self):
- print('stop')
- self.videoWorker.cancel()
- self.canceled = True
-
- def createAudioVisualisation(self):
- # create output video if mandatory settings are filled in
- if self.window.lineEdit_audioFile.text() and self.window.lineEdit_outputFile.text():
- self.canceled = False
- self.progressBarUpdated(-1)
- ffmpeg_cmd = self.settings.value("ffmpeg_cmd", expanduser("~"))
- self.videoThread = QtCore.QThread(self)
- self.videoWorker = video_thread.Worker(self)
- self.videoWorker.moveToThread(self.videoThread)
- self.videoWorker.videoCreated.connect(self.videoCreated)
- self.videoWorker.progressBarUpdate.connect(self.progressBarUpdated)
- self.videoWorker.progressBarSetText.connect(self.progressBarSetText)
- self.videoWorker.imageCreated.connect(self.showPreviewImage)
- self.videoWorker.encoding.connect(self.changeEncodingStatus)
- self.videoThread.start()
- self.videoTask.emit(self.window.lineEdit_audioFile.text(),
- self.window.lineEdit_outputFile.text(),
- self.selectedComponents)
- else:
- self.showMessage("You must select an audio file and output filename.")
-
- def progressBarUpdated(self, value):
- self.window.progressBar_createVideo.setValue(value)
-
- def changeEncodingStatus(self, status):
- if status:
- self.window.pushButton_createVideo.setEnabled(False)
- self.window.pushButton_Cancel.setEnabled(True)
- self.window.comboBox_resolution.setEnabled(False)
- self.window.stackedWidget.setEnabled(False)
- self.window.tab_encoderSettings.setEnabled(False)
- self.window.label_audioFile.setEnabled(False)
- self.window.toolButton_selectAudioFile.setEnabled(False)
- self.window.label_outputFile.setEnabled(False)
- self.window.toolButton_selectOutputFile.setEnabled(False)
- self.window.lineEdit_audioFile.setEnabled(False)
- self.window.lineEdit_outputFile.setEnabled(False)
- self.window.pushButton_addComponent.setEnabled(False)
- self.window.pushButton_removeComponent.setEnabled(False)
- self.window.pushButton_listMoveDown.setEnabled(False)
- self.window.pushButton_listMoveUp.setEnabled(False)
- self.window.comboBox_openPreset.setEnabled(False)
- self.window.pushButton_removePreset.setEnabled(False)
- self.window.pushButton_savePreset.setEnabled(False)
- self.window.pushButton_openProject.setEnabled(False)
- self.window.listWidget_componentList.setEnabled(False)
- else:
- self.window.pushButton_createVideo.setEnabled(True)
- self.window.pushButton_Cancel.setEnabled(False)
- self.window.comboBox_resolution.setEnabled(True)
- self.window.stackedWidget.setEnabled(True)
- self.window.tab_encoderSettings.setEnabled(True)
- self.window.label_audioFile.setEnabled(True)
- self.window.toolButton_selectAudioFile.setEnabled(True)
- self.window.lineEdit_audioFile.setEnabled(True)
- self.window.label_outputFile.setEnabled(True)
- self.window.toolButton_selectOutputFile.setEnabled(True)
- self.window.lineEdit_outputFile.setEnabled(True)
- self.window.pushButton_addComponent.setEnabled(True)
- self.window.pushButton_removeComponent.setEnabled(True)
- self.window.pushButton_listMoveDown.setEnabled(True)
- self.window.pushButton_listMoveUp.setEnabled(True)
- self.window.comboBox_openPreset.setEnabled(True)
- self.window.pushButton_removePreset.setEnabled(True)
- self.window.pushButton_savePreset.setEnabled(True)
- self.window.pushButton_openProject.setEnabled(True)
- self.window.listWidget_componentList.setEnabled(True)
-
- def progressBarSetText(self, value):
- self.window.progressBar_createVideo.setFormat(value)
-
- def videoCreated(self):
- self.videoThread.quit()
- self.videoThread.wait()
-
- def updateResolution(self):
- resIndex = int(window.comboBox_resolution.currentIndex())
- res = self.resolutions[resIndex].split('x')
- self.settings.setValue('outputWidth',res[0])
- self.settings.setValue('outputHeight',res[1])
- self.drawPreview()
-
- def drawPreview(self):
- self.newTask.emit(self.selectedComponents)
- # self.processTask.emit()
- self.autosave()
-
- def showPreviewImage(self, image):
- self.previewWindow.changePixmap(image)
-
- def findComponents(self):
- def findComponents():
- srcPath = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'components')
- if os.path.exists(srcPath):
- for f in sorted(os.listdir(srcPath)):
- name, ext = os.path.splitext(f)
- if name.startswith("__"):
- continue
- elif ext == '.py':
- yield name
- return [import_module('components.%s' % name) for name in findComponents()]
-
- def addComponent(self, moduleIndex):
- index = len(self.pages)
- self.selectedComponents.append(self.modules[moduleIndex].Component())
- self.window.listWidget_componentList.addItem(self.selectedComponents[-1].__doc__)
- self.pages.append(self.selectedComponents[-1].widget(self))
- self.window.listWidget_componentList.setCurrentRow(index)
- self.window.stackedWidget.addWidget(self.pages[-1])
- self.window.stackedWidget.setCurrentIndex(index)
- self.selectedComponents[-1].update()
- self.updateOpenPresetComboBox(self.selectedComponents[-1])
-
- def insertComponent(self, moduleIndex):
- self.selectedComponents.insert(0, self.modules[moduleIndex].Component())
- self.window.listWidget_componentList.insertItem(0, self.selectedComponents[0].__doc__)
- self.pages.insert(0, self.selectedComponents[0].widget(self))
- self.window.listWidget_componentList.setCurrentRow(0)
- self.window.stackedWidget.insertWidget(0, self.pages[0])
- self.window.stackedWidget.setCurrentIndex(0)
- self.selectedComponents[0].update()
- self.updateOpenPresetComboBox(self.selectedComponents[0])
-
- def removeComponent(self):
- for selected in self.window.listWidget_componentList.selectedItems():
- index = self.window.listWidget_componentList.row(selected)
- self.window.stackedWidget.removeWidget(self.pages[index])
- self.window.listWidget_componentList.takeItem(index)
- self.selectedComponents.pop(index)
- self.pages.pop(index)
- self.changeComponentWidget()
- self.drawPreview()
-
- def changeComponentWidget(self):
- selected = self.window.listWidget_componentList.selectedItems()
- if selected:
- index = self.window.listWidget_componentList.row(selected[0])
- self.window.stackedWidget.setCurrentIndex(index)
- self.updateOpenPresetComboBox(self.selectedComponents[index])
-
- def moveComponentUp(self):
- row = self.window.listWidget_componentList.currentRow()
- if row > 0:
- module = self.selectedComponents[row]
- self.selectedComponents.pop(row)
- self.selectedComponents.insert(row - 1,module)
- page = self.pages[row]
- self.pages.pop(row)
- self.pages.insert(row - 1, page)
- item = self.window.listWidget_componentList.takeItem(row)
- self.window.listWidget_componentList.insertItem(row - 1, item)
- widget = self.window.stackedWidget.removeWidget(page)
- self.window.stackedWidget.insertWidget(row - 1, page)
- self.window.listWidget_componentList.setCurrentRow(row - 1)
- self.window.stackedWidget.setCurrentIndex(row -1)
- self.drawPreview()
-
- def moveComponentDown(self):
- row = self.window.listWidget_componentList.currentRow()
- if row != -1 and row < len(self.pages)+1:
- module = self.selectedComponents[row]
- self.selectedComponents.pop(row)
- self.selectedComponents.insert(row + 1,module)
- page = self.pages[row]
- self.pages.pop(row)
- self.pages.insert(row + 1, page)
- item = self.window.listWidget_componentList.takeItem(row)
- self.window.listWidget_componentList.insertItem(row + 1, item)
- widget = self.window.stackedWidget.removeWidget(page)
- self.window.stackedWidget.insertWidget(row + 1, page)
- self.window.listWidget_componentList.setCurrentRow(row + 1)
- self.window.stackedWidget.setCurrentIndex(row + 1)
- self.drawPreview()
-
- def updateOpenPresetComboBox(self, component):
- self.window.comboBox_openPreset.clear()
- self.window.comboBox_openPreset.addItem("Component Presets")
- destination = os.path.join(self.presetDir,
- str(component).strip(), str(component.version()))
- if not os.path.exists(destination):
- os.makedirs(destination)
- for f in os.listdir(destination):
- self.window.comboBox_openPreset.addItem(f)
-
- def openSavePresetDialog(self):
- if self.window.listWidget_componentList.currentRow() == -1:
- return
- while True:
- newName, OK = QtGui.QInputDialog.getText(QtGui.QWidget(), 'Audio Visualizer', 'New Preset Name:')
- badName = False
- for letter in newName:
- if letter in string.punctuation:
- badName = True
- if badName:
- # some filesystems don't like bizarre characters
- self.showMessage("Preset names must contain only letters, numbers, and spaces.")
- continue
- if OK and newName:
- index = self.window.listWidget_componentList.currentRow()
- if index != -1:
- saveValueStore = self.selectedComponents[index].savePreset()
- componentName = str(self.selectedComponents[index]).strip()
- vers = self.selectedComponents[index].version()
- self.createPresetFile(componentName, vers, saveValueStore, newName)
- break
-
- def createPresetFile(self, componentName, version, saveValueStore, filename):
- dirname = os.path.join(self.presetDir, componentName, str(version))
- if not os.path.exists(dirname):
- os.makedirs(dirname)
- filepath = os.path.join(dirname, filename)
- if os.path.exists(filepath):
- ch = self.showMessage("%s already exists! Overwrite it?" % filename, True, QtGui.QMessageBox.Warning)
- if not ch:
- return
- # remove old copies of the preset
- for i in range(0, self.window.comboBox_openPreset.count()):
- if self.window.comboBox_openPreset.itemText(i) == filename:
- self.window.comboBox_openPreset.removeItem(i)
- with open(filepath, 'w') as f:
- f.write(core.Core.stringOrderedDict(saveValueStore))
- self.window.comboBox_openPreset.addItem(filename)
- self.window.comboBox_openPreset.setCurrentIndex(self.window.comboBox_openPreset.count()-1)
-
- def openPreset(self):
- if self.window.comboBox_openPreset.currentIndex() < 1:
- return
- index = self.window.listWidget_componentList.currentRow()
- if index == -1:
- return
- filename = self.window.comboBox_openPreset.itemText(self.window.comboBox_openPreset.currentIndex())
- componentName = str(self.selectedComponents[index]).strip()
- version = self.selectedComponents[index].version()
- dirname = os.path.join(self.presetDir, componentName, str(version))
- filepath = os.path.join(dirname, filename)
- if not os.path.exists(filepath):
- self.window.comboBox_openPreset.removeItem(self.window.comboBox_openPreset.currentIndex())
- return
- with open(filepath, 'r') as f:
- for line in f:
- saveValueStore = dict(eval(line.strip()))
- break
- self.selectedComponents[index].loadPreset(saveValueStore)
- self.drawPreview()
-
- def saveCurrentProject(self):
- if self.currentProject:
- self.createProjectFile(self.currentProject)
- else:
- self.openSaveProjectDialog()
-
- def openSaveProjectDialog(self):
- filename = QtGui.QFileDialog.getSaveFileName(self.window,
- "Create Project File", self.settings.value("projectDir"),
- "Project Files (*.avp)")
- if not filename:
- return
- self.createProjectFile(filename)
-
- def createProjectFile(self, filepath):
- if not filepath.endswith(".avp"):
- filepath += '.avp'
- with open(filepath, 'w') as f:
- print('creating %s' % filepath)
- f.write('[Components]\n')
- for comp in self.selectedComponents:
- saveValueStore = comp.savePreset()
- f.write('%s\n' % str(comp))
- f.write('%s\n' % str(comp.version()))
- f.write('%s\n' % core.Core.stringOrderedDict(saveValueStore))
- if filepath != self.autosavePath:
- self.settings.setValue("projectDir", os.path.dirname(filepath))
- self.settings.setValue("currentProject", filepath)
- self.currentProject = filepath
-
- def openOpenProjectDialog(self):
- filename = QtGui.QFileDialog.getOpenFileName(self.window,
- "Open Project File", self.settings.value("projectDir"),
- "Project Files (*.avp)")
- self.openProject(filename)
-
- def openProject(self, filepath):
- if not filepath or not os.path.exists(filepath) or not filepath.endswith('.avp'):
- return
- self.clear()
- self.currentProject = filepath
- self.settings.setValue("currentProject", filepath)
- self.settings.setValue("projectDir", os.path.dirname(filepath))
- compNames = [mod.Component.__doc__ for mod in self.modules]
- try:
- with open(filepath, 'r') as f:
- validSections = ('Components')
- section = ''
- def parseLine(line):
- line = line.strip()
- newSection = ''
- if line.startswith('[') and line.endswith(']') and line[1:-1] in validSections:
- newSection = line[1:-1]
- return line, newSection
-
- i = 0
- for line in f:
- line, newSection = parseLine(line)
- if newSection:
- section = str(newSection)
- continue
- if line and section == 'Components':
- if i == 0:
- compIndex = compNames.index(line)
- self.addComponent(compIndex)
- i += 1
- elif i == 1:
- # version, not used yet
- i += 1
- elif i == 2:
- saveValueStore = dict(eval(line))
- self.selectedComponents[-1].loadPreset(saveValueStore)
- i = 0
- except (IndexError, ValueError, KeyError, NameError, SyntaxError, AttributeError, TypeError) as e:
- self.clear()
- typ, value, _ = sys.exc_info()
- msg = '%s: %s' % (typ.__name__, value)
- self.showMessage("Project file '%s' is corrupted." % filepath, False,
- QtGui.QMessageBox.Warning, msg)
-
- def showMessage(self, string, showCancel=False, icon=QtGui.QMessageBox.Information, detail=None):
- msg = QtGui.QMessageBox()
- msg.setIcon(icon)
- msg.setText(string)
- msg.setDetailedText(detail)
- if showCancel:
- msg.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
- else:
- msg.setStandardButtons(QtGui.QMessageBox.Ok)
- ch = msg.exec_()
- if ch == 1024:
- return True
- return False
-
- def clear(self):
- ''' empty out all components and fields, get a blank slate '''
- self.selectedComponents = []
- self.window.listWidget_componentList.clear()
- for widget in self.pages:
- self.window.stackedWidget.removeWidget(widget)
- self.pages = []
def LoadDefaultSettings(self):
- self.resolutions = [
- '1920x1080',
- '1280x720',
- '854x480'
+ self.resolutions = [
+ '1920x1080',
+ '1280x720',
+ '854x480'
]
- default = {
- "outputWidth": 1280,
- "outputHeight": 720,
- "outputFrameRate": 30,
- "outputAudioCodec": "aac",
- "outputAudioBitrate": "192k",
- "outputVideoCodec": "libx264",
- "outputVideoFormat": "yuv420p",
- "outputPreset": "medium",
- "outputFormat": "mp4",
- "projectDir" : os.path.join(self.dataDir, 'projects'),
- }
-
- for parm, value in default.items():
- if self.settings.value(parm) == None:
- self.settings.setValue(parm,value)
-
+ default = {
+ "outputWidth": 1280,
+ "outputHeight": 720,
+ "outputFrameRate": 30,
+ "outputAudioCodec": "aac",
+ "outputAudioBitrate": "192k",
+ "outputVideoCodec": "libx264",
+ "outputVideoFormat": "yuv420p",
+ "outputPreset": "medium",
+ "outputFormat": "mp4",
+ "projectDir": os.path.join(self.dataDir, 'projects'),
+ }
+
+ for parm, value in default.items():
+ if self.settings.value(parm) is None:
+ self.settings.setValue(parm, value)
-''' ####### commandline functionality broken until we decide how to implement it
-if len(sys.argv) > 1:
- # command line mode
- app = QtGui.QApplication(sys.argv, False)
- command = Command()
- signal.signal(signal.SIGINT, command.cleanUp)
- sys.exit(app.exec_())
-else:
-'''
-# gui mode
if __name__ == "__main__":
+ ''' FIXME commandline functionality broken until we decide how to implement
+ if len(sys.argv) > 1:
+ # command line mode
+ app = QtGui.QApplication(sys.argv, False)
+ command = Command()
+ signal.signal(signal.SIGINT, command.cleanUp)
+ sys.exit(app.exec_())
+ else:
+ '''
app = QtGui.QApplication(sys.argv)
app.setApplicationName("audio-visualizer")
app.setOrganizationName("audio-visualizer")
- window = uic.loadUi(os.path.join(os.path.dirname(os.path.realpath(__file__)), "mainwindow.ui"))
+ window = uic.loadUi(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "mainwindow.ui"))
# window.adjustSize()
desc = QtGui.QDesktopWidget()
dpi = desc.physicalDpiX()
-
+
topMargin = 0 if (dpi == 96) else int(10 * (dpi / 96))
window.resize(window.width() * (dpi / 96), window.height() * (dpi / 96))
- #window.verticalLayout_2.setContentsMargins(0, topMargin, 0, 0)
-
- main = Main(window)
+ # window.verticalLayout_2.setContentsMargins(0, topMargin, 0, 0)
+
+ main = MainWindow(window)
signal.signal(signal.SIGINT, main.cleanUp)
atexit.register(main.cleanUp)
diff --git a/mainwindow.py b/mainwindow.py
new file mode 100644
index 0000000..b779298
--- /dev/null
+++ b/mainwindow.py
@@ -0,0 +1,586 @@
+from os.path import expanduser
+from queue import Queue
+from importlib import import_module
+from collections import OrderedDict
+from PyQt4 import QtCore, QtGui
+from PyQt4.QtCore import QSettings, Qt
+from PyQt4.QtGui import QDesktopServices, QMenu
+import sys
+import io
+import os
+import string
+import signal
+import filecmp
+import time
+
+import core
+import preview_thread
+import video_thread
+from main import LoadDefaultSettings
+
+
+class PreviewWindow(QtGui.QLabel):
+ def __init__(self, parent, img):
+ super(PreviewWindow, self).__init__()
+ self.parent = parent
+ self.setFrameStyle(QtGui.QFrame.StyledPanel)
+ self.pixmap = QtGui.QPixmap(img)
+
+ def paintEvent(self, event):
+ size = self.size()
+ painter = QtGui.QPainter(self)
+ point = QtCore.QPoint(0, 0)
+ scaledPix = self.pixmap.scaled(
+ size, Qt.KeepAspectRatio, transformMode=Qt.SmoothTransformation)
+
+ # start painting the label from left upper corner
+ point.setX((size.width() - scaledPix.width())/2)
+ point.setY((size.height() - scaledPix.height())/2)
+ painter.drawPixmap(point, scaledPix)
+
+ def changePixmap(self, img):
+ self.pixmap = QtGui.QPixmap(img)
+ self.repaint()
+
+
+class MainWindow(QtCore.QObject):
+
+ newTask = QtCore.pyqtSignal(list)
+ processTask = QtCore.pyqtSignal()
+ videoTask = QtCore.pyqtSignal(str, str, list)
+
+ def __init__(self, window):
+ QtCore.QObject.__init__(self)
+
+ # print('main thread id: {}'.format(QtCore.QThread.currentThreadId()))
+ self.window = window
+ self.core = core.Core()
+ self.pages = []
+ self.selectedComponents = []
+ self.lastAutosave = time.time()
+
+ # create data directory, load/create settings
+ self.dataDir = QDesktopServices.storageLocation(
+ QDesktopServices.DataLocation)
+ self.autosavePath = os.path.join(self.dataDir, 'autosave.avp')
+ self.presetDir = os.path.join(self.dataDir, 'presets')
+ self.settings = QSettings(
+ os.path.join(self.dataDir, 'settings.ini'), QSettings.IniFormat)
+ LoadDefaultSettings(self)
+ if not os.path.exists(self.dataDir):
+ os.makedirs(self.dataDir)
+ for neededDirectory in (
+ self.presetDir, self.settings.value("projectDir")):
+ if not os.path.exists(neededDirectory):
+ os.mkdir(neededDirectory)
+
+ #
+ self.previewQueue = Queue()
+ self.previewThread = QtCore.QThread(self)
+ self.previewWorker = preview_thread.Worker(self, self.previewQueue)
+ self.previewWorker.moveToThread(self.previewThread)
+ self.previewWorker.imageCreated.connect(self.showPreviewImage)
+ self.previewThread.start()
+
+ self.timer = QtCore.QTimer(self)
+ self.timer.timeout.connect(self.processTask.emit)
+ self.timer.start(500)
+
+ # begin decorating the window and connecting events
+ window.toolButton_selectAudioFile.clicked.connect(
+ self.openInputFileDialog)
+
+ window.toolButton_selectOutputFile.clicked.connect(
+ self.openOutputFileDialog)
+
+ window.progressBar_createVideo.setValue(0)
+
+ window.pushButton_createVideo.clicked.connect(
+ self.createAudioVisualisation)
+
+ window.pushButton_Cancel.clicked.connect(self.stopVideo)
+ window.setWindowTitle("Audio Visualizer")
+
+ self.previewWindow = PreviewWindow(self, os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "background.png"))
+ window.verticalLayout_previewWrapper.addWidget(self.previewWindow)
+
+ self.modules = self.findComponents()
+ self.compMenu = QMenu()
+ for i, comp in enumerate(self.modules):
+ action = self.compMenu.addAction(comp.Component.__doc__)
+ action.triggered[()].connect(
+ lambda item=i: self.insertComponent(item))
+
+ self.window.pushButton_addComponent.setMenu(self.compMenu)
+ window.listWidget_componentList.clicked.connect(
+ lambda _: self.changeComponentWidget())
+
+ self.window.pushButton_removeComponent.clicked.connect(
+ lambda _: self.removeComponent())
+
+ currentRes = str(self.settings.value('outputWidth'))+'x' + \
+ str(self.settings.value('outputHeight'))
+ for i, res in enumerate(self.resolutions):
+ window.comboBox_resolution.addItem(res)
+ if res == currentRes:
+ currentRes = i
+ window.comboBox_resolution.setCurrentIndex(currentRes)
+ window.comboBox_resolution.currentIndexChanged.connect(
+ self.updateResolution)
+
+ self.window.pushButton_listMoveUp.clicked.connect(
+ self.moveComponentUp)
+ self.window.pushButton_listMoveDown.clicked.connect(
+ self.moveComponentDown)
+ self.window.pushButton_savePreset.clicked.connect(
+ self.openSavePresetDialog)
+ self.window.comboBox_openPreset.currentIndexChanged.connect(
+ self.openPreset)
+ self.window.pushButton_saveAs.clicked.connect(
+ self.openSaveProjectDialog)
+ self.window.pushButton_saveProject.clicked.connect(
+ self.saveCurrentProject)
+ self.window.pushButton_openProject.clicked.connect(
+ self.openOpenProjectDialog)
+
+ # show the window and load current project
+ window.show()
+ self.currentProject = self.settings.value("currentProject")
+ if self.currentProject and os.path.exists(self.autosavePath) \
+ and filecmp.cmp(self.autosavePath, self.currentProject):
+ # delete autosave if it's identical to the project
+ os.remove(self.autosavePath)
+
+ if self.currentProject and os.path.exists(self.autosavePath):
+ ch = self.showMessage(
+ "Restore unsaved changes in project '%s'?"
+ % os.path.basename(self.currentProject)[:-4], True)
+ if ch:
+ os.remove(self.currentProject)
+ os.rename(self.autosavePath, self.currentProject)
+ else:
+ os.remove(self.autosavePath)
+
+ self.openProject(self.currentProject)
+ self.drawPreview()
+
+ def cleanUp(self):
+ self.timer.stop()
+ self.previewThread.quit()
+ self.previewThread.wait()
+ self.autosave()
+
+ def autosave(self):
+ if time.time() - self.lastAutosave >= 1.0:
+ if os.path.exists(self.autosavePath):
+ os.remove(self.autosavePath)
+ self.createProjectFile(self.autosavePath)
+ self.lastAutosave = time.time()
+
+ def openInputFileDialog(self):
+ inputDir = self.settings.value("inputDir", expanduser("~"))
+
+ fileName = QtGui.QFileDialog.getOpenFileName(
+ self.window, "Open Music File",
+ inputDir, "Music Files (*.mp3 *.wav *.ogg *.fla *.aac)")
+
+ if not fileName == "":
+ self.settings.setValue("inputDir", os.path.dirname(fileName))
+ self.window.lineEdit_audioFile.setText(fileName)
+
+ def openOutputFileDialog(self):
+ outputDir = self.settings.value("outputDir", expanduser("~"))
+
+ fileName = QtGui.QFileDialog.getSaveFileName(
+ self.window, "Set Output Video File",
+ outputDir, "Video Files (*.mp4 *.mov *.mkv *.avi *.webm *.flv)")
+
+ if not fileName == "":
+ self.settings.setValue("outputDir", os.path.dirname(fileName))
+ self.window.lineEdit_outputFile.setText(fileName)
+
+ def stopVideo(self):
+ print('stop')
+ self.videoWorker.cancel()
+ self.canceled = True
+
+ def createAudioVisualisation(self):
+ # create output video if mandatory settings are filled in
+ if self.window.lineEdit_audioFile.text() and \
+ self.window.lineEdit_outputFile.text():
+ self.canceled = False
+ self.progressBarUpdated(-1)
+ ffmpeg_cmd = self.settings.value("ffmpeg_cmd", expanduser("~"))
+ self.videoThread = QtCore.QThread(self)
+ self.videoWorker = video_thread.Worker(self)
+ self.videoWorker.moveToThread(self.videoThread)
+ self.videoWorker.videoCreated.connect(self.videoCreated)
+ self.videoWorker.progressBarUpdate.connect(self.progressBarUpdated)
+ self.videoWorker.progressBarSetText.connect(
+ self.progressBarSetText)
+ self.videoWorker.imageCreated.connect(self.showPreviewImage)
+ self.videoWorker.encoding.connect(self.changeEncodingStatus)
+ self.videoThread.start()
+ self.videoTask.emit(
+ self.window.lineEdit_audioFile.text(),
+ self.window.lineEdit_outputFile.text(),
+ self.selectedComponents)
+ else:
+ self.showMessage(
+ "You must select an audio file and output filename.")
+
+ def progressBarUpdated(self, value):
+ self.window.progressBar_createVideo.setValue(value)
+
+ def changeEncodingStatus(self, status):
+ if status:
+ self.window.pushButton_createVideo.setEnabled(False)
+ self.window.pushButton_Cancel.setEnabled(True)
+ self.window.comboBox_resolution.setEnabled(False)
+ self.window.stackedWidget.setEnabled(False)
+ self.window.tab_encoderSettings.setEnabled(False)
+ self.window.label_audioFile.setEnabled(False)
+ self.window.toolButton_selectAudioFile.setEnabled(False)
+ self.window.label_outputFile.setEnabled(False)
+ self.window.toolButton_selectOutputFile.setEnabled(False)
+ self.window.lineEdit_audioFile.setEnabled(False)
+ self.window.lineEdit_outputFile.setEnabled(False)
+ self.window.pushButton_addComponent.setEnabled(False)
+ self.window.pushButton_removeComponent.setEnabled(False)
+ self.window.pushButton_listMoveDown.setEnabled(False)
+ self.window.pushButton_listMoveUp.setEnabled(False)
+ self.window.comboBox_openPreset.setEnabled(False)
+ self.window.pushButton_removePreset.setEnabled(False)
+ self.window.pushButton_savePreset.setEnabled(False)
+ self.window.pushButton_openProject.setEnabled(False)
+ self.window.listWidget_componentList.setEnabled(False)
+ else:
+ self.window.pushButton_createVideo.setEnabled(True)
+ self.window.pushButton_Cancel.setEnabled(False)
+ self.window.comboBox_resolution.setEnabled(True)
+ self.window.stackedWidget.setEnabled(True)
+ self.window.tab_encoderSettings.setEnabled(True)
+ self.window.label_audioFile.setEnabled(True)
+ self.window.toolButton_selectAudioFile.setEnabled(True)
+ self.window.lineEdit_audioFile.setEnabled(True)
+ self.window.label_outputFile.setEnabled(True)
+ self.window.toolButton_selectOutputFile.setEnabled(True)
+ self.window.lineEdit_outputFile.setEnabled(True)
+ self.window.pushButton_addComponent.setEnabled(True)
+ self.window.pushButton_removeComponent.setEnabled(True)
+ self.window.pushButton_listMoveDown.setEnabled(True)
+ self.window.pushButton_listMoveUp.setEnabled(True)
+ self.window.comboBox_openPreset.setEnabled(True)
+ self.window.pushButton_removePreset.setEnabled(True)
+ self.window.pushButton_savePreset.setEnabled(True)
+ self.window.pushButton_openProject.setEnabled(True)
+ self.window.listWidget_componentList.setEnabled(True)
+
+ def progressBarSetText(self, value):
+ self.window.progressBar_createVideo.setFormat(value)
+
+ def videoCreated(self):
+ self.videoThread.quit()
+ self.videoThread.wait()
+
+ def updateResolution(self):
+ resIndex = int(window.comboBox_resolution.currentIndex())
+ res = self.resolutions[resIndex].split('x')
+ self.settings.setValue('outputWidth', res[0])
+ self.settings.setValue('outputHeight', res[1])
+ self.drawPreview()
+
+ def drawPreview(self):
+ self.newTask.emit(self.selectedComponents)
+ # self.processTask.emit()
+ self.autosave()
+
+ def showPreviewImage(self, image):
+ self.previewWindow.changePixmap(image)
+
+ def findComponents(self):
+ def findComponents():
+ srcPath = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), 'components')
+ if os.path.exists(srcPath):
+ for f in sorted(os.listdir(srcPath)):
+ name, ext = os.path.splitext(f)
+ if name.startswith("__"):
+ continue
+ elif ext == '.py':
+ yield name
+ return [
+ import_module('components.%s' % name)
+ for name in findComponents()]
+
+ def addComponent(self, moduleIndex):
+ index = len(self.pages)
+ self.selectedComponents.append(self.modules[moduleIndex].Component())
+ self.window.listWidget_componentList.addItem(
+ self.selectedComponents[-1].__doc__)
+ self.pages.append(self.selectedComponents[-1].widget(self))
+ self.window.listWidget_componentList.setCurrentRow(index)
+ self.window.stackedWidget.addWidget(self.pages[-1])
+ self.window.stackedWidget.setCurrentIndex(index)
+ self.selectedComponents[-1].update()
+ self.updateOpenPresetComboBox(self.selectedComponents[-1])
+
+ def insertComponent(self, moduleIndex):
+ self.selectedComponents.insert(
+ 0, self.modules[moduleIndex].Component())
+ self.window.listWidget_componentList.insertItem(
+ 0, self.selectedComponents[0].__doc__)
+ self.pages.insert(0, self.selectedComponents[0].widget(self))
+ self.window.listWidget_componentList.setCurrentRow(0)
+ self.window.stackedWidget.insertWidget(0, self.pages[0])
+ self.window.stackedWidget.setCurrentIndex(0)
+ self.selectedComponents[0].update()
+ self.updateOpenPresetComboBox(self.selectedComponents[0])
+
+ def removeComponent(self):
+ for selected in self.window.listWidget_componentList.selectedItems():
+ index = self.window.listWidget_componentList.row(selected)
+ self.window.stackedWidget.removeWidget(self.pages[index])
+ self.window.listWidget_componentList.takeItem(index)
+ self.selectedComponents.pop(index)
+ self.pages.pop(index)
+ self.changeComponentWidget()
+ self.drawPreview()
+
+ def changeComponentWidget(self):
+ selected = self.window.listWidget_componentList.selectedItems()
+ if selected:
+ index = self.window.listWidget_componentList.row(selected[0])
+ self.window.stackedWidget.setCurrentIndex(index)
+ self.updateOpenPresetComboBox(self.selectedComponents[index])
+
+ def moveComponentUp(self):
+ row = self.window.listWidget_componentList.currentRow()
+ if row > 0:
+ module = self.selectedComponents[row]
+ self.selectedComponents.pop(row)
+ self.selectedComponents.insert(row - 1, module)
+ page = self.pages[row]
+ self.pages.pop(row)
+ self.pages.insert(row - 1, page)
+ item = self.window.listWidget_componentList.takeItem(row)
+ self.window.listWidget_componentList.insertItem(row - 1, item)
+ widget = self.window.stackedWidget.removeWidget(page)
+ self.window.stackedWidget.insertWidget(row - 1, page)
+ self.window.listWidget_componentList.setCurrentRow(row - 1)
+ self.window.stackedWidget.setCurrentIndex(row - 1)
+ self.drawPreview()
+
+ def moveComponentDown(self):
+ row = self.window.listWidget_componentList.currentRow()
+ if row != -1 and row < len(self.pages)+1:
+ module = self.selectedComponents[row]
+ self.selectedComponents.pop(row)
+ self.selectedComponents.insert(row + 1, module)
+ page = self.pages[row]
+ self.pages.pop(row)
+ self.pages.insert(row + 1, page)
+ item = self.window.listWidget_componentList.takeItem(row)
+ self.window.listWidget_componentList.insertItem(row + 1, item)
+ widget = self.window.stackedWidget.removeWidget(page)
+ self.window.stackedWidget.insertWidget(row + 1, page)
+ self.window.listWidget_componentList.setCurrentRow(row + 1)
+ self.window.stackedWidget.setCurrentIndex(row + 1)
+ self.drawPreview()
+
+ def updateOpenPresetComboBox(self, component):
+ self.window.comboBox_openPreset.clear()
+ self.window.comboBox_openPreset.addItem("Component Presets")
+ destination = os.path.join(
+ self.presetDir, str(component).strip(), str(component.version()))
+ if not os.path.exists(destination):
+ os.makedirs(destination)
+ for f in os.listdir(destination):
+ self.window.comboBox_openPreset.addItem(f)
+
+ def openSavePresetDialog(self):
+ if self.window.listWidget_componentList.currentRow() == -1:
+ return
+ while True:
+ newName, OK = QtGui.QInputDialog.getText(
+ QtGui.QWidget(), 'Audio Visualizer', 'New Preset Name:')
+ badName = False
+ for letter in newName:
+ if letter in string.punctuation:
+ badName = True
+ if badName:
+ # some filesystems don't like bizarre characters
+ self.showMessage("Preset names must contain only letters, \
+ numbers, and spaces.")
+ continue
+ if OK and newName:
+ index = self.window.listWidget_componentList.currentRow()
+ if index != -1:
+ saveValueStore = \
+ self.selectedComponents[index].savePreset()
+ componentName = str(self.selectedComponents[index]).strip()
+ vers = self.selectedComponents[index].version()
+ self.createPresetFile(
+ componentName, vers, saveValueStore, newName)
+ break
+
+ def createPresetFile(
+ self, componentName, version, saveValueStore, filename):
+ dirname = os.path.join(self.presetDir, componentName, str(version))
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+ filepath = os.path.join(dirname, filename)
+ if os.path.exists(filepath):
+ ch = self.showMessage(
+ "%s already exists! Overwrite it?" % filename,
+ True, QtGui.QMessageBox.Warning)
+ if not ch:
+ return
+ # remove old copies of the preset
+ for i in range(0, self.window.comboBox_openPreset.count()):
+ if self.window.comboBox_openPreset.itemText(i) == filename:
+ self.window.comboBox_openPreset.removeItem(i)
+ with open(filepath, 'w') as f:
+ f.write(core.Core.stringOrderedDict(saveValueStore))
+ self.window.comboBox_openPreset.addItem(filename)
+ self.window.comboBox_openPreset.setCurrentIndex(
+ self.window.comboBox_openPreset.count()-1)
+
+ def openPreset(self):
+ if self.window.comboBox_openPreset.currentIndex() < 1:
+ return
+ index = self.window.listWidget_componentList.currentRow()
+ if index == -1:
+ return
+ filename = self.window.comboBox_openPreset.itemText(
+ self.window.comboBox_openPreset.currentIndex())
+ componentName = str(self.selectedComponents[index]).strip()
+ version = self.selectedComponents[index].version()
+ dirname = os.path.join(self.presetDir, componentName, str(version))
+ filepath = os.path.join(dirname, filename)
+ if not os.path.exists(filepath):
+ self.window.comboBox_openPreset.removeItem(
+ self.window.comboBox_openPreset.currentIndex())
+ return
+ with open(filepath, 'r') as f:
+ for line in f:
+ saveValueStore = dict(eval(line.strip()))
+ break
+ self.selectedComponents[index].loadPreset(saveValueStore)
+ self.drawPreview()
+
+ def saveCurrentProject(self):
+ if self.currentProject:
+ self.createProjectFile(self.currentProject)
+ else:
+ self.openSaveProjectDialog()
+
+ def openSaveProjectDialog(self):
+ filename = QtGui.QFileDialog.getSaveFileName(
+ self.window, "Create Project File",
+ self.settings.value("projectDir"),
+ "Project Files (*.avp)")
+ if not filename:
+ return
+ self.createProjectFile(filename)
+
+ def createProjectFile(self, filepath):
+ if not filepath.endswith(".avp"):
+ filepath += '.avp'
+ with open(filepath, 'w') as f:
+ print('creating %s' % filepath)
+ f.write('[Components]\n')
+ for comp in self.selectedComponents:
+ saveValueStore = comp.savePreset()
+ f.write('%s\n' % str(comp))
+ f.write('%s\n' % str(comp.version()))
+ f.write('%s\n' % core.Core.stringOrderedDict(saveValueStore))
+ if filepath != self.autosavePath:
+ self.settings.setValue("projectDir", os.path.dirname(filepath))
+ self.settings.setValue("currentProject", filepath)
+ self.currentProject = filepath
+
+ def openOpenProjectDialog(self):
+ filename = QtGui.QFileDialog.getOpenFileName(
+ self.window, "Open Project File",
+ self.settings.value("projectDir"),
+ "Project Files (*.avp)")
+ self.openProject(filename)
+
+ def openProject(self, filepath):
+ if not filepath or not os.path.exists(filepath) \
+ or not filepath.endswith('.avp'):
+ return
+ self.clear()
+ self.currentProject = filepath
+ self.settings.setValue("currentProject", filepath)
+ self.settings.setValue("projectDir", os.path.dirname(filepath))
+ compNames = [mod.Component.__doc__ for mod in self.modules]
+ try:
+ with open(filepath, 'r') as f:
+ validSections = ('Components')
+ section = ''
+
+ def parseLine(line):
+ line = line.strip()
+ newSection = ''
+
+ if line.startswith('[') and line.endswith(']') \
+ and line[1:-1] in validSections:
+ newSection = line[1:-1]
+
+ return line, newSection
+
+ i = 0
+ for line in f:
+ line, newSection = parseLine(line)
+ if newSection:
+ section = str(newSection)
+ continue
+ if line and section == 'Components':
+ if i == 0:
+ compIndex = compNames.index(line)
+ self.addComponent(compIndex)
+ i += 1
+ elif i == 1:
+ # version, not used yet
+ i += 1
+ elif i == 2:
+ saveValueStore = dict(eval(line))
+ self.selectedComponents[-1].loadPreset(
+ saveValueStore)
+ i = 0
+ except (IndexError, ValueError, KeyError, NameError,
+ SyntaxError, AttributeError, TypeError) as e:
+ self.clear()
+ typ, value, _ = sys.exc_info()
+ msg = '%s: %s' % (typ.__name__, value)
+ self.showMessage(
+ "Project file '%s' is corrupted." % filepath, False,
+ QtGui.QMessageBox.Warning, msg)
+
+ def showMessage(
+ self, string, showCancel=False,
+ icon=QtGui.QMessageBox.Information, detail=None):
+ msg = QtGui.QMessageBox()
+ msg.setIcon(icon)
+ msg.setText(string)
+ msg.setDetailedText(detail)
+ if showCancel:
+ msg.setStandardButtons(
+ QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
+ else:
+ msg.setStandardButtons(QtGui.QMessageBox.Ok)
+ ch = msg.exec_()
+ if ch == 1024:
+ return True
+ return False
+
+ def clear(self):
+ ''' empty out all components and fields, get a blank slate '''
+ self.selectedComponents = []
+ self.window.listWidget_componentList.clear()
+ for widget in self.pages:
+ self.window.stackedWidget.removeWidget(widget)
+ self.pages = []
diff --git a/preview_thread.py b/preview_thread.py
index 04683ae..d54dba5 100644
--- a/preview_thread.py
+++ b/preview_thread.py
@@ -9,53 +9,52 @@ import numpy
import os
from copy import copy
+
class Worker(QtCore.QObject):
- imageCreated = pyqtSignal(['QImage'])
-
- def __init__(self, parent=None, queue=None):
- QtCore.QObject.__init__(self)
- parent.newTask.connect(self.createPreviewImage)
- parent.processTask.connect(self.process)
- self.core = core.Core()
- self.queue = queue
- self.core.settings = parent.settings
- self.stackedWidget = parent.window.stackedWidget
- self.background = Image.new("RGBA", (1920, 1080),(0,0,0,0))
- self.background.paste(Image.open(os.path.join(os.path.dirname(os.path.realpath(__file__)),"background.png")))
-
-
-
- @pyqtSlot(str, list)
- def createPreviewImage(self, components):
- # print('worker thread id: {}'.format(QtCore.QThread.currentThreadId()))
- dic = {
- "components": components,
- }
- self.queue.put(dic)
-
- @pyqtSlot()
- def process(self):
- try:
- nextPreviewInformation = self.queue.get(block=False)
- while self.queue.qsize() >= 2:
+ imageCreated = pyqtSignal(['QImage'])
+
+ def __init__(self, parent=None, queue=None):
+ QtCore.QObject.__init__(self)
+ parent.newTask.connect(self.createPreviewImage)
+ parent.processTask.connect(self.process)
+ self.core = core.Core()
+ self.queue = queue
+ self.core.settings = parent.settings
+ self.stackedWidget = parent.window.stackedWidget
+ self.background = Image.new("RGBA", (1920, 1080), (0, 0, 0, 0))
+ self.background.paste(Image.open(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "background.png")))
+
+ @pyqtSlot(str, list)
+ def createPreviewImage(self, components):
+ dic = {
+ "components": components,
+ }
+ self.queue.put(dic)
+
+ @pyqtSlot()
+ def process(self):
try:
- self.queue.get(block=False)
+ nextPreviewInformation = self.queue.get(block=False)
+ while self.queue.qsize() >= 2:
+ try:
+ self.queue.get(block=False)
+ except Empty:
+ continue
+
+ width = int(self.core.settings.value('outputWidth'))
+ height = int(self.core.settings.value('outputHeight'))
+ frame = copy(self.background)
+ frame = frame.resize((width, height))
+
+ components = nextPreviewInformation["components"]
+ for component in reversed(components):
+ frame = Image.alpha_composite(
+ frame, component.previewRender(self))
+
+ self._image = ImageQt(frame)
+ self.imageCreated.emit(QtGui.QImage(self._image))
+
except Empty:
- continue
-
- width = int(self.core.settings.value('outputWidth'))
- height = int(self.core.settings.value('outputHeight'))
- frame = copy(self.background)
- frame = frame.resize((width,height))
-
- components = nextPreviewInformation["components"]
- for component in reversed(components):
- #newFrame = Image.alpha_composite(frame,)
- frame = Image.alpha_composite(frame,component.previewRender(self))
-
- self._image = ImageQt(frame)
- self.imageCreated.emit(QtGui.QImage(self._image))
-
- except Empty:
- True
+ True
diff --git a/video_thread.py b/video_thread.py
index e880263..5897ff0 100644
--- a/video_thread.py
+++ b/video_thread.py
@@ -13,6 +13,7 @@ import time
from copy import copy
import signal
+
class Worker(QtCore.QObject):
imageCreated = pyqtSignal(['QImage'])
@@ -40,16 +41,19 @@ class Worker(QtCore.QObject):
frame = None
for compNo, comp in reversed(list(enumerate(self.components))):
- if compNo in self.staticComponents and self.staticComponents[compNo] != None:
+ if compNo in self.staticComponents and \
+ self.staticComponents[compNo] is not None:
if frame is None:
frame = self.staticComponents[compNo]
else:
- frame = Image.alpha_composite(frame, self.staticComponents[compNo])
+ frame = Image.alpha_composite(
+ frame, self.staticComponents[compNo])
else:
if frame is None:
frame = comp.frameRender(compNo, i[0], i[1])
else:
- frame = Image.alpha_composite(frame, comp.frameRender(compNo, i[0], i[1]))
+ frame = Image.alpha_composite(
+ frame, comp.frameRender(compNo, i[0], i[1]))
self.renderQueue.put([i[0], frame])
self.compositeQueue.task_done()
@@ -63,8 +67,9 @@ class Worker(QtCore.QObject):
self.bgI += 1
def previewDispatch(self):
- background = Image.new("RGBA", (1920, 1080),(0,0,0,0))
- background.paste(Image.open(os.path.join(os.path.dirname(os.path.realpath(__file__)), "background.png")))
+ background = Image.new("RGBA", (1920, 1080), (0, 0, 0, 0))
+ background.paste(Image.open(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "background.png")))
background = background.resize((self.width, self.height))
while not self.stopped:
@@ -83,11 +88,10 @@ class Worker(QtCore.QObject):
self.encoding.emit(True)
self.components = components
self.outputFile = outputFile
- self.bgI = 0 # tracked video frame
+ self.bgI = 0 # tracked video frame
self.reset()
self.width = int(self.core.settings.value('outputWidth'))
self.height = int(self.core.settings.value('outputHeight'))
- # print('worker thread id: {}'.format(QtCore.QThread.currentThreadId()))
progressBarValue = 0
self.progressBarUpdate.emit(progressBarValue)
@@ -95,21 +99,24 @@ class Worker(QtCore.QObject):
self.completeAudioArray = self.core.readAudioFile(inputFile, self)
# test if user has libfdk_aac
- encoders = sp.check_output(self.core.FFMPEG_BIN + " -encoders -hide_banner", shell=True)
+ encoders = sp.check_output(
+ self.core.FFMPEG_BIN + " -encoders -hide_banner", shell=True)
acodec = self.core.settings.value('outputAudioCodec')
-
+
if b'libfdk_aac' in encoders and acodec == 'aac':
acodec = 'libfdk_aac'
ffmpegCommand = [
self.core.FFMPEG_BIN,
'-thread_queue_size', '512',
- '-y', # (optional) means overwrite the output file if it already exists.
+ '-y', # overwrite the output file if it already exists.
'-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'), # frames per second
+
+ # frames per second
+ '-r', self.core.settings.value('outputFrameRate'),
'-i', '-', # The input comes from a pipe
'-an',
'-i', inputFile,
@@ -126,14 +133,16 @@ class Worker(QtCore.QObject):
ffmpegCommand.append('-2')
ffmpegCommand.append(outputFile)
- self.out_pipe = sp.Popen(ffmpegCommand, stdin=sp.PIPE,stdout=sys.stdout, stderr=sys.stdout)
+ self.out_pipe = sp.Popen(
+ ffmpegCommand, stdin=sp.PIPE, stdout=sys.stdout, stderr=sys.stdout)
# create video for output
numpy.seterr(divide='ignore')
# initialize components
print('loaded components:',
- ["%s%s" % (num, str(component)) for num, component in enumerate(self.components)])
+ ["%s%s" % (num, str(component)) for num,
+ component in enumerate(self.components)])
self.staticComponents = {}
numComps = len(self.components)
for compNo, comp in enumerate(self.components):
@@ -149,7 +158,8 @@ class Worker(QtCore.QObject):
)
if properties and 'static' in properties:
- self.staticComponents[compNo] = copy(comp.frameRender(compNo, 0, 0))
+ self.staticComponents[compNo] = copy(
+ comp.frameRender(compNo, 0, 0))
self.progressBarUpdate.emit(100)
self.compositeQueue = Queue()
@@ -159,17 +169,20 @@ class Worker(QtCore.QObject):
self.previewQueue = PriorityQueue()
self.renderThreads = []
- # create threads to render frames and send them back here for piping out
+ # Threads to render frames and send them back here for piping out
for i in range(3):
- self.renderThreads.append(Thread(target=self.renderNode, name="Render Thread"))
+ self.renderThreads.append(
+ Thread(target=self.renderNode, name="Render Thread"))
self.renderThreads[i].daemon = True
self.renderThreads[i].start()
- self.dispatchThread = Thread(target=self.renderDispatch, name="Render Dispatch Thread")
+ self.dispatchThread = Thread(
+ target=self.renderDispatch, name="Render Dispatch Thread")
self.dispatchThread.daemon = True
self.dispatchThread.start()
- self.previewDispatch = Thread(target=self.previewDispatch, name="Render Dispatch Thread")
+ self.previewDispatch = Thread(
+ target=self.previewDispatch, name="Render Dispatch Thread")
self.previewDispatch.daemon = True
self.previewDispatch.start()
@@ -197,10 +210,13 @@ class Worker(QtCore.QObject):
break
# increase progress bar value
- if progressBarValue + 1 <= (i / len(self.completeAudioArray)) * 100:
- progressBarValue = numpy.floor((i / len(self.completeAudioArray)) * 100)
+ if progressBarValue + 1 <= (i / len(self.completeAudioArray)) \
+ * 100:
+ progressBarValue = numpy.floor(
+ (i / len(self.completeAudioArray)) * 100)
self.progressBarUpdate.emit(progressBarValue)
- pStr = "Exporting video: " + str(int(progressBarValue)) + "%"
+ pStr = "Exporting video: " + str(int(progressBarValue)) \
+ + "%"
self.progressBarSetText.emit(pStr)
numpy.seterr(all='print')
@@ -220,7 +236,7 @@ class Worker(QtCore.QObject):
pass
self.progressBarUpdate.emit(0)
self.progressBarSetText.emit('Export Canceled')
-
+
else:
if self.error:
print("Export Failed")
@@ -230,14 +246,14 @@ class Worker(QtCore.QObject):
print("Export Complete")
self.progressBarUpdate.emit(100)
self.progressBarSetText.emit('Export Complete')
-
+
self.error = False
self.canceled = False
self.parent.drawPreview()
self.stopped = True
self.encoding.emit(False)
self.videoCreated.emit()
-
+
def updateProgress(self, pStr, pVal):
self.progressBarValue.emit(pVal)
self.progressBarSetText.emit(pStr)
@@ -245,10 +261,10 @@ class Worker(QtCore.QObject):
def cancel(self):
self.canceled = True
self.core.cancel()
-
+
for comp in self.components:
comp.cancel()
-
+
try:
self.out_pipe.send_signal(signal.SIGINT)
except: