@@ -4,28 +4,29 @@ function plugindef()
44 finaleplugin .Author = " Carl Vine"
55 finaleplugin .AuthorURL = " https://carlvine.com/lua"
66 finaleplugin .Copyright = " https://creativecommons.org/licenses/by/4.0/"
7- finaleplugin .Version = " 0.09 "
8- finaleplugin .Date = " 2024/06/19 "
7+ finaleplugin .Version = " 0.10 "
8+ finaleplugin .Date = " 2024/07/17 "
99 finaleplugin .MinJWLuaVersion = 0.70
1010 finaleplugin .Notes = [[
11- Make dynamic marks in the selection louder or softer by stages.
11+ Make dynamic marks in the selection louder or softer in stages.
1212 This functionality is buried within __JWChange__ but is useful
13- and I thought was worth bringing nearer the surface.
13+ enough to bring closer to the surface.
1414 This script works similarly but allows jumping up to 9 _levels_ at once.
1515 The dynamic range is from __pppppp__ to __ffffff__, though scores using
16- older (non-_SMuFL_ ) fonts are restricted to the range __pppp__-__ffff__.
16+ older (non-__SMuFL__ ) fonts are restricted to the range __pppp__-__ffff__.
1717
1818 To repeat the previous level shift without a confirmation dialog
19- hold down [Shift ] when starting the script.
19+ hold down [_Shift_ ] when starting the script.
2020 ]]
2121 return " Dynamic Levels..." ,
2222 " Dynamic Levels" ,
2323 " Make dynamic marks in the selection louder or softer by stages"
2424end
2525
2626local hotkey = { -- customise hotkeys (lowercase only)
27- direction = " z" , -- toggle Louder/Softer
28- show_info = " q" ,
27+ direction = " z" , -- toggle Louder/Softer
28+ create_new = " e" , -- toggle create_new
29+ show_info = " q" ,
2930}
3031local config = {
3132 direction = 0 , -- 0 == "Louder", 1 = "Softer"
@@ -78,7 +79,7 @@ local function get_staff_name(staff_num)
7879 return str
7980end
8081
81- local function track_selection ()
82+ local function set_bounds ()
8283 local bounds = { -- primary region selection boundaries
8384 " StartStaff" , " StartMeasure" , " StartMeasurePos" ,
8485 " EndStaff" , " EndMeasure" , " EndMeasurePos" ,
@@ -102,18 +103,20 @@ local function track_selection()
102103end
103104
104105local function create_dynamics_alert (dialog )
105- local msg = " Do you want this script to create "
106- .. " additional dynamic expressions as required? "
107- .. " (A positive reply will be saved and used if this question arises again)."
106+ local msg = " The required replacement dynamic doesn't exist in this file. "
107+ .. " Do you want this script to create "
108+ .. " additional dynamic expressions as required? "
109+ .. " (You can change this decision later in the dialog window.)"
108110 local ui = dialog and dialog :CreateChildUI () or finenv .UI ()
109111 return ui :AlertYesNo (msg , name ) == finale .YESRETURN
110112end
111113
112- local function create_dyn_def (expression_text )
114+ local function create_dynamic_def (expression_text , hidden )
113115 local cat_def = finale .FCCategoryDef ()
114116 cat_def :Load (1 ) -- default "DYNAMIC" category
115117 local finfo = finale .FCFontInfo ()
116118 cat_def :GetMusicFontInfo (finfo )
119+ finfo .EnigmaStyles = finale [" ENIGMASTYLE_" .. (hidden and " HIDDEN" or " PLAIN" )]
117120 local str = finale .FCString ()
118121 str .LuaString = " ^fontMus"
119122 .. finfo :CreateEnigmaString (finale .FCString ()).LuaString
@@ -127,58 +130,75 @@ local function create_dyn_def(expression_text)
127130 return ted :GetItemNo () -- save new item number
128131end
129132
133+ local function is_hidden_exp (exp_def )
134+ local str = exp_def :CreateTextString ()
135+ return str :CreateLastFontInfo ().Hidden
136+ end
137+
130138local function change_dynamics (dialog )
131139 if finenv .Region ():IsEmpty () then
132140 local ui = dialog and dialog :CreateChildUI () or finenv .UI ()
133141 ui :AlertError (" Please select some music\n before running this script" , name )
134142 return
135143 end
136- local found = {} -- collate matched dynamic expressions
137- local match_count = 0
144+ local found = { show = {}, hide = {} } -- collate matched dynamic expressions
145+ local match_count = { show = 0 , hide = 0 }
138146 local shift = config .levels -- how many dynamic levels to move?
139147 if config .direction == 1 then shift = - shift end -- softer not louder
140148 local dyn_len = library .is_font_smufl_font () and 3 or 2 -- dynamic max string length
141- -- match all target dynamics from existing expressions
142- local exp_defs = mixin .FCMTextExpressionDefs ()
143- exp_defs :LoadAll ()
144- for exp_def in each (exp_defs ) do
145- if exp_def .CategoryID == 1 and exp_def .UseCategoryFont then -- "standard" dynamic?
146- local str = exp_def :CreateTextString ()
147- str :TrimEnigmaTags ()
148- if str .LuaString :len () <= dyn_len then -- within max dynamic length
149- for i , v in ipairs (dyn_char ) do -- check all dynamic glyphs
150- if not found [i ] and str .LuaString == utf8.char (v ) then
151- found [i ] = exp_def .ItemNo -- matched char
152- match_count = match_count + 1
149+
150+ -- match all target dynamics from existing expressions
151+ local function match_dynamics (hidden ) -- hidden is true or false
152+ local mode = hidden and " hide" or " show"
153+ local exp_defs = mixin .FCMTextExpressionDefs ()
154+ exp_defs :LoadAll ()
155+ for exp_def in each (exp_defs ) do
156+ if exp_def .CategoryID == 1 and hidden == is_hidden_exp (exp_def ) then
157+ local str = exp_def :CreateTextString ()
158+ str :TrimEnigmaTags ()
159+ if str .LuaString :len () <= dyn_len then -- within max dynamic length
160+ for i , v in ipairs (dyn_char ) do -- check all dynamic glyphs
161+ if not found [mode ][i ] and str .LuaString == utf8.char (v ) then
162+ found [mode ][i ] = exp_def .ItemNo -- matched char
163+ match_count [mode ] = match_count [mode ] + 1
164+ end
165+ end
153166 end
154167 end
168+ if match_count [mode ] >= # dyn_char then break end -- all collected
155169 end
156170 end
157- if match_count >= # dyn_char then break end -- all collected
158- end
171+ match_dynamics ( true )
172+ match_dynamics ( false )
159173 -- scan the selection for dynamics and change them
160- finenv .StartNewUndoBlock (string.format (" %s %s%d %s" , name ,
174+ finenv .StartNewUndoBlock (string.format (" Dynamics %s%d %s" ,
161175 (config .direction == 0 and " +" or " -" ), config .levels , selection )
162176 )
163177 for e in loadallforregion (mixin .FCMExpressions (), finenv .Region ()) do
164178 if expression .is_dynamic (e ) then
165179 local exp_def = e :CreateTextExpressionDef ()
166- if exp_def and exp_def .UseCategoryFont then -- "standard" dynamic?
180+ if exp_def then
181+ local hidden = is_hidden_exp (exp_def )
182+ local mode = hidden and " hide" or " show"
167183 local str = exp_def :CreateTextString ()
168184 str :TrimEnigmaTags ()
169185 if str .LuaString :len () <= dyn_len then -- dynamic length
170186 for i , v in ipairs (dyn_char ) do -- look for matching dynamic
171187 local target = math.min (math.max (1 , i + shift ), # dyn_char )
172188 if str .LuaString == utf8.char (v ) then -- dynamic match
173- if found [target ] then -- replacement exists
174- e :SetID (found [target ]):Save ()
189+ if found [mode ][ target ] then -- replacement exists
190+ e :SetID (found [mode ][ target ]):Save ()
175191 else -- create new dynamic
176192 if not config .create_new then -- ask permission
177193 config .create_new = create_dynamics_alert (dialog )
178194 end
179195 if config .create_new then -- create missing dynamic exp_def
180- found [target ] = create_dyn_def (utf8.char (dyn_char [target ]))
181- e :SetID (found [target ]):Save ()
196+ if dialog then -- update checkbox condition
197+ dialog :GetControl (" create_new" ):SetCheck (1 )
198+ end
199+ local t = utf8.char (dyn_char [target ])
200+ found [mode ][target ] = create_dynamic_def (t , hidden )
201+ e :SetID (found [mode ][target ]):Save ()
182202 end
183203 end
184204 break -- all done for this target dynamic
@@ -196,7 +216,7 @@ local function run_the_dialog()
196216 local y , m_offset = 0 , finenv .UI ():IsOnMac () and 3 or 0
197217 local save = config .levels
198218 local ctl = {}
199- local dialog = mixin .FCXCustomLuaWindow ():SetTitle (name : sub ( 1 , 7 ) )
219+ local dialog = mixin .FCXCustomLuaWindow ():SetTitle (" Dynamics " )
200220 -- local functions
201221 local function yd (diff ) y = y + (diff or 20 ) end
202222 local function show_info ()
@@ -214,6 +234,9 @@ local function run_the_dialog()
214234 if s :find (" [^1-9]" ) then
215235 if s :find (hotkey .show_info ) then show_info ()
216236 elseif s :find (hotkey .direction ) then flip_direction ()
237+ elseif s :find (hotkey .create_new ) then
238+ local c = ctl .create_new
239+ c :SetCheck ((c :GetCheck () + 1 ) % 2 )
217240 end
218241 else
219242 save = s :sub (- 1 ) -- save last entered char only
@@ -223,7 +246,7 @@ local function run_the_dialog()
223246 local function on_timer () -- track changes in selected region
224247 for k , v in pairs (saved_bounds ) do
225248 if finenv .Region ()[k ] ~= v then -- selection changed
226- track_selection () -- update selection tracker
249+ set_bounds () -- update selection tracker
227250 break -- all done
228251 end
229252 end
@@ -232,7 +255,7 @@ local function run_the_dialog()
232255 yd ()
233256 -- RadioButtonGroup
234257 local labels = finale .FCStrings ()
235- labels :CopyFromStringTable ({ " Louder" , " Softer" })
258+ labels :CopyFromStringTable { " Louder" , " Softer" }
236259 ctl .direction = dialog :CreateRadioButtonGroup (0 , y + 1 , 2 )
237260 :SetText (labels ):SetWidth (55 ):SetSelectedItem (config .direction )
238261 local softer = ctl .direction :GetItemAt (1 ) -- 2nd button
@@ -245,9 +268,14 @@ local function run_the_dialog()
245268 yd (21 )
246269 ctl .q = dialog :CreateButton (110 , y ):SetText (" ?" ):SetWidth (20 )
247270 :AddHandleCommand (function () show_info () end )
271+ yd (21 )
272+ ctl .create_new = dialog :CreateCheckbox (0 , y , " create_new" )
273+ :SetText (" Enable creation of new\n dynamic expressions" )
274+ :SetWidth (150 ):SetCheck (config .create_new and 1 or 0 )
275+ :SetHeight (30 )
248276 -- wrap it up
249- dialog :CreateOkButton ():SetText (" Apply" )
250- dialog :CreateCancelButton ()
277+ dialog :CreateOkButton () :SetText (" Apply" )
278+ dialog :CreateCancelButton (): SetText ( " Close " )
251279 dialog :RegisterInitWindow (function (self )
252280 self :SetTimer (config .timer_id , 125 )
253281 local bold = ctl .q :CreateFontInfo ():SetBold (true )
@@ -259,6 +287,7 @@ local function run_the_dialog()
259287 dialog :RegisterHandleOkButtonPressed (function ()
260288 config .direction = ctl .direction :GetSelectedItem ()
261289 config .levels = ctl .levels :GetInteger ()
290+ config .create_new = (ctl .create_new :GetCheck () == 1 )
262291 change_dynamics (dialog )
263292 end )
264293 dialog :RegisterCloseWindow (function (self )
@@ -272,7 +301,7 @@ local function dynamic_levels()
272301 configuration .get_user_settings (script_name , config , true )
273302 local qim = finenv .QueryInvokedModifierKeys
274303 local mod_key = qim and (qim (finale .CMDMODKEY_ALT ) or qim (finale .CMDMODKEY_SHIFT ))
275- track_selection () -- track current selected region
304+ set_bounds () -- track current selected region
276305 --
277306 if mod_key then
278307 change_dynamics (nil )
0 commit comments