Skip to content

Commit b49605b

Browse files
chore: autopublish 2024-10-02T12:23:49Z
1 parent c3b20a7 commit b49605b

File tree

2 files changed

+108
-74
lines changed

2 files changed

+108
-74
lines changed

dist/musicxml_massage_export.lua

Lines changed: 107 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,34 @@ function plugindef()
22
finaleplugin.RequireDocument = false
33
finaleplugin.RequireSelection = false
44
finaleplugin.NoStore = true
5-
finaleplugin.Author = "Robert Patterson"
5+
finaleplugin.Author = "Robert Patterson (folder scanning added by Carl Vine)"
66
finaleplugin.Copyright = "CC0 https://creativecommons.org/publicdomain/zero/1.0/"
7-
finaleplugin.Version = "1.0.1"
8-
finaleplugin.Date = "September 25, 2024"
7+
finaleplugin.Version = "1.0.6"
8+
finaleplugin.Date = "October 2, 2024"
9+
finaleplugin.LoadLuaOSUtils = true
910
finaleplugin.CategoryTags = "Document"
1011
finaleplugin.MinJWLuaVersion = 0.74
12+
finaleplugin.AdditionalMenuOptions = [[
13+
Massage MusicXML Single File...
14+
]]
15+
finaleplugin.AdditionalUndoText = [[
16+
Massage MusicXML Single File
17+
]]
18+
finaleplugin.AdditionalDescriptions = [[
19+
Massage a MusicXML file to improve importing to Dorico and MuseScore
20+
]]
21+
finaleplugin.AdditionalPrefixes = [[
22+
do_single_file = true
23+
]]
24+
finaleplugin.ScriptGroupName = "Staff Explode"
1125
finaleplugin.Notes = [[
12-
This script reads a musicxml file exported from Finale and modifies it to
13-
improve the importing into Dorico or MuseScore. The best process is as follows:
26+
This script reads musicxml files exported from Finale and modifies them to
27+
improve importing into Dorico or MuseScore. The best process is as follows:
1428
1529
1. Export your document as uncompressed MusicXML.
1630
2. Run this plugin on the output *.musicxml document.
1731
3. The massaged file name has " massaged" appended to the file name.
18-
3. Import the massaged *.musicxml into Dorico or MuseScore.
32+
3. Import the massaged *.musicxml file into Dorico or MuseScore.
1933
2034
Here is a list of some of the changes the script makes:
2135
@@ -30,76 +44,51 @@ function plugindef()
3044
\widowctrl\hyphauto
3145
\fs18
3246
{\info{\comment "os":"mac","fs18":"fs24","fs26":"fs32","fs23":"fs29","fs20":"fs26"}}
33-
{\pard \sl264 \slmult1 \ql \f0 \sa180 \li0 \fi0 This script reads a musicxml file exported from Finale and modifies it to improve the importing into Dorico or MuseScore. The best process is as follows:\par}
47+
{\pard \sl264 \slmult1 \ql \f0 \sa180 \li0 \fi0 This script reads musicxml files exported from Finale and modifies them to improve importing into Dorico or MuseScore. The best process is as follows:\par}
3448
{\pard \sl264 \slmult1 \ql \f0 \sa0 \li360 \fi-360 1.\tx360\tab Export your document as uncompressed MusicXML.\par}
3549
{\pard \sl264 \slmult1 \ql \f0 \sa0 \li360 \fi-360 2.\tx360\tab Run this plugin on the output *.musicxml document.\par}
3650
{\pard \sl264 \slmult1 \ql \f0 \sa0 \li360 \fi-360 3.\tx360\tab The massaged file name has " massaged" appended to the file name.\par}
37-
{\pard \sl264 \slmult1 \ql \f0 \sa0 \li360 \fi-360 4.\tx360\tab Import the massaged *.musicxml into Dorico or MuseScore.\sa180\par}
51+
{\pard \sl264 \slmult1 \ql \f0 \sa0 \li360 \fi-360 4.\tx360\tab Import the massaged *.musicxml file into Dorico or MuseScore.\sa180\par}
3852
{\pard \sl264 \slmult1 \ql \f0 \sa180 \li0 \fi0 Here is a list of some of the changes the script makes:\par}
3953
{\pard \sl264 \slmult1 \ql \f0 \sa0 \li360 \fi-360 \bullet \tx360\tab 8va/8vb and 15ma/15mb symbols are extended to include the last note and extended left to include leading grace notes.\sa180\par}
4054
{\pard \sl264 \slmult1 \ql \f0 \sa180 \li0 \fi0 Due to a limitation in the xml parser, all xml processing instructions are removed. These are metadata that neither Dorico nor MuseScore use, so their removal should not affect importing into those programs.\par}
4155
}
4256
]]
4357
finaleplugin.HashURL = "https://raw.githubusercontent.com/finale-lua/lua-scripts/master/hash/musicxml_massage_export.hash"
44-
return "Massage MusicXML...", "", "Massages MusicXML to make it easier to import to Dorico and MuseScore."
58+
return "Massage MusicXML Folder...",
59+
"Massage MusicXML Folder",
60+
"Massage a folder of MusicXML files to improve importing to Dorico and MuseScore."
4561
end
46-
local text_extension = ".musicxml"
47-
local function remove_processing_instructions(file_path, output_name)
48-
49-
local input_file <close> = io.open(file_path, "r")
62+
do_single_file = do_single_file or false
63+
local xml_extension = ".musicxml"
64+
local add_to_filename = " massaged"
65+
local function alert_error(file_list)
66+
local msg = (#file_list > 1 and "These files do not " or "This file does not ")
67+
.. "appear to be MusicXML exported from Finale:\n\n"
68+
.. table.concat(file_list, "\n")
69+
finenv.UI():AlertError(msg, plugindef())
70+
end
71+
local function remove_processing_instructions(input_name, output_name)
72+
local input_file <close> = io.open(input_name, "r")
5073
if not input_file then
51-
error("Cannot open file: " .. file_path)
74+
error("Cannot open file: " .. input_name)
5275
end
53-
5476
local lines = {}
5577
for line in input_file:lines() do
56-
5778
if line:match("^%s*<%?xml") or not line:match("^%s*<%?.*%?>") then
5879
table.insert(lines, line)
5980
end
6081
end
61-
6282
input_file:close()
63-
6483
local output_file <close> = io.open(output_name, "w")
6584
if not output_file then
66-
error("Cannot open file for writing: " .. file_path)
85+
error("Cannot open file for writing: " .. output_name)
6786
end
68-
6987
for _, line in ipairs(lines) do
7088
output_file:write(line .. "\n")
7189
end
72-
7390
output_file:close()
7491
end
75-
function do_open_dialog(document)
76-
local path_name = finale.FCString()
77-
local file_name = finale.FCString()
78-
local file_path = finale.FCString()
79-
if document then
80-
document:GetPath(file_path)
81-
file_path:SplitToPathAndFile(path_name, file_name)
82-
end
83-
local full_file_name = file_name.LuaString
84-
local extension = finale.FCString(file_name.LuaString)
85-
extension:ExtractFileExtension()
86-
if extension.Length > 0 then
87-
file_name:TruncateAt(file_name:FindLast("." .. extension.LuaString))
88-
end
89-
file_name:AppendLuaString(text_extension)
90-
local open_dialog = finale.FCFileOpenDialog(finenv.UI())
91-
open_dialog:SetWindowTitle(finale.FCString("Open MusicXML for " .. full_file_name))
92-
open_dialog:AddFilter(finale.FCString("*" .. text_extension), finale.FCString("MusicXML File"))
93-
open_dialog:SetInitFolder(path_name)
94-
open_dialog:SetFileName(file_name)
95-
open_dialog:AssureFileExtension(text_extension)
96-
if not open_dialog:Execute() then
97-
return nil
98-
end
99-
local selected_file_name = finale.FCString()
100-
open_dialog:GetFileName(selected_file_name)
101-
return selected_file_name.LuaString
102-
end
10392
function fix_octave_shift(xml_measure)
10493
for xml_direction in xmlelements(xml_measure, "direction") do
10594
local xml_direction_type = xml_direction:FirstChildElement("direction-type")
@@ -153,40 +142,85 @@ function process_xml(score_partwise)
153142
end
154143
end
155144
end
156-
function append_massaged_to_filename(filepath)
157-
158-
local path, filename, extension = filepath:match("^(.-)([^\\/]-)%.([^\\/%.]+)$")
159-
145+
function process_one_file(input_file)
146+
local path, filename, extension = input_file:match("^(.-)([^\\/]-)%.([^\\/%.]+)$")
160147
if not path or not filename or not extension then
161148
error("Invalid file path format")
162149
end
150+
local output_file = path .. filename .. add_to_filename .. xml_extension
151+
remove_processing_instructions(input_file, output_file)
152+
local musicxml = tinyxml2.XMLDocument()
153+
local result = musicxml:LoadFile(output_file)
154+
if result ~= tinyxml2.XML_SUCCESS then
155+
os.remove(output_file)
156+
return input_file
157+
end
158+
local score_partwise = musicxml:FirstChildElement("score-partwise")
159+
if not score_partwise then
160+
os.remove(output_file)
161+
return input_file
162+
end
163+
process_xml(score_partwise)
164+
musicxml:SaveFile(output_file)
165+
return ""
166+
end
167+
function process_directory(path_name)
168+
local folder_dialog = finale.FCFolderBrowseDialog(finenv.UI())
169+
folder_dialog:SetWindowTitle(finale.FCString("Select Folder of MusicXML Files:"))
170+
folder_dialog:SetFolderPath(path_name)
171+
if not folder_dialog:Execute() then
172+
return nil
173+
end
174+
local selected_directory = finale.FCString()
175+
folder_dialog:GetFolderPath(selected_directory)
176+
local src_dir = selected_directory.LuaString
163177

164-
local new_filepath = path .. filename .. " massaged." .. extension
165-
return new_filepath
178+
local error_list = {}
179+
local lfs = require("lfs")
180+
for file in lfs.dir(src_dir) do
181+
if file ~= "." and file ~= ".." and file:sub(-xml_extension:len()) == xml_extension then
182+
local file_error = process_one_file(src_dir .. "/" .. file)
183+
if file_error ~= "" then
184+
table.insert(error_list, file_error)
185+
end
186+
end
187+
end
188+
if #error_list > 0 then
189+
alert_error(error_list)
190+
end
191+
end
192+
function do_open_dialog(path_name)
193+
local open_dialog = finale.FCFileOpenDialog(finenv.UI())
194+
open_dialog:SetWindowTitle(finale.FCString("Select a MusicXML File:"))
195+
open_dialog:AddFilter(finale.FCString("*" .. xml_extension), finale.FCString("MusicXML File"))
196+
open_dialog:SetInitFolder(path_name)
197+
open_dialog:AssureFileExtension(xml_extension)
198+
if not open_dialog:Execute() then
199+
return nil
200+
end
201+
local selected_file_name = finale.FCString()
202+
open_dialog:GetFileName(selected_file_name)
203+
return selected_file_name.LuaString
166204
end
167205
function music_xml_massage_export()
168206
local documents = finale.FCDocuments()
169207
documents:LoadAll()
170208
local document = documents:FindCurrent()
171-
local xml_file = do_open_dialog(document)
172-
if not xml_file then
173-
return
174-
end
175-
local output_name = append_massaged_to_filename(xml_file)
176-
177-
remove_processing_instructions(xml_file, output_name)
178-
local musicxml = tinyxml2.XMLDocument()
179-
local result = musicxml:LoadFile(output_name)
180-
if result ~= tinyxml2.XML_SUCCESS then
181-
error("Unable to process " .. xml_file .. ". " .. musicxml:ErrorStr())
182-
return
209+
local path_name = finale.FCString()
210+
if document then
211+
document:GetPath(path_name)
212+
path_name:SplitToPathAndFile(path_name, nil)
183213
end
184-
local score_partwise = musicxml:FirstChildElement("score-partwise")
185-
if not score_partwise then
186-
error("File " .. xml_file .. " does not appear to be a Finale-exported MusicXML file.")
214+
if do_single_file then
215+
local xml_file = do_open_dialog(path_name)
216+
if xml_file then
217+
local file_error = process_one_file(xml_file)
218+
if file_error ~= "" then
219+
alert_error{file_error}
220+
end
221+
end
222+
else
223+
process_directory(path_name)
187224
end
188-
process_xml(score_partwise)
189-
musicxml:SaveFile(output_name)
190-
finenv.UI():AlertInfo("Processed to " .. output_name .. ".", "Processed File")
191225
end
192226
music_xml_massage_export()

hash/musicxml_massage_export.hash

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
07070dcc479c584c98a9ef96a8ab88870ac603a14797c8f88942f6d46500eb0cdb36f78a3b3bd610115074899756e5208d7a876642f37170de5319233e4dc3a0 musicxml_massage_export.lua
1+
136df994fbc2fe2db01853e9f1d814c746c2e5c5b8c2ec08f5ef2f7c090a67bb91b448835c9cc2ff84fd7580ba09b1b8b48255b22ac1cee88c343542790c36f3 musicxml_massage_export.lua

0 commit comments

Comments
 (0)