Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / SCClassLibrary / Common / Core / Thread.sc
blob1bf03b790ec6bc27489345baac9ca8f254034975
1 // you must not make any change at all to the order or number of
2 // instance variables in these classes!
3 // You should also not muck with the contents of the instance
4 // variables unless you are sure you know what you are doing.
5 // You may add methods.
7 // Thread inherits from Stream for the benefit of its subclass Routine which can
8 // behave like a Stream. Thread itself is not used like a Stream.
10 Thread : Stream {
11         var <state=0, func, stack, method, block, frame, ip=0, sp=0;
12         var numpop=0, receiver, numArgsPushed=0;
13         var <parent, terminalValue;
14         var <primitiveError=0, <primitiveIndex=0, randData=0;
15         var <beats=0.0, <seconds=0.0, <clock, <nextBeat, <>endBeat, <>endValue;
16         var environment;
17         var <>exceptionHandler, >threadPlayer;
18         var <executingPath, <oldExecutingPath;
20         *new { arg func, stackSize = (512);
21                 ^super.new.init(func, stackSize)
22         }
23         init { arg argFunc, argStackSize = 512;
24                 _Thread_Init
25                 ^this.primitiveFailed
26         }
27         copy { ^this } // sorry cannot copy
29         clock_ { arg inClock;
30                 clock = inClock;
31                 beats = clock.secs2beats(seconds);
32         }
33         seconds_ { arg inSeconds; seconds = inSeconds; beats = clock.secs2beats(inSeconds); }
34         beats_ { arg inBeats; beats = inBeats; seconds = clock.beats2secs(inBeats); }
35         isPlaying { ^state == 5 }
37         threadPlayer { ^threadPlayer ?? { this.findThreadPlayer } }
38         findThreadPlayer {
39                 var parent = this.parent;
40                 ^if(parent.notNil and: { parent !== thisProcess.mainThread }) {
41                         parent.threadPlayer
42                 } {
43                         this
44                 }
45         }
47         randSeed_ { arg seed;
48                 // You supply an integer seed.
49                 // This method creates a new state vector and stores it in randData.
50                 // A state vector is an Int32Array of three 32 bit words.
51                 // SuperCollider uses the taus88 random number generator which has a
52                 // period of 2**88, and passes all standard statistical tests.
53                 // Normally Threads inherit the randData state vector from the Thread that created it.
54                 _Thread_RandSeed
55                 ^this.primitiveFailed;
56         }
57         randData_ { arg data;
58                 _Thread_SetRandData
59                 ^this.primitiveFailed;
60         }
61         randData {
62                 _Thread_GetRandData
63         }
64         failedPrimitiveName { _PrimName }
66         handleError { arg error;
67                 (exceptionHandler ? parent).handleError(error)
68         }
70         // these make Thread act like an Object not like Stream.
71         next { ^this }
72         value { ^this }
73         valueArray { ^this }
75         *primitiveError { _PrimitiveError }
76         *primitiveErrorString { _PrimitiveErrorString; }
78         storeOn { arg stream; stream << "nil"; }
79         archiveAsCompileString { ^true }
80         checkCanArchive { "cannot archive Threads".warn }
83 Routine : Thread {
85         *run { arg func, stackSize, clock, quant;
86                 var routine = super.new(func, stackSize);
87                 ^routine.play(clock ? SystemClock, quant);
88         }
90         // resume, next, value, run are synonyms
91         next { arg inval;
92                 _RoutineResume
93                 ^this.primitiveFailed
94         }
95         value { arg inval;
96                 _RoutineResume
97                 ^this.primitiveFailed
98         }
99         resume { arg inval;
100                 _RoutineResume
101                 ^this.primitiveFailed
102         }
103         run { arg inval;
104                 _RoutineResume
105                 ^this.primitiveFailed
106         }
108         valueArray { arg inval;
109                 ^this.value(inval)
110         }
112         reset {
113                 _RoutineReset
114                 ^this.primitiveFailed
115         }
116                 // the _RoutineStop primitive can't stop the currently running Routine
117                 // but a user should be able to use .stop anywhere
118         stop {
119                 if(this === thisThread) { nil.alwaysYield }
120                         { this.prStop };
121         }
122         prStop {
123                 _RoutineStop
124                 ^this.primitiveFailed
125         }
127         p { ^Prout(func) }
129         storeArgs { ^[func] }
130         storeOn { arg stream;
131                 stream << this.class.name;
132                 this.storeParamsOn(stream);
133                 this.storeModifiersOn(stream);
134         }
136         // PRIVATE
137         awake { arg inBeats, inSeconds, inClock;
138                 var temp = inBeats; // prevent optimization
140                 ^this.next(inBeats)
141         }
142         prStart { arg inval;
143                 func.value(inval);
144                 // if the user's function returns then always yield nil
145                 nil.alwaysYield;
146         }