Perl API
The facade is deliberately small: build one converter and use it for as many scores as you have. The stages underneath it are public too, and can be driven one at a time when something needs inspecting between them.
On this page
A complete program
use strict;
use warnings;
use Music::NWC2MusicXML;
my $converter = Music::NWC2MusicXML->new(log_level => 'normal');
for my $input (@ARGV) {
my $out = $converter->convert(input => $input, overwrite => 1);
if (defined $out) {
print "converted $input -> $out\n";
} else {
warn "could not convert $input\n";
}
}
exit($converter->diagnostics->has_warnings ? 1 : 0);
new
Builds a converter and the decoder, parser and generator it will use, so they are constructed once rather than per file.
| Argument | Meaning |
|---|---|
log_level | quiet, normal (the default), verbose or debug. |
warnings_fh | An open filehandle for warnings. Defaults to standard error, via the diagnostics object. |
validate | Run the extended consistency checks. Off by default; the same thing as --validate. |
my $c = Music::NWC2MusicXML->new(log_level => 'verbose', validate => 1);
Returns the blessed converter. It emits no messages of its own.
convert
The single-file entry point: decode, parse, generate, write. Fatal problems
croak; everything that can be survived is a warning and the
conversion continues.
| Argument | Meaning |
|---|---|
input | Path to the .nwc file. Required. |
output | Path for the MusicXML file. Optional; defaults to the input path with .musicxml in place of .nwc. |
overwrite | Replace an existing output file. Off by default, in which case an existing file is left alone. |
my $out = $c->convert(
input => 'Pilgrim.nwc',
output => 'out/Pilgrim.musicxml',
overwrite => 1,
);
Returns the output path on success and undef on failure, with
the reason on the diagnostics object. It writes the output file and
updates the diagnostic counters as side effects.
batch_convert
Converts a list of files in sequence. A file that fails is caught and counted; the rest of the list is still converted, and a summary is printed at the end.
| Argument | Meaning |
|---|---|
inputs | Array reference of input paths. Required. |
output_dir | Directory for the outputs. Optional; by default each file is written beside its input. |
overwrite | Replace existing outputs. Off by default. |
recursive | Keep each file's relative path below output_dir. Off by default. |
base_dir | The directory stripped when working out that relative path, so the output does not repeat scores/ because the input began there. |
my $counts = $c->batch_convert(
inputs => [ glob('scores/**/*.nwc') ],
output_dir => 'musicxml',
recursive => 1,
base_dir => 'scores',
overwrite => 1,
);
# { processed => 12, successful => 11, warnings => 3, failed => 1 }
printf "%d of %d converted, %d failed\n",
$counts->{successful}, $counts->{processed}, $counts->{failed};
Returns a hash reference of counts: processed,
successful, warnings and failed.
It does not croak because one score was bad.
diagnostics
Returns the Music::NWC2MusicXML::Diagnostics object the
converter has been using. It carries the warning count, and every message
the pipeline produces goes through its catalogue, so warnings read the same
way whether they came from the decoder, the parser or the generator.
| Code | Meaning | Resolution |
|---|---|---|
error_no_input | The input parameter was missing. | Pass an input path. |
error_file_not_found | The input file does not exist, or cannot be read. | Check the path and its permissions. |
error_decode | The NWC decoding stage failed. | The file is not an NWC 2.x container, or its payload is damaged. See the embedded error. |
error_parse | The NWCTXT parsing stage failed. | See the embedded error: it names the record that could not be understood. |
error_generate | MusicXML generation failed. | See the embedded error. Usually a score the model could not describe. |
error_write | The output file could not be written. | Check permissions and free space. |
error_mkdir | The output directory could not be created. | Check the permissions of its parent. |
my $diag = $c->diagnostics;
if ($diag->has_warnings) {
print "converted with warnings\n";
}
Class-level defaults
The converter uses Object::Configure,
so defaults can be set once for the whole process instead of being
repeated at each new:
use Music::NWC2MusicXML;
Music::NWC2MusicXML->configure(log_level => 'verbose');
my $c = Music::NWC2MusicXML->new; # already verbose
That is convenient in a long-running program, and worth knowing about in
one that is not yours: a module or a configuration file that has called
configure changes the behaviour of every later
new. An explicit argument still wins.
The stages on their own
The facade chains three objects, and nothing stops you chaining them yourself. That is how a score can be inspected between decoding and generation — and it is what the golden-file regression test does:
use Music::NWC2MusicXML::NWC;
use Music::NWC2MusicXML::Parser;
use Music::NWC2MusicXML::MusicXML;
my $score = Music::NWC2MusicXML::Parser->new->parse(
Music::NWC2MusicXML::NWC->read('t/input/my_score.nwc')
);
my $xml = Music::NWC2MusicXML::MusicXML->new->generate($score);
open my $fh, '>', 't/input/my_score.musicxml' or die $!;
print {$fh} $xml;
close $fh;
| Stage | Call | Gives you |
|---|---|---|
| Decode | Music::NWC2MusicXML::NWC->read($path) | The NWCTXT text the container was built from: pipe-delimited records, one per line. |
| Parse | Music::NWC2MusicXML::Parser->new->parse($text) | A Score of Staff objects, each holding Event objects with exact rational durations. |
| Generate | Music::NWC2MusicXML::MusicXML->new->generate($score) | The MusicXML document, as a string. |
The score model is plain data with accessors, so a program that needs to know what a file contains — the staves, their instruments, the number of measures — can stop after parsing and ask, without producing XML at all.