feat: add Robot (ring modulation) and Dźwięk z tostera (8-bit bitcrusher) player audio effects

This commit is contained in:
mmacierzanka committed 2026-09-11 02:13:21 +02:00
1 parent 39403b8238
commit 51418a2d88
7 files changed
+137

No files matched your search

+4
View File
@@ -9,6 +9,8 @@ from zyrarbot.audio.effects.registry import (
create_default_effects,
get_available_effects_metadata,
)
from zyrarbot.audio.effects.robot import RobotEffect
from zyrarbot.audio.effects.toaster import ToasterEffect
from zyrarbot.audio.effects.tremolo import TremoloEffect
__all__ = [
@@ -17,6 +19,8 @@ __all__ = [
"DistortionEffect",
"FourthDensityEffect",
"MuffledEffect",
"RobotEffect",
"ToasterEffect",
"TremoloEffect",
"create_default_effects",
"get_available_effects_metadata",
+4
View File
@@ -6,6 +6,8 @@ from zyrarbot.audio.effects.base import AudioEffect
from zyrarbot.audio.effects.distortion import DistortionEffect
from zyrarbot.audio.effects.fourth_density import FourthDensityEffect
from zyrarbot.audio.effects.muffled import MuffledEffect
from zyrarbot.audio.effects.robot import RobotEffect
from zyrarbot.audio.effects.toaster import ToasterEffect
from zyrarbot.audio.effects.tremolo import TremoloEffect
@@ -14,6 +16,8 @@ def create_default_effects() -> list[AudioEffect]:
return [
MuffledEffect(),
FourthDensityEffect(),
RobotEffect(),
ToasterEffect(),
DistortionEffect(),
TremoloEffect(),
]
+48
View File
@@ -0,0 +1,48 @@
from __future__ import annotations
import array
import math
from zyrarbot.audio.effects.base import AudioEffect
class RobotEffect(AudioEffect):
"""Efekt metalicznego, robotycznego głosu oparty na ring modulation (modulacja pierścieniowa ~65Hz)."""
id = "robot"
name = "Robot"
description = "Metaliczny, robotyczny głos cyborga (ring modulation ~65Hz)"
badge = "CYBORG"
icon = "bot"
def __init__(self, freq_hz: float = 65.0, mix: float = 0.85) -> None:
self.freq_hz = freq_hz
self.mix = mix
self._phase = 0.0
self._phase_inc = 2.0 * math.pi * freq_hz / 48000.0
def process(self, pcm_data: bytes, sample_rate: int = 48000) -> bytes:
if not pcm_data:
return pcm_data
samples = array.array("h", pcm_data)
phase = self._phase
phase_inc = self._phase_inc
mix = self.mix
dry = 1.0 - mix
for i in range(0, len(samples), 2):
carrier = math.sin(phase)
phase += phase_inc
if phase >= 2.0 * math.pi:
phase -= 2.0 * math.pi
mod_factor = dry + mix * carrier
samples[i] = max(-32768, min(32767, int(samples[i] * mod_factor)))
samples[i + 1] = max(-32768, min(32767, int(samples[i + 1] * mod_factor)))
self._phase = phase
return samples.tobytes()
def reset(self) -> None:
self._phase = 0.0
+56
View File
@@ -0,0 +1,56 @@
from __future__ import annotations
import array
from zyrarbot.audio.effects.base import AudioEffect
class ToasterEffect(AudioEffect):
"""Efekt 'dźwięku z tostera / mikrofalówki' – memiczny lo-fi bitcrusher (5-bit quant + downsampling)."""
id = "toaster"
name = "Dźwięk z tostera"
description = "Memiczny dźwięk z mikrofalówki / kalkulatora (bitcrusher 5-bit, aliasing)"
badge = "8-BIT"
icon = "radio"
def __init__(self, bit_depth: int = 5, downsample: int = 6) -> None:
self.bit_depth = bit_depth
self.downsample = downsample
self.shift = 16 - bit_depth
self._counter = 0
self._hold_l = 0
self._hold_r = 0
def process(self, pcm_data: bytes, sample_rate: int = 48000) -> bytes:
if not pcm_data:
return pcm_data
samples = array.array("h", pcm_data)
shift = self.shift
down = self.downsample
hold_l = self._hold_l
hold_r = self._hold_r
cnt = self._counter
for i in range(0, len(samples), 2):
if cnt == 0:
# Obniżenie rozdzielczości bitowej (bitcrush / kwantyzacja do 5 bitów)
sl = samples[i]
sr = samples[i + 1]
hold_l = (sl >> shift) << shift
hold_r = (sr >> shift) << shift
samples[i] = hold_l
samples[i + 1] = hold_r
cnt = (cnt + 1) % down
self._counter = cnt
self._hold_l = hold_l
self._hold_r = hold_r
return samples.tobytes()
def reset(self) -> None:
self._counter = 0
self._hold_l = 0
self._hold_r = 0
+2
View File
@@ -117,6 +117,8 @@ class ControlCog(MusicCogBase, name="Control"):
nazwa=[
app_commands.Choice(name="Przester (1000%)", value="distortion"),
app_commands.Choice(name="Czwarta gęstość (~1s pitch)", value="fourth_density"),
app_commands.Choice(name="Robot (cyborg voice)", value="robot"),
app_commands.Choice(name="Dźwięk z tostera (8-bit lo-fi)", value="toaster"),
app_commands.Choice(name="Pod wodą (lowpass)", value="muffled"),
app_commands.Choice(name="Tremolo (pulsowanie)", value="tremolo"),
]