/
commands.py
214 lines (149 loc) · 6.64 KB
/
commands.py
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
# -*- coding: utf-8 -*-
"""
Mupix is available as a command line application. If all you want to do is
compare files, there is no need to write any code. Just install it and run
it from the command line. It should work on most platforms. **All commands
return JSON data.**
**********
Mupix Read
**********
Mupix will read symbolic music-files and return json data with Notes, Rests,
Time Signatures, Key Signatures, and, Clefs. You can even choose what data
you want to read by using flags `-n`, `-r`, `-t`, `-k`, `-c`, or have the
data be indented on output by using `-p`.
Example
#######
You could read a file using the folloing::
$ mupix read ./my_musicxml_file.xml
You can `pretty-print` the text by using the `-p` option::
$ mupix -p read ./my_musicxml_file.xml
You can also use bash expansion for multiple files::
$ mupix -p read ./xml/*
*************
Mupix Compare
*************
Comparing two files using the command line. You can even choose what data
you want to read by using flags `-n`, `-r`, `-t`, `-k`, `-c`, or have the
data be indented on output by using `-p`. Or if you're just interested in
the total, you can pass `-T`.
Example
#######
You can compare two files using the following::
$ mupix compare ./ground_truth.xml ./5-D.xml
You can `pretty-print` the output::
$ mupix -p compare ./ground_truth.xml ./5-D.xml
You can change the Musical Marking alignment algorithm::
$ mupix compare --sort=anw-1 ./ground_truth.xml ./5-D.xml
You can choose what you wish to display, and combine commands together too::
$ mupix -nt compare ./ground_truth.xml ./5-D.xml
$ mupix -rk compare --sort=anw-1 ./ground_truth.xml ./5-D.xml
$ mupix -ntk compare --sort=basic ./ground_truth.xml ./5-D.xml
Just the total with `pretty-print`::
$ mupix -pT compare ./ground_truth.xml ./5-D.xml
You can even use bash expansion for multiple files to test against a single ground truth::
$ mupix -pT compare ./ground_truth.xml ./xml/*
**************
Mupix Validate
**************
You can check to see if the file is valid against the official MusicXML specification, this process can take ~20 seconds per file::
$ mupix validate ./testing_xml.xml
Or of multiple files::
$ mupix validate ./*
****************
Mupix xml_finder
****************
You can identify the type of MusicXML file, either part-wise or time-wise by using
the `xml_finder` command::
$ mupix xml_finder ./testing_xml.xml
"""
import click
from mupix.application import xml_validator
from mupix.application import xml_type_finder
from mupix.application import BasicCompare
from mupix.application import SimpleNeedlemanWunsch
from mupix.application import WeightedNeedlemanWunsch
from mupix.application import PartwiseWeightedNeedlemanWunsch
from mupix.typewise import MupixObject
from mupix.extra import output_filter
@click.group()
@click.option("-p", "--pretty-print", is_flag=True, help="Print the output with and automatic indent.")
@click.option("-n", "--notes", is_flag=True, help="Show note objects")
@click.option("-r", "--rests", is_flag=True, help="Show rest objects")
@click.option("-t", "--time-signatures", is_flag=True, help="Show the time signatures")
@click.option("-k", "--key-signatures", is_flag=True, help="Show the key signatures")
@click.option("-c", "--clefs", is_flag=True, help="Show the clefs")
@click.option("-s", "--spanners", is_flag=True, help="Show the spanners")
@click.option("-z", "--error-description", is_flag=True, help="What element matched with what")
@click.option("-T", "--total-only", is_flag=True, help="Show the total of each category")
@click.pass_context
def cli(ctx, pretty_print, notes, rests, time_signatures, key_signatures, clefs, spanners, error_description, total_only):
"""
This tool helps parse MusicXML files and can list how many discrepancies there are, and what type they are.
Feed it any musicXML file and it will list all of its contents, or compare a musicXML file with a "ground truth" musicXML file that you know to be correct. It will list how many mistakes there are, and what they are as well.
"""
@cli.command("compare", short_help="Compare two or more MusicXML files. You may also select the type of algorithm you want to use by specifying --sort=anw") # noqa
@click.option("--sort", default="basic", help="Note alignment algorithm to use when aligning Mupix objects.")
@click.argument("true_data")
@click.argument("test_data", nargs=-1)
@click.pass_context
def compare(ctx, sort, true_data, test_data):
"""
Compares two MusicXML files.
OPTIONS:
--sort=basic Uses a dumb alignment that does not look forward or backward in time.
--sort=anw Uses a simplistic version of the Affine-Needleman-Wunsch based on a single element from the Mupix Objects.
--sort=anw-1 Uses the first version of the Affine-Needleman-Wunsch algorithm, based on multiple elements from each of the Mupix Objects.
TRUE_DATA:
<file> A single file
[TEST_DATA]:
<file> A single file
<file A> <file B> <file C> Or a list of files with spaces for separation
"""
algorithms_dispatcher = {
"basic": BasicCompare,
"anw": SimpleNeedlemanWunsch,
"anw-1": WeightedNeedlemanWunsch,
"pw-anw-1": PartwiseWeightedNeedlemanWunsch,
}
for f in test_data:
output_filter(
ctx.parent.params,
algorithms_dispatcher[sort],
true_data, # true_filepath
f, # test_filepath
[], # do_not_count will be implemented gradually
)
@cli.command("read", short_help="Show the parsed Symbolic file as a list of elements")
@click.argument("file_path", nargs=-1)
@click.pass_context
def read(ctx, file_path):
"""
Prints to screen the parsed symbolic file as a list of elements.
[FILE_PATH]:
<file> A single file
<file A> <file B> <file C> Or a list of files with spaces for separation
"""
for f in file_path:
output_filter(ctx.parent.params, MupixObject.from_filepath, f)
@cli.command("validate", short_help="Check if MusicXML file is valid.")
@click.argument("file_path", nargs=-1)
def validate(file_path):
"""
Checks if the given file is a valid musicXML file.
[FILE_PATH]:
<file> A single file
<file A> <file B> <file C> Or a list of files with spaces for separation
"""
for f in file_path:
print(f"{f}: {xml_validator(f)}")
@cli.command("xml_type", short_help="Check the format of the musicxml.")
@click.argument("file_path", nargs=-1)
def xml_finder(file_path):
"""
Checks if the given musicXML file is written in a part-wise or time-wise fashion.
[FILE_PATH]:
<file> A single file
<file A> <file B> <file C> Or a list of files with spaces for separation
"""
for f in file_path:
print(f"{f}: {xml_type_finder(f)}")