Skip to content

Commit

Permalink
Add a command-line option for transposing a score
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitrio95 committed Jan 14, 2020
1 parent e5ec5e5 commit a35d658
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 2 deletions.
2 changes: 1 addition & 1 deletion libmscore/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ QString pitch2string(int v)
* tracks all the different valid intervals. They are arranged
* in diatonic then chromatic order.
*/
Interval intervalList[26] = {
Interval intervalList[intervalListSize] = {
// diatonic - chromatic
Interval(0, 0), // 0 Perfect Unison
Interval(0, 1), // 1 Augmented Unison
Expand Down
3 changes: 2 additions & 1 deletion libmscore/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ extern void transposeInterval(int pitch, int tpc, int* rpitch, int* rtpc,
Interval, bool useDoubleSharpsFlats);
extern int transposeTpc(int tpc, Interval interval, bool useDoubleSharpsFlats);

extern Interval intervalList[26];
constexpr int intervalListSize = 26;
extern Interval intervalList[intervalListSize];
extern int searchInterval(int steps, int semitones);
extern int chromatic2diatonic(int val);

Expand Down
109 changes: 109 additions & 0 deletions mscore/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3401,5 +3401,114 @@ bool MuseScore::exportScoreMetadata(const QString& inFilePath, const QString& ou
return true;
}

//---------------------------------------------------------
// exportTransposedScoreToJSON
//---------------------------------------------------------

bool MuseScore::exportTransposedScoreToJSON(const QString& inFilePath, const QString& transposeOptions, const QString& outFilePath)
{
QJsonDocument doc = QJsonDocument::fromJson(transposeOptions.toUtf8());
if (!doc.isObject()) {
qCritical("Transpose options JSON is not an object: %s", qUtf8Printable(transposeOptions));
return false;
}

QJsonObject options = doc.object();

TransposeMode mode;
const QString modeName = options["mode"].toString();
if (modeName == "by_key")
mode = TransposeMode::BY_KEY;
else if (modeName == "by_interval")
mode = TransposeMode::BY_INTERVAL;
else if (modeName == "diatonically")
mode = TransposeMode::DIATONICALLY;
else {
qCritical("Transpose: invalid \"mode\" option: %s", qUtf8Printable(modeName));
return false;
}

TransposeDirection direction;
const QString directionName = options["direction"].toString();
if (directionName == "up")
direction = TransposeDirection::UP;
else if (directionName == "down")
direction = TransposeDirection::DOWN;
else if (directionName == "closest")
direction = TransposeDirection::CLOSEST;
else {
qCritical("Transpose: invalid \"direction\" option: %s", qUtf8Printable(directionName));
return false;
}

constexpr int defaultKey = int(Key::INVALID);
const Key targetKey = Key(options["targetKey"].toInt(defaultKey));
if (mode == TransposeMode::BY_KEY) {
const bool targetKeyValid = int(Key::MIN) <= int(targetKey) && int(targetKey) <= int(Key::MAX);
if (!targetKeyValid) {
qCritical("Transpose: invalid targetKey: %d", int(targetKey));
return false;
}
}

const int transposeInterval = options["transposeInterval"].toInt(-1);
if (mode != TransposeMode::BY_KEY) {
const bool transposeIntervalValid = -1 < transposeInterval && transposeInterval < intervalListSize;
if (!transposeIntervalValid) {
qCritical("Transpose: invalid transposeInterval: %d", transposeInterval);
return false;
}
}

const bool transposeKeySignatures = options["transposeKeySignatures"].toBool();
const bool transposeChordNames = options["transposeChordNames"].toBool();
const bool useDoubleSharpsFlats = options["useDoubleSharpsFlats"].toBool();

std::unique_ptr<MasterScore> score(mscore->readScore(inFilePath));
if (!score)
return false;

score->switchToPageMode();
score->cmdSelectAll();

score->startCmd();
const bool transposed = score->transpose(mode, direction, targetKey, transposeInterval, transposeKeySignatures, transposeChordNames, useDoubleSharpsFlats);
if (!transposed) {
qCritical("Transposition failed");
return false;
}
score->endCmd();

bool res = true;
CustomJsonWriter jsonWriter(outFilePath);

// export mscz
{
jsonWriter.addKey("mscz");
bool saved = false;
QTemporaryFile tmpFile(QString("%1_transposed.XXXXXX.mscz").arg(score->title()));
if (tmpFile.open()) {
QFileInfo fi(tmpFile.fileName());
saved = score->Score::saveCompressedFile(&tmpFile, fi, /* onlySelection */ false);
tmpFile.close();
tmpFile.open();
jsonWriter.addValue(tmpFile.readAll().toBase64());
tmpFile.close();
}

if (!saved) {
qCritical("Transpose: adding mscz failed");
jsonWriter.addValue("");
res = false;
}
}

// export score pdf
jsonWriter.addKey("pdf");
jsonWriter.addValue(exportPdfAsJSON(score.get()), /* lastJsonElement */ true);

return res;
}

}

12 changes: 12 additions & 0 deletions mscore/musescore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ bool exportScoreMedia = false;
bool exportScoreMeta = false;
bool exportScoreMp3 = false;
bool exportScorePartsPdf = false;
static bool exportTransposedScore = false;
static QString transposeExportOptions;

QString mscoreGlobalShare;

Expand Down Expand Up @@ -3730,6 +3732,8 @@ static bool processNonGui(const QStringList& argv)
return mscore->exportMp3AsJSON(argv[0]);
else if (exportScorePartsPdf)
return mscore->exportPartsPdfsToJSON(argv[0]);
else if (exportTransposedScore)
return mscore->exportTransposedScoreToJSON(argv[0], transposeExportOptions);

if (pluginMode) {
loadScores(argv);
Expand Down Expand Up @@ -7257,6 +7261,7 @@ MuseScoreApplication::CommandLineParseResult MuseScoreApplication::parseCommandL
parser.addOption(QCommandLineOption("score-meta", "Export score metadata to JSON document and print it to stdout"));
parser.addOption(QCommandLineOption("score-mp3", "Generates mp3 for the given score and export the data to a single JSON file, print it to std out"));
parser.addOption(QCommandLineOption("score-parts-pdf", "Generates parts data for the given score and export the data to a single JSON file, print it to std out"));
parser.addOption(QCommandLineOption("score-transpose", "Transposes the given score and exports the data to a single JSON file, prints it to std out", "options"));
parser.addOption(QCommandLineOption("raw-diff", "Print a raw diff for the given scores"));
parser.addOption(QCommandLineOption("diff", "Print a diff for the given scores"));

Expand Down Expand Up @@ -7422,6 +7427,13 @@ MuseScoreApplication::CommandLineParseResult MuseScoreApplication::parseCommandL
converterMode = true;
}

if (parser.isSet("score-transpose")) {
exportTransposedScore = true;
transposeExportOptions = parser.value("score-transpose");
MScore::noGui = true;
converterMode = true;
}

if (parser.isSet("raw-diff")) {
MScore::noGui = true;
rawDiffMode = true;
Expand Down
1 change: 1 addition & 0 deletions mscore/musescore.h
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,7 @@ class MuseScore : public QMainWindow, public MuseScoreCore {
bool exportScoreMetadata(const QString& inFilePath, const QString& outFilePath = "/dev/stdout");
bool exportMp3AsJSON(const QString& inFilePath, const QString& outFilePath = "/dev/stdout");
bool exportPartsPdfsToJSON(const QString& inFilePath, const QString& outFilePath = "/dev/stdout");
bool exportTransposedScoreToJSON(const QString& inFilePath, const QString& transposeOptions, const QString& outFilePath = "/dev/stdout");
/////////////////////////////////////////////////

void scoreUnrolled(MasterScore* original);
Expand Down

0 comments on commit a35d658

Please sign in to comment.