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 BOOLFALSE;
flash: PUBLIC BOOLFALSE;
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: BOOLTRUE;
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: BOOLTRUE;
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: BOOLFALSE;
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: BOOLFALSE;
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.