class:: Node
summary:: Abstract superclass of Synth and Group
related:: Reference/Server-Architecture, Classes/Synth, Classes/Group, Classes/RootNode
categories:: Server>Nodes, Server>Abstractions

Description::
This class is the abstract super class of Synth and Group, which represent synth and group nodes on the server.  Node objects are not made explicitly, but Synth and Group are subclasses, and inherit the methods  documented below.

subsection:: Freed Nodes and Node Status

Nodes which you explicitly free using the methods free or release will have their group instance variable set to nil. However Nodes which are automatically freed after a certain time (for instance by an link::Classes/EnvGen:: with a doneAction of 2) will not.
This keeps the implementation of the classes simple and lightweight.

To have the current state of a Node tracked you can register it with an instance of link::Classes/NodeWatcher::, either by calling register on the Node instance or on the NodeWatcher singleton. This will enable two variables, isPlaying and isRunning, which you can use for checking purposes.

subsection:: Bundling

Many of the methods below have two versions: a regular one which sends its corresponding message to the server immediately, and one which returns the message in an link::Classes/Array:: so that it can be added to a bundle.
It is also possible to capture the messages generated by the regular methods using Server's automated bundling capabilities. See link::Classes/Server:: and link::Guides/Bundled-Messages:: for more details.

classmethods::
private:: initClass

method:: addActions
Returns:: the list of addActions as an event.
discussion::
Useful for converting addAction symbols to their corresponding integer codes.
code::
(
Node.addActions.at(\addToTail)
);
// returns 1
::

instancemethods::

subsection:: Instance Variables

The following getter methods also have corresponding setters, but they should be used with extreme care and only if you are sure you know what you're doing.

method:: nodeID
Returns:: the Node's node ID number.
discussion::
Normally you should not need to access this since instances of Node can be passed directly as link::Classes/UGen:: inputs or link::Classes/Synth:: args.

method:: group
Returns:: an instance of Group or RootNode corresponding to this Node's group on the server.

method:: server
Returns:: an instance of Server corresponding to this Node's server app.

method:: isPlaying
Returns:: a boolean indicating if this node is currently on the server, providing this Node has been registered with a link::Classes/NodeWatcher::.
discussion::
N.B. If this Node has not been registered this will likely be false in any case.

method:: isRunning
Returns:: a boolean indicating if this node is currently on the server, providing this Node has been registered with a link::Classes/NodeWatcher::.
discussion::
N.B. If this Node has not been registered this will likely be false in any case.

subsection:: Node Commands

See the Node Commands section in link::Reference/Server-Command-Reference:: for the OSC equivalents of the methods outlined below.

method:: free, freeMsg
Stop this Node and free it from its parent group on the server. Once a Node has been freed, you cannot restart it.
argument:: sendFlag
a boolean indicating whether the free message should be sent. If false an n_free message will not be sent to this Node's server, but its isPlaying and isRunning variables will be set to false. The default for sendFlag is true.
discussion::
If this Node is a link::Classes/Group:: this will free all Nodes within the Group.
code::
s.boot;
x = Synth("default");
x.free;
::

method:: run, runMsg
Set the running state of this Node according to a boolean. False will pause the node without freeing it. The default is true.
discussion::
If this Node is a Group this will set the running state of all Nodes within the Group.
code::
s.boot;
(
x = SynthDef("help-node-set", { |freq = 440, out = 0|
	Out.ar(out, SinOsc.ar(freq, 0, 0.1))
}).play
)
x.run(false);
x.run; // default is true
x.free;
::

method:: set, setMsg
Set controls in this Node to values.
discussion::
Controls are defined in a SynthDef as args or instances of link::Classes/Control::. They are specified here using symbols, strings, or indices, and are listed in pairs with values. If this Node is a Group this will set all Nodes within the Group.
code::
s.boot;
(
x = SynthDef("help-node-set", { |freq = 440, out = 0|
	Out.ar(out, SinOsc.ar(freq, 0, 0.1))
}).play
)
x.set(\freq, 880, \out, 1); // two pairs
x.set(0, 660, 1, 0); // freq is the first argument, so it's index is 0. out is index 1.
x.free;
::
Values that are arrays are sent using the OSC array type-tags ($[ and $]).  These values will be assigned to subsequent controls in the manner of setn.
code::
s.boot;
(
x = SynthDef("help-node-set", { |freq = #[440, 450, 460], out = 0|
	Out.ar(out, Mix(SinOsc.ar(freq, 0, 0.1)))
}).play
)
x.set(\freq, [1,2,3] * 400 + [1, 2, 3], \out, 1); // two pairs
x.set(\freq, [3] * 400 + [1, 2, 3], \out, 1); // two pairs
x.set(0, [660, 680, 720], 1, 0); // freq is the first argument, so it's index is 0. out is index 1.
x.free;
::

method:: setn, setnMsg
Set sequential ranges of controls in this Node to values.
discussion::
Controls are defined in a SynthDef as args or instances of link::Classes/Control::. They are specified here using symbols, strings, or indices, and are listed in pairs with arrays of values. If this Node is a Group this will setn all Nodes within the Group.
code::
s.boot;
(
x = SynthDef("help-node-setn", {
	arg out, freq1 = 440, freq2 = 440, freq3 = 440, amp1 = 0.05, amp2 = 0.05, amp3 = 0.05;
	Out.ar(out, Mix(SinOsc.ar([freq1, freq2, freq3], 0, [amp1, amp2, amp3])))
}).play;
)
// set 3 controls starting from \freq1, and 3 controls starting from \amp1
x.setn(\freq1, [440, 880, 441], \amp1, [0.3, 0.1, 0.3]);
x.free;
::

method:: fill, fillMsg
Set sequential ranges of controls in this Node to a single value.
discussion::
Controls are defined in a SynthDef as args or instances of link::Classes/Control::. They are specified here using symbols, strings, or indices, and are listed in groups of three along with an integer indicating the number of controls to set, and the value to set them to. If this Node is a Group this will fill all Nodes within the Group.

method:: map, mapMsg
Map controls in this Node to read from control or audio rate link::Classes/Bus::es.
discussion::
Controls are defined in a SynthDef as args or instances of link::Classes/Control:: or its subclasses. They are specified here using symbols, strings, or indices, and are listed in pairs with Bus objects. The number of sequential controls mapped corresponds to the Bus' number of channels.

If this Node is a Group this will map all Nodes within the Group.

Note that with mapMsg if you mix audio and control rate busses you will get an Array of two messages rather than a single message. Integer bus indices are assumed to refer to control buses. To map a control to an audio bus, you must use a Bus object.
code::
s.boot;
(
b = Bus.control(s, 1); b.set(880);
c = Bus.control(s, 1);	c.set(884);
x = SynthDef("help-Node-map", { |out, freq1 = 440, freq2 = 440|
	Out.ar(out, SinOsc.ar([freq1, freq2], 0, 0.1));
}).play
)
x.map(\freq1, b, \freq2, c);
x.free; b.free; c.free;

// same as above with a multichannel Bus and Control
(
b = Bus.control(s, 2);
b.set(880, 884);
x = SynthDef("help-Node-map2", { |out, freqs = #[440, 440]|
	Out.ar(out, SinOsc.ar(freqs, 0, 0.1));
}).play
)

x.map(\freqs, b);
x.free; b.free;
::

method:: mapn, mapnMsg
Map sequential ranges of controls in this Node to read from control rate Buses.
discussion::
This is similar to map above, but you specify the number of sequential Controls to map. If this Node is a Group this will mapn all Nodes within the Group.

method:: release, releaseMsg
This method causes the receiver to be freed after the specified amount of time. This is a convenience method which assumes that the synth contains an envelope generator (an EnvGen, Linen, or similar UGen) running a sustaining envelope (see link::Classes/Env#Sustained Envelope Creation Methods::) and that this envelope's gate argument is set to a control called code::\gate::.
argument:: releaseTime
The amount of time in seconds during which the node will release. If set to a value code::<= 0::, the synth will release immediately. A code::nil:: value will cause the synth to release using its envelope's normal release stage(s).

note::
Providing a releaseTime != nil doesn't trigger a normal release, but a different behavior called forced release. This difference is particularly important for envelopes with a multi-node release stage, i.e. whose releaseNode is not their last node. See link::Classes/EnvGen#Forced release#::.
::

discussion::
If the receiver is a Group, all nodes within the group will be released.
code::
x = { arg gate=1; BrownNoise.ar(0.5) * EnvGen.kr(Env.cutoff(1), gate, doneAction: Done.freeSelf) }.play;
x.release(5); // override the Env's specified 1 second release time
::
method:: query
Sends an n_query message to the server, which will reply with a message containing information about this node and its place in the server's node tree.
argument:: action
An optional Function to be called. If the node is a code::Synth::, the function will take the arguments code::serverCmd, nodeID, parent, prev, next, isGroup::. If the node is a code::Group::, the function will take the arguments code::serverCmd, nodeID, parent, prev, next, isGroup, head, tail::. Providing a function here will bypass code::query::'s normal behaviour, i.e., the usual node information will not be posted.
discussion::
This information will be printed to the post window. (See also the queryAllNodes method of Server.) "parent" indicates the Node's enclosing group. If "prev" or "next" are equal to -1 that indicates that there are no other nodes in the enclosing group before or after this one, respectively.
code::
g = Group.new;
x = Synth.head(g, "default");
x.query;
g.query;
s.queryAllNodes; // Note the RootNode (ID 0) and the default Group (ID 1)
x.free; g.free;
::

method:: trace
Causes a synth to print out the values of the inputs and outputs of its unit generators for one control period to the post window. Causes a group to print the node IDs and names of each node in the group for one control period.
code::
g = Group.new;
x = Synth.head(g, \default);
x.trace;
g.trace;
x.free; g.free;
::

method:: register
Registers the node at the link::Classes/NodeWatcher:: object.
discussion::
This will enable two variables, isPlaying and isRunning, which you can use for checking purposes.
code::
(
b = s.makeBundle(false, {
	a = Group.new(s); //create a node object
	a.register // register before creating on the server
})
)

a.isPlaying;
s.listSendBundle(nil, b); //start the node on the server
a.isPlaying;
a.isRunning;
a.run(false);
a.isRunning;
s.freeAll; //free all nodes
a.isPlaying;
a.isRunning;
::

subsection:: Changing the order of execution

The following methods can be used to change the Node's place in the order of execution. See the link::Guides/Order-of-execution:: help file for more information on this important topic. See link::Reference/Server-Command-Reference:: for the OSC equivalents of these methods.

method:: moveAfter, moveAfterMsg
Move this Node to be directly after aNode. N.B. n_after, the OSC message which this method encapsulates, allows already freed nodes as targets. This is so that one may attempt a series of moves, with the last successful one taking effect. For this reason this method will fail silently if either the target or this node have already been freed. If you will need to check, you may register the relevant nodes with a NodeWatcher.

method:: moveBefore, moveBeforeMsg
Move this Node to be directly before aNode. N.B. n_before, the OSC message which this method encapsulates, allows already freed nodes as targets. This is so that one may attempt a series of moves, with the last successful one taking effect. For this reason this method will fail silently if either the target or this node have already been freed. If you will need to check, you may register the relevant nodes with a NodeWatcher.

method:: moveToHead, moveToHeadMsg
If aGroup is a Group then this method will move this Node to the head of that Group. If it is nil this will move this Node to the head of the default_group of this Node's Server.

method:: moveToTail, moveToTailMsg
If aGroup is a Group then this method will move this Node to the tail of that Group. If it is nil this will move this Node to the tail of the default_group of this Node's Server.

subsection:: Other Methods

method:: asTarget
Returns:: this Node. See the link::Reference/asTarget:: help file for more details.

method:: printOn
Prints this Node's link::Classes/Class:: (link::Classes/Synth:: or link::Classes/Group::) and nodeID on stream.

method:: hash
Returns:: server.hash bitXor: nodeID.hash

method:: ==
Returns:: true if this Node and aNode have the same nodeID and the same Server object, otherwise returns false.
discussion::
Under certain circumstances this Node and aNode might not be the same object, even though this returns true.
code::
g = Group.basicNew(s, 1); // the default group of s
h = Group.basicNew(s, 1); // and again
g == h; 	// true
g === h;	// false
::

method:: onFree
Evaluate function when this Node is freed.
discussion::
code::
{PinkNoise.ar(1) * Line.kr(1,0,2,doneAction: Done.freeSelf)}.play.onFree {"done".postln};
::

method:: waitForFree
Wait until this Node is freed. Should be used inside a Routine or similar.
discussion::
code::
(
fork {
    { SinOsc.ar(440 ! 2) * Line.kr(0, 1, 5, doneAction: Done.freeSelf) }.play.waitForFree;
    { PinkNoise.ar(1) * Line.kr(1, 0, 2, doneAction: Done.freeSelf) }.play.onFree {"done".postln};
}
)
::

code::
(
SynthDef(\help, { |out|
	var mod = LFNoise2.kr(Rand(1, 6)) * 0.2;
	var snd = mod * Blip.ar(Rand(200, 800) * (mod + 1));
	Out.ar(out, snd);
	FreeSelf.kr(mod < 0);
}).add;
)

(
fork {
	10.do {
		"started a synth".postln;
		Synth(\help).waitForFree;
		"This one ended. Wait a second, I will start the next one.".postln;
		1.wait;
	};
	"This is it.".postln;
}
);
::
