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",
|
"program": "beamshow.py",
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"justMyCode": true,
|
"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.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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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
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:
|
) -> 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)
|
||||||
|
|
|
@ -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
|
|
@ -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"]):
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in a new issue