MKPerformer ClassA MKPerformer object does two
things:
It generates or otherwise obtains a series of
MKNote objects during a performance.
It acts as a cover for
MKConductor's scheduling mechanism by
sequentially and repeatedly requesting invocations of its own
perform method.
The MKPerformer class itself is abstract;
you create a subclass of MKPerformer to
correspond to a unique sources of MKNotes. The
MusicKit includes subclasses that read MKNotes
from a MKPart
(MKPartPerformer) or a scorefile
(MKScorefilePerformer)―the latter
actually inherits from the MKFilePerformer class, a subclass of
MKPerformer that defines methods for managing
files. The MusicKit also includes
pseudo-MKPerformers that fashion
MKNotes from MIDI input
(MKMidi), and that read
MKNotes from a MKScore
(MKScorePerformer, which creates a
MKPartPerformer for each
MKPart in the MKScore).
Consult
MusicKit Class References for
further descriptions of these classes.
Using a MKPerformer object is quite
simple; creating your own subclass is a bit more complicated and
requires a firm understanding of how a
MKPerformer goes about its business. These two
topics are presented below.
MKPerformerTo use a MKPerformer, you need to do two
things: connect it to an MKInstrument and tell
it to go. Every MKPerformer contains some
number of MKNoteSenders, auxiliary objects that
are created by the MKPerformer to act as
MKNote “spigots.”
MKNoteSenders are analogous to an
MKInstrument's
MKNoteReceivers.
To connect a MKPerformer to an
MKInstrument, you retrieve a
MKNoteSender and
MKNoteReceiver from either, respectively, and
connect these objects through the connect: method, as defined by both
MKNoteSender and
MKNoteReceiver. For example, to connect a
MKPartPerformer to a
MKSynthInstrument, you would do the
following:
/* aPartPerformer and aSynthIns are assumed to exist. */
[[a |
Since both classes define the connect: method, the following is equivalent:
/* aPartPerformer and aSynthIns are assumed to exist. */ [[aSynthIns noteReceiver] connect: [aPartPerformer noteSender]]; |
The noteSender method returns
one of a MKPerformer's
MKNoteSenders, just as the noteReceiver method retrieves one of an
MKInstrument's
MKNoteReceivers. If you're using a MusicKit
MKPerformer subclass, you should refer to its
description to determine if it creates more than one
MKNoteSender. If it creates only one, then the
noteSender method is sufficient. If
it creates more than one, you can retrieve the entire set as a
NSArray through the noteSenders method and then choose the
MKNoteSender that you want by plucking it from
the NSArray. A
MKScorefilePerformer, for example, creates a
MKNoteSender for each
MKPart that's represented in its
scorefile.
MKPerformerTo make a MKPerformer run, you send it
the activate message. This prepares
the object for a performance but it doesn't actually start performing
MKNotes until you send startPerformance to the
MKConductor class. If you invoke activate while a performance is in progress (in
other words, after you send startPerformance), the
MKPerformer will immediately start running. In
addition, the MKPerformer may require
subclass-specific preparation; for example, you have to set a
MKPartPerformer's MKPart
before you send it the activate
message.
While a MKPerformer is running, you can
pause and resume its activity through the pause, pauseFor:, and resume methods. To completely stop a
MKPerformer you invoke deactivate. In addition, all
MKPerformers are automatically deactivated when
the MKConductor class receives the finishPerformance message. A
MKPerformer can be given a delegate object that
can be designed to respond to the messages performerDidActivate:, performerDidPause:, performerDidResume:, and performerDidDeactivate:. These messages are
sent by the MKPerformer at the obvious
junctures in its performance.
MKPerformers and
MKConductorsEvery MKPerformer object is associated
with a MKConductor. If you don't set a
MKPerformer's
MKConductor explicitly (through setConductor:), it will be associated with the
defaultConductor. The rate at which a
MKPerformer performs its
MKNotes is controlled by its
MKConductor's tempo. In general, all the
MKPerformers you create can be associated with
the same MKConductor. The only case in which a
MKPerformer demands its own
MKConductor is if you want the
MKPerformer to proceed at a different tempo
from its fellow MKPerformers.
MKPerformer
SubclassThe design of a MKPerformer subclass must
address three tasks: acquiring a MKNote,
sending it into a performance, and scheduling the next
MKNote.
MKNotesEach subclass of MKPerformer defines a
unique system for acquiring MKNotes. You can
design your own MKPerformers that, for example,
read MKNotes from a specialized database or
create MKNotes algorithmically. Regardless of
how a MKPerformer acquires its
MKNotes, it does so as part of the
implementation of its perform
method.
The perform method can be
designed to acquire any number of MKNotes with
a single invocation.
MKNotesTo send a MKNote into a performance, a
MKPerformer relies on its
MKNoteSender objects. A
MKPerformer creates and adds some number of
MKNoteSenders to itself, usually as part of its
init method.
MKNoteSenders are created through the usual
sequence of alloc and init messages; they're added to a
MKPerformer through
MKPerformer's addNoteSender: method. A
MKPerformer can add any number of
MKNoteSenders to itself, although it's
anticipated that most MKPerformers will need
only one.
As part of its implementation of theperform method, a MKPerformer passes
the MKNote it has acquired as the argument in a
sendNote: message, which it sends to
its MKNoteSenders. Each
MKNoteSender then relays the
MKNote to the
MKNoteReceivers to which it's connected; each
MKNoteReceiver passes the
MKNote to the
MKInstrument that it (the
MKNoteReceiver) belongs to. Thus, by sending
sendNote: to a
MKNoteSender, a
MKPerformer communicates
MKNotes to one or more
MKInstruments. If more than one
MKNote is acquired in the perform method, each is sent in a separate
sendNote: message.
MKNote:
Methods that are invoked from within the perform method―and this includes the
sendNote:
method―shouldn't be bracketed by lockPerformance and unlockPerformance.
MKNotesAs described above, every time a
MKPerformer receives the perform message it acquires a
MKNote and then sends it to its
MKNoteSenders. The final obligation of the
perform method is to schedule its own
next invocation. This is done by setting the value of the nextPerform instance variable. The value of
nextPerform is measured in beats
according to the tempo of the MKConductor and,
most important, it's taken as a time delay: If you set nextPerform to 3.0, for example, the perform method will be invoked after 3.0
beats.
To get things started, a MKPerformer's
first perform message is
automatically scheduled to be sent just after the
MKPerformer is activated. You can delay this
initial invocation by setting the nextPerform variable from within the
activateSelf method. The default
implementation of activateSelf does
nothing; a subclass can implement it to provide pre-performance
initialization just such as this.
An important implication of this scheduling mechanism is that a
MKPerformer must be able to determine when it
wants to perform its next MKNote at the time
that it acquires and performs its current
MKNote.