55 lines
1.5 KiB
Python
55 lines
1.5 KiB
Python
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"
|
||
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
|