Introduction
The Player library is provided to allow the development
of a complete multi-tracks MidiShare sequencer. Each Player is
a MidiShare application, has up to 256 tracks, four different
synchronization mode, events chase and loop markers. Sequences
in MidiShare format can be set in the Player. Functions are provided
to read on write MIDIfiles and convert them to the MidiShare sequence
format. This library was first developed to be used in the Symbolic
Composer music composition environment. It has been continually
refined over 3 years in order to provide a stable and general
API. The Player library 2.0 has been completely rewritten, to
make the source code publicly available. This library is currently
used in different applications : Elody
(Grame), PatchWork
and OpenMusic
(IRCAM), Symbolic Composer
(Peter Stone), Java Applets Japer and Pann (Roberto Bresin),
Visual Piano (Smart
Concept) and Prie
(Alfio Fazio)
Source code
The Player library source code is released as a set of C++
classes and C code distributed under the LGPL Licence.
It is organized as separate components which could be reused is
other context. The code uses a lot of Design Patterns from
the catalog defined by Gamma [Gam94] as well as the interface
concept from the Java language.
General overview
- The synchronizer and scheduler provide the musical time for
the system. The synchronizer supports 3 modes of synchronization.
- The tickplayer plays the score using the tick scheduler to
schedule tasks.
- The chaser keeps internally the whole state of program change,
volume, pan or other controller information which are inserted
in the tracks and send these events when needed.
- The score contains events to be played.
- The event sender is in charge of sending events delivered
by the ticks player or the chaser.
- The event receiver handles incoming events, which can be
synchronization events, events to be recorded , special events
(markers..)
- The tracktable contains various state information associated
with each track.
- The loopmanager is in charge of the loop management.
Components
The different components are implemented as patterns of
C++ classes using several patterns described in Gamma [Gam94].
The whole Player is built by combining several components which
are described in the following pages using the OMT (Object
Modeling Technique) notation :
State diagrams
Several components have a notion of state :
- The Player can have one of the following state : kIdle,
kPlaying, kPause, kRecording, kWaiting.
This state will change each time one of the transport function
like Start, Stop, Pause.. is used. There
are two state diagrams depending of the synchronization mode
: Player state diagram1, Player state diagram2.
- The Scheduler (TScheduler class) allows to schedule
tick Tasks which dates are expressed in tick values. Tick
Tasks state evolution is explained in the the following
state diagram.
Classes hierarchy diagrams
Here are several diagrams representing the classes hierarchy
: diagram1, diagram2,
diagram3, and diagram4.
Limitations and improvements
1) Tempo events are not inserted in the score
when the player is recording in clock or external synchronization
mode.
2) Some of the classes can easily be re-used,
although the whole library is probably to "sequencer oriented",
and could be generalized. One possible improvement is to detach
the whole player lib from the "score concept" which
basically suppose that events to be played are contained in a
score data structure. It means that some classes are not general
enough. A more general concept could be a "event producer
" mechanism able to produce events to be played coming either
from a pre-calculated data structure (like the score) or from
a more dynamic generation principle.
References
- [Gam94] Erich Gamma, Richard Helm, Ralph Johnson,
John Vlissides; Design Patterns: Elements of Reusable Object-Oriented
Software, Addison-Wesley, 1994.
- [Str97] Bjarne Stroustrup; The C++ Programming
Language, 3rd Edition, Addison-Wesley Publishing Company, 1997.