Skip to content

Commit

Permalink
add basline vectorscope
Browse files Browse the repository at this point in the history
  • Loading branch information
huang0h committed Jun 11, 2022
1 parent e5124eb commit 830ed35
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 8 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
todo.txt
__pycache__
imgs
*.mp4
*.mp4
testaudio/
10 changes: 7 additions & 3 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# you might need to install these:
# pip install pydub
# pip install pygame
# pip install scipy
from pydub import AudioSegment
import pygame
from scipy import signal

import math
import sys
import numpy as np
import random

from star import Star
from nebula import Nebula
from oscilloscope import Oscilloscope
from vector import Vectorscope

# config vars - edit these to alter the visualizer
FILENAME = "audio/mightaswellbedead.wav"
FILENAME = "testaudio/sinetest.mp3"

WINDOW_SIZE = 400
HOP_SIZE = 100
Expand Down Expand Up @@ -99,7 +99,10 @@ def rand_color(base: int) -> pygame.Color:
RECORDING = False

oscope = Oscilloscope(screen, SCOPE_WIDTH, SCOPE_HEIGHT, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, MAX_AMP)
vscope = Vectorscope(screen, SCOPE_WIDTH, SCOPE_HEIGHT, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, MAX_AMP)

# visualizer still lags behind by small amounts - will investigate further
# current theory is that clock tick lags a bit while music plays uninterrupted
while total_elapsed * smp_per_second + WINDOW_SIZE < NUM_SAMPLES and RUNNING:
for event in pygame.event.get():
if event.type == pygame.QUIT:
Expand Down Expand Up @@ -173,6 +176,7 @@ def rand_color(base: int) -> pygame.Color:
neb.draw()

oscope.draw(window)
vscope.draw(left_win, right_win, 10)

pygame.display.flip()

Expand Down
38 changes: 34 additions & 4 deletions vector.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import pygame
import math
import numpy as np
import scipy
from scipy import signal

# vectorscope based off of Wave Candy's vectorscope
class Vectorscope:
def __init__(self, screen, width, height, x, y, max_amp):
self.screen = screen
Expand All @@ -13,9 +18,33 @@ def draw(self, left_samples, right_samples, resolution):
# x is determined by proportion of magnitude on left/right
# i.e. 100% of signal left = max on left axis
# y is determined by ??? - needs more experimentation
pass

def samples_to_hsla(samples: list) -> pygame.Color:
# split the left, right samples into indivudal windows, based on resolution, and get their averages
left_windows = np.split(np.array(left_samples), np.arange(resolution, len(left_samples), resolution))[:-1]
right_windows = np.split(np.array(right_samples), np.arange(resolution, len(right_samples), resolution))[:-1]

left_windows = list(map(lambda l: np.sum(l) / len(l), left_windows))
right_windows = list(map(lambda l: np.sum(l) / len(l), right_windows))

points = []
for left_avg, right_avg in zip(left_windows, right_windows):
l_x = self.x - (self.width / 2) * (left_avg / self.max_amp)
l_y = self.y - (self.height / 2) * (left_avg / self.max_amp)

r_x = self.x + (self.width / 2) * (right_avg / self.max_amp)
r_y = self.y - (self.height / 2) * (right_avg / self.max_amp)

l_prop = abs(left_avg / (abs(left_avg) + abs(right_avg)))
r_prop = abs(right_avg / (abs(left_avg) + abs(right_avg)))
points.append( ( l_x * l_prop + r_x * r_prop, l_y * l_prop + r_y * r_prop ) )

color = pygame.Color(255, 0, 0) #self.samples_to_hsla(list(map(lambda l, r: l + r / 2, left_samples, right_samples)))

for point in points:
pygame.draw.circle(self.screen, color, point, 5, 1)


def samples_to_hsla(self, samples: list) -> pygame.Color:
color: pygame.Color = pygame.Color(0, 0, 0)
window = signal.windows.blackmanharris(10000)

Expand All @@ -27,5 +56,6 @@ def samples_to_hsla(samples: list) -> pygame.Color:
return color

# formula adapted from https://en.wikipedia.org/wiki/Piano_key_frequencies
hue: int = math.ceil(41.9 * math.log(freq / 440, 2) + 171.11)
# saturation = rms(samples)
hue = math.ceil(41.9 * math.log(freq / 440, 2) + 171.11)
color.hsla = (hue, 100, 100, 100)
return color

0 comments on commit 830ed35

Please sign in to comment.