scel: install files to site-lisp/SuperCollider
[supercollider.git] / HelpSource / Guides / Debugging-tips.schelp
blob43017e7b080419f569db7f07f36c2e6dc0c0739e
1 title:: Debugging tips
2 summary:: tips on debugging synthdefs, client code and more
3 categories:: Language, Debugging
4 related:: Guides/Understanding-Errors
6 section:: Debugging synthdefs
8 The challenge in debugging synthdefs is the invisibility of the server's operations. There are a handful of techniques to expose the output of various UGens.
10 subsection:: SendTrig / OSCFunc
12 SendTrig is originally intended to send a trigger message back to the client, so the client can take further action on the server. However, it can be used to send any numeric value back to the client, which can then be printed out.
14 To print out the values, you need to create an OSCresponderNode as follows:
15 code::
16 o = OSCFunc({ |msg| msg.postln }, '/tr', s.addr);
18 Each line of output is an array with four values: code:: ['/tr', defNode, id (from SendTrig), value (from SendTrig)] ::.
20 code::
21 {       var     freq;
22         freq = LFNoise1.kr(2, 600, 800);
23                 // Impulse is needed to trigger the /tr message to be sent
24         SendTrig.kr(Impulse.kr(4), 0, freq);
25         SinOsc.ar(freq, 0, 0.3) ! 2
26 }.play;
27 [ /tr, 1000, 0, 1340.8098144531 ]
28 [ /tr, 1000, 0, 1153.9201660156 ]
29 [ /tr, 1000, 0, 966.35247802734 ]
30 [ /tr, 1000, 0, 629.31628417969 ]
32 o.free;  // when done, you need to clean up the OSCFunc
35 If you need to track multiple values, you can store them in a collection of arrays and differentiate them by assigning different IDs in the SendTrig UGen.
36 code::
37 l = { List.new } ! 2;
38 o = OSCFunc({ |msg|
39                 // msg[2] is the index
40         l[msg[2]].add(msg[3]);
41 }, '/tr', s.addr);
43 {       var     freq, amp;
44         freq = LFNoise0.kr(8, 600, 800);
45         amp = LFNoise1.kr(10, 0.5, 0.5);
46                 // Impulse is needed to trigger the /tr message to be sent
47         SendTrig.kr(Impulse.kr(4), 0, freq);
48         SendTrig.kr(Impulse.kr(4), 1, amp);
49         SinOsc.ar(freq, 0, 0.3) ! 2
50 }.play;
52 o.free;  // when done, you need to clean up the OSCFunc
54 l[0].array.plot // view frequencies
55 l[1].array.plot // view amps
58 subsection:: Shared controls (Internal server only, control rate only)
60 The internal server allocates a number of control buses whose memory addresses are shared with the client. The client can poll these buses without using OSC messages.
62 Insert a SharedOut.kr UGen into your synthdef. Then, on the client side, use s.getSharedControl(num) to read the value. If you want to track the value over time, use a routine to poll repeatedly.
63 code::
64 {       var     freq;
65         freq = LFNoise1.kr(2, 600, 800);
66         SharedOut.kr(0, freq);          // no need for Impulse here
67         SinOsc.ar(freq, 0, 0.3) ! 2
68 }.play;
70 l = List.new;
71 r = fork { loop { l.add(s.getSharedControl(0)); 0.1.wait } };
72 r.stop;
73 l.array.plot;  // to view the results graphically
76 subsection:: Server-side trace
78 The code::/n_trace:: message causes the server to print a list of all the UGens in the node as well as their input and output values.
80 It takes some practice to read a synthdef trace, but it's the ultimate source of information when a synthdef is not behaving as expected. Signal flow can be identified by looking at the numbers at inputs and outputs. When a UGen's output feeds into another's input, the values will be the same at both ends.
82 For a concrete example, let's look at a synthdef that doesn't work. The intent is to generate a detuned sawtooth wave and run it through a set of parallel resonant filters whose cut-off frequencies are modulating randomly.
83 We run the synth and generate the trace (reproduced below).
84 code::
85 SynthDef(\resonz, { |freq = 440|
86         var     sig, ffreq;
87         sig = Saw.ar([freq, freq+1], 0.2);
88         ffreq = LFNoise1.kr(2, 1, 0.5);
89         Out.ar(0, Resonz.ar(sig, (800, 1000..1800) * ffreq, 0.1))
90 }).send(s);
92 a = Synth(\resonz);
93 a.trace;
94 a.free;
96                 TRACE 1005  resonz    #units: 21
97                   unit 0 Control
98                     in
99                     out 440
100                   unit 1 BinaryOpUGen
101                     in  440 1
102                     out 441
103                   unit 2 Saw
104                     in  441
105                     out 0.451348
106                   unit 3 BinaryOpUGen
107                     in  0.451348 0.2
108                     out 0.0902696
109                   unit 4 Saw
110                     in  440
111                     out -0.367307
112                   unit 5 BinaryOpUGen
113                     in  -0.367307 0.2
114                     out -0.0734615
115                   unit 6 LFNoise1
116                     in  2
117                     out -0.836168
118                   unit 7 BinaryOpUGen
119                     in  -0.836168 0.5
120                     out -0.336168
121                   unit 8 BinaryOpUGen
122                     in  800 -0.336168
123                     out -268.934
124                   unit 9 Resonz
125                     in  -0.0734615 -268.934 0.1
126                     out 843934
127                   unit 10 BinaryOpUGen
128                     in  1000 -0.336168
129                     out -336.168
130                   unit 11 Resonz
131                     in  0.0902696 -336.168 0.1
132                     out 3.02999e+08
133                   unit 12 BinaryOpUGen
134                     in  1200 -0.336168
135                     out -403.402
136                   unit 13 Resonz
137                     in  -0.0734615 -403.402 0.1
138                     out 9.14995e+10
139                   unit 14 BinaryOpUGen
140                     in  1400 -0.336168
141                     out -470.635
142                   unit 15 Resonz
143                     in  0.0902696 -470.635 0.1
144                     out -5.42883
145                   unit 16 BinaryOpUGen
146                     in  1600 -0.336168
147                     out -537.869
148                   unit 17 Resonz
149                     in  -0.0734615 -537.869 0.1
150                     out 515.506
151                   unit 18 BinaryOpUGen
152                     in  1800 -0.336168
153                     out -605.102
154                   unit 19 Resonz
155                     in  0.0902696 -605.102 0.1
156                     out 32785.2
157                   unit 20 Out
158                     in  0 843934 3.02999e+08 9.14995e+10 -5.42883 515.506 32785.2
159                     out
162 Two problems leap out from the trace: first, there are six channels of the output (there should be 1), and second, all the outputs are well outside the audio range -1..1. The first is because we use multichannel expansion to produce an array of Resonz filters, but we don't mix them down into a single channel.
164 Note that there are no out of range signals prior to each Resonz. Looking at the Resonz inputs, we see that the frequency input is negative, which will blow up most digital filters.
166 The resonance frequency derives from multiplying an array by a LFNoise1. Tracing back (the red, italicized numbers), the LFNoise1 is outputting a negative number, where we expected it to be 0.5..1.5. But, the mul and add inputs are reversed!
168 If you look very carefully at the trace, you will see another problem relating to multichannel expansion. The two components of the detuned sawtooth go into alternate Resonz'es, where we expected both to go, combined, into every Resonz. To fix it, the sawtooths need to be mixed as well.
169 code::
170 SynthDef(\resonz, { |freq = 440|
171         var     sig, ffreq;
172         sig = Mix.ar(Saw.ar([freq, freq+1], 0.2));
173         ffreq = LFNoise1.kr(2, 0.5, 1);
174         Out.ar(0, Mix.ar(Resonz.ar(sig, (800, 1000..1800) * ffreq, 0.1)))
175 }).send(s);
177 a = Synth(\resonz);
178 a.trace;
179 a.free;
182 section:: Debugging client-to-server communication
184 Some bugs result from OSC messages to the server being constructed incorrectly. Julian Rohrhuber's DebugNetAddr is a convenient way to capture messages. The class may be downloaded from: http://swiki.hfbk-hamburg.de:8888/MusicTechnology/710 .
186 To use it, you need to quit the currently running local server, then create a new server using a DebugNetAddr instead of a regular NetAddr. Messages will be dumped into a new document window.
187 code::
188 s.quit;
190 Server.default = s = Server.new('local-debug', DebugNetAddr("localhost", 57110));
191 s.boot;
192 s.makeWindow;           // optional
194         latency nil             // these messages get sent on bootup
195                 [ "/notify", 1 ]
197         latency nil
198                 [ "/g_new", 1 ]
200 a = { SinOsc.ar(440, 0, 0.4) ! 2 }.play;
202         latency nil
203                 [ "/d_recv", "data[ 290 ]", [ 9, "-1589009783", 1001, 0, 1, 'i_out', 0, 'out', 0 ] ]
205 a.free;
207         latency nil
208                 [ 11, 1001 ]
211 section:: Debugging client code
213 SuperCollider does not have a step trace function, which makes debugging on the client side tougher, but not impossible.
215 subsection:: Errors
217 Learning how to read SuperCollider error output is absolutely essential. Error dumps often (though not always) contain a great deal of information: what the action was, which objects are being acted upon, and how the flow of execution reached that point.
219 See the link::Guides/Understanding-Errors:: help file for a tutorial.
221 There's also a graphic Inspector for error dumps, which is enabled with the following command:
222 code::
223 Exception.debug = true;         // enable
224 Exception.debug = false;        // disable
226 In most cases, this will give you more information than a regular error dump. Usually the regular error dump is sufficient. If you are using Environments or prototype-style programming, the graphic inspector is indispensable.
228 subsection:: Debug output using post statements
230 The most common approach is to insert statements to print the values of variables and expressions. Since the normal printing methods don't change the value of an expression, they can be placed in the middle of the statement without altering the processing flow. There's no significant difference between:
231 code::
232 if(a > 0) { positive.value(a) };
235 code::
236 if((a > 0).postln) { positive.value(a) };
239 Common methods to use are:
240 code::
241 .postln
242 .postcs         // post the object as a compile string
243 .debug(caller)  // post the object along with a tag identifying the caller
246 code::
248 var     positiveFunc;
249 positiveFunc = { |a|
250         a.debug('positiveFunc-arg a');
251         a*10
253 a = 5;
254 if (a > 0) { positiveFunc.value(a) };
257 // output:
258 positiveFunc-arg a: 5
262 The caller argument is optional; however, it's very helpful for tracing the origin of erroneous values.
264 Another advantage of .debug is that it's easier to search for them in your source code and remove them later.
266 To print multiple values at one time, wrap them in an array before using .debug or .postcs. Note that if any of the array members are collections, postln will hide them behind the class name: "an Array, a Dictionary" etc. Use postcs if you expect to be posting collections.
267 code::
268 [val1, val2, val3].debug(\myMethod);
269 [\callerTag, val1, val2, val3].postcs;
271 By sprinkling these throughout your code, especially at the beginnings of functions or methods, the debugging output can give you a partial trace of which code blocks get visited in what order.
273 subsection:: dumpBackTrace
275 If you discover that a particular method or function is being entered but you don't know how it got there, you can use the code::.dumpBackTrace:: method on any object. You'll get what looks like an error dump, but without the error. Execution continues normally after the stack dump.
276 code::
278 var     positiveFunc;
279 positiveFunc = { |a|
280         a.debug('positiveFunc-arg a');
281         a.dumpBackTrace;
282         a*10
284 a = 5;
285 if (a > 0) { positiveFunc.value(a) };
288 // output:
289 positiveFunc-arg a: 5
290 CALL STACK:
291         < FunctionDef in closed FunctionDef >
292                 arg a = 5
293         < closed FunctionDef >
294                 var positiveFunc = <instance of Function>
295         Interpreter-interpretPrintCmdLine
296                 arg this = <instance of Interpreter>
297                 var res = nil
298                 var func = <instance of Function>
299         Process-interpretPrintCmdLine
300                 arg this = <instance of Main>
303 This tells you that the function came from interpreting a closed FunctionDef (automatically created when evaluating a block of code).
305 In a method definition, it's recommended to use code::this.dumpBackTrace::; in a free-standing function, there is no "this" so you should pick some arbitrary object.
307 subsection:: Tracing streams
309 To see the results of a pattern, use the .trace method. Each output value from the pattern gets posted to the main output.
310 code::
311 s.boot;
312 SynthDescLib.global.read;
314 p = Pbind(\degree, Pwalk((0..14), Pstutter(Pwhite(1, 4, inf), Prand(#[-2, -1, 1, 2], inf)), Pseq(#[-1, 1], inf), 0), \delta, 0.25, \sustain, 0.2, \instrument, \default).trace.play;
316 p.stop;
319 subsection:: Debugging infinite loops or recursion
320 code::
321 while(true);
323 This is a bad idea. It will lock up SuperCollider and you will have to force quit. Sometimes this happens in your code and the reason isn't obvious. Debugging these situations is very painful because you might have to force quit, relaunch SuperCollider, and reload your code just to try again.
324 code::
325 f = { |func| func.value(func) };
326 f.value(f);
328 Infinite recursion, on the other hand, is more likely to cause SuperCollider to quit unexpectedly when the execution stack runs out of space.
330 In Mac OS X, inserting "post" or "debug" calls will not help with infinite loops or recursion, because posted output is held in a buffer until execution is complete. If execution never completes, you never see the output.
332 One useful approach is to insert statements that will cause execution to halt. The easiest is .halt, but it provides you with no information about where or how it stopped, or how it got there. If you want a more descriptive message, make up an error and throw it:
333 code::
334 Error("myFunction-halt").throw;
336 When debugging code that crashes, place a line like this somewhere in the code. If you get the error output, you know that the infinite loop is happening after the error--so move the error.throw later and try again.
337 If it crashes, you know the infinite loop is earlier. Eventually, after a lot of heartache, you can zero in on the location.
339 Here is a rogues' gallery of infinite loop gotchas--things that don't look like infinite loops, but they will kill your code quicker than you can wish you hadn't just pushed the enter key:
340 code::
341 i = 0;
342 while (i < 10) { i.postln; i = i+1 };   // crash
344 While loop syntax is different in SuperCollider from C. The above loop means to check whether i < 10 once, at the beginning of the loop, then loop if the value is true. Since the loop condition is evaluated only once, it never changes, so the loop never stops. The loop condition should be written inside a function, to wit:
345 code::
346 i = 0;
347 while { i < 10 } { i.postln; i = i+1 };
349 Routines and empty arrays:
350 code::
351 a = Array.new;
352 r = Routine({
353         loop {
354                 a.do({ |item| item.yield });
355         }
357 r.next; // crash
359 This looks pretty innocent: iterate repeatedly over an array and yield each item successively. But, if the array is empty, the do loop never executes and yield never gets called. So, the outer loop{} runs forever, doing nothing.
361 Recursion is often used to walk through a tree structure. Tree structures are usually finite--no matter which branch you go down, eventually you will reach the end. If you have a data structure that is self-referential, you can easily get infinite recursion:
362 code::
363 a = (1..10);
364 a.put(5, a);    // now one of the items of a is a itself
365 a.postcs;               // crash--postcs has to walk through the entire collection, which loops on itself
367 Self-referential data structures are sometimes an indication of poor design. If this is the case, avoid them.
368 code::
369 a = 0;
370 SystemClock.sched(2, { a.postln });     // crashes when scheduler fires the function
372 When a scheduled function executes, if it returns a number, the function will be rescheduled for now + the number. If the number is 0, it is effectively the same as an infinite loop.
374 To fix it, make sure the function returns a non-number.
375 code::
376 a = 0;
377 SystemClock.sched(2, { a.postln; nil });
380 subsection:: Removing debugging statements
382 Use formatting to help your eye locate debugging statements when it's time to remove them. SuperCollider code is usually indented. If you write your debugging statements fully left-justified, they're much easier to see.
383 code::
384 a = Array.new;
385 r = Routine({
386         loop {
387                 "debugging".postln;     // looks like regular code, doesn't stand out
388                 a.do({ |item| item.yield });
389         }
391 r.next; // crash
393 // vs:
395 a = Array.new;
396 r = Routine({
397         loop {
398 "debugging".postln;     // this obviously sticks out
399                 a.do({ |item| item.yield });
400         }
402 r.next; // crash