From c21d6f5ea7c6d33e2ded44b823d2dbb5b9384d78 Mon Sep 17 00:00:00 2001 From: DH4 Date: Wed, 31 May 2017 02:15:09 -0500 Subject: New rendering engine partially implemented. Also added a live preview during rendering. FIXME: spectrum is out of sync / rendering too quickly. --- components/original.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'components') diff --git a/components/original.py b/components/original.py index 47e53b8..46e7182 100644 --- a/components/original.py +++ b/components/original.py @@ -49,13 +49,17 @@ class Component(__base__.Component): self.smoothConstantDown = 0.08 self.smoothConstantUp = 0.8 self.lastSpectrum = None - + self.spectrumArray = {} + + for i in range(0, len(self.completeAudioArray), self.sampleSize): + spectrum = transformData(i, self.completeAudioArray, self.sampleSize, + self.smoothConstantDown, self.smoothConstantUp, self.lastSpectrum) + self.spectrumArray[i] = spectrum + 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, self.visColor, self.layout) + return drawBars(width, height, self.spectrumArray[frameNo], self.visColor, self.layout) def pickColor(self): RGBstring, btnStyle = super().pickColor() -- cgit v1.2.3 From 2afdba04fded945f0b47f989e228a8eedd3d50d2 Mon Sep 17 00:00:00 2001 From: tassaron Date: Thu, 1 Jun 2017 09:05:20 -0400 Subject: minor fixes, comments --- components/text.py | 7 ++----- video_thread.py | 42 ++++++++++++++++++++++-------------------- 2 files changed, 24 insertions(+), 25 deletions(-) (limited to 'components') diff --git a/components/text.py b/components/text.py index c9359f2..c0bb61f 100644 --- a/components/text.py +++ b/components/text.py @@ -95,19 +95,16 @@ class Component(__base__.Component): im = Image.new("RGBA", (width, height),(0,0,0,0)) image = ImageQt(im) - image1 = QtGui.QImage(image) - painter = QPainter(image1) + painter = QPainter(image) self.titleFont.setPixelSize(self.fontSize) painter.setFont(self.titleFont) painter.setPen(QColor(*self.textColor)) - - fm = QtGui.QFontMetrics(self.titleFont) painter.drawText(self.xPosition, self.yPosition, self.title) painter.end() buffer = QtCore.QBuffer() buffer.open(QtCore.QIODevice.ReadWrite) - image1.save(buffer, "PNG") + image.save(buffer, "PNG") strio = io.BytesIO() strio.write(buffer.data()) diff --git a/video_thread.py b/video_thread.py index c37741d..6972be4 100644 --- a/video_thread.py +++ b/video_thread.py @@ -71,7 +71,7 @@ class Worker(QtCore.QObject): if time.time() - self.lastPreview >= 0.05 or i[0] == 0: self._image = ImageQt(i[1]) self.imageCreated.emit(QtGui.QImage(self._image)) - lastPreview = time.time() + self.lastPreview = time.time() self.previewQueue.task_done() @@ -139,48 +139,50 @@ class Worker(QtCore.QObject): # create video for output numpy.seterr(divide='ignore') + # initialize components + print('loaded components:', + ["%s%s" % (num, str(component)) for num, component in enumerate(components)]) + self.staticComponents = {} + for compNo, comp in enumerate(components): + properties = None + properties = comp.preFrameRender( + worker=self, + completeAudioArray=self.completeAudioArray, + sampleSize=self.sampleSize + ) + + if properties and 'static' in properties: + self.staticComponents[compNo] = comp.frameRender(compNo, 0) + self.compositeQueue = Queue() self.compositeQueue.maxsize = 20 self.renderQueue = PriorityQueue() self.renderQueue.maxsize = 20 self.previewQueue = PriorityQueue() + # create threads to render frames and send them back here for piping out for i in range(2): - t = Thread(target=self.renderNode) + t = Thread(target=self.renderNode, name="Render Thread") t.daemon = True t.start() - self.dispatchThread = Thread(target=self.renderDispatch) + self.dispatchThread = Thread(target=self.renderDispatch, name="Render Dispatch Thread") self.dispatchThread.daemon = True self.dispatchThread.start() - self.previewDispatch = Thread(target=self.previewDispatch) + self.previewDispatch = Thread(target=self.previewDispatch, name="Render Dispatch Thread") self.previewDispatch.daemon = True self.previewDispatch.start() frameBuffer = {} self.lastPreview = 0.0 - # initialize components - print('loaded components:', - ["%s%s" % (num, str(component)) for num, component in enumerate(components)]) - self.staticComponents = {} - for compNo, comp in enumerate(components): - properties = None - properties = comp.preFrameRender( - worker=self, - completeAudioArray=self.completeAudioArray, - sampleSize=self.sampleSize - ) - - if properties and 'static' in properties: - self.staticComponents[compNo] = comp.frameRender(compNo, 0) - for i in range(0, len(self.completeAudioArray), self.sampleSize): - while True: if i in frameBuffer: + # if frame's in buffer, pipe it to ffmpeg break + # else fetch the next frame & add to the buffer data = self.renderQueue.get() frameBuffer[data[0]] = data[1] self.renderQueue.task_done() -- cgit v1.2.3 From 43073cbd429fe415be3009124bee26b12ec8d2de Mon Sep 17 00:00:00 2001 From: DH4 Date: Thu, 1 Jun 2017 09:52:40 -0500 Subject: Fixed spectrum rendering. Fixed multiple static renders. --- components/original.py | 52 ++++++++++++++++++++++++++------------------------ video_thread.py | 4 +++- 2 files changed, 30 insertions(+), 26 deletions(-) (limited to 'components') diff --git a/components/original.py b/components/original.py index 46e7182..045ffa0 100644 --- a/components/original.py +++ b/components/original.py @@ -4,6 +4,8 @@ from PyQt4 import uic, QtGui from PyQt4.QtGui import QColor import os, random from . import __base__ +import time +from copy import copy class Component(__base__.Component): @@ -52,9 +54,9 @@ class Component(__base__.Component): self.spectrumArray = {} for i in range(0, len(self.completeAudioArray), self.sampleSize): - spectrum = transformData(i, self.completeAudioArray, self.sampleSize, + self.lastSpectrum = self.transformData(i, self.completeAudioArray, self.sampleSize, self.smoothConstantDown, self.smoothConstantUp, self.lastSpectrum) - self.spectrumArray[i] = spectrum + self.spectrumArray[i] = copy(self.lastSpectrum) def frameRender(self, moduleNo, frameNo): width = int(self.worker.core.settings.value('outputWidth')) @@ -66,35 +68,35 @@ class Component(__base__.Component): self.page.lineEdit_visColor.setText(RGBstring) self.page.pushButton_visColor.setStyleSheet(btnStyle) -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) + def transformData(self, i, completeAudioArray, sampleSize, smoothConstantDown, smoothConstantUp, lastSpectrum): + if len(completeAudioArray) < (i + sampleSize): + sampleSize = len(completeAudioArray) - i - y = abs(spectrum[0:int(paddedSampleSize/2) - 1]) + 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) - # filter the noise away - # y[y<80] = 0 + y = abs(spectrum[0:int(paddedSampleSize/2) - 1]) - y = 20 * numpy.log10(y) - y[numpy.isinf(y)] = 0 + # filter the noise away + # y[y<80] = 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 + y = 20 * numpy.log10(y) + y[numpy.isinf(y)] = 0 - x = frequencies[0:int(paddedSampleSize/2) - 1] + 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 - return lastSpectrum + x = frequencies[0:int(paddedSampleSize/2) - 1] + + return lastSpectrum def drawBars(width, height, spectrum, color, layout): vH = height-height/8 diff --git a/video_thread.py b/video_thread.py index 6972be4..388093a 100644 --- a/video_thread.py +++ b/video_thread.py @@ -9,6 +9,7 @@ import sys from queue import Queue, PriorityQueue from threading import Thread import time +from copy import copy class Worker(QtCore.QObject): @@ -152,7 +153,8 @@ class Worker(QtCore.QObject): ) if properties and 'static' in properties: - self.staticComponents[compNo] = comp.frameRender(compNo, 0) + self.staticComponents[compNo] = copy(comp.frameRender(compNo, 0)) + print('done') self.compositeQueue = Queue() self.compositeQueue.maxsize = 20 -- cgit v1.2.3 From fcbe211bf1588d4d3740d5b8ec70aa45bbe8ea69 Mon Sep 17 00:00:00 2001 From: DH4 Date: Thu, 1 Jun 2017 11:01:51 -0500 Subject: Performance boost for static backgrounds. moved drawBars() inside class. --- components/original.py | 63 +++++++++++++++++++++++++------------------------- video_thread.py | 23 +++++++++--------- 2 files changed, 42 insertions(+), 44 deletions(-) (limited to 'components') diff --git a/components/original.py b/components/original.py index 045ffa0..9e7da30 100644 --- a/components/original.py +++ b/components/original.py @@ -44,7 +44,7 @@ class Component(__base__.Component): 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, self.visColor, self.layout) + return self.drawBars(width, height, spectrum, self.visColor, self.layout) def preFrameRender(self, **kwargs): super().preFrameRender(**kwargs) @@ -61,7 +61,7 @@ class Component(__base__.Component): def frameRender(self, moduleNo, frameNo): width = int(self.worker.core.settings.value('outputWidth')) height = int(self.worker.core.settings.value('outputHeight')) - return drawBars(width, height, self.spectrumArray[frameNo], self.visColor, self.layout) + return self.drawBars(width, height, self.spectrumArray[frameNo], self.visColor, self.layout) def pickColor(self): RGBstring, btnStyle = super().pickColor() @@ -97,42 +97,41 @@ class Component(__base__.Component): 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 + def drawBars(self, 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) - 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) + 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) + 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) - im.paste(imTop, (0, y), mask=imTop) - y = 0 + int(height/100*43) - im.paste(imBottom, (0, y), mask=imBottom) + 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 == 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) + if layout == 2: + y = 0 + int(height/100*10) + im.paste(imTop, (0, y), mask=imTop) - return im + return im diff --git a/video_thread.py b/video_thread.py index 388093a..dee254a 100644 --- a/video_thread.py +++ b/video_thread.py @@ -32,16 +32,10 @@ class Worker(QtCore.QObject): while True: i = self.compositeQueue.get() - frame = Image.new( - "RGBA", - (self.width, self.height), - (0, 0, 0, 255) - ) - if self.imBackground is not None: - frame.paste(self.imBackground) + frame = self.imBackground else: - frame.paste(self.getBackgroundAtIndex(i[1])) + frame = self.getBackgroundAtIndex(i[1]) for compNo, comp in enumerate(self.components): if compNo in self.staticComponents and self.staticComponents[compNo] != None: @@ -75,10 +69,16 @@ class Worker(QtCore.QObject): self.lastPreview = time.time() self.previewQueue.task_done() - def getBackgroundAtIndex(self, i): - return self.core.drawBaseImage(self.backgroundFrames[i]) + background = Image.new( + "RGBA", + (self.width, self.height), + (0, 0, 0, 255) + ) + layer = self.core.drawBaseImage(self.backgroundFrames[i]) + background.paste(layer) + return background @pyqtSlot(str, str, str, list) def createVideo(self, backgroundImage, inputFile, outputFile, components): @@ -154,7 +154,6 @@ class Worker(QtCore.QObject): if properties and 'static' in properties: self.staticComponents[compNo] = copy(comp.frameRender(compNo, 0)) - print('done') self.compositeQueue = Queue() self.compositeQueue.maxsize = 20 @@ -163,7 +162,7 @@ class Worker(QtCore.QObject): self.previewQueue = PriorityQueue() # create threads to render frames and send them back here for piping out - for i in range(2): + for i in range(3): t = Thread(target=self.renderNode, name="Render Thread") t.daemon = True t.start() -- cgit v1.2.3