A clock for scheduling MIDI messages in a rate-adjustable, pausable timeline.
For a list of all members of this type, see Clock Members .
System.Object
Clock
This type is safe for multithreaded operations.
Clock is used for scheduling MIDI messages. Though you can always send messages synchronously with the various OutputDevice.Send* methods, doing so requires your code to be "ready" at the precise moment each message needs to be sent. In most cases, and especially in interactive programs, it's more convenient to describe messages that will be sent at specified points in the future, and then rely on a scheduler to make it happen. Clock is such a scheduler.
In the simplest case, Clock can be used to schedule a sequence of messages which is known in its entirety ahead of time. For example, this code snippet schedules two notes to play one after the other:
Clock clock(120); // beatsPerMinute=120 OutputDevice outputDevice = ...; clock.Schedule(new NoteOnMessage(outputDevice, Channel.Channel1, Note.E4, 80, 0)); clock.Schedule(new NoteOffMessage(outputDevice, Channel.Channel1, Note.E4, 80, 1)); clock.Schedule(new NoteOnMessage(outputDevice, Channel.Channel1, Note.D4, 80, 1)); clock.Schedule(new NoteOffMessage(outputDevice, Channel.Channel1, Note.D4, 80, 2));
At this point, four messages have been scheduled, but they haven't been sent because the clock has not started. We can start the clock with Start, pause it with Stop, and reset it with Reset. We can change the beats-per-minute at any time, even as the sequence is playing. And the playing happens in a background thread, so your client code can focus on arranging the notes and controlling the clock.
You can even schedule new notes as the clock is playing. Generally you should schedule messages for times in the future; scheduling a message with a time in the past simply causes it to play immediately, which is probably not what you wanted.
In the above example, we wanted to play two notes but had to schedule four messages. This case is so common that we provide a convenience class, NoteOnOffMessage, which encapsulates a Note On message and its corresponding Note Off message in a single unit. We could rewrite the above example as follows:
Clock clock(120); // beatsPerMinute=120 OutputDevice outputDevice = ...; clock.Schedule(new NoteOnOffMessage(outputDevice, Channel.Channel1, Note.E4, 80, 0, 1)); clock.Schedule(new NoteOnOffMessage(outputDevice, Channel.Channel1, Note.D4, 80, 1, 1));
This works because each NoteOnOffMessage, when it is actually sent, does two things: it sends the Note On message to the output device, and also schedules the correponding Note Off message for the appropriate time in the future. This is an example of a self-propagating message: a message which, when triggered, schedules additional events for the future.
You can design your own self-propagating messages by subclassing from Message. For example, you could make a self-propagating MetronomeMessage which keeps a steady beat by always scheduling the next MetronomeMessage when it plays the current beat. However, subclassing can be tedious, and it is usually preferable to use CallbackMessage to call-out to your own code instead.
Namespace: Midi
Assembly: Midi (in Midi.dll)
Clock Members | Midi Namespace