/usr/share/SuperCollider/HelpSource/Guides/Non-Realtime-Synthesis.schelp is in supercollider-common 1:3.6.3~repack-5.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | title:: Non-Realtime Synthesis
summary:: Non-realtime synthesis with binary files of OSC commands
categories:: Server>NRT, External Control>OSC
related:: Classes/Score
section:: Non-Realtime Synthesis
SuperCollider 3 supports non-realtime synthesis through the use of binary files of OSC commands.
First create an OSC command file (i.e. a score)
code::
f = File("Cmds.osc","w");
// start a sine oscillator at 0.2 seconds.
c = [ 0.2, [\s_new, \NRTsine, 1001, 0, 0]].asRawOSC;
f.write(c.size); // each bundle is preceeded by a 32 bit size.
f.write(c); // write the bundle data.
// stop sine oscillator at 3.0 seconds.
c = [ 3.0, [\n_free, 1001]].asRawOSC;
f.write(c.size);
f.write(c);
// scsynth stops processing immediately after the last command, so here is
// a do-nothing command to mark the end of the command stream.
c = [ 3.2, [0]].asRawOSC;
f.write(c.size);
f.write(c);
f.close;
// the 'NRTsine' SynthDef
(
SynthDef("NRTsine",{ arg freq = 440;
Out.ar(0,
SinOsc.ar(freq, 0, 0.2)
)
}).writeDefFile;
)
::
then on the command line (i.e. in Terminal):
code::
./scsynth -N Cmds.osc _ NRTout.aiff 44100 AIFF int16
::
The command line arguments are:
code::
-N <cmd-filename> <input-filename> <output-filename> <sample-rate> <header-format> <sample-format> <...other scsynth arguments>
::
If you do not need an input sound file, then put "_" for the file name as in the example above.
For details on other valid arguments to the scsynth app see Server-Architecture.
This could be executed in SC as:
code::
"./scsynth -N Cmds.osc _ NRTout.aiff 44100 AIFF int16 -o 1".unixCmd; // -o 1 is mono output
::
A more powerful option is to use the link::Classes/Score:: object, which has convenience methods to create OSC command files and do nrt synthesis.
code::
(
x = [
[0.0, [ \s_new, \NRTsine, 1000, 0, 0, \freq, 1413 ]],
[0.1, [ \s_new, \NRTsine, 1001, 0, 0, \freq, 712 ]],
[0.2, [ \s_new, \NRTsine, 1002, 0, 0, \freq, 417 ]],
[0.3, [ \s_new, \NRTsine, 1003, 0, 0, \freq, 1238 ]],
[0.4, [ \s_new, \NRTsine, 1004, 0, 0, \freq, 996 ]],
[0.5, [ \s_new, \NRTsine, 1005, 0, 0, \freq, 1320 ]],
[0.6, [ \s_new, \NRTsine, 1006, 0, 0, \freq, 864 ]],
[0.7, [ \s_new, \NRTsine, 1007, 0, 0, \freq, 1033 ]],
[0.8, [ \s_new, \NRTsine, 1008, 0, 0, \freq, 1693 ]],
[0.9, [ \s_new, \NRTsine, 1009, 0, 0, \freq, 410 ]],
[1.0, [ \s_new, \NRTsine, 1010, 0, 0, \freq, 1349 ]],
[1.1, [ \s_new, \NRTsine, 1011, 0, 0, \freq, 1449 ]],
[1.2, [ \s_new, \NRTsine, 1012, 0, 0, \freq, 1603 ]],
[1.3, [ \s_new, \NRTsine, 1013, 0, 0, \freq, 333 ]],
[1.4, [ \s_new, \NRTsine, 1014, 0, 0, \freq, 678 ]],
[1.5, [ \s_new, \NRTsine, 1015, 0, 0, \freq, 503 ]],
[1.6, [ \s_new, \NRTsine, 1016, 0, 0, \freq, 820 ]],
[1.7, [ \s_new, \NRTsine, 1017, 0, 0, \freq, 1599 ]],
[1.8, [ \s_new, \NRTsine, 1018, 0, 0, \freq, 968 ]],
[1.9, [ \s_new, \NRTsine, 1019, 0, 0, \freq, 1347 ]],
[3.0, [\c_set, 0, 0]]
];
)
::
You can then use code::Score.write:: to convert the above to the OSC command file as follows:
code::
Score.write(x, "score-test.osc");
"./scsynth -N score-test.osc _ score-test.aiff 44100 AIFF int16 -o 1".unixCmd;
::
Score also provides methods to do nrt synthesis directly:
code::
(
var f, o;
g = [
[0.1, [\s_new, \NRTsine, 1000, 0, 0, \freq, 440]],
[0.2, [\s_new, \NRTsine, 1001, 0, 0, \freq, 660]],
[0.3, [\s_new, \NRTsine, 1002, 0, 0, \freq, 220]],
[1, [\c_set, 0, 0]]
];
o = ServerOptions.new.numOutputBusChannels = 1; // mono output
Score.recordNRT(g, "help-oscFile.osc", "helpNRT.aiff", options: o); // synthesize
)
::
section:: Analysis using a Non-Realtime server
An NRT server may also be used to extract analytical data from a sound file. The main issues are:
DEFINITIONlIST::
## Suppressing audio file output
|| In OSX and Linux environments, use teletype::/dev/null:: for the output file path. In Windows, use teletype::NUL::.
## Retrieving analytical data.
|| The easiest way is to allocate a buffer at the beginning of the NRT score, and use BufWr to fill the buffer. At the end of the score, write the buffer into a temporary file. Then you can use SoundFile on the language side to access the data. See the example.
::
code::
// Example: Extract onsets into a buffer.
(
fork {
var resultbuf, resultpath, oscpath, score, dur, sf, cond, size, data;
// get duration
sf = SoundFile.openRead(Platform.resourceDir +/+ "sounds/a11wlk01.wav");
dur = sf.duration;
sf.close;
resultpath = PathName.tmp +/+ UniqueID.next ++ ".aiff";
oscpath = PathName.tmp +/+ UniqueID.next ++ ".osc";
score = Score([
[0, (resultbuf = Buffer.new(s, 1000, 1, 0)).allocMsg],
[0, [\d_recv, SynthDef(\onsets, {
var sig = SoundIn.ar(0), // will come from NRT input file
fft = FFT(LocalBuf(512, 1), sig),
trig = Onsets.kr(fft),
// count the triggers: this is the index to save the data into resultbuf
i = PulseCount.kr(trig),
// count time in seconds
timer = Sweep.ar(1);
// 'i' must be audio-rate for BufWr.ar
BufWr.ar(timer, resultbuf, K2A.ar(i), loop: 0);
BufWr.kr(i, resultbuf, DC.kr(0), 0); // # of points in index 0
}).asBytes]],
[0, Synth.basicNew(\onsets, s, 1000).newMsg],
[dur, resultbuf.writeMsg(resultpath, headerFormat: "AIFF", sampleFormat: "float")]
]);
cond = Condition.new;
// osc file path, output path, input path - input is soundfile to analyze
score.recordNRT(oscpath, "/dev/null", sf.path, sampleRate: sf.sampleRate,
options: ServerOptions.new
.verbosity_(-1)
.numInputBusChannels_(sf.numChannels)
.numOutputBusChannels_(sf.numChannels)
.sampleRate_(sf.sampleRate),
action: { cond.unhang } // this re-awakens the process after NRT is finished
);
cond.hang; // wait for completion
sf = SoundFile.openRead(resultpath);
// get the size: one frame at the start
sf.readData(size = FloatArray.newClear(1));
size = size[0];
// now the rest of the data
sf.readData(data = FloatArray.newClear(size));
sf.close;
File.delete(oscpath); File.delete(resultpath);
data.postln; // these are your onsets!
};
)
::
|