play tests improvements #2

This commit is contained in:
Patrick Moessler 2023-03-05 01:46:59 +01:00
parent 2c7a3f61e4
commit 345c06611b
9 changed files with 303 additions and 60 deletions

2
.vscode/launch.json vendored
View file

@ -11,7 +11,7 @@
"program": "beamshow.py", "program": "beamshow.py",
"console": "integratedTerminal", "console": "integratedTerminal",
"justMyCode": true, "justMyCode": true,
"args": ["-w","-b","-a","Notepad"] "args": ["-w","-b","-a","Notepad", "--fps"]
} }
] ]
} }

View file

@ -7,7 +7,7 @@ import sys
from effects.effect import Effect from effects.effect import Effect
from effects.presets import Presets from effects.presets import Presets
from util.color import Colors from util.color import Colors
from util.audio import AudioProcess from util.audio import AudioProcess, find_all_inputs
def print_displays() -> None: def print_displays() -> None:
@ -18,6 +18,12 @@ def print_displays() -> None:
sys.exit(0) 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: class Beamshow:
def __init__( def __init__(
self, self,
@ -313,6 +319,9 @@ def app_main() -> None:
argparser.add_argument( argparser.add_argument(
"--list-displays", action="store_true", help="Show available displays" "--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( argparser.add_argument(
"-w", "--window", action="store_true", help="Display in a window" "-w", "--window", action="store_true", help="Display in a window"
) )
@ -348,6 +357,9 @@ def app_main() -> None:
if args.list_displays: if args.list_displays:
print_displays() print_displays()
if args.list_displays:
print_inputs()
show = Beamshow( show = Beamshow(
audio_device_name=args.audio, audio_device_name=args.audio,
render3d=args.render3d, render3d=args.render3d,

View file

@ -31,22 +31,15 @@ class MovingEffect(Effect):
""" """
ring chase two colors
square square
square two color
line scan vh line scan vh
starfield spawn chance starfield spawn chance
rainbow circle rotate rainbow circle rotate
spot row
alles größer
fix double spot 4 spots fix double spot 4 spots
""" """

View file

@ -3,9 +3,11 @@ import pygame as pg
from typing import Iterator, List from typing import Iterator, List
from random import choice, randint, randrange from random import choice, randint, randrange
from effects.chase_circle import ChaseCircle
from effects.effect import Effect from effects.effect import Effect
from effects.line import Lines from effects.line import Lines
from effects.rectangle import Rectangle
from util.color import ( from util.color import (
color_darken, color_darken,
color_randomize, color_randomize,
@ -38,9 +40,10 @@ class Presets:
def __init__(self, bounds: pg.Rect, beat_reactive: bool = False) -> None: def __init__(self, bounds: pg.Rect, beat_reactive: bool = False) -> None:
self.bounds = bounds self.bounds = bounds
self.beat_reactive = beat_reactive self.beat_reactive = beat_reactive
self.shuffles = list(iter(self)) * 2
def default(self) -> List[Effect]: def default(self) -> List[Effect]:
return self.StrobeLine() return self.Rectangle()
def __getitem__(self, idx: str) -> List[Effect]: def __getitem__(self, idx: str) -> List[Effect]:
return getattr(self, idx)() return getattr(self, idx)()
@ -52,18 +55,24 @@ class Presets:
return ( return (
func func
for func in dir(self) 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: def randomize(self) -> str:
return choice( selected = choice(self.shuffles)
[ self.shuffles.remove(selected)
func if not self.shuffles:
for func in dir(self) self.shuffles = list(iter(self)) * 2
if callable(getattr(self, func)) return selected
and not (func.startswith("__") or func == "randomize") # 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]: def DoubleSpotRandomColor(self) -> List[Effect]:
return [ return [
@ -358,28 +367,28 @@ class Presets:
mover=transform_bounce( mover=transform_bounce(
bounds=self.bounds, bounds=self.bounds,
velocity=(0.5, 1), velocity=(0.5, 1),
x_factor=(3, 3), x_factor=(2, 2),
y_factor=(0.5, 1), y_factor=(0.5, 1),
), ),
) )
] ]
def FallingLine(self) -> List[Effect]: # def FallingLine(self) -> List[Effect]:
bounds = pg.rect.Rect(0, 0, self.bounds.width, 30) # bounds = pg.rect.Rect(0, 0, self.bounds.width, 30)
return [ # return [
Lines( # Lines(
bounds=bounds, # bounds=bounds,
vectors=(((0, 15), (self.bounds.width, 15), color_wheel()),), # vectors=(((0, 15), (self.bounds.width, 15), color_wheel()),),
thickness=30, # thickness=30,
mover=transform_falling( # mover=transform_falling(
bounds, # bounds,
acceleration=0.8, # acceleration=0.8,
initial_pos=(0, 0), # initial_pos=(0, 0),
initial_velocity=0.01, # initial_velocity=0.01,
on_beat_reset=True, # on_beat_reset=True,
), # ),
), # ),
] # ]
def StrobeLine(self) -> List[Effect]: def StrobeLine(self) -> List[Effect]:
thickness = 50 thickness = 50
@ -481,3 +490,108 @@ class Presets:
) )
for i in range(count) 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
View 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)

View file

@ -18,7 +18,7 @@ class ScanReticle(MovingEffect):
) -> None: ) -> None:
self.colors = colors self.colors = colors
self.bounds = bounds 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 = pg.Surface(self.bounds.size)
image.fill(Colors.Black) image.fill(Colors.Black)

View file

@ -1,3 +1,4 @@
pygame==2.1.3 pygame==2.1.3
soundcard==0.4.2 soundcard==0.4.2
pyaudiowpatch==0.2.12.5 pyaudiowpatch==0.2.12.5
aubio==0.4.9

View file

@ -1,4 +1,5 @@
import time import time
from typing import List
import aubio import aubio
import pyaudiowpatch as pa import pyaudiowpatch as pa
@ -7,6 +8,17 @@ import numpy as np
import threading 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: def find_audio_device(p: pa.PyAudio, api: int, name: str) -> dict:
api_info = p.get_host_api_info_by_type(api) api_info = p.get_host_api_info_by_type(api)
for i in range(api_info["deviceCount"]): for i in range(api_info["deviceCount"]):

View file

@ -66,29 +66,15 @@ def color_fadeout(initial_color: pg.Color, fade_speed: float) -> ColorGenerator:
def color_fade( def color_fade(
initial_color: pg.Color, end_color: pg.Color, duration: int initial_color: pg.Color, end_color: pg.Color, duration: int
) -> ColorGenerator: ) -> ColorGenerator:
color = copy_color(initial_color) inc = 1.0 / duration
h, s, l, a = color.hsla factor = 0.0
h2, s2, l2, a2 = end_color.hsla col1 = copy_color(initial_color)
h_inc = (h2 - h) / duration col2 = copy_color(end_color)
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)
while True: while True:
yield color yield col1.lerp(col2, factor)
color.hsla = int(h_f), int(s_f), int(l_f), int(a_f) factor += inc
if h_f < h2: if factor > 1:
h_f += h_inc factor = 1
if s_f < s2:
s_f += s_inc
if l_f < l2:
l_f += l_inc
if a_f < a2:
a_f += a_inc
def color_cycle(seq: Sequence[pg.Color]) -> ColorGenerator: def color_cycle(seq: Sequence[pg.Color]) -> ColorGenerator: