play tests improvements #2
This commit is contained in:
parent
2c7a3f61e4
commit
345c06611b
9 changed files with 303 additions and 60 deletions
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
@ -11,7 +11,7 @@
|
|||
"program": "beamshow.py",
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": true,
|
||||
"args": ["-w","-b","-a","Notepad"]
|
||||
"args": ["-w","-b","-a","Notepad", "--fps"]
|
||||
}
|
||||
]
|
||||
}
|
14
beamshow.py
14
beamshow.py
|
@ -7,7 +7,7 @@ import sys
|
|||
from effects.effect import Effect
|
||||
from effects.presets import Presets
|
||||
from util.color import Colors
|
||||
from util.audio import AudioProcess
|
||||
from util.audio import AudioProcess, find_all_inputs
|
||||
|
||||
|
||||
def print_displays() -> None:
|
||||
|
@ -18,6 +18,12 @@ def print_displays() -> None:
|
|||
sys.exit(0)
|
||||
|
||||
|
||||
def print_inputs() -> None:
|
||||
devs = find_all_inputs()
|
||||
print("\n".join((x["name"] for x in devs)))
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
class Beamshow:
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -313,6 +319,9 @@ def app_main() -> None:
|
|||
argparser.add_argument(
|
||||
"--list-displays", action="store_true", help="Show available displays"
|
||||
)
|
||||
argparser.add_argument(
|
||||
"--list-inputs", action="store_true", help="Show available audio inputs"
|
||||
)
|
||||
argparser.add_argument(
|
||||
"-w", "--window", action="store_true", help="Display in a window"
|
||||
)
|
||||
|
@ -348,6 +357,9 @@ def app_main() -> None:
|
|||
if args.list_displays:
|
||||
print_displays()
|
||||
|
||||
if args.list_displays:
|
||||
print_inputs()
|
||||
|
||||
show = Beamshow(
|
||||
audio_device_name=args.audio,
|
||||
render3d=args.render3d,
|
||||
|
|
|
@ -31,22 +31,15 @@ class MovingEffect(Effect):
|
|||
|
||||
"""
|
||||
|
||||
ring chase two colors
|
||||
|
||||
square
|
||||
|
||||
square two color
|
||||
|
||||
line scan vh
|
||||
|
||||
starfield spawn chance
|
||||
|
||||
rainbow circle rotate
|
||||
|
||||
spot row
|
||||
|
||||
alles größer
|
||||
|
||||
fix double spot 4 spots
|
||||
|
||||
"""
|
||||
|
|
|
@ -3,9 +3,11 @@ import pygame as pg
|
|||
from typing import Iterator, List
|
||||
|
||||
from random import choice, randint, randrange
|
||||
from effects.chase_circle import ChaseCircle
|
||||
|
||||
from effects.effect import Effect
|
||||
from effects.line import Lines
|
||||
from effects.rectangle import Rectangle
|
||||
from util.color import (
|
||||
color_darken,
|
||||
color_randomize,
|
||||
|
@ -38,9 +40,10 @@ class Presets:
|
|||
def __init__(self, bounds: pg.Rect, beat_reactive: bool = False) -> None:
|
||||
self.bounds = bounds
|
||||
self.beat_reactive = beat_reactive
|
||||
self.shuffles = list(iter(self)) * 2
|
||||
|
||||
def default(self) -> List[Effect]:
|
||||
return self.StrobeLine()
|
||||
return self.Rectangle()
|
||||
|
||||
def __getitem__(self, idx: str) -> List[Effect]:
|
||||
return getattr(self, idx)()
|
||||
|
@ -52,18 +55,24 @@ class Presets:
|
|||
return (
|
||||
func
|
||||
for func in dir(self)
|
||||
if callable(getattr(self, func)) and not func.startswith("__")
|
||||
if callable(getattr(self, func))
|
||||
and not (func.startswith("__") or func == "randomize")
|
||||
)
|
||||
|
||||
def randomize(self) -> str:
|
||||
return choice(
|
||||
[
|
||||
func
|
||||
for func in dir(self)
|
||||
if callable(getattr(self, func))
|
||||
and not (func.startswith("__") or func == "randomize")
|
||||
]
|
||||
)
|
||||
selected = choice(self.shuffles)
|
||||
self.shuffles.remove(selected)
|
||||
if not self.shuffles:
|
||||
self.shuffles = list(iter(self)) * 2
|
||||
return selected
|
||||
# return choice(
|
||||
# [
|
||||
# func
|
||||
# for func in dir(self)
|
||||
# if callable(getattr(self, func))
|
||||
# and not (func.startswith("__") or func == "randomize")
|
||||
# ]
|
||||
# )
|
||||
|
||||
def DoubleSpotRandomColor(self) -> List[Effect]:
|
||||
return [
|
||||
|
@ -358,28 +367,28 @@ class Presets:
|
|||
mover=transform_bounce(
|
||||
bounds=self.bounds,
|
||||
velocity=(0.5, 1),
|
||||
x_factor=(3, 3),
|
||||
x_factor=(2, 2),
|
||||
y_factor=(0.5, 1),
|
||||
),
|
||||
)
|
||||
]
|
||||
|
||||
def FallingLine(self) -> List[Effect]:
|
||||
bounds = pg.rect.Rect(0, 0, self.bounds.width, 30)
|
||||
return [
|
||||
Lines(
|
||||
bounds=bounds,
|
||||
vectors=(((0, 15), (self.bounds.width, 15), color_wheel()),),
|
||||
thickness=30,
|
||||
mover=transform_falling(
|
||||
bounds,
|
||||
acceleration=0.8,
|
||||
initial_pos=(0, 0),
|
||||
initial_velocity=0.01,
|
||||
on_beat_reset=True,
|
||||
),
|
||||
),
|
||||
]
|
||||
# def FallingLine(self) -> List[Effect]:
|
||||
# bounds = pg.rect.Rect(0, 0, self.bounds.width, 30)
|
||||
# return [
|
||||
# Lines(
|
||||
# bounds=bounds,
|
||||
# vectors=(((0, 15), (self.bounds.width, 15), color_wheel()),),
|
||||
# thickness=30,
|
||||
# mover=transform_falling(
|
||||
# bounds,
|
||||
# acceleration=0.8,
|
||||
# initial_pos=(0, 0),
|
||||
# initial_velocity=0.01,
|
||||
# on_beat_reset=True,
|
||||
# ),
|
||||
# ),
|
||||
# ]
|
||||
|
||||
def StrobeLine(self) -> List[Effect]:
|
||||
thickness = 50
|
||||
|
@ -481,3 +490,108 @@ class Presets:
|
|||
)
|
||||
for i in range(count)
|
||||
]
|
||||
|
||||
def StrobeRect(self) -> List[Effect]:
|
||||
thickness = 50
|
||||
color_lr = color_wheel(hue=0, increase=1, repeat=4)
|
||||
color_ud = color_wheel(hue=180, increase=1, repeat=4)
|
||||
color_lr_s = color_strobe(color=color_lr, rate=(30, 120), flash_color=color_ud)
|
||||
color_ud_s = color_strobe(color=color_ud, rate=(30, 120), flash_color=color_lr)
|
||||
return [
|
||||
Lines(
|
||||
bounds=self.bounds,
|
||||
vectors=(
|
||||
(
|
||||
(0, thickness // 2),
|
||||
(self.bounds.width, thickness // 2),
|
||||
color_ud_s,
|
||||
),
|
||||
(
|
||||
(0, self.bounds.height - thickness // 2),
|
||||
(self.bounds.width, self.bounds.height - thickness // 2),
|
||||
color_ud_s,
|
||||
),
|
||||
),
|
||||
thickness=thickness,
|
||||
mover=transform_static((0, 0)),
|
||||
),
|
||||
Lines(
|
||||
bounds=self.bounds,
|
||||
vectors=(
|
||||
(
|
||||
(thickness // 2, 0),
|
||||
(thickness // 2, self.bounds.height),
|
||||
color_lr_s,
|
||||
),
|
||||
(
|
||||
(self.bounds.width - thickness // 2, 0),
|
||||
(self.bounds.width - thickness // 2, self.bounds.height),
|
||||
color_lr_s,
|
||||
),
|
||||
),
|
||||
thickness=thickness,
|
||||
mover=transform_static((0, 0)),
|
||||
),
|
||||
]
|
||||
|
||||
def ChaseCircle(self) -> List[Effect]:
|
||||
return [
|
||||
ChaseCircle(
|
||||
bounds=self.bounds,
|
||||
colors=(
|
||||
color_wheel(increase=(75 if self.beat_reactive else 0)),
|
||||
color_wheel(hue=180, increase=(75 if self.beat_reactive else 0)),
|
||||
),
|
||||
on_beat_color=self.beat_reactive,
|
||||
size=int(self.bounds.height * 0.7),
|
||||
rot_speed=5,
|
||||
thickness=80,
|
||||
size_factor=1,
|
||||
mover=transform_bounce(
|
||||
bounds=self.bounds,
|
||||
velocity=(0.1, 0.5),
|
||||
x_factor=(0.5, 1),
|
||||
y_factor=(0.1, 0.3),
|
||||
),
|
||||
)
|
||||
]
|
||||
|
||||
def ChaseCircleLine(self) -> List[Effect]:
|
||||
return [
|
||||
ChaseCircle(
|
||||
bounds=self.bounds,
|
||||
colors=(
|
||||
color_wheel(increase=(75 if self.beat_reactive else 0)),
|
||||
color_wheel(hue=180, increase=(75 if self.beat_reactive else 0)),
|
||||
),
|
||||
on_beat_color=self.beat_reactive,
|
||||
size=int(self.bounds.height * 0.7),
|
||||
rot_speed=-20,
|
||||
thickness=80,
|
||||
size_factor=0.2,
|
||||
mover=transform_bounce(
|
||||
bounds=self.bounds,
|
||||
velocity=(0.1, 0.5),
|
||||
x_factor=(0.5, 1),
|
||||
y_factor=(0.1, 0.3),
|
||||
),
|
||||
)
|
||||
]
|
||||
|
||||
def Rectangle(self) -> List[Effect]:
|
||||
return [
|
||||
Rectangle(
|
||||
bounds=self.bounds,
|
||||
color=color_wheel(increase=(75 if self.beat_reactive else 1)),
|
||||
size=int(self.bounds.height*0.9),
|
||||
aspect=1.0,
|
||||
rot_speed=0.5,
|
||||
thickness=80,
|
||||
mover=transform_bounce(
|
||||
bounds=self.bounds,
|
||||
velocity=(0.1, 0.5),
|
||||
x_factor=(0.5, 1),
|
||||
y_factor=(0.1, 0.3),
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
125
effects/rectangle.py
Normal file
125
effects/rectangle.py
Normal file
|
@ -0,0 +1,125 @@
|
|||
from effects.effect import MovingEffect
|
||||
from typing import Any, Optional
|
||||
from util import XYCoord
|
||||
from util.color import Colors, ColorGenerator, color_fade, copy_color
|
||||
import math
|
||||
import pygame as pg
|
||||
|
||||
from util.transform import PositionGenerator
|
||||
|
||||
|
||||
def calc_x(R, T, D):
|
||||
a = 1 + R**2
|
||||
b = 2 * T * (1 + R)
|
||||
c = T**2 * (1 + R**2) - D**2
|
||||
|
||||
return max(
|
||||
(-b + math.sqrt(b**2 - 4 * a * c)) / (2 * a),
|
||||
(-b - math.sqrt(b**2 - 4 * a * c)) / (2 * a),
|
||||
)
|
||||
|
||||
|
||||
class Rectangle(MovingEffect):
|
||||
def __init__(
|
||||
self,
|
||||
bounds: pg.Rect,
|
||||
color: ColorGenerator,
|
||||
size: int,
|
||||
aspect: float = 1.0,
|
||||
rot_speed: float = 0.5,
|
||||
thickness: int = 30,
|
||||
mover: Optional[PositionGenerator] = None,
|
||||
*groups: pg.sprite.Group,
|
||||
) -> None:
|
||||
self.color_gen = color
|
||||
self.color = copy_color(next(color))
|
||||
self.fader = color_fade(
|
||||
initial_color=self.color, end_color=next(self.color_gen), duration=10
|
||||
)
|
||||
self.angle = 45.0
|
||||
self.rot_speed = rot_speed
|
||||
self.thickness = thickness
|
||||
|
||||
x = calc_x(aspect, thickness, size)
|
||||
print(x)
|
||||
print(size)
|
||||
|
||||
self.rsize = (x, (x + 2 * thickness) * aspect - 2 * thickness)
|
||||
print(self.rsize)
|
||||
|
||||
self.rect_image = pg.Surface(self.rsize)
|
||||
self.rect_image.fill(Colors.Black)
|
||||
self.rect_image.set_colorkey(Colors.Black)
|
||||
|
||||
image = pg.Surface((size, size))
|
||||
image.fill(Colors.Black)
|
||||
image.set_colorkey(Colors.Black)
|
||||
super().__init__(
|
||||
image,
|
||||
pg.Rect(
|
||||
bounds.centerx - size // 2,
|
||||
bounds.centery - size // 2,
|
||||
size,
|
||||
size,
|
||||
),
|
||||
mover,
|
||||
*groups,
|
||||
)
|
||||
|
||||
self.update(is_beat=True)
|
||||
|
||||
def update(self, *args: Any, **kwargs: Any) -> None:
|
||||
# self.rect.center = self.mover.send((self.rect.size, kwargs["is_beat"]))
|
||||
|
||||
self.image.fill(Colors.Blue)
|
||||
self.rect_image.fill(Colors.Green)
|
||||
|
||||
# rc = next(self.fader)
|
||||
# pg.draw.rect(
|
||||
# self.rect_image,
|
||||
# rc,
|
||||
# ((0, 0), self.rsize),
|
||||
# 0,
|
||||
# )
|
||||
# pg.draw.rect(
|
||||
# self.rect_image,
|
||||
# Colors.Black,
|
||||
# (
|
||||
# self.thickness // 2,
|
||||
# self.thickness // 2,
|
||||
# self.rsize[0] - self.thickness,
|
||||
# self.rsize[1] - self.thickness,
|
||||
# ),
|
||||
# 0,
|
||||
# )
|
||||
|
||||
# if kwargs["is_beat"]:
|
||||
# new_color = next(self.color_gen)
|
||||
# self.fader = color_fade(
|
||||
# initial_color=self.color, end_color=new_color, duration=10
|
||||
# )
|
||||
# self.color = copy_color(new_color)
|
||||
# pg.draw.rect(
|
||||
# self.rect_image,
|
||||
# Colors.White,
|
||||
# (
|
||||
# self.thickness,
|
||||
# self.thickness,
|
||||
# self.rsize[0] - self.thickness * 2,
|
||||
# self.rsize[1] - self.thickness * 2,
|
||||
# ),
|
||||
# 0,
|
||||
# )
|
||||
|
||||
r2 = pg.transform.rotate(self.rect_image, self.angle)
|
||||
print(self.image.get_width()-r2.get_width())
|
||||
|
||||
self.image.blit(
|
||||
r2,
|
||||
(
|
||||
(self.image.get_width() - r2.get_width()) // 2,
|
||||
(self.image.get_height() - r2.get_height()) // 2,
|
||||
),
|
||||
)
|
||||
|
||||
# self.angle = (self.angle + self.rot_speed) % (360)
|
|
@ -18,7 +18,7 @@ class ScanReticle(MovingEffect):
|
|||
) -> None:
|
||||
self.colors = colors
|
||||
self.bounds = bounds
|
||||
self.rect_size = min(self.bounds.width // 6, self.bounds.height // 6)
|
||||
self.rect_size = min(self.bounds.width // 3, self.bounds.height // 3)
|
||||
|
||||
image = pg.Surface(self.bounds.size)
|
||||
image.fill(Colors.Black)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
pygame==2.1.3
|
||||
soundcard==0.4.2
|
||||
pyaudiowpatch==0.2.12.5
|
||||
pyaudiowpatch==0.2.12.5
|
||||
aubio==0.4.9
|
|
@ -1,4 +1,5 @@
|
|||
import time
|
||||
from typing import List
|
||||
import aubio
|
||||
import pyaudiowpatch as pa
|
||||
|
||||
|
@ -7,6 +8,17 @@ import numpy as np
|
|||
import threading
|
||||
|
||||
|
||||
def find_all_inputs() -> List[dict]:
|
||||
devices: List[dict] = []
|
||||
p = pa.PyAudio()
|
||||
api_info = p.get_host_api_info_by_type(pa.paWASAPI)
|
||||
for i in range(api_info["deviceCount"]):
|
||||
dev_info = p.get_device_info_by_host_api_device_index(api_info["index"], i)
|
||||
if dev_info["maxInputChannels"] > 0:
|
||||
devices.append(dev_info)
|
||||
return devices
|
||||
|
||||
|
||||
def find_audio_device(p: pa.PyAudio, api: int, name: str) -> dict:
|
||||
api_info = p.get_host_api_info_by_type(api)
|
||||
for i in range(api_info["deviceCount"]):
|
||||
|
|
|
@ -66,29 +66,15 @@ def color_fadeout(initial_color: pg.Color, fade_speed: float) -> ColorGenerator:
|
|||
def color_fade(
|
||||
initial_color: pg.Color, end_color: pg.Color, duration: int
|
||||
) -> ColorGenerator:
|
||||
color = copy_color(initial_color)
|
||||
h, s, l, a = color.hsla
|
||||
h2, s2, l2, a2 = end_color.hsla
|
||||
h_inc = (h2 - h) / duration
|
||||
s_inc = (s2 - s) / duration
|
||||
l_inc = (l2 - l) / duration
|
||||
a_inc = (a2 - a) / duration
|
||||
h_f = float(h)
|
||||
s_f = float(s)
|
||||
l_f = float(l)
|
||||
a_f = float(a)
|
||||
|
||||
inc = 1.0 / duration
|
||||
factor = 0.0
|
||||
col1 = copy_color(initial_color)
|
||||
col2 = copy_color(end_color)
|
||||
while True:
|
||||
yield color
|
||||
color.hsla = int(h_f), int(s_f), int(l_f), int(a_f)
|
||||
if h_f < h2:
|
||||
h_f += h_inc
|
||||
if s_f < s2:
|
||||
s_f += s_inc
|
||||
if l_f < l2:
|
||||
l_f += l_inc
|
||||
if a_f < a2:
|
||||
a_f += a_inc
|
||||
yield col1.lerp(col2, factor)
|
||||
factor += inc
|
||||
if factor > 1:
|
||||
factor = 1
|
||||
|
||||
|
||||
def color_cycle(seq: Sequence[pg.Color]) -> ColorGenerator:
|
||||
|
|
Loading…
Reference in a new issue