text: import sys, io, os
  from PyQt4 import QtCore, QtGui, uic
  from PyQt4.QtGui import QPainter, QColor
  from os.path import expanduser
  import subprocess as sp
  import numpy
  from PIL import Image, ImageDraw, ImageFont
  from PIL.ImageQt import ImageQt
  
  class Core():
  
    def __init__(self):
      self.lastBackgroundImage = ""
      self._image = None
  
      self.FFMPEG_BIN = self.findFfmpeg()
  
    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 drawBaseImage(self, backgroundImage, titleText, titleFont):
  
      if self._image == None or not self.lastBackgroundImage == backgroundImage:
        self.lastBackgroundImage = backgroundImage
  
        if backgroundImage == "":
          im = Image.new("RGB", (1280, 720), "black")
        else:
          im = Image.open(backgroundImage)
  
        # resize if necessary
        if not im.size == (1280, 720):
          im = im.resize((1280, 720), Image.ANTIALIAS)
  
        self._image = ImageQt(im)
      
      self._image1 = QtGui.QImage(self._image)
      painter = QPainter(self._image1)
      font = titleFont
      font.setPointSizeF(35)
      painter.setFont(font)
      painter.setPen(QColor(255, 255, 255))
  
      painter.drawText(70, 375, 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):
  
      imTop = Image.new("RGBA", (1280, 360))
      draw = ImageDraw.Draw(imTop)
      for j in range(0, 63):
        draw.rectangle((10 + j * 20, 325, 10 + j * 20 + 20, 325 - spectrum[j * 4] * 1 - 10), fill=(255, 255, 255, 50))
        draw.rectangle((15 + j * 20, 320, 15 + j * 20 + 10, 320 - spectrum[j * 4] * 1), fill="white")
  
  
      imBottom = imTop.transpose(Image.FLIP_TOP_BOTTOM)
  
      im = Image.new("RGB", (1280, 720), "black")
  
      im.paste(image, (0, 0))
      im.paste(imTop, (0, 0), mask=imTop)
      im.paste(imBottom, (0, 360), mask=imBottom)
  
      return im
  
    def readAudioFile(self, filename):
      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")
  
      while True:
        # read 2 seconds of audio
        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)
        # print(audio_array)
  
      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
  
    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: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:paddedSampleSize/2 - 1]
  
      return lastSpectrum