835 lines
14 KiB
Racket
835 lines
14 KiB
Racket
#lang scribble/manual
|
|
@(require (for-label racket))
|
|
|
|
@title{Server Plugin API}
|
|
Reference for writing unit generators@section{categories}
|
|
Internals
|
|
@section{related}
|
|
Guides/WritingUGens
|
|
|
|
@section{section}
|
|
Input rates
|
|
|
|
These four constants identify the calculation rates of inputs in SuperCollider.
|
|
|
|
@section{definitionlist}
|
|
|
|
##
|
|
@racketblock[calc_ScalarRate::
|
|
|| Initial rate. Conventionally known in the language as ".ir".
|
|
|
|
## ]
|
|
|
|
@racketblock[calc_BufRate::
|
|
|| Control rate. Conventionally known in the language as ".kr".
|
|
|
|
## ]
|
|
|
|
@racketblock[calc_FullRate::
|
|
|| Audio rate. Conventionally known in the language as ".ar".
|
|
|
|
## ]
|
|
|
|
@racketblock[calc_DemandRate::
|
|
|| Demand rate.
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
UGen basics
|
|
|
|
These helper macros assume that there is a ugen object called
|
|
@racketblock[unit:: in the local scope.
|
|
|
|
]
|
|
@section{definitionlist}
|
|
|
|
##
|
|
@racketblock[IN(index)::
|
|
|| A single block of audio-rate input as a float* at the given index. Index 0 is the first input to the ugen, index 1 the second input, and so forth.
|
|
|
|
## ]
|
|
|
|
@racketblock[IN0(index)::
|
|
|| A single sample of control-rate input as a float, at the given index.
|
|
|
|
## ]
|
|
|
|
@racketblock[OUT(index)::
|
|
|| A single block of audio-rate output as a float* at the given index.
|
|
|
|
## ]
|
|
|
|
@racketblock[OUT0(index)::
|
|
|| A single sample of control-rate input as a float, at the given index.
|
|
|
|
## ]
|
|
|
|
@racketblock[INRATE(index)::
|
|
|| Get the rate of a given input index. This will be one of the four rates.
|
|
|
|
## ]
|
|
|
|
@racketblock[INBUFLENGTH(index)::
|
|
|| Get the block size of a given input index.
|
|
|
|
## ]
|
|
|
|
@racketblock[SAMPLERATE::
|
|
|| Sample rate of the server in Hertz.
|
|
|
|
## ]
|
|
|
|
@racketblock[SAMPLEDUR::
|
|
|| Sample period of the server in seconds.
|
|
|
|
## ]
|
|
|
|
@racketblock[BUFLENGTH::
|
|
|| Length in samples of an audio buffer (that is, the number of samples in a control period).
|
|
|
|
## ]
|
|
|
|
@racketblock[BUFRATE::
|
|
|| Control rate of the server in Hertz.
|
|
|
|
## ]
|
|
|
|
@racketblock[BUFDUR::
|
|
|| Control period of the server in seconds.
|
|
|
|
## ]
|
|
|
|
@racketblock[FULLRATE::
|
|
||
|
|
|
|
## ]
|
|
|
|
@racketblock[FULLBUFLENGTH::
|
|
||
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
Buffers
|
|
|
|
@section{definitionlist}
|
|
|
|
##
|
|
@racketblock[GET_BUF::
|
|
|| The recommended way to retrieve a buffer. Take the first input of this UGen and use it as a buffer number. This dumps
|
|
a number of variables into the local scope:
|
|
|
|
]
|
|
@section{list}
|
|
|
|
##
|
|
@racketblock[buf:: - a pointer to the ]
|
|
|
|
@racketblock[SndBuf:: instance
|
|
## ]
|
|
|
|
@racketblock[bufData:: - the raw float data from the buffer
|
|
## ]
|
|
|
|
@racketblock[bufChannels:: - the number of channels in the buffer
|
|
## ]
|
|
|
|
@racketblock[bufSamples:: - the number of samples in the buffer
|
|
## ]
|
|
|
|
@racketblock[bufFrames:: - the number of frames in the buffer
|
|
::
|
|
|
|
The buffer is locked using the ]
|
|
|
|
@racketblock[LOCK_SNDBUF:: macro. Buffer lock operations are specific to supernova, and don't
|
|
do anything in vanilla scsynth.
|
|
|
|
## ]
|
|
|
|
@racketblock[GET_BUF_SHARED::
|
|
|| Like ]
|
|
|
|
@racketblock[GET_BUF::, but the buffer is locked using ]
|
|
|
|
@racketblock[LOCK_SNDBUF_SHARED::.
|
|
|
|
## ]
|
|
|
|
@racketblock[SIMPLE_GET_BUF::
|
|
|| Like ]
|
|
|
|
@racketblock[GET_BUF::, but only creates the ]
|
|
|
|
@racketblock[buf:: variable and does not lock the buffer.
|
|
|
|
## ]
|
|
|
|
@racketblock[SIMPLE_GET_BUF_EXCLUSIVE::
|
|
|| Like ]
|
|
|
|
@racketblock[SIMPLE_GET_BUF::, but locks the buffer with ]
|
|
|
|
@racketblock[LOCK_SNDBUF::.
|
|
|
|
## ]
|
|
|
|
@racketblock[SIMPLE_GET_BUF_SHARED::
|
|
|| Like ]
|
|
|
|
@racketblock[SIMPLE_GET_BUF::, but locks the buffer with ]
|
|
|
|
@racketblock[LOCK_SNDBUF_SHARED::.
|
|
::
|
|
|
|
The following macros are for use in supernova. They still exist in scsynth, but will have no effect.
|
|
|
|
]
|
|
|
|
@racketblock[
|
|
ACQUIRE_BUS_AUDIO(index)
|
|
ACQUIRE_BUS_AUDIO_SHARED(index)
|
|
RELEASE_BUS_AUDIO(index)
|
|
RELEASE_BUS_AUDIO_SHARED(index)
|
|
LOCK_SNDBUF(buf)
|
|
LOCK_SNDBUF_SHARED(buf)
|
|
LOCK_SNDBUF2(buf1, buf2)
|
|
LOCK_SNDBUF2_SHARED(buf1, buf2)
|
|
LOCK_SNDBUF2_EXCLUSIVE_SHARED(buf1, buf2)
|
|
LOCK_SNDBUF2_SHARED_EXCLUSIVE(buf1, buf2)
|
|
ACQUIRE_SNDBUF(buf)
|
|
ACQUIRE_SNDBUF_SHARED(buf)
|
|
RELEASE_SNDBUF(buf)
|
|
RELEASE_SNDBUF_SHARED(buf)
|
|
ACQUIRE_BUS_CONTROL(index)
|
|
RELEASE_BUS_CONTROL(index)
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
RGen
|
|
|
|
RGen is a pseudorandom number generator API. Most ugen developers are not interested in seeding their own RGens and
|
|
would prefer to draw from a global RGen instance supplied by SuperCollider. This can be retrieved with the code:
|
|
|
|
|
|
@racketblock[
|
|
RGen& rgen = *unit->mParent->mRGen;
|
|
::
|
|
|
|
]
|
|
@section{definitionlist}
|
|
|
|
##
|
|
@racketblock[uint32 RGen\::trand()::
|
|
|| Return a uniformly distributed random 32-bit integer.
|
|
|
|
## ]
|
|
|
|
@racketblock[double RGen\::drand()::
|
|
|| Return a uniformly distributed random double in [0,1).
|
|
|
|
## ]
|
|
|
|
@racketblock[float RGen\::frand()::
|
|
|| Random float in [0,1).
|
|
|
|
## ]
|
|
|
|
@racketblock[float RGen\::frand0()::
|
|
|| Random float in [1,2).
|
|
|
|
## ]
|
|
|
|
@racketblock[float RGen\::frand2()::
|
|
|| Random float in [-1,1).
|
|
|
|
## ]
|
|
|
|
@racketblock[float RGen\::frand8()::
|
|
|| Random float in [-0.125,0.125).
|
|
|
|
## ]
|
|
|
|
@racketblock[float RGen\::fcoin()::
|
|
|| Either -1 or +1.
|
|
|
|
## ]
|
|
|
|
@racketblock[float RGen\::flinrand()::
|
|
|| Linearly distributed random float in [0,1), with a bias towards the 0 end.
|
|
|
|
## ]
|
|
|
|
@racketblock[float RGen\::fbilinrand()::
|
|
|| Bilinearly distributed random float in (-1,1), with a bias towards 0.
|
|
|
|
## ]
|
|
|
|
@racketblock[float RGen\::fsum3rand()::
|
|
|| A crude but fast approximation to a Gaussian distribution. Results are always in the range (-1,1). The variance is
|
|
1/6 and the standard deviation is 0.41. ]
|
|
@section{footnote}
|
|
The formula is
|
|
@racketblock[(rand() + rand() + rand() - 1.5) * 2/3::,
|
|
technically a shifted and stretched order-3 Irwin-Hall distribution. ::
|
|
|
|
## ]
|
|
|
|
@racketblock[int32 RGen\::irand(int32 scale)::
|
|
|| Random int in [0,scale).
|
|
|
|
## ]
|
|
|
|
@racketblock[int32 RGen\::irand2(int32 scale)::
|
|
|| Random int in [-scale,+scale].
|
|
|
|
## ]
|
|
|
|
@racketblock[int32 RGen\::ilinrand(int32 scale)::
|
|
|| Linearly distributed random int in [0,scale), with a bias towards the 0 end.
|
|
|
|
## ]
|
|
|
|
@racketblock[int32 RGen\::ibilinrand(int32 scale)::
|
|
|| Bilinearly distributed random int in (-scale,scale), with a bias towards the 0.
|
|
|
|
## ]
|
|
|
|
@racketblock[double RGen\::linrand()::
|
|
|| Linearly distributed random double in [0,1), with a bias towards the 0 end.
|
|
|
|
## ]
|
|
|
|
@racketblock[double RGen\::bilinrand()::
|
|
|| Bilinearly distributed random double in (-1,1), with a bias towards 0.
|
|
|
|
## ]
|
|
|
|
@racketblock[double RGen\::exprandrng(double lo, double hi)::
|
|
|| Exponentially distributed random double in [lo,hi).
|
|
|
|
## ]
|
|
|
|
@racketblock[double RGen\::exprand(double scale)::
|
|
||
|
|
|
|
## ]
|
|
|
|
@racketblock[double RGen\::biexprand(double scale)::
|
|
||
|
|
|
|
## ]
|
|
|
|
@racketblock[double RGen\::exprand(double scale)::
|
|
||
|
|
|
|
## ]
|
|
|
|
@racketblock[double RGen\::sum3rand(double scale)::
|
|
|| Double version of ]
|
|
|
|
@racketblock[RGen\::fsum3rand::.
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
Unary operators
|
|
|
|
@section{definitionlist}
|
|
|
|
##
|
|
@racketblock[bool sc_isnan(float/double x)::
|
|
|| Checks whether ]
|
|
|
|
@racketblock[x:: is NaN. This is a legacy function, use ]
|
|
|
|
@racketblock[std\::isnan:: instead.
|
|
|
|
## ]
|
|
|
|
@racketblock[bool sc_isfinite(float/double x)::
|
|
|| Checks whether ]
|
|
|
|
@racketblock[x:: is finite. This is a legacy function, use ]
|
|
|
|
@racketblock[std\::isfinite:: instead.
|
|
|
|
## ]
|
|
|
|
@racketblock[int32 sc_grayCode(int32 x)::
|
|
|| Convert binary to Gray code.
|
|
::
|
|
|
|
The following unary functions are available for both float32 and float64, and are the same as in sclang (minus the "sc_"
|
|
prefixes):
|
|
|
|
]
|
|
@section{list}
|
|
|
|
##
|
|
@racketblock[sc_midicps::
|
|
## ]
|
|
|
|
@racketblock[sc_cpsmidi::
|
|
## ]
|
|
|
|
@racketblock[sc_midiratio::
|
|
## ]
|
|
|
|
@racketblock[sc_ratiomidi::
|
|
## ]
|
|
|
|
@racketblock[sc_octcps::
|
|
## ]
|
|
|
|
@racketblock[sc_cpsoct::
|
|
## ]
|
|
|
|
@racketblock[sc_ampdb::
|
|
## ]
|
|
|
|
@racketblock[sc_dbamp::
|
|
## ]
|
|
|
|
@racketblock[sc_cubed::
|
|
## ]
|
|
|
|
@racketblock[sc_sqrt::
|
|
## ]
|
|
|
|
@racketblock[sc_hanwindow::
|
|
## ]
|
|
|
|
@racketblock[sc_welwindow::
|
|
## ]
|
|
|
|
@racketblock[sc_triwindow::
|
|
## ]
|
|
|
|
@racketblock[sc_rectwindow::
|
|
## ]
|
|
|
|
@racketblock[sc_scurve::
|
|
## ]
|
|
|
|
@racketblock[sc_ramp::
|
|
## ]
|
|
|
|
@racketblock[sc_sign::
|
|
## ]
|
|
|
|
@racketblock[sc_distort::
|
|
## ]
|
|
|
|
@racketblock[sc_softclip::
|
|
## ]
|
|
|
|
@racketblock[sc_ceil::
|
|
## ]
|
|
|
|
@racketblock[sc_floor::
|
|
## ]
|
|
|
|
@racketblock[sc_reciprocal::
|
|
## ]
|
|
|
|
@racketblock[sc_frac::
|
|
## ]
|
|
|
|
@racketblock[sc_log2:: (legacy -- use ]
|
|
|
|
@racketblock[std\::log2(std\::abs(x))::)
|
|
## ]
|
|
|
|
@racketblock[sc_log10:: (legacy -- use ]
|
|
|
|
@racketblock[std\::log10(std\::abs(x))::)
|
|
## ]
|
|
|
|
@racketblock[sc_trunc:: (legacy -- use ]
|
|
|
|
@racketblock[std\::trunc::)
|
|
::
|
|
|
|
The following unary functions are available for both float32 and float64, but have no sclang equivalent:
|
|
|
|
]
|
|
@section{definitionlist}
|
|
|
|
##
|
|
@racketblock[zapgremlins(x)::
|
|
|| Replaces NaNs, infinities, very large and very small numbers (including denormals) with zero. This is useful in ugen
|
|
feedback to safeguard from pathological behavior. (Note lack of sc_ prefix.)
|
|
|
|
## ]
|
|
|
|
@racketblock[sc_bitriwindow(x)::
|
|
|| Alternative to ]
|
|
|
|
@racketblock[sc_triwindow:: using absolute value.
|
|
|
|
## ]
|
|
|
|
@racketblock[sc_scurve0(x)::
|
|
|| Same as ]
|
|
|
|
@racketblock[sc_scurve::, but assumes that ]
|
|
|
|
@racketblock[x:: is in the interval [0, 1].
|
|
|
|
## ]
|
|
|
|
@racketblock[sc_distortneg(x)::
|
|
|| A one-sided distortion function. Same as ]
|
|
|
|
@racketblock[distort:: for ]
|
|
|
|
@racketblock[x > 0::, and the identity function for ]
|
|
|
|
@racketblock[x <= 0::.
|
|
|
|
## ]
|
|
|
|
@racketblock[taylorsin(x)::
|
|
|| Taylor series approximation of ]
|
|
|
|
@racketblock[sin(x):: out to ]
|
|
|
|
@racketblock[x**9 / 9!::. (Note lack of sc_ prefix.)
|
|
|
|
## ]
|
|
|
|
@racketblock[sc_lg3interp(x1, a, b, c, d)::
|
|
|| Cubic Lagrange interpolator.
|
|
|
|
## ]
|
|
|
|
@racketblock[sc_CalcFeedback(delaytime, decaytime)::
|
|
|| Determines the feedback coefficient for a feedback comb filter with the given delay and decay times.
|
|
|
|
## ]
|
|
|
|
@racketblock[sc_wrap1(x)::
|
|
|| Wrap ]
|
|
|
|
@racketblock[x:: around ±1, wrapping only once.
|
|
|
|
## ]
|
|
|
|
@racketblock[sc_fold1(x)::
|
|
|| Fold ]
|
|
|
|
@racketblock[x:: around ±1, folding only once.
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
Binary operators
|
|
|
|
@section{definitionlist}
|
|
|
|
##
|
|
@racketblock[sc_wrap(in, lo, hi [, range])::
|
|
||
|
|
|
|
## ]
|
|
|
|
@racketblock[sc_fold(in, lo, hi [, range [, range2]])::
|
|
||
|
|
|
|
## ]
|
|
|
|
@racketblock[sc_pow(a, b)::
|
|
|| Compute ]
|
|
|
|
@racketblock[pow(a, b)::, retaining the sign of ]
|
|
|
|
@racketblock[a::.
|
|
|
|
## ]
|
|
|
|
@racketblock[sc_powi(x, unsigned int n)::
|
|
|| Compute ]
|
|
|
|
@racketblock[x^n::, not necessarily retaining the sign of ]
|
|
|
|
@racketblock[x::.
|
|
|
|
## ]
|
|
|
|
@racketblock[sc_hypotx(x, y)::
|
|
|| Compute ]
|
|
|
|
@racketblock[abs(x) + abs(y) - (min(abs(x), abs(y)) * (sqrt(2) - 1))::, the minimum distance one will have to travel
|
|
from the origin to (x,y) using only orthogonal and diagonal movements.
|
|
::
|
|
|
|
The following functions are the same as in sclang (minus the "sc_" prefixes):
|
|
|
|
]
|
|
@section{list}
|
|
|
|
##
|
|
@racketblock[sc_mod(in, hi):: (floats, doubles, ints)
|
|
## ]
|
|
|
|
@racketblock[sc_round(x, quant):: (floats, doubles, ints)
|
|
## ]
|
|
|
|
@racketblock[sc_roundUp(x, quant):: (floats, doubles, ints)
|
|
## ]
|
|
|
|
@racketblock[sc_trunc(x, quant):: (floats, doubles, ints)
|
|
## ]
|
|
|
|
@racketblock[sc_gcd(a, b):: (ints, longs, floats)
|
|
## ]
|
|
|
|
@racketblock[sc_lcm(a, b):: (ints, longs, floats)
|
|
## ]
|
|
|
|
@racketblock[sc_bitAnd(a, b):: (ints)
|
|
## ]
|
|
|
|
@racketblock[sc_bitOr(a, b):: (ints)
|
|
## ]
|
|
|
|
@racketblock[sc_leftShift(a, b):: (ints)
|
|
## ]
|
|
|
|
@racketblock[sc_rightShift(a, b):: (ints)
|
|
## ]
|
|
|
|
@racketblock[sc_unsignedRightShift(a, b):: (ints)
|
|
## ]
|
|
|
|
@racketblock[sc_thresh(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_clip2(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_wrap2(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_fold2(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_excess(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_scaleneg(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_amclip(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_ring1(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_ring2(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_ring3(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_ring4(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_difsqr(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_sumsqr(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_sqrsum(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_sqrdif(a, b)::
|
|
## ]
|
|
|
|
@racketblock[sc_atan2(a, b):: (legacy -- use ]
|
|
|
|
@racketblock[std\::atan2::)
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
Constants
|
|
|
|
The following constants are doubles:
|
|
|
|
@section{list}
|
|
|
|
##
|
|
@racketblock[pi::
|
|
## ]
|
|
|
|
@racketblock[pi2:: = pi/2
|
|
## ]
|
|
|
|
@racketblock[pi32:: = 3pi/2
|
|
## ]
|
|
|
|
@racketblock[twopi:: = 2pi
|
|
## ]
|
|
|
|
@racketblock[rtwopi:: (1/2pi)
|
|
## ]
|
|
|
|
@racketblock[log001:: = log(0.001)
|
|
## ]
|
|
|
|
@racketblock[log01:: = log(0.01)
|
|
## ]
|
|
|
|
@racketblock[log1:: = log(0.1)
|
|
## ]
|
|
|
|
@racketblock[rlog2:: = 1/log(2)
|
|
## ]
|
|
|
|
@racketblock[sqrt2:: = sqrt(2)
|
|
## ]
|
|
|
|
@racketblock[rsqrt2:: = 1/sqrt(2)
|
|
## ]
|
|
|
|
@racketblock[truncDouble:: = 3 * 2^51 (used to truncate precision)
|
|
::
|
|
|
|
The following constants are floats:
|
|
|
|
]
|
|
@section{list}
|
|
|
|
##
|
|
@racketblock[pi_f::
|
|
## ]
|
|
|
|
@racketblock[pi2_f::
|
|
## ]
|
|
|
|
@racketblock[pi32_f::
|
|
## ]
|
|
|
|
@racketblock[twopi_f::
|
|
## ]
|
|
|
|
@racketblock[sqrt2_f::
|
|
## ]
|
|
|
|
@racketblock[rsqrt2_f::
|
|
## ]
|
|
|
|
@racketblock[truncFloat:: = 3 * 2^22 (used to truncate precision)
|
|
::
|
|
|
|
]
|
|
@section{section}
|
|
Unroll macros
|
|
|
|
The macros in this section are legacy features. They are seen in many of SuperCollider's built-in ugens, and are
|
|
intended to provide more efficient alternatives to the standard
|
|
@racketblock[for (int i = 0; i < inNumSamples; i++) { out[i]
|
|
= in[i] }:: loop. These efficiency savings are negligible on modern systems and use of these macros is not recommended,
|
|
especially since they make debugging difficult.
|
|
|
|
]
|
|
@section{definitionlist}
|
|
|
|
##
|
|
@racketblock[LOOP(length, stmt)::
|
|
|| Execute code ]
|
|
|
|
@racketblock[stmt::, ]
|
|
|
|
@racketblock[length:: times.
|
|
|
|
## ]
|
|
|
|
@racketblock[LOOP1(length, stmt)::
|
|
|| A faster drop-in alternative to ]
|
|
|
|
@racketblock[LOOP::, which assumes that ]
|
|
|
|
@racketblock[length > 0:: so a branch instruction is saved.
|
|
|
|
## ]
|
|
|
|
@racketblock[LooP(length) stmt::
|
|
|| An alternative to LOOP/LOOP1 that is more debugger-friendly. The body of the loop comes after the call to ]
|
|
|
|
@racketblock[LooP::.
|
|
|
|
## ]
|
|
|
|
@racketblock[ZIN(index)::
|
|
|| Similar to ]
|
|
|
|
@racketblock[IN::, but subtracts 1 from the pointer to correct for off-by-one errors when using ]
|
|
|
|
@racketblock[LOOP:: and ]
|
|
|
|
@racketblock[ZXP::.
|
|
|
|
## ]
|
|
|
|
@racketblock[ZOUT(index)::
|
|
|| Same as ]
|
|
|
|
@racketblock[OUT::, but subtracts 1 from the pointer to correct for off-by-one errors when using ]
|
|
|
|
@racketblock[LOOP:: and ]
|
|
|
|
@racketblock[ZXP::.
|
|
|
|
## ]
|
|
|
|
@racketblock[ZIN0(index)::
|
|
|| Alias for ]
|
|
|
|
@racketblock[IN0::.
|
|
|
|
## ]
|
|
|
|
@racketblock[ZOUT0(index)::
|
|
|| Alias for ]
|
|
|
|
@racketblock[OUT0::.
|
|
|
|
## ]
|
|
|
|
@racketblock[ZXP(z)::
|
|
|| Pre-increment and dereference ]
|
|
|
|
@racketblock[z::.
|
|
|
|
## ]
|
|
|
|
@racketblock[ZX(z)::
|
|
|| Dereference ]
|
|
|
|
@racketblock[z::.
|
|
|
|
## ]
|
|
|
|
@racketblock[PZ(z)::
|
|
|| Pre-increment ]
|
|
|
|
@racketblock[z::.
|
|
|
|
## ]
|
|
|
|
@racketblock[ZP(z)::
|
|
|| Does nothing.
|
|
|
|
## ]
|
|
|
|
@racketblock[ZOFF::
|
|
|| Return 1.
|
|
]
|
|
|
|
|