mvrdevelopment / spec

DIN SPEC 15800 General Device Type Format (GDTF) and My Virtual Rig (MVR) File Format description DIN SPEC 15801
64 stars 13 forks source link

Forbid Nonsensical ChannelFunctions #77

Open Firionus opened 3 years ago

Firionus commented 3 years ago

Summary

The DIN 15800:2020-07 (GDTF 1.1) allows ChannelFunctions that are nonsensical because some ChannelFunctions may provide different values for the same attribute. This should be prohibited by the standard.

When is a DMXMode sensible?

A real fixture will take some DMX input and act on it.

GDTF attempts to describe the relationship between DMX input and what the fixture does. It does this with a simplified representation of the real world, namely the fixture is broken down into a Geometry tree where each Geometry can have Attributes. Attributes have a numeric value. This value can also be undefined. For example when Gobo1 continuously rotates, Gobo1PosRotate is defined as the angular speed but Gobo1Pos is undefined. (You may say it continuously changes, but GDTF currently doesn't allow us to integrate rotational speed over time, so it's undefined. )

To put it a bit more mathematically, there is

The GDTF DMXMode describes a mapping from each DMX input to a fixture state, or mathematically: A GDTF DMXMode should describe a function f : D -> R (named f because it is what the fixture does in the real world). In that case, for every element dD there is exactly one rR where f (d)=r.

If this mapping/function exists, I'll call a DMXMode sensible. If such a function does not exist the DMXMode is nonsensical. This only happens when a DMX input maps to two different fixture states. The case where a DMX input maps to no fixture state is impossible because if a DMX input maps to nothing, it just means that all attribute values are undefined, which is a valid state.

Example 1: Nonsensical ChannelFunctions

The following could be part of a valid GDTF file according to DIN 15800:2020-07:

<LogicalChannel Attribute="XYZ_X">
    <ChannelFunction Attribute="XYZ_X" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1"/>
    <ChannelFunction Attribute="XYZ_X" DMXFrom="0/1" Default="0/1" PhysicalFrom="1" PhysicalTo="0"/>
</LogicalChannel>

This is nonsensical because the DMX value 0/1 could map to [XYZ_X = 1] or [XYZ_X = 0].

You may say that there should be no ChannelFunctions that control the same Attribute of the same Geometry. There are cases where that is needed though:

Example 2: Crazy Effect Selection

Consider a (horribly designed) fixture that has 3 DMX channels for effects:

That behavior can only be modelled if we allow multiple ChannelFunctions with the same Geometry and Attribute:

<DMXChannel DMXBreak="1" Offset="1" InitialFunction="base_Effects1.Effects1.Effects1 1" Geometry="base">
    <LogicalChannel Attribute="Effects1">
        <ChannelFunction Attribute="Effects1" DMXFrom="0/1" Default="0/1">
            <ChannelSet DMXFrom="0/1" Name="Effect 1" PhysicalFrom="1" PhysicalTo="1"/>
            <ChannelSet DMXFrom="128/1" Name="Effect 2" PhysicalFrom="2" PhysicalTo="2"/>
        </ChannelFunction>
    </LogicalChannel>
</DMXChannel>
<DMXChannel DMXBreak="1" Offset="2" InitialFunction="base_Effects1Rate.Effects1Rate.Effects1Rate 1" Geometry="base">
    <LogicalChannel Attribute="Effects1Rate">
        <ChannelFunction Attribute="Effects1Rate" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1" ModeTo="127/1"/>
        <ChannelFunction Attribute="Effects1Fade" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="128/1" ModeMaster="base_Effects1" ModeTo="255/1"/>
    </LogicalChannel>
</DMXChannel>
<DMXChannel DMXBreak="1" Offset="3" InitialFunction="base_Effects1Fade.Effects1Fade.Effects1Fade 1" Geometry="base">
    <LogicalChannel Attribute="Effects1Fade">
        <ChannelFunction Attribute="Effects1Fade" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1" ModeTo="127/1"/>
        <ChannelFunction Attribute="Effects1Rate" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="128/1" ModeMaster="base_Effects1" ModeTo="255/1"/>
    </LogicalChannel>
</DMXChannel>

Solution 1

The GDTF standard should prohibit ChannelFunctions that control the same Attribute of the same Geometry at the same time.

Example:


In a given DMXMode, no more than one ChannelFunction must control the same Attribute of the same Geometry at a time. This mutual exclusivity can be achieved through mutually exclusive DMX values inside a DMXChannel or through properly set ModeMaster.


The issue with adding such a restriction to the standard is that is not trivial to check whether a DMXMode fulfils this property. This makes the standard hard to understand when one does not have a good understanding of the principles GDTF offers for mutual exclusivity. Therefore such an abstract requirement is a potential source of bugs in implementations.

I'll try to outline what is needed to validate mutual exclusivity of ChannelFunctions:

GDTF has one basic principle for mutual exclusivity, which is the DMX ranges inside a DMXChannel which may or may not overlap for ChannelFunctions. The secondary mechanism for mutual exclusion is the ModeMaster and whether ModeFrom/ModeTo overlap. To prove that two ChannelFunctions are mutually exclusive one has to do the equivalent of building a full dependency tree of ModeMasters. A first draft for an algorithm may look something like this:

WARNING the following may still contain logic errors

The thought of having to implement such an algorithm in XPath to add it to the Schematron File makes me shiver. It would probably be possible though as that ModeMaster Tree Structure sounds like something that is representable in XML.

But I'd definitely prefer the next solution:

Solution 2

Be more restrictive, but simpler to validate, in the standard:


In a given DMXMode, all ChannelFunctions controlling the same Attribute of the same Geometry (given by their enclosing DMXChannel) must either

OR


This proposed restriction only allows a subset of the previous solution, but can be validated without building a full ModeMaster dependency tree.

As an example of something that would be valid with Solution 1 but not with Solution 2, consider a different version of Example 2 where Rate and Fade are replaced by Control1 and Control2 and the Effect switching is done with ChannelFunctions Effects1 and Effects2.

<DMXChannel DMXBreak="1" Offset="1" InitialFunction="base_Effects1.Effects1.Effects1 1" Geometry="base">
    <LogicalChannel Attribute="Effects1">
        <ChannelFunction Attribute="Effects1" DMXFrom="0/1" Default="0/1"/>
        <ChannelFunction Attribute="Effects2" DMXFrom="128/1" Default="0/1"/>
    </LogicalChannel>
</DMXChannel>
<DMXChannel DMXBreak="1" Offset="2" InitialFunction="base_Control1.Control1.Control1 1" Geometry="base">
    <LogicalChannel Attribute="Control1">
        <ChannelFunction Attribute="Control1" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1.Effects1.Effects1 1" ModeTo="255/1"/>
        <ChannelFunction Attribute="Control2" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1.Effects1.Effects2 2" ModeTo="255/1"/>
    </LogicalChannel>
</DMXChannel>
<DMXChannel DMXBreak="1" Offset="3" InitialFunction="base_Control2.Control2.Control2 1" Geometry="base">
    <LogicalChannel Attribute="Control2">
        <ChannelFunction Attribute="Control2" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1.Effects1.Effects1 1" ModeTo="255/1"/>
        <ChannelFunction Attribute="Control1" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1.Effects1.Effects2 2" ModeTo="255/1"/>
    </LogicalChannel>
</DMXChannel>

Why would this be invalid with Solution 2? The ChannelFunctions base_Control1.Control1.Control1 1 and base_Control2.Control2.Control1 2 control the same attribute of the same Geometry. They are not in the same DMXChannel, so the first condition is not met. They both define a ModeMaster, but not the same one so the second condition is also false. Validation would fail even though the Description is "sensible" because ModeMaster defined by both clashing ChannelFunctions are themselves mutually exclusive due to their non-overlapping DMX Ranges in Channel 1. But in order for validation to prove that, we would have to recursively check the exclusion properties (because the ModeMasters can again have other ModeMasters which must be proven to be mutually exclusive, and so on...). This is what I mean when I say: We'd have to build a full ModeMaster dependency tree. Considering the complexity involved, I think we should disallow such ModeMaster structures.

Please note that "nested" architectures, where a ModeMaster depends on a ChannelFunction which again has a ModeMaster, are still possible with Solution 2. The only thing that is prohibited is to do the switching between multiple ChannelFunctions with the same Geometry and Attribute with more than one ChannelFunction. Instead, that kind of switching would have to happen inside one ChannelFunction or DMXChannel based on DMX value.

I think this is a small price to pay in order to have a relatively simple to understand rule that ensures GDTF files are "sensible" in the sense that they unambiguously map DMX values to fixture state.

moritzstaffel commented 3 years ago

Thanks for your involvement in GDTF. I will have a look on your text now :)

moritzstaffel commented 3 years ago

This Channel Usage is only valid if you use Modemasters.

<LogicalChannel Attribute="XYZ_X">
    <ChannelFunction Attribute="XYZ_X" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1"/>
    <ChannelFunction Attribute="XYZ_X" DMXFrom="0/1" Default="0/1" PhysicalFrom="1" PhysicalTo="0"/>
</LogicalChannel>

Modemasters here define that based if another channel function / Dmx Channel is in a specific range, only then the channel function gets active.

I think we missed this in the GDTF Spec to make more clear. The same applies to Channel Sets. Also even when the Attributes would be different, you would not allow this. That's why we have the additional attributes proposal for a channel function.

moritzstaffel commented 3 years ago

And yes this would be also not allowed. The builder currently only checks that the logical channel is not using the same attribute, but you are right here.

<DMXChannel DMXBreak="1" Offset="1" InitialFunction="base_Effects1.Effects1.Effects1 1" Geometry="base">
    <LogicalChannel Attribute="Effects1">
        <ChannelFunction Attribute="Effects1" DMXFrom="0/1" Default="0/1"/>
        <ChannelFunction Attribute="Effects2" DMXFrom="128/1" Default="0/1"/>
    </LogicalChannel>
</DMXChannel>
<DMXChannel DMXBreak="1" Offset="2" InitialFunction="base_Control1.Control1.Control1 1" Geometry="base">
    <LogicalChannel Attribute="Control1">
        <ChannelFunction Attribute="Control1" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1.Effects1.Effects1 1" ModeTo="255/1"/>
        <ChannelFunction Attribute="Control2" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1.Effects1.Effects2 2" ModeTo="255/1"/>
    </LogicalChannel>
</DMXChannel>
<DMXChannel DMXBreak="1" Offset="3" InitialFunction="base_Control2.Control2.Control2 1" Geometry="base">
    <LogicalChannel Attribute="Control2">
        <ChannelFunction Attribute="Control2" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1.Effects1.Effects1 1" ModeTo="255/1"/>
        <ChannelFunction Attribute="Control1" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1.Effects1.Effects2 2" ModeTo="255/1"/>
    </LogicalChannel>
</DMXChannel>
Firionus commented 3 years ago

This Channel Usage is only valid if you use Modemasters.

<LogicalChannel Attribute="XYZ_X">
    <ChannelFunction Attribute="XYZ_X" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1"/>
    <ChannelFunction Attribute="XYZ_X" DMXFrom="0/1" Default="0/1" PhysicalFrom="1" PhysicalTo="0"/>
</LogicalChannel>

[...]

I think we missed this in the GDTF Spec to make more clear. The same applies to Channel Sets.

I'm pretty certain there is nothing in the standard (DIN 15800:2020-07) that prohibits that example (please prove me wrong), so this shouldn't be a clarification issue - it is about adding restrictions that didn't exist before.

Also even when the Attributes would be different, you would not allow this.

Yes you would, because I'm pretty sure it conforms to DIN 15800:2020-07 (again, please prove me wrong with a quote of the DIN).

That's why we have the additional attributes proposal for a channel function.

Where can I track that?

And yes this would be also not allowed. The builder currently only checks that the logical channel is not using the same attribute, but you are right here.

<DMXChannel DMXBreak="1" Offset="1" InitialFunction="base_Effects1.Effects1.Effects1 1" Geometry="base">
    <LogicalChannel Attribute="Effects1">
        <ChannelFunction Attribute="Effects1" DMXFrom="0/1" Default="0/1"/>
        <ChannelFunction Attribute="Effects2" DMXFrom="128/1" Default="0/1"/>
    </LogicalChannel>
</DMXChannel>
<DMXChannel DMXBreak="1" Offset="2" InitialFunction="base_Control1.Control1.Control1 1" Geometry="base">
    <LogicalChannel Attribute="Control1">
        <ChannelFunction Attribute="Control1" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1.Effects1.Effects1 1" ModeTo="255/1"/>
        <ChannelFunction Attribute="Control2" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1.Effects1.Effects2 2" ModeTo="255/1"/>
    </LogicalChannel>
</DMXChannel>
<DMXChannel DMXBreak="1" Offset="3" InitialFunction="base_Control2.Control2.Control2 1" Geometry="base">
    <LogicalChannel Attribute="Control2">
        <ChannelFunction Attribute="Control2" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1.Effects1.Effects1 1" ModeTo="255/1"/>
        <ChannelFunction Attribute="Control1" DMXFrom="0/1" Default="0/1" PhysicalFrom="0" PhysicalTo="1" ModeFrom="0/1" ModeMaster="base_Effects1.Effects1.Effects2 2" ModeTo="255/1"/>
    </LogicalChannel>
</DMXChannel>

My whole point is that the quoted example conforms to the DIN 15800:2020-07. Why would it not be allowed (quote DIN please)? Where am I right exactly?