@@ -4,8 +4,8 @@ function plugindef()
44 finaleplugin .NoStore = true
55 finaleplugin .Author = " Robert Patterson"
66 finaleplugin .Copyright = " CC0 https://creativecommons.org/publicdomain/zero/1.0/"
7- finaleplugin .Version = " 1.0.3 "
8- finaleplugin .Date = " December 31, 2024 "
7+ finaleplugin .Version = " 1.1.0 "
8+ finaleplugin .Date = " December 8, 2025 "
99 finaleplugin .CategoryTags = " Document"
1010 finaleplugin .MinJWLuaVersion = 0.75
1111 finaleplugin .Notes = [[
@@ -59,6 +59,7 @@ local enigma_string = require("library.enigma_string")
5959local utils = require (" library.utils" )
6060local client = require (" library.client" )
6161local score = require (" library.score" )
62+ local library = require (" library.general_library" )
6263
6364do_folder = do_folder or false
6465
@@ -68,7 +69,7 @@ local MUSX_EXTENSION <const> = ".musx"
6869local MUS_EXTENSION <const> = " .mus"
6970local TEXT_EXTENSION <const> = " .mss"
7071local PART_EXTENSION <const> = " .part" .. TEXT_EXTENSION
71- local MSS_VERSION <const> = " 4.50 "
72+ local MSS_VERSION <const> = " 4.60 "
7273
7374-- hard-coded scaling values
7475local EVPU_PER_INCH <const> = 288
@@ -77,6 +78,8 @@ local EVPU_PER_SPACE <const> = 24
7778local EFIX_PER_EVPU <const> = 64
7879local EFIX_PER_SPACE <const> = EVPU_PER_SPACE * EFIX_PER_EVPU
7980local MUSE_FINALE_SCALE_DIFFERENTIAL <const> = 20 / 24
81+ local MUSE_NUMERIC_PRECISION <const> = 5
82+ local NORMAL_STAFF_HEIGHT_SP <const> = 4
8083
8184-- Current state
8285local TIMER_ID <const> = 1 -- value that identifies our timer
@@ -121,6 +124,7 @@ local tie_prefs
121124local tuplet_prefs
122125local text_exps
123126local music_font_name
127+ local spatium_scaling
124128
125129function open_current_prefs ()
126130 local font_prefs = finale .FCFontPrefs ()
@@ -177,6 +181,13 @@ function open_current_prefs()
177181 else
178182 music_font_name = nil
179183 end
184+ local page_percent = page_prefs .PageScaling / 100
185+ local staff_percent = (page_prefs .SystemStaffHeight / (EVPU_PER_SPACE * 4 * 16 )) * (page_prefs .SystemScaling / 100 )
186+ spatium_scaling = page_percent * staff_percent
187+ end
188+
189+ local function format_muse_float (value )
190+ return string.format (" %" .. " ." .. tostring (MUSE_NUMERIC_PRECISION ) .. " g" , value )
180191end
181192
182193function set_element_text (style_element , name , value )
@@ -185,7 +196,7 @@ function set_element_text(style_element, name, value)
185196 log_message (" incorrect property for " .. name , true )
186197 elseif type (value ) == " number" then
187198 if math.type (value ) == " float" then
188- value = string.format ( " %.5g " , value )
199+ value = format_muse_float ( value )
189200 setter_func = " SetText"
190201 else
191202 setter_func = " SetIntText"
@@ -202,6 +213,34 @@ function set_element_text(style_element, name, value)
202213 return element
203214end
204215
216+ local function set_point_element (style_element , name , x , y )
217+ local element = style_element :FirstChildElement (name )
218+ if not element then
219+ element = style_element :InsertNewChildElement (name )
220+ end
221+ element :SetText (" " )
222+ element :SetAttribute (" x" , format_muse_float (x ))
223+ element :SetAttribute (" y" , format_muse_float (y ))
224+ return element
225+ end
226+
227+ local function font_mag_val (font_info )
228+ return font_info .Absolute and 1 or MUSE_FINALE_SCALE_DIFFERENTIAL
229+ end
230+
231+ local function calc_font_ascent_in_spaces (font_info )
232+ if not font_info then
233+ return 0
234+ end
235+ local text_metrics = finale .FCTextMetrics ()
236+ local test_string = finale .FCString ()
237+ test_string .LuaString = " 0123456789"
238+ if not text_metrics :LoadString (test_string , font_info , 100 * font_mag_val (font_info )) then
239+ return 0
240+ end
241+ return text_metrics .TopEVPUs / EVPU_PER_SPACE
242+ end
243+
205244function muse_font_efx (font_info )
206245 local retval = 0
207246 if font_info .Bold then
232271
233272function write_font_pref (style_element , name_prefix , font_info )
234273 set_element_text (style_element , name_prefix .. " FontFace" , font_info .Name )
235- set_element_text (style_element , name_prefix .. " FontSize" , font_info .Size * (font_info . Absolute and 1 or MUSE_FINALE_SCALE_DIFFERENTIAL ))
274+ set_element_text (style_element , name_prefix .. " FontSize" , font_info .Size * font_mag_val (font_info ))
236275 set_element_text (style_element , name_prefix .. " FontSpatiumDependent" , not font_info .Absolute )
237276 set_element_text (style_element , name_prefix .. " FontStyle" , muse_font_efx (font_info ))
238277end
@@ -300,9 +339,7 @@ function write_page_prefs(style_element)
300339 set_element_text (style_element , " pageTwosided" , page_prefs .UseFacingPages )
301340 set_element_text (style_element , " enableIndentationOnFirstSystem" , page_prefs .UseFirstSystemMargins )
302341 set_element_text (style_element , " firstSystemIndentationValue" , page_prefs .FirstSystemLeft / EVPU_PER_SPACE )
303- local page_percent = page_prefs .PageScaling / 100
304- local staff_percent = (page_prefs .SystemStaffHeight / (EVPU_PER_SPACE * 4 * 16 )) * (page_prefs .SystemScaling / 100 )
305- set_element_text (style_element , " spatium" , (EVPU_PER_SPACE * staff_percent * page_percent ) / EVPU_PER_MM )
342+ set_element_text (style_element , " spatium" , (EVPU_PER_SPACE * spatium_scaling ) / EVPU_PER_MM )
306343 local first_system = finale .FCStaffSystem ()
307344 if first_system :LoadFirst () then
308345 local min_size = 100
@@ -452,57 +489,116 @@ function write_measure_number_prefs(style_element)
452489 set_element_text (style_element , " showMeasureNumber" , meas_num_regions :LoadAll () > 0 )
453490 if meas_num_regions .Count > 0 then
454491 local meas_nums = meas_num_regions :GetItemAt (0 )
455- set_element_text ( style_element , " showMeasureNumberOne " , not meas_nums : GetHideFirstNumber ( current_is_part ) )
456- set_element_text (style_element , " measureNumberInterval " , meas_nums :GetMultipleValue ( current_is_part ))
457- set_element_text (style_element , " measureNumberSystem " , meas_nums :GetShowOnSystemStart ( current_is_part ) and not meas_nums : GetShowMultiples ( current_is_part ))
458- local function process_segment ( font_info , enclosure , use_enclosure , justification , alignment , vertical , prefix )
459- local function justification_string ( justi )
460- if justi == finale . MNJUSTIFY_LEFT then
461- return " left,baseline "
462- elseif justi == finale . MNJUSTIFY_CENTER then
463- return " center,baseline "
464- else
465- return " right,baseline "
466- end
492+ local parts_val = library . calc_parts_boolean_for_measure_number_region ( meas_nums , current_is_part )
493+ set_element_text (style_element , " showMeasureNumberOne " , not meas_nums :GetHideFirstNumber ( parts_val ))
494+ set_element_text (style_element , " measureNumberInterval " , meas_nums :GetMultipleValue ( parts_val ))
495+ local show_on_every = meas_nums : GetShowMultiples ( parts_val )
496+ local use_show_on_start = meas_nums : GetShowOnSystemStart ( parts_val ) and not show_on_every
497+ set_element_text ( style_element , " measureNumberSystem " , use_show_on_start )
498+
499+ local function justification_string ( justi )
500+ if justi == finale . MNJUSTIFY_LEFT then
501+ return " left,baseline "
502+ elseif justi == finale . MNJUSTIFY_CENTER then
503+ return " center,baseline "
467504 end
468- local function horz_alignment (align ) -- MuseScore 4.6 changes this to "left", "center", "right"
469- if align == finale .MNALIGN_LEFT then
470- return 0
471- elseif align == finale .MNALIGN_CENTER then
472- return 1
473- else
474- return 2
475- end
476- end
477- local function vert_alignment (vert )
478- return vert >= 0 and 0 or 1
505+ return " right,baseline"
506+ end
507+
508+ local function align_string (align )
509+ if align == finale .MNALIGN_LEFT then
510+ return " left"
511+ elseif align == finale .MNALIGN_CENTER then
512+ return " center"
479513 end
514+ return " right"
515+ end
516+
517+ local function vert_alignment (vert )
518+ return vert >= 0 and 0 or 1
519+ end
520+
521+ local function process_segment (font_info , enclosure , use_enclosure , justification , alignment , horizontal , vertical , prefix )
522+ horizontal = horizontal or 0
523+ vertical = vertical or 0
480524 write_font_pref (style_element , prefix , font_info )
481525 set_element_text (style_element , prefix .. " VPlacement" , vert_alignment (vertical ))
482- set_element_text (style_element , prefix .. " HPlacement" , horz_alignment (alignment ))
526+ set_element_text (style_element , prefix .. " HPlacement" , align_string (alignment ))
483527 set_element_text (style_element , prefix .. " Align" , justification_string (justification ))
528+ set_element_text (style_element , prefix .. " Position" , align_string (justification ))
529+ local horizontal_sp = horizontal / EVPU_PER_SPACE
530+ local vertical_sp = vertical / EVPU_PER_SPACE
531+ local text_height_sp = calc_font_ascent_in_spaces (font_info ) * spatium_scaling
532+ set_point_element (style_element , prefix .. " PosAbove" , horizontal_sp , math.min (- vertical_sp , 0 ))
533+ set_point_element (style_element , prefix .. " PosBelow" , horizontal_sp ,
534+ math.max (- (vertical_sp + NORMAL_STAFF_HEIGHT_SP ) - text_height_sp , 0 ))
484535 write_frame_prefs (style_element , prefix , use_enclosure and enclosure or nil )
485536 end
486- local font_info = meas_nums :GetShowOnSystemStart (current_is_part ) and meas_nums :CreateStartFontInfo (current_is_part ) or meas_nums :CreateMultipleFontInfo (current_is_part )
487- local enclosure = meas_nums :GetShowOnSystemStart (current_is_part ) and meas_nums :GetEnclosureStart (current_is_part ) or meas_nums :GetEnclosureMultiple (current_is_part )
488- local use_enclosure = meas_nums :GetShowOnSystemStart (current_is_part ) and meas_nums :GetUseEnclosureStart (current_is_part ) or meas_nums :GetUseEnclosureMultiple (current_is_part )
489- local justification = meas_nums :GetShowMultiples (current_is_part ) and meas_nums :GetMultipleJustification (current_is_part ) or meas_nums :GetStartJustification (current_is_part )
490- local alignment = meas_nums :GetShowMultiples (current_is_part ) and meas_nums :GetMultipleAlignment (current_is_part ) or meas_nums :GetStartAlignment (current_is_part )
491- local vertical = meas_nums :GetShowOnSystemStart (current_is_part ) and meas_nums :GetStartVerticalPosition (current_is_part ) or meas_nums :GetMultipleVerticalPosition (current_is_part )
537+
538+ local scroll_view = finale .FCSystemStaves ()
539+ scroll_view :LoadScrollView ()
540+ local staff = finale .FCStaff ()
541+ local top_on = false
542+ local bottom_on = false
543+ local any_interior_on = false
544+ local all_staves_on = scroll_view .Count > 0
545+ for index = 0 , scroll_view .Count - 1 do
546+ local staff_id = scroll_view :GetItemAt (index ).Staff
547+ local shows = false
548+ if staff :Load (staff_id ) then
549+ shows = staff .ShowMeasureNumbers
550+ end
551+ all_staves_on = all_staves_on and shows
552+ if index == 0 then
553+ top_on = shows
554+ elseif index == scroll_view .Count - 1 then
555+ bottom_on = shows
556+ elseif shows then
557+ any_interior_on = true
558+ end
559+ end
560+
561+ local placement_mode = " on-so-staves"
562+ local show_top = meas_nums :GetShowOnTopStaff (parts_val )
563+ local show_bottom = meas_nums :GetShowOnBottomStaff (parts_val )
564+ local exclude_others = meas_nums :GetExcludeOtherStaves (parts_val )
565+ local use_above = exclude_others or (not any_interior_on and not bottom_on )
566+ local use_below = exclude_others or (not any_interior_on and not top_on )
567+ if use_above and show_top then
568+ placement_mode = " above-system"
569+ elseif use_below and show_bottom then
570+ placement_mode = " below-system"
571+ elseif all_staves_on then
572+ placement_mode = " on-all-staves"
573+ elseif show_bottom and not use_below then
574+ log_message (" Show on Bottom not supported when other staves also show measure numbers." )
575+ end
576+ set_element_text (style_element , " measureNumberPlacementMode" , placement_mode )
577+
578+ local font_info = use_show_on_start and meas_nums :CreateStartFontInfo (parts_val ) or meas_nums :CreateMultipleFontInfo (parts_val )
579+ local enclosure = use_show_on_start and meas_nums :GetEnclosureStart (parts_val ) or meas_nums :GetEnclosureMultiple (parts_val )
580+ local use_enclosure = use_show_on_start and meas_nums :GetUseEnclosureStart (parts_val ) or meas_nums :GetUseEnclosureMultiple (parts_val )
581+ local justification = show_on_every and meas_nums :GetMultipleJustification (parts_val ) or meas_nums :GetStartJustification (parts_val )
582+ local alignment = show_on_every and meas_nums :GetMultipleAlignment (parts_val ) or meas_nums :GetStartAlignment (parts_val )
583+ local vertical = use_show_on_start and meas_nums :GetStartVerticalPosition (parts_val ) or meas_nums :GetMultipleVerticalPosition (parts_val )
584+ local horizontal = use_show_on_start and meas_nums :GetStartHorizontalPosition (parts_val ) or meas_nums :GetMultipleHorizontalPosition (parts_val )
585+ set_element_text (style_element , " measureNumberAlignToBarline" , alignment == finale .MNALIGN_LEFT )
492586 set_element_text (style_element , " measureNumberOffsetType" , 1 )
493- process_segment (font_info , enclosure , use_enclosure , justification , alignment , vertical , " measureNumber" )
494- set_element_text (style_element , " mmRestShowMeasureNumberRange" , meas_nums :GetShowMultiMeasureRange (current_is_part ))
495- local left_char = meas_nums :GetMultiMeasureBracketLeft (current_is_part )
587+ process_segment (font_info , enclosure , use_enclosure , justification , alignment , horizontal , vertical , " measureNumber" )
588+ process_segment (font_info , enclosure , use_enclosure , justification , alignment , horizontal , vertical , " measureNumberAlternate" )
589+
590+ set_element_text (style_element , " mmRestShowMeasureNumberRange" , meas_nums :GetShowMultiMeasureRange (parts_val ))
591+ local left_char = meas_nums :GetMultiMeasureBracketLeft (parts_val )
496592 if left_char == 0 then
497593 set_element_text (style_element , " mmRestRangeBracketType" , 2 )
498- elseif left_char == ' (' then
594+ elseif left_char == string.byte ( ' (' ) then
499595 set_element_text (style_element , " mmRestRangeBracketType" , 1 )
500596 else
501597 set_element_text (style_element , " mmRestRangeBracketType" , 0 )
502598 end
503- process_segment (meas_nums :CreateMultiMeasureFontInfo (current_is_part ), meas_nums : GetEnclosureMultiple ( current_is_part ), meas_nums : GetUseEnclosureMultiple ( current_is_part ) ,
504- meas_nums :GetMultiMeasureJustification (current_is_part ), meas_nums :GetMultiMeasureAlignment (current_is_part ),
505- meas_nums :GetMultiMeasureVerticalPosition (current_is_part ), " mmRestRange" )
599+ process_segment (meas_nums :CreateMultiMeasureFontInfo (parts_val ), nil , false ,
600+ meas_nums :GetMultiMeasureJustification (parts_val ), meas_nums :GetMultiMeasureAlignment (parts_val ),
601+ meas_nums :GetMultiMeasureHorizontalPosition ( parts_val ), meas_nums : GetMultiMeasureVerticalPosition (parts_val ), " mmRestRange" )
506602 end
507603 set_element_text (style_element , " createMultiMeasureRests" , current_is_part )
508604 set_element_text (style_element , " minEmptyMeasures" , mmrest_prefs .StartNumberingAt )
0 commit comments