1
Score objects model. Design rationale
2
--------------------------------------
5
Objects model: history and evolution
6
-----------------------------------
8
I didn't have any previous experience about modelling music and so I started by following the MusicXML model. A second reason to follow it was that a liked to implement export/import MusicXML and so, to simplify this objective, my internal representation should allow for easy conversion to/from MusicXML.
12
- Score is a collection of instruments (<parts>). Titles are directly owned by the score:
13
<!ELEMENT score-partwise (%score-header;, part+)>
15
- <part> contains all measures for one instrument
16
<!ELEMENT part (measure+)>
18
- <measure> contains all the information
19
<!ELEMENT measure (%music-data;)>
21
"(note | backup | forward | direction | attributes |
22
harmony | figured-bass | print | sound | barline |
23
grouping | link | bookmark)*">
25
- <notes> have additional elements, such as <notations><lyrics><technical><fermata>etc. Let me refer to all them by <notations>
27
( ( (grace, %full-note;, (tie, tie?)?) |
28
(cue, %full-note;, duration) |
29
(%full-note;, duration, (tie, tie?)?)),
30
instrument?, %editorial-voice;, type?, dot*, accidental?, time-modification?,
31
stem?, notehead?, staff?, beam*, notations*, lyric*)>
33
- <notations> are musical notations, not other elements (directions).
36
(tied | slur | tuplet | glissando | slide |
37
ornaments | technical | articulations | dynamics |
38
fermata | arpeggiate | non-arpeggiate |
39
accidental-mark | other-notation)*)>
41
- <directions> are not note-specific, and therefore might attach to a
42
<part> or the overall score. i.e. texts
43
<!ELEMENT direction (direction-type+, offset?,
44
%editorial-voice;, staff?, sound?)>
45
<!ELEMENT direction-type (rehearsal+ | segno+ | words+ |
46
coda+ | wedge | dynamics+ | dashes | bracket | pedal |
47
metronome | octave-shift | harp-pedals | damp |
48
damp-all | eyeglasses | scordatura | other-direction)>
50
I also took into account that in the Sibelius model all objects are attached to an staff. As this was not in contradiction with the MusicXML model I started assuming that any object will be a StaffObj, even if it does not consume time. <directions> where the only exception but they can be considered as attached to the score, as well as titles: everything fitted perfectly.
52
When I started to implement <notations> I found that as they are attached to <notes> they did not fit in the lmStaffObj model. So I created a new class for <notations>: lmAuxObj
54
Also I created a more abstract class (ScoreObj) with two specializations: lmStaffObj and lmAuxObj. And specialized lmStaffObj: CompositeObj, for objects that can own <notations>, that is lmAuxObjs, (only notes/rests) and SimpleObj, for the remaining objects.
61
A root class lmObject with two specializations:
63
- ContainerObj: main grouping elements: score, instrument, vstaff. As they do not share common operations I will not define (yet) an abstract class for them.
65
- ScoreObj: Anything that can appear in an score
68
lmScore: The top most container. A lmScore is, mainly, a collection of Instruments
69
plus some data (composer, title, ...). It also contains all independent objects.
71
- collection of instruments (m_cInstruments)
72
- list of score titles (m_cTitles)
73
- collection of independent ScoreObjs (m_cGlobalStaffobjs). These are all those
74
objects not directly associated to a musical object (notes, staff, etc.).
75
They are owned by nobody.
77
lmInstrument: A container for the ScoreObjs associated to one instrument:
78
- List of VStaves that this instrument has (m_cStaves)
80
lmVStaff: Container for the ScoreObjs on this VStaff (m_cStaffObjs)
82
ScoreObj is specialized in three:
84
- StaffObj: objects attached to an VStaff (measure). In this group we have the main musical elements, normally with duration (notes/rests) or time positioned (clef, key signature, time signature). They are in a staff/measure, so they are attached to an VStaff. They normally 'consume' time and so measuring phase is done by time position and Draw() is done
85
in two phases controlled just by its timePos.
87
- AuxObj: objects attached not to a staff but to one or more StaffObj. For example, to one StaffObj: a note plus its accidental symbol; caesura marks, texts, and some <notations> (i.e. articulations) attached to notes; repeat signs attached to barlines, etc. To two StaffObj: ties attached to two notes, wedges for dynamics, etc. As the do not consume time, the measuring phase is done by specific methods, controlled by owner objects.
89
- GraphicObj (graphics): elements with no musical meaning for the program. So, from a program point of view they are just 'decoration': text (different from lyrics or other meaningful texts), lines, arrows. boxes, markup and visual emphasis, some <notations> (i.e. articulations), etc. They can be attached both to StaffObj and to AuxObj.
90
For example: to put a coloured box around a caesura mark, with an arrow pointing to it and a text attached to the arrow. This can be achieved be drawing a box, an arrow and the text, positioning them as desired, grouping them to form a compound graphic object and attaching this GraphObj to the caesura AuxObj.
91
No measuring phase needed as they are always parent anchored (relative dx,dy to parent m_paperPos).
93
A GraphObj is not an StaffObj and, so it can not be attached directly to an staff. In order to allow for placing GraphObjs on the staff it is necessary to create an 'empty' StaffObj. This empty StaffObj could have width so it can also be used as a 'spacer'.
95
GraphObj are compound objs, that is, they can be formed by aggregation of simpler GraphObj.
98
Finally, I defined other auxiliary objects non-derived from lmObject:
100
lmBeam: info about the beam for a group of notes
101
lmChord: info about a chord
102
lmArch: info to draw an arch
103
lmContext: info about current accidentals
104
lmBasicText: info for a text (font size, font family, ..)
105
lmStaff: Properties for each staff on a VStaff (num.lines, spacing, ...)
108
Current defined lmStaffObj:
110
- not owning lmAuxObjs
112
lmBarline, lmClef, lmWordsDirection, lmKeySignature, lmSOControl,
113
lmScoreText, lmTimeSignature, lmTupletBracket, lmMetronomeMark
117
lmNoteRest (lmNote, lmRest)
120
Currently (to be reviewed) lmAuxObj (do not consume time ==> owned by the Score)
121
Other symbols, related either to an staff, to the score (paper) or
122
to other ScoreObjs, that do not "take time". Examples of this group objects are
123
texts, slurs, ties, lyrics and note accidentals.
125
As the owner is not the lmVStaff but other object (i.e.: Ties are owned by Notes,
126
scores titles are owned by the lmScore) they are not included in the lmVStaff
127
objects collection. Therefore, certain operations such as renderization are not
128
triggered by the VStaff.
129
To deal with these AuxObjs in a uniform way for common functions such
130
as selecting, dragging, etc., they will be included in a global list,
131
so that all these functions can be easily implemented by just iterating over
134
For some other functions, such as rendering, the uniform approach could not be so
135
feasible as renderization will be launched sometimes by the owner lmStaffObj
137
and other times centrally, by iterating over the list and rendering the objects
138
in it (i.e. lmScore titles). In these cases, it will be necessary to include
139
flags to signal that the operation will be performed by the owner and, so,
146
AuxObjs related to NoteRests. The rendering is controlled by the owner
147
lmNoteRest and the measurement and drawing phases are implemented by
148
two different methods instead
149
of the combined method Draw() used by StaffObjs.
161
Types of elements to consider and implementation criteria
162
----------------------------------------------------------
164
1. Elements with musical meaning directly on an staff and affecting only to that staff: notes, rests, clefs, keys, barlines, etc. ==> modelled by StaffObj
166
2. Elements with musical meaning not directly on an staff but associated to elements on the staff and affecting only to them. For example: attached to notes/rests (ties, slurs, fermata, lyrics, accidentals, articulations, technical markup, etc. ==> modelled by AuxObj
168
3. Elements with musical meaning that can not be associated to elements on the staff, and affecting not only to one staff but to the system. These include tempo (metronome marks), text (dynamics texts) and rehearsal marks. ==> modelled by StaffObj
170
4. Elements with no musical meaning but with meaning for the program. For example system and page breaks. ==> modelled by StaffObj
172
5. Elements with no meaning at all for the program. So, from a program point of view they are just 'decoration': text (different from lyrics or other meaningful texts), lines, arrows. boxes, etc. ==> modelled by GraphObj attached either to AuxObj or to StaffObj
175
The difference between AuxObj and GraphicObj is sometimes fuzzy. For example: Lyrics are text; therefore, should we model them as GraphicObjs or as AuxObjs? Two criteria will help:
177
1. Is it going to be treated by the program just as 'decoration' or is there any possibility to perform some future 'musical' processing? For example, in future a feature to sing tunes could be added and, in this case, lyrics need to be 'understandable' by the program and should be modelled as AuxObj. Otherwise, if the program does not need to know the semantics of the element it is simpler to treat it as a GraphicObj.
179
2. For auto-layout, is it 'user positioned' or its positioning is complex? If it is user positioned it should be treated as a GraphicObj.
183
Attachment of GraphicObj to containers
184
---------------------------------------------
186
Should we allow direct attachment of graphic objs to containers (the score, a page, an staff, etc.)?
188
With GraphicObj no measuring phase needed as they are always parent anchored (relative dx,dy to parent m_paperPos). But, where is the origin (m_paperPos) for containers?
190
Probably it is non-sense to have GraphicObj attached to containers, other that the score. For the score, origin is paper origin of current page, so Draw should be launched by the BoxPage object. For other containers (lmInstrument, lmVStaff) the lmGraphicObj should be attached to an StaffObj or to a measure (in fact the barline StaffObj), and Draw() should be launched by the parent Draw method.
192
The consequence is that only StaffObjs and the score can have other objects attached. This is compatible with MusicXML as all elements are part of a measure (I think it is an heritage of the initial MusicXML structure. The second consequence of this heritage is that the only objects attached to the score are the score titles). In Sibelious also all elements must be in a system.
194
But all this is consequence of the linear storage model imposed by MusicXML. In a score editor it should be feasible to attach objects and properties to any part. Let's analyse how to implement some examples to get knowledge to take a decision.
196
Example 1. The user selects a system on page 2 and add a border frame to it and to change its background colour.
197
The user interacts with the GR (BoxSystem) and any object/property attached to that system could be stored in the first measure of that system. This will comply with MusicXML structure.
199
Example 2. User selects a page and attach a text to it.
200
The user interacts with the GR (BoxPage) and any object/property attached to that system could be stored in the first system of that page. This in turn implies (example 1) to attach the object/property in the first measure of that system.
205
There is no need to attach GraphObj to the Score as we can attach them to the firts measure. This will force to move titles from the score. Does it worth moving them?
208
- Uniform object model: GraphObjs only attached to AuxObj and StaffObj
209
- Could lose flexibility? --> It does not appear to.
212
- Titles will not be identifyied as 'titles' but as 'grafic objects'. Therefore we lose
213
semantics. Problems to export to MusicXML and other formats.
216
So to avoid losing semantics and as it is already implemented, let's leave the titles in the Score.
221
=============================================================================================
222
Summary: Objects, properties and main behaviour/purpose
223
=============================================================================================
229
- Can have options (m_pObjOptions)
234
Any object displayed on the score:
236
- They have type and identification number (m_nType, m_nId)
237
- Could be draggable (m_fIsDraggable)
238
- They have positioning info: origin (m_paperPos), page num (m_nNumPage)
239
- Could be selected, so they have a selection rectangle (m_fSelected, m_selRect)
240
- can be rendered (methods: Draw, GetBitmap) Two phases draw. Invoke DrawObject.
241
- Can have Graphic objects attached (m_pAuxObjs)
246
- Can be font rendered (m_pFont, m_glyphPos)
247
- Can be Shape rendered (m_fShapeRendered m_pShape)
252
Objects on the Staff.
254
- Measuring phase is done by time position
256
- They can have duration (time positioned: m_rTimePos)
257
- They are related to an Staff (m_pVStaff, m_nStaffNum, m_numMeasure)
258
- They can own objects lmAuxObj and lmGraphicObj
259
- Source code methods (SourceLDP, SourceXML)
263
Objetcs attached to StaffObjs.
265
- Measuring phase is done by specific methods, controlled by owner StaffObj
266
- They can own objects lmGraphicObj
267
- No source code methods. Source code generated by owner StaffObj.
271
- No measuring phase. Parent anchored (relative dx,dy to parent m_paperPos).
272
- Recursive composition (aggregation)
280
- play methods (Play, PlayMeasure, Pause, Stop, WaitForTermination)
281
- serving highlight events (ScoreHighlight)
282
- Dump methods (Dump, DumpMidiEvents)
283
- Source code methods (SourceLDP, SourceXML)
285
- Manage score titles
286
- identification (score name, m_nID)
288
InstrumentsList m_cInstruments; //list of instruments that form this score
289
StaffObjsList m_cTitles; //list of score titles
290
StaffObjsList m_cGlobalStaffobjs; //list of other StaffObjs not included in an lmVStaff
295
- VStaff management (m_cStaves)
297
- Source code methods (SourceLDP, SourceXML)
298
- MIDI configuration (m_nMidiInstr, m_nMidiChannel)
299
- Instrument name and indentation (m_nIndentFirst, m_nIndentOther, m_pName, m_pAbbreviation)
301
VStavesList m_cStaves; //wxList of VStaves that this instrument has
308
- Time signature management
309
- Key signature management
310
- notes and rests management
311
- barlines management
312
- control ScoreObjs management (AddNewSystem, ShiftTime)
313
- words directions management
314
- Measures management (GetNumMeasures)
315
- Rendering methods (DrawStaffLines, DrawProlog, NewLine, SetUpFonts, GetStaffLineThick)
316
- renderization helper methods (GetXPosFinalBarline)
317
- Units conversion (TenthsToLogical)
319
- Source code methods (SourceLDP, SourceXML)
321
- notes context management
322
- sound related methods (ComputeMidiEvents)
325
lmColStaffObjs m_cStaffObjs; //collection of StaffObjs
326
StaffList m_cStaves; //list of Staves (lmStaff objects)
331
=============================================================================================
336
Selection (selectable objects)
337
------------------------------
338
ScoreObjs are selectable by definition, as the user should be able to select (and copy,
339
delete, move, ...) any rendered object. But the procedure to select an object will
340
vary. Simple objects, such as notes or clefs, will have a clear bounding rectangle, that
341
normally will not intersect the bound ling rectangle of neighbour objects; selection
342
can be done just by clicking with the mouse on this selection rectangle. Other objects,
343
such an instrument's staff or the whole score, could be difficult to select by this method
344
as either (1) will not have associated a selection rectangle (i.e. an instrument's staff,
345
as it goes across a lot of pages), or (2) will conflict with too many other selection
346
rectangles (i.e. the staff lines or the whole score). Therefore, for these composite
347
objects we will need a different approach for selection.
349
So, we will call "RectSelectable objects" only to those of the first type: the will have a
350
clear bounding selection rectangle and selection can be implemented just by clicking
351
on this rectangle with the mouse. The other ScoreObjs will have a different
352
procedure for selection but not a selection rectangle.
355
-----------------------------------------------------------------------------------------
356
-----------------------------------------------------------------------------------------
357
We could consider five types of positioning methods:
358
1. TimeParallel: All ScoreObjs with the same timepos must be rendered aligned at
359
the same x position. (only Notes and Rests)
360
2. TimeSequencial: All ScoreObjs with the same timepos will be rendered along
361
the x axis in sequence, in the same sequence as they where created (clefs and keys)
362
3. Indirect: Its positioning coordinates are predefined by the position of the
364
4. FixedAbs: pre-defined, by specifying its absolute positioning coordinates (that
365
is, referred to page origin).
366
5. FixedRel: pre-defined, by specifying its positioning coordinates, relative to
370
ScoreObjs that, by necessity, must go in sequence in a staff (such as notes,
371
rests, clefs and keys). When one of these signs appear they add time to the
372
measure duration. Therefore, they have timing information.
374
RelativePositionedObj:
375
Its position is relative to the position of the owner:
376
- owned by page: page origin.
377
- owned by barline: barline position
378
- owned by an lmScoreObj (i.e. note): lmScoreObj position
380
-----------------------------------------------------------------------------------------
381
-----------------------------------------------------------------------------------------
382
Considering positioning and sizing, a lmScoreObj can be of two types:
383
- draggable: the objects can be freely positioned on the score, only constrained
384
by music writing rules (i.e.: note, clef).
385
- sizable: the object size is not fully restricted by staff size or other and so,
386
can be someway resized. The object is rendered with handle marks for
387
resizing (i.e.: slur, tie, text)
389
-----------------------------------------------------------------------------------------
394
============================================================================================
395
Move to architecture:
396
============================================================================================
399
Because formatting algorithms tend to be complex, it's also desirable to keep them
400
well contained and, if possible, completely independent of the document structure.
401
We will define a separate class hierarchy for objects that encapsulate formatting
402
algorithms. The root object is the class "lmFormatter".