diff --git a/src/lib/par/disposition.hpp b/src/lib/par/disposition.hpp new file mode 100644 index 000000000..6ee6e5718 --- /dev/null +++ b/src/lib/par/disposition.hpp @@ -0,0 +1,51 @@ +/* + DISPOSITION.hpp - actual constitution of a parameter descriptor + + Copyright (C) + 2026 Hermann Vosseler + +  **Lumiera** is free software; you can redistribute it and/or modify it +  under the terms of the GNU General Public License as published by the +  Free Software Foundation; either version 2 of the License, or (at your +  option) any later version. See the file COPYING for further details. + +*/ + + +/** @file disposition.hpp + ** Concrete configuration of a parameter descriptor with type and value provision. + ** This is the full definition, with all details spelled out, and what is actually + ** stored within the _outer shell_ of a Parameter. The publicly visible interface + ** of the latter is implemented by delegating to the constituents of the disposition. + ** + ** @todo WIP-WIP-WIP can be considered an initial draft and placeholder, as of 2026 + */ + + +#ifndef LIB_PAR_DISPOSITION_H +#define LIB_PAR_DISPOSITION_H + + +#include "lib/par/domain.hpp" +#include "lib/par/provision.hpp" + + +namespace lib { +namespace par { + + + + /** + * A complete configuration and setup of a parameter, including a type specification + * with domain and scale, and a value provision. Can be generated through a builder + * notation and stored within the Parameter object (as a container). + */ + class Disposition + { + public: + }; + + + +}} // namespace lib::par +#endif /*LIB_PAR_DISPOSITION_H*/ diff --git a/src/lib/par/param-type.cpp b/src/lib/par/param-type.cpp index 69ba479ce..1cef924c7 100644 --- a/src/lib/par/param-type.cpp +++ b/src/lib/par/param-type.cpp @@ -1,5 +1,5 @@ /* - ParamType - parameter scale and type descriptor + ParamType - parameter type record including domain and scale Copyright (C) 2026 Hermann Vosseler diff --git a/src/lib/par/param-type.hpp b/src/lib/par/param-type.hpp index 2a1ff834e..e3326fffd 100644 --- a/src/lib/par/param-type.hpp +++ b/src/lib/par/param-type.hpp @@ -1,5 +1,5 @@ /* - PARAM-TYPE.hpp - parameter scale and type descriptor + PARAM-TYPE.hpp - parameter type record including domain and scale Copyright (C) 2026 Hermann Vosseler @@ -37,7 +37,8 @@ namespace par { /** * Interface: represent a specific configuration of parameter value type, * range and scale. Every ParamType descriptor is also a _prototype_ and has - * an unique identity, ensured by registration, so that it acts as a type identifier. + * an unique identity, ensured by registration, so that it acts as a type identifier. + * @todo RLY? registration?? * Furthermore, the interface exposes allowed conversion and conforming operations. */ class ParamType diff --git a/src/lib/par/parameter.hpp b/src/lib/par/parameter.hpp index beca8d46e..27b604c57 100644 --- a/src/lib/par/parameter.hpp +++ b/src/lib/par/parameter.hpp @@ -13,7 +13,13 @@ /** @file parameter.hpp - ** A generic type value that can be discovered and automated. + ** A generic typed value that can be discovered and automated. + ** The actual data type of the parameter is an opaque implementation detail, + ** yet value ranges and conversions are handled automatically. It is thus + ** both a descriptor and an opaque container. Parameter elements can be copied, + ** yet the presence of some specific parameter at a given point in the model + ** constitutes an identity -- and the parameter descriptor can be tagged + ** with that identity. ** ** @todo this is a draft and placeholder, as of 2026 */ diff --git a/src/lib/par/provision.hpp b/src/lib/par/provision.hpp new file mode 100644 index 000000000..405078d05 --- /dev/null +++ b/src/lib/par/provision.hpp @@ -0,0 +1,53 @@ +/* + PROVISION.hpp - determine how a parameter's value is given + + Copyright (C) + 2026 Hermann Vosseler + +  **Lumiera** is free software; you can redistribute it and/or modify it +  under the terms of the GNU General Public License as published by the +  Free Software Foundation; either version 2 of the License, or (at your +  option) any later version. See the file COPYING for further details. + +*/ + + +/** @file provision.hpp + ** Provide access to a parameter's value, either directly or by automation. + ** Each parameter has a _base value_ and a time-based current value. The latter + ** is retrieved by evaluating an automation function. + ** + ** @todo WIP-WIP-WIP can be considered an initial draft and placeholder, as of 2026 + */ + + +#ifndef LIB_PAR_PROVISION_H +#define LIB_PAR_PROVISION_H + + +#include "lib/par/param-type.hpp" + + +namespace lib { +namespace par { + + + + /** + * Interface: access to a parameter's value, to adjust or evaluate automation. + * Conceptually, the value is decomposed into a _base value_ and possibly a + * time-controlled adjustment (automation). The base value can be retrieved + * and assigned, while the current time-based value is the result of evaluation. + * Any parameter value is associated to a ParamType that defines the underlying + * value domain and possibly a scale with range limits and metric constraints. + */ + class Provision + { + public: + virtual ~Provision(); ///< this is an interface + }; + + + +}} // namespace lib::par +#endif /*LIB_PAR_PROVISION_H*/ diff --git a/src/lib/par/scale.hpp b/src/lib/par/scale.hpp new file mode 100644 index 000000000..85592e7f5 --- /dev/null +++ b/src/lib/par/scale.hpp @@ -0,0 +1,54 @@ +/* + PARAM-TYPE.hpp - value scale to use for parameters + + Copyright (C) + 2026 Hermann Vosseler + +  **Lumiera** is free software; you can redistribute it and/or modify it +  under the terms of the GNU General Public License as published by the +  Free Software Foundation; either version 2 of the License, or (at your +  option) any later version. See the file COPYING for further details. + +*/ + + +/** @file scale.hpp + ** Specification of the allowed value scale of a parameter, including range and metric. + ** The scale descriptor is used as delegate from the ParamType descriptor and maintained + ** within a global registry for sake of deduplication. It is expected that a lot of parameters + ** will share some common scales, like e.g. percentage values or decibels. The setup of a scale + ** may limit the value range, provide hints for the UI representation -- yet may possibly also + ** encompass nominal scales that comprise a selection of ID values. + ** + ** @todo WIP-WIP-WIP can be considered an initial draft and placeholder, as of 2026 + */ + + +#ifndef LIB_PAR_SCALE_H +#define LIB_PAR_SCALE_H + + +#include "lib/par/domain.hpp" + + +namespace lib { +namespace par { + + + + /** + * Interface: describe the properties of a value scale to use for parameters, + * including range limits and metric (linear, logarithmic). The core operation + * is to conform a value to this specific scale. + * @todo not clear if we want a virtual interface here....? + */ + class Scale + { + public: + virtual ~Scale(); ///< this is an interface + }; + + + +}} // namespace lib::par +#endif /*LIB_PAR_SCALE_H*/ diff --git a/tests/lib/par/parameter-domain-test.cpp b/tests/lib/par/parameter-domain-test.cpp index 08aa18916..844c5b642 100644 --- a/tests/lib/par/parameter-domain-test.cpp +++ b/tests/lib/par/parameter-domain-test.cpp @@ -170,6 +170,15 @@ namespace test{ /** @test base function to access the contents of an opaque buffer * with known type, and convert into another target type. + * - the base interface #Domain represents an opaque type + * - it exposes #TypeHandler interfaces for a fixed selection + * of common elementary #BaseTypes + * - here we use a `BaseDomain` as actual implementation, + * yet knowledge regarding the type `int` is erased and any + * access is based solely on a `Domain&` + * - an opaque source ValBuf is passed explicitly + * @remark this covers the value access capability of a + * type handler interface, working on external storage. */ void verify_valueAccess() @@ -204,6 +213,10 @@ namespace test{ /** @test base function to assign a directly given data value * into an opaque buffer with known (yet different) type. + * @remark since the type handler interface covers both reading + * and writing, here the roles are reversed here, so that the + * target of the assignment is the opaque buffer, whose actual + * type remains hidden behind the #Domain interface. */ void verify_valueSetting() diff --git a/tests/lib/par/parameter-provision-test.cpp b/tests/lib/par/parameter-provision-test.cpp new file mode 100644 index 000000000..811ee237d --- /dev/null +++ b/tests/lib/par/parameter-provision-test.cpp @@ -0,0 +1,91 @@ +/* + ParameterProvision(Test) - verify parameter value provision and automation + + Copyright (C) + 2026, Hermann Vosseler + +  **Lumiera** is free software; you can redistribute it and/or modify it +  under the terms of the GNU General Public License as published by the +  Free Software Foundation; either version 2 of the License, or (at your +  option) any later version. See the file COPYING for further details. + +* *****************************************************************/ + +/** @file parameter-provision-test.cpp + ** unit test \ref ParameterProvision_test + */ + + +#include "test/run.hpp" +//#include "test/test-helper.hpp" +#include "lib/par/parameter.hpp" +//#include "lib/format-cout.hpp" + +//#include +//#include +//#include + +//using std::string; +//using std::vector; +//using std::swap; + + +namespace lib { +namespace par { +namespace test{ + +// using lumiera::error::LUMIERA_ERROR_LOGIC; + + namespace {//Test fixture.... + + + }//(End)Test fixture + + + + + + + + + + /**************************************************************************//** + * @test document behaviour of paramter value provision and automation. + */ + class ParameterProvision_test : public Test + { + + virtual void + run (Arg) + { + simpleUsage(); + verify_Value(); + verify_Function(); + } + + + void + simpleUsage() + { + } + + + void + verify_Value() + { + } + + + void + verify_Function() + { + } + }; + + + /** Register this test class... */ + LAUNCHER (ParameterProvision_test, "unit lib"); + + + +}}} // namespace lib::par::test diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 5c1a51f6c..058d10cb7 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -81495,7 +81495,7 @@ - + @@ -81679,6 +81679,8 @@ + + @@ -82020,6 +82022,26 @@ + + + + +

+ das ist ein essentielles Requirement +

+ +
+ + + +

+ nachfolgende Reflexion und die Formulierung des »Routing«-Konzepts hat das deutlich gemacht: Aus Sicht des Users(Film-Editors) würde das einen immer wiederkehrenden Problemfall im Workflow entschärfen; hinzu kommt, daß ein solches Design sauberer kaskadiert und faktorisiert: wir wollen nicht den »globalen Automaten« oben drauf setzen +

+ +
+ + +
@@ -82046,7 +82068,8 @@ - + + @@ -82068,7 +82091,7 @@ - + @@ -82138,6 +82161,44 @@ + + + + + + + + +

+ Bis zu dem Punkt war ich geleitet von der effizienten Verwendung  der Parameter im Code, und hatte eigentlich nur den Value-Zugriff (und die Zuweisungen) im Blick. Dem entsprechend stand im Vordergund, einen Code-Pfad zu ermöglichen, in dem das ganze Typ-System links liegen bleibt und der Code auf einem direkt gegebenen Value arbeitet. Die Typ-IDs waren vor allem von Bedeutung, wenn man Parameter als einen Interface-Deskriptor deutet, also um z.B. dann im GUI korrekt zu rendern. +

+ +
+
+ + + + +

+ In dem Moment aber, wo ich angefangen habe, eine Parameter-Klasse zu konzipieren, ist mir die Festlegung auf einen Inline-Buffer in den Vordergrund gerückt. Ich habe dann Angst bekommen, daß ein aufgeblähter Parameter-Typ sich pervasiv ausbreitet. Das wurde verstärkt durch die Einsicht, daß Parameter eine 2.Ebene im low-Level-Modell darstellen. (Diese Einsicht »dämmert« mir zunehmend, und ich finde das gar nicht so toll, weil sich damit das ganze Konzept mit den Pipelines und Segmenten auflösen könnte) +

+ +
+
+ + + + +

+ ...sobald man sich tatsächlich alle konkreten low-level-Operationen anschaut, und im Besonderen auch an die Cache-locality denkt. Und ja, mir ist komplett klar, daß ich hier im »Abwägungen im lufleeren Raum« mache +

+ +
+
+ + + +
@@ -82243,7 +82304,7 @@ - + @@ -82252,10 +82313,11 @@

+ - + @@ -82460,6 +82522,16 @@ + + + + +

+ Erscheint als guter Kompromiß: die Scale wird nicht so häufig gebraucht, nämlich nur beim akzeptieren neuer Werte; zudem könnte man einen entsprechenden Limiter generieren und in die Kette der Provisions (Datenquellen) einschleifen +

+ +
+
@@ -82486,7 +82558,7 @@
- + @@ -82495,6 +82567,7 @@

+ @@ -82506,7 +82579,7 @@ nochmal zur Erinnerung: bin in dieses ganze Riesen-Thema nur reingeschlittert, weil ich den processKey als Job-Parameter aufgeben mußte (und der war eine so »schöne Lösung«, die das Thema markiert und auf später verschiebt). Dann habe ich gesagt, einen Zacken nachlegen und mal eben ein Design für Parameter machen. Ich weiß aber noch gar nicht, wo genau die Parameter sonst noch eingesetzt werden sollen. Ich weiß nur, daß ich sie universell einsetzen möchte.

- Im Besonderen ist die ganze Auswertung von Parametern komplett ungeklärt. Diese Auswertung passiert irgendwie in Response auf Interaktionen im GUI (vor allem: ändern der Playback-Position, aber natürlich auch direkte Wert-Tweaks). Es ist klar, daß die Auswertung nicht im GUI selber stattfinden wird, denn dafür haben wir die Trennung (die Commands, den UI-Bus und das Event-Sourcing). Wahrscheinlich wird eine Auswertung in einer Projektion der Events passieren, entweder nach einem Builder-Lauf, oder in vielen Fällen anstelle eines Solchen (wenn gar nichts neu gebaut werden muß). Auch der Builder ist ja konzeptionell eine Projektion. Dann aber ist andererseits auch klar, daß Parameter irgendwie in der Render-Engine ausgewerter werden, und zwar dort verpackt in einen Automations-Funktor. Möglicherweise wird diese Auswertung aber auch eine Art compilierte Variante sein. + Im Besonderen ist die ganze Auswertung von Parametern komplett ungeklärt. Diese Auswertung passiert irgendwie in Response auf Interaktionen im GUI (vor allem: ändern der Playback-Position, aber natürlich auch direkte Wert-Tweaks). Es ist klar, daß die Auswertung nicht im GUI selber stattfinden wird, denn dafür haben wir die Trennung (die Commands, den UI-Bus und das Event-Sourcing). Wahrscheinlich wird eine Auswertung in einer Projektion der Events passieren, entweder nach einem Builder-Lauf, oder in vielen Fällen anstelle eines Solchen (wenn gar nichts neu gebaut werden muß). Auch der Builder ist ja konzeptionell eine Projektion. Dann aber ist andererseits auch klar, daß Parameter irgendwie in der Render-Engine ausgewertet werden, und zwar dort verpackt in einen Automations-Funktor. Möglicherweise wird diese Auswertung aber auch eine Art compilierte Variante sein.

@@ -82517,9 +82590,21 @@ + + + + +

+ ....ich halte selbst den Versuch für gefährlich, mich erst mal nicht um Optimierung zu kümmern, sondern die Eigenschaften des Parameters »generisch« zu repräsentieren. Der Grund ist: es dauert Jahre, bis ich da im Stande bin, eine Rückmeldung zu bekommen — und dann hat sich ein mögliches Design bereits festgesetzt und hat sekundäre Konsequenzen hervorgebracht. Wie man es auch dreht und wendet: es gibt keine Metode wie man's »richtig« macht... +

+ + +
- + + + @@ -82561,8 +82646,9 @@ - - + + + @@ -82686,7 +82772,16 @@ - + + + + +

+ ...da die VTable in der Regel als Pointer implementiert wird, also 64bit belegt — somit bricht der Datenpuffer immer schon mal einen weiteren Slot an (selbst wenn man die Datentypen weiter limitieren würde) +

+ +
+
@@ -82739,7 +82834,7 @@ - + @@ -82748,6 +82843,14 @@

+ + + +

+ und somit ist das gesamte (abstrahierte, virtuelle) Verhalten dennoch bereits zur Compile-Zeit festgelegt, und die Laufzeit-Größe einer Instanz beträgt nur 1 «slot» (für die VTable); dennoch gibt es verschiedene (zur Compile-time generierte) Implementierungen, d.h. das virtuelle Interface abstrahiert tatsächlich etwas, das allerdings bereits statisch (zur compile-time) komplett ausformuliert wurde +

+ +
@@ -82759,12 +82862,12 @@ - +

- Jede, wirklich jede Ausprägungs-Variante schlägt sich nieder in Form einiter (deduplizierter) Datenfelder in einem Daten-Segment (private static), sowie einem kompletten Satz an Methoden-Implementierungen im Code-Segment, und einer VTable mit Zeigern auf diese. Muß man eine weitere Methode ins Interface aufnehmen, entsteht sofort ein starker Hebel... + Jede, wirklich jede Ausprägungs-Variante schlägt sich nieder in Form einiger (deduplizierter) Datenfelder in einem Daten-Segment (private static), sowie einem kompletten Satz an Methoden-Implementierungen im Code-Segment, und einer VTable mit Zeigern auf diese. Muß man eine weitere Methode ins Interface aufnehmen, entsteht sofort ein starker Hebel...

@@ -82892,7 +82995,7 @@ - + @@ -82911,19 +83014,19 @@ Experimente mit Varianten

- Es zeigt sich, daß dieses Konstrukt den Compiler in eine komplexe Situation bringt, in der wirklich jedes Detail stimmig sein muß. Im Besonderen kann die Diagnostik komplett irreführend sein; wenn etwas mit der Sichtbarkeit nicht stimmt, kommt es zu einer (verdeckten) Ambiguität, die u.U. (abhängig vom konkreten Typ) automatisch vom Compiler „repariert“ wird (ich meine diese problematischen Regeln, daß z.B. ein unsigned an vielen Stellen geräuschlos auf einen Signed zugewiesen werden kann). Außerdem ist es wichtig, das Pragma zum Unterdrücken von -Woverloaded-virtual bereits vor  dem Template stehen muß, in dem das Shaddowing auftritt (nicht etwa, wie man intuitiv erwarten würde, vor der Verwendung). + Es zeigt sich, daß dieses Konstrukt den Compiler in eine komplexe Situation bringt, in der wirklich jedes Detail stimmig sein muß. Im Besonderen kann die Diagnostik komplett irreführend sein; wenn etwas mit der Sichtbarkeit nicht stimmt, kommt es zu einer (verdeckten) Ambiguität, die u.U. (abhängig vom konkreten Typ) automatisch vom Compiler „repariert“ wird (ich meine diese problematischen Regeln, daß z.B. ein unsigned an vielen Stellen geräuschlos auf einen Signed zugewiesen werden kann). Außerdem ist es wichtig, das Pragma zum Unterdrücken von -Woverloaded-virtual bereits vor dem Template stehen muß, in dem das Shaddowing auftritt (nicht etwa, wie man intuitiv erwarten würde, vor der Verwendung).

- In diesen Experimenten erscheint dann doch das ursprüngliche Baumuster von Alexandrescu die stabilste Lösung zu sein. Also ein multiple-mix-in für das Interface, aber eine Kette für die Implementierung. Das liegt daran, daß dann eine eventuelle Ambiguität beim Aufruf wirklich direkt im Interface passiert, nicht irgendwo in einer Kette; hinzu kommt, daß wir in einer Kette die Sichtbarkeit explizit wieder herstellen müssen durch ein using BAS::functionname; — und das kann weitere Ambiguitäten erzeugen, und erfordert vor allem irgendwo eine catch-all-Definition (z.B. mit leerer Argumentliste). Das ist verwirrend und kann weitere Ambiguitäten erzeugen. + In diesen Experimenten erscheint dann doch das ursprüngliche Baumuster von Alexandrescu die stabilste Lösung zu sein. Also ein multiple-mix-in für das Interface, aber eine Kette für die Implementierung. Das liegt daran, daß dann eine eventuelle Ambiguität beim Aufruf wirklich direkt im Interface passiert, nicht irgendwo in einer Kette; hinzu kommt, daß wir in einer Kette die Sichtbarkeit explizit wieder herstellen müssen durch ein using BAS::functionname; — und das erfordert vor allem irgendwo eine catch-all-Definition (z.B. mit leerer Argumentliste). Das wäre noch verwirrender und kann weitere Ambiguitäten erzeugen.

- Wenn der Compiler irgendwo automatisch (falsch) konvertiert, kann es dann zu völlig verwirrenden anderen Problemen kommen, wie z.B. der Zugriff über eine Referenz auf ein Objekt anderen Typs (was nur mit einer const-Referenz erlaubt ist). + Wenn der Compiler irgendwo automatisch (falsch) konvertiert, kann es dann zu völlig irreführenden sekundären Problemen kommen, wie z.B. der Zugriff über eine Referenz auf ein Objekt anderen Typs (was nur mit einer const-Referenz erlaubt ist).

- Insofern verstehe ich durchaus die Motivation, warum -Woverloaded-virtual  eingeführt wurde; hier gibt es viele Fallen, die einen unerfahren Programmierer vor unlösbare Probleme stellen können + Insofern verstehe ich durchaus die Motivation, warum -Woverloaded-virtual  eingeführt wurde; hier gibt es viele Fallen, die einen unerfahren Programmierer vor unlösbare Probleme stellen können

@@ -82973,12 +83076,12 @@
- +

- ...denn an der Stelle spielt Sichtbarkeit gar keine Rolle mehr, es wird nur eine schon vorhandene Interface-Methode in der VTable auf eine konkrete Implementierung gebunden. Allerdings nur, wenn man tatsächlich das Interface als multiple-mix-in generiert — denn das umgeht das Sichtbarkeits-Problem + ...denn an dieser Stelle in der Hierarchie spielt Sichtbarkeit gar keine Rolle mehr, es wird nur eine schon vorhandene Interface-Methode in der VTable auf eine konkrete Implementierung gebunden. Allerdings nur, wenn man tatsächlich das Interface als multiple-mix-in generiert — denn das umgeht das Sichtbarkeits-Problem (⟶ das ursprüngliche Design von Alexandrescu ist ziemlich clever)

@@ -83425,7 +83528,7 @@ - + @@ -83466,7 +83569,7 @@ - + @@ -83696,6 +83799,483 @@ + + + + + + + +

+ Das Thema mit den Parametern hatte ich aufgemacht zwischen »Maynooth« und der FrOSCon ... und während dem die Recherche zu IO_URING und die Vorbereitung auf das Worflow-Meeting mit Wouter komplett im Vordergrund stand +

+ +
+
+ + + + +

+ ...ohne an jeder Stelle wieder in Reflexionen zu verfallen; der Entwurf sollte das Thema soweit aufschließen, daß man dann, im Anschluß, konkretere Überlegungen zur Performance anstellen können wird... +

+ +
+
+ + + + +

+ ...vorläufig genügt die Beobachtung, daß eine Scale aus einer BaseDomain hervorgeht; und die Wirkung der Scale beschränkt sich auf das Setzen/Ändern von Werten (unter der wichtigen Invariante daß vorliegende Werte »konform« sein müssen). Möglicherweise wird man die Wirkung einer Scale auch direkt in einen Automations-Funktor mit integrieren können. (Überlegung am Rande: mehrere Indirektionen hintereinander profitieren ebenfalls von der Zusammenfassung in eine VTable, selbst ohne monomorphic optimisation — unter der Annahme daß der Cache heiß bleibt) +

+ +
+
+ + + + +

+ könnte nun vom vorläufigen Interface ausgehend skizzieren +

+ +
+ + + + + + + + + +

+ der Deskriptor ist kopierbar und allein durch seine manifesten Eigenschaften bestimmt (was auf Wert-Semantik hindeutet), jedoch enthält ein Parameter manipulierbaren Zustand und bestimmte Instanzen werden per ID referenziert (was auf Referenz-Semantik hindeutet) +

+ +
+
+ + + + +
    +
  • + für sich genommen hat ein solcher Deskriptor Value-Semantik, wobei allerdings einige seiner Eigenschaften aus Verweisen auf Datenquellen besteht (welche für sich eine Identität besitzen). +
  • +
  • + wenn ein solcher Deskriptor aber in einem speziell ausgezeichneten Model als Attribution verwendet wird, nimmt der den Charakter einer Instanz an +
  • +
  • + innerhalb dieses beschreibenden Modell-Kontextes, ist diese Instanz eindeutig (und kann mit einer ID adressiert werden) +
  • +
  • + allerdings gibt es mehrere Kopien dieses Modell-Kontextes als Projektionen, da sich das Modell weiterentwickelt, und außerdem zur Ausführung übersetzt wird +
  • +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

+ Bekanntlich war das mal ein »Experiment nebenbei« aus der Anfangzeit ... das sich dann bei mir im Kopf festgesetzt hat. +

+
    +
  • + es wrid ein »ad hoc« erfundenes Marker-Interface verwendet (obwohl man inzwischen in C++ automatisch feststellen könnte, ob etwas kopierbar / klonbar ist) +
  • +
  • + dann wurde aber wegen diesem Marker-Interface die totale Flexibilität eingeführt, so daß man es letztlich nur optional einsetzen kann (dafür dann aber mit einem dynamic-cast „bezahlt“) +
  • +
  • + dabei habe ich den Verdacht, daß diese ganze Idee mit dem Marker-Interface frei drehend ist, denn letztlich implementiert ja doch bereits der Adapter alles, und delegiert an die Standard-Copy-Operationen +
  • +
  • + zudem ist die Anordnung der verschiedenen Bausteine im Code selber durchaus verwirrend; man hat keine rechte Linie, der man folgen kann +
  • +
  • + abgesehen davon: die Fallunterscheidung ist unvollständig, es gibt genügend Fälle, bei denen wir dann doch in eine nicht-implementierte Operation laufen +
  • +
  • + und später dann hatte ich die gleiche Idee nochmal isoliert als VirtualCopySupport implementiert, und in lib::Variant verwendet +
  • +
+ +
+
+ + + + +

+ dabei geht es aber letztlich nur darum, wie der Copy-Support eingeschleift wird. Denn die eigentliche Implementierung erledigt der PolymorphicValue::Adapter — die Frage der „Kooperation“ läuft darauf hinaus, ob das CopySupport-API direkt auf der Vererbungs-Linie des Implementierungs-Typs gefunden wird, oder ob es über einen Mix-In dazugebaut wird; dem entsprechend ist auch der Adapter anders aufgehängt. +

+ +
+
+ + + + + +

+ da mal mit dem Debugger durchsteppen... dann sieht man was passiert +

+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + +

+ Das ist ein 64bit-Wort, das in sub-Felder aufgeteilt wurde, um alle Typ/Registrierungs-IDs kompakt unterzubringen; jede sub-ID ist Index in eine global-statische Registrierungstabelle +

+ +
+
+ + + + + + + + + + + + + + + + + + + + +

+ bei einer rein-funktionalen Provision wird das nicht möglich sein; wenn dagegen irgendwo ein »Buffer« wäre, dann könnte man dem auch einen Wert zuweisen +

+ +
+
+ + + + +

+ Das heißt.... +

+
    +
  • + konzeptionell gibt es immer einen Buffer +
  • +
  • + der liegt aber im Allgemeinen irgendwo in der Kette +
  • +
  • + wenn man auf eine andere Provision referenziert, und lokal keinen Buffer hat, dann wird der pull() durchgereicht, und das setVal() wirkt auf den Buffer »upstream« +
  • +
+ +
+
+
+ + + + + + + + +

+ weil man sonst für jeden Aufruf einen double-Dispatch bekommt +

+ +
+ +
+ + +
+ + + + + + + + + + + +

+ ...dieser gilt global als der »Wert« des Parameter; eine eventuelle Automations-Anwendung wird immer auf diesen Ankerwert draufgesetzt +

+ +
+
+
+ + + + + + + + +
+ + + + + + + + +

+ das ist eine parametrisierte Subklasse der Domain; daher gibt es nur N BaseDomains (kleine Anzahl), welche allesamt lediglich eine andere VTable definieren, und daher direkt eingeschleift werden können. +

+ +
+ + + +
+ + + + + + + +

+ Wenn sich die Praxis etablieren läßt, die meisten Parameter von einem Prototypen zu erstellen, dann kann man die meiste elaborierte Registrierungs-Logik einfach weglassen! Für einen von grund auf neu definierten Typ wird einfach ein neuer Registry-Eintrag hinzugefügt, wohingegen ein vom Prototypen erstellter Parameter die bestehende Registrierung einfach übernimmt. Scale-Änderungen werden dann CoW. +

+ +
+
+ + + + +

+ wodurch viel zustandsbehaftete Logik wegfällt +

+ +
+
+
+
+ + + + + + + + +

+ selbst im Extermfall erwarte ich nicht mehr als ein paar tausend Scales (vermutlich ehr ein paar hundert); mithin wäre locker Platz für tausende verschiedener Automations-Quellen gegeben +

+ +
+
+ + + + +

+ Und zwar, weil wir es nicht wollen, daß die Engine auf aktuelle Definitionen im Model »durchgreift«. Im Sinne moderner Architekturen und zunehmender Parallelisierung wäre das nicht (mehr) wünschenswert; stattdessen wird jede Änderung durch den Builder propagiert und als eine neue Provision-Instanz realisiert. Das hat zur Konsequenz, daß fortlaufend die nicht mehr benötigten Einträge aufgeräumt werden müssen +

+ +
+
+ + + + + + +

+ Meine erste Einschätzung ist, daß eine Automation typischerweise für genau einen Parameter zum Einsatz kommt; es könnten allerdings mehrere Automationen zusammengeführt werden zu einem Gesamtresultat. Insofern hängt die Zahl der Mehrfachverwendung nur daran, wie häufig Parameter-Deskriptoren im Zuge der normalen Verarbeitung einfach kopiert werden; da sie prinzipiell kopierbar sind, ist ja der springende Punkt daß man darauf gar nicht achten muß +

+ +
+
+ + + + + +

+ Das ist eigentlich eine grundsätzliche Frage: inwiefern können wir uns die Replikation per Segment der Timeline eigentlich »leisten«? Bei den Render-Nodes erscheint das zunächst plausibel, da sich ja (meistens) die Topologie ändert; grundsätzlich wäre aber auch bei Render-Nodes eine deduplikation denkbar. Für Parameter gilt das umso mehr, da hier i.d.R eine die ganze Nutzdauer übergreifende Automation eingesetzt wird. Man könnte nun auch diese einfach per Segment replizieren — oder, falls man deduplizieren möchte/muß, dann wäre die Lebensdauer-Steuerung per Segment insgesamt hinfällig, oder es wäre zumindest eine Mapping-Tabelle notwendig, die dann wieder das Problem mit den Locks aufwirft. Und zu allem Überfluß ist das ganze Thema mit der Lebensdauer von Rendervorgängen für mich im aktuellen Entwicklungsstand überhaupt nicht recht greifbar — ich kann nur spekulieren +

+ +
+ +
+
+
+ + + + + +

+ Ich gehe derzeit davon aus, 4 »Slots« für den Param-Deskriptor zu reservieren: einer für die VTable, einer für das ID-Wort, und zwei für die Daten. Allerdings reicht für alle einfachen Datenwerte  tatächlich ein einziger 64bit-Slot aus. Zwei »Slots« würden höchstens sowas wie ein Datentupel ermöglichen (und ich weiß nicht recht, wofür das gut sein soll, komplexe Zahlen? oder ein 128bit-Float?); ein einfacher Farbwert allerdings würde dann schon drei »Slots« verlangen.. +

+ +
+
+ + + + +

+ ...die einzige Lösung, die mir einfält, und die dann nicht doch wieder auf ein Lock hinausläuft, ist ein »Water-Level«. Also so ähnlich wie die Deadline-basierte Freigabe im Block-Flow (für den Scheduler). Und das Beispiel zeigt auch schon die Tücken, das macht nur Sinn, wenn es für jeden Eintrag eine garantierte Obsoleszenz gibt — andernfalls hat man dann am Ende doch wieder eine Garbage-Collection +

+ +
+ +
+
+ + + + + + +

+ es ist durchaus üblich, einen Abschnitt auf der Kurve zu markieren, und dann wie einen Regler zu verschieben; dabei erwartet man sich einen »fliegenden Feedback« +

+ +
+
+ + + + + +

+ insofern der Builder eine Projektion darstellt im Sinne von CQRS, müßte dieser beim Verarbeiten eines Änderungs-Events »irgendwie« wissen, wohin er die Änderungen in das bestehende low-level-Model propagieren soll; wir bräuchten sowas wie Patch-Tables +

+ +
+
+ + + + +

+ hierzu müßte man in die Automationsquelle einen Update-Mechanismus einbauen, der jeweils an einer Gate-Flag erkennt, ob er die Automations-Definition aktualisieren soll, bevor er sie auswertet; das Gate wäre dann letztlich wieder ein atomic-Lock (aber insofern akzeptabel, da es ja einfach ein Update sperrt, wenn die Quelle grade geändert wird, was kein sequentially-consistent erfordert) +

+ +
+
+ + + + +

+ wenn ein Update beginnt, wird der alte Wert erhalten, und der neue Wert im alternativen Segment modifiziert; nach Abschluß der Modifikation wechseln beide Segmente ihre Rolle, wofür eine automic-Flag umgeschaltet wird +

+ +
+
+
+ + + + +

+ ...und das verletzt die eigentlich beabsichtigte Segregation +

+ +
+
+ + + + + + + + + + + + + + + + + + + + +

+ in C++ kann man auch eine Builder-Notation per Typ-Konversion realisieren, was oft elegant ist, aber auch zweideutig; in vielen Fällen ist es letztlich doch besser, eine klare Klammer-Struktur zu erzeugen, mit einer terminal-Instruktion +

+ +
+
+ + + +
+
+
+
+
@@ -84955,7 +85535,7 @@

- /** @internal extension point + /** @internal extension point

* Create the environment for rendering a connected and related set of output streams. @@ -93739,6 +94319,16 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + @@ -114966,7 +115556,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -115510,6 +116100,10 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + @@ -119675,7 +120269,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -119688,7 +120282,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)

- Denn die Gefahr wäre zu groß, daß irgendjemand das dann als General-Koordinate für alles hernimmt — und den Unterschied zwischen Ausgabe-Grid und Source-Koordinaten per Machtspruch unter den Teppich kehrt. Man darf den all den Schwachmaten dieser Welt auch keinen kleinen Finger geben.... + Denn die Gefahr wäre zu groß, daß irgendjemand das dann als General-Koordinate für alles hernimmt — und den Unterschied zwischen Ausgabe-Grid und Source-Koordinaten per Machtspruch unter den Teppich kehrt. Man darf all den Schwachmaten dieser Welt auch keinen kleinen Finger geben....

@@ -119823,7 +120417,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
- + @@ -119975,8 +120569,18 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + + + +

+ Mute/Solo, Probe-Points, Automation +

+ +
+
@@ -120060,7 +120664,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
- + + @@ -120095,7 +120700,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
- + @@ -120202,7 +120807,31 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + + + + + + +

+ das ermöglicht es, Parameter zu kopieren (shallow-copy), aber auch eine bestimmte Version der Funktion für einen Build-Zustand festzulegen (d.h. Zugriff ist ein DAG), während eine andere Version im GUI bereits weiter verändert wird +

+ +
+
+ + + + +

+ ...dieser Wert gilt, wenn keine Qualifikation per nominal-time erfolgt; das bedeutet, die Automation beaufschlagt diesen Basis-Wert mit einer zeitabhängigken Modifikation +

+ +
+
+
@@ -120270,6 +120899,10 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + +
@@ -181796,7 +182429,7 @@ std::cout << tmpl.render({"what", "World"}) << s

- /* + /*

 * Gadgets are 'next-generation widgets' - they combine a CSS node @@ -186566,7 +187199,7 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo

- also keine "Banner" aus Sternen.
Abhilfe: /*********************//** + also keine "Banner" aus Sternen.
Abhilfe: /*********************//**

@@ -187577,7 +188210,7 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo                            filter out files when building tarballs

-                              (defaults to: -I*.a -I*.la -I*.o -I*.so -I.*.sw? -I*/*~ -I,,* -I.[#~]* -I.arch-ids -I.arch-inventory -I.be -I.bzr -I.bzr.backup -I.bzr.tags -I.bzrignore -I.cvsignore -I.deps -I.git -I.gitattributes -I.gitignore -I.gitmodules -I.gitreview -I.hg -I.hgignore -I.hgsigs -I.hgtags -I.mailmap -I.mtn-ignore -I.shelf -I.svn -ICVS -IDEADJOE -IRCS -I_MTN -I_darcs -I{arch}). +                              (defaults to: -I*.a -I*.la -I*.o -I*.so -I.*.sw? -I*/*~ -I,,* -I.[#~]* -I.arch-ids -I.arch-inventory -I.be -I.bzr -I.bzr.backup -I.bzr.tags -I.bzrignore -I.cvsignore -I.deps -I.git -I.gitattributes -I.gitignore -I.gitmodules -I.gitreview -I.hg -I.hgignore -I.hgsigs -I.hgtags -I.mailmap -I.mtn-ignore -I.shelf -I.svn -ICVS -IDEADJOE -IRCS -I_MTN -I_darcs -I{arch}).

@@ -188074,8 +188707,8 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
- - + + @@ -215758,7 +216391,7 @@ Since then others have made contributions, see the log for the history.

- /** derive total ordering from base class */ + /** derive total ordering from base class */

std::strong_ordering operator<=>(FrameRate  const&) const =  default; @@ -216591,7 +217224,7 @@ Since then others have made contributions, see the log for the history.src/vault/gear/work-force.cpp:69:43: warning: '++' expression of 'volatile'-qualified type is deprecated [-Wvolatile]

- 69 | for (volatile size_t i=0; i<degree; ++i) {/*SPIN*/} + 69 | for (volatile size_t i=0; i<degree; ++i) {/*SPIN*/}

@@ -216976,7 +217609,7 @@ Since then others have made contributions, see the log for the history.

- /** + /**

* Identification tuple for addressing frames unambiguously. @@ -216997,7 +217630,7 @@ Since then others have made contributions, see the log for the history.* be replaced by a combined C/C++ header

- */ + */

class FrameID : boost::totally_ordered<FrameID>  ////////////TODO it seems we don't need total ordering, only comparison. Clarify this! @@ -217747,7 +218380,7 @@ Since then others have made contributions, see the log for the history.

- /** + /**

* copy-initialise (or convert) from the given Mutator instance. @@ -217783,7 +218416,7 @@ Since then others have made contributions, see the log for the history.* which in turn becomes the only child of the new Record.

- */ + */

Record (Mutator const&  mut) @@ -218680,7 +219313,7 @@ Since then others have made contributions, see the log for the history.

- env.GuiResource(f) for f in env.Glob('stage/*.css') + env.GuiResource(f) for f in env.Glob('stage/*.css')

@@ -220758,7 +221391,7 @@ env.Command('out.bin', 'in.bin', my_action)

- /* + /*

  INDEX-ITER.hpp  -  iterator with indexed random-access to referred container @@ -220791,7 +221424,7 @@ env.Command('out.bin', 'in.bin', my_action)

- */ + */