diff options
| author | tassaron | 2017-06-18 14:46:08 -0400 |
|---|---|---|
| committer | tassaron | 2017-06-18 14:46:08 -0400 |
| commit | 044fddfa9c5063f61e4a97993efe7cd5b2bae066 (patch) | |
| tree | 011551caf0c8f21831a697eccef67acda1dfaa5f | |
| parent | 2c63b053769ecdc2791af3b35392f0ff0b19ad76 (diff) | |
basic commandline functionality using 3 args
needs more args so components can be modified without gui
| -rw-r--r-- | command.py | 215 | ||||
| -rw-r--r-- | core.py | 40 | ||||
| -rw-r--r-- | main.py | 54 | ||||
| -rw-r--r-- | mainwindow.py | 76 | ||||
| -rw-r--r-- | video_thread.py | 2 |
5 files changed, 196 insertions, 191 deletions
@@ -1,122 +1,97 @@ -# 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 core +import video_thread +from main import LoadDefaultSettings + + 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) -''' + videoTask = QtCore.pyqtSignal(str, str, list) + + def __init__(self): + QtCore.QObject.__init__(self) + self.core = core.Core() + self.dataDir = self.core.dataDir + + self.parser = argparse.ArgumentParser( + description='Create a visualization for an audio file') + self.parser.add_argument( + '-i', '--input', help='input audio file', required=True) + self.parser.add_argument( + '-o', '--output', help='output video file', required=True) + + # optional arguments + self.parser.add_argument( + 'projpath', metavar='path-to-project', + help='open a project file (.avp)', nargs='?') + + ''' + 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( + os.path.join(self.dataDir, 'settings.ini'), QSettings.IniFormat) + LoadDefaultSettings(self) + + if self.args.projpath: + self.core.openProject(self, self.args.projpath) + + self.createAudioVisualisation() + + 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) + + self.videoThread.start() + self.videoTask.emit( + self.args.input, + self.args.output, + self.core.selectedComponents) + + def videoCreated(self): + self.videoThread.quit() + self.videoThread.wait() + self.cleanUp() + + def showMessage(self, **kwargs): + print(kwargs['msg']) + if 'detail' in kwargs: + print(kwargs['detail']) + + def drawPreview(self, *args): + pass + + def cleanUp(self, *args): + pass @@ -37,6 +37,7 @@ class Core(): '*.wav', '*.ogg', '*.fla', + '*.flac', '*.aac', ]) self.imageFormats = Core.appendUppercase([ @@ -76,9 +77,10 @@ class Core(): for i, component in enumerate(self.selectedComponents): component.compPos = i - def insertComponent(self, compPos, moduleIndex): + def insertComponent(self, compPos, moduleIndex, loader): + '''Creates a new component''' if compPos < 0: - compPos = len(self.selectedComponents) -1 + compPos = len(self.selectedComponents) if len(self.selectedComponents) > 50: return None @@ -87,8 +89,14 @@ class Core(): 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): @@ -115,11 +123,8 @@ class Core(): index = 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''' @@ -148,9 +153,10 @@ 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''' errcode, data = self.parseAvFile(filepath) + print(data) if errcode == 0: try: for i, tup in enumerate(data['Components']): @@ -169,10 +175,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: @@ -190,7 +199,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() @@ -202,7 +213,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, @@ -1,8 +1,5 @@ -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 @@ -10,7 +7,6 @@ import signal import core import preview_thread import video_thread -from mainwindow import * def LoadDefaultSettings(self): @@ -36,34 +32,50 @@ 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") - 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) + if mode == 'cmd': + from command import * + + main = Command() + + elif mode == 'gui': + from mainwindow import * + + 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 = MainWindow(window) + main = MainWindow(window, proj) + # applicable to both modes signal.signal(signal.SIGINT, main.cleanUp) atexit.register(main.cleanUp) diff --git a/mainwindow.py b/mainwindow.py index f722158..2a8762d 100644 --- a/mainwindow.py +++ b/mainwindow.py @@ -45,7 +45,7 @@ class MainWindow(QtCore.QObject): processTask = QtCore.pyqtSignal() videoTask = QtCore.pyqtSignal(str, str, list) - def __init__(self, window): + def __init__(self, window, project): QtCore.QObject.__init__(self) # print('main thread id: {}'.format(QtCore.QThread.currentThreadId())) @@ -151,7 +151,7 @@ class MainWindow(QtCore.QObject): 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) @@ -211,24 +211,36 @@ class MainWindow(QtCore.QObject): 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) def cleanUp(self): self.timer.stop() @@ -240,7 +252,8 @@ class MainWindow(QtCore.QObject): 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) @@ -252,7 +265,6 @@ class MainWindow(QtCore.QObject): else: modified = (presetStore != self.core.savedPresets[name]) else: - print(pos, presetStore) modified = bool(presetStore) if pos < 0: pos = len(self.core.selectedComponents)-1 @@ -306,10 +318,14 @@ class MainWindow(QtCore.QObject): 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): @@ -411,6 +427,7 @@ class MainWindow(QtCore.QObject): 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) @@ -437,19 +454,11 @@ class MainWindow(QtCore.QObject): 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) @@ -458,11 +467,10 @@ class MainWindow(QtCore.QObject): 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): diff --git a/video_thread.py b/video_thread.py index d7220f1..2255259 100644 --- a/video_thread.py +++ b/video_thread.py @@ -27,7 +27,6 @@ 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 @@ -280,7 +279,6 @@ class Worker(QtCore.QObject): self.error = False self.canceled = False - self.parent.drawPreview() self.stopped = True self.encoding.emit(False) self.videoCreated.emit() |
