feat: add player audio effects module with real-time pipeline, distortion, fourth density, and UI controls

This commit is contained in:
mmacierzanka committed 2026-09-11 01:54:42 +02:00
1 parent 46a1fcf385
commit a12b726648
20 files changed
+698 -70

No files matched your search

+1
View File
@@ -21,6 +21,7 @@ EXPECTED_ENDPOINTS = {
("post", "/api/stop"),
("post", "/api/volume"),
("post", "/api/volume_boost"),
("post", "/api/effects/toggle"),
("post", "/api/loop"),
("post", "/api/loop_playlist"),
("post", "/api/loop_cycle"),
+75
View File
@@ -0,0 +1,75 @@
from __future__ import annotations
import struct
import unittest
from zyrarbot.audio.effects import (
AudioEffectsPipeline,
DistortionEffect,
FourthDensityEffect,
MuffledEffect,
TremoloEffect,
create_default_effects,
)
class TestAudioEffects(unittest.TestCase):
def test_distortion_clips_pcm(self):
fx = DistortionEffect(multiplier=10.0)
pcm = struct.pack("<hh", 10000, -10000)
out = fx.process(pcm)
left, right = struct.unpack("<hh", out)
self.assertEqual(left, 32767)
self.assertEqual(right, -32768)
def test_muffled_filters_pcm(self):
fx = MuffledEffect(alpha=0.1)
# Step input
pcm = struct.pack("<hh", 10000, 10000)
out = fx.process(pcm)
left, right = struct.unpack("<hh", out)
# With alpha=0.1, output sample should be smoothed to 1000
self.assertEqual(left, 1000)
self.assertEqual(right, 1000)
def test_tremolo_modulates_amplitude(self):
fx = TremoloEffect(freq_hz=4.0, depth=0.6)
pcm = struct.pack("<hh", 10000, 10000)
out = fx.process(pcm)
left, right = struct.unpack("<hh", out)
# At phase 0, sin(0) = 0 -> lfo = 0.5 -> factor = 1.0 - 0.6*0.5 = 0.7
self.assertAlmostEqual(left, 7000, delta=100)
self.assertAlmostEqual(right, 7000, delta=100)
def test_fourth_density_processes_without_error(self):
fx = FourthDensityEffect()
pcm = (struct.pack("<hh", 1000, -1000)) * 960
out = fx.process(pcm)
self.assertEqual(len(out), len(pcm))
def test_pipeline_chains_multiple_effects_and_applies_volume(self):
pipeline = AudioEffectsPipeline(create_default_effects())
pcm = (struct.pack("<hh", 1000, -1000)) * 960
# When no effects active and volume=1.0, data is unchanged
out = pipeline.process(pcm, volume=1.0)
self.assertEqual(out, pcm)
# Activate fourth_density and distortion simultaneously
pipeline.set_active("fourth_density", True)
pipeline.set_active("distortion", True)
self.assertTrue(pipeline.is_active("fourth_density"))
self.assertTrue(pipeline.is_active("distortion"))
out_mult = pipeline.process(pcm, volume=0.5)
self.assertEqual(len(out_mult), len(pcm))
self.assertNotEqual(out_mult, pcm)
# Toggle off
toggled = pipeline.toggle("distortion")
self.assertFalse(toggled)
self.assertFalse(pipeline.is_active("distortion"))
if __name__ == "__main__":
unittest.main()