import Vex from "vexflow" ; import { ClefEnum } from "../../VoiceData/Instructions/ClefInstruction" ; import { ClefInstruction } from "../../VoiceData/Instructions/ClefInstruction" ; import { Pitch } from "../../../Common/DataObjects/Pitch" ; import { Fraction } from "../../../Common/DataObjects/Fraction" ; import { RhythmInstruction } from "../../VoiceData/Instructions/RhythmInstruction" ; import { RhythmSymbolEnum } from "../../VoiceData/Instructions/RhythmInstruction" ; import { KeyInstruction } from "../../VoiceData/Instructions/KeyInstruction" ; import { KeyEnum } from "../../VoiceData/Instructions/KeyInstruction" ; import { AccidentalEnum } from "../../../Common/DataObjects/Pitch" ; import { NoteEnum } from "../../../Common/DataObjects/Pitch" ; import { VexFlowGraphicalNote } from "./VexFlowGraphicalNote" ; import { GraphicalNote } from "../GraphicalNote" ; import { SystemLinesEnum } from "../SystemLinesEnum" ; import { FontStyles } from "../../../Common/Enums/FontStyles" ; import { Fonts } from "../../../Common/Enums/Fonts" ; import { OutlineAndFillStyleEnum , OUTLINE_AND_FILL_STYLE_DICT } from "../DrawingEnums" ; import log from "loglevel" ; import { ArticulationEnum , StemDirectionType , VoiceEntry } from "../../VoiceData/VoiceEntry" ; import { SystemLinePosition } from "../SystemLinePosition" ; import { GraphicalVoiceEntry } from "../GraphicalVoiceEntry" ; import { OrnamentEnum , OrnamentContainer } from "../../VoiceData/OrnamentContainer" ; import { Notehead , NoteHeadShape } from "../../VoiceData/Notehead" ; import { unitInPixels } from "./VexFlowMusicSheetDrawer" ; import { EngravingRules } from "../EngravingRules" ; import { Note } from "../../../MusicalScore/VoiceData/Note" ; import StaveNote = Vex . Flow . StaveNote ; import { ArpeggioType } from "../../VoiceData/Arpeggio" ; import { TabNote } from "../../VoiceData/TabNote" ; import { PlacementEnum } from "../../VoiceData/Expressions/AbstractExpression" ; import { GraphicalStaffEntry } from "../GraphicalStaffEntry" ; import { Articulation } from "../../VoiceData/Articulation" ; /**
 * Helper class, which contains static methods which actually convert
 * from OSMD objects to VexFlow objects.
 */ export class VexFlowConverter { type { [ alterationsNo : number ] private static majorMap : { [ _ ] : string ; } = { "-1" : "F" , "-2" : "Bb" , "-3" : "Eb" , "-4" : "Ab" , "-5" : "Db" , "-6" : "Gb" , "-7" : "Cb" , "-8" : "Fb" , "0" : "C" , "1" : "G" , "2" : "D" , "3" : "A" , "4" : "E" , "5" : "B" , "6" : "F#" , "7" : "C#" , "8" : "G#" } ; type { [ alterationsNo : number ] private static minorMap : { [ _ ] : string ; } = { "-1" : "D" , "-2" : "G" , "-3" : "C" , "-4" : "F" , "-5" : "Bb" , "-6" : "Eb" , "-7" : "Ab" , "-8" : "Db" , "0" : "A" , "1" : "E" , "2" : "B" , "3" : "F#" , "4" : "C#" , "5" : "G#" , "6" : "D#" , "7" : "A#" , "8" : "E#" } ; param fraction returns { string [ ] } public static durations ( fraction , isTuplet ) { const durations = [ ] ; const remainingFraction = fraction . clone ( ) ; while ( remainingFraction . RealValue > 0 ) { const dur = remainingFraction . RealValue ; if ( dur >= 2 ) { durations . push ( "1/2" ) ; remainingFraction . Sub ( new Fraction ( 2 , 1 ) ) ; } else if ( dur >= 1 ) { durations . push ( "w" ) ; remainingFraction . Sub ( new Fraction ( 1 , 1 ) ) ; } else if ( dur < 1 && dur >= 0.5 ) { if ( isTuplet && dur > 0.5 ) { return [ "w" ] ; } else { durations . push ( "h" ) ; remainingFraction . Sub ( new Fraction ( 1 , 2 ) ) ; } } else if ( dur < 0.5 && dur >= 0.25 ) { if ( isTuplet && dur > 0.25 ) { return [ "h" ] ; } else { durations . push ( "q" ) ; remainingFraction . Sub ( new Fraction ( 1 , 4 ) ) ; } } else if ( dur < 0.25 && dur >= 0.125 ) { if ( isTuplet && dur > 0.125 ) { return [ "q" ] ; } else { durations . push ( "8" ) ; remainingFraction . Sub ( new Fraction ( 1 , 8 ) ) ; } } else if ( dur < 0.125 && dur >= 0.0625 ) { if ( isTuplet && dur > 0.0625 ) { return [ "8" ] ; } else { durations . push ( "16" ) ; remainingFraction . Sub ( new Fraction ( 1 , 16 ) ) ; } } else if ( dur < 0.0625 && dur >= 0.03125 ) { if ( isTuplet && dur > 0.03125 ) { return [ "16" ] ; } else { durations . push ( "32" ) ; remainingFraction . Sub ( new Fraction ( 1 , 32 ) ) ; } } else if ( dur < 0.03125 && dur >= 0.015625 ) { if ( isTuplet && dur > 0.015625 ) { return [ "32" ] ; } else { durations . push ( "64" ) ; remainingFraction . Sub ( new Fraction ( 1 , 64 ) ) ; } } else { if ( isTuplet ) { return [ "64" ] ; } else { durations . push ( "128" ) ; remainingFraction . Sub ( new Fraction ( 1 , 128 ) ) ; } } } return durations ; } param pitch returns { string [ ] } public static pitch ( pitch , isRest , clef , notehead = undefined , octaveOffsetGiven = undefined ) { let octaveOffset = octaveOffsetGiven ; if ( octaveOffsetGiven === undefined ) { octaveOffset = 3 ; } if ( isRest && octaveOffsetGiven === undefined ) { octaveOffset = 0 ; if ( clef . ClefType === ClefEnum . F ) { octaveOffset = 2 ; } if ( clef . ClefType === ClefEnum . C ) { octaveOffset = 2 ; } } const fund = NoteEnum [ pitch . FundamentalNote ] . toLowerCase ( ) ; const acc = Pitch . accidentalVexflow ( pitch . Accidental ) ; const octave = pitch . Octave - clef . OctaveOffset + octaveOffset ; let noteheadCode = "" ; if ( notehead ) { noteheadCode = this . NoteHeadCode ( notehead ) ; } return [ fund + "n/" + octave + noteheadCode , acc , clef ] ; } public static restToNotePitch ( pitch , clefType ) { let octave = pitch . Octave ; switch ( clefType ) { case ClefEnum . C : case ClefEnum . F : { octave += 2 ; break ; } case ClefEnum . G : default : } return new Pitch ( pitch . FundamentalNote , octave , AccidentalEnum . NONE ) ; } /** returns the Vexflow code for a note head. Some are still unsupported, see Vexflow/tables.js */ public static NoteHeadCode ( notehead ) { const codeStart = "/" ; const codeFilled = notehead . Filled ? "2" : "1" ; switch ( notehead . Shape ) { case NoteHeadShape . NORMAL : return "" ; case NoteHeadShape . DIAMOND : return codeStart + "D" + codeFilled ; case NoteHeadShape . TRIANGLE : return codeStart + "T" + codeFilled ; case NoteHeadShape . X : return codeStart + "X" + codeFilled ; case NoteHeadShape . CIRCLEX : return codeStart + "X3" ; case NoteHeadShape . RECTANGLE : return codeStart + "R" + codeFilled ; case NoteHeadShape . SQUARE : return codeStart + "S" + codeFilled ; case NoteHeadShape . SLASH : return "" ; default : return "" ; } } public static GhostNotes ( frac ) { const ghostNotes = [ ] ; const durations = VexFlowConverter . durations ( frac , false ) ; for ( const duration of durations ) { ghostNotes . push ( new Vex . Flow . GhostNote ( { duration : duration , } ) ) ; } return ghostNotes ; } param gve returns { Vex . Flow . StaveNote } public static StaveNote ( gve ) { gve . sortForVexflow ( ) ; const notes = gve . notes ; const rules = gve . parentStaffEntry . parentMeasure . parentSourceMeasure . Rules ; const baseNote = notes [ 0 ] ; let keys = [ ] ; const accidentals = [ ] ; const baseNoteLength = baseNote . graphicalNoteLength ; const isTuplet = baseNote . sourceNote . NoteTuplet !== undefined ; let duration = VexFlowConverter . durations ( baseNoteLength , isTuplet ) [ 0 ] ; if ( baseNote . sourceNote . TypeLength !== undefined && baseNote . sourceNote . TypeLength !== baseNoteLength && baseNote . sourceNote . TypeLength . RealValue !== 0 ) { duration = VexFlowConverter . durations ( baseNote . sourceNote . TypeLength , isTuplet ) [ 0 ] ; baseNote . numberOfDots = baseNote . sourceNote . DotsXml ; } let vfClefType = undefined ; let numDots = baseNote . numberOfDots ; let alignCenter = false ; let xShift = 0 ; let slashNoteHead = false ; let isRest = false ; let restYPitch ; for ( const note of notes ) { if ( numDots < note . numberOfDots ) { numDots = note . numberOfDots ; } if ( note . sourceNote . isRest ( ) ) { isRest = true ; if ( note . sourceNote . Pitch ) { const restVfPitch = ( note as VexFlowGraphicalNote ) . vfpitch ; keys = [ restVfPitch [ 0 ] ] ; break ; } else { keys = [ "b/4" ] ; const pauseVoiceEntry = note . parentVoiceEntry ?. parentVoiceEntry ; if ( pauseVoiceEntry ) { const neighborGSEs = note . parentVoiceEntry ?. parentStaffEntry . parentMeasure . staffEntries ; let previousVoiceEntry , followingVoiceEntry ; let pauseVEIndex = - 1 ; for ( let i = 0 ; i < neighborGSEs . length ; i ++ ) { if ( neighborGSEs [ i ] ?. graphicalVoiceEntries [ 0 ] . parentVoiceEntry === pauseVoiceEntry ) { pauseVEIndex = i ; break ; } } if ( pauseVEIndex >= 1 && ( neighborGSEs . length - 1 ) >= ( pauseVEIndex + 1 ) ) { previousVoiceEntry = neighborGSEs [ pauseVEIndex - 1 ] ?. graphicalVoiceEntries [ 0 ] ?. parentVoiceEntry ; followingVoiceEntry = neighborGSEs [ pauseVEIndex + 1 ] ?. graphicalVoiceEntries [ 0 ] ?. parentVoiceEntry ; if ( previousVoiceEntry && followingVoiceEntry ) { const previousNote = previousVoiceEntry . Notes [ 0 ] ; const followingNote = followingVoiceEntry . Notes [ 0 ] ; if ( previousNote . NoteBeam ?. Notes . includes ( followingNote ) ) { const previousNotePitch = previousVoiceEntry . Notes . last ( ) . Pitch ; const clef = ( note as VexFlowGraphicalNote ) . Clef ( ) ; const vfpitch = VexFlowConverter . pitch ( VexFlowConverter . restToNotePitch ( previousNotePitch . getTransposedPitch ( - 2 ) , clef . ClefType ) , false , clef ) ; keys = [ vfpitch [ 0 ] ] ; } } } } } const isWholeMeasureRest = baseNoteLength . RealValue === note . sourceNote . SourceMeasure . ActiveTimeSignature . RealValue ; if ( isWholeMeasureRest ) { keys = [ "d/5" ] ; duration = "w" ; numDots = 0 ; alignCenter = true ; xShift = rules . WholeRestXShiftVexflow * unitInPixels ; } if ( note . sourceNote . ParentStaff . Voices . length > 1 ) { const staffGves = note . parentVoiceEntry . parentStaffEntry . graphicalVoiceEntries ; const restVoiceId = note . parentVoiceEntry . parentVoiceEntry . ParentVoice . VoiceId ; let maxHalftone ; let linesShift ; for ( const staffGve of staffGves ) { for ( const gveNote of staffGve . notes ) { if ( gveNote === note || gveNote . sourceNote . isRest ( ) || ! gveNote . sourceNote . PrintObject ) { continue ; } const wantedStemDirection = gveNote . parentVoiceEntry . parentVoiceEntry . WantedStemDirection ; const isUpperVoiceRest = restVoiceId === 1 || restVoiceId === 5 ; const lineShiftDirection = isUpperVoiceRest ? 1 : - 1 ; const gveNotePitch = gveNote . sourceNote . Pitch ; const noteHalftone = gveNotePitch . getHalfTone ( ) ; const newHigh = lineShiftDirection === 1 && noteHalftone > maxHalftone ; const newLow = lineShiftDirection === - 1 && noteHalftone < maxHalftone ; if ( ! maxHalftone || newHigh || newLow ) { maxHalftone = noteHalftone ; linesShift = 0 ; if ( isUpperVoiceRest && wantedStemDirection === StemDirectionType . Up ) { linesShift += 7 ; } else if ( ! isUpperVoiceRest && wantedStemDirection === StemDirectionType . Down ) { linesShift += 7 ; } else if ( isUpperVoiceRest ) { linesShift += 1 ; } else { linesShift += 2 ; } if ( ! duration . includes ( "8" ) ) { if ( wantedStemDirection === StemDirectionType . Up && lineShiftDirection === - 1 ) { linesShift += 1 ; } } if ( gveNote . sourceNote . NoteBeam ) { linesShift += 1 ; } if ( duration . includes ( "w" ) ) { linesShift /= 2 ; } linesShift += ( Math . ceil ( rules . RestCollisionYPadding ) * 0.5 ) ; linesShift *= lineShiftDirection ; note . lineShift = linesShift ; } } } if ( maxHalftone > 0 ) { let octaveOffset = 3 ; const restClefInstruction = ( note as VexFlowGraphicalNote ) . Clef ( ) ; switch ( restClefInstruction . ClefType ) { case ClefEnum . F : octaveOffset = 5 ; break ; case ClefEnum . C : octaveOffset = 4 ; break ; default : break ; } restYPitch = Pitch . fromHalftone ( maxHalftone ) ; keys = [ VexFlowConverter . pitch ( restYPitch , true , restClefInstruction , undefined , octaveOffset ) [ 0 ] ] ; } } break ; } if ( note . sourceNote . Notehead ) { if ( note . sourceNote . Notehead . Shape === NoteHeadShape . SLASH ) { slashNoteHead = true ; } } const pitch = ( note as VexFlowGraphicalNote ) . vfpitch ; keys . push ( pitch [ 0 ] ) ; accidentals . push ( pitch [ 1 ] ) ; if ( ! vfClefType ) { const vfClef = VexFlowConverter . Clef ( pitch [ 2 ] ) ; vfClefType = vfClef . type ; } } for ( let i = 0 , len = numDots ; i < len ; ++ i ) { duration += "d" ; } if ( slashNoteHead ) { duration += "s" ; } if ( isRest ) { duration += "r" ; } let vfnote ; const vfnoteStruct = { align_center : alignCenter , auto_stem : true , clef : vfClefType , duration : duration , keys : keys , slash : gve . GraceSlash , } ; const firstNote = gve . notes [ 0 ] . sourceNote ; if ( firstNote . IsCueNote ) { vfnoteStruct . glyph_font_scale = Vex . Flow . DEFAULT_NOTATION_FONT_SCALE * Vex . Flow . GraceNote . SCALE ; vfnoteStruct . stroke_px = Vex . Flow . GraceNote . LEDGER_LINE_OFFSET ; } if ( gve . parentVoiceEntry . IsGrace || gve . notes [ 0 ] . sourceNote . IsCueNote ) { vfnote = new Vex . Flow . GraceNote ( vfnoteStruct ) ; } else { vfnote = new Vex . Flow . StaveNote ( vfnoteStruct ) ; ( vfnote as any ) . stagger_same_whole_notes = rules . StaggerSameWholeNotes ; } const lineShift = gve . notes [ 0 ] . lineShift ; if ( lineShift !== 0 ) { vfnote . getKeyProps ( ) [ 0 ] . line += lineShift ; } vfnote . getKeyProps ( ) . forEach ( ( { line } , i ) => gve . notes [ i ] . staffLine = line ) ; if ( rules . LedgerLineWidth || rules . LedgerLineStrokeStyle ) { if ( ! ( ( vfnote as any ) . ledgerLineStyle ) ) { ( vfnote as any ) . ledgerLineStyle = { } ; } if ( rules . LedgerLineWidth ) { ( vfnote as any ) . ledgerLineStyle . lineWidth = rules . LedgerLineWidth ; } if ( rules . LedgerLineStrokeStyle ) { ( vfnote as any ) . ledgerLineStyle . strokeStyle = rules . LedgerLineStrokeStyle ; } } if ( rules . ColoringEnabled ) { const defaultColorStem = rules . DefaultColorStem ; let stemColor = gve . parentVoiceEntry . StemColor ; if ( ! stemColor && defaultColorStem ) { stemColor = defaultColorStem ; } const stemStyle = { fillStyle : stemColor , strokeStyle : stemColor } ; if ( stemColor ) { vfnote . setStemStyle ( stemStyle ) ; if ( vfnote . flag && rules . ColorFlags ) { vfnote . setFlagStyle ( stemStyle ) ; } } } vfnote . x_shift = xShift ; if ( gve . parentVoiceEntry . IsGrace && gve . notes [ 0 ] . sourceNote . NoteBeam ) { gve . parentVoiceEntry . WantedStemDirection = gve . notes [ 0 ] . sourceNote . NoteBeam . Notes [ 0 ] . ParentVoiceEntry . WantedStemDirection ; } if ( gve . parentVoiceEntry ) { const wantedStemDirection = gve . parentVoiceEntry . WantedStemDirection ; switch ( wantedStemDirection ) { case ( StemDirectionType . Up ) : vfnote . setStemDirection ( Vex . Flow . Stem . UP ) ; gve . parentVoiceEntry . StemDirection = StemDirectionType . Up ; break ; case ( StemDirectionType . Down ) : vfnote . setStemDirection ( Vex . Flow . Stem . DOWN ) ; gve . parentVoiceEntry . StemDirection = StemDirectionType . Down ; break ; default : } } for ( let i = 0 , len = notes . length ; i < len ; i += 1 ) { ( notes [ i ] as VexFlowGraphicalNote ) . setIndex ( vfnote , i ) ; if ( accidentals [ i ] ) { if ( accidentals [ i ] === "###" ) { vfnote . addAccidental ( i , new Vex . Flow . Accidental ( "##" ) ) ; vfnote . addAccidental ( i , new Vex . Flow . Accidental ( "#" ) ) ; continue ; } else if ( accidentals [ i ] === "bbs" ) { vfnote . addAccidental ( i , new Vex . Flow . Accidental ( "bb" ) ) ; vfnote . addAccidental ( i , new Vex . Flow . Accidental ( "b" ) ) ; continue ; } vfnote . addAccidental ( i , new Vex . Flow . Accidental ( accidentals [ i ] ) ) ; } const tremoloStrokes = notes [ i ] . sourceNote . TremoloStrokes ; if ( tremoloStrokes > 0 ) { const tremolo = new Vex . Flow . Tremolo ( tremoloStrokes ) ; ( tremolo as any ) . extra_stroke_scale = rules . TremoloStrokeScale ; ( tremolo as any ) . y_spacing_scale = rules . TremoloYSpacingScale ; vfnote . addModifier ( i , tremolo ) ; } } if ( firstNote . Length . RealValue === 0.25 && firstNote . Notehead && firstNote . Notehead . Filled === false ) { const keyProps = vfnote . getKeyProps ( ) ; for ( let i = 0 ; i < keyProps . length ; i ++ ) { ( < any > keyProps [ i ] ) . code = "v81" ; } } for ( let i = 0 , len = numDots ; i < len ; ++ i ) { vfnote . addDotToAll ( ) ; } return vfnote ; } public static generateArticulations ( vfnote , articulations , rules ) { if ( ! vfnote || vfnote . getAttribute ( "type" ) === "GhostNote" ) { return ; } for ( const articulation of articulations ) { let vfArtPosition = Vex . Flow . Modifier . Position . ABOVE ; if ( vfnote . getStemDirection ( ) === Vex . Flow . Stem . UP ) { vfArtPosition = Vex . Flow . Modifier . Position . BELOW ; } let vfArt = undefined ; const articulationEnum = articulation . articulationEnum ; if ( rules . ArticulationPlacementFromXML ) { if ( articulation . placement === PlacementEnum . Above ) { vfArtPosition = Vex . Flow . Modifier . Position . ABOVE ; } else if ( articulation . placement === PlacementEnum . Below ) { vfArtPosition = Vex . Flow . Modifier . Position . BELOW ; } } switch ( articulationEnum ) { case ArticulationEnum . accent : { vfArt = new Vex . Flow . Articulation ( "a>" ) ; break ; } case ArticulationEnum . downbow : { vfArt = new Vex . Flow . Articulation ( "am" ) ; if ( articulation . placement === undefined ) { vfArtPosition = Vex . Flow . Modifier . Position . ABOVE ; } break ; } case ArticulationEnum . fermata : { vfArt = new Vex . Flow . Articulation ( "a@a" ) ; vfArtPosition = Vex . Flow . Modifier . Position . ABOVE ; break ; } case ArticulationEnum . marcatodown : { vfArt = new Vex . Flow . Articulation ( "a|" ) ; break ; } case ArticulationEnum . marcatoup : { vfArt = new Vex . Flow . Articulation ( "a^" ) ; break ; } case ArticulationEnum . invertedfermata : { vfArt = new Vex . Flow . Articulation ( "a@u" ) ; vfArtPosition = Vex . Flow . Modifier . Position . BELOW ; break ; } case ArticulationEnum . lefthandpizzicato : { vfArt = new Vex . Flow . Articulation ( "a+" ) ; break ; } case ArticulationEnum . naturalharmonic : { vfArt = new Vex . Flow . Articulation ( "ah" ) ; break ; } case ArticulationEnum . snappizzicato : { vfArt = new Vex . Flow . Articulation ( "ao" ) ; break ; } case ArticulationEnum . staccatissimo : { vfArt = new Vex . Flow . Articulation ( "av" ) ; break ; } case ArticulationEnum . staccato : { vfArt = new Vex . Flow . Articulation ( "a." ) ; break ; } case ArticulationEnum . tenuto : { vfArt = new Vex . Flow . Articulation ( "a-" ) ; break ; } case ArticulationEnum . upbow : { vfArt = new Vex . Flow . Articulation ( "a|" ) ; if ( articulation . placement === undefined ) { vfArtPosition = Vex . Flow . Modifier . Position . ABOVE ; } break ; } case ArticulationEnum . strongaccent : { vfArt = new Vex . Flow . Articulation ( "a^" ) ; break ; } default : { break ; } } if ( vfArt ) { vfArt . setPosition ( vfArtPosition ) ; ( vfnote as StaveNote ) . addModifier ( 0 , vfArt ) ; } } } public static generateOrnaments ( vfnote , oContainer ) { let vfPosition = Vex . Flow . Modifier . Position . ABOVE ; if ( oContainer . placement === PlacementEnum . Below ) { vfPosition = Vex . Flow . Modifier . Position . BELOW ; } let vfOrna = undefined ; switch ( oContainer . GetOrnament ) { case OrnamentEnum . DelayedInvertedTurn : { vfOrna = new Vex . Flow . Ornament ( "turn_inverted" ) ; vfOrna . setDelayed ( true ) ; break ; } case OrnamentEnum . DelayedTurn : { vfOrna = new Vex . Flow . Ornament ( "turn" ) ; vfOrna . setDelayed ( true ) ; break ; } case OrnamentEnum . InvertedMordent : { vfOrna = new Vex . Flow . Ornament ( "mordent" ) ; vfOrna . setDelayed ( false ) ; break ; } case OrnamentEnum . InvertedTurn : { vfOrna = new Vex . Flow . Ornament ( "turn_inverted" ) ; vfOrna . setDelayed ( false ) ; break ; } case OrnamentEnum . Mordent : { vfOrna = new Vex . Flow . Ornament ( "mordent_inverted" ) ; vfOrna . setDelayed ( false ) ; break ; } case OrnamentEnum . Trill : { vfOrna = new Vex . Flow . Ornament ( "tr" ) ; vfOrna . setDelayed ( false ) ; break ; } case OrnamentEnum . Turn : { vfOrna = new Vex . Flow . Ornament ( "turn" ) ; vfOrna . setDelayed ( false ) ; break ; } default : { log . warn ( "unhandled OrnamentEnum type: " + oContainer . GetOrnament ) ; return ; } } if ( vfOrna ) { if ( oContainer . AccidentalBelow !== AccidentalEnum . NONE ) { vfOrna . setLowerAccidental ( Pitch . accidentalVexflow ( oContainer . AccidentalBelow ) ) ; } if ( oContainer . AccidentalAbove !== AccidentalEnum . NONE ) { vfOrna . setUpperAccidental ( Pitch . accidentalVexflow ( oContainer . AccidentalAbove ) ) ; } vfOrna . setPosition ( vfPosition ) ; ( vfnote as StaveNote ) . addModifier ( 0 , vfOrna ) ; } } public static StrokeTypeFromArpeggioType ( arpeggioType ) { switch ( arpeggioType ) { case ArpeggioType . ARPEGGIO_DIRECTIONLESS : return Vex . Flow . Stroke . Type . ARPEGGIO_DIRECTIONLESS ; case ArpeggioType . BRUSH_DOWN : return Vex . Flow . Stroke . Type . BRUSH_UP ; case ArpeggioType . BRUSH_UP : return Vex . Flow . Stroke . Type . BRUSH_DOWN ; case ArpeggioType . RASQUEDO_DOWN : return Vex . Flow . Stroke . Type . RASQUEDO_UP ; case ArpeggioType . RASQUEDO_UP : return Vex . Flow . Stroke . Type . RASQUEDO_DOWN ; case ArpeggioType . ROLL_DOWN : return Vex . Flow . Stroke . Type . ROLL_UP ; case ArpeggioType . ROLL_UP : return Vex . Flow . Stroke . Type . ROLL_DOWN ; default : return Vex . Flow . Stroke . Type . ARPEGGIO_DIRECTIONLESS ; } } param notes returns { Vex . Flow . StaveNote } public static CreateTabNote ( gve ) { const tabPositions = [ ] ; const notes = gve . notes . reverse ( ) ; const tabPhrases = [ ] ; const frac = gve . notes [ 0 ] . graphicalNoteLength ; const isTuplet = gve . notes [ 0 ] . sourceNote . NoteTuplet !== undefined ; let duration = VexFlowConverter . durations ( frac , isTuplet ) [ 0 ] ; let numDots = 0 ; let tabVibrato = false ; for ( const note of gve . notes ) { const tabNote = note . sourceNote as TabNote ; const tabPosition = { str : tabNote . StringNumberTab , fret : tabNote . FretNumber } ; tabPositions . push ( tabPosition ) ; if ( tabNote . BendArray ) { tabNote . BendArray . forEach ( function ( bend ) : void { let phraseText ; const phraseStep = bend . bendalter - tabPosition . fret ; if ( phraseStep > 1 ) { phraseText = "Full" ; } else if ( phraseStep === 1 ) { phraseText = "1/2" ; } else { phraseText = "1/4" ; } if ( bend . direction === "up" ) { tabPhrases . push ( { type : Vex . Flow . Bend . UP , text : phraseText , width : 10 } ) ; } else { tabPhrases . push ( { type : Vex . Flow . Bend . DOWN , text : phraseText , width : 10 } ) ; } } ) ; } if ( tabNote . VibratoStroke ) { tabVibrato = true ; } if ( numDots < note . numberOfDots ) { numDots = note . numberOfDots ; } } for ( let i = 0 , len = numDots ; i < len ; ++ i ) { duration += "d" ; } const vfnote = new Vex . Flow . TabNote ( { duration : duration , positions : tabPositions , } ) ; for ( let i = 0 , len = notes . length ; i < len ; i += 1 ) { ( notes [ i ] as VexFlowGraphicalNote ) . setIndex ( vfnote , i ) ; } tabPhrases . forEach ( function ( phrase ) : void { if ( phrase . type === Vex . Flow . Bend . UP ) { vfnote . addModifier ( new Vex . Flow . Bend ( phrase . text , false ) ) ; } else { vfnote . addModifier ( new Vex . Flow . Bend ( phrase . text , true ) ) ; } } ) ; if ( tabVibrato ) { vfnote . addModifier ( new Vex . Flow . Vibrato ( ) ) ; } return vfnote ; } param clef param size returns see https see https public static Clef ( clef , size = "default" ) { let type ; let annotation ; if ( size !== "default" && size !== "small" ) { log . warn ( `Invalid VexFlow clef size "${ size }" specified. Using "default".` ) ; size = "default" ; } switch ( clef . ClefType ) { case ClefEnum . G : switch ( clef . Line ) { case 1 : type = "french" ; break ; case 2 : type = "treble" ; break ; default : type = "treble" ; log . error ( `Clef ${ ClefEnum [ clef . ClefType ] } on line ${ clef . Line } not supported by VexFlow. Using default value "${ type }".` ) ; } break ; case ClefEnum . F : switch ( clef . Line ) { case 4 : type = "bass" ; break ; case 3 : type = "baritone-f" ; break ; case 5 : type = "subbass" ; break ; default : type = "bass" ; log . error ( `Clef ${ ClefEnum [ clef . ClefType ] } on line ${ clef . Line } not supported by VexFlow. Using default value "${ type }".` ) ; } break ; case ClefEnum . C : switch ( clef . Line ) { case 3 : type = "alto" ; break ; case 4 : type = "tenor" ; break ; case 1 : type = "soprano" ; break ; case 2 : type = "mezzo-soprano" ; break ; default : type = "alto" ; log . error ( `Clef ${ ClefEnum [ clef . ClefType ] } on line ${ clef . Line } not supported by VexFlow. Using default value "${ type }".` ) ; } break ; case ClefEnum . percussion : type = "percussion" ; break ; case ClefEnum . TAB : type = "treble" ; break ; default : log . info ( "bad clef type: " + clef . ClefType ) ; type = "treble" ; } if ( clef . OctaveOffset === 1 && type !== "bass" ) { annotation = "8va" ; } else if ( clef . OctaveOffset === - 1 ) { annotation = "8vb" ; } return { type , size , annotation } ; } param rhythm returns { Vex . Flow . TimeSignature } constructor public static TimeSignature ( rhythm ) { let timeSpec ; switch ( rhythm . SymbolEnum ) { case RhythmSymbolEnum . NONE : timeSpec = rhythm . Rhythm . Numerator + "/" + rhythm . Rhythm . Denominator ; break ; case RhythmSymbolEnum . COMMON : timeSpec = "C" ; break ; case RhythmSymbolEnum . CUT : timeSpec = "C|" ; break ; default : } return new Vex . Flow . TimeSignature ( timeSpec ) ; } param key returns { string } public static keySignature ( key ) { if ( ! key ) { return undefined ; } let ret ; switch ( key . Mode ) { case KeyEnum . minor : ret = VexFlowConverter . minorMap [ key . Key ] + "m" ; break ; case KeyEnum . major : ret = VexFlowConverter . majorMap [ key . Key ] ; break ; case KeyEnum . none : ret = VexFlowConverter . majorMap [ key . Key ] ; break ; default : ret = "C" ; } return ret ; } param lineType returns { any } public static line ( lineType , linePosition ) { switch ( lineType ) { case SystemLinesEnum . SingleThin : if ( linePosition === SystemLinePosition . MeasureBegin ) { return Vex . Flow . StaveConnector . type . SINGLE ; } return Vex . Flow . StaveConnector . type . SINGLE_RIGHT ; case SystemLinesEnum . DoubleThin : return Vex . Flow . StaveConnector . type . THIN_DOUBLE ; case SystemLinesEnum . ThinBold : return Vex . Flow . StaveConnector . type . BOLD_DOUBLE_RIGHT ; case SystemLinesEnum . BoldThinDots : return Vex . Flow . StaveConnector . type . BOLD_DOUBLE_LEFT ; case SystemLinesEnum . DotsThinBold : return Vex . Flow . StaveConnector . type . BOLD_DOUBLE_RIGHT ; case SystemLinesEnum . DotsBoldBoldDots : return Vex . Flow . StaveConnector . type . BOLD_DOUBLE_RIGHT ; case SystemLinesEnum . None : return Vex . Flow . StaveConnector . type . NONE ; default : } } param fontSize param fontStyle param font returns { string } public static font ( fontSize , fontStyle = FontStyles . Regular , font = Fonts . TimesNewRoman , rules , fontFamily = undefined ) { let style = "normal" ; let weight = "normal" ; let family = `'${ rules . DefaultFontFamily }'` ; switch ( fontStyle ) { case FontStyles . Bold : weight = "bold" ; break ; case FontStyles . Italic : style = "italic" ; break ; case FontStyles . BoldItalic : style = "italic" ; weight = "bold" ; break ; case FontStyles . Underlined : break ; default : break ; } switch ( font ) { case Fonts . Kokila : break ; default : } if ( fontFamily && fontFamily !== "default" ) { family = `'${ fontFamily }'` ; } return style + " " + weight + " " + Math . floor ( fontSize ) + "px " + family ; } /**
     * Converts the style into a string that VexFlow RenderContext can understand
     * as the weight of the font
     */ public static fontStyle ( style ) { switch ( style ) { case FontStyles . Bold : return "bold" ; case FontStyles . Italic : return "italic" ; case FontStyles . BoldItalic : return "italic bold" ; default : return "normal" ; } } param styleId returns { string } public static style ( styleId ) { const ret = OUTLINE_AND_FILL_STYLE_DICT . getValue ( styleId ) ; return ret ; } }