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.

ArgumentMeaning
log_levelquiet, normal (the default), verbose or debug.
warnings_fhAn open filehandle for warnings. Defaults to standard error, via the diagnostics object.
validateRun 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.

ArgumentMeaning
inputPath to the .nwc file. Required.
outputPath for the MusicXML file. Optional; defaults to the input path with .musicxml in place of .nwc.
overwriteReplace 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.

ArgumentMeaning
inputsArray reference of input paths. Required.
output_dirDirectory for the outputs. Optional; by default each file is written beside its input.
overwriteReplace existing outputs. Off by default.
recursiveKeep each file's relative path below output_dir. Off by default.
base_dirThe 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.

CodeMeaningResolution
error_no_inputThe input parameter was missing.Pass an input path.
error_file_not_foundThe input file does not exist, or cannot be read.Check the path and its permissions.
error_decodeThe NWC decoding stage failed.The file is not an NWC 2.x container, or its payload is damaged. See the embedded error.
error_parseThe NWCTXT parsing stage failed.See the embedded error: it names the record that could not be understood.
error_generateMusicXML generation failed.See the embedded error. Usually a score the model could not describe.
error_writeThe output file could not be written.Check permissions and free space.
error_mkdirThe 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;
StageCallGives you
DecodeMusic::NWC2MusicXML::NWC->read($path)The NWCTXT text the container was built from: pipe-delimited records, one per line.
ParseMusic::NWC2MusicXML::Parser->new->parse($text)A Score of Staff objects, each holding Event objects with exact rational durations.
GenerateMusic::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.

← Commands What converts →