Hi!
I am learning about the .range
and .curverange
methods for UGens
and wondering about why it aren’t the same; like .range
having a curve parameter that defaults to 0
.
What are your thoughts on this?
Cheers!
.range
calls .linlin
, curverange
calls lincurve
and exprange
calls .linexp
… (the names here are asymmetrical in a not so lovely way imho!)
…so absolutely - I do think .range(min:0, max:1, curve:\lin)
would be nice -
I confess that 7 years in I somehow missed ‘rangecurve’!
…and why not fold \exp
in while we’re there. so `.range(0.01, 100, \exp)
…would have to “soft deprecate” the explicit methods so as not to break anything…
…might even be nice to have all the Env.shapeNames available?
I just learned about curverange
as well. range
with a third argument is definitely easier to use/remember.
And what about the Line
UGen? I think it would also make sense for it to accept a curve parameter (and thus make it more powerful, and soft deprecate XLine
)…
It’s not possible to replicate the exact behavior of XLine (or linexp or the \exp curve shape) using curve
. The formulas are very different, so I would not be in favor even of soft deprecation here.
EnvGen.kr(Env([start, end], [time], curve))
is Line with a curve factor, btw, and EnvGen is retriggerable – i.e. a more powerful line generator already exists.
hjh
but the curve
arg in Env
can be set to \exp
…
But wouldn’t you rather write Line.kr(start, end, time, 3)
than EnvGen.kr( Env( [start, end], time, 3))
?
Adding curve
to Line
could provide a nice onramp for students perhaps: use Line
- try different curves - for multiple segments you have to define an Env and use EnvGen
(but you already know about curves and the interface is consistent.) Line
for a single segment and Env
for multiple segments or retriggering is cleaner than the current division between Line
XLine
and EnvGen
On a side note in the days before IDE’s having related Classes whose names differ as to their first letter may have made sense - now though if you type Line
you don’t see XLine
as an option - a curve
flag on the other hand would be discoverable (as would a Class called LineX
but anyhow…)
The ship kinda sailed already, though, because there are already 3 arguments following “time” – putting curve 4th would break code (and annoy maintainers of other language clients).
FWIW I think neither Line nor XLine is particularly useful because of the lack of a trigger input. They’re convenient for one-off special cases, but I’m not sure that over-generalizing them is necessary.
LinePlusPlus {
// removing mul/add because you already give the range explicitly
*ar { |start = 0, end = 1, time = 1, curve = \lin, trig = 1, doneAction = 0|
^EnvGen.ar(
Env([start, start, end], [0, time], curve),
trig,
doneAction: doneAction
)
}
}
OK, done (except kr).
hjh
What about putting curve
last to preserve compatibility? Usage: Line.kr(start, end, time, curve:3)
.
- Pros:
- Allows for trying things out faster
- Would align with the proposed extension for
range
.
- Cons: ?
What about putting
curve
last to preserve compatibility?
I see your point, but don’t fully agree.
When considering changes such as this, it’s easy to underestimate the cost/risk, and overestimate the benefits. This got SC into trouble before; 8-9 years ago, I was running into a lot of weird bugs and edge cases because of an accumulation of things like “wouldn’t it be nice if…?” “Yeah, sure, go ahead” (combined with insufficient testing etc etc). This has led me to a default position of skepticism about changing existing interfaces.
I can be convinced. But I think “wouldn’t it be nice…” is not quite enough. What alternatives have been considered? Has it been thought through from a design perspective, rather than a patching-a-hole perspective? Does this connect to future needs (where a quick fix might get in the way)? In a professional software dev setting, these are questions that a program manager would answer. We don’t have program managers – so we have to learn to think like program managers.
For example, I did suggest an alternative – of course, the name LinePlusPlus is facetious and should be changed, but that approach:
- gives you access to all Env segment shapes (where a curve UGen input would not let you use \lin, \exp, \sin etc);
- and supports retriggering.
So… changing Line would have a benefit, but also a cost (mainly with non-SC clients, whose class definitions may not be in sync with the latest SC UGen binaries – I bet you didn’t think of this! I usually don’t either. Sciss had to fight long and hard to bring visibility to that aspect). An extended Line** pseudo-UGen has more benefit, and minor maintenance cost.
Just saying, consider more angles.
hjh
I like the LinePlusPlus
idea - perhaps Segment
would be a good name…
…on the other hand it might be simpler to have an Env
constructor instead: Env.line
?
@Asmatzaile here is the post by @Sciss explaining the issue with changing the number of arguments in UGens Keeping SuperCollider evolving with minimal impact on users work - #69 by Sciss. I do think that this is something that should be remedied if it is not too hard rather than we have to freeze all UGen interfaces forever.
Thanks @jamshark70 for the thorough answer and @semiquaver for linking the UGens arguments post by sciss!
I think Segment
is a good idea for the name. Concerning the names of the arguments; would they be initial
, target
, time
and curve
? I think that initial
and target
are more inline with the concept of segment
than start
and and end
… what about you?
Btw @jamshark70 should the topic be split to have a separate discussion for .range
/ .curverange
and Line
/ Segment
?
Btw @jamshark70 should the topic be split to have a separate discussion for
.range
/.curverange
andLine
/Segment
?
I’d say, not yet…?
I do think that this is something that should be remedied if it is not too hard rather than we have to freeze all UGen interfaces forever.
The problems are:
- Access (by e.g.
ZIN(i)
) to input slots that may not have been specified in the SynthDef. Currently, e.g., SinOsc has two inputs, and we rely on the class library to write two inputs into the SynthDef. If someone added an input, then the SC classlib would write three inputs for it, but a different language client that hadn’t been updated would write two. New UGen code trying to run that synth would doZIN(2)
and… what then? Segfault? I wasn’t able to reproduce a segfault in that case in Linux, but I don’t know about other OSes. - If a new input were not initialized, would it get garbage data or substitute 0, or…? We’d need a policy on that.
Plugins/classlib: Support multiple RandIDs in one SynthDef by jamshark70 · Pull Request #6159 · supercollider/supercollider · GitHub suggests a workaround (for a boolean input – a float value would need a bit different conditional), though I’m not sure it’s ideal as a policy for the future.
hjh
I’d say, not yet…?
Does this UGen adding arguments thing also affect .range
? If not, I could try to make the PR for that, there seems to be an agreement in that it’s more discoverable and that leverages cognitive load.