Split drum track operation
This commit is contained in:
parent
fcf89b0c3a
commit
88e0f46f6b
4 changed files with 109 additions and 7 deletions
|
@ -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());
|
||||
|
|
|
@ -34,6 +34,8 @@ struct MidiOperation
|
|||
|
||||
CHANGE_CLEF,
|
||||
|
||||
SPLIT_DRUMS,
|
||||
|
||||
SWING
|
||||
} type;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue