## Name

Music::NWC2MusicXML - Convert NoteWorthy Composer 2 `.nwc` score files to MusicXML.

## Version

0.001.2

## Synopsis

```perl
# Simple conversion
use Music::NWC2MusicXML;

my $converter = Music::NWC2MusicXML->new;
$converter->convert(
    input  => 'Pilgrim.nwc',
    output => 'Pilgrim.musicxml',
);

# Batch conversion
$converter->batch_convert(
    inputs     => [ glob('*.nwc') ],
    output_dir => 'musicxml',
    overwrite  => 1,
);
```

## Description

`Music::NWC2MusicXML` is the top-level facade for the NWC-to-MusicXML conversion
pipeline.  It coordinates three independent stages:

- 1. **NWC binary decoding** (`Music::NWC2MusicXML::NWC`) -- reads the `.nwc`
binary container, verifies the magic signature, decompresses the zlib payload,
and extracts the NWCTXT text representation.
- 2. **NWCTXT parsing** (`Music::NWC2MusicXML::Parser`) -- parses the NWCTXT into
an internal representation (`Music::NWC2MusicXML::Score`).
- 3. **MusicXML generation** (`Music::NWC2MusicXML::MusicXML`) -- serialises the
internal representation to a well-formed UTF-8 MusicXML document.

Each stage is independently testable.  The facade wires them together,
handles batch processing, and routes all diagnostics through a single
`Music::NWC2MusicXML::Diagnostics` instance.

## Preservation Principle

The guiding principle of the conversion is:

_Preserve musical meaning rather than graphical appearance._

Priority order: notes and rhythm > voices > measures > articulations >
dynamics > lyrics > structural markings > instrument info > graphical layout.

### New

Construct a converter.

#### Purpose

Creates a configured converter instance that can be reused for multiple
conversions without reconstructing the pipeline components each time.

#### Arguments

Named parameters:

- `log_level`    -- `quiet`, `normal` (default), `verbose`, `debug`.
- `warnings_fh` -- filehandle for warning output (optional; defaults to
STDERR in the `Diagnostics` object).
- `validate`    -- perform extended consistency checks (boolean, default 0).

#### Returns

Blessed `Music::NWC2MusicXML` object.

#### Usage Example

```perl
my $c = Music::NWC2MusicXML->new(log_level => 'verbose', validate => 1);
```

#### Api Specification

##### Input

```
log_level    : SCALAR  (optional, default 'normal')
warnings_fh  : (filehandle, optional)
validate     : SCALAR  (optional, default 0)
```

##### Output

```
Music::NWC2MusicXML object
```

#### Messages

None.

### Convert

Convert a single `.nwc` file to MusicXML.

#### Purpose

Main single-file conversion entry point.  Chains decoder -> parser ->
generator, writes the output file, and updates the internal diagnostic counters.

#### Arguments

Named parameters:

- `input`     -- path to the `.nwc` input file (required).
- `output`    -- path for the `.musicxml` output file (optional).
Defaults to the input path with the extension replaced by `.musicxml`.
- `overwrite` -- if false (default), skip conversion when the output file
already exists.

#### Returns

Scalar string -- the output file path if conversion succeeded, or undef on
failure.

#### Side Effects

Writes the output file.  Updates diagnostic counters.
Croaks on fatal errors; non-fatal issues are issued as warnings.

#### Usage Example

```perl
my $out = $c->convert(input => 'Pilgrim.nwc', overwrite => 1);
```

#### Api Specification

##### Input

```
input     : SCALAR (path, required)
output    : SCALAR (path, optional)
overwrite : boolean (optional, default false)
```

##### Output

```
SCALAR (output path) or undef
```

#### Messages

| Code               | Meaning                              | Resolution                    |
|--------------------|--------------------------------------|-------------------------------|
| error\_no\_input     | `input` parameter missing           | Provide input path            |
| error\_file\_not\_found| Input file does not exist           | Check path                    |
| error\_decode       | NWC decoding stage failed            | See error detail              |
| error\_parse        | NWCTXT parsing stage failed          | See error detail              |
| error\_generate     | MusicXML generation failed           | See error detail              |
| error\_write        | Cannot write output file             | Check permissions / disk space|

### Batch\_Convert

Convert multiple `.nwc` files, optionally into a separate output directory.

#### Purpose

Processes a list of input files in sequence.  Failures on individual files
are caught and counted; conversion continues with remaining files.
A summary is printed at the end.

#### Arguments

Named parameters:

- `inputs`     -- arrayref of input file paths (required).
- `output_dir` -- directory for output files (optional; defaults to each
file's own directory).
- `overwrite`  -- overwrite existing output files (boolean, default 0).
- `recursive`  -- preserve relative directory structure under
`output_dir` (boolean, default 0).
- `base_dir`   -- base directory stripped when computing relative paths
for recursive mode (optional).

#### Returns

Hashref: `{ processed => N, successful => N, warnings => N, failed => N }`.

#### Side Effects

Writes output files.  Prints a summary to STDERR.
Does not croak on per-file failures.

#### Usage Example

```perl
$c->batch_convert(
    inputs     => [ glob('scores/**/*.nwc') ],
    output_dir => 'musicxml',
    recursive  => 1,
    base_dir   => 'scores',
    overwrite  => 1,
);
```

#### Api Specification

##### Input

```
inputs     : ARRAYREF of SCALAR paths (required)
output_dir : SCALAR (optional)
overwrite  : SCALAR bool (optional, default 0)
recursive  : SCALAR bool (optional, default 0)
base_dir   : SCALAR (optional)
```

##### Output

```
HASHREF { processed:int, successful:int, warnings:int, failed:int }
```

### Diagnostics

Return the `Music::NWC2MusicXML::Diagnostics` instance.

## Diagnostics

#### Messages

| Code                 | Meaning                             | Resolution                        |
|----------------------|-------------------------------------|-----------------------------------|
| error\_no\_input       | input parameter missing             | Provide input path                |
| error\_file\_not\_found | Input file absent                   | Check path and permissions        |
| error\_decode         | NWC decoding stage failed           | See embedded error                |
| error\_parse          | NWCTXT parsing stage failed         | See embedded error                |
| error\_generate       | MusicXML generation failed          | See embedded error                |
| error\_write          | Cannot write output                 | Check disk space and permissions  |
| error\_mkdir          | Cannot create output directory      | Check parent directory permissions|

## Limitations

- Parallel batch processing is not implemented; files are converted sequentially.
- MusicXML validation against the official DTD/XSD is not performed
internally; use an external validator with `--validate`.
- Tuplet time-modification and multi-voice `RestChord` records are not yet
emitted (Phase 4 items).

## Dependencies

[Object::Configure](https://metacpan.org/pod/Object%3A%3AConfigure) is used to allow callers to pre-configure converter
defaults at the class level (e.g. `Music::NWC2MusicXML->configure(log_level => 'verbose')`).
This means a consuming application can set defaults once and `new` will
honour them without repeating the arguments on each call.

## See Also

- [Configure an Object at Runtime](https://metacpan.org/pod/Object%3A%3AConfigure)
- [Test Dashboard](https://nigelhorne.github.io/nwc2musicxml/coverage/)

## Support

This module is provided as-is without any warranty.

## Formal Specification

### New

```
[ConverterInit]
  log_level   : LogLevel
  validate    : Boolean
  diagnostics : Diagnostics
  nwc_decoder : NWCDecoder
  parser      : Parser
  generator   : Generator

(placeholder -- populate with Z calculus as implementation matures)
```

### Convert

```
[Convert]
  input?  : FileName
  output? : FileName
  ----------
  result! : FileName | Undef

(placeholder)
```

### Batchconvert

```
[BatchConvert]
  inputs?     : seq FileName
  output_dir? : DirName
  ----------
  summary!    : BatchSummary

(placeholder)
```

## Author

Nigel Horne `<njh@nigelhorne.com>`

## License

Copyright 2026 Nigel Horne.

Usage is subject to the GPL2 licence terms.
If you use it,
please let me know.
