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 MKNote
s. The
MusicKit includes subclasses that read MKNote
s
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-MKPerformer
s that fashion
MKNote
s from MIDI input
(MKMidi
), and that read
MKNote
s 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.
MKPerformer
To 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 MKNoteSender
s, auxiliary objects that
are created by the MKPerformer
to act as
MKNote
“spigots.”
MKNoteSender
s are analogous to an
MKInstrument
's
MKNoteReceiver
s.
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
MKNoteSender
s, just as the noteReceiver method retrieves one of an
MKInstrument
's
MKNoteReceiver
s. 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.
MKPerformer
To make a MKPerformer
run, you send it
the activate message. This prepares
the object for a performance but it doesn't actually start performing
MKNote
s 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
MKPerformer
s 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.
MKPerformer
s and
MKConductor
sEvery 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
MKNote
s is controlled by its
MKConductor
's tempo. In general, all the
MKPerformer
s 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 MKPerformer
s.
MKPerformer
SubclassThe design of a MKPerformer
subclass must
address three tasks: acquiring a MKNote
,
sending it into a performance, and scheduling the next
MKNote
.
MKNote
sEach subclass of MKPerformer
defines a
unique system for acquiring MKNote
s. You can
design your own MKPerformer
s that, for example,
read MKNote
s from a specialized database or
create MKNote
s algorithmically. Regardless of
how a MKPerformer
acquires its
MKNote
s, it does so as part of the
implementation of its perform
method.
The perform method can be
designed to acquire any number of MKNote
s with
a single invocation.
MKNote
sTo send a MKNote
into a performance, a
MKPerformer
relies on its
MKNoteSender
objects. A
MKPerformer
creates and adds some number of
MKNoteSender
s to itself, usually as part of its
init method.
MKNoteSender
s 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
MKNoteSender
s to itself, although it's
anticipated that most MKPerformer
s 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 MKNoteSender
s. Each
MKNoteSender
then relays the
MKNote
to the
MKNoteReceiver
s 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
MKNote
s to one or more
MKInstrument
s. 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.
MKNote
sAs described above, every time a
MKPerformer
receives the perform message it acquires a
MKNote
and then sends it to its
MKNoteSender
s. 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
.