<> <> <> <> <> DIRECTORY MusicDefs, Note USING [Delta], Real USING [FixI], Score USING [KeyHeight, ShowPitch], Sheet USING [default, FindLine, FindSection, FindStaves, Height, NextLine, PriorLine]; SheetImplB: CEDAR PROGRAM IMPORTS MusicDefs, Note, Real, Score, Sheet EXPORTS Sheet = BEGIN OPEN MusicDefs, Sheet; <<****************************************************************************>> <> <<****************************************************************************>> MapNote: PUBLIC PROC[sheet: SheetPTR, n: NotePTR] RETURNS[x, y: INTEGER] = { l: Section; show: INTEGER; t: Time _ n.sync.time; IF n.rest AND n.value = whole THEN t _ t-7; l _ sheet[FindSection[sheet, t]]; x _ t-l.time+l.x+Note.Delta[sheet, n]; show _ Score.ShowPitch[sheet, n.pitch, n.spelled, l.key]; RETURN[x, l.y-sheet.top+PitchHeight[sheet, t, show, l.key, l.staves.staff[n.staff]]]; }; Map: PUBLIC PROC[sheet: SheetPTR, t: Time, pitch: INTEGER, staff: CARDINAL] RETURNS[x, y: INTEGER] = { l: Section _ sheet[FindSection[sheet, t]]; RETURN[t-l.time+l.x, l.y-sheet.top + PitchHeight[sheet, t, pitch, l.key, l.staves.staff[staff]]]; }; MapHeight: PUBLIC PROC[sheet: SheetPTR, t: Time, height: INTEGER] RETURNS[x, y: INTEGER] = { l: Section _ sheet[FindSection[sheet, t]]; RETURN[t-l.time+l.x, l.y-sheet.top + height]; }; Height: PUBLIC PROC[sheet: SheetPTR, t: Time, pitch: INTEGER, staff: CARDINAL] RETURNS[INTEGER] = { l: Section _ sheet[FindSection[sheet, t]]; RETURN[PitchHeight[sheet, t, pitch, l.key, l.staves.staff[staff]]]; }; Pitch: PUBLIC PROC[sheet: SheetPTR, t: Time, height: INTEGER, staff: CARDINAL] RETURNS[INTEGER] = { i: CARDINAL; pitch: INTEGER _ 12; octave: INTEGER; l: Section _ sheet[FindSection[sheet, t]]; keyPitch: INTEGER _ (44+l.key*7) MOD 12; height _ height - PitchHeight[sheet, t, keyPitch, l.key, l.staves.staff[staff]]; IF height < 0 THEN octave _ height/28-1 ELSE octave _ height/28; octave _ height/28 - (IF height < 0 THEN 1 ELSE 0); height _ Mod[height, 28]; FOR i IN [0..12) DO IF pitchHeight[i] >= height THEN { pitch _ i; EXIT; }; ENDLOOP; RETURN[pitch + keyPitch + 12*octave]; }; PitchHeight: PROC[sheet: SheetPTR, t: Time, pitch, key: INTEGER, staff: Staff] RETURNS[INTEGER] = { <> < 100 use the staff's pitch>> height, octave: INTEGER; IF pitch > 100 THEN RETURN[staff.y]; IF NOT sheet.accidental THEN RETURN[CrackHeight[t, pitch, staff]]; octave _ (pitch-Mod[pitch, 12]-staff.pitch+Mod[staff.pitch, 12])/12; height _ 28*octave + Score.KeyHeight[key, pitch] - Score.KeyHeight[key, staff.pitch]; RETURN[staff.y+height]; }; CrackHeight: PROC[t: Time, pitch: INTEGER, staff: Staff] RETURNS[INTEGER] = { <> height: INTEGER; octave: INTEGER; ms: CARDINAL _ Mod[staff.pitch, 12]; mp: CARDINAL _ Mod[pitch, 12]; octave _ (pitch-mp-staff.pitch+ms)/12; height _ 28*octave + crackHeight[mp] - crackHeight[ms]; RETURN[staff.y+height]; }; crackHeight: ARRAY[0..12) OF INTEGER = [0, 4, 6, 8, 10, 12, 14, 16, 20, 22, 24, 26]; pitchHeight: ARRAY [0..12) OF INTEGER = [0, 1, 4, 5, 8, 12, 13, 16, 17, 20, 21, 24]; <<****************************************************************************>> <> <<****************************************************************************>> ScreenPoint: PUBLIC PROC[sheet: SheetPTR] RETURNS[x, y: INTEGER] = { rx, ry: REAL _ 0; <<[rx, ry] _ Graphics.WorldToUser[sheet.context, mouse.x, 808 - mouse.y];>> x _ Real.FixI[rx]; y _ Real.FixI[ry]+sheet.top; }; NearestTime: PUBLIC PROC[sheet: SheetPTR, x, y: INTEGER] RETURNS[time: Time, height: INTEGER] = { line, next: CARDINAL _ 0; IF x = default THEN [x, y] _ ScreenPoint[sheet]; WHILE sheet[next].y >= y DO line _ next; next _ Sheet.NextLine[sheet, line]; ENDLOOP; IF y < ((sheet[line].y+Sheet.Height[sheet, sheet[line].time, , 3]+8)/2+sheet[next].y/2) THEN line _ next; IF x < sheet[line].x THEN x _ sheet[line].x; IF x > sheet.width THEN x _ sheet.width; time _ sheet[line].time+ x- sheet[line].x; height _ y- sheet[line].y; }; AlternateTime: PUBLIC PROC[sheet: SheetPTR, t1: Time, h1: INTEGER, lines: INTEGER] RETURNS[time: Time, height: INTEGER] = { next, prior, l: CARDINAL; time _ t1; height _ h1; l _ Sheet.FindLine[sheet, time]; IF lines > 0 THEN FOR i: CARDINAL IN [0..ABS[lines]) DO next _ Sheet.NextLine[sheet, l]; time _ time + (sheet.width - sheet[next].x); height _ height - (sheet[next].y - sheet[l].y); l _ next; ENDLOOP; IF lines < 0 THEN FOR i: CARDINAL IN [0..ABS[lines]) DO prior _ Sheet.PriorLine[sheet, l]; time _ time - (sheet.width - sheet[l].x); height _ height + (sheet[l].y - sheet[prior].y); l _ prior; ENDLOOP; RETURN[time, height]; }; NearestStaff: PUBLIC PROC[sheet: SheetPTR, t: Time, height: INTEGER] RETURNS[CARDINAL] = { j: CARDINAL _ 10; staves: StavesPTR = Sheet.FindStaves[sheet, t]; FOR i: CARDINAL IN [0..staves.length) DO IF i < 2 AND staves.staff[i] = staves.staff[i+1] THEN LOOP; IF height < staves.staff[i].y THEN { j _ i; LOOP; }; IF j = 10 THEN RETURN[i]; IF height < (staves.staff[j].y+staves.staff[i].y+34)/2 THEN RETURN[i] ELSE RETURN[j]; ENDLOOP; RETURN[staves.length-1]; }; END. GetStaves: PROC[time: Time] RETURNS[StavesPTR] = { sync: SyncPTR _ NIL; FOR i: CARDINAL IN [0..cacheLength) DO IF cache[i] = NIL THEN EXIT; IF cache[i].type # staves THEN LOOP; IF cache[i].time > time AND sync = NIL THEN sync _ cache[i]; IF cache[i].time > time THEN EXIT; sync _ cache[i]; ENDLOOP; IF sync = NIL THEN { Sheet.SetStaves[2, 0, EndOfScore[]]; RETURN[GetStaves[time]]; }; RETURN[LOOPHOLE[@sync.event]]; }; Reset: PUBLIC PROC = { staves: Staves; page: INTEGER _ 2; i, j: CARDINAL _ 0; sync: SyncPTR _ NIL; time, break, top, cacheTime: Time _ 0; height, x, sc, sheetHeight: INTEGER _ 0; Score.BuildCache[]; MakeSheetConsistent[]; IF scale = 2 THEN sc _ 3 ELSE sc _ 2*scale; FOR i IN [0..cacheLength] DO IF i # cacheLength AND cache[i].type NOT IN SheetSwitch THEN LOOP; IF i = cacheLength AND sync = NIL THEN RETURN; IF i = cacheLength THEN cacheTime _ 400000 ELSE cacheTime _ cache[i].time; IF sync = NIL THEN {sync _ cache[i]; staves _ LOOPHOLE[sync.event]}; WHILE time < cacheTime DO sheet[j] _ [, height, 0, Key[time], time, LOOPHOLE[@sync.event]]; IF x = 0 AND top-height > (650*sc)/2 THEN { top _ height; sheet[j].page _ page; page _ page+1; }; SELECT TRUE FROM x = 0 => {x _ ABS[8*(sheet[j].key)]; IF x = 0 THEN x _ 8}; ENDCASE => x _ x + time-sheet[j-1].time; sheet[j].x _ x; IF time >= break THEN break _ break+staffLength-x; time _ MIN[cacheTime, break]; IF time >= break THEN { sheetHeight _ -staves.staff[staves.sl].y; height _ height - sheetHeight - staves.offset; x _ 0; }; j _ j+1; IF j = sheetLength THEN RETURN; ENDLOOP; IF i = cacheLength THEN EXIT; sync _ cache[i]; staves _ LOOPHOLE[sync.event]; ENDLOOP; FOR i: CARDINAL IN [0..beamHeapLength) DO Beam.SetStems[beamHeap[i]]; ENDLOOP; };