The following sections briefly describe the topics that the Kit addresses through its classes and protocols. Within the descriptions, class and protocol names are highlighted as they're introduced for easy identification.
Music is represented in a three-level hierarchy of MKScore, MKPart, and MKNote objects. MKScores and MKParts are analogous to orchestral scores and the instrumental parts that they contain: a MKScore represents a musical composition while each MKPart corresponds to a particular means of realization. MKParts consists of a time-sorted collection of MKNotes, each of which contains data that describes a musical event.
The information in a MKNote object falls into four categories:
A list of attribute-value pairs called parameters that describe the characteristics of a musical event
A noteType that determines the general character of the MKNote
An identifying integer called a noteTag, used to associate different MKNotes with each other
A timeTag, or the onset time of the MKNote
A parameter supplies a value for a particular attribute of a musical sound, its frequency or amplitude, for example. A parameter's value can be simple―an integer, floating point number, or character string―or it can be another object. The MKNote object provides special methods for setting the value of a parameter as an MKEnvelope object or a MKWaveTable object. With the MKEnvelope object you can create a value that varies over time. The MKWaveTable object contains sound or spectrum data that's used in various types of synthesis, such as wavetable synthesis.
The manner in which a parameter is interpreted depends on the object that realizes the MKNote. For example, one object could interpret a heightened brightness parameter by increasing the amplitude of the sound, while another, given the same MKNote, might increase the sound's spectral content. In this way, parameters are similar to Objective-C messages: The precise meaning of either depends on how they are implemented by the object that receives them.
A MKNote's noteType and noteTag are used together to help interpret a MKNote's parameters. There are five noteTypes:
noteDur represents an entire musical note (a note with a duration).
noteOn establishes the beginning of a note.
noteOff establishes the end of a note.
noteUpdate represents the middle of a note.
mute represents a MKNote not directly associated with sound-production.
noteDurs and noteOns both establish the beginning of a musical note. The difference between them is that the noteDur also has information that tells when the note should end. A note created by a noteOn simply keeps sounding until a noteOff comes along to stop it. In either case, a noteUpdate can change the attributes of a musical note while it's sounding. The mute noteType is used to represent any additional information, such as barlines or rehearsal numbers.
A noteTag is an arbitrary integer that's used to identify different MKNotes as part of the same musical note or phrase. For example, a noteOff is paired with a noteOn by matching noteTag values. You can create a legato passage with a series of noteOns, all with the same noteTag, concluded by a single noteOff.
The MusicKit's noteTag system solves many of the problems inherent in MIDI, which uses a combination of key number and channel to identify events that are part of the same musical phrase. For example, the MusicKit can create and manage an unlimited number of simultaneous legato phrases while MIDI can only manage 16 (in MIDI mono mode). Also, with MIDI's tagging system, mixing streams of notes is difficult―notes can easily get clobbered or linger on beyond their appointed end. The MusicKit avoids this problem by reassigning unique noteTag values when streams of MKNotes are mixed together.
A MKNote's timeTag is relevant only when the MKNote is in a MKPart―it specifies the time of the MKNote relative to the start of its MKPart. timeTag values are measured in beats, where the value of a beat can be set by the user. If the MKNote is a noteDur, its duration is also computed in beats.
An entire MKScore can be stored in a scorefile. The scorefile format is designed to represent any information that can be put in a MKNote object, including the MKPart to which the MKNote belongs. Scorefiles are in ASCII format and can easily be created and modified with a text editor. In addition, the MusicKit provides a language called ScoreFile that lets you add simple programming constructs such as variables, assignments, and arithmethic expressions to your scorefile.
During a MusicKit performance, MKNote objects are dispatched, in time order, to objects that realize them in some manner―usually by making a sound on the DSP or on an external MIDI synthesizer. This process involves, primarily, instances of MKPerformer, MKInstrument, and MKConductor:
A MKPerformer acquires MKNotes, either by opening a file, looking in a MKPart or MKScore, or generating them itself, and sends them to one or more MKInstruments. Pseudo-performers such as MKMidi or the application itself may act as MKPerformers, supplying MKNotes in response to asynchronous events.
An MKInstrument receives MKNotes sent to it by one or more MKPerformers and realizes them in some distinct manner.
The MKConductor acts as a scheduler, ensuring that MKNotes are transmitted from MKPerformers to MKInstruments in order and at the right time.
This system is useful for designing a wide variety of applications that process MKNotes sequentially. For example, a MusicKit performance can be configured to perform MIDI or DSP sequencing, graphic animation, MIDI real-time processing (such as echo, channel mapping, or doubling), sequential editing on a file, mixing and filtering of MKNote streams under interactive control, and so on.
Both MKPerformer and MKInstrument are abstract classes. This means that you never create and use instances of these classes directly in an application. Rather, they define common protocol (for sending and receiving MKNotes) that's used by their subclasses. The subclasses build on this protocol to generate or realize MKNotes in some application-specific manner.
The MusicKit provides a number of MKPerformer and MKInstrument subclasses. The principle MKPerformer subclasses are:
MKScorePerformer and MKPartPerformer. These read MKNotes from a designated MKScore and MKPart, respectively. MKScorePerformer is actually a collection of MKPartPerformers, one for each MKPart in the MKScore.
MKScorefilePerformer reads a scorefiles, forming MKNote objects from the contents of the file. It's only advantage over MKScorePerformer is that there is no memory-resident representation of the MKScore is used. Thus, it can instantaneously perform huge MKScores that would require some time to read into a MKScore.
MKMidi (a pseudo-MKPerformer) creates MKNote objects from the byte stream generated by an external MIDI synthesizer attached to a serial port.
The MKInstrument subclasses provided by the MusicKit are:
MKSynthInstrument objects realize MKNotes by synthesizing them on the DSP.
MKMidi (a pseudo-Instrument) turns MKNote objects into MIDI commands and sends the resulting byte stream back out to an external MIDI synthesizer connected to a serial port.
MKScoreRecorder and MKPartRecorder receive MKNotes, copy them, and add them to a MKScore and MKPart, respectively.
MKScorefileWriter writes scorefiles on the fly during a performance. It is analagous to MKScorefilePerformer.
MKNoteFilter is a subclass of MKInstrument that also implements MKPerformer's MKNote-sending protocol, thus it can both receive and send MKNotes. Any number of MKNoteFilter objects can be interposed between a MKPerformer and an MKInstrument. MKNoteFilter is, itself, abstract. The action a MKNoteFilter object takes in response to receiving a MKNote is defined by the subclass. For example, you can create a MKNoteFilter subclass that creates and activates a new MKPerformer for every MKNote it receives.
MKOrchestra handles all allocation and DSP time management. MKSynthInstrument is a voice allocator and manages instances of MKSynthPatch, each of which representes a single sound-producing/processing voice on the DSP. MKSynthPatches are comprised of MKUnitGenerators, basic building blocks of DSP synthesis, as well as MKSynthData, DSP memory objects. The MusicKit provides an extensive set of MKSynthPatch and MKUnitGenerator subclasses, in the MKSynthPatch and MKUnitGenerator frameworks, respectively.