Skip to content

Commit 5cbd049

Browse files
chore: autopublish 2024-09-22T12:33:20Z
1 parent 52e3f72 commit 5cbd049

File tree

4 files changed

+730
-6
lines changed

4 files changed

+730
-6
lines changed

dist/articulation_reset_auto_positioning.lua

Lines changed: 363 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,365 @@
1+
package.preload["library.note_entry"] = package.preload["library.note_entry"] or function()
2+
3+
local note_entry = {}
4+
5+
function note_entry.get_music_region(entry)
6+
local exp_region = finale.FCMusicRegion()
7+
exp_region:SetCurrentSelection()
8+
exp_region.StartStaff = entry.Staff
9+
exp_region.EndStaff = entry.Staff
10+
exp_region.StartMeasure = entry.Measure
11+
exp_region.EndMeasure = entry.Measure
12+
exp_region.StartMeasurePos = entry.MeasurePos
13+
exp_region.EndMeasurePos = entry.MeasurePos
14+
return exp_region
15+
end
16+
17+
18+
local use_or_get_passed_in_entry_metrics = function(entry, entry_metrics)
19+
if entry_metrics then
20+
return entry_metrics, false
21+
end
22+
entry_metrics = finale.FCEntryMetrics()
23+
if entry_metrics:Load(entry) then
24+
return entry_metrics, true
25+
end
26+
return nil, false
27+
end
28+
29+
function note_entry.get_evpu_notehead_height(entry)
30+
local highest_note = entry:CalcHighestNote(nil)
31+
local lowest_note = entry:CalcLowestNote(nil)
32+
local evpu_height = (2 + highest_note:CalcStaffPosition() - lowest_note:CalcStaffPosition()) * 12
33+
return evpu_height
34+
end
35+
36+
function note_entry.get_top_note_position(entry, entry_metrics)
37+
local retval = -math.huge
38+
local loaded_here
39+
entry_metrics, loaded_here = use_or_get_passed_in_entry_metrics(entry, entry_metrics)
40+
if nil == entry_metrics then
41+
return retval
42+
end
43+
if not entry:CalcStemUp() then
44+
retval = entry_metrics.TopPosition
45+
else
46+
local cell_metrics = finale.FCCell(entry.Measure, entry.Staff):CreateCellMetrics()
47+
if nil ~= cell_metrics then
48+
local evpu_height = note_entry.get_evpu_notehead_height(entry)
49+
local scaled_height = math.floor(((cell_metrics.StaffScaling * evpu_height) / 10000) + 0.5)
50+
retval = entry_metrics.BottomPosition + scaled_height
51+
cell_metrics:FreeMetrics()
52+
end
53+
end
54+
if loaded_here then
55+
entry_metrics:FreeMetrics()
56+
end
57+
return retval
58+
end
59+
60+
function note_entry.get_bottom_note_position(entry, entry_metrics)
61+
local retval = math.huge
62+
local loaded_here
63+
entry_metrics, loaded_here = use_or_get_passed_in_entry_metrics(entry, entry_metrics)
64+
if nil == entry_metrics then
65+
return retval
66+
end
67+
if entry:CalcStemUp() then
68+
retval = entry_metrics.BottomPosition
69+
else
70+
local cell_metrics = finale.FCCell(entry.Measure, entry.Staff):CreateCellMetrics()
71+
if nil ~= cell_metrics then
72+
local evpu_height = note_entry.get_evpu_notehead_height(entry)
73+
local scaled_height = math.floor(((cell_metrics.StaffScaling * evpu_height) / 10000) + 0.5)
74+
retval = entry_metrics.TopPosition - scaled_height
75+
cell_metrics:FreeMetrics()
76+
end
77+
end
78+
if loaded_here then
79+
entry_metrics:FreeMetrics()
80+
end
81+
return retval
82+
end
83+
84+
function note_entry.calc_widths(entry)
85+
local left_width = 0
86+
local right_width = 0
87+
for note in each(entry) do
88+
local note_width = note:CalcNoteheadWidth()
89+
if note_width > 0 then
90+
if note:CalcRightsidePlacement() then
91+
if note_width > right_width then
92+
right_width = note_width
93+
end
94+
else
95+
if note_width > left_width then
96+
left_width = note_width
97+
end
98+
end
99+
end
100+
end
101+
return left_width, right_width
102+
end
103+
104+
105+
106+
107+
function note_entry.calc_left_of_all_noteheads(entry)
108+
if entry:CalcStemUp() then
109+
return 0
110+
end
111+
local left, _ = note_entry.calc_widths(entry)
112+
return -left
113+
end
114+
115+
function note_entry.calc_left_of_primary_notehead(_entry)
116+
return 0
117+
end
118+
119+
function note_entry.calc_center_of_all_noteheads(entry)
120+
local left, right = note_entry.calc_widths(entry)
121+
local width_centered = (left + right) / 2
122+
if not entry:CalcStemUp() then
123+
width_centered = width_centered - left
124+
end
125+
return width_centered
126+
end
127+
128+
function note_entry.calc_center_of_primary_notehead(entry)
129+
local left, right = note_entry.calc_widths(entry)
130+
if entry:CalcStemUp() then
131+
return left / 2
132+
end
133+
return right / 2
134+
end
135+
136+
function note_entry.calc_stem_offset(entry)
137+
if not entry:CalcStemUp() then
138+
return 0
139+
end
140+
local left, _ = note_entry.calc_widths(entry)
141+
return left
142+
end
143+
144+
function note_entry.calc_right_of_all_noteheads(entry)
145+
local left, right = note_entry.calc_widths(entry)
146+
if entry:CalcStemUp() then
147+
return left + right
148+
end
149+
return right
150+
end
151+
152+
function note_entry.calc_note_at_index(entry, note_index)
153+
local x = 0
154+
for note in each(entry) do
155+
if x == note_index then
156+
return note
157+
end
158+
x = x + 1
159+
end
160+
return nil
161+
end
162+
163+
function note_entry.stem_sign(entry)
164+
if entry:CalcStemUp() then
165+
return 1
166+
end
167+
return -1
168+
end
169+
170+
function note_entry.duplicate_note(note)
171+
local new_note = note.Entry:AddNewNote()
172+
if nil ~= new_note then
173+
new_note.Displacement = note.Displacement
174+
new_note.RaiseLower = note.RaiseLower
175+
new_note.Tie = note.Tie
176+
new_note.TieBackwards = note.TieBackwards
177+
end
178+
return new_note
179+
end
180+
181+
function note_entry.delete_note(note)
182+
local entry = note.Entry
183+
if nil == entry then
184+
return false
185+
end
186+
187+
finale.FCAccidentalMod():EraseAt(note)
188+
finale.FCCrossStaffMod():EraseAt(note)
189+
finale.FCDotMod():EraseAt(note)
190+
finale.FCNoteheadMod():EraseAt(note)
191+
finale.FCPercussionNoteMod():EraseAt(note)
192+
finale.FCTablatureNoteMod():EraseAt(note)
193+
finale.FCPerformanceMod():EraseAt(note)
194+
if finale.FCTieMod then
195+
finale.FCTieMod(finale.TIEMODTYPE_TIESTART):EraseAt(note)
196+
finale.FCTieMod(finale.TIEMODTYPE_TIEEND):EraseAt(note)
197+
end
198+
return entry:DeleteNote(note)
199+
end
200+
201+
function note_entry.make_rest(entry)
202+
local articulations = entry:CreateArticulations()
203+
for articulation in each(articulations) do
204+
articulation:DeleteData()
205+
end
206+
if entry:IsNote() then
207+
while entry.Count > 0 do
208+
note_entry.delete_note(entry:GetItemAt(0))
209+
end
210+
end
211+
entry:MakeRest()
212+
return true
213+
end
214+
215+
function note_entry.calc_pitch_string(note)
216+
local pitch_string = finale.FCString()
217+
local cell = finale.FCCell(note.Entry.Measure, note.Entry.Staff)
218+
local key_signature = cell:GetKeySignature()
219+
note:GetString(pitch_string, key_signature, false, false)
220+
return pitch_string
221+
end
222+
223+
function note_entry.calc_spans_number_of_octaves(entry)
224+
local top_note = entry:CalcHighestNote(nil)
225+
local bottom_note = entry:CalcLowestNote(nil)
226+
local displacement_diff = top_note.Displacement - bottom_note.Displacement
227+
local num_octaves = math.ceil(displacement_diff / 7)
228+
return num_octaves
229+
end
230+
231+
function note_entry.add_augmentation_dot(entry)
232+
233+
entry.Duration = bit32.bor(entry.Duration, bit32.rshift(entry.Duration, 1))
234+
end
235+
236+
function note_entry.remove_augmentation_dot(entry)
237+
if entry.Duration <= 0 then
238+
return false
239+
end
240+
local lowest_order_bit = 1
241+
if bit32.band(entry.Duration, lowest_order_bit) == 0 then
242+
243+
lowest_order_bit = bit32.bxor(bit32.band(entry.Duration, entry.Duration - 1), entry.Duration)
244+
end
245+
246+
local new_value = bit32.band(entry.Duration, bit32.bnot(lowest_order_bit))
247+
if new_value ~= 0 then
248+
entry.Duration = new_value
249+
return true
250+
end
251+
return false
252+
end
253+
254+
function note_entry.get_next_same_v(entry)
255+
if entry.NextSameVInFrame then
256+
return entry:NextSameVInFrame()
257+
end
258+
local next_entry = entry:Next()
259+
if entry.Voice2 then
260+
if (nil ~= next_entry) and next_entry.Voice2 then
261+
return next_entry
262+
end
263+
return nil
264+
end
265+
if entry.Voice2Launch then
266+
while (nil ~= next_entry) and next_entry.Voice2 do
267+
next_entry = next_entry:Next()
268+
end
269+
end
270+
return next_entry
271+
end
272+
273+
function note_entry.hide_stem(entry)
274+
local stem = finale.FCCustomStemMod()
275+
stem:SetNoteEntry(entry)
276+
stem:UseUpStemData(entry:CalcStemUp())
277+
if stem:LoadFirst() then
278+
stem.ShapeID = 0
279+
stem:Save()
280+
else
281+
stem.ShapeID = 0
282+
stem:SaveNew()
283+
end
284+
end
285+
286+
function note_entry.rest_offset(entry, offset)
287+
if entry:IsNote() then
288+
return false
289+
end
290+
local rest_prop = "OtherRestPosition"
291+
if entry.Duration >= finale.BREVE then
292+
rest_prop = "DoubleWholeRestPosition"
293+
elseif entry.Duration >= finale.WHOLE_NOTE then
294+
rest_prop = "WholeRestPosition"
295+
elseif entry.Duration >= finale.HALF_NOTE then
296+
rest_prop = "HalfRestPosition"
297+
end
298+
entry:MakeMovableRest()
299+
local rest = entry:GetItemAt(0)
300+
local curr_staffpos = rest:CalcStaffPosition()
301+
local staff_spec = finale.FCCurrentStaffSpec()
302+
staff_spec:LoadForEntry(entry)
303+
local total_offset = staff_spec[rest_prop] + offset - curr_staffpos
304+
entry:SetRestDisplacement(entry:GetRestDisplacement() + total_offset)
305+
return true
306+
end
307+
return note_entry
308+
end
309+
package.preload["library.articulation"] = package.preload["library.articulation"] or function()
310+
311+
local articulation = {}
312+
local note_entry = require("library.note_entry")
313+
314+
function articulation.delete_from_entry_by_char_num(entry, char_num)
315+
local artics = entry:CreateArticulations()
316+
for a in eachbackwards(artics) do
317+
local defs = a:CreateArticulationDef()
318+
if defs:GetAboveSymbolChar() == char_num then
319+
a:DeleteData()
320+
end
321+
end
322+
end
323+
324+
function articulation.is_note_side(artic, curr_pos)
325+
if nil == curr_pos then
326+
curr_pos = finale.FCPoint(0, 0)
327+
if not artic:CalcMetricPos(curr_pos) then
328+
return false
329+
end
330+
end
331+
local entry = artic:GetNoteEntry()
332+
local cell_metrics = finale.FCCell(entry.Measure, entry.Staff):CreateCellMetrics()
333+
if nil == cell_metrics then
334+
return false
335+
end
336+
if entry:CalcStemUp() then
337+
local bot_pos = note_entry.get_bottom_note_position(entry)
338+
bot_pos = math.floor(((10000 * bot_pos) / cell_metrics.StaffScaling) + 0.5)
339+
return curr_pos.Y <= bot_pos
340+
else
341+
local top_pos = note_entry.get_top_note_position(entry)
342+
top_pos = math.floor(((10000 * top_pos) / cell_metrics.StaffScaling) + 0.5)
343+
return curr_pos.Y >= top_pos
344+
end
345+
end
346+
347+
function articulation.calc_main_character_dimensions(artic_def)
348+
local text_mets = finale.FCTextMetrics()
349+
if not text_mets:LoadArticulation(artic_def, false, 100) then
350+
return 0, 0
351+
end
352+
return text_mets:CalcWidthEVPUs(), text_mets:CalcHeightEVPUs()
353+
end
354+
355+
function articulation.reset_to_default(artic, artic_def)
356+
artic_def = artic_def or artic:CreateArticulationDef()
357+
artic.StackingMode = finale.ARTICSTACKING_USEDEFINITION
358+
artic.PlacementMode = finale.ARTICPLACEMENT_AUTOMATIC
359+
artic:ResetPos(artic_def)
360+
end
361+
return articulation
362+
end
1363
function plugindef()
2364
finaleplugin.Author = "Robert Patterson"
3365
finaleplugin.Copyright = "CC0 https://creativecommons.org/publicdomain/zero/1.0/"
@@ -26,7 +388,7 @@ logic to manage the stacking context.
26388
return "Reset Automatic Articulation Positions", "Reset Automatic Articulation Positions",
27389
"Resets the position of automatically positioned articulations while ignoring those with manual positioning."
28390
end
29-
local articulation = require("library/articulation")
391+
local articulation = require("library.articulation")
30392
function articulation_reset_auto_positioning()
31393
for note_entry in eachentry(finenv.Region()) do
32394
local articulations = note_entry:CreateArticulations()

0 commit comments

Comments
 (0)