This commit is contained in:
parent
5d2065ae85
commit
2d279b8eae
@ -6,7 +6,7 @@ if TYPE_CHECKING:
|
||||
from bot.translator import Translator
|
||||
|
||||
app_name = "WalkMan"
|
||||
app_version = "2.3.5"
|
||||
app_version = "2.5.0"
|
||||
client_name = app_name + "-V (Version)" + app_version
|
||||
about_text: Callable[[Translator], str] = lambda translator: translator.translate(
|
||||
"""\
|
||||
|
@ -43,6 +43,8 @@ class CommandProcessor:
|
||||
"e": user_commands.EnqueueCommand,
|
||||
"q": user_commands.QueueCommand,
|
||||
"u": user_commands.PlayUrlCommand,
|
||||
"eq": user_commands.EqualizerCommand,
|
||||
"8d": user_commands.Audio8DCommand,
|
||||
"sv": user_commands.ServiceCommand,
|
||||
"s": user_commands.StopCommand,
|
||||
"b": user_commands.PreviousTrackCommand,
|
||||
|
@ -455,20 +455,25 @@ class SpeedCommand(Command):
|
||||
@property
|
||||
def help(self) -> str:
|
||||
return self.translator.translate(
|
||||
"SPEED Sets playback speed from 0.25 to 4. If no speed is given, shows current speed"
|
||||
"LEVEL Sets playback speed/pitch level from -5 to 5. 0 is normal. If no level is given, shows current level."
|
||||
)
|
||||
|
||||
def __call__(self, arg: str, user: User) -> Optional[str]:
|
||||
if not arg:
|
||||
return self.translator.translate("Current rate: {}").format(
|
||||
str(self.player.get_speed())
|
||||
)
|
||||
else:
|
||||
try:
|
||||
self.player.set_speed(float(arg))
|
||||
except ValueError:
|
||||
raise errors.InvalidArgumentError()
|
||||
return self.translator.translate("Current speed level: {level}").format(level=self.player.speed_level)
|
||||
|
||||
if self.player.state == State.Stopped:
|
||||
return self.translator.translate("Nothing is playing. This command only works during playback.")
|
||||
|
||||
try:
|
||||
level = int(arg)
|
||||
self.player.set_speed(level)
|
||||
if level == 0:
|
||||
return self.translator.translate("Speed and pitch reset to normal.")
|
||||
else:
|
||||
return self.translator.translate("Speed level set to: {level}").format(level=self.player.speed_level)
|
||||
except ValueError:
|
||||
raise errors.InvalidArgumentError()
|
||||
|
||||
class FavoritesCommand(Command):
|
||||
@property
|
||||
@ -700,3 +705,55 @@ class QueueCommand(Command):
|
||||
response += self.translator.translate("\n...and {count} more.").format(count=remaining)
|
||||
|
||||
return response
|
||||
|
||||
class EqualizerCommand(Command):
|
||||
@property
|
||||
def help(self) -> str:
|
||||
preset_list = ", ".join(self.player.eq_presets.keys())
|
||||
return self.translator.translate(
|
||||
"PRESET Sets the audio equalizer. If no preset is given, shows current and available presets. Available presets: {presets}"
|
||||
).format(presets=preset_list)
|
||||
|
||||
def __call__(self, arg: str, user: User) -> Optional[str]:
|
||||
if not arg:
|
||||
# Tampilkan status saat ini dan daftar preset yang tersedia
|
||||
preset_list = ", ".join(self.player.eq_presets.keys())
|
||||
return self.translator.translate(
|
||||
"Current equalizer: {current_eq}\nAvailable presets: {presets}"
|
||||
).format(current_eq=self.player.current_eq.capitalize(), presets=preset_list)
|
||||
|
||||
if self.player.state == State.Stopped:
|
||||
return self.translator.translate("Nothing is playing. This command only works during playback.")
|
||||
|
||||
preset_to_set = arg.lower()
|
||||
success = self.player.set_eq(preset_to_set)
|
||||
|
||||
if success:
|
||||
if preset_to_set == 'off':
|
||||
return self.translator.translate("Equalizer has been turned off.")
|
||||
else:
|
||||
return self.translator.translate("Equalizer set to: {preset}").format(preset=preset_to_set.capitalize())
|
||||
else:
|
||||
return self.translator.translate("'{preset}' is not a valid preset.").format(preset=arg)
|
||||
|
||||
class Audio8DCommand(Command):
|
||||
@property
|
||||
def help(self) -> str:
|
||||
return self.translator.translate("on/off Toggles the 8D audio effect.")
|
||||
|
||||
def __call__(self, arg: str, user: User) -> Optional[str]:
|
||||
arg = arg.lower()
|
||||
|
||||
if self.player.state == State.Stopped:
|
||||
return self.translator.translate("Nothing is playing. This command only works during playback.")
|
||||
|
||||
if arg == "on":
|
||||
self.player.set_8d(True)
|
||||
return self.translator.translate("8D audio effect enabled.")
|
||||
elif arg == "off":
|
||||
self.player.set_8d(False)
|
||||
return self.translator.translate("8D audio effect disabled.")
|
||||
else:
|
||||
# Tampilkan status saat ini jika argumen tidak valid
|
||||
status = "enabled" if self.player.is_8d_enabled else "disabled"
|
||||
return self.translator.translate("8D audio is currently {status}. Use '8d on' or '8d off'.").format(status=status)
|
@ -44,6 +44,18 @@ class Player:
|
||||
self.mode = Mode.TrackList
|
||||
self.volume = self.config.default_volume
|
||||
self.manual_queue = False
|
||||
self.eq_presets = {
|
||||
'off': '', # Untuk mematikan EQ
|
||||
'default': 'equalizer=gains=[0 0 0 0 0 0 0 0 0 0]',
|
||||
'rock': 'equalizer=gains=[4 2 1 -2 -3 -1 2 4 5 5]',
|
||||
'pop': 'equalizer=gains=[-1 1 3 4 3 1 -1 -1 -2 -2]',
|
||||
'jazz': 'equalizer=gains=[3 2 1 -1 -2 -2 1 3 4 4]',
|
||||
'classic': 'equalizer=gains=[-2 -2 -2 -1 1 3 4 4 5 5]',
|
||||
'bass': 'equalizer=gains=[6 5 4 2 1 0 0 0 0 0]'
|
||||
}
|
||||
self.current_eq = 'off'
|
||||
self.speed_level = 0 # 0 is normal, positive is faster, negative is slower
|
||||
self.is_8d_enabled = False
|
||||
|
||||
def initialize(self) -> None:
|
||||
logging.debug("Initializing player")
|
||||
@ -56,6 +68,21 @@ class Player:
|
||||
self._player.observe_property("media-title", self.on_metadata_update)
|
||||
logging.debug("Player callbacks registered")
|
||||
|
||||
def set_eq(self, preset_name: str) -> bool:
|
||||
"""Sets the audio equalizer preset."""
|
||||
preset_name = preset_name.lower()
|
||||
if preset_name in self.eq_presets:
|
||||
self.current_eq = preset_name
|
||||
self._update_audio_filters()
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_8d(self, enable: bool) -> None:
|
||||
"""Enables or disables the 8D audio effect."""
|
||||
self.is_8d_enabled = enable
|
||||
self._update_audio_filters()
|
||||
|
||||
|
||||
def enqueue(self, tracks: List[Track]) -> None:
|
||||
"""Adds tracks to the queue, clearing the old playlist if needed."""
|
||||
if self.state == State.Stopped or not self.track_list:
|
||||
@ -193,10 +220,47 @@ class Player:
|
||||
def get_speed(self) -> float:
|
||||
return self._player.speed
|
||||
|
||||
def set_speed(self, arg: float) -> None:
|
||||
if arg < 0.25 or arg > 4:
|
||||
raise ValueError()
|
||||
self._player.speed = arg
|
||||
def set_speed(self, level: int) -> None:
|
||||
"""Sets the playback speed and pitch based on a level."""
|
||||
level = max(-5, min(level, 5))
|
||||
self.speed_level = level
|
||||
|
||||
if level == 0:
|
||||
self._player.speed = 1.0
|
||||
# Cukup panggil update, ia akan menghapus 'scaletempo' secara implisit
|
||||
self._update_audio_filters()
|
||||
else:
|
||||
speed_multiplier = 1.0 + (level * 0.10)
|
||||
self._player.speed = speed_multiplier
|
||||
# Tambahkan filter 'scaletempo' untuk menonaktifkan koreksi pitch bawaan mpv
|
||||
self._update_audio_filters(add_filters=['scaletempo'])
|
||||
|
||||
def _update_audio_filters(self, add_filters: list = None, remove_filters: list = None):
|
||||
"""Builds and applies the audio filter string based on active effects."""
|
||||
active_filters = []
|
||||
|
||||
# 1. Cek Equalizer
|
||||
if self.current_eq != 'off':
|
||||
active_filters.append(self.eq_presets[self.current_eq])
|
||||
|
||||
# 2. Cek 8D Audio
|
||||
if self.is_8d_enabled:
|
||||
# Filter 8D. Kecepatan 0.2Hz adalah awal yang baik.
|
||||
active_filters.append('pan=stereo|c0<c0+c1*sin(2*PI*t*0.2)|c1<c1-c0*sin(2*PI*t*0.2)')
|
||||
|
||||
# 3. Cek efek terkait kecepatan (misalnya, 'scaletempo' dari set_speed)
|
||||
# Ini memungkinkan kita menambahkan filter sementara
|
||||
if add_filters:
|
||||
for f in add_filters:
|
||||
# Hindari duplikasi
|
||||
if not any(f.split('=')[0] in af for af in active_filters):
|
||||
active_filters.append(f)
|
||||
|
||||
# Gabungkan semua filter aktif dengan koma
|
||||
final_filter_string = ",".join(filter for filter in active_filters if filter)
|
||||
|
||||
# Terapkan ke mpv
|
||||
self._player.af = final_filter_string
|
||||
|
||||
def seek_back(self, step: Optional[float] = None) -> None:
|
||||
step = step if step else self.config.seek_step
|
||||
|
Loading…
x
Reference in New Issue
Block a user