~martijnbraam/openatem

docs and misc protocol features v1 APPLIED

Thanks for a nice tool!

Jan Kundrát (5):
  docs: fix a copy-paste error for AUTO transition
  docs: more info on multiview configuration
  docs: InPr: clarify multiview output type
  Some sources are not available on both AUX1 and AUX2
  Implement reading of headphone monitoring: FMHP and FAMS

 pyatem/command.py  |  2 +-
 pyatem/field.py    | 92 +++++++++++++++++++++++++++++++++++++++++++++-
 pyatem/protocol.py |  2 +
 3 files changed, 94 insertions(+), 2 deletions(-)

-- 
2.33.0
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~martijnbraam/openatem/patches/26225/mbox | git am -3
Learn more about email & git

[PATCH 1/5] docs: fix a copy-paste error for AUTO transition Export this patch

Signed-off-by: Jan Kundrát <jkt@jankundrat.com>
---
 pyatem/command.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyatem/command.py b/pyatem/command.py
index 907fa69..1562e9a 100644
--- a/pyatem/command.py
+++ b/pyatem/command.py
@@ -37,7 +37,7 @@ class CutCommand(Command):

class AutoCommand(Command):
    """
    Implementation of the `DAut` command. This is equivalent to pressing the CUT button in the UI
    Implementation of the `DAut` command. This is equivalent to pressing the AUTO button in the UI

    ====== ==== ====== ===========
    Offset Size Type   Description
-- 
2.33.0

[PATCH 2/5] docs: more info on multiview configuration Export this patch

Signed-off-by: Jan Kundrát <jkt@jankundrat.com>
---
 pyatem/field.py | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/pyatem/field.py b/pyatem/field.py
index 2277483..7c60605 100644
--- a/pyatem/field.py
+++ b/pyatem/field.py
@@ -2042,6 +2042,39 @@ class MultiviewerInputField(FieldBase):
    5      1    bool   Supports enabling the safe area overlay
    6      2    ?      unknown
    ====== ==== ====== ===========

    Window numbering differs between switcher families. For example, on Atem
    Mini Extreme, windows are numbered on a row-by-row basis, starting at upper
    left. If a quadrant is not split, it gets the number of its upper left
    mini-window. This is an example of a layout on Atem Mini Extreme:

     +----+----+---------+
     |  0 |  1 |    2    |
     |  4 |  5 |         |
     +----+----+----+----+
     |    8    | 10 | 11 |
     |         | 14 | 15 |
     +---------+----+----+

    On the non-Extreme Mini switchers, the window layout does not appear to be
    configurable, and therefore the numbers are allocated on a contiguous
    basis:

     +----+----+---------+
     |  0      |    1    |
     +----+----+----+----+
     |  2 |  3 |  4 |  5 |
     +----+----+----+----+
     |  6 | 7? | 8? | 9? |
     +----+----+----+----+

    Since the windows marked '?' are not configurable on non-Extreme Minis,
    these numbers are just an educated guess.

    Audio VU meters appear to be supported on small and big windows alike, but
    only on those which show a video input or the Program output. The safe area
    overlay appears to only work on full-sized Preview.

    """

    CODE = "MvIn"
-- 
2.33.0

[PATCH 3/5] docs: InPr: clarify multiview output type Export this patch

I'm seeing that particular port type not just for the Multiview output
from the ME, and also for the "status displays" (audio, recording,
streaming).  Tested on the Atem Mini Extreme and Atem Mini Pro.

Signed-off-by: Jan Kundrát <jkt@jankundrat.com>
---
 pyatem/field.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyatem/field.py b/pyatem/field.py
index 7c60605..7130cea 100644
--- a/pyatem/field.py
+++ b/pyatem/field.py
@@ -279,7 +279,7 @@ class InputPropertiesField(FieldBase):
    7     passthrough
    128   M/E output
    129   AUX output
    131   Multiview output
    131   Multiview output, or a dedicated status window (audio, recording, streaming)
    ===== =========

    ===== ===============
-- 
2.33.0

[PATCH 4/5] Some sources are not available on both AUX1 and AUX2 Export this patch

The Atem Mini Extreme has got two AUX outputs ("HDMI OUT 1" and "HDMI
OUT 2"). Two of the inputs, HDMI1 and HDMI2, support a special "direct
mode" where they can be passed through to an HDMI output at a lower
latency (perhaps just via a HDMI retimer?). This is similar to the
original Atem Mini series where this was only supported for HDMI1. Now,
on the Extreme, HDMI1 can be low-latency-put to HDMI OUT 1, and the
HDMI2 can be passed through to HDMI OUT 2. This is a problem because the
code would not know the difference, and there was apparently just one
bit for the "can be sent to AUX" flag.

The catch is that on the Atem Mini Pro at least, the "can be sent to
HDMI OUT 1" bit is always 0, even on the newest FW. On the Atem Mini
Extreme, I have not seen any source with available_aux == 1 and
available_aux1 == available_aux2 == 0. The only sources where
available_aux1 != available_aux2 are the DIR1 and DIR2 for the direct
pass-through.

Signed-off-by: Jan Kundrát <jkt@jankundrat.com>
---
 pyatem/field.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/pyatem/field.py b/pyatem/field.py
index 7130cea..67e03af 100644
--- a/pyatem/field.py
+++ b/pyatem/field.py
@@ -314,6 +314,8 @@ class InputPropertiesField(FieldBase):
    :ivar available_supersource_art: Source can be routed to supersource
    :ivar available_supersource_box: Source can be routed to supersource
    :ivar available_key_source: Source can be used as keyer key source
    :ivar available_aux1: Source can be sent to AUX1 (Extreme only)
    :ivar available_aux2: Source can be sent to AUX2 (Extreme only)
    :ivar available_me1: Source can be routed to M/E 1
    :ivar available_me2: Source can be routed to M/E 2
    """
@@ -347,6 +349,8 @@ class InputPropertiesField(FieldBase):
        self.available_supersource_art = fields[11] & (1 << 2) != 0
        self.available_supersource_box = fields[11] & (1 << 3) != 0
        self.available_key_source = fields[11] & (1 << 4) != 0
        self.available_aux1 = fields[11] & (1 << 5) != 0
        self.available_aux2 = fields[11] & (1 << 6) != 0

        self.available_me1 = fields[12] & (1 << 0) != 0
        self.available_me2 = fields[12] & (1 << 1) != 0
-- 
2.33.0

[PATCH 5/5] Implement reading of headphone monitoring: FMHP and FAMS Export this patch

Signed-off-by: Jan Kundrát <jkt@jankundrat.com>
---
 pyatem/field.py    | 53 ++++++++++++++++++++++++++++++++++++++++++++++
 pyatem/protocol.py |  2 ++
 2 files changed, 55 insertions(+)

diff --git a/pyatem/field.py b/pyatem/field.py
index 67e03af..d2cd92f 100644
--- a/pyatem/field.py
+++ b/pyatem/field.py
@@ -1560,6 +1560,59 @@ class FairlightTallyField(FieldBase):
        return '<fairlight-tally {}>'.format(self.tally)


class FairlightHeadphonesField(FieldBase):
    """
    Data from the `FMHP`, phones output volume and mute

    This doesn't get triggered when soloing channels.

    ====== ==== ====== ===========
    Offset Size Type   Descriptions
    ====== ==== ====== ===========
    0      4    i32    Volume in 0.01 dB (-60.00 to +6.00 dB)
    5      4    ?      Unknown
    8      1    bool   Muted (0) / Umuted (1)
    9      1    u8     Last soloed channel (just the main part)
    10     22   ?      Unknown

    """

    def __init__(self, raw):
        self.raw = raw
        self.volume, self.unmuted = struct.unpack('> i 4x ? 23x', raw)

    def __repr__(self):
        return '<fairlight-headphones volume={} unmuted={}>'.format(self.volume, self.unmuted)


class FairlightSoloField(FieldBase):
    """
    Data from the `FAMS`, soloing channels to phones

    ====== ==== ====== ===========
    Offset Size Type   Descriptions
    ====== ==== ====== ===========
    0      1    bool   Anything soloed?
    1      7    ?      Unknown
    8      1    u8     Unknown: 0x00 for HDMI channels, 0x05 for 3.5mm jack
    9      1    u8     Soloed channel (main)
    10     12   ?      Unknown
    22     1    u8     No subchannels (0x01), split into L/R (0xff)
    23     1    u8     Soloed channel (subchannel)

    """

    def __init__(self, raw):
        self.raw = raw
        self.solo, self.channel, self.is_split_lr, self.subchannel = struct.unpack('> ? 8x B 12x BB', raw)

    def __repr__(self):
        return '<fairlight-solo active={} source={}>'.format(
            self.solo,
            self.channel if self.is_split_lr == 0x01 else '{}.{}'.format(self.channel, self.subchannel),
        )


class AtemEqBandPropertiesField(FieldBase):
    """
    Data from the `AEBP` field. This encodes the EQ settings in the fairlight mixer. For every channel there will
diff --git a/pyatem/protocol.py b/pyatem/protocol.py
index 2ee2b86..bf1be27 100644
--- a/pyatem/protocol.py
+++ b/pyatem/protocol.py
@@ -124,6 +124,8 @@ class AtemProtocol:
            'AMTl': 'audio-mixer-tally',
            'FASP': 'fairlight-strip-properties',
            'FAMP': 'fairlight-master-properties',
            'FMHP': 'fairlight-headphones',
            'FAMS': 'fairlight-solo',
            '_TlC': 'tally-config',
            'TlIn': 'tally-index',
            'TlSr': 'tally-source',
-- 
2.33.0