Merge pull request #32 from djfun/newgui-commandline

making commandline features from master work with the new component system
This commit is contained in:
Brianna 2017-06-23 07:18:46 -04:00 committed by GitHub
commit 5607bff61f
11 changed files with 394 additions and 226 deletions

View File

@ -1,122 +1,126 @@
# FIXME: commandline functionality broken until we decide how to implement it
'''
from PyQt4 import QtCore
from PyQt4.QtCore import QSettings
import argparse
import os
import sys
import core
import video_thread
from main import LoadDefaultSettings
class Command(QtCore.QObject):
videoTask = QtCore.pyqtSignal(str, str, str, list)
videoTask = QtCore.pyqtSignal(str, str, list)
def __init__(self):
QtCore.QObject.__init__(self)
self.modules = []
self.selectedComponents = []
def __init__(self):
QtCore.QObject.__init__(self)
self.core = core.Core()
self.dataDir = self.core.dataDir
self.canceled = False
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.parser = argparse.ArgumentParser(
description='Create a visualization for an audio file',
epilog='EXAMPLE COMMAND: main.py myvideotemplate.avp '
'-i ~/Music/song.mp3 -o ~/video.mp4 '
'-c 0 image path=~/Pictures/thisWeeksPicture.jpg '
'-c 1 video "preset=My Logo" -c 2 vis layout=classic')
self.parser.add_argument(
'-i', '--input', metavar='SOUND',
help='input audio file')
self.parser.add_argument(
'-o', '--output', metavar='OUTPUT',
help='output video file')
self.settings = QSettings('settings.ini', QSettings.IniFormat)
LoadDefaultSettings(self)
# optional arguments
self.parser.add_argument(
'projpath', metavar='path-to-project',
help='open a project file (.avp)', nargs='?')
self.parser.add_argument(
'-c', '--comp', metavar=('LAYER', 'ARG'),
help='first arg must be component NAME to insert at LAYER.'
'"help" for information about possible args for a component.',
nargs='*', action='append')
# 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)
self.args = self.parser.parse_args()
self.settings = QSettings(
os.path.join(self.dataDir, 'settings.ini'), QSettings.IniFormat)
LoadDefaultSettings(self)
# font settings
if self.args.font:
self.font = QFont(self.args.font)
else:
self.font = QFont(self.settings.value("titleFont", QFont()))
if self.args.projpath:
self.core.openProject(self, self.args.projpath)
self.core.selectedComponents = list(
reversed(self.core.selectedComponents))
self.core.componentListChanged()
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.comp:
for comp in self.args.comp:
pos = comp[0]
name = comp[1]
args = comp[2:]
try:
pos = int(pos)
except ValueError:
print(pos, 'is not a layer number.')
quit(1)
realName = self.parseCompName(name)
if not realName:
print(name, 'is not a valid component name.')
quit(1)
modI = self.core.moduleIndexFor(realName)
i = self.core.insertComponent(pos, modI, self)
for arg in args:
self.core.selectedComponents[i].command(arg)
if self.args.xposition:
self.textX = int(self.args.xposition)
else:
self.textX = int(self.settings.value("xPosition", 70))
if self.args.input and self.args.output:
self.createAudioVisualisation()
elif 'help' not in sys.argv:
self.parser.print_help()
quit(1)
if self.args.yposition:
self.textY = int(self.args.yposition)
else:
self.textY = int(self.settings.value("yPosition", 375))
def createAudioVisualisation(self):
self.videoThread = QtCore.QThread(self)
self.videoWorker = video_thread.Worker(self)
self.videoWorker.moveToThread(self.videoThread)
self.videoWorker.videoCreated.connect(self.videoCreated)
ffmpeg_cmd = self.settings.value("ffmpeg_cmd", expanduser("~"))
self.videoThread.start()
self.videoTask.emit(
self.args.input,
self.args.output,
list(reversed(self.core.selectedComponents))
)
self.videoThread = QtCore.QThread(self)
self.videoWorker = video_thread.Worker(self)
def videoCreated(self):
self.videoThread.quit()
self.videoThread.wait()
quit(0)
self.videoWorker.moveToThread(self.videoThread)
self.videoWorker.videoCreated.connect(self.videoCreated)
def showMessage(self, **kwargs):
print(kwargs['msg'])
if 'detail' in kwargs:
print(kwargs['detail'])
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 drawPreview(self, *args):
pass
def videoCreated(self):
self.videoThread.quit()
self.videoThread.wait()
self.cleanUp()
def parseCompName(self, name):
'''Deduces a proper component name out of a commandline arg'''
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)
'''
if name.title() in self.core.compNames:
return name.title()
for compName in self.core.compNames:
if name.capitalize() in compName:
return compName
compFileNames = [ \
os.path.splitext(os.path.basename(
mod.__file__))[0] \
for mod in self.core.modules \
]
for i, compFileName in enumerate(compFileNames):
if name.lower() in compFileName:
return self.core.compNames[i]
return
return None

View File

@ -1,5 +1,6 @@
from PyQt4 import QtGui, QtCore
from PIL import Image
import os
class Component(QtCore.QObject):
@ -7,11 +8,12 @@ class Component(QtCore.QObject):
# modified = QtCore.pyqtSignal(int, bool)
def __init__(self, moduleIndex, compPos):
def __init__(self, moduleIndex, compPos, core):
super().__init__()
self.currentPreset = None
self.moduleIndex = moduleIndex
self.compPos = compPos
self.core = core
def __str__(self):
return self.__doc__
@ -32,24 +34,60 @@ class Component(QtCore.QObject):
# read your widget values, then call super().update()
def loadPreset(self, presetDict, presetName):
'''Children should take (presetDict, presetName=None) as args'''
# Use super().loadPreset(presetDict, presetName)
# Then update your widgets using the preset dict
'''Subclasses take (presetDict, presetName=None) as args.
Must use super().loadPreset(presetDict, presetName) first,
then update self.page widgets using the preset dict.
'''
self.currentPreset = presetName \
if presetName != None else presetDict['preset']
'''
def savePreset(self):
return {}
'''
def preFrameRender(self, **kwargs):
'''Triggered only before a video is exported (video_thread.py)
self.worker = the video thread worker
self.completeAudioArray = a list of audio samples
self.sampleSize = number of audio samples per video frame
self.progressBarUpdate = signal to set progress bar number
self.progressBarSetText = signal to set progress bar text
Use the latter two signals to update the MainProgram if needed
for a long initialization procedure (i.e., for a visualizer)
'''
for var, value in kwargs.items():
exec('self.%s = value' % var)
def command(self, arg):
'''Configure a component using argument from the commandline.
Use super().command(arg) at the end of a subclass's method,
if no arguments are found in that method first
'''
if arg.startswith('preset='):
_, preset = arg.split('=', 1)
path = os.path.join(self.core.getPresetDir(self), preset)
if not os.path.exists(path):
print('Couldn\'t locate preset "%s"' % preset)
quit(1)
else:
print('Opening "%s" preset on layer %s' % \
(preset, self.compPos))
self.core.openPreset(path, self.compPos, preset)
else:
print(
self.__doc__, 'Usage:\n'
'Open a preset for this component:\n'
' "preset=Preset Name"')
self.commandHelp()
quit(0)
def commandHelp(self):
'''Print help text for this Component's commandline arguments'''
def blankFrame(self, width, height):
return Image.new("RGBA", (width, height), (0, 0, 0, 0))
def pickColor(self):
'''Use color picker to get color input from the user,
and return this as an RGB string and QPushButton stylesheet.
In a subclass apply stylesheet to any color selection widgets
'''
dialog = QtGui.QColorDialog()
dialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, True)
color = dialog.getColor()
@ -63,7 +101,7 @@ class Component(QtCore.QObject):
return None, None
def RGBFromString(self, string):
''' turns an RGB string like "255, 255, 255" into a tuple '''
''' 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:
@ -83,7 +121,7 @@ class Component(QtCore.QObject):
self.parent = parent
page = uic.loadUi(os.path.join(
os.path.dirname(os.path.realpath(__file__)), 'example.ui'))
# connect widgets signals
# --- connect widget signals here ---
self.page = page
return page
@ -102,12 +140,6 @@ class Component(QtCore.QObject):
height = int(self.worker.core.settings.value('outputHeight'))
image = Image.new("RGBA", (width, height), (0,0,0,0))
return image
def cancel(self):
self.canceled = True
def reset(self):
self.canceled = False
'''
class BadComponentInit(Exception):

View File

@ -233,3 +233,14 @@ class Component(__base__.Component):
else:
self.page.lineEdit_color2.setText(RGBstring)
self.page.pushButton_color2.setStyleSheet(btnStyle)
def commandHelp(self):
print('Specify a color:\n color=255,255,255')
def command(self, arg):
if not arg.startswith('preset=') and '=' in arg:
key, arg = arg.split('=', 1)
if key == 'color':
self.page.lineEdit_color1.setText(arg)
return
super().command(arg)

View File

@ -92,3 +92,20 @@ class Component(__base__.Component):
self.settings.setValue("backgroundDir", os.path.dirname(filename))
self.page.lineEdit_image.setText(filename)
self.update()
def command(self, arg):
if not arg.startswith('preset=') and '=' in arg:
key, arg = arg.split('=', 1)
if key == 'path' and os.path.exists(arg):
try:
Image.open(arg)
self.page.lineEdit_image.setText(arg)
self.page.checkBox_stretch.setChecked(True)
return
except OSError as e:
print("Not a supported image format")
quit(1)
super().command(arg)
def commandHelp(self):
print('Load an image:\n path=/filepath/to/image.png')

View File

@ -183,3 +183,22 @@ class Component(__base__.Component):
return im
def command(self, arg):
if not arg.startswith('preset=') and '=' in arg:
key, arg = arg.split('=', 1)
if key == 'color':
self.page.lineEdit_visColor.setText(arg)
return
elif key == 'layout':
if arg == 'classic':
self.page.comboBox_visLayout.setCurrentIndex(0)
elif arg == 'split':
self.page.comboBox_visLayout.setCurrentIndex(1)
elif arg == 'bottom':
self.page.comboBox_visLayout.setCurrentIndex(2)
return
super().command(arg)
def commandHelp(self):
print('Give a layout name:\n layout=[classic/split/bottom]')
print('Specify a color:\n color=255,255,255')

View File

@ -19,12 +19,14 @@ class Component(__base__.Component):
def widget(self, parent):
height = int(parent.settings.value('outputHeight'))
width = int(parent.settings.value('outputWidth'))
self.parent = parent
self.textColor = (255, 255, 255)
self.title = 'Text'
self.alignment = 1
self.fontSize = height / 13.5
self.xPosition = width / 2
fm = QtGui.QFontMetrics(self.titleFont)
self.xPosition = width / 2 - fm.width(self.title)/2
self.yPosition = height / 2 * 1.036
page = uic.loadUi(os.path.join(
@ -146,3 +148,29 @@ class Component(__base__.Component):
return
self.page.lineEdit_textColor.setText(RGBstring)
self.page.pushButton_textColor.setStyleSheet(btnStyle)
def commandHelp(self):
print('Enter a string to use as centred white text:')
print(' "title=User Error"')
print('Specify a text color:\n color=255,255,255')
print('Set custom x, y position:\n x=500 y=500')
def command(self, arg):
if not arg.startswith('preset=') and '=' in arg:
key, arg = arg.split('=', 1)
if key == 'color':
self.page.lineEdit_textColor.setText(arg)
return
elif key == 'size':
self.page.spinBox_fontSize.setValue(int(arg))
return
elif key == 'x':
self.page.spinBox_xTextAlign.setValue(int(arg))
return
elif key == 'y':
self.page.spinBox_yTextAlign.setValue(int(arg))
return
elif key == 'title':
self.page.lineEdit_title.setText(arg)
return
super().command(arg)

View File

@ -221,6 +221,23 @@ class Component(__base__.Component):
width, height = scale(self.scale, width, height, int)
self.chunkSize = 4*width*height
def command(self, arg):
if not arg.startswith('preset=') and '=' in arg:
key, arg = arg.split('=', 1)
if key == 'path' and os.path.exists(arg):
if os.path.splitext(arg)[1] in self.core.videoFormats:
self.page.lineEdit_video.setText(arg)
self.page.spinBox_scale.setValue(100)
self.page.checkBox_loop.setChecked(True)
return
else:
print("Not a supported video format")
quit(1)
super().command(arg)
def commandHelp(self):
print('Load a video:\n path=/filepath/to/video.mp4')
def scale(scale, width, height, returntype=None):
width = (float(width) / 100.0) * float(scale)
height = (float(height) / 100.0) * float(scale)

65
core.py
View File

@ -43,6 +43,7 @@ class Core():
'*.wav',
'*.ogg',
'*.fla',
'*.flac',
'*.aac',
])
self.imageFormats = Core.appendUppercase([
@ -77,24 +78,32 @@ class Core():
for name in findComponents()
]
self.moduleIndexes = [i for i in range(len(self.modules))]
self.compNames = [mod.Component.__doc__ for mod in self.modules]
def componentListChanged(self):
for i, component in enumerate(self.selectedComponents):
component.compPos = i
def insertComponent(self, compPos, moduleIndex):
if compPos < 0:
compPos = len(self.selectedComponents) -1
def insertComponent(self, compPos, moduleIndex, loader):
'''Creates a new component'''
if compPos < 0 or compPos > len(self.selectedComponents):
compPos = len(self.selectedComponents)
if len(self.selectedComponents) > 50:
return None
component = self.modules[moduleIndex].Component(
moduleIndex, compPos)
moduleIndex, compPos, self)
self.selectedComponents.insert(
compPos,
component)
self.componentListChanged()
# init component's widget for loading/saving presets
self.selectedComponents[compPos].widget(loader)
self.updateComponent(compPos)
if hasattr(loader, 'insertComponent'):
loader.insertComponent(compPos)
return compPos
def moveComponent(self, startI, endI):
@ -117,15 +126,11 @@ class Core():
self.selectedComponents[i].update()
def moduleIndexFor(self, compName):
compNames = [mod.Component.__doc__ for mod in self.modules]
index = compNames.index(compName)
index = self.compNames.index(compName)
return self.moduleIndexes[index]
def clearPreset(self, compIndex, loader=None):
'''Clears a preset from a component'''
def clearPreset(self, compIndex):
self.selectedComponents[compIndex].currentPreset = None
if loader:
loader.updateComponentTitle(compIndex)
def openPreset(self, filepath, compIndex, presetName):
'''Applies a preset to a specific component'''
@ -143,6 +148,10 @@ class Core():
self.savedPresets[presetName] = dict(saveValueStore)
return True
def getPresetDir(self, comp):
return os.path.join(
self.presetDir, str(comp), str(comp.version()))
def getPreset(self, filepath):
'''Returns the preset dict stored at this filepath'''
if not os.path.exists(filepath):
@ -154,8 +163,13 @@ class Core():
return saveValueStore
def openProject(self, loader, filepath):
'''loader is the object calling this method (mainwindow/command)
which implements an insertComponent method'''
''' loader is the object calling this method which must have
its own showMessage(**kwargs) method for displaying errors.
'''
if not os.path.exists(filepath):
loader.showMessage(msg='Project file not found')
return
errcode, data = self.parseAvFile(filepath)
if errcode == 0:
try:
@ -175,10 +189,13 @@ class Core():
# saved preset was renamed or deleted
clearThis = True
# insert component into the loader
i = loader.insertComponent(
self.moduleIndexFor(name), -1)
# create the actual component object & get its index
i = self.insertComponent(
-1,
self.moduleIndexFor(name),
loader)
if i == None:
loader.showMessage(msg="Too many components!")
break
try:
@ -196,7 +213,9 @@ class Core():
(self.selectedComponents[i], e))
if clearThis:
self.clearPreset(i, loader)
self.clearPreset(i)
if hasattr(loader, 'updateComponentTitle'):
loader.updateComponentTitle(i)
except:
errcode = 1
data = sys.exc_info()
@ -208,7 +227,8 @@ class Core():
# probably just an old version, still loadable
print('file missing value: %s' % value)
return
loader.createNewProject()
if hasattr(loader, 'createNewProject'):
loader.createNewProject()
msg = '%s: %s' % (typ.__name__, value)
loader.showMessage(
msg="Project file '%s' is corrupted." % filepath,
@ -218,12 +238,14 @@ class Core():
def parseAvFile(self, filepath):
'''Parses an avp (project) or avl (preset package) file.
Returns data usable by another method.'''
Returns dictionary with section names as the keys, each one
contains a list of tuples: (compName, version, compPresetDict)
'''
data = {}
try:
with open(filepath, 'r') as f:
def parseLine(line):
'''Decides if a given avp or avl line is a section header'''
'''Decides if a file line is a section header'''
validSections = ('Components')
line = line.strip()
newSection = ''
@ -307,8 +329,7 @@ class Core():
def createPresetFile(
self, compName, vers, presetName, saveValueStore, filepath=''):
'''Create a preset file (.avl) at filepath using args.
Or if filepath is empty, create an internal preset using
the args for the filepath.'''
Or if filepath is empty, create an internal preset using args'''
if not filepath:
dirname = os.path.join(self.presetDir, compName, str(vers))
if not os.path.exists(dirname):

71
main.py
View File

@ -1,16 +1,10 @@
from importlib import import_module
from PyQt4 import QtGui, uic
from PyQt4.QtCore import Qt
import sys
import io
import os
import atexit
import signal
import core
import preview_thread
import video_thread
from mainwindow import *
def LoadDefaultSettings(self):
@ -36,42 +30,59 @@ def LoadDefaultSettings(self):
}
for parm, value in default.items():
#print(parm, self.settings.value(parm))
if self.settings.value(parm) is None:
self.settings.setValue(parm, value)
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_())
mode = 'gui'
if len(sys.argv) > 2:
mode = 'cmd'
elif len(sys.argv) == 2:
if sys.argv[1].startswith('-'):
mode = 'cmd'
else:
# opening a project file with gui
proj = sys.argv[1]
else:
'''
# normal gui launch
proj = None
app = QtGui.QApplication(sys.argv)
app.setApplicationName("audio-visualizer")
app.setOrganizationName("audio-visualizer")
if getattr(sys, 'frozen', False):
# frozen
wd = os.path.dirname(sys.executable)
else:
# unfrozen
wd = os.path.dirname(os.path.realpath(__file__))
if mode == 'cmd':
from command import *
window = uic.loadUi(os.path.join(wd, "mainwindow.ui"))
# window.adjustSize()
desc = QtGui.QDesktopWidget()
dpi = desc.physicalDpiX()
main = Command()
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)
elif mode == 'gui':
from mainwindow import *
import atexit
import signal
main = MainWindow(window)
if getattr(sys, 'frozen', False):
# frozen
wd = os.path.dirname(sys.executable)
else:
# unfrozen
wd = os.path.dirname(os.path.realpath(__file__))
signal.signal(signal.SIGINT, main.cleanUp)
atexit.register(main.cleanUp)
window = uic.loadUi(os.path.join(wd, "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 = MainWindow(window, proj)
signal.signal(signal.SIGINT, main.cleanUp)
atexit.register(main.cleanUp)
# applicable to both modes
sys.exit(app.exec_())

View File

@ -45,7 +45,7 @@ class MainWindow(QtGui.QMainWindow):
processTask = QtCore.pyqtSignal()
videoTask = QtCore.pyqtSignal(str, str, list)
def __init__(self, window):
def __init__(self, window, project):
QtGui.QMainWindow.__init__(self)
# print('main thread id: {}'.format(QtCore.QThread.currentThreadId()))
@ -149,7 +149,7 @@ class MainWindow(QtGui.QMainWindow):
for i, comp in enumerate(self.core.modules):
action = self.compMenu.addAction(comp.Component.__doc__)
action.triggered[()].connect(
lambda item=i: self.insertComponent(item))
lambda item=i: self.core.insertComponent(0, item, self))
self.window.pushButton_addComponent.setMenu(self.compMenu)
@ -209,24 +209,36 @@ class MainWindow(QtGui.QMainWindow):
self.openPresetManager
)
# Show the window and load current project
window.show()
self.currentProject = self.settings.value("currentProject")
if self.autosaveExists(identical=True):
# 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(
msg="Restore unsaved changes in project '%s'?"
% os.path.basename(self.currentProject)[:-4],
showCancel=True)
if ch:
self.saveProjectChanges()
else:
if project and project != self.autosavePath:
# open a project from the commandline
if not os.path.dirname(project):
project = os.path.join(os.path.expanduser('~'), project)
self.currentProject = project
self.settings.setValue("currentProject", project)
if os.path.exists(self.autosavePath):
os.remove(self.autosavePath)
else:
# open the last currentProject from settings
self.currentProject = self.settings.value("currentProject")
# delete autosave if it's identical to this project
if self.autosaveExists(identical=True):
os.remove(self.autosavePath)
if self.currentProject and os.path.exists(self.autosavePath):
ch = self.showMessage(
msg="Restore unsaved changes in project '%s'?"
% os.path.basename(self.currentProject)[:-4],
showCancel=True)
if ch:
self.saveProjectChanges()
else:
os.remove(self.autosavePath)
self.openProject(self.currentProject, prompt=False)
self.drawPreview()
self.drawPreview(True)
# Setup Hotkeys
QtGui.QShortcut("Ctrl+S", self.window, self.saveCurrentProject)
@ -261,7 +273,8 @@ class MainWindow(QtGui.QMainWindow):
appName = 'Audio Visualizer'
if self.currentProject:
appName += ' - %s' % \
os.path.basename(self.currentProject)[:-4]
os.path.splitext(
os.path.basename(self.currentProject))[0]
self.window.setWindowTitle(appName)
@QtCore.pyqtSlot(int, dict)
@ -273,7 +286,6 @@ class MainWindow(QtGui.QMainWindow):
else:
modified = (presetStore != self.core.savedPresets[name])
else:
print(pos, presetStore)
modified = bool(presetStore)
if pos < 0:
pos = len(self.core.selectedComponents)-1
@ -327,10 +339,14 @@ class MainWindow(QtGui.QMainWindow):
self.lastAutosave = time.time()
def autosaveExists(self, identical=True):
if self.currentProject and os.path.exists(self.autosavePath) \
and filecmp.cmp(
self.autosavePath, self.currentProject) == identical:
return True
try:
if self.currentProject and os.path.exists(self.autosavePath) \
and filecmp.cmp(
self.autosavePath, self.currentProject) == identical:
return True
except FileNotFoundError:
print('project file couldn\'t be located:', self.currentProject)
return identical
return False
def saveProjectChanges(self):
@ -432,6 +448,7 @@ class MainWindow(QtGui.QMainWindow):
self.window.listWidget_componentList.setEnabled(True)
self.window.menuButton_newProject.setEnabled(True)
self.window.menuButton_openProject.setEnabled(True)
self.drawPreview(True)
def progressBarUpdated(self, value):
self.window.progressBar_createVideo.setValue(value)
@ -458,19 +475,11 @@ class MainWindow(QtGui.QMainWindow):
def showPreviewImage(self, image):
self.previewWindow.changePixmap(image)
def insertComponent(self, moduleIndex, compPos=0):
def insertComponent(self, index):
componentList = self.window.listWidget_componentList
stackedWidget = self.window.stackedWidget
if compPos < 0:
compPos = componentList.count()
index = self.core.insertComponent(
compPos, moduleIndex)
if index == None:
self.showMessage(msg="Too many components!")
return None
row = componentList.insertItem(
componentList.insertItem(
index,
self.core.selectedComponents[index].__doc__)
componentList.setCurrentRow(index)
@ -479,11 +488,10 @@ class MainWindow(QtGui.QMainWindow):
self.core.selectedComponents[index].modified.connect(
self.updateComponentTitle)
self.pages.insert(index, self.core.selectedComponents[index].widget(self))
self.pages.insert(index, self.core.selectedComponents[index].page)
stackedWidget.insertWidget(index, self.pages[index])
stackedWidget.setCurrentIndex(index)
self.core.updateComponent(index)
return index
def removeComponent(self):
@ -620,7 +628,6 @@ class MainWindow(QtGui.QMainWindow):
self.openProject(filename)
def openProject(self, filepath, prompt=True):
print('opening', filepath)
if not filepath or not os.path.exists(filepath) \
or not filepath.endswith('.avp'):
self.updateWindowTitle()

View File

@ -27,10 +27,9 @@ class Worker(QtCore.QObject):
self.core = core.Core()
self.core.settings = parent.settings
self.modules = parent.core.modules
self.stackedWidget = parent.window.stackedWidget
self.parent = parent
parent.videoTask.connect(self.createVideo)
self.sampleSize = 1470
self.sampleSize = 1470 # 44100 / 30 = 1470
self.canceled = False
self.error = False
self.stopped = False
@ -100,7 +99,8 @@ class Worker(QtCore.QObject):
# test if user has libfdk_aac
encoders = sp.check_output(
self.core.FFMPEG_BIN + " -encoders -hide_banner", shell=True)
self.core.FFMPEG_BIN + " -encoders -hide_banner",
shell=True)
encoders = encoders.decode("utf-8")
@ -121,15 +121,15 @@ class Worker(QtCore.QObject):
vencoders = options['video-codecs'][vcodec]
aencoders = options['audio-codecs'][acodec]
print(encoders)
#print(encoders)
for encoder in vencoders:
print(encoder)
#print(encoder)
if encoder in encoders:
vencoder = encoder
break
for encoder in aencoders:
print(encoder)
#print(encoder)
if encoder in encoders:
aencoder = encoder
break
@ -162,16 +162,15 @@ 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)
# create video for output
# ### Now start creating video for output ###
numpy.seterr(divide='ignore')
# initialize components
print('loaded components:',
["%s%s" % (num, str(component)) for num,
component in enumerate(self.components)])
# Call preFrameRender on all components
print('Loaded Components:', ", ".join(
["%s) %s" % (num, str(component)) \
for num, component in enumerate(reversed(self.components))
]))
self.staticComponents = {}
numComps = len(self.components)
for compNo, comp in enumerate(self.components):
@ -191,14 +190,17 @@ class Worker(QtCore.QObject):
comp.frameRender(compNo, 0, 0))
self.progressBarUpdate.emit(100)
# Create ffmpeg pipe and queues for frames
self.out_pipe = sp.Popen(
ffmpegCommand, stdin=sp.PIPE, stdout=sys.stdout, stderr=sys.stdout)
self.compositeQueue = Queue()
self.compositeQueue.maxsize = 20
self.renderQueue = PriorityQueue()
self.renderQueue.maxsize = 20
self.previewQueue = PriorityQueue()
self.renderThreads = []
# Threads to render frames and send them back here for piping out
self.renderThreads = []
for i in range(3):
self.renderThreads.append(
Thread(target=self.renderNode, name="Render Thread"))
@ -280,7 +282,6 @@ class Worker(QtCore.QObject):
self.error = False
self.canceled = False
self.parent.drawPreview()
self.stopped = True
self.encoding.emit(False)
self.videoCreated.emit()