SelectionImpl.mesa
Copyright (C) 1981, 1984 Xerox Corporation. All rights reserved.
Author: John Maxwell
last modified: January 16, 1982 12: 05 PM
Edited by Doug Wyatt, June 14, 1984 1:16:02 pm PDT
DIRECTORY
Beam USING [AddBeam, AddChord, AddNote, Remove, SetStems],
Chord USING [AddNote, RemoveNote, SetDefaultStem, Sort],
Graphics USING [DisplayChar, MoveTo],
Heuristic USING [MakeNTuplets],
MusicDefs,
Note USING [FindChord, GetBackTie],
Piece USING [AddSync, CleanUpSyncs, Delete],
Real USING [FixI],
Selection USING [Clear, Draw, MakeBeam, MakeBeamOfBeams, RemoveNote],
Sheet USING [Height, HiLite, Map, MapNote, NextStaff],
Sync USING [AddNote],
Utility USING [FreeBeam, FreeNote, NewBeam, NewChord, NewSync];
SelectionImpl: CEDAR PROGRAM
IMPORTS Beam, Chord, Graphics, Heuristic, MusicDefs, Note, Piece, Real, Selection, Sheet, Sync, Utility
EXPORTS Selection, MusicDefs
= BEGIN OPEN Graphics, MusicDefs;
lineSelect: PUBLIC BOOL;
select1, greySelect1: PUBLIC Time ← 1;
greySelect2, select2: PUBLIC Time ← 0;
selection: PUBLIC ARRAY [0..maxSelectionLength) OF NotePTR;
selectionLength: PUBLIC CARDINAL ← 0;
min, max: PUBLIC Time ← 1;
command: PUBLIC BOOL ← FALSE;
flash: PUBLIC BOOL ← FALSE;
Includes:
PUBLIC
PROC[n: NotePTR]
RETURNS[
BOOL] = {
IF voice AND n.voice#selectedVoice THEN RETURN[FALSE];
IF lineSelect THEN RETURN[n.sync.time IN [select1..select2)]
ELSE
FOR i:
CARDINAL
IN [0..selectionLength)
DO
IF selection[i]=n THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE]
***************************************************************************
selection manipulation
***************************************************************************
Clear:
PUBLIC
PROC = {
Selection.Draw[];
greySelect1 ← select1 ← 1;
greySelect2 ← select2 ← 0;
selectionLength ← 0;
};
AddNote:
PUBLIC
PROC[n: NotePTR] = {
i: CARDINAL;
x, y: INTEGER;
IF lineSelect THEN Clear[];
IF n=NIL THEN RETURN;
IF voice AND n.voice#selectedVoice THEN RETURN;
IF selectionLength=maxSelectionLength THEN RETURN;
FOR i IN [0..selectionLength) DO IF selection[i]=n THEN RETURN; ENDLOOP;
selection[selectionLength] ← n;
selectionLength ← selectionLength+1;
lineSelect ← FALSE;
[x, y] ← Sheet.MapNote[n];
Graphics.MoveTo[context,[x, y]];
SetBrush[black, invert];
Graphics.DisplayChar[context, 170C];
};
RemoveNote:
PUBLIC
PROC[n: NotePTR] = {
x, y: INTEGER;
IF n=NIL THEN RETURN;
SetBrush[black, invert];
FOR i:
CARDINAL
IN [0..selectionLength)
DO
IF selection[i]#n THEN LOOP;
selection[i] ←
NIL;
FOR j:
CARDINAL
DECREASING
IN [0..selectionLength)
DO
IF selection[j]#NIL THEN EXIT;
selectionLength ← j;
ENDLOOP;
[x, y] ← Sheet.MapNote[n];
Graphics.MoveTo[context,[x, y]];
Graphics.DisplayChar[context, 170C];
RETURN; ENDLOOP;
};
AddLine:
PUBLIC
PROC[time1, time2: Time] = {
IF lineSelect
THEN Sheet.HiLite[black, select1, select2]
ELSE Selection.Clear[];
Sheet.HiLite[black, time1, time2];
select1 ← time1;
select2 ← time2;
lineSelect ← TRUE;
};
AddGreyLine:
PUBLIC
PROC[time1, time2: Time] = {
IF lineSelect
THEN Sheet.HiLite[grey, greySelect1, greySelect2]
ELSE Selection.Clear[];
Sheet.HiLite[grey, time1, time2];
greySelect1 ← time1;
greySelect2 ← time2;
lineSelect ← TRUE;
};
Draw:
PUBLIC
PROC = {
x, y: INTEGER;
IF lineSelect
THEN {
Sheet.HiLite[black, select1, select2];
Sheet.HiLite[grey, greySelect1, greySelect2];
RETURN};
SetBrush[black, invert];
FOR i:
CARDINAL
IN [0..selectionLength)
DO
IF selection[i]=NIL THEN LOOP;
IF voice AND selection[i].voice#selectedVoice THEN LOOP;
[x, y] ← Sheet.MapNote[selection[i]];
Graphics.MoveTo[context,[x, y]];
Graphics.DisplayChar[context, 170C];
ENDLOOP;
};
****************************************************************************
procedures that take the current selection as an implicit parameter
****************************************************************************
SetNoteValue:
PUBLIC
PROC[v: NoteValue, dots:
INTEGER] = {
i, j: CARDINAL;
n: NotePTR;
IF lineSelect
THEN
FOR i
IN [0..scoreLength)
DO
IF score[i]=NIL THEN LOOP;
IF score[i].time < select1 OR score[i].time > select2 THEN LOOP;
FOR j
IN [0..syncLength)
DO
IF (n ← score[i].event[j])=NIL THEN EXIT;
IF voice AND n.voice#selectedVoice THEN LOOP;
n.value← v;
IF dots>1 THEN n.doubleDotted ← TRUE ELSE n.doubleDotted ← FALSE;
IF dots MOD 2=1 THEN n.dotted ← TRUE ELSE n.dotted ← FALSE;
IF v>quarter OR n.beam=NIL OR NOT n.beam.beamed THEN LOOP;
Beam.Remove[n.beam, n, Note.FindChord[n], NIL];
ENDLOOP;
ENDLOOP
ELSE
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice AND n.voice#selectedVoice THEN LOOP;
SetDirty[n.sync.time, n.sync.time];
n.value← v;
IF dots>1 THEN n.doubleDotted ← TRUE ELSE n.doubleDotted ← FALSE;
IF dots MOD 2=1 THEN n.dotted ← TRUE ELSE n.dotted ← FALSE;
IF v>quarter OR n.beam=NIL OR NOT n.beam.beamed THEN LOOP;
Beam.Remove[n.beam, n, Note.FindChord[n], NIL];
ENDLOOP;
IF lineSelect THEN SetDirty[select1, select2];
};
SetRest:
PUBLIC
PROC[rest:
BOOL] = {
i, j: CARDINAL;
n: NotePTR;
IF lineSelect
THEN
FOR i
IN [0..scoreLength)
DO
IF score[i]=NIL THEN LOOP;
IF score[i].time < select1 OR score[i].time > select2 THEN LOOP;
FOR j
IN [0..syncLength)
DO
IF (n ← score[i].event[j])=NIL THEN EXIT;
IF voice AND n.voice#selectedVoice THEN LOOP;
n.rest ← rest;
ENDLOOP;
ENDLOOP
ELSE
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice
AND n.voice#selectedVoice
THEN
LOOP;
SetDirty[n.sync.time, n.sync.time];
n.rest← rest;
ENDLOOP;
IF lineSelect THEN SetDirty[select1, select2];
};
SetStaff:
PUBLIC
PROC[staff:
CARDINAL] = {
n: NotePTR;
Count:
PROC[s:
CARDINAL, t: Time]
RETURNS[j:
CARDINAL] = {
j ← 0; FOR i: CARDINAL IN [0..s) DO j ← Sheet.NextStaff[j, t]; ENDLOOP};
IF staff=0 THEN {flash ← TRUE; RETURN} ELSE staff ← staff-1;
IF lineSelect
THEN
FOR i:
CARDINAL
IN [0..scoreLength)
DO
IF score[i]=NIL THEN LOOP;
IF score[i].time < select1 OR score[i].time > select2 THEN LOOP;
FOR j:
CARDINAL
IN [0..syncLength)
DO
IF (n ← score[i].event[j])=NIL THEN EXIT;
IF voice AND n.voice#selectedVoice THEN LOOP;
n.staff ← Count[staff, n.sync.time];
IF n.beam#NIL THEN Beam.SetStems[n.beam];
ENDLOOP;
ENDLOOP
ELSE
FOR i:
CARDINAL
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice AND n.voice#selectedVoice THEN LOOP;
SetDirty[n.sync.time, n.sync.time];
n.staff ← Count[staff, n.sync.time];
IF n.beam#NIL THEN Beam.SetStems[n.beam];
ENDLOOP;
IF lineSelect THEN SetDirty[select1, select2];
};
SetStem:
PUBLIC
PROC[stemUp:
BOOL] = {
i, j: CARDINAL;
x, y, xb, yb: INTEGER;
d: INTEGER;
n: NotePTR;
c: ChordPTR;
b: BeamPTR;
IF lineSelect
THEN
FOR i
IN [0..scoreLength)
DO
IF score[i]=NIL THEN LOOP;
IF score[i].time < select1 OR score[i].time > select2 THEN LOOP;
FOR j
IN [0..syncLength)
DO
IF (n ← score[i].event[j])=NIL THEN EXIT;
IF voice AND n.voice#selectedVoice THEN LOOP;
n.stemUp ← stemUp;
c ← Note.FindChord[n];
IF c#NIL THEN c.stemUp ← stemUp;
IF (b ← n.beam)=NIL OR NOT n.beam.beamed THEN LOOP;
[x, y] ← Sheet.Map[n.sync.time, n.pitch, n.staff];
[xb, yb] ← Sheet.Map[b.sync1.time,, b.staff];
yb ← yb+b.height;
d ← Real.FixI[yb+b.tilt*(x-xb)-y];
b.height ← b.height-(IF stemUp THEN MIN[0, d-28] ELSE MAX[0, d+28]);
ENDLOOP;
ENDLOOP
ELSE
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice AND n.voice#selectedVoice THEN LOOP;
SetDirty[n.sync.time, n.sync.time];
n.stemUp ← stemUp;
c ← Note.FindChord[n];
IF c#NIL THEN c.stemUp ← stemUp;
IF (b ← n.beam)=NIL OR NOT n.beam.beamed THEN LOOP;
[x, y] ← Sheet.Map[n.sync.time, n.pitch, n.staff];
[xb, yb] ← Sheet.Map[b.sync1.time,, b.staff];
yb ← yb+b.height;
d ← Real.FixI[yb+n.beam.tilt*(x-xb)-y];
b.height ← b.height-(IF stemUp THEN MIN[0, d-28] ELSE MAX[0, d+28]);
ENDLOOP;
IF lineSelect THEN SetDirty[select1, select2];
};
SetGrace:
PUBLIC
PROC[grace:
BOOL] = {
i, j: CARDINAL;
n: NotePTR;
IF lineSelect
THEN
FOR i
IN [0..scoreLength)
DO
IF score[i]=NIL THEN LOOP;
IF score[i].time < select1 OR score[i].time > select2 THEN LOOP;
FOR j
IN [0..syncLength)
DO
IF (n ← score[i].event[j])=NIL THEN EXIT;
IF voice AND n.voice#selectedVoice THEN LOOP;
n.grace ← grace;
ENDLOOP;
ENDLOOP
ELSE
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice
AND n.voice#selectedVoice
THEN
LOOP;
SetDirty[n.sync.time, n.sync.time];
n.grace← grace;
ENDLOOP;
IF lineSelect THEN SetDirty[select1, select2];
};
Transpose:
PUBLIC
PROC[halfsteps:
INTEGER] = {
i, j: CARDINAL;
n: NotePTR;
IF lineSelect
THEN
FOR i
IN [0..scoreLength)
DO
IF score[i]=NIL THEN LOOP;
IF score[i].time < select1 OR score[i].time > select2 THEN LOOP;
FOR j
IN [0..syncLength)
DO
IF (n ← score[i].event[j])=NIL THEN EXIT;
IF voice AND n.voice#selectedVoice THEN LOOP;
n.pitch ← n.pitch+halfsteps;
IF (halfsteps MOD 12)#0 THEN {n.spelled ← inKey; n.show ← FALSE};
ENDLOOP;
ENDLOOP
ELSE
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice AND n.voice#selectedVoice THEN LOOP;
SetDirty[n.sync.time, n.sync.time];
n.pitch ← n.pitch+halfsteps;
IF (halfsteps MOD 12)#0 THEN {n.spelled ← inKey; n.show ← FALSE};
ENDLOOP;
IF lineSelect THEN SetDirty[select1, select2];
};
**************************************************************************
syncs
**************************************************************************
MakeSync:
PUBLIC
PROC = {
sync: SyncPTR ← NIL;
c: ChordPTR;
n: NotePTR;
i, j: CARDINAL;
begin, end: Time;
begin ← EndOfScore[];
end ← -1;
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
begin ← MIN[begin, n.sync.time];
end ← MAX[end, n.sync.time];
ENDLOOP;
IF ABS[end-begin]>20 THEN {flash ← TRUE; RETURN};
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice AND n.voice#selectedVoice THEN LOOP;
SetDirty[n.sync.time, n.sync.time];
IF sync=NIL THEN { sync ← n.sync; LOOP; };
c ← Note.FindChord[n];
FOR j
IN [0..chordLength)
DO
IF c=NIL AND j#0 THEN EXIT;
IF c#NIL THEN n ← c.note[j];
IF n=NIL THEN EXIT;
Sync.AddNote[sync, n];
ENDLOOP;
ENDLOOP;
Piece.CleanUpSyncs[score];
};
ClearSync:
PUBLIC
PROC = {
n: NotePTR;
sync: SyncPTR;
i, j: CARDINAL;
first: BOOL ← TRUE;
IF lineSelect
THEN
FOR i
IN [0..scoreLength)
DO
IF score[i].time<select1 OR score[i].time>select2 THEN LOOP;
FOR j
DECREASING
IN [0..syncLength)
DO
IF score[i].event[j]=NIL THEN EXIT;
sync ← Utility.NewSync[];
sync.time ← score[i].time;
Piece.AddSync[score, sync];
Sync.AddNote[sync, score[i].event[j]];
ENDLOOP;
ENDLOOP;
IF
NOT lineSelect
THEN
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice
AND n.voice#selectedVoice
THEN
LOOP;
SetDirty[n.sync.time, n.sync.time];
sync ← Utility.NewSync[];
sync.time ← n.sync.time;
Piece.AddSync[score, sync];
Sync.AddNote[sync, n];
ENDLOOP;
Piece.CleanUpSyncs[score];
IF lineSelect THEN SetDirty[select1, select2];
};
MakeTie:
PUBLIC
PROC = {
n: NotePTR;
ties: ARRAY [0..10) OF RECORD[n1, n2: NotePTR];
ties ← ALL[[NIL, NIL]];
build up matching pairs
FOR i:
CARDINAL
IN [0..selectionLength)
DO
IF selection[i]=NIL THEN LOOP;
FOR j:
CARDINAL
IN [0..10)
DO
IF ties[j].n1=NIL THEN {ties[j].n1 ← selection[i]; EXIT};
IF ties[j].n1.pitch#selection[i].pitch THEN LOOP;
IF ties[j].n1.sync=selection[i].sync THEN {flash ← TRUE; RETURN};
IF ties[j].n2#NIL THEN {flash ← TRUE; RETURN};
ties[j].n2 ← selection[i];
EXIT; ENDLOOP;
ENDLOOP;
IF ties[0].n1=NIL THEN {flash ← TRUE; RETURN};
if there are only two notes, we ignore pitch constraints
IF ties[0].n2=
NIL
AND ties[1].n2=
NIL
AND ties[2].n1=
NIL
THEN {
ties[0].n2 ← ties[1].n1;
ties[1].n1 ← NIL};
check that there are an even number of pitches
FOR i:
CARDINAL
IN [0..10)
DO
IF ties[i].n1=NIL THEN EXIT;
IF ties[i].n2=NIL THEN {flash ← TRUE; RETURN};
ENDLOOP;
tie the pairs together
FOR i:
CARDINAL
IN [0..10)
DO
IF ties[i].n1=NIL THEN EXIT;
IF ties[i].n1.sync.time>ties[i].n2.sync.time
THEN
{n ← ties[i].n1; ties[i].n1 ← ties[i].n2; ties[i].n2 ← n};
IF ties[i].n1.tied
THEN {
(n ← Note.GetBackTie[ties[i].n1]).tie ← NIL;
SetDirty[n.sync.time, n.sync.time]};
IF (n ← ties[i].n2.tie)#
NIL
THEN {
n.tied ← FALSE;
SetDirty[n.sync.time, n.sync.time]};
ties[i].n2.tie ← ties[i].n1;
ties[i].n1.tied ← TRUE;
ties[i].n2.tieHeight ← -10;
SetDirty[ties[i].n1.sync.time, ties[i].n2.sync.time];
ENDLOOP;
};
ClearTie:
PUBLIC
PROC = {
n: NotePTR;
i, j: CARDINAL;
IF lineSelect
THEN
FOR i
IN [0..scoreLength)
DO
IF score[i].time<select1 THEN LOOP;
IF score[i].time>select2 THEN EXIT;
FOR j
IN [0..syncLength)
DO
IF (n ← score[i].event[j])=NIL THEN EXIT;
IF n.tie=NIL THEN LOOP;
n.tie.tied ← FALSE;
n.tie ← NIL;
ENDLOOP;
ENDLOOP
ELSE
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF n.tie=NIL THEN LOOP;
SetDirty[n.sync.time, n.sync.time];
SetDirty[n.tie.sync.time, n.tie.sync.time];
n.tie.tied ← FALSE;
n.tie ← NIL;
ENDLOOP;
IF lineSelect THEN SetDirty[select1, select2];
};
******************************************************************
chords
******************************************************************
MakeChord:
PUBLIC
PROC = {
n: NotePTR;
begin, end: Time;
chord: ChordPTR;
beam: BeamPTR ← NIL;
sync: SyncPTR ← NIL;
count: CARDINAL ← 0;
is this a legal chording?
begin ← EndOfScore[];
end ← -1;
FOR i:
CARDINAL
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice AND n.voice#selectedVoice THEN LOOP;
begin ← MIN[begin, n.sync.time];
end ←
MAX[end, n.sync.time];
count ← count+1;
ENDLOOP;
IF ABS[end-begin]>20 OR count<2 THEN {flash ← TRUE; RETURN};
make the new chord
chord ← Utility.NewChord[];
FOR i:
CARDINAL
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice
AND n.voice#selectedVoice
THEN
LOOP;
SetDirty[n.sync.time, n.sync.time];
Chord.AddNote[chord, n];
ENDLOOP;
Chord.SetDefaultStem[chord];
Piece.CleanUpSyncs[score];
};
ClearChord:
PUBLIC
PROC = {
n: NotePTR;
c: ChordPTR;
i, j: CARDINAL;
IF lineSelect
THEN {
FOR i
DECREASING
IN [0..scoreLength)
DO
IF score[i].time < select1 OR score[i].time > select2 THEN LOOP;
FOR j
IN [0..syncLength)
DO
IF (n ← score[i].event[j])=NIL THEN EXIT;
IF voice AND n.voice#selectedVoice THEN LOOP;
c ← Note.FindChord[n];
IF c#NIL THEN Chord.RemoveNote[c, n]; -- NIL's n.beam
ENDLOOP;
ENDLOOP};
IF
NOT lineSelect
THEN {
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice AND n.voice#selectedVoice THEN LOOP;
SetDirty[n.sync.time, n.sync.time];
c ← Note.FindChord[n];
IF c#NIL THEN Chord.RemoveNote[c, n]; -- NIL's n.beam
ENDLOOP};
IF lineSelect THEN SetDirty[select1, select2];
};
****************************************************************************
beams and n-tuplets
****************************************************************************
MakeBeam:
PUBLIC
PROC[beamed:
BOOL] = {
b: BeamPTR ← Utility.NewBeam[];
c: ChordPTR;
n, tmp: NotePTR;
i: CARDINAL;
height, stem: INTEGER;
stemUp, first: BOOL ← TRUE;
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice AND n.voice#selectedVoice THEN LOOP;
don't beam quarters or above
IF beamed AND n.value<eighth THEN LOOP;
IF n.beam = b THEN LOOP; --beaming a note in a chord already beamed
c ←Note.FindChord[n];
IF n.beam#NIL THEN Beam.Remove[n.beam, n, c, NIL];
IF c#
NIL
THEN {
tmp ← c.note[0];
Beam.AddChord[b, c];
IF first
THEN { stemUp← c.stemUp; first ←
FALSE;
[] ← Chord.Sort[c, NOT stemUp];
height ← (IF stemUp THEN -1000 ELSE 1000);
b.staff ← c.note[0].staff; };
IF beamed THEN c.stemUp ← stemUp;
[] ← Chord.Sort[c, NOT stemUp];
tmp ← c.note[0];
IF c.stemUp AND height<Sheet.Height[tmp.sync.time, tmp.pitch, tmp.staff] OR
NOT c.stemUp
AND height>Sheet.Height[tmp.sync.time, tmp.pitch, tmp.staff]
THEN height ← Sheet.Height[tmp.sync.time, tmp.pitch, tmp.staff];
};
IF c=
NIL
THEN {
Beam.AddNote[b, n];
IF first
THEN { stemUp← n.stemUp; first ←
FALSE;
height ← (IF stemUp THEN -1000 ELSE 1000);
b.staff ← n.staff; };
IF beamed THEN n.stemUp ← stemUp;
IF n.stemUp
AND height<Sheet.Height[n.sync.time, n.pitch, n.staff]
OR
NOT n.stemUp
AND height>Sheet.Height[n.sync.time, n.pitch, n.staff]
THEN height ← Sheet.Height[n.sync.time, n.pitch, n.staff];
};
ENDLOOP;
IF beamed THEN stem ← 34 ELSE stem ← 28;
b.height ← height-Sheet.Height[0,, b.staff]+(IF stemUp THEN stem ELSE -stem);
IF b.chord[1]=endOfBeam THEN {Utility.FreeBeam[@b]; RETURN};
SetDirty[b.sync1.time, b.sync2.time];
};
MakeBeamOfBeams:
PUBLIC
PROC[beamed:
BOOL] = {
CONTROL b beams beams together
n: NotePTR;
c: ChordPTR;
oldBeam: BeamPTR;
b: BeamPTR ← Utility.NewBeam[];
FOR i:
CARDINAL
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF n.beam=NIL THEN LOOP;
IF NOT n.beam.beamed THEN {flash ← TRUE; RETURN};
IF n.beam.beam#NIL THEN {flash ← TRUE; RETURN};
ENDLOOP;
FOR i:
CARDINAL
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice AND n.voice#selectedVoice THEN LOOP;
oldBeam ← n.beam;
IF oldBeam=b THEN LOOP;
IF oldBeam#
NIL
THEN {
Beam.AddBeam[b, oldBeam];
b.staff ← oldBeam.staff;
b.height ← oldBeam.height;
LOOP; };
IF beamed AND n.value<eighth THEN LOOP;
IF (c ← Note.FindChord[n])#
NIL
THEN Beam.AddChord[b, c]
ELSE Beam.AddNote[b, n];
ENDLOOP;
IF beamed
THEN
FOR i:
CARDINAL
IN [0..beamLength)
DO
IF b.chord[i]=endOfBeam THEN EXIT;
WITH ev: b.chord[i]
SELECT
FROM
beam => {
ev.b.height ← b.height;
ev.b.staff ← b.staff;
ev.b.tilt ← 0;
};
ENDCASE;
ENDLOOP;
b.tilt ← 0;
SetDirty[b.sync1.time, b.sync2.time];
};
ClearBeam:
PUBLIC
PROC = {
c: ChordPTR;
b: BeamPTR;
n: NotePTR;
i, j: CARDINAL;
IF lineSelect
THEN {
SetDirty[select1, select2];
FOR i
IN [0..scoreLength)
DO
IF score[i].time < select1 OR score[i].time > select2 THEN LOOP;
FOR j
IN [0..syncLength)
DO
IF (n ← score[i].event[j])=NIL THEN EXIT;
IF voice AND n.voice#selectedVoice THEN EXIT;
c ←Note.FindChord[n];
b ← n.beam;
IF b#NIL THEN Beam.Remove[b, n, c, NIL];
ENDLOOP;
ENDLOOP};
IF
NOT lineSelect
THEN {
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice AND n.voice#selectedVoice THEN LOOP;
SetDirty[n.sync.time, n.sync.time];
c ←Note.FindChord[n];
b ← n.beam;
IF b=NIL THEN LOOP;
Beam.Remove[b, n, c, NIL];
ENDLOOP};
};
MakeNTuplet:
PUBLIC
PROC[n, a:
INTEGER] = {
i: CARDINAL;
b: BeamPTR ← NIL;
newBeam: BOOL ← FALSE;
IF lineSelect THEN {Heuristic.MakeNTuplets[a, n, select1, select2]; RETURN};
FOR i
IN [0..selectionLength)
DO
IF selection[i]=NIL THEN LOOP;
IF voice AND selection[i].voice#selectedVoice THEN LOOP;
IF b=NIL THEN b ← selection[i].beam;
IF b=NIL OR selection[i].beam#b THEN newBeam ← TRUE;
ENDLOOP;
IF newBeam
THEN {
Selection.MakeBeam[FALSE];
FOR i
IN [0..selectionLength)
DO
IF selection[i]=NIL THEN LOOP;
IF voice AND selection[i].voice#selectedVoice THEN LOOP;
b ← selection[i].beam;
EXIT; ENDLOOP;
IF b#NIL THEN b.beamed ← FALSE};
IF b=NIL THEN RETURN;
b.against ← n;
b.ntuple ← a;
b.invisible ← FALSE;
SetDirty[b.sync1.time, b.sync2.time];
};
HideNTuplets:
PUBLIC
PROC[invisible:
BOOL] = {
b: BeamPTR;
n: NotePTR;
i, j: CARDINAL;
IF lineSelect
THEN
FOR i
IN [0..scoreLength)
DO
IF score[i]=NIL THEN LOOP;
IF score[i].time < select1 OR score[i].time > select2 THEN LOOP;
FOR j
IN [0..syncLength)
DO
IF (n ← score[i].event[j])=NIL THEN EXIT;
IF voice AND n.voice#selectedVoice THEN LOOP;
FOR b ← n.beam, b.beam
WHILE b#
NIL
DO
IF b.ntuple=0 THEN LOOP;
b.invisible ← invisible;
ENDLOOP;
ENDLOOP;
ENDLOOP
ELSE
FOR i
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice AND n.voice#selectedVoice THEN LOOP;
SetDirty[n.sync.time, n.sync.time];
FOR b ← n.beam, b.beam
WHILE b#
NIL
DO
IF b.ntuple=0 THEN LOOP;
b.invisible ← invisible;
ENDLOOP;
ENDLOOP;
IF lineSelect THEN SetDirty[select1, select2];
};
MakeNTupletOfBeams:
PUBLIC
PROC[n, a:
INTEGER] = {
t: NotePTR;
i: CARDINAL;
b: BeamPTR ← NIL;
newBeam: BOOL ← FALSE;
TopBeam:
PROC[b: BeamPTR]
RETURNS[BeamPTR] =
{IF b#NIL AND b.beam#NIL THEN RETURN[b.beam] ELSE RETURN[b]};
FOR i
IN [0..selectionLength)
DO
IF (t ← selection[i])=NIL THEN LOOP;
IF voice AND t.voice#selectedVoice THEN LOOP;
IF b=NIL THEN b ← TopBeam[t.beam];
IF b=NIL OR TopBeam[t.beam]#b THEN newBeam ← TRUE;
ENDLOOP;
IF newBeam
THEN {
Selection.MakeBeamOfBeams[FALSE];
FOR i
IN [0..selectionLength)
DO
IF selection[i]=NIL THEN LOOP;
IF selection[i].beam=NIL THEN LOOP;
IF voice AND selection[i].voice#selectedVoice THEN LOOP;
b ← TopBeam[selection[i].beam];
EXIT; ENDLOOP;
IF b#NIL THEN b.beamed ← FALSE};
IF b=NIL THEN RETURN;
b.against ← n;
b.ntuple ← a;
b.invisible ← FALSE;
SetDirty[b.sync1.time, b.sync2.time];
};
Delete:
PUBLIC
PROC = {
n: NotePTR;
IF lineSelect
THEN Piece.Delete[select1, select2]
ELSE
FOR i:
CARDINAL
IN [0..selectionLength)
DO
IF (n ← selection[i])=NIL THEN LOOP;
IF voice AND n.voice#selectedVoice THEN LOOP;
SetDirty[n.sync.time, n.sync.time];
Selection.RemoveNote[n];
Utility.FreeNote[@n];
ENDLOOP;
};
END.