Table of Contents

Using JW Lua - Create Harp Glissando

If you have never used JW Lua to run scripts before, this is a good page to start. At the bottom of the page is a full script that will automatically create a harp gliss from a 7-tuplet that you might want to test (the script works on Finale 2012 and later versions).

This wiki page is based on beta version 0.07 of JW Lua, but it should hopefully work with any later version as well.

Step 1 - Download and Install JW Lua

The beta versions of JW Lua are available for download at this page: http://finaletips.nu/index.php?option=com_phocadownload&view=category&id=28:beta-version&Itemid=2

Install the plug-in as any other third party Finale plug-in. The Windows version contains a DLL file as well, which must be put in the same location as the plug-in .fxt file.

Step 2 - Start JW Lua

Once the JW Lua plug-in has been installed and Finale has been restarted, select JW Lua… in Finale's Plug-ins menu.

Step 3 - Create a script group

To organize the scripts into a workflow, a script need to be put in a group.

  1. Select the Manager page
  2. Click the New… button to the top right, which will open the Edit Plug-in Group dialog box.
  3. Enter a Group Name (such as “Harp Editing”, “Plucked Strings”, “Note Editing”, “Client X”, etc) where you want to put your script.
  4. Enter a Description with a text that is a more detailed description of what the group will contain.
  5. Leave everything else as it is and press the OK button.

Step 4 - Add the script to the group

Download the harpgliss.lua file below, if you haven't done so already. Make sure to store the JW Lua scripts at a good location on your computer. These scripts can be put anywhere on the hard drive, they don't need to be related to the Finale installation.

To add the script to the group:

  1. Make sure that the group is selected in the top list on the Manager page.
  2. Press the New… button next to the bottom list.
  3. In the dialog box that appears, locate the script on your computer and select it to add to the group.

When you exit Finale, the changes made on the Manager page will be saved.

Step 5 - Refresh the plug-in list

Select the Explorer page and press the Refresh All button. The group should now appear with the script inside.

Step 6 - Run

On the Explorer page, open your group container and select the script. Press the Run button.

The Harp Glissando script

The harp glissado script will transform 7-tuplets with seven undotted notes (of a “flagged” note duration) in the selected region into graphical harp glissando start note that spans the duration of the tuplet.

The script will only modify staves that are defined a Harp in Finale's Score Manager - so if a 7-tuplet is for example found on a violin staff, nothing will be processed. It will also handle situations such as when the tuplet duration spans a half note or more. The original notes in the tuplet doesn't need to be beamed.

Note that at the very start of the script are 2 values (StemLength and SmallNoteResize) that you might want to modify. To do that, select the Development page and open/edit/save the file there.

(Click on the harpgliss.lua text to download the script.)

harpgliss.lua
-- 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