Merge branch 'component-backgrounds' of github.com:IamDH4/audio-visualizer-python into feature-newgui

This commit is contained in:
DH4 2017-06-06 02:07:13 -05:00
commit 4920fcc034
16 changed files with 1094 additions and 245 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

BIN
background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -7,6 +7,13 @@ class Component:
def version(self):
# change this number to identify new versions of a component
return 1
def cancel(self):
# make sure your component responds to these variables in frameRender()
self.canceled = True
def reset(self):
self.canceled = False
def preFrameRender(self, **kwargs):
for var, value in kwargs.items():
@ -66,4 +73,10 @@ class Component:
def savePreset(self):
return {}
def cancel(self):
self.canceled = True
def reset(self):
self.canceled = False
'''

87
components/color.py Normal file
View File

@ -0,0 +1,87 @@
from PIL import Image, ImageDraw
from PyQt4 import uic, QtGui, QtCore
from PyQt4.QtGui import QColor
import os
from . import __base__
class Component(__base__.Component):
'''Color'''
def widget(self, parent):
self.parent = parent
page = uic.loadUi(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'color.ui'))
self.color1 = (0,0,0)
self.color2 = (133,133,133)
self.x = 0
self.y = 0
page.lineEdit_color1.setText('%s,%s,%s' % self.color1)
page.lineEdit_color2.setText('%s,%s,%s' % self.color2)
page.pushButton_color1.clicked.connect(lambda: self.pickColor(1))
btnStyle = "QPushButton { background-color : %s; outline: none; }" % QColor(*self.color1).name()
page.pushButton_color1.setStyleSheet(btnStyle)
page.pushButton_color2.clicked.connect(lambda: self.pickColor(2))
btnStyle = "QPushButton { background-color : %s; outline: none; }" % QColor(*self.color2).name()
page.pushButton_color2.setStyleSheet(btnStyle)
# disable color #2 until non-default 'fill' option gets changed
page.lineEdit_color2.setDisabled(True)
page.pushButton_color2.setDisabled(True)
page.spinBox_x.setValue(self.x)
page.spinBox_x.setValue(self.y)
page.lineEdit_color1.textChanged.connect(self.update)
page.lineEdit_color2.textChanged.connect(self.update)
page.spinBox_x.valueChanged.connect(self.update)
page.spinBox_y.valueChanged.connect(self.update)
self.page = page
return page
def update(self):
self.color1 = self.RGBFromString(self.page.lineEdit_color1.text())
self.color2 = self.RGBFromString(self.page.lineEdit_color2.text())
self.x = self.page.spinBox_x.value()
self.y = self.page.spinBox_y.value()
self.parent.drawPreview()
def previewRender(self, previewWorker):
width = int(previewWorker.core.settings.value('outputWidth'))
height = int(previewWorker.core.settings.value('outputHeight'))
return self.drawFrame(width, height)
def preFrameRender(self, **kwargs):
super().preFrameRender(**kwargs)
return ['static']
def frameRender(self, moduleNo, arrayNo, frameNo):
width = int(self.worker.core.settings.value('outputWidth'))
height = int(self.worker.core.settings.value('outputHeight'))
return self.drawFrame(width, height)
def drawFrame(self, width, height):
r,g,b = self.color1
return Image.new("RGBA", (width, height), (r, g, b, 255))
def loadPreset(self, pr):
self.page.lineEdit_color1.setText('%s,%s,%s' % pr['color1'])
self.page.lineEdit_color2.setText('%s,%s,%s' % pr['color2'])
btnStyle = "QPushButton { background-color : %s; outline: none; }" % QColor(*pr['color1']).name()
self.page.pushButton_color1.setStyleSheet(btnStyle)
btnStyle = "QPushButton { background-color : %s; outline: none; }" % QColor(*pr['color2']).name()
self.page.pushButton_color2.setStyleSheet(btnStyle)
def savePreset(self):
return {
'color1' : self.color1,
'color2' : self.color2,
}
def pickColor(self, num):
RGBstring, btnStyle = super().pickColor()
if not RGBstring:
return
if num == 1:
self.page.lineEdit_color1.setText(RGBstring)
self.page.pushButton_color1.setStyleSheet(btnStyle)
else:
self.page.lineEdit_color2.setText(RGBstring)
self.page.pushButton_color2.setStyleSheet(btnStyle)

306
components/color.ui Normal file
View File

@ -0,0 +1,306 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>586</width>
<height>197</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>4</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="label_textColor">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>31</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Color #1</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_color1">
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="MaximumSize" stdset="0">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_color1">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>1</width>
<height>0</height>
</size>
</property>
<property name="maxLength">
<number>12</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_textColor_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>31</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Color #2</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_color2">
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="MaximumSize" stdset="0">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_color2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>1</width>
<height>0</height>
</size>
</property>
<property name="maxLength">
<number>12</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="leftMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_textLayout">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Fill </string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_fill"/>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_xTitleAlign">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_x">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>999999999</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_yTitleAlign">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_y">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

64
components/image.py Normal file
View File

@ -0,0 +1,64 @@
from PIL import Image, ImageDraw
from PyQt4 import uic, QtGui, QtCore
import os
from . import __base__
class Component(__base__.Component):
'''Image'''
def widget(self, parent):
self.parent = parent
self.settings = parent.settings
page = uic.loadUi(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'image.ui'))
self.imagePath = ''
self.x = 0
self.y = 0
page.lineEdit_image.textChanged.connect(self.update)
page.pushButton_image.clicked.connect(self.pickImage)
self.page = page
return page
def update(self):
self.imagePath = self.page.lineEdit_image.text()
self.parent.drawPreview()
def previewRender(self, previewWorker):
width = int(previewWorker.core.settings.value('outputWidth'))
height = int(previewWorker.core.settings.value('outputHeight'))
return self.drawFrame(width, height)
def preFrameRender(self, **kwargs):
super().preFrameRender(**kwargs)
return ['static']
def frameRender(self, moduleNo, arrayNo, frameNo):
width = int(self.worker.core.settings.value('outputWidth'))
height = int(self.worker.core.settings.value('outputHeight'))
return self.drawFrame(width, height)
def drawFrame(self, width, height):
frame = Image.new("RGBA", (width, height), (0,0,0,0))
if self.imagePath and os.path.exists(self.imagePath):
image = Image.open(self.imagePath)
if image.size != (width, height):
image = image.resize((width, height), Image.ANTIALIAS)
frame.paste(image)
return frame
def loadPreset(self, pr):
self.page.lineEdit_image.setText(pr['image'])
def savePreset(self):
return {
'image' : self.imagePath,
}
def pickImage(self):
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~"))
filename = QtGui.QFileDialog.getOpenFileName(self.page,
"Choose Image", imgDir, "Image Files (*.jpg *.png)")
if filename:
self.settings.setValue("backgroundDir", os.path.dirname(filename))
self.page.lineEdit_image.setText(filename)
self.update()

197
components/image.ui Normal file
View File

@ -0,0 +1,197 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>586</width>
<height>197</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>4</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="label_textColor">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>31</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Image</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_image">
<property name="minimumSize">
<size>
<width>1</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_image">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>1</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
<property name="MaximumSize" stdset="0">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_xTitleAlign">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_x">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_yTitleAlign">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_y">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>999999999</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -58,6 +58,8 @@ class Component(__base__.Component):
self.smoothConstantUp = 0.8
self.lastSpectrum = None
self.spectrumArray = {}
self.width = int(self.worker.core.settings.value('outputWidth'))
self.height = int(self.worker.core.settings.value('outputHeight'))
for i in range(0, len(self.completeAudioArray), self.sampleSize):
if self.canceled:
@ -72,12 +74,9 @@ class Component(__base__.Component):
pStr = "Analyzing audio: "+ str(progress) +'%'
self.progressBarSetText.emit(pStr)
self.progressBarUpdate.emit(int(progress))
def frameRender(self, moduleNo, frameNo):
width = int(self.worker.core.settings.value('outputWidth'))
height = int(self.worker.core.settings.value('outputHeight'))
return self.drawBars(width, height, self.spectrumArray[frameNo], self.visColor, self.layout)
def frameRender(self, moduleNo, arrayNo, frameNo):
return self.drawBars(self.width, self.height, self.spectrumArray[arrayNo], self.visColor, self.layout)
def pickColor(self):
RGBstring, btnStyle = super().pickColor()
@ -154,12 +153,3 @@ class Component(__base__.Component):
return im
def cancel(self):
self.canceled = True
def reset(self):
self.canceled = False

View File

@ -18,7 +18,6 @@ class Component(__base__.Component):
self.parent = parent
self.textColor = (255,255,255)
self.title = 'Text'
self.titleFont = None
self.alignment = 1
self.fontSize = height / 13.5
self.xPosition = width / 2
@ -35,8 +34,6 @@ class Component(__base__.Component):
page.pushButton_textColor.setStyleSheet(btnStyle)
page.lineEdit_title.setText(self.title)
#if self.titleFont:
# page.fontComboBox_titleFont.setCurrentFont(QFont(self.titleFont))
page.comboBox_textAlign.setCurrentIndex(int(self.alignment))
page.spinBox_fontSize.setValue(int(self.fontSize))
page.spinBox_xTextAlign.setValue(int(self.xPosition))
@ -109,7 +106,7 @@ class Component(__base__.Component):
super().preFrameRender(**kwargs)
return ['static']
def frameRender(self, moduleNo, frameNo):
def frameRender(self, moduleNo, arrayNo, frameNo):
width = int(self.worker.core.settings.value('outputWidth'))
height = int(self.worker.core.settings.value('outputHeight'))
return self.addText(width, height)
@ -142,9 +139,3 @@ class Component(__base__.Component):
return
self.page.lineEdit_textColor.setText(RGBstring)
self.page.pushButton_textColor.setStyleSheet(btnStyle)
def cancel(self):
self.canceled = True
def reset(self):
self.canceled = False

141
components/video.py Normal file
View File

@ -0,0 +1,141 @@
from PIL import Image, ImageDraw
from PyQt4 import uic, QtGui, QtCore
import os, subprocess, threading
from queue import PriorityQueue
from . import __base__
class Video:
'''Video Component Frame-Fetcher'''
def __init__(self, ffmpeg, videoPath, width, height, frameRate, chunkSize, parent, loopVideo):
self.parent = parent
self.chunkSize = chunkSize
self.size = (width, height)
self.frameNo = -1
self.currentFrame = 'None'
if loopVideo:
self.loopValue = '-1'
else:
self.loopValue = '0'
self.command = [
ffmpeg,
'-thread_queue_size', '512',
'-r', frameRate,
'-stream_loop', self.loopValue,
'-i', videoPath,
'-f', 'image2pipe',
'-pix_fmt', 'rgba',
'-filter:v', 'scale='+str(width)+':'+str(height),
'-vcodec', 'rawvideo', '-',
]
self.frameBuffer = PriorityQueue()
self.frameBuffer.maxsize = int(frameRate)
self.finishedFrames = {}
self.thread = threading.Thread(target=self.fillBuffer, name=self.__doc__)
self.thread.daemon = True
self.thread.start()
def frame(self, num):
while True:
if num in self.finishedFrames:
image = self.finishedFrames.pop(num)
return Image.frombytes('RGBA', self.size, image)
i, image = self.frameBuffer.get()
self.finishedFrames[i] = image
self.frameBuffer.task_done()
def fillBuffer(self):
self.pipe = subprocess.Popen(self.command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8)
while True:
if self.parent.canceled:
break
self.frameNo += 1
# If we run out of frames, use the last good frame and loop.
if len(self.currentFrame) == 0:
self.frameBuffer.put((self.frameNo-1, self.lastFrame))
continue
self.currentFrame = self.pipe.stdout.read(self.chunkSize)
#print('creating frame #%s' % str(self.frameNo))
if len(self.currentFrame) != 0:
self.frameBuffer.put((self.frameNo, self.currentFrame))
self.lastFrame = self.currentFrame
class Component(__base__.Component):
'''Video'''
def widget(self, parent):
self.parent = parent
self.settings = parent.settings
page = uic.loadUi(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'video.ui'))
self.videoPath = ''
self.x = 0
self.y = 0
self.loopVideo = False
page.lineEdit_video.textChanged.connect(self.update)
page.pushButton_video.clicked.connect(self.pickVideo)
page.checkBox_loop.stateChanged.connect(self.update)
self.page = page
return page
def update(self):
self.videoPath = self.page.lineEdit_video.text()
self.loopVideo = self.page.checkBox_loop.isChecked()
self.parent.drawPreview()
def previewRender(self, previewWorker):
width = int(previewWorker.core.settings.value('outputWidth'))
height = int(previewWorker.core.settings.value('outputHeight'))
self.chunkSize = 4*width*height
return self.getPreviewFrame(width, height)
def preFrameRender(self, **kwargs):
super().preFrameRender(**kwargs)
width = int(self.worker.core.settings.value('outputWidth'))
height = int(self.worker.core.settings.value('outputHeight'))
self.chunkSize = 4*width*height
self.video = Video(self.parent.core.FFMPEG_BIN, self.videoPath,
width, height, self.settings.value("outputFrameRate"),
self.chunkSize, self.parent, self.loopVideo)
def frameRender(self, moduleNo, arrayNo, frameNo):
return self.video.frame(frameNo)
def loadPreset(self, pr):
self.page.lineEdit_video.setText(pr['video'])
def savePreset(self):
return {
'video' : self.videoPath,
}
def pickVideo(self):
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~"))
filename = QtGui.QFileDialog.getOpenFileName(self.page,
"Choose Video", imgDir, "Video Files (*.mp4 *.mov)")
if filename:
self.settings.setValue("backgroundDir", os.path.dirname(filename))
self.page.lineEdit_video.setText(filename)
self.update()
def getPreviewFrame(self, width, height):
command = [
self.parent.core.FFMPEG_BIN,
'-thread_queue_size', '512',
'-i', self.videoPath,
'-f', 'image2pipe',
'-pix_fmt', 'rgba',
'-filter:v', 'scale='+str(width)+':'+str(height),
'-vcodec', 'rawvideo', '-',
'-ss', '90',
'-vframes', '1',
]
pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8)
byteFrame = pipe.stdout.read(self.chunkSize)
image = Image.frombytes('RGBA', (width, height), byteFrame)
pipe.stdout.close()
pipe.kill()
return image

224
components/video.ui Normal file
View File

@ -0,0 +1,224 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>586</width>
<height>197</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>4</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="label_textColor">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>31</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Video</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_video">
<property name="minimumSize">
<size>
<width>1</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_video">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>1</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
<property name="MaximumSize" stdset="0">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_xTitleAlign">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_x_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_yTitleAlign">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_y">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>999999999</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QCheckBox" name="checkBox_loop">
<property name="text">
<string>Loop</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

62
core.py
View File

@ -13,11 +13,10 @@ from collections import OrderedDict
class Core():
def __init__(self):
self.lastBackgroundImage = ""
self._image = None
self.FFMPEG_BIN = self.findFfmpeg()
self.tempDir = None
self.tempDir = os.path.join(tempfile.gettempdir(), 'audio-visualizer-python-data')
if not os.path.exists(self.tempDir):
os.makedirs(self.tempDir)
atexit.register(self.deleteTempDir)
def findFfmpeg(self):
@ -31,31 +30,6 @@ class Core():
except:
return "avconv"
def parseBaseImage(self, backgroundImage, preview=False):
''' determines if the base image is a single frame or list of frames '''
if backgroundImage == "":
return ['']
else:
_, bgExt = os.path.splitext(backgroundImage)
if not bgExt == '.mp4':
return [backgroundImage]
else:
return self.getVideoFrames(backgroundImage, preview)
def drawBaseImage(self, backgroundFile):
if backgroundFile == '':
im = Image.new("RGB", (int(self.settings.value('outputWidth')), int(self.settings.value('outputHeight'))), "black")
else:
im = Image.open(backgroundFile)
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)
return im
def readAudioFile(self, filename, parent):
command = [ self.FFMPEG_BIN,
'-i', filename]
@ -121,30 +95,10 @@ class Core():
return completeAudioArray
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
self.deleteTempDir()
os.mkdir(self.tempDir)
if firstOnly:
filename = 'preview%s.jpg' % os.path.basename(videoPath).split('.', 1)[0]
options = '-ss 10 -vframes 1'
else:
filename = '$frame%05d.jpg'
options = ''
sp.call( \
'%s -i "%s" -y %s "%s"' % ( \
self.FFMPEG_BIN,
videoPath,
options,
os.path.join(self.tempDir, filename)
),
shell=True
)
return sorted([os.path.join(self.tempDir, f) for f in os.listdir(self.tempDir)])
try:
rmtree(self.tempDir)
except FileNotFoundError:
pass
def cancel(self):
self.canceled = True
@ -153,6 +107,6 @@ class Core():
self.canceled = False
@staticmethod
def sortedStringDict(dictionary):
def stringOrderedDict(dictionary):
sorted_ = OrderedDict(sorted(dictionary.items(), key=lambda t: t[0]))
return repr(sorted_)

67
main.py
View File

@ -1,4 +1,4 @@
import sys, io, os, shutil, atexit, string, signal, filecmp
import sys, io, os, shutil, atexit, string, signal, filecmp, time
from os.path import expanduser
from queue import Queue
from importlib import import_module
@ -133,9 +133,9 @@ class PreviewWindow(QtGui.QLabel):
class Main(QtCore.QObject):
newTask = QtCore.pyqtSignal(str, list)
newTask = QtCore.pyqtSignal(list)
processTask = QtCore.pyqtSignal()
videoTask = QtCore.pyqtSignal(str, str, str, list)
videoTask = QtCore.pyqtSignal(str, str, list)
def __init__(self, window):
QtCore.QObject.__init__(self)
@ -145,6 +145,7 @@ class Main(QtCore.QObject):
self.core = core.Core()
self.pages = []
self.selectedComponents = []
self.lastAutosave = time.time()
# create data directory, load/create settings
self.dataDir = QDesktopServices.storageLocation(QDesktopServices.DataLocation)
@ -172,14 +173,13 @@ class Main(QtCore.QObject):
# 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.pushButton_Cancel.clicked.connect(self.stopVideo)
window.setWindowTitle("Audio Visualizer")
self.previewWindow = PreviewWindow(self, os.path.join(os.path.dirname(os.path.realpath(__file__)), "background.jpg"))
self.previewWindow = PreviewWindow(self, os.path.join(os.path.dirname(os.path.realpath(__file__)), "background.png"))
window.verticalLayout_previewWrapper.addWidget(self.previewWindow)
self.modules = self.findComponents()
@ -236,15 +236,17 @@ class Main(QtCore.QObject):
self.autosave()
def autosave(self):
if os.path.exists(self.autosavePath):
os.remove(self.autosavePath)
self.createProjectFile(self.autosavePath)
if time.time() - self.lastAutosave >= 1.0:
if os.path.exists(self.autosavePath):
os.remove(self.autosavePath)
self.createProjectFile(self.autosavePath)
self.lastAutosave = time.time()
def openInputFileDialog(self):
inputDir = self.settings.value("inputDir", expanduser("~"))
fileName = QtGui.QFileDialog.getOpenFileName(self.window,
"Open Music File", inputDir, "Music Files (*.mp3 *.wav *.ogg *.flac)");
"Open Music File", inputDir, "Music Files (*.mp3 *.wav *.ogg *.fla *.aac)");
if not fileName == "":
self.settings.setValue("inputDir", os.path.dirname(fileName))
@ -254,23 +256,12 @@ class Main(QtCore.QObject):
outputDir = self.settings.value("outputDir", expanduser("~"))
fileName = QtGui.QFileDialog.getSaveFileName(self.window,
"Set Output Video File", outputDir, "Video Files (*.mkv)");
"Set Output Video File", outputDir, "Video Files (*.mp4 *.mov *.mkv *.avi *.webm *.flv)");
if not fileName == "":
self.settings.setValue("outputDir", os.path.dirname(fileName))
self.window.lineEdit_outputFile.setText(fileName)
def openBackgroundFileDialog(self):
backgroundDir = self.settings.value("backgroundDir", expanduser("~"))
fileName = QtGui.QFileDialog.getOpenFileName(self.window,
"Open Background Image", backgroundDir, "Image Files (*.jpg *.png);; Video Files (*.mp4)");
if not fileName == "":
self.settings.setValue("backgroundDir", os.path.dirname(fileName))
self.window.lineEdit_background.setText(fileName)
self.drawPreview()
def stopVideo(self):
print('stop')
self.videoWorker.cancel()
@ -291,8 +282,7 @@ class Main(QtCore.QObject):
self.videoWorker.imageCreated.connect(self.showPreviewImage)
self.videoWorker.encoding.connect(self.changeEncodingStatus)
self.videoThread.start()
self.videoTask.emit(self.window.lineEdit_background.text(),
self.window.lineEdit_audioFile.text(),
self.videoTask.emit(self.window.lineEdit_audioFile.text(),
self.window.lineEdit_outputFile.text(),
self.selectedComponents)
else:
@ -323,10 +313,6 @@ class Main(QtCore.QObject):
self.window.pushButton_savePreset.setEnabled(False)
self.window.pushButton_openProject.setEnabled(False)
self.window.listWidget_componentList.setEnabled(False)
self.window.label_background.setEnabled(False)
self.window.lineEdit_background.setEnabled(False)
self.window.toolButton_selectBackground.setEnabled(False)
else:
self.window.pushButton_createVideo.setEnabled(True)
self.window.pushButton_Cancel.setEnabled(False)
@ -349,12 +335,6 @@ class Main(QtCore.QObject):
self.window.pushButton_openProject.setEnabled(True)
self.window.listWidget_componentList.setEnabled(True)
self.window.label_background.setEnabled(True)
self.window.lineEdit_background.setEnabled(True)
self.window.toolButton_selectBackground.setEnabled(True)
def progressBarSetText(self, value):
self.window.progressBar_createVideo.setFormat(value)
@ -370,7 +350,7 @@ class Main(QtCore.QObject):
self.drawPreview()
def drawPreview(self):
self.newTask.emit(self.window.lineEdit_background.text(), self.selectedComponents)
self.newTask.emit(self.selectedComponents)
# self.processTask.emit()
self.autosave()
@ -381,7 +361,7 @@ class Main(QtCore.QObject):
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):
for f in sorted(os.listdir(srcPath)):
name, ext = os.path.splitext(f)
if name.startswith("__"):
continue
@ -446,7 +426,7 @@ class Main(QtCore.QObject):
def moveComponentDown(self):
row = self.window.listWidget_componentList.currentRow()
if row < len(self.pages) + 1:
if row != -1 and row < len(self.pages)+1:
module = self.selectedComponents[row]
self.selectedComponents.pop(row)
self.selectedComponents.insert(row + 1,module)
@ -507,7 +487,7 @@ class Main(QtCore.QObject):
if self.window.comboBox_openPreset.itemText(i) == filename:
self.window.comboBox_openPreset.removeItem(i)
with open(filepath, 'w') as f:
f.write(core.Core.sortedStringDict(saveValueStore))
f.write(core.Core.stringOrderedDict(saveValueStore))
self.window.comboBox_openPreset.addItem(filename)
self.window.comboBox_openPreset.setCurrentIndex(self.window.comboBox_openPreset.count()-1)
@ -550,12 +530,13 @@ class Main(QtCore.QObject):
if not filepath.endswith(".avp"):
filepath += '.avp'
with open(filepath, 'w') as f:
print('creating %s' % filepath)
f.write('[Components]\n')
for comp in self.selectedComponents:
saveValueStore = comp.savePreset()
f.write('%s\n' % str(comp))
f.write('%s\n' % str(comp.version()))
f.write('%s\n' % core.Core.sortedStringDict(saveValueStore))
f.write('%s\n' % core.Core.stringOrderedDict(saveValueStore))
if filepath != self.autosavePath:
self.settings.setValue("projectDir", os.path.dirname(filepath))
self.settings.setValue("currentProject", filepath)
@ -604,14 +585,18 @@ class Main(QtCore.QObject):
saveValueStore = dict(eval(line))
self.selectedComponents[-1].loadPreset(saveValueStore)
i = 0
except:
except (IndexError, ValueError, KeyError, NameError, SyntaxError, AttributeError, TypeError) as e:
self.clear()
self.showMessage("Project file '%s' is corrupted." % filepath)
typ, value, _ = sys.exc_info()
msg = '%s: %s' % (typ.__name__, value)
self.showMessage("Project file '%s' is corrupted." % filepath, False,
QtGui.QMessageBox.Warning, msg)
def showMessage(self, string, showCancel=False, icon=QtGui.QMessageBox.Information):
def showMessage(self, string, showCancel=False, icon=QtGui.QMessageBox.Information, detail=None):
msg = QtGui.QMessageBox()
msg.setIcon(icon)
msg.setText(string)
msg.setDetailedText(detail)
if showCancel:
msg.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
else:

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>1008</width>
<height>575</height>
<width>1028</width>
<height>592</height>
</rect>
</property>
<property name="sizePolicy">
@ -421,73 +421,6 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_background">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>85</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Background</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_background">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>28</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButton_selectBackground">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>28</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
@ -621,7 +554,6 @@
</layout>
<zorder></zorder>
<zorder></zorder>
<zorder></zorder>
</widget>
<widget class="QWidget" name="tab_encoderSettings">
<attribute name="title">

View File

@ -22,10 +22,9 @@ class Worker(QtCore.QObject):
@pyqtSlot(str, list)
def createPreviewImage(self, backgroundImage, components):
def createPreviewImage(self, components):
# print('worker thread id: {}'.format(QtCore.QThread.currentThreadId()))
dic = {
"backgroundImage": backgroundImage,
"components": components,
}
self.queue.put(dic)
@ -40,25 +39,14 @@ class Worker(QtCore.QObject):
except Empty:
continue
bgImage = self.core.parseBaseImage(\
nextPreviewInformation["backgroundImage"],
preview=True
)
if bgImage == []:
bgImage = ''
else:
bgImage = bgImage[0]
im = self.core.drawBaseImage(bgImage)
width = int(self.core.settings.value('outputWidth'))
height = int(self.core.settings.value('outputHeight'))
frame = Image.new("RGBA", (width, height),(0,0,0,255))
frame.paste(im)
frame = Image.new("RGBA", (width, height),(0,0,0,0))
components = nextPreviewInformation["components"]
for component in reversed(components):
newFrame = Image.alpha_composite(frame,component.previewRender(self))
frame = Image.alpha_composite(frame,newFrame)
#newFrame = Image.alpha_composite(frame,)
frame = Image.alpha_composite(frame,component.previewRender(self))
self._image = ImageQt(frame)
self.imageCreated.emit(QtGui.QImage(self._image))

View File

@ -37,19 +37,19 @@ class Worker(QtCore.QObject):
def renderNode(self):
while not self.stopped:
i = self.compositeQueue.get()
if self.imBackground is not None:
frame = self.imBackground
else:
frame = self.getBackgroundAtIndex(i[1])
frame = None
for compNo, comp in reversed(list(enumerate(self.components))):
if compNo in self.staticComponents and self.staticComponents[compNo] != None:
frame = Image.alpha_composite(frame, self.staticComponents[compNo])
if frame is None:
frame = self.staticComponents[compNo]
else:
frame = Image.alpha_composite(frame, self.staticComponents[compNo])
else:
frame = Image.alpha_composite(frame, comp.frameRender(compNo, i[0]))
# frame.paste(compFrame, mask=compFrame)
if frame is None:
frame = comp.frameRender(compNo, i[0], i[1])
else:
frame = Image.alpha_composite(frame, comp.frameRender(compNo, i[0], i[1]))
self.renderQueue.put([i[0], frame])
self.compositeQueue.task_done()
@ -59,10 +59,8 @@ class Worker(QtCore.QObject):
for i in range(0, len(self.completeAudioArray), self.sampleSize):
self.compositeQueue.put([i, self.bgI])
if not self.imBackground:
# increment background video frame for next iteration
if self.bgI < len(self.backgroundFrames)-1:
self.bgI += 1
# increment tracked video frame for next iteration
self.bgI += 1
def previewDispatch(self):
while not self.stopped:
@ -74,39 +72,18 @@ class Worker(QtCore.QObject):
self.previewQueue.task_done()
def getBackgroundAtIndex(self, 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):
@pyqtSlot(str, str, list)
def createVideo(self, inputFile, outputFile, components):
self.encoding.emit(True)
self.components = components
self.outputFile = outputFile
self.bgI = 0 # tracked video frame
self.reset()
self.width = int(self.core.settings.value('outputWidth'))
self.height = int(self.core.settings.value('outputHeight'))
# print('worker thread id: {}'.format(QtCore.QThread.currentThreadId()))
progressBarValue = 0
self.progressBarUpdate.emit(progressBarValue)
self.progressBarSetText.emit('Loading background image…')
self.backgroundImage = backgroundImage
self.backgroundFrames = self.core.parseBaseImage(backgroundImage)
if len(self.backgroundFrames) < 2:
# the base image is not a video so we can draw it now
self.imBackground = self.getBackgroundAtIndex(0)
else:
# base images will be drawn while drawing the audio bars
self.imBackground = None
self.bgI = 0
self.progressBarSetText.emit('Loading audio file...')
self.completeAudioArray = self.core.readAudioFile(inputFile, self)
@ -120,6 +97,7 @@ class Worker(QtCore.QObject):
ffmpegCommand = [
self.core.FFMPEG_BIN,
'-thread_queue_size', '512',
'-y', # (optional) means overwrite the output file if it already exists.
'-f', 'rawvideo',
'-vcodec', 'rawvideo',
@ -165,7 +143,7 @@ class Worker(QtCore.QObject):
)
if properties and 'static' in properties:
self.staticComponents[compNo] = copy(comp.frameRender(compNo, 0))
self.staticComponents[compNo] = copy(comp.frameRender(compNo, 0, 0))
self.progressBarUpdate.emit(100)
self.compositeQueue = Queue()
@ -250,7 +228,6 @@ class Worker(QtCore.QObject):
self.error = False
self.canceled = False
self.parent.drawPreview()
self.core.deleteTempDir()
self.stopped = True
self.encoding.emit(False)
self.videoCreated.emit()