diff options
author | Ben Connors <benconnors@outlook.com> | 2019-05-30 20:29:03 -0400 |
---|---|---|
committer | Ben Connors <benconnors@outlook.com> | 2019-05-30 20:29:03 -0400 |
commit | 8f430752f2b5a508dabe76fccfaf3f129a562e4b (patch) | |
tree | d65a7801e855c4c07efd709e8d136373f26e4506 | |
parent | 9c464c705ef8ef0ecc2aa674beaaf89460e70d3d (diff) |
Clean up audio submodule
- Implement MPVPlayer
- Restructure into submodule, split files
-rw-r--r-- | blc/audio/__init__.py | 23 | ||||
-rw-r--r--[-rwxr-xr-x] | blc/audio/ffplay.py (renamed from blc/audio.py) | 78 | ||||
-rwxr-xr-x | blc/audio/interface.py | 53 | ||||
-rw-r--r-- | blc/audio/mpv.py | 48 | ||||
-rw-r--r-- | blc/audio/util.py | 9 |
5 files changed, 136 insertions, 75 deletions
diff --git a/blc/audio/__init__.py b/blc/audio/__init__.py new file mode 100644 index 0000000..ebb9067 --- /dev/null +++ b/blc/audio/__init__.py @@ -0,0 +1,23 @@ +"""Audio module for BLC. + +This module defines an AudioPlayer interface which allows for various audio backends to be used +interchangeably. It also defines a bare-bones better-than-nothing "FFPlayer" implementation and +a better "MPVPlayer" implementation. + +"DefaultAudioPlayer" should be used in general and will refer to MPVPlayer if available and +FFPlayer otherwise. +""" + +from .interface import AudioPlayer +from .ffplay import FFPlayer + + +__all__ = ["AudioPlayer", "FFPlayer", "DefaultAudioPlayer"] + +try: + from .mpv import MPVPlayer + __all__.append("MPVPlayer") + DefaultAudioPlayer = MPVPlayer +except ImportError as e: + print(e) + DefaultAudioPlayer = FFPlayer diff --git a/blc/audio.py b/blc/audio/ffplay.py index 9df8853..306351a 100755..100644 --- a/blc/audio.py +++ b/blc/audio/ffplay.py @@ -1,77 +1,11 @@ -#!/usr/bin/env python3 - -"""Audio module for BLC. - -This module defines an AudioPlayer interface which allows for various audio backends to be used -interchangeably. It also defines a bare-bones better-than-nothing "FFPlayer" implementation and -a better "MPVPlayer" implementation. - -"DefaultAudioPlayer" should be used in general and will refer to MPVPlayer if available and -FFPlayer otherwise. -""" +"""Module for FFPlay-based audio player.""" import atexit import subprocess as subp import time -import warnings - -from abc import ABC, abstractmethod, abstractproperty -def ttoti(t): - """Convert seconds to milliseconds.""" - return int(1000*t + 0.5) - -def titot(ti): - """Convert milliseconds to seconds.""" - return ti/1000 - -class AudioPlayer(ABC): - """Class for playing audio. - - All time indices must be integers in milliseconds. - """ - @abstractmethod - def play(self, start=-1): - """Play the audio from the given time. - - If start is -1, play it from the current time index (e.g. if paused). If the player is - already playing, throw an error. - """ - return - - @abstractmethod - def seek(self, t): - """Seek to the given time index.""" - return - - @abstractmethod - def pause(self): - """Pause the player.""" - return - - @abstractmethod - def stop(self): - """Stop the player and reset to the first time index.""" - return - - @abstractproperty - def volume(self): - """Get or set the current volume.""" - return - - @abstractproperty - def position(self) -> int: - """The current position in milliseconds.""" - return - - @abstractproperty - def playing(self) -> bool: - """Return if the player is playing or not.""" - return - - def __init__(self, fname, args=()): - self.fname = fname - self.args = args +from .interface import AudioPlayer +from .util import ttoti, titot class FFPlayer(AudioPlayer): """Audio player using ffplay. @@ -147,10 +81,4 @@ class FFPlayer(AudioPlayer): self.player = None self.start = 0 self.start_time = 0 - -## try: -## import mpv -## except (OSError, ImportError): -## warnings.warn("mpv backend unavailable, falling back to ffplay", RuntimeWarning) -DefaultAudioPlayer = FFPlayer diff --git a/blc/audio/interface.py b/blc/audio/interface.py new file mode 100755 index 0000000..fff19cf --- /dev/null +++ b/blc/audio/interface.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +"""Module for the AudioPlayer interface.""" + +from abc import ABC, abstractmethod, abstractproperty + +class AudioPlayer(ABC): + """Class for playing audio. + + All time indices must be integers in milliseconds. + """ + @abstractmethod + def play(self, start=-1): + """Play the audio from the given time. + + If start is -1, play it from the current time index (e.g. if paused). If the player is + already playing, throw an error. + """ + return + + @abstractmethod + def seek(self, t): + """Seek to the given time index.""" + return + + @abstractmethod + def pause(self): + """Pause the player.""" + return + + @abstractmethod + def stop(self): + """Stop the player and reset to the first time index.""" + return + + @abstractproperty + def volume(self) -> int: + """Get or set the current volume.""" + return + + @abstractproperty + def position(self) -> int: + """The current position in milliseconds.""" + return + + @abstractproperty + def playing(self) -> bool: + """Return if the player is playing or not.""" + return + + def __init__(self, fname, args=()): + self.fname = fname + self.args = args diff --git a/blc/audio/mpv.py b/blc/audio/mpv.py new file mode 100644 index 0000000..da21494 --- /dev/null +++ b/blc/audio/mpv.py @@ -0,0 +1,48 @@ +"""Module for using MPV as the AudioPlayer backend.""" + +import mpv + +from .interface import AudioPlayer +from .util import titot, ttoti + +class MPVPlayer(AudioPlayer): + """Class for using MPV as an audio player.""" + @property + def position(self): + return ttoti(self.player.time_pos) + + def play(self, start=-1): + ## TODO: Raise error if already playing? + self.player.pause = False + + def pause(self): + self.player.pause = True + + def seek(self, t): + self.player.seek(titot(t), reference="absolute", precision="exact") + + def stop(self): + self.player.pause = True + self.seek(0) + + @property + def volume(self) -> int: + return int(self.player.volume) + + @volume.setter + def volume(self, value): + self.player.volume = value + + @property + def playing(self) -> bool: + if self.started: + return not (self.player.pause or self.player.eof_reached) + return False + + def __init__(self, fname, args=()): + super().__init__(fname, args) + self.player = mpv.MPV() + self.player.pause = True + self.player.keep_open = True + self.started = False + self.player.loadfile(fname) diff --git a/blc/audio/util.py b/blc/audio/util.py new file mode 100644 index 0000000..ed8345b --- /dev/null +++ b/blc/audio/util.py @@ -0,0 +1,9 @@ +"""Various AudioPlayer utilities.""" + +def ttoti(t): + """Convert seconds to milliseconds.""" + return int(1000*t + 0.5) + +def titot(ti): + """Convert milliseconds to seconds.""" + return ti/1000 |