How Musescore works?
I'm a Computer Science student from the Hong Kong University of Science and Technology. And now I'm doing a music related project in which I use Musescore to convert midi files into MusicXML. To ensure the validy of the project, I wish to know how Musescore does the conversion and what algorithms it is using. Is there any documentation I can refer to?
Comments
It is OpenSource, so you can see the code
In reply to It is OpenSource, so you can by Jojo-Schmitz
Thanks. But are the algoirthms documented?
In reply to Thanks. But are the by kevin.hy.lee
No. The algorithms are not documented.
You can check the sources and in particular importmidi.cpp and exportxml.cpp. As you may have guess, MuseScore imports MIDI in its own internal model and then convert this internal model to MusicXML. MusicXML is pretty solid and has a nice test suite. MIDI import is more difficult, and less solid... In particular, tuplets are not handled at all and ties are always favored instead of dotted notes without considering the beats. Any help is welcome :)
Thank you so much for the direction. It really helps!
I notice that in midi file.cpp, there's a function that finds chords.
Is it an algorithm published in a research paper?
//---------------------------------------------------------
// findChords
//---------------------------------------------------------
void MidiTrack::findChords()
{
EventList dl;
int n = _events.size();
Drumset* drumset;
if (_drumTrack)
drumset = smDrumset;
else
drumset = 0;
int jitter = 3; // tick tolerance for note on/off
for (int i = 0; i < n; ++i) {
Event* e = _events[i];
if (e == 0)
continue;
if (e->type() != ME_NOTE) {
dl.append(e);
continue;
}
int ontime = e->ontime();
int offtime = e->offtime();
Event* chord = new Event(ME_CHORD);
chord->setOntime(ontime);
chord->setDuration(e->duration());
chord->notes().append(e);
int voice = 0;
chord->setVoice(voice);
dl.append(chord);
_events[i] = 0;
bool useDrumset = false;
if (drumset) {
int pitch = e->pitch();
if (drumset->isValid(pitch)) {
useDrumset = true;
voice = drumset->voice(pitch);
chord->setVoice(voice);
}
}
for (int k = i + 1; k < n; ++k) {
if (_events[k] == 0 || _events[k]->type() != ME_NOTE)
continue;
Event* nn = _events[k];
if (nn->ontime() - jitter > ontime)
break;
if (qAbs(nn->ontime() - ontime) > jitter || qAbs(nn->offtime() - offtime) > jitter)
continue;
int pitch = nn->pitch();
if (useDrumset) {
if (drumset->isValid(pitch) && drumset->voice(pitch) == voice) {
chord->notes().append(nn);
_events[k] = 0;
}
}
else {
chord->notes().append(nn);
_events[k] = 0;
}
}
}
_events = dl;
}
In reply to I notice that in midi by kevin.hy.lee
I can't be 100% positive. Werner will have a more definitive answer since he wrote the code. But I guess the algorithm here is not from a research paper. After all it's quite "simple". It goes through the events and replace noteon/noteoff by "chord" events if the noteon/noteoff overlap including a little jitter.
Btw, the code you pasted here is from MuseScore 1.2 and can differ from the current development version.
In reply to I can't be 100% positive. by [DELETED] 5
I agree that it is quite simple.
But one stupid question, are the ontime and offtime in millisecond? So the integer jitter actually means 3 ms?
In reply to I agree that it is quite by kevin.hy.lee
No ontime and offtime are in MIDI ticks and the jitter as well.