Add audio channel selection (mono/left/right), show device LED count in target editor

Audio capture now produces per-channel FFT spectrum and RMS alongside
the existing mono mix. Each audio color strip source can select which
channel to visualize via a new "Channel" dropdown. This enables stereo
setups with separate left/right segments on the same LED strip.

Also shows the device LED count under the device selector in the target
editor for quick reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-23 15:05:15 +03:00
parent 9d593379b8
commit f15ff8fea0
13 changed files with 129 additions and 31 deletions

View File

@@ -83,6 +83,7 @@ def _css_to_response(source, overlay_active: bool = False) -> ColorStripSourceRe
visualization_mode=getattr(source, "visualization_mode", None),
audio_device_index=getattr(source, "audio_device_index", None),
audio_loopback=getattr(source, "audio_loopback", None),
audio_channel=getattr(source, "audio_channel", None),
sensitivity=getattr(source, "sensitivity", None),
color_peak=getattr(source, "color_peak", None),
overlay_active=overlay_active,
@@ -164,6 +165,7 @@ async def create_color_strip_source(
visualization_mode=data.visualization_mode,
audio_device_index=data.audio_device_index,
audio_loopback=data.audio_loopback,
audio_channel=data.audio_channel,
sensitivity=data.sensitivity,
color_peak=data.color_peak,
)
@@ -237,6 +239,7 @@ async def update_color_strip_source(
visualization_mode=data.visualization_mode,
audio_device_index=data.audio_device_index,
audio_loopback=data.audio_loopback,
audio_channel=data.audio_channel,
sensitivity=data.sensitivity,
color_peak=data.color_peak,
)

View File

@@ -71,6 +71,7 @@ class ColorStripSourceCreate(BaseModel):
audio_loopback: Optional[bool] = Field(None, description="True for system audio (WASAPI loopback), False for mic/line-in")
sensitivity: Optional[float] = Field(None, description="Audio sensitivity/gain 0.1-5.0", ge=0.1, le=5.0)
color_peak: Optional[List[int]] = Field(None, description="Peak/high RGB color for VU meter [R,G,B]")
audio_channel: Optional[str] = Field(None, description="Audio channel: mono|left|right")
# shared
led_count: int = Field(default=0, description="Total LED count (0 = auto from calibration / device)", ge=0)
description: Optional[str] = Field(None, description="Optional description", max_length=500)
@@ -112,6 +113,7 @@ class ColorStripSourceUpdate(BaseModel):
audio_loopback: Optional[bool] = Field(None, description="True for system audio (WASAPI loopback), False for mic/line-in")
sensitivity: Optional[float] = Field(None, description="Audio sensitivity/gain 0.1-5.0", ge=0.1, le=5.0)
color_peak: Optional[List[int]] = Field(None, description="Peak/high RGB color for VU meter [R,G,B]")
audio_channel: Optional[str] = Field(None, description="Audio channel: mono|left|right")
# shared
led_count: Optional[int] = Field(None, description="Total LED count (0 = auto from calibration / device)", ge=0)
description: Optional[str] = Field(None, description="Optional description", max_length=500)
@@ -155,6 +157,7 @@ class ColorStripSourceResponse(BaseModel):
audio_loopback: Optional[bool] = Field(None, description="WASAPI loopback mode")
sensitivity: Optional[float] = Field(None, description="Audio sensitivity")
color_peak: Optional[List[int]] = Field(None, description="Peak color [R,G,B]")
audio_channel: Optional[str] = Field(None, description="Audio channel: mono|left|right")
# shared
led_count: int = Field(0, description="Total LED count (0 = auto from calibration / device)")
description: Optional[str] = Field(None, description="Description")