2017-06-06 11:14:39 -04:00
|
|
|
import sys
|
|
|
|
import io
|
|
|
|
import os
|
2015-03-02 16:47:52 -05:00
|
|
|
from PyQt4 import QtCore, QtGui, uic
|
|
|
|
from os.path import expanduser
|
|
|
|
import subprocess as sp
|
|
|
|
import numpy
|
2017-05-28 14:19:28 -04:00
|
|
|
from PIL import Image
|
2017-06-08 16:50:48 -04:00
|
|
|
#import tempfile
|
2017-05-18 19:14:27 -04:00
|
|
|
from shutil import rmtree
|
2017-06-08 16:50:48 -04:00
|
|
|
#import atexit
|
2017-06-02 01:30:44 -04:00
|
|
|
import time
|
2017-06-03 15:24:52 -04:00
|
|
|
from collections import OrderedDict
|
2017-06-07 12:59:59 -04:00
|
|
|
import json
|
2017-06-08 09:56:57 -04:00
|
|
|
from importlib import import_module
|
2017-06-08 16:50:48 -04:00
|
|
|
from PyQt4.QtGui import QDesktopServices
|
2017-06-08 20:32:25 -04:00
|
|
|
import string
|
2015-03-02 16:47:52 -05:00
|
|
|
|
2017-06-06 11:14:39 -04:00
|
|
|
|
2015-03-02 16:47:52 -05:00
|
|
|
class Core():
|
|
|
|
|
2017-06-06 11:14:39 -04:00
|
|
|
def __init__(self):
|
|
|
|
self.FFMPEG_BIN = self.findFfmpeg()
|
2017-06-08 16:50:48 -04:00
|
|
|
#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)
|
|
|
|
self.dataDir = QDesktopServices.storageLocation(
|
|
|
|
QDesktopServices.DataLocation)
|
|
|
|
self.presetDir = os.path.join(self.dataDir, 'presets')
|
2017-06-07 12:59:59 -04:00
|
|
|
self.wd = os.path.dirname(os.path.realpath(__file__))
|
|
|
|
self.loadEncoderOptions()
|
|
|
|
|
2017-06-08 09:56:57 -04:00
|
|
|
self.modules = self.findComponents()
|
|
|
|
self.selectedComponents = []
|
2017-06-08 16:50:48 -04:00
|
|
|
self.selectedModules = []
|
2017-06-08 09:56:57 -04:00
|
|
|
|
|
|
|
def findComponents(self):
|
|
|
|
def findComponents():
|
|
|
|
srcPath = os.path.join(self.wd, 'components')
|
|
|
|
if os.path.exists(srcPath):
|
|
|
|
for f in sorted(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 insertComponent(self, compPos, moduleIndex):
|
2017-06-08 16:50:48 -04:00
|
|
|
if compPos < 0:
|
|
|
|
compPos = len(self.selectedComponents) -1
|
2017-06-08 09:56:57 -04:00
|
|
|
self.selectedComponents.insert(
|
|
|
|
compPos,
|
2017-06-08 16:50:48 -04:00
|
|
|
self.modules[moduleIndex].Component()
|
|
|
|
)
|
|
|
|
self.selectedModules.insert(
|
|
|
|
compPos,
|
|
|
|
moduleIndex
|
|
|
|
)
|
|
|
|
return compPos
|
2017-06-08 09:56:57 -04:00
|
|
|
|
|
|
|
def moveComponent(self, startI, endI):
|
|
|
|
comp = self.selectedComponents.pop(startI)
|
2017-06-08 16:50:48 -04:00
|
|
|
self.selectedComponents.insert(endI, comp)
|
|
|
|
i = self.selectedModules.pop(startI)
|
|
|
|
self.selectedModules.insert(endI, i)
|
|
|
|
return endI
|
2017-06-08 09:56:57 -04:00
|
|
|
|
|
|
|
def updateComponent(self, i):
|
2017-06-08 16:50:48 -04:00
|
|
|
print('updating %s' % self.selectedComponents[i])
|
2017-06-08 09:56:57 -04:00
|
|
|
self.selectedComponents[i].update()
|
|
|
|
|
2017-06-08 16:50:48 -04:00
|
|
|
def moduleIndexFor(self, compIndex):
|
|
|
|
return self.selectedModules[compIndex]
|
|
|
|
|
|
|
|
def createPresetFile(self, compName, vers, saveValueStore, filename):
|
|
|
|
dirname = os.path.join(self.presetDir, compName, str(vers))
|
|
|
|
if not os.path.exists(dirname):
|
|
|
|
os.makedirs(dirname)
|
|
|
|
filepath = os.path.join(dirname, filename)
|
|
|
|
with open(filepath, 'w') as f:
|
|
|
|
f.write(Core.stringOrderedDict(saveValueStore))
|
|
|
|
|
2017-06-07 12:59:59 -04:00
|
|
|
def loadEncoderOptions(self):
|
|
|
|
file_path = os.path.join(self.wd, 'encoder-options.json')
|
|
|
|
with open(file_path) as json_file:
|
|
|
|
self.encoder_options = json.load(json_file)
|
2017-06-06 11:14:39 -04:00
|
|
|
|
|
|
|
def findFfmpeg(self):
|
|
|
|
if sys.platform == "win32":
|
|
|
|
return "ffmpeg.exe"
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
with open(os.devnull, "w") as f:
|
|
|
|
sp.check_call(['ffmpeg', '-version'], stdout=f, stderr=f)
|
|
|
|
return "ffmpeg"
|
|
|
|
except:
|
|
|
|
return "avconv"
|
|
|
|
|
|
|
|
def readAudioFile(self, filename, parent):
|
|
|
|
command = [self.FFMPEG_BIN, '-i', filename]
|
|
|
|
|
|
|
|
try:
|
|
|
|
fileInfo = sp.check_output(command, stderr=sp.STDOUT, shell=False)
|
|
|
|
except sp.CalledProcessError as ex:
|
|
|
|
fileInfo = ex.output
|
|
|
|
pass
|
|
|
|
|
|
|
|
info = fileInfo.decode("utf-8").split('\n')
|
|
|
|
for line in info:
|
|
|
|
if 'Duration' in line:
|
|
|
|
d = line.split(',')[0]
|
|
|
|
d = d.split(' ')[3]
|
|
|
|
d = d.split(':')
|
|
|
|
duration = float(d[0])*3600 + float(d[1])*60 + float(d[2])
|
|
|
|
|
|
|
|
command = [
|
|
|
|
self.FFMPEG_BIN,
|
|
|
|
'-i', filename,
|
|
|
|
'-f', 's16le',
|
|
|
|
'-acodec', 'pcm_s16le',
|
|
|
|
'-ar', '44100', # ouput will have 44100 Hz
|
|
|
|
'-ac', '1', # mono (set to '2' for stereo)
|
|
|
|
'-']
|
|
|
|
in_pipe = sp.Popen(
|
|
|
|
command, stdout=sp.PIPE, stderr=sp.DEVNULL, bufsize=10**8)
|
|
|
|
|
|
|
|
completeAudioArray = numpy.empty(0, dtype="int16")
|
|
|
|
|
|
|
|
progress = 0
|
|
|
|
lastPercent = None
|
|
|
|
while True:
|
|
|
|
if self.canceled:
|
|
|
|
break
|
|
|
|
# read 2 seconds of audio
|
|
|
|
progress = progress + 4
|
|
|
|
raw_audio = in_pipe.stdout.read(88200*4)
|
|
|
|
if len(raw_audio) == 0:
|
|
|
|
break
|
|
|
|
audio_array = numpy.fromstring(raw_audio, dtype="int16")
|
|
|
|
completeAudioArray = numpy.append(completeAudioArray, audio_array)
|
|
|
|
|
|
|
|
percent = int(100*(progress/duration))
|
|
|
|
if percent >= 100:
|
|
|
|
percent = 100
|
|
|
|
|
|
|
|
if lastPercent != percent:
|
|
|
|
string = 'Loading audio file: '+str(percent)+'%'
|
|
|
|
parent.progressBarSetText.emit(string)
|
|
|
|
parent.progressBarUpdate.emit(percent)
|
|
|
|
|
|
|
|
lastPercent = percent
|
|
|
|
|
|
|
|
in_pipe.kill()
|
|
|
|
in_pipe.wait()
|
|
|
|
|
|
|
|
# add 0s the end
|
|
|
|
completeAudioArrayCopy = numpy.zeros(
|
|
|
|
len(completeAudioArray) + 44100, dtype="int16")
|
|
|
|
completeAudioArrayCopy[:len(completeAudioArray)] = completeAudioArray
|
|
|
|
completeAudioArray = completeAudioArrayCopy
|
|
|
|
|
|
|
|
return completeAudioArray
|
|
|
|
|
2017-06-08 16:50:48 -04:00
|
|
|
#def deleteTempDir(self):
|
|
|
|
# try:
|
|
|
|
# rmtree(self.tempDir)
|
|
|
|
# except FileNotFoundError:
|
|
|
|
# pass
|
2017-06-06 11:14:39 -04:00
|
|
|
|
|
|
|
def cancel(self):
|
|
|
|
self.canceled = True
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
self.canceled = False
|
|
|
|
|
2017-06-08 20:32:25 -04:00
|
|
|
@staticmethod
|
|
|
|
def badName(name):
|
|
|
|
'''Returns whether a name contains non-alphanumeric chars'''
|
|
|
|
badName = False
|
|
|
|
for letter in name:
|
|
|
|
if letter in string.punctuation:
|
|
|
|
badName = True
|
|
|
|
return badName
|
|
|
|
|
2017-06-06 11:14:39 -04:00
|
|
|
@staticmethod
|
|
|
|
def stringOrderedDict(dictionary):
|
|
|
|
sorted_ = OrderedDict(sorted(dictionary.items(), key=lambda t: t[0]))
|
|
|
|
return repr(sorted_)
|