Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathdynamic_levels.lua
More file actions
Latest commit
293 lines (279 loc) · 11.9 KB
/
Copy pathdynamic_levels.lua
File metadata and controls
293 lines (279 loc) · 11.9 KB
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
functionplugindef()
finaleplugin.RequireSelection=false
finaleplugin.HandlesUndo=true
finaleplugin.Author="Carl Vine"
finaleplugin.AuthorURL="https://carlvine.com/lua"
finaleplugin.Copyright="https://creativecommons.org/licenses/by/4.0/"
finaleplugin.Version="0.12"
finaleplugin.Date="2024/07/20"
finaleplugin.MinJWLuaVersion=0.70
finaleplugin.Notes=[[
Make dynamic marks in the selection louder or softer by stages.
This functionality is buried within the __JW Change__ plugin
but is useful enough to make it accessible more easily.
This script works similarly but allows jumping up to 9 _levels_ at once.
Dynamics range from __pppppp__ to __ffffff__, though scores using
older (non-__SMuFL__) fonts are restricted to the range __pppp__-__ffff__.
To repeat the previous level shift without a confirmation dialog
hold down [_Shift_] when starting the script.
]]
return"Dynamic Levels...",
"Dynamic Levels",
"Make dynamic marks in the selection louder or softer by stages"
end
localhotkey= { -- customise hotkeys (lowercase only)
direction="z", -- toggle Louder/Softer
create_new="e", -- toggle create_new
show_info="q",
}
localconfig= {
direction=0, -- 0 == "Louder", 1 = "Softer"
levels=1, -- how many "levels" louder or softer
create_new=false, -- don't create new dynamics without permission
window_pos_x=false,
window_pos_y=false,
}
localconfiguration=require("library.configuration")
localmixin=require("library.mixin")
localexpression=require("library.expression")
localutils=require("library.utils")
locallibrary=require("library.general_library")
localscript_name=library.calc_script_name()
localname=plugindef():gsub("%.%.%.", "")
localdyn_char=library.is_font_smufl_font() and
{ -- char numbers for SMuFL dynamics (1-14)
0xe527, 0xe528, 0xe529, 0xe52a, 0xe52b, 0xe520, 0xe52c, -- pppppp -> mp
0xe52d, 0xe522, 0xe52f, 0xe530, 0xe531, 0xe532, 0xe533, -- mf -> ffffff
} or
{ -- char numbers for non-SMuFL dynamics (1-10)
175, 184, 185, 112, 80, -- pppp -> mp
70, 102, 196, 236, 235-- mf -> ffff
}
localfunctiondialog_set_position(dialog)
ifconfig.window_pos_xandconfig.window_pos_ythen
dialog:StorePosition()
dialog:SetRestorePositionOnlyData(config.window_pos_x, config.window_pos_y)
dialog:RestorePosition()
end
end
localfunctiondialog_save_position(dialog)
dialog:StorePosition()
config.window_pos_x=dialog.StoredX
config.window_pos_y=dialog.StoredY
configuration.save_user_settings(script_name, config)
end
localfunctionget_staff_name(staff_num)
localstaff=finale.FCStaff()
staff:Load(staff_num)
localstr=staff:CreateDisplayAbbreviatedNameString().LuaString
ifnotstrorstr=="" then
str="Staff" ..staff_num
end
returnstr
end
localfunctionupdate_selection()
localrgn=finenv.Region()
ifrgn:IsEmpty() then
return""
else
locals=get_staff_name(rgn.StartStaff)
ifrgn.EndStaff~=rgn.StartStaffthen
s=s.."-" ..get_staff_name(rgn.EndStaff)
end
s=s.." m." ..rgn.StartMeasure
ifrgn.StartMeasure~=rgn.EndMeasurethen
s=s.."-" ..rgn.EndMeasure
end
returns
end
end
localfunctioncreate_dynamics_alert(dialog)
localmsg="The required replacement dynamic doesn't exist in this file. "
.."Do you want this script to create "
.."additional dynamic expressions as required? "
.."(You can change this decision later in the dialog window.)"
localui=dialoganddialog:CreateChildUI() orfinenv.UI()
returnui:AlertYesNo(msg, name) ==finale.YESRETURN
end
localfunctioncreate_dynamic_def(expression_text, hidden)
localcat_def=finale.FCCategoryDef()
cat_def:Load(1) -- default "DYNAMIC" category
localfinfo=finale.FCFontInfo()
cat_def:GetMusicFontInfo(finfo)
finfo.EnigmaStyles=finale["ENIGMASTYLE_" .. (hiddenand"HIDDEN" or"PLAIN")]
localstr=finale.FCString()
str.LuaString="^fontMus"
..finfo:CreateEnigmaString(finale.FCString()).LuaString
..expression_text
localted=mixin.FCMTextExpressionDef()
ted:SaveNewTextBlock(str)
:AssignToCategory(cat_def)
:SetUseCategoryPos(true)
:SetUseCategoryFont(true)
:SaveNew()
returnted:GetItemNo() -- save new item number
end
localfunctionis_hidden_exp(exp_def)
localstr=exp_def:CreateTextString()
returnstr:CreateLastFontInfo().Hidden
end
localfunctionchange_dynamics(dialog)
localselection=update_selection()
ifselection=="" then-- empty region
localui=dialoganddialog:CreateChildUI() orfinenv.UI()
ui:AlertError("Please select some music\nbefore running this script", name)
return
end
localfound= { show= {}, hide= {} } -- collate matched dynamic expressions
localmatch_count= { show=0, hide=0 }
localshift=config.levels-- how many dynamic levels to move?
ifconfig.direction==1thenshift=-shiftend-- softer not louder
localdyn_len=library.is_font_smufl_font() and3or2-- dynamic max string length
-- match all target dynamics within existing dynamic expressions
localfunctionmatch_dynamics(hidden) -- hidden is true or false
localmode=hiddenand"hide" or"show"
localexp_defs=mixin.FCMTextExpressionDefs()
exp_defs:LoadAll()
forexp_defineach(exp_defs) do
ifexp_def.CategoryID==1andhidden==is_hidden_exp(exp_def) then
localstr=exp_def:CreateTextString()
str:TrimEnigmaTags()
ifstr.LuaString:len() <=dyn_lenthen-- within max dynamic length
fori, vinipairs(dyn_char) do-- check all dynamic glyphs
ifnotfound[mode][i] andstr.LuaString==utf8.char(v) then
found[mode][i] =exp_def.ItemNo-- matched char
match_count[mode] =match_count[mode] +1
end
end
end
end
ifmatch_count[mode] >=#dyn_charthenbreakend-- all collected
end
end
match_dynamics(true)
match_dynamics(false)
-- start
finenv.StartNewUndoBlock(string.format("Dynamics %s%d %s",
(config.direction==0and"+" or"-"), config.levels, selection)
)
-- scan the selection for dynamics and change them
foreinloadallforregion(mixin.FCMExpressions(), finenv.Region()) do
ifexpression.is_dynamic(e) then
localexp_def=e:CreateTextExpressionDef()
ifexp_defthen
localhidden=is_hidden_exp(exp_def)
localmode=hiddenand"hide" or"show"
localstr=exp_def:CreateTextString()
str:TrimEnigmaTags()
ifstr.LuaString:len() <=dyn_lenthen-- dynamic length
fori, vinipairs(dyn_char) do-- look for matching dynamic
localtarget=math.min(math.max(1, i+shift), #dyn_char)
ifstr.LuaString==utf8.char(v) then-- dynamic match
iffound[mode][target] then-- replacement exists
e:SetID(found[mode][target]):Save()
else-- create new dynamic
ifnotconfig.create_newthen-- ask permission
config.create_new=create_dynamics_alert(dialog)
end
ifconfig.create_newthen-- create missing dynamic exp_def
ifdialogthen-- update checkbox condition
dialog:GetControl("create_new"):SetCheck(1)
end
localt=utf8.char(dyn_char[target]) -- dynamic text char
found[mode][target] =create_dynamic_def(t, hidden)
e:SetID(found[mode][target]):Save()
end
end
break-- all done for this target dynamic
end
end
end
end
end
end
finenv.EndUndoBlock(true)
finenv.Region():Redraw()
end
localfunctionrun_the_dialog()
localy, m_offset=0, finenv.UI():IsOnMac() and3or0
localsave=config.levels
localctl= {}
localdialog=mixin.FCXCustomLuaWindow():SetTitle("Dynamics")
-- local functions
localfunctionyd(diff) y=y+ (diffor20) end
localfunctionshow_info()
utils.show_notes_dialog(dialog, "About " ..name, 330, 160)
end
localfunctioncstat(horiz, vert, wide, str) -- dialog static text
returndialog:CreateStatic(horiz, vert):SetWidth(wide):SetText(str)
end
localfunctionkey_subs()
locals=ctl.levels:GetText():lower()
ifs:find("[^1-9]") then
ifs:find(hotkey.show_info) thenshow_info()
elseifs:find(hotkey.direction) then
localn=ctl.direction:GetSelectedItem()
ctl.direction:SetSelectedItem((n+1) %2)
elseifs:find(hotkey.create_new) then
localn=ctl.create_new:GetCheck()
ctl.create_new:SetCheck((n+1) %2)
end
else
save=s:sub(-1) -- save last entered char only
end
ctl.levels:SetText(save)
end
ctl.title=cstat(10, y, 120, name:upper())
yd()
-- RadioButtonGroup
locallabels=finale.FCStrings()
labels:CopyFromStringTable{ "Louder", "Softer" }
ctl.direction=dialog:CreateRadioButtonGroup(0, y+1, 2)
:SetText(labels):SetWidth(55):SetSelectedItem(config.direction)
localsofter=ctl.direction:GetItemAt(1) -- 2nd button
softer:SetTop(y+24)
cstat(23, y+11, 25, "(" ..hotkey.direction..")")
-- levels
cstat(65, y, 55, "Levels:")
ctl.levels=dialog:CreateEdit(110, y-m_offset):SetText(config.levels):SetWidth(20)
:AddHandleCommand(function() key_subs() end)
yd()
ctl.q=dialog:CreateButton(110, y):SetText("?"):SetWidth(20)
:AddHandleCommand(function() show_info() end)
yd(23)
ctl.create_new=dialog:CreateCheckbox(0, y, "create_new")
:SetWidth(145):SetCheck(config.create_newand1or0)
:SetText("Enable Creation of New")
yd(13)
cstat(13, y, 135, "Dynamic Expressions (" ..hotkey.create_new..")")
-- wrap it up
dialog:CreateOkButton() :SetText("Apply")
dialog:CreateCancelButton():SetText("Close")
dialog:RegisterInitWindow(function()
localbold=ctl.q:CreateFontInfo():SetBold(true)
ctl.q:SetFont(bold)
ctl.title:SetFont(bold)
end)
dialog_set_position(dialog)
dialog:RegisterHandleOkButtonPressed(function()
config.direction=ctl.direction:GetSelectedItem()
config.levels=ctl.levels:GetInteger()
config.create_new= (ctl.create_new:GetCheck() ==1)
change_dynamics(dialog)
end)
dialog:RegisterCloseWindow(function(self)
dialog_save_position(self)
end)
dialog:RunModeless()
end
localfunctiondynamic_levels()
configuration.get_user_settings(script_name, config, true)
localqim=finenv.QueryInvokedModifierKeys
localmod_key=qimand (qim(finale.CMDMODKEY_ALT) orqim(finale.CMDMODKEY_SHIFT))
ifmod_keythen
change_dynamics(nil)
else
run_the_dialog()
end
end
dynamic_levels()