Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HoaBLT-based ugens fail when angle is pi/2 #118

Open
dyfer opened this issue Mar 1, 2022 · 3 comments
Open

HoaBLT-based ugens fail when angle is pi/2 #118

dyfer opened this issue Mar 1, 2022 · 3 comments

Comments

@dyfer
Copy link
Contributor

dyfer commented Mar 1, 2022

I observed that HoaBLT-based plugins fail with an error, if the distortion angle is exactly pi/2 or -pi/2 (constant value).

Examples:

// fail
x.free; x = {HoaZoom.ar(DC.ar(0 ! 4), pi/2, 0, 0, AtkHoa.refRadius, 1)}.play;
x.free; x = {HoaFocus.ar(DC.ar(0 ! 4), pi/2, 0, 0, AtkHoa.refRadius, 1)}.play;
x.free; x = {HoaBalance.ar(DC.ar(0 ! 4), pi/2, AtkHoa.refRadius, 1)}.play;
x.free; x = {HoaAsymmetry.ar(DC.ar(0 ! 4), pi/2, AtkHoa.refRadius, 1)}.play;

// negative extreme also fails
x.free; x = {HoaZoom.ar(DC.ar(0 ! 4), -pi/2, 0, 0, AtkHoa.refRadius, 1)}.play;

Error:

ERROR: binary operator '+' failed.
RECEIVER:
   Float nan   00000000 7FF80000
ARGS:
Instance of BinaryOpUGen {    (0x118abdbc8, gc=14, fmt=00, flg=00, set=04)
  instance variables [9]
    synthDef : instance of SynthDef (0x128da4fc8, size=16, set=4)
    inputs : instance of Array (0x1181555d8, size=2, set=2)
    rate : Symbol 'audio'
    synthIndex : Integer 36
    specialIndex : Integer 2
    antecedents : nil
    descendants : nil
    widthFirstAntecedents : nil
    operator : Symbol '*'
}
   nil

PROTECTED CALL STACK:
	Meta_MethodError:new	0x139027540
		arg this = BinaryOpFailureError
		arg what = nil
		arg receiver = nan
	Meta_DoesNotUnderstandError:new	0x139029800
		arg this = BinaryOpFailureError
		arg receiver = nan
		arg selector = +
		arg args = [ a BinaryOpUGen, nil ]
	Object:performBinaryOpOnSomething	0x138479dc0
		arg this = nan
		arg aSelector = +
		arg thing = a BinaryOpUGen
		arg adverb = nil
	a FunctionDef	0x13a5d8040
		sourceCode = "<an open Function>"
		arg i = 0
	Integer:do	0x13a2fba40
		arg this = 4
		arg function = a Function
		var i = 0
	SequenceableCollection:performBinaryOpOnSeqColl	0x13a5d7b80
		arg this = [ nan, nan, nan, nan ]
		arg aSelector = +
		arg theOperand = [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ]
		arg adverb = nil
		var size = 4
		var newList = [  ]
	a FunctionDef	0x13a4aae00
		sourceCode = "<an open Function>"
		arg elem = [ nan, nan, nan, nan ]
	ArrayedCollection:do	0x13a557c40
		arg this = [ [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ nan, nan, nan, nan ] ]
		arg function = a Function
		var i = 1
	Collection:sum	0x13a4aa5c0
		arg this = [ [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ nan, nan, nan, nan ] ]
		arg function = nil
		var sum = [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ]
	a FunctionDef	0x13a4978c0
		sourceCode = "<an open Function>"
		arg elem = [ [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ nan, nan, nan, nan ] ]
		arg i = 1
	ArrayedCollection:do	0x13a557c40
		arg this = [ [ [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, -0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ] ], [ [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ nan, nan, nan, nan ] ] ]
		arg function = a Function
		var i = 1
	Collection:collectAs	0x13a497500
		arg this = [ [ [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, -0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ] ], [ [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ nan, nan, nan, nan ] ] ]
		arg function = a Function
		arg class = Array
		var res = [ [ a Sum4, 0.0, a Sum4, 0.0 ] ]
	Meta_Mix:new	0x138adc740
		arg this = Mix
		arg array = [ [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, -0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ nan, nan, nan, nan ] ]
		var reducedArray = [ [ [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, -0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ] ], [ [ a BinaryOpUGen, 0.0, a BinaryOpUGen, 0.0 ], [ nan, nan, nan, nan ] ] ]
		var mixedArray = nil
	Meta_HoaBLT:bltLook	0x139e8f200
		arg this = HoaBLT
		arg in = [ an OutputProxy, an OutputProxy, an OutputProxy, an OutputProxy ]
		arg alpha = 1.0
		arg theta = 0
		arg phi = 0
		arg weightFunc = a Function
		arg radius = 1.5
		arg n = 1
		var toPhi = -1.5707963267949
	SynthDef:buildUgenGraph	0x13b068e00
		arg this = a SynthDef
		arg func = a Function
		arg rates = nil
		arg prependArgs = [  ]
		var result = nil
		var saveControlNames = [ ControlName  P 0 i_out scalar 0 ]
	a FunctionDef	0x13a180700
		sourceCode = "<an open Function>"
		arg i_out = an OutputProxy
		var result = nil
		var rate = nil
		var env = nil
	SynthDef:buildUgenGraph	0x13b068e00
		arg this = a SynthDef
		arg func = a Function
		arg rates = nil
		arg prependArgs = [  ]
		var result = nil
		var saveControlNames = nil
	a FunctionDef	0x13b067440
		sourceCode = "<an open Function>"
	Function:prTry	0x1394241c0
		arg this = a Function
		var result = nil
		var thread = a Thread
		var next = nil
		var wasInProtectedFunc = false
	
CALL STACK:
	DoesNotUnderstandError:reportError
		arg this = <instance of BinaryOpFailureError>
	Nil:handleError
		arg this = nil
		arg error = <instance of BinaryOpFailureError>
	Thread:handleError
		arg this = <instance of Thread>
		arg error = <instance of BinaryOpFailureError>
	Object:throw
		arg this = <instance of BinaryOpFailureError>
	Function:protect
		arg this = <instance of Function>
		arg handler = <instance of Function>
		var result = <instance of BinaryOpFailureError>
	SynthDef:build
		arg this = <instance of SynthDef>
		arg ugenGraphFunc = <instance of Function>
		arg rates = nil
		arg prependArgs = nil
	Function:play
		arg this = <instance of Function>
		arg target = <instance of Group>
		arg outbus = 0
		arg fadeTime = 0.02
		arg addAction = 'addToHead'
		arg args = nil
		var def = nil
		var synth = nil
		var server = <instance of Server>
		var bytes = nil
		var synthMsg = nil
	< closed FunctionDef >  (no arguments or variables)
	Interpreter:interpretPrintCmdLine
		arg this = <instance of Interpreter>
		var res = nil
		var func = <instance of Function>
		var code = "x = {HoaZoom.ar(DC.ar(0 ! 4)..."
		var doc = nil
		var ideClass = <instance of Meta_ScIDE>
	Process:interpretPrintCmdLine
		arg this = <instance of Main>
^^ ERROR: binary operator '+' failed.
RECEIVER: nan

However, exceeding the range seems okay (i.e. there's no error):

x.free; x = {HoaZoom.ar(DC.ar(0 ! 4), pi, 0, 0, AtkHoa.refRadius, 1)}.play;

Using control signal (as opposed to a constant) with the same value seems to work fine as well...

x.free; x = {HoaZoom.ar(DC.ar(0 ! 4), DC.kr(pi/2), 0, 0, AtkHoa.refRadius, 1)}.play;
@mtmccrea
Copy link
Member

mtmccrea commented Mar 2, 2022

I had a quick look and, given these angle.sin is 1 in these cases, and given the nans in the error dump, I suspect this needs protection from divide-by-zero?

atk-sc3/Classes/HoaUGen.sc

Lines 229 to 231 in 346dfe8

warpFunc = { |mu, alpha|
(mu + alpha) / (1 + (alpha * mu))
};

@mtmccrea
Copy link
Member

mtmccrea commented Mar 2, 2022

This quick and dirty "fix" seems to ... not break at least

		warpFunc = { |mu, alpha|
			var denom = (1 + (alpha * mu));
			if(denom.rate == \scalar) {
				if(denom == 0) {denom = 0.0000001};
			};
			(mu + alpha) / denom;
		};

I haven't reasoned through the actual function or expected output, but given there aren't any other variables I'd imagine in this condition we might just know the exact value this function should return in the case the denom==0, and the division would just be altogether avoided.
Care should be taken in the case of running signals that these low denominator values divide nicely. ATM they may just be surviving because many UGens zapgremlins.

@joslloand
Copy link
Contributor

It would be good to check against the BLT implementations in HoaMatrixXformer, i.e., HoaMatrixXformer:-newDominate

When we're at ±pi/2 the result should collapse nicely into a cardioid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants