Move all mixer settings from local constants to the settings file. Document mixer dependencies and settings.
This commit is contained in:
parent
407ab639cd
commit
0dbcc591d7
@ -4,7 +4,7 @@ from threading import Lock
|
||||
from serial import Serial
|
||||
|
||||
from mopidy.mixers import BaseMixer
|
||||
from mopidy.settings import MIXER_PORT
|
||||
from mopidy.settings import MIXER_EXT_PORT
|
||||
|
||||
logger = logging.getLogger(u'mopidy.mixers.denon')
|
||||
|
||||
@ -16,6 +16,15 @@ class DenonMixer(BaseMixer):
|
||||
The external mixer is the authoritative source for the current volume.
|
||||
This allows the user to use his remote control the volume without Mopidy
|
||||
cancelling the volume setting.
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- pyserial (python-serial on Debian/Ubuntu)
|
||||
|
||||
**Settings**
|
||||
|
||||
- :attr:`mopidy.settings.default.MIXER_EXT_PORT` -- Example:
|
||||
``/dev/ttyUSB0``
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
@ -23,7 +32,7 @@ class DenonMixer(BaseMixer):
|
||||
Connects using the serial specifications from Denon's RS-232 Protocol
|
||||
specification: 9600bps 8N1.
|
||||
"""
|
||||
self._device = Serial(port=MIXER_PORT, timeout=0.2)
|
||||
self._device = Serial(port=MIXER_EXT_PORT, timeout=0.2)
|
||||
self._levels = ['99'] + ["%(#)02d" % {'#': v} for v in range(0, 99)]
|
||||
self._volume = 0
|
||||
self._lock = Lock()
|
||||
|
||||
@ -3,7 +3,8 @@ from serial import Serial
|
||||
from multiprocessing import Pipe, Process
|
||||
|
||||
from mopidy.mixers import BaseMixer
|
||||
from mopidy.settings import MIXER_PORT
|
||||
from mopidy.settings import (MIXER_EXT_PORT, MIXER_EXT_SOURCE,
|
||||
MIXER_EXT_SPEAKERS_A, MIXER_EXT_SPEAKERS_B)
|
||||
|
||||
logger = logging.getLogger('mopidy.mixers.nad')
|
||||
|
||||
@ -24,6 +25,19 @@ class NadMixer(BaseMixer):
|
||||
recalibrate the mixer, set the volume to 0 through Mopidy. This will reset
|
||||
the amplifier to a known state, including powering on the device, selecting
|
||||
the configured speakers and input sources.
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- pyserial (python-serial on Debian/Ubuntu)
|
||||
|
||||
**Settings**
|
||||
|
||||
- :attr:`mopidy.settings.default.MIXER_EXT_PORT` --
|
||||
Example: ``/dev/ttyUSB0``
|
||||
- :attr:`mopidy.settings.default.MIXER_EXT_SOURCE` -- Example: ``Aux``
|
||||
- :attr:`mopidy.settings.default.MIXER_EXT_SPEAKERS_A` -- Example: ``On``
|
||||
- :attr:`mopidy.settings.default.MIXER_EXT_SPEAKERS_B` -- Example: ``Off``
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
@ -42,26 +56,25 @@ class NadMixer(BaseMixer):
|
||||
|
||||
|
||||
class NadTalker(Process):
|
||||
#: Timeout in seconds used for read/write operations.
|
||||
#:
|
||||
#: If you set the timeout too low, the reads will never get complete
|
||||
#: confirmations and calibration will decrease volume forever. If you set
|
||||
#: the timeout too high, stuff takes more time.
|
||||
"""
|
||||
Independent process which does the communication with the NAD device.
|
||||
|
||||
Since the communication is done in an independent process, Mopidy won't
|
||||
block other requests while doing rather time consuming work like
|
||||
calibrating the NAD device's volume.
|
||||
"""
|
||||
|
||||
# Timeout in seconds used for read/write operations.
|
||||
# If you set the timeout too low, the reads will never get complete
|
||||
# confirmations and calibration will decrease volume forever. If you set
|
||||
# the timeout too high, stuff takes more time. 0.2s seems like a good value
|
||||
# for NAD C 355BEE.
|
||||
TIMEOUT = 0.2
|
||||
|
||||
#: Number of volume levels the device supports
|
||||
NUM_STEPS = 40
|
||||
# Number of volume levels the device supports. 40 for NAD C 355BEE.
|
||||
VOLUME_LEVELS = 40
|
||||
|
||||
#: The amplifier source to use
|
||||
SOURCE = 'Aux'
|
||||
|
||||
#: State of speakers A
|
||||
SPEAKERS_A = 'On'
|
||||
|
||||
#: State of speakers B
|
||||
SPEAKERS_B = 'Off'
|
||||
|
||||
#: Volume in range [0..NUM_STEPS]. :class:`None` before calibration.
|
||||
# Volume in range 0..VOLUME_LEVELS. :class:`None` before calibration.
|
||||
_nad_volume = None
|
||||
|
||||
def __init__(self, pipe=None):
|
||||
@ -79,12 +92,9 @@ class NadTalker(Process):
|
||||
self._set_device_to_known_state()
|
||||
|
||||
def _open_connection(self):
|
||||
"""
|
||||
Opens serial connection to the device.
|
||||
|
||||
Communication settings: 115200 bps 8N1
|
||||
"""
|
||||
self._device = Serial(port=MIXER_PORT, baudrate=115200,
|
||||
# Opens serial connection to the device.
|
||||
# Communication settings: 115200 bps 8N1
|
||||
self._device = Serial(port=MIXER_EXT_PORT, baudrate=115200,
|
||||
timeout=self.TIMEOUT)
|
||||
self._get_device_model()
|
||||
|
||||
@ -106,17 +116,17 @@ class NadTalker(Process):
|
||||
self._command_device('Main.Power', 'On')
|
||||
|
||||
def _select_speakers(self):
|
||||
while self._ask_device('Main.SpeakerA') != self.SPEAKERS_A:
|
||||
logger.info(u'Setting speakers A "%s"', self.SPEAKERS_A)
|
||||
self._command_device('Main.SpeakerA', self.SPEAKERS_A)
|
||||
while self._ask_device('Main.SpeakerB') != self.SPEAKERS_B:
|
||||
logger.info(u'Setting speakers B "%s"', self.SPEAKERS_B)
|
||||
self._command_device('Main.SpeakerB', self.SPEAKERS_B)
|
||||
while self._ask_device('Main.SpeakerA') != MIXER_EXT_SPEAKERS_A:
|
||||
logger.info(u'Setting speakers A "%s"', MIXER_EXT_SPEAKERS_A)
|
||||
self._command_device('Main.SpeakerA', MIXER_EXT_SPEAKERS_A)
|
||||
while self._ask_device('Main.SpeakerB') != MIXER_EXT_SPEAKERS_B:
|
||||
logger.info(u'Setting speakers B "%s"', MIXER_EXT_SPEAKERS_B)
|
||||
self._command_device('Main.SpeakerB', MIXER_EXT_SPEAKERS_B)
|
||||
|
||||
def _select_input_source(self):
|
||||
while self._ask_device('Main.Source') != self.SOURCE:
|
||||
logger.info(u'Selecting input source "%s"', self.SOURCE)
|
||||
self._command_device('Main.Source', self.SOURCE)
|
||||
while self._ask_device('Main.Source') != MIXER_EXT_SOURCE:
|
||||
logger.info(u'Selecting input source "%s"', MIXER_EXT_SOURCE)
|
||||
self._command_device('Main.Source', MIXER_EXT_SOURCE)
|
||||
|
||||
def _unmute(self):
|
||||
while self._ask_device('Main.Mute') != 'Off':
|
||||
@ -132,13 +142,11 @@ class NadTalker(Process):
|
||||
self._readline()
|
||||
|
||||
def _calibrate_volume(self):
|
||||
"""
|
||||
The NAD C 355BEE amplifier has 40 different volume levels. We have no
|
||||
way of asking on which level we are. Thus, we must calibrate the mixer
|
||||
by decreasing the volume 39 times.
|
||||
"""
|
||||
# The NAD C 355BEE amplifier has 40 different volume levels. We have no
|
||||
# way of asking on which level we are. Thus, we must calibrate the
|
||||
# mixer by decreasing the volume 39 times.
|
||||
logger.info(u'Calibrating NAD amplifier')
|
||||
steps_left = self.NUM_STEPS - 1
|
||||
steps_left = self.VOLUME_LEVELS - 1
|
||||
while steps_left:
|
||||
if self._decrease_volume():
|
||||
steps_left -= 1
|
||||
@ -146,12 +154,10 @@ class NadTalker(Process):
|
||||
logger.info(u'Done calibrating NAD amplifier')
|
||||
|
||||
def _set_volume(self, volume):
|
||||
"""
|
||||
Increase or decrease the amplifier volume until it matches the given
|
||||
target volume.
|
||||
"""
|
||||
# Increase or decrease the amplifier volume until it matches the given
|
||||
# target volume.
|
||||
logger.debug(u'Setting volume to %d' % volume)
|
||||
target_nad_volume = int(round(volume * self.NUM_STEPS / 100.0))
|
||||
target_nad_volume = int(round(volume * self.VOLUME_LEVELS / 100.0))
|
||||
if self._nad_volume is None:
|
||||
return # Calibration needed
|
||||
while target_nad_volume > self._nad_volume:
|
||||
@ -162,30 +168,26 @@ class NadTalker(Process):
|
||||
self._nad_volume -= 1
|
||||
|
||||
def _increase_volume(self):
|
||||
# Increase volume. Returns :class:`True` if confirmed by device.
|
||||
self._write('Main.Volume+')
|
||||
return self._readline() == 'Main.Volume+'
|
||||
|
||||
def _decrease_volume(self):
|
||||
# Decrease volume. Returns :class:`True` if confirmed by device.
|
||||
self._write('Main.Volume-')
|
||||
return self._readline() == 'Main.Volume-'
|
||||
|
||||
def _write(self, data):
|
||||
"""
|
||||
Write data to device.
|
||||
|
||||
Prepends and appends a newline to the data, as recommended by the NAD
|
||||
documentation.
|
||||
"""
|
||||
# Write data to device. Prepends and appends a newline to the data, as
|
||||
# recommended by the NAD documentation.
|
||||
if not self._device.isOpen():
|
||||
self._device.open()
|
||||
self._device.write('\n%s\n' % data)
|
||||
logger.debug('Write: %s', data)
|
||||
|
||||
def _readline(self):
|
||||
"""
|
||||
Read line from device. The result is stripped for leading and trailing
|
||||
whitespace.
|
||||
"""
|
||||
# Read line from device. The result is stripped for leading and
|
||||
# trailing whitespace.
|
||||
if not self._device.isOpen():
|
||||
self._device.open()
|
||||
result = self._device.readline(eol='\n').strip()
|
||||
|
||||
@ -25,7 +25,7 @@ BACKENDS = (
|
||||
#: the format.
|
||||
CONSOLE_LOG_FORMAT = u'%(levelname)-8s %(asctime)s [%(threadName)s] %(name)s\n %(message)s'
|
||||
|
||||
#: Sound mixer to use.
|
||||
#: Sound mixer to use. See :mod:`mopidy.mixers` for all available mixers.
|
||||
#:
|
||||
#: Default on Linux::
|
||||
#:
|
||||
@ -38,25 +38,32 @@ CONSOLE_LOG_FORMAT = u'%(levelname)-8s %(asctime)s [%(threadName)s] %(name)s\n
|
||||
#: Default on other operating systems::
|
||||
#:
|
||||
#: MIXER = u'mopidy.mixers.dummy.DummyMixer'
|
||||
#:
|
||||
#: **Available external mixers**
|
||||
#:
|
||||
#: .. note::
|
||||
#: Using external mixers depends on the pyserial library.
|
||||
#:
|
||||
#: Denon AVR/AVC via RS-232::
|
||||
#:
|
||||
#: MIXER = u'mopidy.mixers.denon.DenonMixer'
|
||||
#:
|
||||
MIXER = u'mopidy.mixers.dummy.DummyMixer'
|
||||
if sys.platform == 'linux2':
|
||||
MIXER = u'mopidy.mixers.alsa.AlsaMixer'
|
||||
elif sys.platform == 'darwin':
|
||||
MIXER = u'mopidy.mixers.osa.OsaMixer'
|
||||
|
||||
#: Which port the mixer is connected to if using an external mixer.
|
||||
#: This must point to the device port like ``/dev/ttyUSB0`` or similar.
|
||||
MIXER_PORT = None
|
||||
#: External mixers only. Which port the mixer is connected to.
|
||||
#:
|
||||
#: This must point to the device port like ``/dev/ttyUSB0``.
|
||||
#: *Default:* :class:`None`
|
||||
MIXER_EXT_PORT = None
|
||||
|
||||
#: External mixers only. What input source the external mixer should use.
|
||||
#:
|
||||
#: Example: ``Aux``. *Default:* :class:`None`
|
||||
MIXER_EXT_SOURCE = None
|
||||
|
||||
#: External mixers only. What state Speakers A should be in.
|
||||
#:
|
||||
#: *Default:* :class:`None`.
|
||||
MIXER_EXT_SPEAKERS_A = None
|
||||
|
||||
#: External mixers only. What state Speakers B should be in.
|
||||
#:
|
||||
#: *Default:* :class:`None`.
|
||||
MIXER_EXT_SPEAKERS_B = None
|
||||
|
||||
#: Which address Mopidy should bind to. Examples:
|
||||
#:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user