MKUnitGenerator
SubclassEach MKUnitGenerator
subclass is an
object-oriented interface to a DSP macro, called a
unit generator, that's written in
MC56001 assembly language. The Objective-C code
in the subclass is generated automatically from a
DSP macro by the dspwrap
program. To build your own MKUnitGenerator
subclass that you can use in MKSynthPatch
design, you run dspwrap on a
MC56001 assembly language macro that you've
created. In addition, you can modify and wrap the
DSP macros that NeXT provides as source code in the
directory /usr/local/lib/dsp/ugsrc.
The design of DSP assembly language macros is outside the scope
of the present discussion. The following sections show how to use
dspwrap and how to further modify the
MKUnitGenerator
s that it creates.
The dspwrap program is used to
create array processing C functions as well as
MKUnitGenerator
subclasses. To indicate that
you want to create the latter, you call the program with the -ug switch followed by the name of the file
that contains the assembly code macro (you must include the
“.asm” extension when specifying the file). For example,
the invocation
dspwrap -ug unoisehp.asm |
creates a master MKUnitGenerator
class
called UnoisehpUG as well as the appropriate leaf classes. These are
embodied in the following files, which are automatically generated by
dspwrap:
UnoisehpUG.m is the implementation file of the master class.
UnoisehpUG.h is the master class interface file.
UnoisehpUGx.m and UnoisehpUGy.m are leaf class implementations.
UnoisehpUGx.h and UnoisehpUGy.h are the leaf interface files.
unoisehpUGInclude.m is imported by the master class.
The number of leaf classes that are created depends on the number of address-valued memory arguments, described below, in the macro: A different leaf class is created for each combination of x and y DSP memory spaces. The unoisehp macro, which implements a high-pass random number generator, has only one such argument―its output―so two leaf classes are generated, one for either memory space.
Some other files, such as documentation and DSP assembler and linker files, are also created. These can be moved, deleted, or disregarded as you see fit. For the present purposes, only the files listed above are important.
There are two basic reasons to modify a
MKUnitGenerator
class that's generated by
dspwrap:
To set the values of the DSP memory arguments that are passed to the macro
To define the class's response to some common messages
Of the files generated by dspwrap, you should modify only those that define the master class. In other words, continuing with the Unoisehp example, only UnoisehpUG.m and UnoisehpUG.h should be edited. The entire implementation file of the UnoisehpUG master class as generated by dspwrap is shown below:
#import <MusicKit/MusicKit.h> #import "UnoisehpUG.h" @implementation UnoisehpUG:MKUnitGenerator /* DSP memory arguments. */ enum args { aout, seed}; #import "unoisehpUGInclude.m" |
The two enum variables shown above, aout and seed, are DSP memory arguments. A memory argument represents a location on the DSP from which the unit generator that's executing can read information sent to it by the MusicKit. There are two types of memory arguments:
Address-valued arguments administer the location in DSP memory from which, or to which, the executing unit generator reads or writes data.
Datum-valued arguments take a value that's used as part of the unit generator's computation.
In the example, aout variable
is an address-valued argument that represents the
MKUnitGenerator
's output patchpoint. We create
a Unoisehp method named setOutput:
that sets this argument:
-setOutput:outputPatchPoint { return [self setAddressArg:aout to:outputPatchPoint]; } |
The setAddressArg:to: method is
defined by MKUnitGenerator
to set an
address-valued DSP memory argument.
The other enum variable,
seed, is a datum-valued memory
argument. It's set through MKUnitGenerator
's
setDatumArg:to: method, as
demonstrated in our implementation of Unoisehp's setSeed:method:
-setSeed:(int)aSeed { return [self setDatumArg:seed to:aSeed]; } |
During a performance, a MKUnitGenerator
can expect to receive the following messages:
run tells the receiver to begin doing whatever it does.
finish winds down the receiver before coming to a halt.
idle provides instructions for halting the receiver's activity.
Invocations of these methods were shown in the implementations
of the Simplicity and Envy MKSynthPatch
es.
Remember that finish returns the
amount of time the MKUnitGenerator
needs to
complete its mission―the amount of time to wait before
idle should be sent. The default
implementations of these methods can be sufficient. For further
tuning, you should implement, in your master class, the methods
runSelf, finishSelf, and idleSelf―methods that are automatically
invoked when the corresponding performance messages are
received.
You almost always provide an implementation of idleSelf to ensure that your
MKUnitGenerator
is brought to a halt in a
manner befitting its activity. The Unoisehp implementation of this
method sets its output to the DSP's sink, a
location that, by convention, is never read:
-idleSelf { /* Set the output (aout) to sink. */ [self setAddressArgToSink:aout]; return self; } |