Skip to content

Instantly share code, notes, and snippets.

@dannguyen
Forked from ravenkls/visualise.py
Created November 3, 2019 21:23
Show Gist options
  • Save dannguyen/a43f9ef84f3a00b0ff0996fbf3a7d51b to your computer and use it in GitHub Desktop.
Save dannguyen/a43f9ef84f3a00b0ff0996fbf3a7d51b to your computer and use it in GitHub Desktop.

Revisions

  1. @ravenkls ravenkls revised this gist Apr 27, 2019. 1 changed file with 39 additions and 78 deletions.
    117 changes: 39 additions & 78 deletions visualise.py
    Original file line number Diff line number Diff line change
    @@ -1,115 +1,76 @@
    from pydub import AudioSegment
    from PyQt5 import QtCore, QtWidgets
    from PyQt5.QtMultimedia import *
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    from PyQt5 import QtCore
    import numpy as np
    import sys
    import time
    import math


    class Visualise(QtCore.QThread):
    class VisualiseFrequency(QtCore.QThread):

    def __init__(self, song, player):
    def __init__(self, song, canvas, player):
    super().__init__()
    self.canvas = canvas
    self.figure = self.canvas.figure
    self.player = player
    self.samples = song.get_array_of_samples()
    self.samples = np.array(song.get_array_of_samples())
    self.song = song

    def run(self):
    interval = 0.05

    fig = plt.figure()
    fig.patch.set_facecolor((0, 0, 0))
    ax1 = fig.add_subplot(1,1,1)
    self.figure.patch.set_facecolor((0, 0, 0))
    ax1 = self.figure.add_subplot(1,1,1)
    ax1.set_facecolor((0, 0, 0))


    bars_n = 30
    max_bar_height = 35
    frequency_range = 0.3
    interval = 0.05
    bars_n = 60

    frequency_range = 1

    bars = [0]*bars_n
    bars = np.zeros(bars_n)
    max_sample = self.samples.max()
    for timestamp in range(0, math.ceil(self.song.duration_seconds/interval)):
    start = time.time()


    timestamp *= interval
    sample_count = int(self.song.frame_rate * interval)
    start_index = int((self.player.position()/1000) * self.song.frame_rate)
    v_sample = self.samples[start_index:start_index+sample_count]

    zero_crossings = np.where(np.diff(np.sign(v_sample)))[0]
    data = []
    for i in range(len(zero_crossings)-1):
    x1 = zero_crossings[i]
    x2 = zero_crossings[i+1]
    diff = abs(x1 - x2)
    frequency = diff / len(v_sample)
    amp = max(max(v_sample[x1:x2]), abs(min(v_sample[x1:x2])))
    data.append((frequency, amp))

    fourier = np.fft.fft(v_sample)
    freq = np.fft.fftfreq(fourier.size, d=interval)
    amps = 2/v_sample.size * np.abs(fourier)
    data = np.array([freq, amps]).T

    bar_width_range = frequency_range / bars_n
    bars_samples = []
    bars_samples = np.array([])

    if not data:
    if not data.size:
    time.sleep(max(interval - time.time() + start, 0))
    continue

    for f in np.arange(0, frequency_range, bar_width_range):
    amps = [x[1] for x in data if f-bar_width_range<x[0]<f]
    if not amps:
    bars_samples.append(0)
    amps = np.array(data)
    amps = amps[(f-bar_width_range<amps[:,0]) & (amps[:,0]<f)]
    if not amps.size:
    bars_samples = np.append(bars_samples, 0)
    else:
    bars_samples.append(max(amps))
    bars_samples = np.append(bars_samples, amps.max())

    highest_amp = 18000
    step = highest_amp // max_bar_height
    if step:
    for n, amp in enumerate(bars_samples):
    if bars[n] > 0 and amp // step < bars[n]:
    bars[n] -= bars[n] / 3
    if bars[n] < 1:
    bars[n] = 0
    else:
    bars[n] = amp // step
    for n, amp in enumerate(bars_samples):
    if bars[n] > 0 and amp < bars[n]:
    bars[n] -= bars[n] / 3
    if bars[n] < 1:
    bars[n] = 0
    else:
    bars = [0]*bars

    bars[n] = 0
    else:
    bars[n] = amp
    if bars[n] < 1:
    bars[n] = 0
    ax1.clear()
    ax1.plot(range(len(bars)), bars, color='r')
    if ax1.lines:
    ax1.lines[0].set_data(range(len(bars)), bars)
    else:
    ax1.plot(range(len(bars)), bars, color='r')
    ax1.set_ylim(top=max_sample, bottom=0)
    ax1.fill_between(range(len(bars)), bars, color='#c60303')
    plt.ylim(top=70, bottom=0)
    plt.draw()
    self.canvas.draw()
    plt.pause(0.001)
    time.sleep(max(interval - time.time() + start, 0))


    class Window(QtWidgets.QWidget):

    def __init__(self):
    super().__init__()
    song = AudioSegment.from_mp3('song.mp3')
    song = song.set_channels(1)

    content = QMediaContent(QtCore.QUrl('song.mp3'))
    self.player = QMediaPlayer()

    self.vis = Visualise(song, self.player)

    self.player.setMedia(content)
    self.player.mediaStatusChanged.connect(self.start)

    def start(self):
    self.player.play()
    self.vis.start()
    plt.show()

    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.showMinimized()
    sys.exit(app.exec_())
  2. @ravenkls ravenkls created this gist Apr 26, 2019.
    115 changes: 115 additions & 0 deletions visualise.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,115 @@
    from pydub import AudioSegment
    from PyQt5 import QtCore, QtWidgets
    from PyQt5.QtMultimedia import *
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    import numpy as np
    import sys
    import time
    import math


    class Visualise(QtCore.QThread):

    def __init__(self, song, player):
    super().__init__()
    self.player = player
    self.samples = song.get_array_of_samples()
    self.song = song

    def run(self):
    interval = 0.05

    fig = plt.figure()
    fig.patch.set_facecolor((0, 0, 0))
    ax1 = fig.add_subplot(1,1,1)
    ax1.set_facecolor((0, 0, 0))


    bars_n = 30
    max_bar_height = 35
    frequency_range = 0.3

    bars = [0]*bars_n
    for timestamp in range(0, math.ceil(self.song.duration_seconds/interval)):
    start = time.time()


    timestamp *= interval
    sample_count = int(self.song.frame_rate * interval)
    start_index = int((self.player.position()/1000) * self.song.frame_rate)
    v_sample = self.samples[start_index:start_index+sample_count]

    zero_crossings = np.where(np.diff(np.sign(v_sample)))[0]
    data = []
    for i in range(len(zero_crossings)-1):
    x1 = zero_crossings[i]
    x2 = zero_crossings[i+1]
    diff = abs(x1 - x2)
    frequency = diff / len(v_sample)
    amp = max(max(v_sample[x1:x2]), abs(min(v_sample[x1:x2])))
    data.append((frequency, amp))


    bar_width_range = frequency_range / bars_n
    bars_samples = []

    if not data:
    time.sleep(max(interval - time.time() + start, 0))
    continue

    for f in np.arange(0, frequency_range, bar_width_range):
    amps = [x[1] for x in data if f-bar_width_range<x[0]<f]
    if not amps:
    bars_samples.append(0)
    else:
    bars_samples.append(max(amps))

    highest_amp = 18000
    step = highest_amp // max_bar_height
    if step:
    for n, amp in enumerate(bars_samples):
    if bars[n] > 0 and amp // step < bars[n]:
    bars[n] -= bars[n] / 3
    if bars[n] < 1:
    bars[n] = 0
    else:
    bars[n] = amp // step
    if bars[n] < 1:
    bars[n] = 0
    else:
    bars = [0]*bars

    ax1.clear()
    ax1.plot(range(len(bars)), bars, color='r')
    ax1.fill_between(range(len(bars)), bars, color='#c60303')
    plt.ylim(top=70, bottom=0)
    plt.draw()
    plt.pause(0.001)
    time.sleep(max(interval - time.time() + start, 0))


    class Window(QtWidgets.QWidget):

    def __init__(self):
    super().__init__()
    song = AudioSegment.from_mp3('song.mp3')
    song = song.set_channels(1)

    content = QMediaContent(QtCore.QUrl('song.mp3'))
    self.player = QMediaPlayer()

    self.vis = Visualise(song, self.player)

    self.player.setMedia(content)
    self.player.mediaStatusChanged.connect(self.start)

    def start(self):
    self.player.play()
    self.vis.start()
    plt.show()

    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.showMinimized()
    sys.exit(app.exec_())