From 77257c56536dc6ef94046de5d65e78e28e91e3db Mon Sep 17 00:00:00 2001
From: Ichthyostega
-
+
Return value
@@ -28104,7 +28104,7 @@
matches that space by default, but can be changed for the above reasons. The helper functions
- cairo_user_to_device() and cairo_user_to_device_distance() tell you what the device-coordinates are for a user-coordinates position or distance.
+ cairo_user_to_device() and cairo_user_to_device_distance() tell you what the device-coordinates are for a user-coordinates position or distance.
+
If the question is more than 365 days old, and ...
void hun(T* obj, class C* c)
+ void hun(T* obj, class C* c)
{
//do some checking on c
if (some conditions from c are true)
@@ -85694,7 +85694,7 @@
- Separate hard bounds from the control range. These get conflated constantly and they are different things. A hard bound says values outside are illegal, and conform either clamps or errors. A control range says "this is the travel of the fader", and values outside are perfectly legal but unusual. Gain is the obvious case: the useful range is maybe −60 to +12 dB, but +30 dB is not an error. If you have one min/max pair it will silently become whichever of the two you happened to need first. Two pairs, or one pair plus a flag, costs almost nothing today.
+ Separate hard bounds from the control range. These get conflated constantly and they are different things. A hard bound says values outside are illegal, and conform either clamps or errors. A control range says "this is the travel of the fader", and values outside are perfectly legal but unusual. Gain is the obvious case: the useful range is maybe −60 to +12 dB, but +30 dB is not an error. If you have one min/max pair it will silently become whichever of the two you happened to need first. Two pairs, or one pair plus a flag, costs almost nothing today.
@@ -85704,7 +85704,7 @@
- Decide whether the stored value is in the metric's own units or in a canonical unit. This is the one place where your design page makes a claim that the implementation can quietly break. The page says combining is addition in a logarithmic scale and multiplication in a linear one, and that this is why scale belongs to the type. That's only true if the stored representation actually is in dB. If you store canonical linear and treat the metric as a display attribute, the joining operator becomes ambiguous again, and you're back to the thing the page argues against. My suggestion: store in the metric's units, so "the metric determines the join" is literally true rather than an interpretive claim.
+ Decide whether the stored value is in the metric's own units or in a canonical unit. This is the one place where your design page makes a claim that the implementation can quietly break. The page says combining is addition in a logarithmic scale and multiplication in a linear one, and that this is why scale belongs to the type. That's only true if the stored representation actually is in dB. If you store canonical linear and treat the metric as a display attribute, the joining operator becomes ambiguous again, and you're back to the thing the page argues against. My suggestion: store in the metric's units, so "the metric determines the join" is literally true rather than an interpretive claim.
@@ -85716,7 +85716,7 @@
Cyclic interacts with min/max in a way you'll want to be explicit about: for a cyclic scale, min/max define the period rather than a bound, and conform wraps instead of clamping. That's cheap. What isn't cheap, and what you should defer, is cyclic
- interpolation: shortest arc versus explicit winding for an automation curve crossing the seam. That belongs to the automation function, not to Scale.
+ interpolation: shortest arc versus explicit winding for an automation curve crossing the seam. That belongs to the automation function, not to Scale.
@@ -85725,19 +85725,19 @@
-
+
Sentinels
-
+
Worth separating two things that both look like sentinels.
-
+
Some are genuine domain members. Minus-infinity gain, "off", the extremal end of a fader. These have a definite position in the ordering and definite algebraic behaviour: −∞ dB is the absorbing element for gain combination, 0 dB is the identity. They belong in the domain, and a log-metric numeric scale that can represent its own absorbing element is more useful than one that can't. IEEE gets this part right, and borrowing -inf for exactly this is reasonable.
-
+
Others are not values at all. "Unset", "indeterminate", "multiple values selected in the GUI", "bypassed". These have no position in the ordering, no join behaviour, and every arithmetic operation on them is a bug. Putting them in-band is how you get NaN's contagion problem, plus a per-type encoding story (NaN payloads for float, INT_MIN for int, nothing sensible for bool). You have four 64-bit slots and only need one for the value. A small out-of-band state word in the container is uniform across every implementation type, costs you nothing, and keeps comparison honest.
-
+
Then make conform the single choke point that recognises and resolves both kinds. Everything downstream gets to assume it's looking at a real value.
@@ -85749,7 +85749,7 @@
-
+
If you want a rule for where to stop, it's this: build now only what you couldn't add later without changing code you can't reach. Behind your vtable, everything is reachable. Two things are not.
@@ -86059,8 +86059,772 @@ class ScaleRegistry
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ famous last words...
+
+
+ Also sollten wir zumindest den pathologischen Fall erkennen, und zwar effizient
+
+
+
+
+
+
+
+
+
+
+ ...weil das auch in einem Release-Build passiert und dann (hoffentlich) zu einem sichtbaren Crash führt.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ wie üblich habe ich Claude ganz bewußt nicht direkt den Stand meiner Überlegungen mitgeteilt; insofern ist es eine Bestätigung daß Claude ebenfalls (nur) zwei Hauptfälle verfolgt: Integral ⟶ Unsigned, sowie Floating-Point. Ebenfalls interessant, daß Claude auf die naheliegende Lösung mit Float-128 überhaupt nicht eingeht (vermutlich weil Claude von den vorhergehenden Chants den Kontext der Frage erkennen kann, und daher weiß, daß ich eine Library-Lösung brauche)
+
+
+
+
+
+
+
+
+
+ Fallunterscheidung std::integral vs std::floating_point
+
+
+
+
+
+
+
+ "Two problems hide behind one symptom here, and they have opposite YAGNI answers: for the integral case, total correctness is cheap and worth having unconditionally; for floating point it is impossible, so the only real decision is where to reject."
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Integral: do the arithmetic in the unsigned domain
+
+
+ The trick is not to widen the type but to change the domain. For any VAL of width N, the true span maxVal - minVal is at most 2^N-1, so it always fits into make_unsigned_t<VAL> — and unsigned arithmetic is modular by definition, so no UB even when the intermediate "overflows".
+
+
+
+
+
+
+
+
+
+
+
+ template<std::integral VAL>
+
+
+ constexpr VAL
+
+
+ wrapCyclic (VAL rawVal, VAL minVal, VAL maxVal)
+
+
+ {
+
+
+ REQUIRE (minVal < maxVal);
+
+
+ using U = std::make_unsigned_t<VAL>;
+
+
+ const U PERIOD = U(U(maxVal) - U(minVal)); // exact, always representable in U
+
+
+ U off;
+
+
+ if (rawVal >= minVal)
+
+
+ off = U(U(rawVal) - U(minVal)) % PERIOD;
+
+
+ else
+
+
+ {
+
+
+ const U dist = U(U(minVal) - U(rawVal)); // ≥ 1, so dist-1 cannot underflow
+
+
+ off = PERIOD-1 - (dist-1) % PERIOD; // ≡ (-dist) mod PERIOD
+
+
+ }
+
+
+ return VAL(U(U(minVal) + off));
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+ Three things worth noting. The PERIOD-1 - (dist-1) % PERIOD form is what avoids the usual double-modulus dance and gets the dist % PERIOD == 0 case right. The redundant-looking outer U(...) casts are not redundant for types narrower than int: integral promotion drags unsigned short operands up to int, and the modular wrap you rely on then doesn't happen. And the final VAL(U) conversion is well-defined modular since C++20, though in practice it never wraps — minVal + off is mathematically in range by construction.
+
+
+
+
+
+ This covers the full type range, including minVal = INT_MIN, maxVal = INT_MAX. Given that your Scale carries optional min/max qualifiers, that case is not exotic at all: toggle cyclic on a scale with no explicit bounds and the naive version is immediately UB. That alone makes the five extra lines worth it. And since make_unsigned_t is identity for unsigned types, one implementation serves signed and unsigned alike.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Floating point: the half-open invariant is the thing that actually bites
+
+
+ template<std::floating_point VAL>
+
+
+ constexpr VAL
+
+
+ wrapCyclic (VAL rawVal, VAL minVal, VAL maxVal)
+
+
+ {
+
+
+ REQUIRE (minVal < maxVal);
+
+
+ const VAL PERIOD = maxVal - minVal;
+
+
+ VAL off = std::fmod (rawVal - minVal, PERIOD);
+
+
+ if (off < 0) off += PERIOD; // this addition rounds...
+
+
+ if (not (off < PERIOD)) off = 0; // ...and can land exactly on PERIOD
+
+
+ const VAL res = minVal + off; // so can this one
+
+
+ return res < maxVal? res : minVal;
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+ std::fmod is exact — IEEE 754 specifies the result as exactly representable, no rounding introduced. Everything around it is not. The classic failure: off is a tiny negative like -1e-300, off + PERIOD rounds to exactly PERIOD, and you return maxVal from a half-open interval. That is not a boundary exotic case; it happens for any input a hair below minVal, which in an automation context is routine. Same for the final minVal + off rounding up to maxVal. Returning minVal there is not a fudge — maxVal ≡ minVal in a cyclic domain, so it is the correct representative.
+
+
+ The cases I would not write code for:
+
+
+ -
+
rawVal - minVal overflowing to ±∞ (needs fmod(fmod(rawVal,P) - fmod(minVal,P), P), valid because both inner results are exact and their difference is bounded by 2·PERIOD).
+
+ -
+
PERIOD itself overflowing to ∞.
+
+ -
+ Resolution collapse: once
|rawVal - minVal| / PERIOD exceeds 1/epsilon, the ulp spacing at rawVal exceeds the period and the answer, while exactly computed, carries no information.
+
+
+
+ The reason to skip these is not that they're rare but that the third one is unfixable. If someone wraps 1e18 into a 0.1-wide cycle, no implementation recovers the resolution — so the honest response is to reject, not to compute. One ASSERT at scale definition (PERIOD finite and PERIOD > 0) plus one in the wrap covering the ratio bound gives you a diagnosis instead of silent nonsense, and costs nothing in release builds.
+
+
+
+
+
+
+
+
+
+
+
+
+ Auf weitere Nachfrage und Bitte um Erläuterung der gewählten speziellen Formulierungen stellt Claude einen gemeinsamen Lösungsansatz heraus...
+
+
+
+
+
+
+
+
+
+ Both questions turn out to have a common shape: the awkwardness comes from having moved into a domain (unsigned, resp. finite-precision) where the convenient operation is no longer available, and the fix is to precompute the right quantity instead of patching after the fact.
+
+
+ (1) Why PERIOD-1 - (dist-1) % PERIOD
+
+
+ Start with why the obvious form isn't available. In C++, % truncates toward zero, so (-7) % 3 is -1, not 2 — the result lands in (-P, 0] for negative dividends, not in [0, P). The usual repair is
+
+
+
+
+
+
+
+
+
+
+
+ VAL r = (rawVal - minVal) % PERIOD;
+
+
+ if (r < 0) r += PERIOD;
+
+
+
+
+
+ which is correct, cheap, and unavailable to us, because the whole reason for the unsigned domain is that rawVal - minVal can overflow. Once you're in U, there is no negative dividend to correct — you only have the magnitude dist = minVal - rawVal ≥ 1, and you need (-dist) mod PERIOD.
+
+
+
+
+
+ The textbook identity for that is
+
+
+ offset = (PERIOD - dist % PERIOD) % PERIOD;
+
+
+
+
+
+ The outer % is there solely because of one input: when dist % PERIOD == 0, the inner expression yields PERIOD itself, which is out of range. So you pay a second division to fix a single boundary value.
+
+
+
+
+
+ The shifted form removes that boundary instead of patching it.
+
+
+
+
+
+ Write
+
+
+ dist - 1 = q·PERIOD + s with s = (dist-1) mod PERIOD ∈ [0, PERIOD).
+
+
+ Then
+
+
+ dist = q·PERIOD + s + 1,
+
+
+ so
+
+
+ -dist ≡ -(s+1) ≡ PERIOD-1-s (mod PERIOD)
+
+
+
+
+
+ and PERIOD-1-s lies in [0, PERIOD-1], i.e. already in range — no second reduction possible or needed. The -1/+1 shift maps the problematic residue 0 to the interior, and maps the interior residue PERIOD-1 to 0, which is precisely the value that was missing.
+
+
+
+
+
+ So the preference is: one division instead of two (and integer division is the only expensive operation in this function — tens of cycles on 64-bit operands), no branch, and no intermediate that can transiently equal PERIOD and leak out through a later refactoring. dist - 1 cannot underflow because the enclosing branch guarantees rawVal < minVal, hence dist ≥ 1.
+
+
+
+
+
+ (2) One rejection predicate, not two —
and the near-minVal case isn't one of them
+
+
+ Your instinct that there are two conditions is right in the sense that overflow of rawVal - minVal and resolution collapse are genuinely independent: neither implies the other. With PERIOD = 0.1 the resolution limit sits at |rawVal - minVal| ≈ 4.5e14, nowhere near overflow; with PERIOD ≈ 1e300 the subtraction can overflow while the ratio is still fine. But both are bounds on the same quantity, and if you avoid computing the difference you can cover them with one comparison.
+
+
+
+
+
+ Let the builder precompute a magnitude limit and store it in the scale:
+
+
+
+
+
+ // at scale definition, cyclic + floating point
+
+
+ VAL lim = PERIOD / std::numeric_limits<VAL>::epsilon();
+
+
+ if (not std::isfinite(lim))
+
+
+ lim = std::numeric_limits<VAL>::max();
+
+
+ lim /= 2; // exact
+
+
+
+
+
+ The builder then rejects the definition unless std::abs(minVal) <= lim and std::abs(maxVal) <= lim (plus minVal < maxVal, both finite, and PERIOD normal rather than subnormal). A cycle of width 0.1 anchored at 1e300 is not a scale anyone can use, and that judgment belongs at definition time.
+
+
+
+
+
+ Invocation then needs exactly one check:
+
+
+
+
+
+ if (not (std::abs(rawVal) <= lim))
+
+
+ throw error::Invalid{...};
+
+
+
+
+
+ Since |rawVal| ≤ lim and |minVal| ≤ lim, the difference is bounded by 2·lim ≤ PERIOD/ε, which both keeps ulp(rawVal - minVal) ≤ PERIOD and makes the subtraction non-overflowing. And because the predicate is written as a negated <=, NaN and ±∞ fall into the reject branch for free — no separate isfinite test. That matters: without it, fmod(NaN, PERIOD) is NaN, every comparison in the wrap is false, and your not (off < PERIOD) clamp quietly turns it into minVal. A silently invented value is the worst outcome available here.
+
+
+
+
+
+ Your second candidate — rawVal very close to minVal — is not a rejection case. Cancellation there loses absolute precision in the difference, but the result stays inside the cycle and remains the nearest representable answer; what needs protecting is only the half-open invariant, and the two clamps already do that. Rejecting would be wrong: values just below minVal are the single most common input to a wrap.
+
+
+
+
+
+ On sanitising the resolution case: I'd argue against it, precisely because this is library code. Clamping or wrapping anyway produces a result indistinguishable from a legitimate one, and the caller has no way to learn that their automation curve has gone numerically meaningless. The information was destroyed in the input — no post-hoc treatment restores it, so there's nothing to sanitise, only something to conceal.
+
+
+
+
+
+ Throwing is the right call, and it's affordable: one comparison on the hot path, well predicted, with the throw only on the path where the value is already garbage. Two caveats specific to your setting. First, an exception thrown inside a render job must not escape a worker thread — you'll want the job invocation wrapped so it fails the job rather than reaching std::terminate; I assume the scheduler already has that boundary, but this makes it load-bearing. Second, if the "sentinel values outside the continuous range" idea from the Parametrisation design ever lands on NaN, the sentinel has to be intercepted before the cyclic conform, never inside it.
+
+
+
+
+
+ A nice side effect: if wrapCyclic is constexpr, the throw makes a violating call ill-formed at compile time, so constant-folded scale definitions get rejected by the compiler rather than at runtime.
+
+
+
+
+
+ Given that Scale already exposes a "conform" operation, the natural home for this is there — cyclic wrapping is a conform, and conform is where out-of-domain inputs are supposed to be adjudicated.
+
+
+
+
+
+
+
+
+ Complete Reasoning for the Unsigned-case
+
+
+
+
+
+ Below, everything named with a lower-case letter is a mathematical integer (element of ℤ, unbounded). Machine operations are written with distinct symbols so the two layers never blur. The proof is in two layers, and your question — wrapped arithmetic or equivalence transformation? — is answered by the split: wrapping is used exactly once, in Lemma 1, to establish that one machine value equals one mathematical value. Everything after that is ordinary arithmetic on non-negative integers, with no wrapping and no appeal to modular representation.
+
+
+ Definitions
+
+
+ Let VAL have width N. Write
+
+
+ -
+
A = [VAL_MIN, VAL_MAX] ⊂ ℤ for the set of values representable in VAL, with |A| = 2^N;
+
+ -
+
B = [0, 2^N - 1] ⊂ ℤ for the set representable in U = make_unsigned_t<VAL>;
+
+ -
+
ι : A → B, ι(v) = v mod 2^N, the value-preserving-mod conversion VAL → U (identity if v ≥ 0, else v + 2^N);
+
+ -
+
⊖, ⊕ for the machine's unsigned operations on U: a ⊖ b = (a - b) mod 2^N, a ⊕ b = (a + b) mod 2^N.
+
+
+
+ For a ∈ ℤ and p ≥ 1, let a mod p denote the mathematical modulo:
the unique r ∈ [0, p) with a ≡ r (mod p).
+
+
+ The modulus operator % in C++ is truncating and therefore agrees with this only on non-negative dividends; that restriction is the sole property of % used below.
+
+
+
+
+
+ Given m = minVal, M = maxVal, x = rawVal, all in A, with m < M.
+
+
+ Thus p ≔ M - m is the period-span.
+
+
+
+
+
+ Goal. Compute the unique offset off ∈ [0, p) with off ≡ x - m (mod p),
+
+
+ then return m + off.
+
+
+
+
+
+ Observation 0. 1 ≤ p ≤ VAL_MAX - VAL_MIN = 2^N - 1, so p ∈ B.
+
+
+ The span is always representable in U even when it is not representable in VAL.
+
+
+
+
+
+ Lemma 1 (the only wrapping step)
+
+
+ Let x < m and put dist = m - x ∈ ℤ. Then dist ∈ [1, 2^N - 1] ⊆ B, and the machine expression U(ι(m) ⊖ ι(x)) evaluates to exactly dist.
+
+
+ Proof:
+
+
+ Lower bound: x < m gives dist ≥ 1.
+
+
+ Upper bound: x ≥ VAL_MIN and m ≤ VAL_MAX give
+
+
+ dist ≤ VAL_MAX - VAL_MIN = 2^N - 1. Hence dist ∈ B.
+
+
+ For the value: ι(v) ≡ v (mod 2^N) by definition,
so ι(m) - ι(x) ≡ m - x = dist (mod 2^N).
+
+
+
+
+
+ Therefore
+
+
+
+
+ ι(m) ⊖ ι(x) = (ι(m) - ι(x)) mod 2^N = dist mod 2^N = dist,
+
+
+
+
+ the last equality because dist ∈ [0, 2^N). ∎
+
+
+
+
+
+ This is the whole role of unsigned wrap-around: it hands us the mathematical dist unharmed, despite x - m being possibly outside A. (The outer cast U(...) in the code is needed when N is narrower than int, where integral promotion would lift the operands to int and suppress the mod 2^N reduction.)
+
+
+ From here on, all quantities lie in [0, 2^N) and every operation below is checked to stay there, so no further machine wrapping occurs and the reasoning is purely in ℤ.
+
+
+
+
+
+ Restated goal. Since x - m = -dist, we need off = (-dist) mod p
+
+
+
+
+
+ Proposition 1 (the two-division form)
+
+
+ Let s₀ = dist mod p. Then (p - s₀) mod p = (-dist) mod p.
+
+
+ Proof:
+
+
+ dist ≥ 0, so C++ dist % p yields s₀ (truncating and mathematical modulo agree). From dist ≡ s₀, we get -dist ≡ -s₀ ≡ p - s₀ (mod p). So p - s₀ is a correct representative, but s₀ ∈ [0, p) gives p - s₀ ∈ (0, p] — in range except at the single point s₀ = 0, where the value is p ∉ [0, p). The outer reduction maps p ↦ 0 and fixes [0, p) pointwise, yielding the representative in [0, p). ∎
+
+
+ The second division exists solely to repair one input.
+
+
+ Note also that p - s₀ > 0 always, so no unsigned underflow —
+
+
+ the form is safe, just wasteful.
+
+
+
+
+
+ Proposition 2 (the one-division form)
+
+
+ Let s = (dist - 1) mod p. Then p - 1 - s = (-dist) mod p.
+
+
+ Proof:
+
+
+ By Lemma 1, dist ≥ 1, hence dist - 1 ≥ 0 and C++ (dist-1) % p yields s.
+
+
+ Congruence. dist - 1 ≡ s (mod p) implies dist ≡ s + 1 (mod p), hence
+
+
+
+
+ -dist ≡ -(s + 1) ≡ p - s - 1 (mod p).
+
+
+
+
+ Range. s ∈ [0, p - 1], therefore p - 1 - s ∈ [0, p - 1] ⊂ [0, p).
+
+
+ Since the representative of a residue class in [0, p) is unique,
and p - 1 - s is both congruent to -dist and inside [0, p), it is (-dist) mod p. ∎
+
+
+
+
+
+ No repair step is possible or needed.
+
+
+ Intermediates: p - 1 ≥ 0 since p ≥ 1, and (p-1) - s ≥ 0 since s ≤ p-1, so neither subtraction underflows in U. (Precedence gives PERIOD-1 - (dist-1) % PERIOD = (p-1) - ((dist-1) % p), as intended.)
+
+
+
+
+
+ Why the shift works
+
+
+ Both propositions factor the same map d ↦ (-d) mod p, but through different intermediate maps on the residue:
+
+
+ -
+ Prop. 1 uses
s₀ ↦ p - s₀, which sends [0, p-1] onto [1, p] — a bijection onto the wrong interval, off by one at both ends.
+
+ -
+ Prop. 2 uses
s ↦ p - 1 - s, the reflection of [0, p-1] onto itself — an involution of the correct interval.
+
+
+
+ The -1/+1 shift is precisely the reindexing that converts the first map into the second: it moves the problematic residue 0 into the interior and supplies the residue p-1 that was otherwise unreachable.
+
+
+
+
+
+ Worked check, p = 3:
+
+
+
+
+
+
+
+
+
+ dist 1 2 3 4 5 6
+(-dist) mod 3 2 1 0 2 1 0
+
+Prop.2: (dist-1)%3 0 1 2 0 1 2
+ 2 - s 2 1 0 2 1 0 ✓ always in range
+
+Prop.1: dist%3 1 2 0 1 2 0
+ 3 - s₀ 2 1 3 2 1 3 ← out of range at dist = 3, 6
+ (…)%3 2 1 0 2 1 0 ✓ only after repair
+
+
+
+
+ Closing the loop
+
+
+ off ∈ [0, p) gives m ≤ m + off ≤ m + p - 1 = M - 1, so m + off ∈ A: the result is representable in VAL, always. The machine computes ι(m) ⊕ off ≡ m + off (mod 2^N), and the conversion back to VAL (modular since C++20) recovers m + off exactly, since that value lies in A.
+
+
+ The positive branch is the same argument with Lemma 1 applied in the other direction: x ≥ m gives x - m ∈ [0, 2^N - 1] ⊆ B, so ι(x) ⊖ ι(m) = x - m exactly, and % on a non-negative dividend is the mathematical modulo directly.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ich sehe zwar intuitiv die Logik, aber die Beschreibung von Claude ist zweideutig. Daher verlange ich von Claude einen voll ausformulierten mathematischen Beweis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ zwar sind die nach unsigned gewrappeden werte ι(rawVal) und ι(minVal) rein numerisch andere Zahlen, aber sie haben den gleichen Abstand dist. Das ist tatsächlich der Kern des Ansatzes und das bedarf eines Beweises, da minVal >0 sein kann
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Und zwar, weil sich damit der Code organisieren läßt, ohne den Namepsace mit Spezial-Implementierungen zu belasten, aber auch ohne jetzt wieder eine neue generische Library-Funktion aufzumachen, die ich dann doch wieder nicht sauber ausentwickle und teste....
+
+
+
+
+
+
+
@@ -104681,7 +105445,7 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
#include <functional>
@@ -114156,7 +114920,7 @@ Date: Thu Apr 20 18:53:17 2023 +0200
- template<class RES>
+ template<class RES>
pair<RES, Ctx>
runBuild(Builder<RES> buildr, Ctx c)
{
@@ -114197,7 +114961,7 @@ runBuild(Builder<RES> buildr, Ctx c)
- template<class R1, class R2>
+ template<class R1, class R2>
auto
StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
{
@@ -174376,7 +175140,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
- mustache tmpl{"Hello {{what}}!"};
+ mustache tmpl{"Hello {{what}}!"};
std::cout << tmpl.render({"what", "World"}) << std::en
@@ -180680,7 +181444,7 @@ std::cout << tmpl.render({"what", "World"}) << s
- Earliest deadline first (EDF) or least time to go is a dynamic priority scheduling algorithm used in real-time operating systems to place processes in a priority queue. Whenever a scheduling event occurs (task finishes, new task released, etc.) the queue will be searched for the process closest to its deadline. This process is the next to be scheduled for execution.
+ Earliest deadline first (EDF) or least time to go is a dynamic priority scheduling algorithm used in real-time operating systems to place processes in a priority queue. Whenever a scheduling event occurs (task finishes, new task released, etc.) the queue will be searched for the process closest to its deadline. This process is the next to be scheduled for execution.
@@ -183827,7 +184591,7 @@ std::cout << tmpl.render({"what", "World"}) << s
-
+
struct bar : public sigc::trackable {};
@@ -183879,7 +184643,7 @@ std::cout << tmpl.render({"what", "World"}) << s
The event mask determines which events a widget will receive. Keep in mind that different widgets have different default event masks, and by changing the event mask you may disrupt a widget’s functionality, so be careful. This function must be called while a widget is unrealized. Consider
- add_events() for widgets that are already realized, or if you want to preserve the existing event mask. This function can’t be used with widgets that have no window. (See get_has_window()). To get events on those widgets, place them inside a Gtk::EventBox and receive events on the event box.
+ add_events() for widgets that are already realized, or if you want to preserve the existing event mask. This function can’t be used with widgets that have no window. (See get_has_window()). To get events on those widgets, place them inside a Gtk::EventBox and receive events on the event box.
@@ -186019,10 +186783,10 @@ std::cout << tmpl.render({"what", "World"}) << s
Beispiel:
- cairo_scale (cr, 100, 100);
+ cairo_scale (cr, 100, 100);
- cairo_translate (cr, 0.1, 0.1);
+ cairo_translate (cr, 0.1, 0.1);
@@ -186512,7 +187276,7 @@ std::cout << tmpl.render({"what", "World"}) << s
-
+
template<
@@ -186664,7 +187428,7 @@ std::cout << tmpl.render({"what", "World"}) << s
-
@@ -187422,7 +188186,7 @@ std::cout << tmpl.render({"what", "World"}) << s
-
+
explicit-specifier(optional) template-name ( parameter-decl-clause ) -> simple-template-id ;
@@ -187787,7 +188551,7 @@ std::cout << tmpl.render({"what", "World"}) << s
- template <template <typename...> class ALO>
+ template <template <typename...> class ALO>
concept Allocator = true; // actual constraint here
template <template <typename...> class ALO>
@@ -188746,7 +189510,7 @@ class Something
- std::stringstream ss;
+ std::stringstream ss;
ss << std::this_thread::get_id();
int id = std::stoi(ss.str());
@@ -188756,7 +189520,7 @@ int id = std::stoi(ss.str());
- std::hash<std::thread::id>{}(std::this_thread::get_id())
+ std::hash<std::thread::id>{}(std::this_thread::get_id())
@@ -188770,7 +189534,7 @@ int id = std::stoi(ss.str());
- std::thread::id threadId = std::this_thread::get_id();
+ std::thread::id threadId = std::this_thread::get_id();
unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<void*>(&threadId));
@@ -189899,7 +190663,7 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
- plot-element:
+ plot-element:
{<iteration>}
<definition> | {sampling-range} <function> | <data source>
| keyentry
@@ -190027,7 +190791,7 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
- set xrange [-10:10]
+ set xrange [-10:10]
set yrange [] writeback
plot sin(x)
set yrange restore
@@ -190083,7 +190847,7 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
- set multiplot
+ set multiplot
set size 0.4,0.4
set origin 0.1,0.1
plot sin(x)
@@ -190219,7 +190983,7 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
- plot 'data' with boxes, sin(x) with lines
+ plot 'data' with boxes, sin(x) with lines
@@ -193390,10 +194154,10 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
-
+
A. Shared goals and method (framing, before the four categories)
-
+
-
Vision and common ground — flow and "organic editing" (Wouter's core framing: interruptions kill flow; the goal is focus on storytelling), software as extension of the body, protecting settled parts of an edit, the trackless aspiration, medium level of abstraction / "not a Premiere clone". Largely agreed — this is where you two converged fastest.
@@ -193401,19 +194165,19 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
Working method — explorative reasoning ("enumerate what's possible, narrow by plausibility, look for game-like mechanics"), Wouter's scenario catalogue, the recognised need to build and user-test before judging. Includes the agreed intent to produce a design document.
-
+
B. Grouping (the richest material)
3. Grouping devices and encapsulation — Wouter's sections>groups>clips model with three sync modes (Apr 2025) vs. your "everything is a sequence" self-similarity; the convergence: groups as evolution of linked clips, co-existing with nested sequences; implicit grouping through placements; the "group leader" concept. Status: substantially converged, representation open.
4. Placement prototypes — the settled set of three (relative-to-parent/absolute, magnetic, content-anchored), the move/trim/slip behaviour matrix from your 29.8. mail, "fewer prototypes the better". Status: largely agreed; edge cases open (swapping, offset inheritance, deletion of anchors, negative time — the last one resolved: no brick wall, relocatable zero point).
5. Moving, reordering and ripple behaviour — drag semantics (your a/b/c → Wouter's hierarchy principle "parents move children"; magic depends on placement, not modifier), blocking vs. never-say-no (open!), reordering of magnetic clips (open!), lift vs. extract (terminology settled), the parked ripple-trim debate incl. your power-of-defaults argument.
6. Adding clips and automatic placement setup — the three setup options, proximity rules, your hooking gesture (Dec 2025, "would like to try it"), Wouter's arrow/two-step alternatives, the clip-lifetime state model, the Gimp pattern (sticky sub-mode + temporary modifier — explicitly endorsed by both). Status: converging but undecided; this is where the discussion paused in December.
-
+
C. Control
7. Keybindings, gestures, navigation — your flat-keymap critique and context-based primitives, Wouter's configurability requirement and ergonomics analysis (the "Fingers crossed" mail is a hidden gem), the synthesis "simplify down / map down", sticky selection vs. selection-in-undo-stack, keyboard navigation gestures, modifier budget (Shift=select, Alt=duplicate, Ctrl=alternative action — late convergence).
8. Tools, modes, views, contextual tool palette — anchored in Wouter's document and the FrOSCon-25 meeting; the palette as carrier for placement types; Blender-style key popups; trim mode as contextual mode.
9. The gear switch — your proposal, Wouter's concerns (gear-recall, Speed Editor experience), unresolved: sub-mode or always-on (his FrOSCon correction).
10. Immediate feedback and gesture architecture — the gesture controller / command-sentence pipeline, live-preview economics ("don't compete with industry"), the Priority-1/Priority-2 cue scheme, Wouter's concrete cue wishlist (locked-indicator + direction arrows). Status: goals agreed, feasibility open.
-
+
D. Routing (thin — mostly agenda fodder)
11. Layering, tracks as space, tag-based routing — layering decoupled from track order, subtracks as fluid working space, shear-aside on collision, tagging for organisation and routing (Wouter's "get rid of bins entirely"), vertical-space and black-box concerns with nested sequences, the popup-portal idea.
-
+
E. Scope and priorities (cross-cutting, discussed substantively)
12. Scope boundaries — node compositing inside the NLE (Wouter contra, you "agree and disagree"), i18n/RTL priority decision, GTK vs. Qt, target personas. Status: partly settled, partly consciously deferred.
-
+
Topics 1–2 and 12 sit outside your fourfold scheme; I'd frame A as introduction-adjacent and E as a closing section. The agenda document then derives from the "open" entries per topic plus the uncovered Routing/Editing-trimming ground.
@@ -194280,7 +195044,7 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
Richard Spindler found his way through Parma thanks to the great
- OpenStreetMap project.
+ OpenStreetMap project.
@@ -194591,7 +195355,7 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
On Tue, 14 Aug 2007 23:32:01 +0200, Edouard Chalaron
- <e.chalaron@xtra.co.nz> wrote:
+ <e.chalaron@xtra.co.nz> wrote:
Well I am sorry, but the way icons look is of the last relevance
I
@@ -194631,7 +195395,7 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
-
+
marquitux caballero wrote:
in the comunity very cool people tried to explain me thos things, but
@@ -194702,7 +195466,7 @@ Cinelerra mailing list
- This my maybe arguable view how to hive Cinelerra CV out of its
+ This my maybe arguable view how to hive Cinelerra CV out of its
develoment stall:
1) Change the focus of CinelerraCV
@@ -195250,7 +196014,7 @@ Cinelerra mailing list
- Wow Du hast hast mächtig vorgelegtb mit deiner uml/wiki doc.
+ Wow Du hast hast mächtig vorgelegtb mit deiner uml/wiki doc.
Wie Du vllt siehst hab ich ausser bisschen wiki kosmetik noch nicht viel
gemacht, ich schreib gerade mal was zum backend was ich hoffentlich
@@ -195293,7 +196057,7 @@ Vorschlag währe das man Bouml nach doc/uml/ generiern lässt
- Voßeler Hermann wrote:
+ Voßeler Hermann wrote:
Hallo Christian,
@@ -195370,7 +196134,7 @@ interessierte davon was mitbekommen anstatt privater mails.
-
+
Vorhin hab ich gesehen, daß Du auch grade die ersten Schritte
in UML gemacht hast; bin schon gespannt...
@@ -195408,7 +196172,7 @@ oder bouml einfach ein paar sachen um bestimmte dinge zu modelliern.
- Ichthyostega wrote:
+ Ichthyostega wrote:
So, could you please have a look at this prototype buildsystem? I pushed out to cinelerra3/ichthyo
#scons - just the buildsystem
@@ -195444,7 +196208,7 @@ note about gnu style: (how I/emacs interpret it)
-
+
After a talk on IRC ichthyo and me agreed on making lumiera a multi language project where each part can be written in the language which will fit it best. Language purists might disagree on such a mix, but I believe the benefits outweigh the drawbacks.
@@ -195507,7 +196271,7 @@ note about gnu style: (how I/emacs interpret it)
Beachte dazu auch folgendes: der erste (wichtigere) RfC »All Plugin Interfaces are C« ist datiert auf 26.9. Nur dieser erste Kommentar trägt den Timestamp 3.7. — außerdem steht dort im Pro/Contra-Teil unter "Alternatives"
-
+
-
@@ -195543,7 +196307,7 @@ note about gnu style: (how I/emacs interpret it)
Phasen immer sehr aufmerksam). Er hat im Mail-Austausch an eben jenem
Morgen geschrieben:
- morning, trying it out now , next i'll write some DesignProcess
+ morning, trying it out now , next i'll write some DesignProcess
proposals about C nameing rules, plugins and interfaces. (i am back ;))
Natürlich könnte diese Mail für mich der Anlaß gewesen sein, nochmal
@@ -195610,7 +196374,7 @@ proposals about C nameing rules, plugins and interfaces. (i am back ;))
- Btw: seen my Interface / CStyleGuide proposal in the pipapo wiki? please
+ Btw: seen my Interface / CStyleGuide proposal in the pipapo wiki? please
review it carefully if it looks ok, I straight go into make a referene
implementation, since this is a very low level building block.
@@ -195663,7 +196427,7 @@ implementation, since this is a very low level building block.
-
+
Am Dienstag, den 03.07.2007, 20:51 +0200 schrieb Christian Thaeter:
@@ -195782,7 +196546,7 @@ Hermann
- Voßeler Hermann wrote:
+ Voßeler Hermann wrote:
Am Dienstag, den 03.07.2007, 20:51 +0200 schrieb Christian Thaeter:
@@ -195922,7 +196686,7 @@ we provide for us, we provide for people extenting it too)
Er skizziert ja, wie er sich das vorstellt:
- we now need to define/collect what interfaces are needed to implement tracks.
+ we now need to define/collect what interfaces are needed to implement tracks.
Das ist das gefürchtete "dann kann man" ... und andere Leute sollen sich gefälligst mal den Arsch aufreißen, ich hab euch jetzt das Prinzip gezeigt.
@@ -196212,7 +196976,7 @@ we provide for us, we provide for people extenting it too)
-
+
after a talk on irc, we decided to do it this way, further work will be documented in the repository (tiddlywiki/source)
@@ -196605,7 +197369,7 @@ we provide for us, we provide for people extenting it too)
- mark carter schrieb:
+ mark carter schrieb:
Maybe a lot of my problem is that I'm new to the code. Coming in from
fresh on such a big project is bound to be daunting,....
@@ -197090,7 +197854,7 @@ on some aspects of file handling media loading.
- Lately i had almost no time to hack on cinelerra and it doesn't seem
+ Lately i had almost no time to hack on cinelerra and it doesn't seem
that situation will improve in forseeable future.
@@ -199240,7 +200004,7 @@ that situation will improve in forseeable future.
-
+
meta policies
@@ -205498,7 +206262,7 @@ that situation will improve in forseeable future.
- attempt to write a readonly database
-
+
@@ -213593,7 +214357,7 @@ runner.run(test_suite())
-
- override_dh_auto_configure:
+ override_dh_auto_configure:
dh_auto_configure -- --prefix=/opt/rawau
@@ -214667,7 +215431,7 @@ actively maintained upstream. Please remove gdl from Debian.
- The original plugin file is the file posted to http://www.scons.org/wiki/DoxygenBuilder by Matthew Nicolson
+ The original plugin file is the file posted to http://www.scons.org/wiki/DoxygenBuilder by Matthew Nicolson
2006-03-31. Attached to this wiki page were two other files, both of which are in the repository history
although removed from being in the working tree: doxygen_reiners_2007-02-26.py, and
doxygen_boehme_2007-07-18.py. Boehme's version seems to include many of the changes in Reiners but many of
@@ -221082,7 +221846,7 @@ Since then others have made contributions, see the log for the history.
- 1 import sys
+ 1 import sys
2
3 try:
4 untrusted.execute()
@@ -221868,7 +222632,7 @@ Since then others have made contributions, see the log for the history.
-
+
Use one of these approaches: chain actions in a single Command, or install first then attach a post-action (via AddPostAction or Command on the installed node). Both keep the install and chmod as a single build step.
@@ -222450,7 +223214,7 @@ env.Chmod(installed[0], 0o644)
-
+
Short answer
@@ -224274,7 +225038,7 @@ env.Command('out.bin', 'in.bin', my_action)
- debuild -S -sd --sign-key=11FDF5D2DBD7BBD7F4D9D9C42CF2539262382557
+ debuild -S -sd --sign-key=11FDF5D2DBD7BBD7F4D9D9C42CF2539262382557
@@ -224665,7 +225429,7 @@ env.Command('out.bin', 'in.bin', my_action)
10.2
-
+
Libtool .la files should not be installed for public libraries. If they’re required (for libltdl, for instance), the dependency_libs setting should be emptied. Library packages historically including .la files must continue to include them (with dependency_libs emptied) until all libraries that depend on that library have removed or emptied their .la files.
@@ -226249,7 +227013,7 @@ env.Command('out.bin', 'in.bin', my_action)
Some works meticulously keep track of what copyrights and licenses apply to each particular file when combining source from multiple origins. Some instead apply
- all licenses and all copyrights of component parts to the entire combined work. Both are generally accepted by the open source community, as long as it's clear that an effort is being made to identify and comply with the original licenses.
+ all licenses and all copyrights of component parts to the entire combined work. Both are generally accepted by the open source community, as long as it's clear that an effort is being made to identify and comply with the original licenses.