Skip to content

Commit

Permalink
Fix #54 Messy chord timings
Browse files Browse the repository at this point in the history
  • Loading branch information
infojunkie committed Nov 15, 2024
1 parent ec180fc commit 3862e93
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 101 deletions.
6 changes: 3 additions & 3 deletions build/ireal-musicxml.cjs

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions build/ireal-musicxml.cjs.map

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions build/ireal-musicxml.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions build/ireal-musicxml.js.map

Large diffs are not rendered by default.

104 changes: 59 additions & 45 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ireal-musicxml",
"version": "2.0.3",
"version": "2.0.4",
"description": "iReal Pro to MusicXML converter.",
"author": "Karim Ratib <[email protected]> (https://github.com/infojunkie)",
"license": "GPL-3.0-only",
Expand Down
71 changes: 49 additions & 22 deletions src/lib/converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,23 @@ export class Converter {
"8x": Converter.prototype.convertRepeatNx
};

static mapTime = {
"24": { beats: 2, beatType: 4, beatUnit: 1 },
"34": { beats: 3, beatType: 4, beatUnit: 0.5 },
"44": { beats: 4, beatType: 4, beatUnit: 1 },
"54": { beats: 5, beatType: 4, beatUnit: 1 },
"64": { beats: 6, beatType: 4, beatUnit: 1 },
"74": { beats: 7, beatType: 4, beatUnit: 1 },
"38": { beats: 3, beatType: 8, beatUnit: 1 },
"58": { beats: 5, beatType: 8, beatUnit: 1 },
"68": { beats: 6, beatType: 8, beatUnit: 1 },
"78": { beats: 7, beatType: 8, beatUnit: 1 },
"98": { beats: 9, beatType: 8, beatUnit: 1 },
"12": { beats: 12, beatType: 8, beatUnit: 3 },
"22": { beats: 2, beatType: 2, beatUnit: 1 },
"32": { beats: 3, beatType: 2, beatUnit: 0.5 },
};

static convert(song, options = {}) {
const realOptions = Object.assign({}, this.defaultOptions, options);
return new Converter(song, realOptions).convert();
Expand All @@ -143,7 +160,7 @@ export class Converter {
constructor(song, options) {
this.song = song;
this.options = options;
this.time = { beats: 4, beatType: 4, beatMin: 1 };
this.time = { beats: 4, beatType: 4, beatUnit: 1 };
this.fifths = null; // key signature's degree of fifths
this.measure = null; // current measure (of class Measure) being built
this.barRepeat = 0; // current bar number for single- and double-bar repeats
Expand Down Expand Up @@ -308,6 +325,22 @@ export class Converter {
this.fermata = false;
this.short = false;
}

clone() {
const chord = new Converter.Chord(
structuredClone(this.harmony),
structuredClone(this.notes),
structuredClone(this.ireal)
);
chord.spaces = this.spaces;
chord.fermata = this.fermata;
chord.short = this.short;
return chord;
}

beats() {
return this.short ? 1 : 1 + this.spaces;
}
};

convertMeasures() {
Expand Down Expand Up @@ -365,8 +398,7 @@ export class Converter {

// If we're still repeating bars, copy the previous bar now.
if (this.barRepeat) {
// TODO We should probably deep-copy those measures.
this.measure.chords = [...measures[measures.length-this.barRepeat-1].chords];
this.measure.chords = measures[measures.length-this.barRepeat-1].chords.map(chord => chord.clone());
}
}

Expand Down Expand Up @@ -447,8 +479,7 @@ export class Converter {
case 'x': {
// Handle single bar repeat.
this.barRepeat = 1;
// TODO We should probably deep-copy those measures.
this.measure.chords = [...measures[measures.length-this.barRepeat].chords];
this.measure.chords = measures[measures.length-this.barRepeat].chords.map(chord => chord.clone());
break;
}
case 'r': {
Expand All @@ -457,8 +488,7 @@ export class Converter {
// Here, we copy the next-to-last measure and set the repeat flag.
// The next opening measure will pick up the remaining measure.
this.barRepeat = 2;
// TODO We should probably deep-copy those measures.
this.measure.chords = [...measures[measures.length-this.barRepeat].chords];
this.measure.chords = measures[measures.length-this.barRepeat].chords.map(chord => chord.clone());
break;
}
case 'p':
Expand Down Expand Up @@ -882,20 +912,16 @@ export class Converter {
}

convertTime(time) {
let beats = parseInt(time[0]);
let beatType = parseInt(time[1]);
let beatMin = 1;
if (time === '12') {
beats = 12;
beatType = 8;
beatMin = 3;
}
this.time = { beats, beatType, beatMin };
this.time = this._map(
Converter.mapTime, time, {
beats: parseInt(time[0]), beatType: parseInt(time[1]), beatUnit: 1
}, `Unexpected time signature ${time}`
);
return {
'time': [{
'beats': beats
'beats': this.time.beats
}, {
'beat-type': beatType
'beat-type': this.time.beatType
}]
};
}
Expand All @@ -919,7 +945,7 @@ export class Converter {
this._log(LogLevel.Error, `Too many chords (${measure.chords.length} out of ${this.time.beats})`, measure);
return true;
}
let beats = measure.chords.reduce((beats, chord) => beats+1+chord.spaces, 0);
let beats = measure.chords.reduce((beats, chord) => beats + chord.beats() * this.time.beatUnit, 0);
if (!beats) {
this._log(LogLevel.Warn, `No chord found. Skipping current measure.`, measure);
return false;
Expand All @@ -931,7 +957,7 @@ export class Converter {
while (beats > this.time.beats) {
if (measure.chords[chordIndex].spaces > 0) {
measure.chords[chordIndex].spaces--;
beats--;
beats -= this.time.beatUnit;
}
chordIndex = (chordIndex + 1) % measure.chords.length;
}
Expand All @@ -943,20 +969,21 @@ export class Converter {
while (beats < this.time.beats) {
if (!measure.chords[chordIndex].short) {
measure.chords[chordIndex].spaces++;
beats++;
beats += this.time.beatUnit;
hasBeatsChangedInACycle = true;
}
chordIndex = (chordIndex + 1) % measure.chords.length;
if (chordIndex === 0 && !hasBeatsChangedInACycle) {
// We've made a complete cycle and beat count has not changed - break now.
this._log(LogLevel.Warn, `Cannot add more beats to the current measure.`, measure);
break;
}
}
}

// Adjust actual chord durations.
measure.chords = measure.chords.map(chord => {
chord.notes = this.calculateChordDuration(1+chord.spaces).map((duration, i, ds) =>
chord.notes = this.calculateChordDuration(chord.beats() * this.time.beatUnit).map((duration, i, ds) =>
this.convertChordNote(
duration,
i === ds.length - 1 ? chord.fermata : false, // Possible fermata on last chord note only
Expand Down
Loading

0 comments on commit 3862e93

Please sign in to comment.