Review: execution, resolution, environments, etc

My understanding of this problem was always sketchy. Here are three bits of code that illustrate my confusion and ignorance.

//***
(
   Ndef(\tgrains, {  

	var rate, snd, trigRate, centerPos;

	// mouse movement X and Y:
	   trigRate = MouseY.kr(2, 200, 1);
	   centerPos = MouseX.kr(0, BufDur.kr(b));
etc.
***//

the well-known MouseX.kr strategy. But,

//***
(
   Ndef(\tgrains).addSpec(\trigRate, [2, 220,'exp']);
   Ndef(\tgrains).addSpec(\centerPos, [1, BufDur(b),'exp']);

   Ndef(\tgrains, {  |trigRate = 60, centerPos = 2|

	var rate, snd;

etc.
***//

fails silently until NDef(\tgrains).gui; And alsoā€¦

//***
k.elAt(\sl, 1).action_({|el| Ndef(\tgrains).set(\centerPos, el.value.linexp(0.0,1.0, 1,BufDur(b)))});
***//

using Modality to attempt a link to a nanoKontrol2 to control trigRate with a slider.

Can someone please give me a quick explanation and a suggestion about where to go to find a more or less compete and understandable explanation about why snippet 1 works while snippets 2 & 3 donā€™t?
It would also be great to see a solution or work around so I can get a dynamic value into my Specs.
Thanks for your help.
ā€¦edN

quick observationā€¦
BufDur(b) will never work and you used it twice.
Itā€™s either b.duration, BufDur.ir(b) or BufDur.kr(b). The latter if you plan on swapping buffers, the first if youā€™re not inside a SynthDef/Ndef.
hope that little typo was the issue.

Thanks for getting back. I find that niether the .kr nor the .ir version work in Ndef(\tgrains).gui or the Modality slider assignment.
However, b.duration seems to work in both situations even with a buffer swap.

Iā€™m still no further ahead regarding the theory but this seems to solve my immediate issue.
Thanks again. ā€¦edN

Iā€™m still no further ahead regarding the theory but this seems to solve my immediate issue.

Ok, hereā€™s an attempt to clarify a bit more (hope it doesnā€™t do the opposite and blur)

BufDur(b) is the same as writing BufDur.new(b) and this does not evaluate to a number - it gives you a new object. try it by runningā€¦
BufDur(b); //-> a BufDur

So in for example .linexp(0.0,1.0, 1,BufDur(b)) the linexp method canā€™t really know what the value for the fourth argument should be. It expects a number but we give it a new object.
In a parallel universe linexp might give you a warning or crash here, but our linexp doesnā€™t complain so itā€™s not easy to spot the error. It just swallows the new object and fail silently or you get some unexpected result.
That line must be written .linexp(0.0,1.0, 1, b.duration) for it to work. Then the linexp method will get the duration of b as a proper floating-point value for the fourth argument.

When to use b.duration over BufDur.kr(b) is a separate question. It has to do with language vs server code.

Because BufDur is a UGen it is only useful inside a synthesis graph i.e. within a SynthDef/Ndef or {}.play construction. Think of a BufDur as something that sends out a continuous signal.
Your Ndef(\tgrains).set and Ndef(\tgrains).addSpec are both language side code though so a signal there wonā€™t work. You will want to use b.duration there as it returns a single value.

compareā€¦

s.boot;
b = Buffer.alloc(s, 1000);  //one thousand samples, 1000/44100ā‰ˆ0.0227 (or whatever sr you use)

//sclang side...
b.duration
//a single number

//as b.duration returns a number it also can be used inside a synth...
Ndef(\a, {b.duration.poll; DC.ar(0)}).play
Ndef(\a).clear
//but then that particular duration value is hardcoded into the definition - no good for general purpose code

//it is better practice to use a BufDur ugen inside of a synth...
Ndef(\b, {BufDur.kr(b).poll; DC.ar(0)}).play
Ndef(\b).clear
//even though in this example it make no difference. Just as bad we have now hardcoded the buffer number b into the definition.

//the whole reason to use BufDur though is that you can use an argument and query the duration of any buffer...
Ndef(\c, {|buf| BufDur.kr(buf).poll; DC.ar(0)}).set(\buf, b).play
c = Buffer.alloc(s, 2000);
Ndef(\c).set(\buf, c);
Ndef(\c).clear
//now your synth code is generic and you can use it with any buffer (also swap buffers while the synth is running)

and last hereā€™s a common error that we all run into from time to timeā€¦

Ndef(\d, {BufDur(b).poll; DC.ar(0)}).play  //BAD
Ndef(\d).clear
//this is how BufDur fail silently - BufDur(b) need a rate - either .ir or .kr

_f

#|
fredrikolofsson.com musicalfieldsforever.com

1 Like

As lucid as ever, Fredrik. Thank you very much. The example code helps to see the behaviour in other contexts.
ā€¦edN

Side note: Please see also Code markup: Correct style ā€“ not using code markup tags may corrupt the code displayed in the forum (* may become boldface; "straight quotes" become ā€œcurved typographic quotesā€ etc).

hjh