Skip to content

Commit

Permalink
Merge pull request #2422 from telephon/topic-server-refactoring-reord…
Browse files Browse the repository at this point in the history
…ered

class library and ide: refactor server
  • Loading branch information
Alberto de Campo committed Dec 2, 2016
2 parents b4e8660 + f75f65b commit 6a3f37e
Show file tree
Hide file tree
Showing 18 changed files with 1,283 additions and 773 deletions.
164 changes: 164 additions & 0 deletions HelpSource/Classes/Recorder.schelp
@@ -0,0 +1,164 @@
class:: Recorder
summary:: Write Audio to Harddisk
categories:: Server>Abstractions
related:: Classes/Server, Classes/DiskOut, Guides/Non-Realtime-Synthesis

description:: A Recorder allows you to write audio to harddisk, reading from a given bus and a certain number of channels, relative to a given node. A link::Classes/Server:: has one instance, which is accessible also through the link::Classes/ScIDE::. You can use the server directly to record its output


code::
(
{ SinOsc.ar(
SinOsc.ar(
XLine.kr(1, 100, 5)).exprange(*XLine.kr([20, 800], [7000, 200], 10)
)
) * 0.1

}.play;
s.record(duration: 10);
)
::


This functionality is also available through the recording button on the server windows.
Pressing it once calls record, and pressing it again calls stopRecording (see below). When doing so the file created will be in your recordings folder and be named for the current date and time.
The default location of the recordings folder varies from platform to platform. Setting this variable allows you to change the default.

code::
// find where the recordings are written to
thisProcess.platform.recordingsDir
::

NOTE::
By default, record creates the recording synth after the Server's default group and uses In.ar. Thus if you add nodes after the recording synth their output will not be captured.
To avoid this, either use Node objects (which use the default node as their target) or (when using messaging style) use a target nodeID of 1.
code::
s.sendMsg("/s_new", "default", s.nextNodeID, 1, 1);
::
::

For more detail on this subject see link::Guides/Order-of-execution::, link::Reference/default_group::, and link::Guides/NodeMessaging::.

See link::Classes/SoundFile:: for information on the various sample and header formats.
Not all sample and header formats are compatible. Note that the sampling rate of the output file will be the same as that of the server app. This can be set using the Server's link::Classes/ServerOptions::.



ClassMethods::

method::new
Create a new instance for a given server.

argument::server


InstanceMethods::

method:: prepareForRecord
Allocates the necessary buffer, etc. for recording the server's output. (See code::record:: below.)

argument:: path
a link::Classes/String:: representing the path and name of the output file.

argument::numChannels
The number of output channels to record.

discussion::
If you do not specify a path than a file will be created in your recordings folder (see the note above on this) called code::SC_thisDateAndTime::. Changes to the header or sample format, or to the number of channels must be made strong::before:: calling this.



method:: record
Starts or resumes recording the output.
argument:: path
this is optional, and is passed to code::prepareForRecord:: (above).

argument:: bus
The bus (link::Classes/Bus:: object or integer bus index), the offset at which to start to count the number of channels. You can record any adjacent number of bus channels.

argument:: numChannels
The number of output channels to record.

argument:: node
The link::Classes/Node:: to record immediately after. By default, this is the default group 1.

argument:: duration
If set, this limits recording to a given time in seconds.

discussion::
If you have not called prepareForRecord first (see above) then it will be invoked for you (but that adds a slight delay before recording starts for real).

code::
r = Recorder(s);
{ GVerb.ar(Dust.ar(4)) }.play; // play on bus 64
r.record(numChannels:2, duration:2);
r.stopRecording;
::

method:: pauseRecording
Pauses recording. Can be resumed by executing record again, or by calling resumeRecording.

method:: resumeRecording
Start recording again.

method:: stopRecording
Stops recording, closes the file, and frees the associated resources.
discussion::
You must call this when finished recording or the output file will be unusable. Cmd-. while recording has the same effect.

method:: recHeaderFormat
Get/set the header format (string) of the output file. The default is "aiff". Must be called strong::before:: prepareForRecord.

method:: recSampleFormat
Get/set the sample format (string) of the output file. The default is "float". Must be called strong::before:: prepareForRecord.

method::recBufSize
Get/set the size of the link::Classes/Buffer:: to use with the link::Classes/DiskOut:: UGen. This must be a power of two. The default is the code::sampleRate.nextPowerOfTwo:: or the first power of two number of samples longer than one second. Must be called strong::before:: prepareForRecord.

method::isRecording
returns true, if we are inthe process of recording

method::duration
returns the number of seconds we have been recording so far

private::cmdPeriod
private::prRecord
private::prStopRecord
private::makePath

section::Examples


code::
s.boot; // start the server

// something to record
(
SynthDef("bubbles", {
var f, zout;
f = LFSaw.kr(0.4, 0, 24, LFSaw.kr([8,7.23], 0, 3, 80)).midicps; // glissando function
zout = CombN.ar(SinOsc.ar(f, 0, 0.04), 0.2, 0.2, 4); // echoing sine wave
Out.ar(0, zout);
}).add;
SynthDef("tpulse", { arg out=0,freq=700,sawFreq=440.0;
Out.ar(out, SyncSaw.ar(freq, sawFreq,0.1) )
}).add;

)

x = Synth.new("bubbles");

s.prepareForRecord; // if you want to start recording on a precise moment in time, you have to call this first.

s.record; // start recording. This can also be called directly, if it isn't imprtant when precisely you need to start.

s.pauseRecording; // pausable

s.record // start again

s.stopRecording; // this closes the file and deallocates the buffer recording node, etc.

x.free; // stop the synths

// look in your recordings folder and you'll find a file named for this date and time
::
120 changes: 62 additions & 58 deletions HelpSource/Classes/Server.schelp
Expand Up @@ -5,69 +5,27 @@ related:: Classes/ServerOptions, Reference/Server-Architecture, Reference/Server

description::

A Server object is the client-side representation of a server app and is used to control the app from the SuperCollider language application. (See link::Guides/ClientVsServer:: for more details on the distinction.)
It forwards OSC messages and has a number of allocators that keep track of IDs for nodes, buses and buffers.
A Server object is a representation of a server application. It is used to control it from SuperCollider language. (See link::Guides/Server-Guide::, as well as link::Guides/ClientVsServer:: for more details on the distinction.) It forwards OSC messages and has a number of allocators that keep track of IDs for nodes, buses and buffers.

The server application is a commandline program, so all commands apart from OSC messages are unix commands.

The server application represented by a Server object might be running on the same machine as the client (in the same address space as the language application or separately; see below), or it may be running on a remote machine.
The server application represented by a Server object might be running on the same machine as the sclang, or it may be running on a remote machine.

Most of a Server's options are controlled through its instance of ServerOptions. See the link::Classes/ServerOptions:: helpfile for more detail.

subsection:: Paths

Server apps running on the local machine have two unix environment variables: code::SC_SYNTHDEF_PATH:: and code::SC_PLUGIN_PATH::. These indicate directories of synthdefs and ugen plugins that will be loaded at startup. These are in addition to the default synthdef/ and plugin/ directories which are hard-coded.
A server also holds an instance of a link::Classes/Recorder:: (for recording output into a file) and a link::Classes/Volume:: (master level).

These can be set within SC using the getenv and setenv methods of class link::Classes/String::.
code::
// all defs in this directory will be loaded when a local server boots
"SC_SYNTHDEF_PATH".setenv("~/scwork/".standardizePath);
"echo $SC_SYNTHDEF_PATH".unixCmd;
note::
By default, there is always one default server, which is stored in the interpreter variable 's'. E.g. you can boot the defult server by calling code::s.boot::
::

subsection:: The default group

When a Server is booted there is a top level group with an ID of 0 that defines the root of the node tree. (This is represented by a subclass of link::Classes/Group:: : link::Classes/RootNode::.)
If the server app was booted from within SCLang (as opposed to from the command line) the method code::initTree:: will be called automatically after booting.
This will also create a link::Reference/default_group:: with an ID of 1, which is the default group for all link::Classes/Node::s when using object style.
This provides a predictable basic node tree so that methods such as Server-scope, Server-record, etc. can function without running into order of execution problems.

The default group is persistent, i.e. it is recreated after a reboot, pressing cmd-., etc. See link::Classes/RootNode:: and link::Reference/default_group:: for more information.
Note::
If a Server has been booted from the command line you must call code::initTree:: manually in order to initialize the default group, if you want it. See code::initTree:: below.
code::
s.boot;
{ SinOsc.ar * 0.1 }.play(s); // play a synth on the server
::

subsection:: Local vs. Internal

In general, when working with a single machine one will probably be using one of two Server objects which are created at startup and stored in the class variables link::#*local:: and link::#*internal::. In SuperCollider.app (OSX), two GUI windows are created to control these. Use link::#-makeGui:: to create a GUI window manually.

The difference between the two is that the local server runs as a separate application with its own address space, and the internal server runs within the same space as the language/client app.

Both local and internal server supports link::#-scope#scoping:: and link::Classes/Bus#Synchronous control bus methods#synchronous bus access::.

The local server, and any other server apps running on your local machine, have the advantage that if the language app crashes, it (and thus possibly your piece) will continue to run. It is thus an inherently more robust arrangement. But note that even if the synths on the server continue to run, any language-side sequencing and control will terminate if the language app crashes.

At the current time, there is generally no benefit in using the internal server, but it remains for the purposes of backwards compatibility.

subsection:: The default Server

There is always a default Server, which is stored in the class variable code::default::. Any link::Classes/Synth::s or link::Classes/Group::s created without a target will be created on the default server. At startup this is set to be the local server (see above), but can be set to be any Server.

subsection:: Local vs. Remote Servers, Multi-client Configurations

Most of the time users work with a server app running on the same machine as the SC language client. It is possible to use a server running on a different machine via a network, providing you know the IP address and port of that server. The link::#*remote:: method provides a convenient way to do this.

One common variant of this approach is multiple clients using the same server. If you wish to do this you will need to set the server's link::Classes/ServerOptions#-maxLogins:: to at least the number of clients you wish to allow. When a client registers for link::#-notify#notifications:: the server will supply a client ID. This also configures the allocators to avoid conflicts when allocating link::Classes/Node##Nodes::, link::Classes/Buffer##Buffers::, or link::Classes/Bus##Busses::.

In order to use a remote server with tcp one should first boot the remote server using the code::-t:: option and then run the following code:
The server application may be in three different states: running, not running, or unresponsive (for example while loading large files from disk).

code::
(
s.options.protocol_(\tcp);
s.addr.connect;
s.startAliveThread( 0 );
s.doWhenBooted({ "remote tcp server started".postln; s.notify; s.initTree });
)
s.serverRunning // returns true if it is true
::


Expand Down Expand Up @@ -113,22 +71,42 @@ get/set the local server, stored in classvar code::local:: (created already on i

method:: internal
get/set the internal server, stored in classvar code::internal:: (created already on initClass)
See: link::Guides/Server-Guide::

method:: default
Get or set the default server. By default this is the local server (see above).
discussion::
Setting this will also assign it to the link::Classes/Interpreter:: variable 's'.
code::
Server.default = Server.internal; // set the internal Server to be the default Server
// set the internal Server to be the default Server
Server.default = Server.internal;
s.postln; // internal
::

subsection::Accessing all servers

method:: all
get/set the set of all servers.
get a link::Classes/Set:: of all servers

code::
Server.all
::

method:: allRunningServers
returns:: the set of all running servers.

code::
Server.allRunningServers
::

method:: named
get an link::Classes/IdentityDictionary:: of all servers listed by their name

code::
Server.named.at(\default)
::


method:: quitAll
quit all registered servers

Expand All @@ -138,6 +116,18 @@ query the system for any sc-server apps and hard quit them
method:: freeAll
free all nodes in all registered servers

method:: hardFreeAll
try to free all nodes in all registered servers, even if the server seems not to be running

method::sync_s
If kept true (default), when the default server is changed, also the interpreter variable s is changed.
code::
Server.default = Server(\alice, NetAddr("127.0.0.1", 57130));
s.postln; // see: it is alice.
::

subsection::Switching the server application

method:: supernova

Switches the server program to supernova. Check link::Classes/ParGroup:: how to make use of multicore hardware with the supernova server.
Expand Down Expand Up @@ -232,15 +222,29 @@ argument:: recover
If true, create a new node ID allocator for the server, but use the old buffer and bus allocators. This is useful if the server process did not actually stop. In normal use, the default value "false" should be used.
argument:: onFailure
In this method, the onFailure argument is for internal use only. If you wish to take specific actions when the server boots or fails to boot, it is recommended to use link::#-waitForBoot:: or link::#-doWhenBooted::.

discussion::
N.B. You cannot boot a server app on a remote machine.
You cannot boot a server app on a remote machine, but you can initialise the allocators by calling this message.

method:: quit
quit the server application

argument::onComplete
A function that is called when quit has completed.

argument::onFailure
A function that is called when quit has failed.


method:: reboot
quit and restart the server application

argument::func
a function that is called between quit and (re-)boot.

argument::onFailure
A function that is called when quit has failed.

method:: freeAll
free all nodes in this server

Expand Down Expand Up @@ -334,7 +338,7 @@ Returns true if a link::Classes/ServerShmInterface:: is available. See also link
discussion::
The shared memory interface is initialized after first server boot.

subsection:: Automatic Message Bundling
subsection:: Message Bundling

Server provides support for automatically bundling messages. This is quite convenient in object style, and ensures synchronous execution. See also link::Guides/Bundled-Messages::

Expand Down Expand Up @@ -566,6 +570,8 @@ x.free; // stop the synths
// look in your recordings folder and you'll find a file named for this date and time
::

Recording is done via an of link::Classes/Recorder:: - a server holds one instance implicitly.

method:: prepareForRecord
Allocates the necessary buffer, etc. for recording the server's output. (See code::record:: below.)
argument:: path
Expand All @@ -588,8 +594,6 @@ Stops recording, closes the file, and frees the associated resources.
discussion::
You must call this when finished recording or the output file will be unusable. Cmd-. while recording has the same effect.

method:: recordNode
Returns:: the current recording synth so that it can be used as a target. This should only be necessary for nodes which are not created in the default group.

method:: recChannels
Get/set the number of channels (int) to record. Is automatically set to the value of link::Classes/ServerOptions#-numOutputBusChannels:: when booting the server. Must be called strong::before:: prepareForRecord.
Expand Down

0 comments on commit 6a3f37e

Please sign in to comment.