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
|
// you must not make any change at all to the order or number of
// instance variables in these classes!
// You should also not muck with the contents of the instance
// variables unless you are sure you know what you are doing.
// You may add methods.
// Thread inherits from Stream for the benefit of its subclass Routine which can
// behave like a Stream. Thread itself is not used like a Stream.
Thread : Stream {
var <state=0, func, stack, method, block, frame, ip=0, sp=0;
var numpop=0, receiver, numArgsPushed=0;
var parent, terminalValue;
var <primitiveError=0, <primitiveIndex=0, randData=0;
var <beats=0.0, <seconds=0.0, <clock, <nextBeat, <>endBeat, <>endValue;
var environment;
var <>exceptionHandler;
var <executingPath, <oldExecutingPath;
*new { arg func, stackSize=512;
^super.new.init(func, stackSize)
}
init { arg argFunc, argStackSize=512;
_Thread_Init
^this.primitiveFailed
}
copy { ^this } // sorry cannot copy
clock_ { arg inClock;
clock = inClock;
beats = clock.secs2beats(seconds);
}
seconds_ { arg inSeconds; seconds = inSeconds; beats = clock.secs2beats(inSeconds); }
beats_ { arg inBeats; beats = inBeats; seconds = clock.beats2secs(inBeats); }
isPlaying { ^state == 5 }
randSeed_ { arg seed;
// You supply an integer seed.
// This method creates a new state vector and stores it in randData.
// A state vector is an Int32Array of three 32 bit words.
// SuperCollider uses the taus88 random number generator which has a
// period of 2**88, and passes all standard statistical tests.
// Normally Threads inherit the randData state vector from the Thread that created it.
_Thread_RandSeed
^this.primitiveFailed;
}
randData_ { arg data;
_Thread_SetRandData
^this.primitiveFailed;
}
randData {
_Thread_GetRandData
}
failedPrimitiveName { _PrimName }
handleError { arg error;
(exceptionHandler ? parent).handleError(error)
}
// these make Thread act like an Object not like Stream.
next { ^this }
value { ^this }
valueArray { ^this }
*primitiveError { _PrimitiveError }
*primitiveErrorString { _PrimitiveErrorString; }
storeOn { arg stream; stream << "nil"; }
archiveAsCompileString { ^true }
checkCanArchive { "cannot archive Threads".warn }
}
Routine : Thread {
*run { arg func, stackSize=64, clock, quant=0;
var routine = super.new(func, stackSize);
^routine.play(clock ? SystemClock, quant);
}
// resume, next, value, run are synonyms
next { arg inval;
_RoutineResume
^this.primitiveFailed
}
value { arg inval;
_RoutineResume
^this.primitiveFailed
}
resume { arg inval;
_RoutineResume
^this.primitiveFailed
}
run { arg inval;
_RoutineResume
^this.primitiveFailed
}
valueArray { arg inval;
^this.value(inval)
}
reset {
_RoutineReset
^this.primitiveFailed
}
// the _RoutineStop primitive can't stop the currently running Routine
// but a user should be able to use .stop anywhere
stop {
if(this === thisThread) { nil.alwaysYield }
{ this.prStop };
}
prStop {
_RoutineStop
^this.primitiveFailed
}
p { ^Prout(func) }
storeArgs { ^[func] }
storeOn { arg stream;
stream << this.class.name;
this.storeParamsOn(stream);
this.storeModifiersOn(stream);
}
// PRIVATE
awake { arg inBeats, inSeconds, inClock;
var temp = inBeats; // prevent optimization
^this.next(inBeats)
}
prStart { arg inval;
func.value(inval);
// if the user's function returns then always yield nil
nil.alwaysYield;
}
}
|