forked from finale-lua/lua-scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnote_harp_gliss.lua
212 lines (195 loc) · 7.02 KB
/
note_harp_gliss.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
function plugindef()
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, Plucked Strings, Region, Tuplet, Woodwinds"
return "Harp gliss", "Harp gliss", "Transforms 7-tuplets to harp gliss notation."
end
local configuration = require("library.configuration")
local config = {
stem_length = 84, -- Stem Length of the first note in EVPUs
small_note_size = 70, -- Resize % of small notes
}
configuration.get_parameters("harp_gliss.config.txt", config)
-- 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 change_beam_info(primary_beam, entry)
local current_length = entry:CalcStemLength()
primary_beam.Thickness = 0
if entry:CalcStemUp() then
primary_beam.LeftVerticalOffset = primary_beam.LeftVerticalOffset + config.stem_length - current_length
else
primary_beam.LeftVerticalOffset = primary_beam.LeftVerticalOffset - config.stem_length + current_length
end
end
-- Changes a primary beam for and entry
function change_primary_beam(entry)
local primary_beams = finale.FCPrimaryBeamMods(entry)
primary_beams:LoadAll()
if primary_beams.Count > 0 then
-- Modify the existing beam modification record to hide the beam
local primary_beam = primary_beams:GetItemAt(0)
change_beam_info(primary_beam, entry)
primary_beam:Save()
else
-- Create a beam modification record and hide the beam
local primary_beam = finale.FCBeamMod(false)
primary_beam:SetNoteEntry(entry)
change_beam_info(primary_beam, entry)
primary_beam: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 verify_entries(entry, tuplet)
local entry_staff_spec = finale.FCCurrentStaffSpec()
entry_staff_spec:LoadForEntry(entry)
if entry_staff_spec.InstrumentUUID ~= finale.FFUUID_HARP then
return false
end
local symbolic_duration = 0
local first_entry = entry
for _ = 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 ~= first_entry.Staff then
return false
end
if entry.Layer ~= first_entry.Layer then
return false
end
if entry:CalcDots() > 0 then
return false
end
symbolic_duration = symbolic_duration + entry.Duration
entry = entry:Next()
end
return (symbolic_duration == tuplet:CalcFullSymbolicDuration())
end
-- If a "valid" harp tuplet is found for an entry, this method returns it.
function get_matching_tuplet(entry)
local tuplets = entry:CreateTuplets()
for tuplet in each(tuplets) do
if tuplet.SymbolicNumber == 7 and verify_entries(entry, tuplet) then
return tuplet
end
end
return nil
end
-- Hides a tuplet (both by visibility and appearance)
function hide_tuplet(tuplet)
tuplet.ShapeStyle = finale.TUPLETSHAPE_NONE
tuplet.NumberStyle = finale.TUPLETNUMBER_NONE
tuplet.Visible = false
tuplet: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 hide_stems(entry, tuplet)
local hide_first_entry = (tuplet:CalcFullReferenceDuration() >= finale.WHOLE_NOTE)
for i = 0, 6 do
if i > 0 or hide_first_entry 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 set_noteheads(entry, tuplet)
for i = 0, 6 do
for chord_note in each(entry) do
local notehead = finale.FCNoteheadMod()
if i == 0 then
local reference_duration = tuplet:CalcFullReferenceDuration()
if reference_duration >= finale.WHOLE_NOTE then
notehead.CustomChar = 119 -- Whole note character
elseif reference_duration >= finale.HALF_NOTE then
notehead.CustomChar = 250 -- Half note character
end
else
notehead.Resize = config.small_note_size
end
notehead:SaveAt(chord_note)
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 change_dotted_first_entry(entry, tuplet)
local reference_duration = tuplet:CalcFullReferenceDuration()
local tuplet_dots = finale.FCNoteEntry.CalcDotsForDuration(reference_duration)
local entry_dots = entry:CalcDots()
if tuplet_dots == 0 then
return
end
if tuplet_dots > 3 then
return
end -- Don't support too complicated gliss rhythm values
if entry_dots > 0 then
return
end
-- Create dotted rhythm
local next_entry = entry:Next()
local next_duration = next_entry.Duration / 2
for _ = 1, tuplet_dots do
entry.Duration = entry.Duration + next_duration
next_entry.Duration = next_entry.Duration - next_duration
next_duration = next_duration / 2
end
end
function harp_gliss()
-- Make sure the harp tuplets are beamed
local harp_tuplets_exist = false
for entry in eachentrysaved(finenv.Region()) do
local harp_tuplet = get_matching_tuplet(entry)
if harp_tuplet then
harp_tuplets_exist = true
for _ = 1, 6 do
entry = entry:Next()
entry.BeamBeat = false
end
end
end
if not harp_tuplets_exist 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 harp_tuplet = get_matching_tuplet(entry)
if harp_tuplet then
change_dotted_first_entry(entry, harp_tuplet)
change_primary_beam(entry)
hide_tuplet(harp_tuplet)
hide_stems(entry, harp_tuplet)
set_noteheads(entry, harp_tuplet)
end
end
end
harp_gliss()