-- CHANGE THESE 2 VALUES IF YOU WANT OTHER VALUES StemLength = 84 -- Stem Length of the first note in EVPUs SmallNoteResize = 70 -- Resize % of small notes function plugindef() -- This function and the 'finaleplugin' namespace -- are both reserved for the plug-in definition. finaleplugin.RequireSelection = true finaleplugin.MinFinaleVersion = "2012" finaleplugin.Author = "Jari Williamsson" finaleplugin.Version = "0.01" finaleplugin.Notes = [[ This script will only process 7-tuplets that appears on staves that has been defined as "Harp" in the Score Manager. ]] finaleplugin.CategoryTags = "Idiomatic, Note, Pluckedstrings, Region, Tuplet, Woodwinds" return "Harp gliss (from 7-tuplet)", "Harp gliss", "Transforms 7-tuplets to harp gliss notation." end -- Sets the beam width to 0 and resizes the stem for the first note (by moving -- the primary beam) -- This is a sub-function to ChangePrimaryBeam() function ChangeBeamInfo(primarybeam, entry) local currentlength = entry:CalcStemLength() primarybeam.Thickness = 0 if entry:CalcStemUp() then primarybeam.LeftVerticalOffset = primarybeam.LeftVerticalOffset + StemLength - currentlength else primarybeam.LeftVerticalOffset = primarybeam.LeftVerticalOffset - StemLength + currentlength end end -- Changes a primary beam for and entry function ChangePrimaryBeam(entry) local primarybeams = finale.FCPrimaryBeamMods(entry) primarybeams:LoadAll() if primarybeams.Count > 0 then -- Modify the existing beam modification record to hide the beam local primarybeam = primarybeams:GetItemAt(0) ChangeBeamInfo(primarybeam, entry) primarybeam:Save() else -- Create a beam modification record and hide the beam local primarybeam = finale.FCBeamMod(false) primarybeam:SetNoteEntry(entry) ChangeBeamInfo(primarybeam, entry) primarybeam:SaveNew() end end -- Assures that the entries that spans the entries are -- considered "valid" for a harp gliss. Rests and too few -- notes in the tuplet are things that aren't ok. -- This is a sub-function to GetMatchingTuplet() function VerifyEntries(entry, tuplet) local entrystaffspec = finale.FCCurrentStaffSpec() entrystaffspec:LoadForEntry(entry) if entrystaffspec.InstrumentUUID ~= finale.FFUUID_HARP then return false end local symbolicduration = 0 local firstentry = entry for i = 0, 6 do if entry == nil then return false end if entry:IsRest() then return false end if entry.Duration >= finale.QUARTER_NOTE then return false end if entry.Staff ~= firstentry.Staff then return false end if entry.Layer ~= firstentry.Layer then return false end if entry:CalcDots() > 0 then return false end symbolicduration = symbolicduration + entry.Duration entry = entry:Next() end return (symbolicduration == tuplet:CalcFullSymbolicDuration()) end -- If a "valid" harp tuplet is found for an entry, this method returns it. function GetMatchingTuplet(entry) local tuplets = entry:CreateTuplets() for t in each(tuplets) do if t.SymbolicNumber == 7 and VerifyEntries(entry, t) then return t end end return nil end -- Hides a tuplet (both by visibility and appearance) function HideTuplet(t) t.ShapeStyle = finale.TUPLETSHAPE_NONE t.NumberStyle = finale.TUPLETNUMBER_NONE t.Visible = false t:Save() end -- Hide stems for the small notes in the gliss. If the "full" note has a long -- enough duration to not have a stem, the first entry also gets a hidden stem. function HideStems(entry, tuplet) local hidefirstentry = (tuplet:CalcFullReferenceDuration() >= finale.WHOLE_NOTE) for i = 0, 6 do if i > 0 or hidefirstentry then local stem = finale.FCCustomStemMod() stem:SetNoteEntry(entry) stem:UseUpStemData(entry:CalcStemUp()) if stem:LoadFirst() then stem.ShapeID = 0 stem:Save() else stem.ShapeID = 0 stem:SaveNew() end end entry = entry:Next() end end -- Change the notehead shapes and notehead sizes function SetNoteheads(entry, tuplet) for i = 0, 6 do for chordnote in each(entry) do local notehead = finale.FCNoteheadMod() if i == 0 then local fullrefdur = tuplet:CalcFullReferenceDuration() if fullrefdur >= finale.WHOLE_NOTE then notehead.CustomChar = 119 -- Whole note character elseif fullrefdur >= finale.HALF_NOTE then notehead.CustomChar = 250 -- Half note character end else notehead.Resize = SmallNoteResize end notehead:SaveAt(chordnote) end entry = entry:Next() end end -- If the tuplet spans a duration that is dotted, modify the -- rhythm at the beginning of the tuplet function ChangeDottedFirstEntry(entry, tuplet) local refdur = tuplet:CalcFullReferenceDuration() local tupletdots = finale.FCNoteEntry.CalcDotsForDuration(refdur) local entrydots = entry:CalcDots() if tupletdots == 0 then return end if tupletdots > 3 then return end -- Don't support too complicated gliss rhythm values if entrydots > 0 then return end -- Create dotted rhythm local nextentry = entry:Next() local nextduration = nextentry.Duration / 2 for i = 1, tupletdots do entry.Duration = entry.Duration + nextduration nextentry.Duration = nextentry.Duration - nextduration nextduration = nextduration / 2 end end -- *** THE SCRIPT EXECUTION STARTS HERE *** -- Make sure the harp tuplets are beamed for entry in eachentrysaved(finenv.Region()) do local harptuplet = GetMatchingTuplet(entry) if harptuplet then harp_tuplets_exist = true for i = 1, 6 do entry = entry:Next() entry.BeamBeat = false end end end if harp_tuplets_exist == nil then return end -- Since the entries might change direction when they are beamed, -- tell Finale to update the entry metric data info finale.FCNoteEntry.MarkEntryMetricsForUpdate() -- Change the harp tuplets for entry in eachentrysaved(finenv.Region()) do local harptuplet = GetMatchingTuplet(entry) if harptuplet then ChangeDottedFirstEntry(entry, harptuplet) ChangePrimaryBeam(entry) HideTuplet(harptuplet) HideStems(entry, harptuplet) SetNoteheads(entry, harptuplet) end end