MKOrchestra
ClassThe MKOrchestra
class manages DSP
resources used in music synthesis/processing. Each instance of
MKOrchestra
represents a single DSP; in the
basic NeXT configuration, there's only one DSP so you create only one
MKOrchestra
object.
The methods defined by the MKOrchestra
class let you manage a DSP by allocating portions of its memory for
specific synthesis/processing modules and by setting its processing
characteristics.
You can allocate entire MKSynthPatch
es or
individual MKUnitGenerator
and
MKSynthData
objects through
MKOrchestra
methods. Primary among these
are:
allocSynthPatch:
allocates an instance of the given MKSynthPatch
subclass.
allocUnitGenerator:
does the same for a MKUnitGenerator
subclass.
allocSynthData:length: allocates a portion of DSP memory of a given length.
Keep in mind, however, that similar methods defined in other
classes―specifically, the MKSynthPatch
allocation methods defined in
MKSynthInstrument
, and the
MKUnitGenerator
and
MKSynthData
allocation methods defined in
MKSynthPatch
―are built upon and designed
to usurp the allocation methods defined by
MKOrchestra
. You only to need to allocate
synthesis/processing objects directly if you want to assemble
sound-making modules at a low level.
Different applications have different needs. When playing a
sequence or scorefile, it is essential that the timing of the notes be
precise and a bit of latency is tolerable. On the other hand, when
playing the DSP from a MIDI
keyboard, the critical element is to keep response time to a
minimum. In the first case, you should set the
MKOrchestra
to “timed mode” by
sending [orchestra setTimed:YES],
while in the second case, you should set the
MKOrchestra
to “untimed mode” by
sending [orchestra setTimed:NO]. In
addition, when performing from a keyboard, you should call
MKSetRealTimeEnvelopes(YES)
before allocating
your MKSynthPatch
es. This has the effect of
setting the MusicKit
MKSynthPatch
es to use a version of the envelope
handler that is best-suited to the interactive situation. Actually,
MKSetRealTimeEnvelopes(YES)
may be used for
either case; its only drawback is that it does not allow for
arbitrarily long envelopes. In timed mode, the fixed latency is set by
the function MKSetDeltaT()
. For example,
MKSetDeltaT(.1)
sets a fixed latency
of a tenth of a second.
To avoid creating duplicate synthesis/processing modules on the
DSP, each instance of
MKOrchestra
maintains a shared object table.
Objects on the table are MKSynthPatch
es,
MKSynthData
s, and
MKUnitGenerator
s; each is indexed by some other
object that represents the shared object. For example, the
OscgafUG
MKUnitGenerator
(a family of oscillators) lets you specify its waveform-generating
wave table as a MKPartials
object (you can also
set it as a MKSamples
object; for the purposes
of this example we only consider the MKPartials
case). When its wave table is set through the setTable:length: method, the oscillator
allocates a MKSynthData
object from the
MKOrchestra
to represent the
DSP memory that will hold the waveform data
computed from the MKPartials
. It also places
the MKSynthData
on the shared object table
using the MKPartials
as an index by sending the
message
[MKOrchestra installSharedSynthData: theSynthData for: thePartials]; |
If another oscillator's wave table is set as the same
MKPartials
object, the already allocated
MKSynthData
can be returned by sending the
message:
id aSynthData = [MKOrchestra sharedObjectFor: thePartials]; |
The method installSharedObject:for: is provided for
installing MKSynthPatch
es and
MKUnitGenerator
s.
MKOrchestra
's Device StatusBefore you can do anything with an
MKOrchestra
―particularly, before you can
allocate synthesis/processing objects―you must create and open
it. As usual, creation is done through the alloc and init
methods; to open an MKOrchestra
, you send it
the open message. This provides a
channel of communication with the DSP that the
MKOrchestra
represents. The DSP can be opened
by only one application at a time, so you should always check the
value returned by open; the method returns nil if the DSP couldn't be opened.
Once you've allocated the objects that you want, either through
the methods described above or through those defined by
MKSynthInstrument
and
MKSynthPatch
, you can start the
synthesis/processing by sending the run message to the
MKOrchestra
. The stop method halts synthesis/processing and
close breaks communication with the
DSP. These methods change the MKOrchestra
's
status, which is always one of the following MKDeviceStatus
values:
Table 5-1. MKOrchestra status
Status | Meaning |
---|---|
MK_devOpen | The MKOrchestra is open but not running. |
MK_devRunning | The MKOrchestra is open and running. |
MK_devStopped | The MKOrchestra has been running but is now stopped. |
MK_devClosed | The MKOrchestra is closed. |
You can query an MKOrchestra
's status
through the deviceStatus
method.
MKOrchestra
OutputWhen the MKOrchestra
is running it
produces a stream of samples that, by default, are sent to the stereo
digital to analog converter (DAC), which converts
the samples into an audio signal. But there are two other
options:
You can tell the MKOrchestra
to
write the samples to a soundfile by invoking the method setOutputSoundfile: (you must set the soundfile
before sending run to the
MKOrchestra
).
You can tell the MKOrchestra
to
write the samples to the DSP serial port by invoking the method
setSerialSoundOut: (you must set this
before sending run to the
MKOrchestra
). For more information, see the Section called Using the DSP Serial Port below.
Note that you may not combine these output routes―the sound can only go to one destination at a time.
One of the most powerful aspects of the MusicKit is its seamless integration with the NeXT DSP serial port. There are three main uses for the serial port:
Direct to DAT transfers of sound in or out of the MusicKit
For very high quality digital-to-analog conversion.
For high quality analog-to-digital conversion.
The standard NeXT configuration (at the time of this writing) does not include a high-quality sound input. Therefore, in order to do real-time high-quality sound processing, you need to obtain a device that plugs into the DSP serial port. Similarly, you may want to use the DSP serial port for high-quality sound output to an outboard digital-to-analog converter or for direct digital transfer to or from a DAT machine.
A number of such devices are commercially available. Metaresearch sells the DigitalEars, an analog-to-digital converter. Ariel has an analog-to-digital converter called the Digital Microphone. Ariel also sells the ProPort analog-to-digital and digital-to-analog converter, as well as the DatPort DAT interface. Stealth sells the DAI2400 DAT interface. Singular Solutions sells the AD64x, which is a combination analog-to-digital converter and DAT interface.
To set up the MKOrchestra
to do sound
input via the DSP serial port, you send it the message:
[orchestra setSerialSoundIn:YES]; |
To set up the MKOrchestra
to do sound
output via the DSP serial port, you send it the message:
[orchestra setSerialSoundOut:YES]; |
You may simultaneously do serial port input and output. Alternatively, you may combine serial port input with normal NeXT sound output.
You may additionally provide an object that tells the MusicKit about the kind of device you have connected to the DSP serial port. To do this you send the message:
[orchestra setSerialPortDevice:aSerialPortDevice]; |
aSerialPortDevice must be an instance of the MusicKit class DSPSerialPortDevice or one of its subclasses. The class DSPSerialPortDevice itself provides a general-purpose interface to a number of common devices. It supports DigitalEars, the Ariel Digital Microphone, DatPort and ProPort. However, some devices have special requirements and features. The Stealth DAI2400 is supported by the StealthDAI2400 class, which is a subclass of DSPSerialPortDevice; similarly, the Singular Solutions AD64x is supported by the SSAD64x class. You must use these subclasses when using these devices. The devices are not compatible with the generic interface provided by DSPSerialPortDevice. For example, to use the AD64x:
#import <MusicKit/DSPSerialPortDevice.h> [orchestra setSerialPortDevice:[[SSAD64x alloc] init]]; |
For details on implementing your own DSPSerialPortDevice subclass, see the DSPSerialPortDevice class description in the file Classes/DSPSerialPortDevice.rtf.