From 75c1c65c9d63515a1488b63e9df9971984e1f7e8 Mon Sep 17 00:00:00 2001 From: DH4 Date: Sun, 28 May 2017 06:34:34 -0500 Subject: [PATCH] Integration with tassaron2 modular design. True Alpha Rendering added, several bug fixes. --- components/__init__.py | 1 + components/original.py | 113 ++++ components/original.ui | 92 ++++ components/text.py | 59 ++ components/text.ui | 329 +++++++++++ core.py | 107 +--- main.py | 104 ++-- main.ui | 564 ------------------- mainwindow.ui | 1178 ++++++++++++++-------------------------- preview_thread.py | 42 +- video_thread.py | 80 ++- 11 files changed, 1135 insertions(+), 1534 deletions(-) create mode 100644 components/__init__.py create mode 100644 components/original.py create mode 100644 components/original.ui create mode 100644 components/text.py create mode 100644 components/text.ui delete mode 100644 main.ui diff --git a/components/__init__.py b/components/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/components/__init__.py @@ -0,0 +1 @@ + diff --git a/components/original.py b/components/original.py new file mode 100644 index 0000000..d1caa7b --- /dev/null +++ b/components/original.py @@ -0,0 +1,113 @@ +''' Original Audio Visualization ''' +import numpy +from PIL import Image, ImageDraw +from PyQt4 import uic +import os, random + + +class Component: + def widget(self,parent): + self.parent = parent + + 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) + + return page + def update(self): + self.layout = self.page.comboBox_visLayout.currentIndex() + print(self.layout) + self.parent.drawPreview() + + def previewRender(self, previewWorker, widget): + 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 drawBars(width, height, spectrum, (255, 255, 255), self.layout) + + def preFrameRender(self, **kwargs): + for kwarg, value in kwargs.items(): + exec('self.%s = value' % kwarg) + self.smoothConstantDown = 0.08 + self.smoothConstantUp = 0.8 + self.lastSpectrum = None + + def frameRender(self, moduleNo, frameNo): + self.lastSpectrum = transformData(frameNo, self.completeAudioArray, self.sampleSize, + self.smoothConstantDown, self.smoothConstantUp, self.lastSpectrum) + width = int(self.worker.core.settings.value('outputWidth')) + height = int(self.worker.core.settings.value('outputHeight')) + return drawBars(width, height, self.lastSpectrum, (255,255,255), self.layout) + +def transformData(i, completeAudioArray, sampleSize, smoothConstantDown, smoothConstantUp, lastSpectrum): + if len(completeAudioArray) < (i + sampleSize): + sampleSize = len(completeAudioArray) - i + numpy.seterr(divide='ignore') + window = numpy.hanning(sampleSize) + data = completeAudioArray[i:i+sampleSize][::1] * window + paddedSampleSize = 2048 + 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) + + y = abs(spectrum[0:int(paddedSampleSize/2) - 1]) + + # filter the noise away + # y[y<80] = 0 + + y = 20 * numpy.log10(y) + 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) + else: + lastSpectrum = y + + x = frequencies[0:int(paddedSampleSize/2) - 1] + + return lastSpectrum + +def drawBars(width, height, spectrum, color, layout): + vH = height-height/8 + bF = width / 64 + bH = bF / 2 + bQ = bF / 4 + imTop = Image.new("RGBA", (width, height),(0,0,0,0)) + draw = ImageDraw.Draw(imTop) + r, g, b = color + color2 = (r, g, b, 125) + + 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) + + + imBottom = imTop.transpose(Image.FLIP_TOP_BOTTOM) + + im = Image.new("RGBA", (width, height),(0,0,0,0)) + + if layout == 0: + y = 0 - int(height/100*43) + im.paste(imTop, (0, y), mask=imTop) + y = 0 + int(height/100*43) + im.paste(imBottom, (0, y), mask=imBottom) + + if layout == 1: + y = 0 + int(height/100*10) + im.paste(imTop, (0, y), mask=imTop) + y = 0 - int(height/100*10) + im.paste(imBottom, (0, y), mask=imBottom) + + if layout == 2: + y = 0 + int(height/100*10) + im.paste(imTop, (0, y), mask=imTop) + + return im diff --git a/components/original.ui b/components/original.ui new file mode 100644 index 0000000..0e6dd98 --- /dev/null +++ b/components/original.ui @@ -0,0 +1,92 @@ + + + Form + + + + 0 + 0 + 584 + 169 + + + + Form + + + + + 10 + 10 + 567 + 29 + + + + + + + + 0 + 0 + + + + Visualizer Layout + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + Visualizer Color + + + + + + + + 32 + 32 + + + + + + + + 32 + 32 + + + + + + + + + + + + + diff --git a/components/text.py b/components/text.py new file mode 100644 index 0000000..68b02fe --- /dev/null +++ b/components/text.py @@ -0,0 +1,59 @@ +''' Title Text ''' +import numpy +from PIL import Image, ImageDraw +from PyQt4 import uic +import os + + +class Component: + def widget(self,parent): + page = uic.loadUi(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'text.ui')) + return page + def previewRender(self, previewWorker, widget): + width = int(previewWorker.core.settings.value('outputWidth')) + height = int(previewWorker.core.settings.value('outputHeight')) + im = Image.new("RGBA", (width, height),(0,0,0,0)) + + return im + + def preFrameRender(self, **kwargs): + pass + def frameRender(self, moduleNo, frameNo): + width = int(previewWorker.core.settings.value('outputWidth')) + height = int(previewWorker.core.settings.value('outputHeight')) + im = Image.new("RGBA", (width, height),(0,0,0,0)) + + return im + + ''' + self._image = ImageQt(im) + + self._image1 = QtGui.QImage(self._image) + painter = QPainter(self._image1) + font = titleFont + font.setPixelSize(fontSize) + painter.setFont(font) + painter.setPen(QColor(*textColor)) + + yPosition = yOffset + + fm = QtGui.QFontMetrics(font) + if alignment == 0: #Left + xPosition = xOffset + if alignment == 1: #Middle + xPosition = xOffset - fm.width(titleText)/2 + if alignment == 2: #Right + xPosition = xOffset - fm.width(titleText) + painter.drawText(xPosition, yPosition, titleText) + painter.end() + + buffer = QtCore.QBuffer() + buffer.open(QtCore.QIODevice.ReadWrite) + self._image1.save(buffer, "PNG") + + strio = io.BytesIO() + strio.write(buffer.data()) + buffer.close() + strio.seek(0) + return Image.open(strio) + ''' diff --git a/components/text.ui b/components/text.ui new file mode 100644 index 0000000..4431278 --- /dev/null +++ b/components/text.ui @@ -0,0 +1,329 @@ + + + Form + + + + 0 + 0 + 584 + 169 + + + + Form + + + + + 10 + 20 + 567 + 25 + + + + + 0 + + + + + Title + + + + + + + + 0 + 0 + + + + + 300 + 0 + + + + Testing New GUI + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + + 0 + 0 + + + + X + + + + + + + + 0 + 0 + + + + + 80 + 16777215 + + + + + 0 + 0 + + + + 0 + + + 999999999 + + + 0 + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + + 0 + 0 + + + + Y + + + + + + + + 0 + 0 + + + + + 80 + 16777215 + + + + 999999999 + + + + + + + + + 10 + 51 + 567 + 29 + + + + + + + + 0 + 0 + + + + Font + + + + + + + + 0 + 0 + + + + + 140 + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + + 0 + 0 + + + + Font Size + + + + + + + 500 + + + + + + + + + 10 + 86 + 567 + 29 + + + + + + + + 0 + 0 + + + + Text Layout + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + Text Color + + + + + + + + 32 + 32 + + + + + + + + 32 + 32 + + + + + + + + + + + + + 10 + 121 + 567 + 29 + + + + + + + + diff --git a/core.py b/core.py index 8292f5b..c8bfbca 100644 --- a/core.py +++ b/core.py @@ -42,8 +42,7 @@ class Core(): else: return self.getVideoFrames(backgroundImage, preview) - def drawBaseImage(self, backgroundFile, titleText, titleFont, fontSize, alignment,\ - xOffset, yOffset, textColor, visColor): + def drawBaseImage(self, backgroundFile): if backgroundFile == '': im = Image.new("RGB", (int(self.settings.value('outputWidth')), int(self.settings.value('outputHeight'))), "black") else: @@ -51,81 +50,10 @@ class Core(): if self._image == None or not self.lastBackgroundImage == backgroundFile: self.lastBackgroundImage = backgroundFile - # resize if necessary if not im.size == (int(self.settings.value('outputWidth')), int(self.settings.value('outputHeight'))): im = im.resize((int(self.settings.value('outputWidth')), int(self.settings.value('outputHeight'))), Image.ANTIALIAS) - - self._image = ImageQt(im) - - self._image1 = QtGui.QImage(self._image) - painter = QPainter(self._image1) - font = titleFont - font.setPixelSize(fontSize) - painter.setFont(font) - painter.setPen(QColor(*textColor)) - - fm = QtGui.QFontMetrics(font) - yPosition = yOffset + fm.height()/6 - - if alignment == 0: #Left - xPosition = xOffset - if alignment == 1: #Middle - xPosition = xOffset - fm.width(titleText)/2 - if alignment == 2: #Right - xPosition = xOffset - fm.width(titleText) - painter.drawText(xPosition, yPosition, titleText) - painter.end() - - buffer = QtCore.QBuffer() - buffer.open(QtCore.QIODevice.ReadWrite) - self._image1.save(buffer, "PNG") - - strio = io.BytesIO() - strio.write(buffer.data()) - buffer.close() - strio.seek(0) - return Image.open(strio) - - def drawBars(self, spectrum, image, color): - - width = int(self.settings.value('outputWidth')) - height = int(int(self.settings.value('outputHeight'))/2) - - vH = height-height/8 - bF = int(self.settings.value('outputWidth')) / 64 - bH = bF / 2 - bQ = bF / 4 - imTop = Image.new("RGBA", (width, height)) - draw = ImageDraw.Draw(imTop) - r, g, b = color - color2 = (r, g, b, 50) - - bP = int(self.settings.value('outputHeight')) / 800 - - 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) - - - imBottom = imTop.transpose(Image.FLIP_TOP_BOTTOM) - - im = Image.new("RGB", (int(self.settings.value('outputWidth')), int(self.settings.value('outputHeight'))), "black") - im.paste(image, (0, 0)) - - layout = int(self.settings.value('visLayout')) - - if layout == 0: - im.paste(imTop, (0, 0), mask=imTop) - im.paste(imBottom, (0, int(vH+bF*1.8)), mask=imBottom) - - if layout == 1: - im.paste(imTop, (0, int(height+bF*1.5)), mask=imTop) - im.paste(imBottom, (0, int(0-bF*1.5)), mask=imBottom) - - if layout == 2: - im.paste(imTop, (0, int(height+bF*1.5)), mask=imTop) - + return im def readAudioFile(self, filename): @@ -159,41 +87,10 @@ class Core(): return completeAudioArray - 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') - spectrum = numpy.fft.fft(paddedData) - sample_rate = 44100 - frequencies = numpy.fft.fftfreq(len(spectrum), 1./sample_rate) - - y = abs(spectrum[0:int(paddedSampleSize/2) - 1]) - - # filter the noise away - # y[y<80] = 0 - - y = 20 * numpy.log10(y) - 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) - else: - lastSpectrum = y - - x = frequencies[0:int(paddedSampleSize/2) - 1] - - return lastSpectrum - def deleteTempDir(self): if self.tempDir and os.path.exists(self.tempDir): rmtree(self.tempDir) - def getVideoFrames(self, videoPath, firstOnly=False): self.tempDir = os.path.join(tempfile.gettempdir(), 'audio-visualizer-python-data') # recreate the temporary directory so it is empty diff --git a/main.py b/main.py index 4fe9315..b700ad7 100644 --- a/main.py +++ b/main.py @@ -10,15 +10,18 @@ import atexit from queue import Queue from PyQt4.QtCore import QSettings import signal +from importlib import import_module import preview_thread, core, video_thread class Command(QtCore.QObject): - videoTask = QtCore.pyqtSignal(str, str, QFont, int, int, int, int, tuple, tuple, str, str) + videoTask = QtCore.pyqtSignal(str, str, QFont, int, int, int, int, tuple, tuple, 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') @@ -90,7 +93,8 @@ class Command(QtCore.QObject): self.textColor, self.visColor, self.args.input, - self.args.output) + self.args.output, + self.selectedComponents) def videoCreated(self): self.videoThread.quit() @@ -109,9 +113,9 @@ class Command(QtCore.QObject): class Main(QtCore.QObject): - newTask = QtCore.pyqtSignal(str, str, QFont, int, int, int, int, tuple, tuple) + newTask = QtCore.pyqtSignal(str, list) processTask = QtCore.pyqtSignal() - videoTask = QtCore.pyqtSignal(str, str, QFont, int, int, int, int, tuple, tuple, str, str) + videoTask = QtCore.pyqtSignal(str, str, str, list) def __init__(self, window): QtCore.QObject.__init__(self) @@ -121,6 +125,8 @@ class Main(QtCore.QObject): self.core = core.Core() self.settings = QSettings('settings.ini', QSettings.IniFormat) LoadDefaultSettings(self) + + self.pages = [] # load colors as tuples from a comma-separated string self.textColor = core.Core.RGBFromString(self.settings.value("textColor", '255, 255, 255')) @@ -140,24 +146,26 @@ class Main(QtCore.QObject): 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_selectBackground.clicked.connect(self.openBackgroundFileDialog) window.toolButton_selectOutputFile.clicked.connect(self.openOutputFileDialog) window.progressBar_createVideo.setValue(0) window.pushButton_createVideo.clicked.connect(self.createAudioVisualisation) window.setWindowTitle("Audio Visualizer") - window.comboBox_textAlign.addItem("Left") - window.comboBox_textAlign.addItem("Middle") - window.comboBox_textAlign.addItem("Right") - window.comboBox_textAlign.setCurrentIndex(1) - window.comboBox_visLayout.addItem("Classic") - window.comboBox_visLayout.addItem("Split") - window.comboBox_visLayout.addItem("Bottom") - visLayoutValue = int(self.settings.value('visLayout')) - window.comboBox_visLayout.setCurrentIndex(visLayoutValue) + self.modules = self.findComponents() + for component in self.modules: + window.comboBox_componentSelection.addItem(component.__doc__) + window.listWidget_componentList.clicked.connect(lambda _: self.changeComponentWidget()) + self.selectedComponents = [] - currentRes = self.settings.value('outputWidth')+'x'+self.settings.value('outputHeight') + self.window.pushButton_addComponent.clicked.connect( \ + lambda _: self.addComponent(self.window.comboBox_componentSelection.currentIndex()) + ) + 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: @@ -165,8 +173,12 @@ class Main(QtCore.QObject): window.comboBox_resolution.setCurrentIndex(currentRes) window.comboBox_resolution.currentIndexChanged.connect(self.updateResolution) - # FIXME This needs to be changed in a future commit. - # We should be setting these values somewhere else. + ''' + window.comboBox_textAlign.addItem("Left") + window.comboBox_textAlign.addItem("Middle") + window.comboBox_textAlign.addItem("Right") + window.comboBox_textAlign.setCurrentIndex(1) + window.spinBox_fontSize.setValue(int(int(self.settings.value("outputHeight")) / 14 )) window.spinBox_xTextAlign.setValue(int(int(self.settings.value('outputWidth'))/2)) window.spinBox_yTextAlign.setValue(int(int(self.settings.value('outputHeight'))/2)) @@ -206,7 +218,7 @@ class Main(QtCore.QObject): window.spinBox_fontSize.valueChanged.connect(self.drawPreview) window.lineEdit_textColor.textChanged.connect(self.drawPreview) window.lineEdit_visColor.textChanged.connect(self.drawPreview) - + ''' self.drawPreview() window.show() @@ -268,18 +280,10 @@ class Main(QtCore.QObject): self.videoThread.start() self.videoTask.emit(self.window.lineEdit_background.text(), - self.window.lineEdit_title.text(), - self.window.fontComboBox_titleFont.currentFont(), - self.window.spinBox_fontSize.value(), - self.window.comboBox_textAlign.currentIndex(), - self.window.spinBox_xTextAlign.value(), - self.window.spinBox_yTextAlign.value(), - core.Core.RGBFromString(self.window.lineEdit_textColor.text()), - core.Core.RGBFromString(self.window.lineEdit_visColor.text()), self.window.lineEdit_audioFile.text(), - self.window.lineEdit_outputFile.text()) + self.window.lineEdit_outputFile.text(), + self.selectedComponents) - def progressBarUpdated(self, value): self.window.progressBar_createVideo.setValue(value) @@ -298,16 +302,8 @@ class Main(QtCore.QObject): self.drawPreview def drawPreview(self): - self.settings.setValue('visLayout', self.window.comboBox_visLayout.currentIndex()) - self.newTask.emit(self.window.lineEdit_background.text(), - self.window.lineEdit_title.text(), - self.window.fontComboBox_titleFont.currentFont(), - self.window.spinBox_fontSize.value(), - self.window.comboBox_textAlign.currentIndex(), - self.window.spinBox_xTextAlign.value(), - self.window.spinBox_yTextAlign.value(), - core.Core.RGBFromString(self.window.lineEdit_textColor.text()), - core.Core.RGBFromString(self.window.lineEdit_visColor.text())) + #self.settings.setValue('visLayout', self.window.comboBox_visLayout.currentIndex()) + self.newTask.emit(self.window.lineEdit_background.text(), self.selectedComponents) # self.processTask.emit() def showPreviewImage(self, image): @@ -328,6 +324,40 @@ class Main(QtCore.QObject): self.window.lineEdit_visColor.setText(RGBstring) window.pushButton_visColor.setStyleSheet(btnStyle) + 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 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): + self.window.listWidget_componentList.addItem(self.modules[moduleIndex].__doc__) + self.selectedComponents.append(self.modules[moduleIndex].Component()) + self.selectedComponents[-1].page = self.selectedComponents[-1].widget(self) + self.pages.append(self.selectedComponents[-1].page) + self.window.stackedWidget.addWidget(self.pages[-1]) + self.selectedComponents[-1].update() + + 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) + print(self.selectedComponents) + self.drawPreview() + + def changeComponentWidget(self): + selected = self.window.listWidget_componentList.selectedItems() + index = self.window.listWidget_componentList.row(selected[0]) + self.window.stackedWidget.setCurrentIndex(index) + def LoadDefaultSettings(self): self.resolutions = [ '1920x1080', diff --git a/main.ui b/main.ui deleted file mode 100644 index 5acb7eb..0000000 --- a/main.ui +++ /dev/null @@ -1,564 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 635 - 600 - - - - - 0 - 0 - - - - - 635 - 600 - - - - MainWindow - - - - - 0 - 0 - - - - - - - - - - 0 - 0 - - - - - 0 - 200 - - - - - 16777215 - 16777215 - - - - GroupBox - - - - - - - - - - - 1 - 0 - - - - - 200 - 0 - - - - - 16777215 - 16777215 - - - - PushButton - - - - - - - - 2 - 0 - - - - QFrame::Box - - - - - - - - - - - - - - - 1 - 0 - - - - - 200 - 0 - - - - - 16777215 - 16777215 - - - - PushButton - - - - - - - - 2 - 0 - - - - QFrame::Box - - - - - - - - - - - - - - - 1 - 0 - - - - - 200 - 0 - - - - - 16777215 - 16777215 - - - - PushButton - - - - - - - - 2 - 0 - - - - QFrame::Box - - - - - - - - - - - - - - - 200 - 0 - - - - - 200 - 16777215 - - - - - 200 - 0 - - - - QFrame::NoFrame - - - - - - - - - - - - - - - - - - 200 - 0 - - - - - 200 - 16777215 - - - - - 200 - 0 - - - - QFrame::NoFrame - - - - - - - - - - - - - - - - - - - - - - 999 - - - - - - - Qt::LeftToRight - - - X - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - -99999 - - - 99999 - - - - - - - Y - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - -99999 - - - 99999 - - - - - - - - - - - - - - 200 - 0 - - - - - 200 - 16777215 - - - - - 200 - 0 - - - - QFrame::NoFrame - - - - - - - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - - - - - 200 - 0 - - - - - 200 - 16777215 - - - - - 200 - 0 - - - - QFrame::NoFrame - - - - - - - - - - - - - - - - - - - 0 - 0 - - - - - 0 - 220 - - - - - 16777215 - 220 - - - - GroupBox - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - 320 - 180 - - - - - 320 - 180 - - - - QFrame::Box - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - GroupBox - - - - - - - - 24 - - - Qt::AlignCenter - - - true - - - - - - - - 0 - 0 - - - - PushButton - - - - - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - - - - diff --git a/mainwindow.ui b/mainwindow.ui index 3dbb817..ce8233e 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 1139 - 658 + 1165 + 707 @@ -109,118 +109,90 @@ 3 - - - - 0 - 0 - + + + 3 - - - 280 - 200 - - - - - - - Qt::ScrollBarAlwaysOn - - - Qt::ScrollBarAlwaysOff - - - - - - - - - 3 - - - - - - Open Project + + + + + Open Project + + + + + + + Save Project + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + 0 + 0 + + + + + 280 + 0 + - - - Save Project - - + + + + + Add Component + + + + + + + Remove Component + + + + - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 10 - - - - - - + - + 0 0 - - - 280 - 0 - - - - - - - - Add Component - - - - - - - Remove Component - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -251,456 +223,81 @@ 4 + + 0 + - - - 8 - - - 8 - - - - - 0 - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - 80 - 0 - - - - Audio File - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 340 - 28 - - - - - 16777215 - 28 - - - - - 0 - 0 - - - - - - - - - 0 - 28 - - - - - 16777215 - 28 - - - - ... - - - - - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - Background - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 0 - 28 - - - - - 16777215 - 28 - - - - - - - - - 0 - 28 - - - - - 16777215 - 28 - - - - ... - - - - - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - 0 - 0 - - - - Output File - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 0 - 28 - - - - - 16777215 - 28 - - - - - - - - - 0 - 28 - - - - - 16777215 - 28 - - - - ... - - - - - - - - - - - - 0 - 0 - - - - - 98 - 0 - - - - Video Format - - - - - - - - - - - 0 - 0 - - - - Video Preset - - - - - - - - - - - - - - - 0 - 0 - - - - - 98 - 0 - - - - Video Codec - - - - - - - - 150 - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 5 - - - - - - - - - 0 - 0 - - - - Resolution - - - - - - - - - - - - - - - 0 - 0 - - - - - 98 - 0 - - - - Audio Codec - - - - - - - - 150 - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 10 - - - - - - - - - 0 - 0 - - - - Bitrate - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Maximum - - - - 20 - 40 - - - - - - - - + - + 0 0 - - + + + 0 + 180 + + + + + 16777215 + 180 + + + + QTabWidget::North + + + QTabWidget::Rounded 0 - - + + + Input Settings + + + + 10 + - - + + 0 - + + + + 0 + 0 + + + + + 100 + 0 + + + + + 80 + 0 + + - Title + Audio File + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + 0 @@ -709,56 +306,14 @@ - 300 - 0 + 340 + 28 - - Testing New GUI - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - - - - - 0 - 0 - - - - X - - - - - - - - 0 - 0 - - - 80 - 16777215 + 16777215 + 28 @@ -767,84 +322,55 @@ 0 - - 0 - - - 999999999 - - - 0 - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - + + - 5 - 20 + 0 + 28 - - - - - - - 0 - 0 - - - - Y - - - - - - - - 0 - 0 - - - 80 - 16777215 + 16777215 + 28 - - 999999999 + + ... - + - + 0 0 + + + 100 + 0 + + - Font + Background + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + 0 @@ -853,14 +379,124 @@ - 140 + 0 + 28 + + + + + 16777215 + 28 + + + + + + + + + 0 + 28 + + + + + 16777215 + 28 + + + + ... + + + + + + + + + + Encoder Settings + + + + 10 + + + + + + + + 0 + 0 + + + + + 98 + 0 + + + + Video Format + + + + + + + + + + + 0 + 0 + + + + Video Preset + + + + + + + + + + + + + + + 0 + 0 + + + + + 98 + 0 + + + + Video Codec + + + + + + + + 150 0 - + Qt::Horizontal @@ -870,13 +506,13 @@ 5 - 20 + 5 - + 0 @@ -884,39 +520,48 @@ - Font Size + Resolution - - - 500 - - + - + - + 0 0 + + + 98 + 0 + + - Text Layout + Audio Codec - + + + + 150 + 0 + + + - + Qt::Horizontal @@ -926,46 +571,13 @@ 5 - 20 + 10 - - - Text Color - - - - - - - - 32 - 32 - - - - - - - - 32 - 32 - - - - - - - - - - - - - + 0 @@ -973,139 +585,179 @@ - Visualizer Layout + Bitrate - + + + + + + + + + Export Video + + + + 10 + + + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + 0 + 0 + + + + Output File + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 0 + 28 + + + + + 16777215 + 28 + + + + + + + + + 0 + 28 + + + + + 16777215 + 28 + + + + ... + + + + + + + + + + + 0 + + + + + + 0 + 0 + + + + 24 + + - + Qt::Horizontal - QSizePolicy::Fixed + QSizePolicy::Minimum - 5 + 10 20 - + - Visulizer Color + Create video - - - - 32 - 32 - - + - - - - - 32 - 32 - + Cancel - - - - - - - Qt::Vertical - - - QSizePolicy::Minimum - - - - 20 - 80 - - - - - - verticalSpacer_4 - - - - - - 0 - - - 20 - - - 0 - - - 0 - - + + + + 0 + 0 + + 0 - 0 + 180 - - 24 - - - - - - - Qt::Horizontal - - - QSizePolicy::Minimum - - + - 10 - 20 + 16777215 + 180 - - - - - - Create video - - - - - - - Cancel + + -1 diff --git a/preview_thread.py b/preview_thread.py index 593a70f..e8b2021 100644 --- a/preview_thread.py +++ b/preview_thread.py @@ -18,23 +18,17 @@ class Worker(QtCore.QObject): self.core = core.Core() self.queue = queue self.core.settings = parent.settings + self.stackedWidget = parent.window.stackedWidget - @pyqtSlot(str, str, QtGui.QFont, int, int, int, int, tuple, tuple) - def createPreviewImage(self, backgroundImage, titleText, titleFont, fontSize,\ - alignment, xOffset, yOffset, textColor, visColor): + @pyqtSlot(str, list) + def createPreviewImage(self, backgroundImage, components): # print('worker thread id: {}'.format(QtCore.QThread.currentThreadId())) dic = { "backgroundImage": backgroundImage, - "titleText": titleText, - "titleFont": titleFont, - "fontSize": fontSize, - "alignment": alignment, - "xoffset": xOffset, - "yoffset": yOffset, - "textColor" : textColor, - "visColor" : visColor + "components": components, } + print(components) self.queue.put(dic) @pyqtSlot() @@ -56,21 +50,21 @@ class Worker(QtCore.QObject): else: bgImage = bgImage[0] - im = self.core.drawBaseImage( - bgImage, - nextPreviewInformation["titleText"], - nextPreviewInformation["titleFont"], - nextPreviewInformation["fontSize"], - nextPreviewInformation["alignment"], - nextPreviewInformation["xoffset"], - nextPreviewInformation["yoffset"], - nextPreviewInformation["textColor"], - nextPreviewInformation["visColor"]) - spectrum = numpy.fromfunction(lambda x: 0.008*(x-128)**2, (255,), dtype="int16") + im = self.core.drawBaseImage(bgImage) + frame = Image.new("RGBA", (1280, 720),(0,0,0,255)) + frame.paste(im) - im = self.core.drawBars(spectrum, im, nextPreviewInformation["visColor"]) - self._image = ImageQt(im) + componentWidgets = [self.stackedWidget.widget(i) for i in range(self.stackedWidget.count())] + components = nextPreviewInformation["components"] + print(components) + print(componentWidgets) + for component, componentWidget in zip(components, componentWidgets): + print('drawing') + newFrame = Image.alpha_composite(frame,component.previewRender(self, componentWidget)) + frame = Image.alpha_composite(frame,newFrame) + + self._image = ImageQt(frame) self.imageCreated.emit(QtGui.QImage(self._image)) except Empty: diff --git a/video_thread.py b/video_thread.py index 5b9a896..ccb2730 100644 --- a/video_thread.py +++ b/video_thread.py @@ -17,24 +17,15 @@ class Worker(QtCore.QObject): QtCore.QObject.__init__(self) self.core = core.Core() self.core.settings = parent.settings + self.modules = parent.modules + self.stackedWidget = parent.window.stackedWidget parent.videoTask.connect(self.createVideo) - - @pyqtSlot(str, str, QtGui.QFont, int, int, int, int, tuple, tuple, str, str) - def createVideo(self, backgroundImage, titleText, titleFont, fontSize, alignment,\ - xOffset, yOffset, textColor, visColor, inputFile, outputFile): + @pyqtSlot(str, str, str, list) + def createVideo(self, backgroundImage, inputFile, outputFile, components): # print('worker thread id: {}'.format(QtCore.QThread.currentThreadId())) def getBackgroundAtIndex(i): - return self.core.drawBaseImage( - backgroundFrames[i], - titleText, - titleFont, - fontSize, - alignment, - xOffset, - yOffset, - textColor, - visColor) + return self.core.drawBaseImage(backgroundFrames[i]) progressBarValue = 0 self.progressBarUpdate.emit(progressBarValue) @@ -84,40 +75,47 @@ class Worker(QtCore.QObject): out_pipe = sp.Popen(ffmpegCommand, stdin=sp.PIPE,stdout=sys.stdout, stderr=sys.stdout) - smoothConstantDown = 0.08 - smoothConstantUp = 0.8 - lastSpectrum = None + # initialize components + componentWidgets = [self.stackedWidget.widget(i) for i in range(self.stackedWidget.count())] + + print('######################## Data') + print(components) + print(componentWidgets) sampleSize = 1470 - + for component, widget in zip(components, componentWidgets): + component.preFrameRender(worker=self, widget=widget, completeAudioArray=completeAudioArray, sampleSize=sampleSize) + numpy.seterr(divide='ignore') + frame = getBackgroundAtIndex(0) bgI = 0 + # create video for output for i in range(0, len(completeAudioArray), sampleSize): - # create video for output - lastSpectrum = self.core.transformData( - i, - completeAudioArray, - sampleSize, - smoothConstantDown, - smoothConstantUp, - lastSpectrum) - if imBackground != None: - im = self.core.drawBars(lastSpectrum, imBackground, visColor) - else: - im = self.core.drawBars(lastSpectrum, getBackgroundAtIndex(bgI), visColor) - if bgI < len(backgroundFrames)-1: - bgI += 1 + newFrame = Image.new("RGBA", (int(self.core.settings.value('outputWidth')), int(self.core.settings.value('outputHeight'))),(0,0,0,255)) + if imBackground: + newFrame.paste(imBackground) + else: + newFrame.paste(getBackgroundAtIndex(bgI)) + + for compNo, comp in enumerate(components): + newFrame = Image.alpha_composite(newFrame,comp.frameRender(compNo, i)) + + if not imBackground: + if bgI < len(backgroundFrames)-1: + bgI += 1 # write to out_pipe - try: - out_pipe.stdin.write(im.tobytes()) - finally: - True + try: + frame = Image.new("RGB", (int(self.core.settings.value('outputWidth')), int(self.core.settings.value('outputHeight'))),(0,0,0)) + frame.paste(newFrame) + out_pipe.stdin.write(frame.tobytes()) + finally: + True - # increase progress bar value - if progressBarValue + 1 <= (i / len(completeAudioArray)) * 100: - progressBarValue = numpy.floor((i / len(completeAudioArray)) * 100) - self.progressBarUpdate.emit(progressBarValue) - self.progressBarSetText.emit('%s%%' % str(int(progressBarValue))) + # increase progress bar value + if progressBarValue + 1 <= (i / len(completeAudioArray)) * 100: + progressBarValue = numpy.floor((i / len(completeAudioArray)) * 100) + self.progressBarUpdate.emit(progressBarValue) + self.progressBarSetText.emit('%s%%' % str(int(progressBarValue))) numpy.seterr(all='print')