Skip to content

Commit

Permalink
Add CommonJS tests
Browse files Browse the repository at this point in the history
  • Loading branch information
infojunkie committed Oct 21, 2024
1 parent a35a41e commit 3360407
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 29 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ iReal Pro to MusicXML converter.
[Check out the demo!](https://blog.karimratib.me/demos/chirp/) You can upload one of the [iReal Pro main playlists](https://www.irealpro.com/main-playlists/) as a test.

# Installation
- Install `xmllint` (included in [libxml2](http://www.xmlsoft.org/) on most platforms)
- Install `xmllint` (included in [libxml2](http://www.xmlsoft.org/) on most platforms) - only needed for validation
- `npm install && npm run build`
- `npm test`

Expand Down Expand Up @@ -60,21 +60,21 @@ The chords found in the iReal Pro song are translated to their MusicXML represen
An additional detail is the handling of "alternate chords" that can be specified in iReal Pro - these also [will be handled in this converter eventually](https://github.com/infojunkie/ireal-musicxml/issues/2).

## Rhythmic information
Because iReal Pro uses a fixed grid for each bar, rhythmic assumptions need to be made, [both in the iReal Pro app itself](https://www.irealb.com/forums/showthread.php?25161-Using-empty-cells-to-control-chord-duration) and in this converter. The [timing algorithm is described in this blog post](https://blog.karimratib.me/2020/11/30/ireal-musicxml.html#emulating-the-ireal-pro-playback-model), and some [follow-up works remains to be done](https://github.com/infojunkie/ireal-musicxml/issues/54).
Because iReal Pro uses a fixed grid for each bar, timing assumptions need to be made about chord onsets, [both in the iReal Pro app itself](https://www.irealb.com/forums/showthread.php?25161-Using-empty-cells-to-control-chord-duration) and in this converter. The [timing algorithm is described in this blog post](https://blog.karimratib.me/2020/11/30/ireal-musicxml.html#emulating-the-ireal-pro-playback-model), and some [follow-up works remains to be done](https://github.com/infojunkie/ireal-musicxml/issues/54).

## Layout and styling information
The styling and layout of lead sheets has evolved over time to improve their accessibility in live situations, where musical information needs to be concise and readable. This includes the following score customizations:
iReal Pro has a distinctive visual sheet style that aims to enhance readability. This converter attempts to recreate this visual style:
- Using rhythmic notation or slash notation to display the chords
- Enhancing the size of the noteheads and chord names
- Increasing the size of noteheads and chord names
- Removing uneeded elements from the score, such as clef and staff lines
- Respecting the original positioning of measures to best reflect the structure of the song
- Fitting the score on one page where at all possible

The MusicXML layouting support is expressive enough to represent all these customizations. Unfortunately, existing engraving software do not support the full set of MusicXML directives, thus being only partially able to recreate the intended scores. The (heavy-handed) solution is to go one additional step to [manually convert the MusicXML output from this present converter to the native format of the desired engraving software](https://github.com/infojunkie/ireal-musicxml/issues/16).
MusicXML support for layout and style is expressive enough to represent all these customizations. Unfortunately, existing engraving software do not support the full set of MusicXML directives, thus recreating the intended style only partially. The (heavy-handed) solution is to go one additional step and [convert the MusicXML output from this present converter to the native format of the desired engraving software](https://github.com/infojunkie/ireal-musicxml/issues/16).

## Backing track information
The backing track patterns of the iReal Pro styles are not documented. Therefore, a mapping needs to be made to support a play back of the converted MusicXML scores that replicates or approximates the original iReal Pro playback. This is achieved in 2 phases:
The backing track patterns of the iReal Pro styles are not documented. Therefore, a mapping is done to support playing back the converted MusicXML scores that replicates or approximates the original iReal Pro playback. This is achieved in 2 phases:

- First, the MusicXML `sound/play/other-play[@type = 'groove']` element is used to capture the playback style as specified in the iReal Pro song. Because MusicXML does not currently feature a dedicated element to specify the performance style, the generic `other-play` element was [selected to capture this information](https://github.com/w3c/musicxml/discussions/449).

- Next, the downstream playback component interprets the above MusicXML element to generate a backing track for the score. This is done in the [`musicxml-midi`](https://github.com/infojunkie/musicxml-midi) component that utilizes an extensive library of "grooves" to map the incoming iReal Pro style to MIDI accompaniment tracks.
- Next, the downstream playback component interprets the above MusicXML element to generate a backing track for the score. This is done in [`musicxml-midi`](https://github.com/infojunkie/musicxml-midi) which utilizes an extensive library of "grooves" to map the incoming iReal Pro style to MIDI accompaniment tracks.
9 changes: 5 additions & 4 deletions build/ireal-musicxml.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ var package_default = {
},
homepage: "https://github.com/infojunkie/ireal-musicxml",
type: "module",
types: "./src/types/ireal-musicxml.d.ts",
types: "./build/ireal-musicxml.d.ts",
files: [
"LICENSE.txt",
"build/*",
Expand All @@ -402,12 +402,13 @@ var package_default = {
require: "./build/ireal-musicxml.cjs"
},
scripts: {
build: "npm run build:esm && npm run build:cjs",
build: "npm run build:esm && npm run build:cjs && npm run build:d.ts",
"build:d.ts": "cp src/types/* build/",
"build:esm": "esbuild src/lib/index.js --bundle --format=esm --sourcemap --outfile=build/ireal-musicxml.js",
"build:cjs": "esbuild src/lib/index.js --bundle --platform=node --packages=external --outfile=build/ireal-musicxml.cjs",
test: "npm run test:lint && npm run test:spec && npm run test:ts",
test: "npm run build && npm run test:lint && npm run test:spec && npm run test:ts",
"test:spec": 'node --test --test-name-pattern="${TEST:-.*}"',
"test:ts": "npm run build && node --test --loader=ts-node/esm --require ts-node/register test/*.spec.ts",
"test:ts": "node --test --loader=ts-node/esm --require ts-node/register test/*.spec.ts",
"test:lint": "eslint src --fix"
},
devDependencies: {
Expand Down
2 changes: 1 addition & 1 deletion build/ireal-musicxml.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class Playlist {
export class Song {
/**
* Song parser. Parsing occurs in this constructor.
* Refer to https://github.com/infojunkie/ireal-musicxml/blob/main/doc/ireal.md for structure details.
* Refer to https://github.com/infojunkie/ireal-musicxml/blob/main/doc/irealpro.md for structure details.
* @param ireal iReal Pro encoding for a single song
* @param oldFormat Flag to indicate that the encoding above corresponds to the older irealbook:// format.
*/
Expand Down
9 changes: 5 additions & 4 deletions build/ireal-musicxml.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions build/ireal-musicxml.js.map

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"homepage": "https://github.com/infojunkie/ireal-musicxml",
"type": "module",
"types": "./src/types/ireal-musicxml.d.ts",
"types": "./build/ireal-musicxml.d.ts",
"files": [
"LICENSE.txt",
"build/*",
Expand All @@ -24,12 +24,13 @@
"require": "./build/ireal-musicxml.cjs"
},
"scripts": {
"build": "npm run build:esm && npm run build:cjs",
"build": "npm run build:esm && npm run build:cjs && npm run build:d.ts",
"build:d.ts": "cp src/types/* build/",
"build:esm": "esbuild src/lib/index.js --bundle --format=esm --sourcemap --outfile=build/ireal-musicxml.js",
"build:cjs": "esbuild src/lib/index.js --bundle --platform=node --packages=external --outfile=build/ireal-musicxml.cjs",
"test": "npm run test:lint && npm run test:spec && npm run test:ts",
"test": "npm run build && npm run test:lint && npm run test:spec && npm run test:ts",
"test:spec": "node --test --test-name-pattern=\"${TEST:-.*}\"",
"test:ts": "npm run build && node --test --loader=ts-node/esm --require ts-node/register test/*.spec.ts",
"test:ts": "node --test --loader=ts-node/esm --require ts-node/register test/*.spec.ts",
"test:lint": "eslint src --fix"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion src/types/ireal-musicxml.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class Playlist {
export class Song {
/**
* Song parser. Parsing occurs in this constructor.
* Refer to https://github.com/infojunkie/ireal-musicxml/blob/main/doc/ireal.md for structure details.
* Refer to https://github.com/infojunkie/ireal-musicxml/blob/main/doc/irealpro.md for structure details.
* @param ireal iReal Pro encoding for a single song
* @param oldFormat Flag to indicate that the encoding above corresponds to the older irealbook:// format.
*/
Expand Down
45 changes: 45 additions & 0 deletions test/index.spec.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const assert = require('node:assert');
const { describe, it } = require('node:test');
const fs = require('fs');
const {
Version,
convertSync,
LogLevel,
convert,
Playlist,
Converter
} = require('../build/ireal-musicxml.cjs');

describe('ireal-musicxml using CommonJS', () => {
it('accesses the library version', () => {
assert.strictEqual(Version.name, 'ireal-musicxml');
});

it('converts an iReal Pro song to MusicXML synchronously', () => {
const result = convertSync(fs.readFileSync('test/data/playlist.html', 'utf-8'), {
notation: "rhythmic",
logLevel: LogLevel.None
});
assert.strictEqual(result.name, 'Jazz Combo');
assert.strictEqual(result.songs.length, 6);
assert.notStrictEqual(result.songs[0].musicXml, '');
});

it('converts an iReal Pro song to MusicXML asynchronously', async () => {
const result = await convert(fs.readFileSync('test/data/playlist.html', 'utf-8'), {
notation: "slash",
logLevel: LogLevel.Error
});
assert.strictEqual(result.name, 'Jazz Combo');
assert.strictEqual(result.songs.length, 6);
assert.notStrictEqual(result.songs[0].musicXml, '');
});

it('parses and exports a playlist manually', () => {
const playlist = new Playlist(fs.readFileSync('test/data/playlist.html', 'utf-8'));
assert.strictEqual(playlist.name, 'Jazz Combo')
assert.strictEqual(playlist.songs.length, 6);
const musicXml = Converter.convert(playlist.songs[0]);
assert.notStrictEqual(musicXml, '');
});
});
17 changes: 11 additions & 6 deletions test/index.spec.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
import assert from 'node:assert';
import { describe, it } from 'node:test';
import fs from 'fs';
import * as iRealMusicXml from '../src/lib/index.js';
import {
convertSync,
convert,
Playlist,
Converter
} from '../src/lib/index.js';

describe('iRealMusicXml', () => {
describe('ireal-musicxml', () => {
it('converts an iReal Pro song to MusicXML synchronously', () => {
const result = iRealMusicXml.convertSync(fs.readFileSync('test/data/playlist.html', 'utf-8'));
const result = convertSync(fs.readFileSync('test/data/playlist.html', 'utf-8'));
assert.strictEqual(result.name, 'Jazz Combo')
assert.strictEqual(result.songs.length, 6);
assert.notStrictEqual(result.songs[0].musicXml, '');
});

it('converts an iReal Pro song to MusicXML asynchronously', async () => {
const result = await iRealMusicXml.convert(fs.readFileSync('test/data/playlist.html', 'utf-8'));
const result = await convert(fs.readFileSync('test/data/playlist.html', 'utf-8'));
assert.strictEqual(result.name, 'Jazz Combo')
assert.strictEqual(result.songs.length, 6);
assert.notStrictEqual(result.songs[0].musicXml, '');
});

it('parses and exports a playlist manually', () => {
const playlist = new iRealMusicXml.Playlist(fs.readFileSync('test/data/playlist.html', 'utf-8'));
const playlist = new Playlist(fs.readFileSync('test/data/playlist.html', 'utf-8'));
assert.strictEqual(playlist.name, 'Jazz Combo')
assert.strictEqual(playlist.songs.length, 6);
const musicXml = iRealMusicXml.Converter.convert(playlist.songs[0]);
const musicXml = Converter.convert(playlist.songs[0]);
assert.notStrictEqual(musicXml, '');
});
});

0 comments on commit 3360407

Please sign in to comment.