diff --git a/README.md b/README.md index eb81e01..0facef0 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,9 @@ The following software must be installed for `pymusiclooper` to function correct Supported audio formats *without* ffmpeg include: WAV, FLAC, Ogg/Vorbis, Ogg/Opus, MP3. A full list can be found at [libsndfile's supported formats page](https://libsndfile.github.io/libsndfile/formats.html) +Additionally, to use the `play` command on Linux systems, you may need to +install the PortAudio library. On Ubuntu, run `sudo apt install libportaudio2`. + ## Installation ### Option 1: Installing using pipx [Recommended] diff --git a/pymusiclooper/playback.py b/pymusiclooper/playback.py index a871d3a..0014a19 100644 --- a/pymusiclooper/playback.py +++ b/pymusiclooper/playback.py @@ -1,16 +1,22 @@ """Module for playback through the terminal""" +import importlib import logging import signal import threading import numpy as np -import lazy_loader as lazy from rich.progress import BarColumn, Progress, TextColumn from pymusiclooper.console import rich_console -# Lazy-load sounddevice -sd = lazy.load("sounddevice") +# Lazy-load sounddevice: call `sd()` to return the module. +# (We use this instead of `lazy-loader`, to get clearer error messages when +# sounddevice is missing dependencies like PortAudio.) +_sd = None +def sd(): + global _sd + _sd = _sd or importlib.import_module("sounddevice") + return _sd class PlaybackHandler: """Handler class for initiating looping playback through the terminal.""" @@ -93,9 +99,9 @@ def callback(outdata, frames, time, status): self.current_frame += chunksize if chunksize < frames: outdata[chunksize:] = 0 - raise sd.CallbackStop() + raise sd().CallbackStop() - self.stream = sd.OutputStream( + self.stream = sd().OutputStream( samplerate=samplerate, channels=n_channels, callback=callback,