Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for DIRMODE #23

Merged
merged 4 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/PRACTICALITIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,19 @@ However the set of values that comes back is not stable between receivers.

Initially it was assumed that it would always respond with all supported features.
But at least for PUREDIRMODE this is not the case. It is supported on RX-V1067, but not part of BASIC response.

## (Pure) Direct mode

Turns out there are 2 direct modes; Direct and Pure Direct.

These are slightly different. Pure Direct bypasses more signal processing than Direct does.
It seems Pure Direct is an evolution of Direct because Direct seems to apply to older/lower end models.

Both commands support `On` and `Off`.

```
@MAIN:PUREDIRMODE=? e.g. RX-A810
@MAIN:DIRMODE=? e.g. RX-V473
```

Both seem to be part of BASIC. Except for RX-V1067 where PUREDIRMODE is supported, but not in BASIC.
mvdwetering marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 2 additions & 0 deletions tests/test_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
BandDab,
BandTun,
DabPreset,
DirMode,
Enhancer,
FmPreset,
HdmiOut,
Expand Down Expand Up @@ -43,6 +44,7 @@ def test_invalid_values_on_enums():
assert BandTun("x") is BandTun.UNKNOWN
assert DabPreset("x") is DabPreset.UNKNOWN
assert Enhancer("x") is Enhancer.UNKNOWN
assert DirMode("x") is DirMode.UNKNOWN
assert FmPreset("x") is FmPreset.UNKNOWN
assert HdmiOut("x") is HdmiOut.UNKNOWN
assert HdmiOutOnOff("x") is HdmiOutOnOff.UNKNOWN
Expand Down
17 changes: 17 additions & 0 deletions tests/test_zone.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
InitVolMode,
Input,
Mute,
DirMode,
PureDirMode,
Pwr,
PwrB,
Expand Down Expand Up @@ -53,6 +54,7 @@
(SUBUNIT, "ADAPTIVEDRC", "Off"),
(SUBUNIT, "SPEAKERA", "Off"),
(SUBUNIT, "SPEAKERB", "On"),
(SUBUNIT, "DIRMODE", "On"),
],
),
(
Expand Down Expand Up @@ -159,6 +161,7 @@ def test_initialize_minimal(connection, update_callback):
assert z.soundprg is None
assert z.twochdecoder is None
assert z.puredirmode is None
assert z.dirmode is None
for scene_id in range(1, NUM_SCENES + 1):
assert getattr(z, f"scene{scene_id}name") is None

Expand All @@ -182,6 +185,7 @@ def test_initialize_full(connection, update_callback):
assert z.zonename == "ZoneName"
assert z.twochdecoder is TwoChDecoder.DolbyPl2xMovie
assert z.puredirmode is PureDirMode.OFF
assert z.dirmode is DirMode.ON

for scene_id in range(1, NUM_SCENES + 1):
assert getattr(z, f"scene{scene_id}name") == f"Scene name {scene_id}"
Expand Down Expand Up @@ -474,6 +478,19 @@ def test_puredirmode(connection, initialized_zone: ZoneBase):
connection.send_protocol_message(SUBUNIT, "PUREDIRMODE", "Off")
assert initialized_zone.puredirmode == PureDirMode.OFF

def test_dirmode(connection, initialized_zone: ZoneBase):
# Writing to device
initialized_zone.dirmode = DirMode.ON
connection.put.assert_called_with(SUBUNIT, "DIRMODE", "On")
initialized_zone.dirmode = DirMode.OFF
connection.put.assert_called_with(SUBUNIT, "DIRMODE", "Off")

# Updates from device
connection.send_protocol_message(SUBUNIT, "DIRMODE", "On")
assert initialized_zone.dirmode == DirMode.ON
connection.send_protocol_message(SUBUNIT, "DIRMODE", "Off")
assert initialized_zone.dirmode == DirMode.OFF


def test_initvolmode(connection, initialized_zone: ZoneBase):
# Writing to device
Expand Down
2 changes: 2 additions & 0 deletions ynca/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
BandDab,
BandTun,
DabPreset,
DirMode,
Enhancer,
FmPreset,
HdmiOut,
Expand Down Expand Up @@ -60,6 +61,7 @@
"BandDab",
"BandTun",
"DabPreset",
"DirMode",
"Enhancer",
"FmPreset",
"HdmiOut",
Expand Down
12 changes: 12 additions & 0 deletions ynca/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,18 @@ def _missing_(cls, value):
UNKNOWN = UNKNOWN_STRING
"""Unknown values in the enum are mapped to UNKNOWN"""

@unique
class DirMode(Enum):
ON = "On"
OFF = "Off"

@classmethod
def _missing_(cls, value):
logger.warning("Unknown value '%s' in %s", value, cls.__name__)
return cls.UNKNOWN

UNKNOWN = UNKNOWN_STRING
"""Unknown values in the enum are mapped to UNKNOWN"""
mvdwetering marked this conversation as resolved.
Show resolved Hide resolved

@unique
class Enhancer(str, Enum):
Expand Down
1 change: 1 addition & 0 deletions ynca/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def put_data(self, subunit, function, new_value):
"DTSDIALOGUECONTROL",
"SPEAKERA",
"SPEAKERB",
"DIRMODE",
],
"METAINFO": ["ARTIST", "ALBUM", "SONG", "TRACK", "CHNAME"],
"RDSINFO": ["RDSPRGTYPE", "RDSPRGSERVICE", "RDSTXTA", "RDSTXTB", "RDSCLOCK"],
Expand Down
46 changes: 28 additions & 18 deletions ynca/subunits/zone.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,15 @@

from ..constants import Subunit
from ..converters import EnumConverter, FloatConverter, MultiConverter, StrConverter
from ..function import (
Cmd,
EnumFunctionMixin,
EnumOrFloatFunctionMixin,
FloatFunctionMixin,
IntFunctionMixin,
StrFunctionMixin,
)
from ..enums import (
AdaptiveDrc,
DirMode,
Enhancer,
HdmiOut,
InitVolLvl,
InitVolMode,
Input,
Mute,
AdaptiveDrc,
Enhancer,
PureDirMode,
Pwr,
PwrB,
Expand All @@ -34,6 +27,14 @@
ZoneBAvail,
ZoneBMute,
)
from ..function import (
Cmd,
EnumFunctionMixin,
EnumOrFloatFunctionMixin,
FloatFunctionMixin,
IntFunctionMixin,
StrFunctionMixin,
)
from ..helpers import number_to_string_with_stepsize
from ..subunit import SubunitBase
from . import PlaybackFunctionMixin
Expand All @@ -44,6 +45,7 @@
def raiser(ex: Type[Exception]):
raise ex


def do_vol_up(self, step_size: float, function: str):
"""
Increase the volume with given stepsize.
Expand All @@ -54,6 +56,7 @@ def do_vol_up(self, step_size: float, function: str):
value = "Up {} dB".format(step_size)
self._put(function, value)


def do_vol_down(self, step_size: float, function: str):
"""
Decrease the volume with given stepsize.
Expand All @@ -65,13 +68,13 @@ def do_vol_down(self, step_size: float, function: str):
self._put(function, value)



class ZoneBase(PlaybackFunctionMixin, SubunitBase):

# BASIC gets a lot of attribute like PWR, SLEEP, VOL, MUTE, INP, STRAIGHT, ENHANCER, SOUNDPRG and more
# Use it to significantly reduce the amount of commands to send

adaptivedrc = EnumFunctionMixin[AdaptiveDrc](AdaptiveDrc)
dirmode = EnumFunctionMixin[DirMode](DirMode, init="BASIC")
enhancer = EnumFunctionMixin[Enhancer](Enhancer)
hdmiout = EnumFunctionMixin[HdmiOut](HdmiOut)
hpbass = FloatFunctionMixin(
Expand Down Expand Up @@ -99,29 +102,32 @@ class ZoneBase(PlaybackFunctionMixin, SubunitBase):
inp = EnumFunctionMixin[Input](Input, init="BASIC")

lipsynchdmiout1offset = IntFunctionMixin()

def lipsynchdmiout1offset_down(self):
"""
Increase by 1 step (=1 ms).
"""
self._put("LIPSYNCHDMIOUT1OFFSET", "Down")

def lipsynchdmiout1offset_up(self):
"""
Decrease by 1 step (=1 ms).
"""
self._put("LIPSYNCHDMIOUT1OFFSET", "Up")

lipsynchdmiout2offset = IntFunctionMixin()

def lipsynchdmiout2offset_down(self):
"""
Increase by 1 step (=1 ms).
"""
self._put("LIPSYNCHDMIOUT2OFFSET", "Down")

def lipsynchdmiout2offset_up(self):
"""
Decrease by 1 step (=1 ms).
"""
self._put("LIPSYNCHDMIOUT2OFFSET", "Up")
mvdwetering marked this conversation as resolved.
Show resolved Hide resolved


maxvol = FloatFunctionMixin(
converter=MultiConverter(
Expand All @@ -137,7 +143,9 @@ def lipsynchdmiout2offset_up(self):
),
)
mute = EnumFunctionMixin[Mute](Mute, init="BASIC")
puredirmode = EnumFunctionMixin[PureDirMode](PureDirMode) # Not part of BASIC on RX-V1067
puredirmode = EnumFunctionMixin[PureDirMode](
PureDirMode
) # , init="BASIC") # Not in BASIC on RX-V1067
pwr = EnumFunctionMixin[Pwr](Pwr, init="BASIC")
scene1name = StrFunctionMixin(Cmd.GET, init="SCENENAME")
scene2name = StrFunctionMixin(Cmd.GET, init="SCENENAME")
Expand Down Expand Up @@ -167,7 +175,9 @@ def lipsynchdmiout2offset_up(self):
threedcinema = EnumFunctionMixin[ThreeDeeCinema](
ThreeDeeCinema, name_override="3DCINEMA"
)
twochdecoder = EnumFunctionMixin[TwoChDecoder](TwoChDecoder, name_override="2CHDECODER")
twochdecoder = EnumFunctionMixin[TwoChDecoder](
TwoChDecoder, name_override="2CHDECODER"
)
vol = FloatFunctionMixin(
converter=FloatConverter(
to_str=lambda v: number_to_string_with_stepsize(v, 1, 0.5)
Expand All @@ -181,7 +191,7 @@ def scene(self, scene_id: int | str):
self._put("SCENE", f"Scene {scene_id}")

def vol_up(self, step_size: float = 0.5):
do_vol_up(self, step_size = step_size, function="VOL")
do_vol_up(self, step_size=step_size, function="VOL")

def vol_down(self, step_size: float = 0.5):
do_vol_down(self, step_size, function="VOL")
Expand All @@ -193,8 +203,8 @@ class Main(ZoneBase):
# ZoneA/B only exists as "subzones" on the main subunit

# Speaker A/B are in BASIC on RX-V583, but are not on RX-V573 it seems
speakera = EnumFunctionMixin[SpeakerA](SpeakerA) #, init="BASIC")
speakerb = EnumFunctionMixin[SpeakerB](SpeakerB) #, init="BASIC")
speakera = EnumFunctionMixin[SpeakerA](SpeakerA) # , init="BASIC")
speakerb = EnumFunctionMixin[SpeakerB](SpeakerB) # , init="BASIC")

pwrb = EnumFunctionMixin[PwrB](PwrB, init="BASIC")

Expand Down