-- MusicDefs.mesa
-- Author: John Maxwell
-- last modified: May 21, 1982 11:29 am
DIRECTORY
Graphics USING [Context, FontRef, PaintMode, SetPaintMode, SetStipple],
KeyboardFace USING [keyboard],
MouseFace USING [buttons];
MusicDefs: DEFINITIONS IMPORTS Graphics, KeyboardFace, MouseFace =
BEGIN
Error: SIGNAL[s: STRING];
Notify: SIGNAL[s: STRING];
Overflow: SIGNAL[type: Sequence];
Sequence: TYPE = {beam,beamHeap,chord,chordHeap,piece,score,sheet,sync};
-- ****************************************************************************
-- the basic music types
-- ****************************************************************************
score: ScorePTR; -- the root of all of the data
ScorePTR: TYPE = LONG POINTER TO ScoreRec;
ScoreRec: TYPE = RECORD [
name: LONG STRING ← NIL, -- name of the score
beamHeap: BeamHeapPTR ← NIL, -- collection of beams
chordHeap: ChordHeapPTR ← NIL, -- collection of chords
cache: CachePTR ← NIL, -- current key, time signature, etc.
sheet: SheetPTR ← NIL, -- cached information about the sheet (derived from the piece)
selection: SelectionPTR ← NIL, -- information about the currect selection
view: ViewRec ← [],-- global view information
length: CARDINAL ← 0, -- length of score
event: SEQUENCE max: CARDINAL OF EventPTR]; -- collection of events
endOfScore: CARDINAL = LAST[CARDINAL];
-- PiecePTR: TYPE = LONG POINTER TO PieceRec;
-- PieceRec: TYPE = RECORD[
-- length: CARDINAL ← 0, ++ actual length of piece
-- sync: SEQUENCE max: CARDINAL OF EventPTR]; ++ collection of syncs
EventPTR: TYPE = LONG POINTER TO EventRec;
EventRec: TYPE = RECORD[
time: Time ← 0, -- measured in pixels from beginning of piece
variant: SELECT type: EventType FROM
sync => [length: CARDINAL, -- actual length of the sequence
note: SEQUENCE max: CARDINAL OF NotePTR], -- collection of notes
measure => [measure: MeasureType, eol: BOOLEAN], -- eol = force to end of line
timeSignature => [ts: TimeSignature ← [4,4]],
keySignature => [key: INTEGER],
metrenome => [metrenome: INTEGER],
staves => [ -- marks a change in staffing
staves: StavesType ← style,
height: INTEGER ← 0,
offset: INTEGER ← 0,
length: [0..6) ← 0, -- number of staffs in following array
index: [0..6) ← 0, -- index of the staff that we are interested in (for clefs and ottava)
staff: ARRAY [0..6) OF Staff],
ENDCASE];
Time: TYPE = LONG INTEGER;
SyncPTR: TYPE = LONG POINTER TO sync EventRec; -- 'sync' comes from 'synchronize'
StavesPTR: TYPE = LONG POINTER TO staves EventRec;
StavesType: TYPE = {style, clef, octava1, octava2};
EventType: TYPE = MACHINE DEPENDENT {sync (0), measure (1),
timeSignature (7), keySignature (8), metrenome (9), staves (10), spare14 (31)};
MeasureType: TYPE = {measure, repeat1, repeat2, endMeasure, doubleMeasure, m5};
TimeSignature: TYPE = RECORD [top, bottom: [0..32)];
NotePTR: TYPE = LONG POINTER TO NoteRec;
NoteRec: TYPE = MACHINE DEPENDENT RECORD[
sync: SyncPTR ← NIL, -- pointer back to sync
beam: BeamPTR ← NIL, -- pointer back to beam
chord: ChordPTR ← NIL, -- pointer back to chord
pitch: INTEGER ← 44, -- pitch of the note
voice: CARDINAL ← 0, -- the voice that this note belongs to
value: NoteValue ← unknown, -- what is the logical value of this note?
spelled: Accidental ← inKey, -- does this note have an explicit spelling on it?
rest: BOOLEAN ← FALSE, -- is this a rest note?
dotted: BOOLEAN ← FALSE, -- is this note dotted?
doubleDotted: BOOLEAN ← FALSE, -- is this note double dotted?
grace: BOOLEAN ← FALSE, -- is this a grace note?
stemUp: BOOLEAN ← TRUE, -- is the stem up or down?
spare1: BOOLEAN ← FALSE,
embellish: Embellishment ← none, -- does this note have an embellishment on it?
tied: BOOLEAN ← FALSE, -- is this the second note of a tied note?
tie: NotePTR ← NIL, -- pointer to the second note of a tie
tieHeight: INTEGER ← 0, -- the height of said tie
show: BOOLEAN ← FALSE,
shown: Accidental ← inKey, -- the accidental displayed on the screen (cached)
spare: [0..256) ← 0,
staff: [0..16) ← 1, -- the index of the staff that this note is on
delta: [-128..128) ← 0, -- how far to move the note relative to the sync
accDelta: [-128..128) ← 0, -- how far to move the accidental relative to the sync
toc: LONG CARDINAL ← 0, -- physical-note time of occurance (in clock pulses)
duration: CARDINAL ← 0]; -- physical-note duration (in clock pulses)
NoteValue: TYPE= {whole, half, quarter, eighth, sixteenth, thirtysecond, sixtyfourth, unknown};
Accidental: TYPE={doubleSharp, sharp, natural, inKey, flat, doubleFlat};
Embellishment: TYPE = {none, trill, mordent1, mordent2, e1, e2, e3, e4};
PhysicalNote: TYPE = RECORD[
pitch: INTEGER ← 0,
duration: CARDINAL ← 0,
loudness: CARDINAL ← 0,
toc: LONG CARDINAL ← 0]; --toc is the physical time of occurrance
ChordPTR: TYPE = LONG POINTER TO ChordRec;
ChordRec: TYPE = RECORD[
stemUp: BOOLEAN ← TRUE,
delta: INTEGER ← 0, -- offset from center line of sync (cached)
length: CARDINAL ← 0, -- length of note sequence
note: SEQUENCE max: CARDINAL OF NotePTR];
BeamPTR: TYPE = LONG POINTER TO BeamRec;
BeamRec: TYPE = RECORD[
tilt: REAL, -- tilt of beam
beamed: BOOLEAN, -- does the beam show, or do you use brackets instead?
ntuple, against: [0..128), -- for ntupled beams; the ratio is what is important
sync1, sync2: SyncPTR ← NIL, -- first and last sync in beam (cached)
beam: BeamPTR ← NIL, -- beam that this beam belongs to
height: INTEGER, -- height of beam from top of left-most note
invisible: BOOLEAN ← FALSE,
length: [0..1024), -- length of chord sequence
staff: [0..32), -- graphical information
chord: SEQUENCE max: CARDINAL OF VariousPTR];
VariousPTR: TYPE = RECORD[SELECT type: {note,chord,beam} FROM
note => [n: NotePTR], chord=> [c: ChordPTR], beam=>[b: BeamPTR], ENDCASE];
endOfBeam: VariousPTR; --avoids a call to BlockEqualCodeLong
-- ******************************************************************************
-- other types
-- ******************************************************************************
BeamHeapPTR: TYPE = LONG POINTER TO RECORD[
length: CARDINAL ← 0,
beam: SEQUENCE max: CARDINAL OF BeamPTR];
ChordHeapPTR: TYPE = LONG POINTER TO RECORD[
length: CARDINAL ← 0,
chord: SEQUENCE max: CARDINAL OF ChordPTR];
CachePTR: TYPE = LONG POINTER TO CacheRec;
CacheRec: TYPE = RECORD[ -- all of the structural (non-sync) events
length: CARDINAL ← 0,
event: SEQUENCE max: CARDINAL OF EventPTR];
SheetPTR: TYPE = LONG POINTER TO SheetRec;
SheetRec: TYPE = RECORD[
styles: StylePTR ← NIL,
context: Graphics.Context ← NIL,
top: INTEGER ← 0, -- the y position of the top of the score (for scrolling)
begin, endTime: Time ← 0, -- start and end of the part of the score that is currently visible
dirty1, dirty2: Time ← 0, -- the portion of the score that needs to be repainted
length: CARDINAL ← 0, -- length of sheet sequence
section: SEQUENCE max: CARDINAL OF Section]; -- sequence of sections
Section: TYPE = RECORD[
time: Time ← 0, -- actual time of beginning of section. (may be different from staves.time)
x, y: INTEGER ← 0, -- position of the lower left corner of the section
page: INTEGER ← 0, -- the page that this section is on
key: INTEGER ← 0, -- the key for this section
staves: StavesPTR ← NIL];
StylePTR: TYPE = LONG POINTER TO StyleRec;
StyleRec: TYPE = RECORD[
length: CARDINAL ← 0,
style: SEQUENCE max: CARDINAL OF Style];
Style: TYPE = RECORD[
height: INTEGER ← 0,
offset: INTEGER ← 0,
length: [0..6) ← 0, -- number of staffs in following array
staff: ARRAY [0..6) OF Staff];
Staff: TYPE = RECORD[
pitch: INTEGER ← 0, -- pitch of note on bottom line
y: INTEGER ← 0]; -- height relative to bottom line
SelectionPTR: TYPE = LONG POINTER TO SelectionRec;
SelectionRec: TYPE = RECORD[
voice: CARDINAL ← noVoice, -- currently selected voice
maxVoice: CARDINAL ← 0, -- index of the highest numbered voice
lineSelect: BOOLEAN ← FALSE, -- line selection or note selection?
select1, select2: Time ← 0, -- line selected
greySelect1, greySelect2: Time ← 0, -- secondary line selection
length: CARDINAL ← 0, -- length of note selection
note: SEQUENCE max: CARDINAL OF NotePTR]; -- notes selected
noVoice: CARDINAL = 1000;
ViewRec: TYPE = RECORD[
scale: INTEGER ← 1, -- means 'scale' in physical mode, 'justification' in graphical mode.
accidental: BOOLEAN ← TRUE,
notehead: BOOLEAN ← TRUE,
sync: BOOLEAN ← FALSE,
display: DisplayMode ← graphical,
noCarry: BOOLEAN ← FALSE,
hardcopy: BOOLEAN ← FALSE, -- display in hardcopy mode
printing: BOOLEAN ← FALSE, -- we are printing instead of displaying
command: BOOLEAN ← FALSE, -- we have a new command
flash: BOOLEAN ← FALSE]; -- flash the screen for an error
DisplayMode: TYPE = {physical, logical, graphical};
ObjectType: TYPE = {measure, note, leftBeam, rightBeam, tie};
LookCommand: TYPE = {accidental, graphical, hardcopy, justified, logical, noCarry, notehead, overview, physical, sheet, sync, voice};
-- chordLength: CARDINAL = 10;
-- syncLength: CARDINAL = 13;
-- beamLength: CARDINAL = 16;
sheetLength: CARDINAL= 350;
maxScoreLength: CARDINAL = MAX[maxPieceLength,3000]; --6000
maxPieceLength: CARDINAL = 1000;
maxBeamHeapLength: CARDINAL = 1000; --2000
maxChordHeapLength: CARDINAL = 1000; --2000
maxSelectionLength: CARDINAL = 100;
--******************************************************************************
--global variables
--******************************************************************************
-- style: ARRAY [0..20] OF Staves;
--view on score
-- TF: CARDINAL; ++ "Time Factor" = horizontal scale of score on sheet.
-- scale,staffLength,top: INTEGER;
--return info for commands
-- min,max: Time; ++ extent of change
-- command,flash: BOOLEAN; ++ flash = "error"
--graphics
-- context: Graphics.Context;
text,music: Graphics.FontRef;
-- print: BOOLEAN;
--communicating with the synthesizer
dataStructureInFlux: BOOLEAN;
playing,listening: READONLY BOOLEAN;
--data storage
-- ****************************************************************************
-- INLINE Procedures
-- ****************************************************************************
white: CARDINAL = 000000B;
light: CARDINAL;
grey: CARDINAL = 122645B;
black: CARDINAL = 177777B;
-- Measure: PROC[e: EventType] RETURNS[BOOLEAN] = INLINE
-- {RETURN[e=measure OR e=staves]};
EndOfScore: PROCEDURE RETURNS[Time] =INLINE
{IF score.length#0 THEN RETURN[score.event[score.length-1].time+40] ELSE RETURN[10]};
LMod: PROCEDURE[m,n: Time] RETURNS[k: Time] = INLINE
{k ← m - n*(m/n); IF k>n THEN k ← k+n};
Mod: PROCEDURE[m,n: INTEGER] RETURNS[k: INTEGER] = INLINE
{k ← m MOD n; IF k<0 THEN k ← k+n};
SetBrush: PROCEDURE[context: Graphics.Context, tex: CARDINAL, pnt: Graphics.PaintMode] = INLINE
{Graphics.SetStipple[context,tex]; [] ← Graphics.SetPaintMode[context,pnt]};
SetDirty: PROCEDURE[score: ScorePTR, begin,end: Time] = INLINE
{score.sheet.dirty1 ← MIN[score.sheet.dirty1, begin];
score.sheet.dirty2 ← MAX[score.sheet.dirty2, end]};
-- *************************************************************************
-- mouse and keyboard
-- *************************************************************************
AnyBug: PROCEDURE RETURNS[BOOLEAN] =
INLINE {RETURN[RedBug[] OR BlueBug[] OR YellowBug[]]};
RedBug: PROCEDURE RETURNS[BOOLEAN] =
INLINE {RETURN[MouseFace.buttons[Mouse1] = down]};
YellowBug: PROCEDURE RETURNS[BOOLEAN] =
INLINE {RETURN[MouseFace.buttons[Mouse2] = down]};
BlueBug: PROCEDURE RETURNS[BOOLEAN] =
INLINE {RETURN[MouseFace.buttons[Mouse3] = down]};
Shift: PROCEDURE RETURNS[BOOLEAN] = INLINE {RETURN[
KeyboardFace.keyboard[57] = down OR -- A5
KeyboardFace.keyboard[76] = down]}; -- A6
Control: PROCEDURE RETURNS[BOOLEAN] =
INLINE {RETURN[KeyboardFace.keyboard[52] = down]}; -- L11
END.