msms
Version:
MuseScore Measure Shuffler
90 lines (78 loc) • 2.19 kB
JavaScript
// imports
const convert = require('xml-js');
const fs = require('fs');
/**
* Configuration start
*/
const MAX = 100; // how many combinations to generate
const ADJOK = false; // is it ok to have adjacent repeated motives
const motives = {
A: [2, 3], // Motive A is measures 2 and 3
B: [4, 5],
C: [8],
D: [10, 11],
E: [16],
F: [17],
G: [19],
H: [22],
I: [23],
};
// we want motive A to happen twice in the new score,
// motive C to happen 4 times and so on
const distribution = 'AADDFFEEEBGHICCCC';
const OUT = 'out/';
/**
* Configuration end
*/
// read the "template" score
const xml = fs.readFileSync('Template.mscx', 'utf8');
const options = {compact: true, ignoreComment: true, spaces: 4};
const source = convert.xml2js(xml, options);
// an array of all measures
const origMeasures = source.museScore.Score.Staff.Measure;
// extract the patterns from the template
const patterns = {};
Object.keys(motives).forEach((letter) => {
patterns[letter] = [];
motives[letter].forEach((m) => {
patterns[letter].push(origMeasures[m - 1]); // measures start from 1, arrays from 0
});
});
function checkAdjecents(combo) {
if (ADJOK) {
return true;
}
for (let i = 1; i < combo.length; i++) {
if (combo[i] === combo[i - 1]) {
return false;
}
}
return true;
}
// generate MAX random combinations
const combinations = new Set();
let these = distribution.split('');
while (combinations.size < MAX) {
these.sort(() => 0.5 - Math.random());
if (checkAdjecents(these)) {
combinations.add(these.join(''));
}
}
if (!fs.existsSync(OUT)) {
fs.mkdirSync(OUT);
}
combinations.forEach((combo) => {
// first and last measures are always the same
const last = origMeasures[origMeasures.length - 1];
const first = origMeasures[0];
const newMeasures = [first];
combo.split('').forEach((letter) => {
patterns[letter].forEach((_, idx) => {
newMeasures.push(patterns[letter][idx]);
});
});
newMeasures.push(last);
source.museScore.Score.Staff.Measure = newMeasures;
source.museScore.Score.Staff.VBox.Text[0].text._text = combo;
fs.writeFileSync(OUT + combo + '.mscx', convert.js2xml(source, options));
});