From 1c125316c005dfffcb17ca2004770d56e438cca8 Mon Sep 17 00:00:00 2001 From: Kinuax Date: Sat, 11 May 2024 20:53:29 +0200 Subject: [PATCH] Fix overlap and unrecognized audio format error. --- poetry.lock | 22 ++++++++++++++++------ pyproject.toml | 1 + rolabesti/views/tracklist.py | 4 ++-- rolabesti/views/utils.py | 23 ++++++++++++++++++----- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/poetry.lock b/poetry.lock index 97e1759..41055d2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -360,6 +360,17 @@ python-dotenv = ">=0.21.0" toml = ["tomli (>=2.0.1)"] yaml = ["pyyaml (>=6.0.1)"] +[[package]] +name = "pydub" +version = "0.25.1" +description = "Manipulate audio with an simple and easy high level interface" +optional = false +python-versions = "*" +files = [ + {file = "pydub-0.25.1-py2.py3-none-any.whl", hash = "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6"}, + {file = "pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f"}, +] + [[package]] name = "pygame" version = "2.5.2" @@ -428,17 +439,16 @@ files = [ [[package]] name = "pygments" -version = "2.17.2" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] [[package]] @@ -750,4 +760,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "fa2d0875e4934b7e12675cec0d7781e12b1f0c938a8d3407193ad6179e1ef20a" +content-hash = "1270371bc043d87d38fc0a032dbdbc75a93e7413f053d02f16eff11e6587d04d" diff --git a/pyproject.toml b/pyproject.toml index 37f7bdd..a266e9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,7 @@ mutagen = "1.47.0" platformdirs = "4.2.0" pydantic = "2.7.0" pydantic-settings = "2.2.1" +pydub = "0.25.1" pygame = "2.5.2" pymongo = "4.6.2" tinydb = "4.8.0" diff --git a/rolabesti/views/tracklist.py b/rolabesti/views/tracklist.py index f68b8fd..b6b8f21 100644 --- a/rolabesti/views/tracklist.py +++ b/rolabesti/views/tracklist.py @@ -5,7 +5,7 @@ import typer -from .utils import play_audio +from .utils import play_mp3 from rolabesti.models import FIELD_FILTERS, Track from rolabesti.logger import Logger from rolabesti.utils import length_to_string @@ -37,7 +37,7 @@ def play(self, cli: bool, overlap_length: int) -> None: if cli: for i, track in enumerate(self.tracks): self.logger.log(f"[green]playing --> [/green]{track}") - play_audio(track.path) + play_mp3(track.path, i % 2) # Adjust waiting_length. Filter out last track and too short tracks. if i < self.count - 1 and overlap_length < track.length: diff --git a/rolabesti/views/utils.py b/rolabesti/views/utils.py index 72475dc..13e6011 100644 --- a/rolabesti/views/utils.py +++ b/rolabesti/views/utils.py @@ -1,6 +1,10 @@ +import tempfile from contextlib import contextmanager, redirect_stdout from pathlib import Path +from pydub import AudioSegment + + try: from wurlitzer import pipes except ModuleNotFoundError: @@ -15,10 +19,19 @@ def pipes(): import pygame -def play_audio(trackpath: Path) -> None: - """Play the audio file located at trackpath.""" - pygame.mixer.init() +pygame.mixer.init() +channels = [pygame.mixer.Channel(0), pygame.mixer.Channel(1)] + + +def play_mp3(trackpath: Path, channel: int) -> None: + """Play the track located at trackpath on the given channel.""" # Avoid messages from C libraries. with pipes(): - pygame.mixer.music.load(trackpath) - pygame.mixer.music.play() + try: + sound = pygame.mixer.Sound(trackpath) + except pygame.error: + # Convert mp3 to wav if "Unrecognized audio format" error. + with tempfile.TemporaryFile() as wav_file: + AudioSegment.from_mp3(trackpath).export(wav_file, format="wav") + sound = pygame.mixer.Sound(wav_file) + channels[channel].play(sound)