@@ -11,7 +11,6 @@ import { Pitch, PitchKey, Clef, PitchLetter, TickAccidental,
1111import { SmoMicrotone } from './noteModifiers' ;
1212import { VexFlow , pitchToLedgerLine , vexCanonicalNotes } from '../../common/vex' ;
1313
14- const VF = VexFlow ;
1514/**
1615 * Used for xml clef conversion
1716 */
@@ -97,6 +96,8 @@ export class SmoAudioPitch {
9796 * base note lengths + dots)
9897 */
9998export interface SimpleDuration {
99+ index : number ,
100+ ticks : number ,
100101 baseTicks : number ,
101102 dots : number
102103}
@@ -268,7 +269,14 @@ export class SmoMusic {
268269 }
269270 ] ;
270271 }
271- static getLineFromSmoPitch ( clef : string , smoPitch : Pitch ) : number {
272+ /**
273+ * Return the number of lines above first ledger line below the staff.
274+ * e.g. middle c in treble clef returns 0. Top line f in treble returns 5.
275+ * @param clef
276+ * @param pitch
277+ * @returns number where 0 is the first ledger line below
278+ */
279+ static pitchToStaffLine ( clef : string , smoPitch : Pitch ) : number {
272280 const octave = smoPitch . octave * 7 - 4 * 7 ;
273281 const keyTable = smoPitch . letter + smoPitch . accidental ;
274282 let line = ( SmoMusic . noteValues [ keyTable ] . root_index + octave ) / 2 ;
@@ -390,7 +398,7 @@ export class SmoMusic {
390398 */
391399 static pitchToLedgerLine ( clef : Clef , pitch : Pitch ) : number {
392400 // return the distance from the top ledger line, as 0.5 per line/space
393- const line = SmoMusic . getLineFromSmoPitch ( clef , pitch ) ;
401+ const line = SmoMusic . pitchToStaffLine ( clef , pitch ) ;
394402 if ( line > 5 ) {
395403 return - 1 * ( line - 5 ) ;
396404 }
@@ -399,16 +407,7 @@ export class SmoMusic {
399407 }
400408 return 0 ;
401409 }
402- /**
403- * Return the number of ledger lines based on the pitch and clef
404- * @param clef
405- * @param pitch
406- * @returns number where 0 is the top staff line
407- */
408- static pitchToStaffLine ( clef : Clef , pitch : Pitch ) : number {
409- // return the distance from the top ledger line, as 0.5 per line/space
410- return SmoMusic . getLineFromSmoPitch ( clef , pitch ) ;
411- }
410+
412411 /**
413412 * return flag state (up === 1 or down === 2) based on pitch and clef if auto
414413 * */
@@ -455,6 +454,17 @@ export class SmoMusic {
455454 'subbass' : 7 ,
456455 'french' : - 1
457456 }
457+ static scaleTones : string [ ] = [ 'tonic' , '2' , '3' , '4' , '5' , '6' , '7' ] ;
458+ static getScaleTonesForKey ( keySignature : string ) : Record < string , string > {
459+ const key = SmoMusic . enharmonicRoles [ keySignature ] ;
460+ const rv : Record < string , string > = { } ;
461+ key . forEach ( ( role ) => {
462+ if ( SmoMusic . scaleTones . indexOf ( role . role ) >= 0 ) {
463+ rv [ role . letter ] = role . letter + role . accidental ;
464+ }
465+ } ) ;
466+ return rv ;
467+ }
458468 /**
459469 * The purpose of this table is to keep consistent enharmonic spelling when transposing
460470 * instruments in different keys. It is not theoritically complete, e.g.
@@ -1115,7 +1125,8 @@ export class SmoMusic {
11151125 const flatKey = keySignature . indexOf ( 'b' ) >= 0 ;
11161126 const ar = SmoMusic . getEnharmonics ( SmoMusic . pitchToVexKey ( smoPitch ) ) ;
11171127 rv = SmoMusic . stripVexOctave ( SmoMusic . pitchToVexKey ( smoPitch ) ) ;
1118- const scaleMap : Record < string , string > = new VF . Music ( ) . createScaleMap ( keySignature ) ;
1128+ const scaleMap : Record < string , string > = SmoMusic . getScaleTonesForKey ( keySignature ) ;
1129+ // new VF.Music().createScaleMap(keySignature);
11191130 ar . forEach ( ( vexKey ) => {
11201131 if ( vexKey . length === 1 ) {
11211132 vexKey += 'n' ;
@@ -1159,8 +1170,7 @@ export class SmoMusic {
11591170 static getKeyFriendlyEnharmonic ( letter : string , keySignature : string ) : string {
11601171 let rv : string = letter ;
11611172 let i = 0 ;
1162- const muse = new VF . Music ( ) ;
1163- const scale : string [ ] = Object . values ( muse . createScaleMap ( keySignature ) ) ;
1173+ const scale : string [ ] = Object . values ( SmoMusic . getScaleTonesForKey ( keySignature ) ) ;
11641174 let prop : string = SmoMusic . getEnharmonic ( letter . toLowerCase ( ) ) ;
11651175 while ( prop . toLowerCase ( ) !== letter . toLowerCase ( ) ) {
11661176 for ( i = 0 ; i < scale . length ; ++ i ) {
@@ -1185,8 +1195,8 @@ export class SmoMusic {
11851195 * @returns
11861196 */
11871197 static getKeySignatureKey ( letter : PitchLetter , keySignature : string ) : string {
1188- const km = new VF . KeyManager ( keySignature ) ;
1189- return ( km as any ) . scaleMap [ letter ] ;
1198+ const scaleMap = SmoMusic . getScaleTonesForKey ( keySignature ) ;
1199+ return scaleMap [ letter ] ;
11901200 }
11911201
11921202 static getAccidentalForKeySignature ( smoPitch : Pitch , keySignature : string ) : string {
@@ -1465,23 +1475,28 @@ export class SmoMusic {
14651475 }
14661476 if ( SmoMusic . _validDurations === null ) {
14671477 SmoMusic . _validDurations = { } ;
1478+ let index = 0 ;
14681479 for ( var i = 0 ; i < SmoMusic . durationsDescending . length ; ++ i ) {
14691480 const baseTicks = SmoMusic . durationsDescending [ i ] ;
14701481 for ( var j = 3 ; j >= 1 ; -- j ) {
14711482 const { dottedValue, minDot } = computeDots ( baseTicks , j ) ;
14721483 if ( dottedValue < SmoMusic . highestDuration && minDot > SmoMusic . lowestDuration ) {
14731484 SmoMusic . _validDurations [ dottedValue ] = {
1485+ index : SmoMusic . _validDurationKeys . length ,
1486+ ticks : dottedValue ,
14741487 baseTicks,
14751488 dots : j
14761489 }
14771490 SmoMusic . _validDurationKeys . push ( dottedValue ) ;
14781491 }
14791492 }
1480- SmoMusic . _validDurationKeys . push ( baseTicks ) ;
14811493 SmoMusic . _validDurations [ baseTicks ] = {
1494+ index : SmoMusic . _validDurationKeys . length ,
1495+ ticks : baseTicks ,
14821496 baseTicks,
14831497 dots : 0
14841498 } ;
1499+ SmoMusic . _validDurationKeys . push ( baseTicks ) ;
14851500 }
14861501 }
14871502 return SmoMusic . _validDurations ;
@@ -1690,11 +1705,9 @@ export class SmoMusic {
16901705 // Get ticks for this note with an added dot. Return
16911706 // identity if that is not a supported value.
16921707 static getNextDottedLevel ( ticks : number ) : number {
1693- const ttd = SmoMusic . ticksToDuration ;
1694- const vals = Object . values ( ttd ) ;
1695- const ix = vals . indexOf ( ttd [ ticks ] ) ;
1696- if ( ix >= 0 && ix < vals . length && vals [ ix ] [ 0 ] === vals [ ix + 1 ] [ 0 ] ) {
1697- return SmoMusic . durationToTicks ( vals [ ix + 1 ] ) ;
1708+ const ticksOrNull = SmoMusic . closestSmoDurationFromTicks ( ticks ) ;
1709+ if ( ticksOrNull && ticksOrNull . index > 0 ) {
1710+ return SmoMusic . validDurations [ SmoMusic . _validDurationKeys [ ticksOrNull . index - 1 ] ] . ticks ;
16981711 }
16991712 return ticks ;
17001713 }
@@ -1703,36 +1716,12 @@ export class SmoMusic {
17031716 // Get ticks for this note with one fewer dot. Return
17041717 // identity if that is not a supported value.
17051718 static getPreviousDottedLevel ( ticks : number ) : number {
1706- const ttd = SmoMusic . ticksToDuration ;
1707- const vals = Object . values ( ttd ) ;
1708- const ix = vals . indexOf ( ttd [ ticks ] ) ;
1709- if ( ix > 0 && vals [ ix ] [ 0 ] === vals [ ix - 1 ] [ 0 ] ) {
1710- return SmoMusic . durationToTicks ( vals [ ix - 1 ] ) ;
1719+ const ticksOrNull = SmoMusic . closestSmoDurationFromTicks ( ticks ) ;
1720+ if ( ticksOrNull && ticksOrNull . index < SmoMusic . _validDurationKeys . length + 1 ) {
1721+ return SmoMusic . validDurations [ SmoMusic . _validDurationKeys [ ticksOrNull . index + 1 ] ] . ticks ;
17111722 }
17121723 return ticks ;
17131724 }
1714-
1715-
1716- // ### durationToTicks
1717- // Uses VF.durationToTicks, but handles dots.
1718- static durationToTicks ( duration : string ) : number {
1719- let split = 0 ;
1720- let i = 0 ;
1721- let vfDuration = 0 ;
1722- let dots = duration . indexOf ( 'd' ) ;
1723- if ( dots < 0 ) {
1724- return VF . durationToTicks ( duration ) as number ;
1725- } else {
1726- vfDuration = VF . durationToTicks ( duration . substring ( 0 , dots ) ) as number ;
1727- dots = duration . length - dots ; // number of dots
1728- split = vfDuration / 2 ;
1729- for ( i = 0 ; i < dots ; ++ i ) {
1730- vfDuration += split ;
1731- split = split / 2 ;
1732- }
1733- return vfDuration ;
1734- }
1735- }
17361725
17371726 /**
17381727 * break the duration up into an array of durations, to split a long
0 commit comments