Skip to content

Commit 76ca1df

Browse files
authored
Merge pull request #752 from cv-on-hub/cv_cue_notes_overlay
Update cue_notes_overlay.lua
2 parents 3026cff + 12d1f4a commit 76ca1df

File tree

1 file changed

+100
-67
lines changed

1 file changed

+100
-67
lines changed

src/cue_notes_overlay.lua

Lines changed: 100 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ function plugindef()
33
finaleplugin.Author = "Carl Vine"
44
finaleplugin.AuthorURL = "https://carlvine.com/lua/"
55
finaleplugin.Copyright = "https://creativecommons.org/licenses/by/4.0/"
6-
finaleplugin.Version = "0.28"
7-
finaleplugin.Date = "2024/02/07"
6+
finaleplugin.Version = "0.32"
7+
finaleplugin.Date = "2024/07/12"
88
finaleplugin.MinJWLuaVersion = 0.70
99
finaleplugin.Notes = [[
1010
This script takes music from a nominated layer in the selected staff
@@ -14,48 +14,49 @@ function plugindef()
1414
If the destination measure is empty a whole-measure rest
1515
will be created as a reminder that the cue isn't played.
1616
17-
Cue notes are often shown in a different octave to accommodate
18-
the clef and transposition of the destination.
19-
Use _Cue Octave Offset_ setting for this.
17+
Use __Cue Octave Offset__ to change the register of a cue to
18+
suit the clef and transposition of the destination.
2019
Cues can interact visually with "played" material in countless ways
2120
so settings probably need to change between scenarios.
2221
2322
The cue copy is reduced in size and muted, and can optionally duplicate
2423
articulations, expressions, lyrics and smart shapes.
25-
"Note-based" smart shapes are copied, typically slurs and glissandos,
24+
__Note-based__ smart shapes are copied, typically slurs and glissandos,
2625
because they actually "attach" to the cued notes.
2726
28-
This script stores cue names in a text expression category called _Cue Names_
29-
which will be created automatically if needed.
27+
This script stores cue names in a text expression category called
28+
__Cue Names__ which will be created automatically if needed.
3029
Once created you can adjust its text and position parameters
3130
like any other expression category.
3231
3332
Rests in the cue will be offset by the value you have set
34-
for layer 1 at _Document_ _Document Options_ _Layers_.
35-
They will automatically offset in the same direction as
33+
for layer 1 at _Document_ → _Document Options_ → _Layers_.
34+
They will automatically be offset in the same direction as
3635
the nominated cue stem direction.
3736
3837
> __Command Keys__
39-
> In the _Destination Staff_ window, hit the tab key to move the cursor
40-
> into a numeric field and these key commands become available:
41-
42-
> - __q__ - show these script notes
43-
> - __w__ - flip [copy articulations]
44-
> - __e__ - flip [copy expressions]
45-
> - __r__ - flip [copy smartshapes]
46-
> - __t__ - flip [copy lyrics]
47-
> - __y__ - flip [mute cuenotes]
48-
> - __a__ - check all options
49-
> - __s__ - check no options
50-
> - __d__ - select all staves
51-
> - __f__ - select no staves
52-
> - __g__ - select empty staves
53-
> - __z (-)__ - octave -1
54-
> - __x (+)__ - octave +1
55-
> - __c__ - flip stem direction
56-
> - __v__ - flip [destination stems opposite]
38+
> In the __Destination Staff__ window, highlight one of the
39+
> numeric fields and these key commands become available:
40+
41+
> - __q__: show script info
42+
> - __w__: toggle [copy articulations]
43+
> - __e__: toggle [copy expressions]
44+
> - __r__: toggle [copy smartshapes]
45+
> - __t__: toggle [copy lyrics]
46+
> - __y__: toggle [mute cuenotes]
47+
> - __a__: check all options
48+
> - __s__: check no options
49+
> - __d__: select all staves
50+
> - __f__: select no staves
51+
> - __g__: select empty staves
52+
> - __z (-)__: octave -1
53+
> - __x (+)__: octave +1
54+
> - __c__: toggle stem direction
55+
> - __v__: toggle [destination stems opposite]
5756
]]
58-
return "Cue Notes Overlay...", "Cue Notes Overlay", "Copy as cue notes to another staff"
57+
return "Cue Notes Overlay...",
58+
"Cue Notes Overlay",
59+
"Copy as cue notes to another staff"
5960
end
6061

6162
local config = { -- retained and over-written by the user's "settings" file
@@ -64,24 +65,46 @@ local config = { -- retained and over-written by the user's "settings" file
6465
copy_smartshapes = true,
6566
copy_lyrics = false,
6667
mute_cuenotes = true,
67-
cuenote_percent = 70, -- (75% too big, 66% too small)
68-
source_layer = 1, -- layer the cue comes from
69-
cuenote_layer = 4, -- layer the cue ends up
70-
stem_direction = 0, -- "0" up, "1" down
68+
cuenote_percent = 70, -- (75% too big, 66% too small)
69+
source_layer = 1, -- layer the cue comes from
70+
cuenote_layer = 4, -- layer the cue ends up
71+
stem_direction = 0, -- "0" up, "1" down
7172
stems_oppose = true, -- destination stem direction opposite to cue stem
72-
octave_offset = 0, -- octave displacement (-5 to +5) of copied cue version
73+
octave_offset = 0, -- octave displacement (-5 to +5) of copied cue version
7374
abbreviate = true, -- abbreviate staff names when creating new titles
7475
cuename_item = 0, -- ItemNo of the last selected cue_name expression
7576
overwrite_layer = 4, -- overriden by user
7677
-- not user accessible:
77-
shift_expression_down = -24 * 9, -- when cue_name is below staff
78-
shift_expression_left = -24, -- EVPUs; cue names generally need to be LEFT of music start
78+
shift_exp_up = 24, -- cue_name above staff
79+
shift_exp_down = -24 * 9, -- cue_name below staff
80+
shift_exp_left = -24, -- EVPUs; cue names generally need to be LEFT of music start
7981
-- if creating a new "Cue Names" category ...
8082
cue_category_name = "Cue Names",
8183
cue_font_smaller = 1, -- how many points smaller than the standard technique expression
8284
window_pos_x = false,
8385
window_pos_y = false,
8486
}
87+
local hotkey = { -- customise
88+
show_info = "q",
89+
copy_articulations = "w",
90+
copy_expressions = "e",
91+
copy_smartshapes = "r",
92+
copy_lyrics = "t",
93+
mute_cuenotes = "y",
94+
--
95+
set_all = "a",
96+
clear_all = "s",
97+
all_staves = "d",
98+
no_staves = "f",
99+
empty_staves = "g",
100+
--
101+
octave_dn1 = "z",
102+
octave_dn2 = "-",
103+
octave_up1 = "x",
104+
octave_up2 = "+",
105+
stem_direction = "c",
106+
stems_oppose = "v",
107+
}
85108
local options = {
86109
check = { "copy_articulations", "copy_expressions", "copy_smartshapes", "copy_lyrics", "mute_cuenotes" },
87110
integer = { "cuenote_percent", "source_layer", "cuenote_layer" }, -- integer edit boxes
@@ -149,11 +172,10 @@ end
149172
local function get_staff_name(staff_num)
150173
local staff = finale.FCStaff() -- copy the source Staff Name
151174
staff:Load(staff_num)
152-
local str = staff:CreateDisplayFullNameString()
153-
local name = { full = str.LuaString }
154-
str = staff:CreateDisplayAbbreviatedNameString()
155-
name.abbrev = str.LuaString
156-
return name
175+
return {
176+
full = staff:CreateDisplayFullNameString().LuaString,
177+
abbrev = staff:CreateDisplayAbbreviatedNameString().LuaString
178+
}
157179
end
158180

159181
local function new_cue_name(source_staff)
@@ -187,7 +209,7 @@ local function choose_name_index(name_list, source_staff)
187209
dialog:CreateStatic(0, 17):SetText("Select cue name:"):SetWidth(100)
188210
make_info_button(dialog, 180, 17)
189211
local staff_list = dialog:CreateListBox(0, 40):SetWidth(200)
190-
:AddString("*** new name ***") -- menu item [0] is "*** new name ***"
212+
:AddString("*** new cue name ***") -- menu item [0] is "*** new name ***"
191213
for i, v in ipairs(name_list) do -- add all names in the extant list
192214
staff_list:AddString(v[1])
193215
if v[2] == config.cuename_item then staff_list:SetSelectedItem(i) end
@@ -224,12 +246,12 @@ local function create_new_expression(exp_name, category_number)
224246
end
225247

226248
local function choose_destination_staff(source_staff)
227-
local source_name
228249
local rgn = finale.FCMusicRegion()
229250
rgn:SetCurrentSelection()
230251
rgn:SetFullMeasureStack() -- scan the whole stack
231252

232253
-- assemble selected staves
254+
local source_name
233255
local staff_list = {} -- staff number; name
234256
for staff_number in eachstaff(rgn) do
235257
local name = get_staff_name(staff_number)
@@ -306,21 +328,21 @@ local function choose_destination_staff(source_staff)
306328
or s:find("[^0-9]")
307329
)
308330
) then
309-
if s:find("[q?]") then info_dialog()
310-
elseif s:find("w") then flip_check("copy_articulations")
311-
elseif s:find("e") then flip_check("copy_expressions")
312-
elseif s:find("r") then flip_check("copy_smartshapes")
313-
elseif s:find("t") then flip_check("copy_lyrics")
314-
elseif s:find("y") then flip_check("mute_cuenotes")
315-
elseif s:find("a") then set_check_state(1) -- check all
316-
elseif s:find("s") then set_check_state(0) -- check none
317-
elseif s:find("d") then set_list_state(1) -- all staves
318-
elseif s:find("f") then set_list_state(0) -- no staves
319-
elseif s:find("g") then set_list_state(-1) -- empty staves
320-
elseif s:find("[-z_]") then octave_change(1) -- octave - 1
321-
elseif s:find("[+x=]") then octave_change(-1) -- octave + 1
322-
elseif s:find("c") then flip_direction() -- up/down stem
323-
elseif s:find("v") then flip_check("stems_oppose")
331+
if s:find(hotkey.show_info) then info_dialog()
332+
elseif s:find(hotkey.mute_cuenotes) then flip_check("mute_cuenotes")
333+
elseif s:find(hotkey.set_all) then set_check_state(1)
334+
elseif s:find(hotkey.clear_all) then set_check_state(0)
335+
elseif s:find(hotkey.all_staves) then set_list_state(1)
336+
elseif s:find(hotkey.no_staves) then set_list_state(0)
337+
elseif s:find(hotkey.empty_staves) then set_list_state(-1) -- empty staves
338+
elseif s:find(hotkey.octave_dn1) or s:find(hotkey.octave_dn2) then octave_change(1)
339+
elseif s:find(hotkey.octave_up1) or s:find(hotkey.octave_up2) then octave_change(-1)
340+
elseif s:find(hotkey.stem_direction) then flip_direction() -- up/down stem
341+
elseif s:find(hotkey.stems_oppose) then flip_check("stems_oppose")
342+
else
343+
for _, v in ipairs(options.check) do
344+
if s:find(hotkey[v]) then flip_check(v) break end
345+
end
324346
end
325347
ctl:SetText(saved[name]):SetKeyboardFocus()
326348
elseif s ~= "" then
@@ -425,12 +447,11 @@ local function choose_overwrite_layer(staff_name, empty_layers)
425447
dialog:CreateStatic(0, 55):SetText("Please confirm:"):SetWidth(100)
426448
local list = dialog:CreateListBox(0, 75):SetWidth(wide):SetHeight(70)
427449
for i = 1, layer.max_layers() do
428-
local si = tostring(i)
429450
if i == config.cuenote_layer then
430-
list:AddString("overwrite CUENOTE layer " .. si)
451+
list:AddString("overwrite CUENOTE layer " .. i)
431452
else
432453
msg = empty_layers[i] and "use empty layer " or "overwrite layer "
433-
list:AddString(msg .. si)
454+
list:AddString(msg .. i)
434455
end
435456
if i == config.overwrite_layer then list:SetSelectedItem(i - 1) end
436457
end
@@ -625,6 +646,18 @@ local function new_expression_category(new_name)
625646
return ok, (ok and new_category:GetID() or 0)
626647
end
627648

649+
local function find_first_non_rest(staff, measure)
650+
local nel = finale.FCNoteEntryLayer(config.source_layer - 1, staff, measure, measure)
651+
nel:Load()
652+
for i = 0, (nel.Count - 1) do
653+
local e = nel:GetItemAt(i)
654+
if e ~= nil and e:IsNote() then
655+
return e.MeasurePos
656+
end
657+
end
658+
return 0
659+
end
660+
628661
local function create_cue_notes()
629662
configuration.get_user_settings(script_name, config, true)
630663
local cue_names = { } -- compile NAME/ItemNo of all pre-existing CUE_NAME expressions
@@ -686,22 +719,22 @@ local function create_cue_notes()
686719
return
687720
end
688721
-- make the cue copy
722+
local vert_shift = (config.stem_direction == 1) and config.shift_exp_down or config.shift_exp_up
723+
local measure_pos = find_first_non_rest(start_staff, source_region.StartMeasure)
689724
for _, one_staff in ipairs(destination_staves) do
690725
if notelayer_copy(source_region, one_staff) then
691726
local cue_name = mixin.FCMExpression() -- "name" the cue
692727
cue_name:SetStaff(one_staff)
693728
:SetVisible(true)
694-
:SetMeasurePos(0)
729+
:SetMeasurePos(measure_pos)
730+
:SetLayerAssignment(config.cuenote_layer)
695731
:SetScaleWithEntry(false)
696732
:SetPartAssignment(true)
697733
:SetScoreAssignment(true)
698734
:SetID(config.cuename_item)
699-
:SetHorizontalPos(config.shift_expression_left)
735+
:SetHorizontalPos(config.shift_exp_left)
736+
:SetVerticalPos(vert_shift)
700737
:SaveNewToCell(finale.FCCell(source_region.StartMeasure, one_staff))
701-
if config.stem_direction == 1 then -- downstem
702-
cue_name.VerticalPos = config.shift_expression_down
703-
cue_name:Save()
704-
end
705738
end
706739
end
707740
refocus()

0 commit comments

Comments
 (0)