Split drum track operation

This commit is contained in:
Andrey M. Tokarev 2013-08-11 23:54:36 +04:00
parent fcf89b0c3a
commit 88e0f46f6b
4 changed files with 109 additions and 7 deletions

View file

@ -239,11 +239,11 @@ void sortNotesByLength(std::multimap<Fraction, MidiChord> &chords)
// and separate them into different chords
// so all notes inside every chord will have equal lengths
void splitUnequalChords(QList<MTrack> &tracks)
void splitUnequalChords(std::multimap<int, MTrack> &tracks)
{
for (auto &track: tracks) {
std::vector<std::pair<Fraction, MidiChord>> newChordEvents;
auto &chords = track.chords;
auto &chords = track.second.chords;
sortNotesByLength(chords);
for (auto &chordEvent: chords) {
auto &chord = chordEvent.second;
@ -299,9 +299,10 @@ void removeEmptyTuplets(MTrack &track)
}
}
void splitDrumVoices(QList<MTrack> &tracks)
void splitDrumVoices(std::multimap<int, MTrack> &tracks)
{
for (MTrack &track: tracks) {
for (auto &trackItem: tracks) {
MTrack &track = trackItem.second;
std::vector<std::pair<Fraction, MidiChord>> newChordEvents;
auto &chords = track.chords;
Drumset* drumset = track.mtrack->drumTrack() ? smDrumset : 0;
@ -350,6 +351,60 @@ void splitDrumVoices(QList<MTrack> &tracks)
}
}
std::map<int, MTrack> splitDrumTrack(MTrack &drumTrack)
{
std::map<int, MTrack> newTracks; // <percussion note pitch, track>
if (drumTrack.chords.empty())
return newTracks;
while (!drumTrack.chords.empty()) {
int pitch = -1;
MTrack *curTrack = nullptr;
for (auto it = drumTrack.chords.begin(); it != drumTrack.chords.end(); ) {
MidiChord &chord = it->second;
for (auto noteIt = chord.notes.begin(); noteIt != chord.notes.end(); ) {
if (pitch == -1) {
pitch = noteIt->pitch;
MTrack newTrack = drumTrack;
newTrack.chords.clear();
newTrack.tuplets.clear();
newTrack.name = smDrumset->name(pitch);
newTracks.insert({pitch, newTrack});
curTrack = &newTracks.find(pitch)->second;
}
if (noteIt->pitch == pitch) {
MidiChord newChord;
newChord.voice = chord.voice;
newChord.notes.push_back(*noteIt);
curTrack->chords.insert({it->first, newChord});
auto tupletIt = drumTrack.findTuplet(chord.voice, it->first,
noteIt->len);
if (tupletIt != drumTrack.tuplets.end()) {
auto newTupletIt = curTrack->findTuplet(newChord.voice, it->first,
noteIt->len);
if (newTupletIt == curTrack->tuplets.end()) {
MidiTuplet::TupletData newTupletData = tupletIt->second;
newTupletData.voice = newChord.voice;
curTrack->tuplets.insert({tupletIt->first, newTupletData});
}
}
noteIt = chord.notes.erase(noteIt);
continue;
}
++noteIt;
}
if (chord.notes.isEmpty()) {
it = drumTrack.chords.erase(it);
continue;
}
++it;
}
}
return newTracks;
}
void quantizeAllTracks(std::multimap<int, MTrack> &tracks,
TimeSigMap *sigmap,
const Fraction &lastTick)
@ -397,7 +452,8 @@ void MTrack::processMeta(int tick, const MidiEvent& mm)
break;
case META_TRACK_NAME:
name = (const char*)data;
if (name.isEmpty())
name = (const char*)data;
break;
case META_TEMPO:
@ -1393,6 +1449,23 @@ QList<TrackMeta> getTracksMeta(const std::multimap<int, MTrack> &tracks,
return tracksMeta;
}
void splitDrumTracks(std::multimap<int, MTrack> &tracks)
{
for (auto it = tracks.begin(); it != tracks.end(); ++it) {
if (!it->second.mtrack->drumTrack())
continue;
auto operations = preferences.midiImportOperations.trackOperations(
it->second.indexOfOperation);
if (!operations.splitDrums)
continue;
auto newTracks = splitDrumTrack(it->second);
int trackIndex = it->first;
it = tracks.erase(it);
for (const auto &newTrack: newTracks)
it = tracks.insert({trackIndex, newTrack.second});
}
}
void convertMidi(Score *score, const MidiFile *mf)
{
Fraction lastTick;
@ -1404,10 +1477,11 @@ void convertMidi(Score *score, const MidiFile *mf)
quantizeAllTracks(tracks, sigmap, lastTick);
removeOverlappingNotes(tracks);
splitIntoLeftRightHands(tracks);
splitUnequalChords(tracks);
splitDrumVoices(tracks);
splitDrumTracks(tracks);
// no more track insertion/reordering/deletion from now
QList<MTrack> trackList = prepareTrackList(tracks);
splitUnequalChords(trackList);
splitDrumVoices(trackList);
createInstruments(score, trackList);
createMeasures(lastTick, score);
createNotes(lastTick, trackList, mf->midiType());

View file

@ -34,6 +34,8 @@ struct MidiOperation
CHANGE_CLEF,
SPLIT_DRUMS,
SWING
} type;

View file

@ -28,6 +28,7 @@ struct Controller {
Node *septuplets = nullptr;
Node *nonuplets = nullptr;
Node *multipleVoices = nullptr;
Node *splitDrums = nullptr;
int trackCount = 0;
bool isDrumTrack = false;
@ -175,6 +176,15 @@ OperationsModel::OperationsModel()
root->children.push_back(std::unique_ptr<Node>(changeClef));
Node *splitDrums = new Node;
splitDrums->name = "Split drum set";
splitDrums->oper.type = MidiOperation::Type::SPLIT_DRUMS;
splitDrums->oper.value = TrackOperations().splitDrums;
splitDrums->parent = root.get();
root->children.push_back(std::unique_ptr<Node>(splitDrums));
controller->splitDrums = splitDrums;
Node *doLHRH = new Node;
doLHRH->name = "LH/RH separation";
doLHRH->oper.type = MidiOperation::Type::DO_LHRH_SEPARATION;
@ -483,6 +493,9 @@ void setNodeOperations(Node *node, const DefinedTrackOperations &opers)
case MidiOperation::Type::CHANGE_CLEF:
node->oper.value = opers.opers.changeClef; break;
case MidiOperation::Type::SPLIT_DRUMS:
node->oper.value = opers.opers.splitDrums; break;
}
}
for (const auto &nodePtr: node->children)
@ -569,6 +582,8 @@ bool Controller::updateNodeDependencies(Node *node, bool forceUpdate)
if (forceUpdate) {
if (LHRHdoIt)
LHRHdoIt->visible = !isDrumTrack;
if (splitDrums)
splitDrums->visible = isDrumTrack;
if (multipleVoices)
multipleVoices->visible = !isDrumTrack;
result = true;

View file

@ -83,6 +83,9 @@ void TracksModel::setTrackOperation(int trackIndex, MidiOperation::Type operType
case MidiOperation::Type::DO_LHRH_SEPARATION:
trackData.opers.LHRH.doIt = operValue.toBool();
break;
case MidiOperation::Type::SPLIT_DRUMS:
trackData.opers.splitDrums = operValue.toBool();
break;
case MidiOperation::Type::LHRH_METHOD:
trackData.opers.LHRH.method = (MidiOperation::LHRHMethod)operValue.toInt();
break;
@ -178,6 +181,14 @@ DefinedTrackOperations TracksModel::trackOperations(int row) const
}
}
// MidiOperation::Type::SPLIT_DRUMS
for (int i = 1; i != trackCount_; ++i) {
if (tracksData_[i].opers.splitDrums != opers.opers.splitDrums) {
opers.undefinedOpers.insert((int)MidiOperation::Type::SPLIT_DRUMS);
break;
}
}
// MidiOperation::Type::LHRH_METHOD
for (int i = 1; i != trackCount_; ++i) {
if (tracksData_[i].opers.LHRH.method != opers.opers.LHRH.method) {