diff options
-rw-r--r-- | muse2/muse/helper.cpp | 12 | ||||
-rw-r--r-- | muse2/muse/helper.h | 4 | ||||
-rw-r--r-- | muse2/muse/midiedit/dcanvas.cpp | 423 | ||||
-rw-r--r-- | muse2/muse/midiedit/dcanvas.h | 46 | ||||
-rw-r--r-- | muse2/muse/midiedit/dlist.cpp | 223 | ||||
-rw-r--r-- | muse2/muse/midiedit/dlist.h | 18 | ||||
-rw-r--r-- | muse2/muse/midiedit/drumedit.cpp | 96 | ||||
-rw-r--r-- | muse2/muse/midiedit/drumedit.h | 17 | ||||
-rw-r--r-- | muse2/muse/midiedit/drummap.cpp | 2 | ||||
-rw-r--r-- | muse2/muse/midiedit/drummap.h | 10 | ||||
-rw-r--r-- | muse2/muse/midiedit/prcanvas.cpp | 4 | ||||
-rw-r--r-- | muse2/muse/midiedit/prcanvas.h | 1 | ||||
-rw-r--r-- | muse2/muse/midiedit/scoreedit.cpp | 25 | ||||
-rw-r--r-- | muse2/muse/midiedit/scoreedit.h | 2 | ||||
-rw-r--r-- | muse2/muse/track.cpp | 42 | ||||
-rw-r--r-- | muse2/muse/track.h | 13 | ||||
-rw-r--r-- | muse2/muse/undo.cpp | 12 | ||||
-rw-r--r-- | muse2/muse/undo.h | 3 |
18 files changed, 791 insertions, 162 deletions
diff --git a/muse2/muse/helper.cpp b/muse2/muse/helper.cpp index 1a223bb3..255e8505 100644 --- a/muse2/muse/helper.cpp +++ b/muse2/muse/helper.cpp @@ -328,4 +328,16 @@ bool any_event_selected(const set<Part*>& parts, bool in_range) return !get_events(parts, in_range ? 3 : 1).empty(); } +bool drummaps_almost_equal(DrumMap* one, DrumMap* two, int len) +{ + for (int i=0; i<len; i++) + { + DrumMap tmp = one[i]; + tmp.mute=two[i].mute; + if (tmp!=two[i]) + return false; + } + return true; +} + } // namespace MusEUtil diff --git a/muse2/muse/helper.h b/muse2/muse/helper.h index e86a8949..b8ff391e 100644 --- a/muse2/muse/helper.h +++ b/muse2/muse/helper.h @@ -25,6 +25,8 @@ #include <set> +#include "drummap.h" + class QActionGroup; class QString; class QMenu; @@ -43,6 +45,8 @@ bool any_event_selected(const std::set<Part*>&, bool in_range=false); QMenu* populateAddSynth(QWidget* parent); QActionGroup* populateAddTrack(QMenu* addTrack); +bool drummaps_almost_equal(DrumMap* one, DrumMap* two, int drummap_size=128); + } #endif diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index 138511d6..34173780 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -34,12 +34,12 @@ #include <stdio.h> #include <values.h> #include <errno.h> -#include <set> //#include <sys/stat.h> //#include <sys/mman.h> #include "dcanvas.h" #include "midieditor.h" +#include "drumedit.h" #include "drummap.h" #include "event.h" #include "mpevent.h" @@ -50,18 +50,21 @@ #include "shortcuts.h" #include "icons.h" #include "functions.h" +#include "helper.h" #define CARET 10 #define CARET2 5 +using MusEGlobal::debugMsg; +using MusEGlobal::heavyDebugMsg; + //--------------------------------------------------------- // DEvent //--------------------------------------------------------- -DEvent::DEvent(Event e, Part* p) +DEvent::DEvent(Event e, Part* p, int instr) : CItem(e, p) { - int instr = e.pitch(); int y = instr * TH + TH/2; int tick = e.tick() + p->tick(); setPos(QPoint(tick, y)); @@ -79,7 +82,14 @@ void DrumCanvas::addItem(Part* part, Event& event) return; } - DEvent* ev = new DEvent(event, part); + int instr=pitch_and_track_to_instrument(event.pitch(), part->track()); + if (instr<0) + { + if (heavyDebugMsg) printf("trying to add event which is hidden or not in any part known to me\n"); + return; + } + + DEvent* ev = new DEvent(event, part, instr); items.add(ev); int diff = event.endTick()-part->lenTick(); @@ -101,6 +111,35 @@ DrumCanvas::DrumCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy, const char* name) : EventCanvas(pr, parent, sx, sy, name) { + drumEditor=dynamic_cast<DrumEdit*>(pr); + + old_style_drummap_mode = drumEditor->old_style_drummap_mode(); + + if (old_style_drummap_mode) + { + if (debugMsg) printf("DrumCanvas in old style drummap mode\n"); + ourDrumMap = drumMap; + must_delete_our_drum_map=false; + + instrument_number_mapping_t temp; + for (ciPart it=drumEditor->parts()->begin(); it!=drumEditor->parts()->end(); it++) + temp.tracks.insert(it->second->track()); + + for (int i=0;i<DRUM_MAPSIZE;i++) + { + temp.pitch=i; + instrument_map.append(temp); + } + } + else + { + if (debugMsg) printf("DrumCanvas in new style drummap mode\n"); + ourDrumMap=NULL; + rebuildOurDrumMap(); + } + + + setVirt(false); cursorPos= QPoint(0,0); _stepSize=1; @@ -114,6 +153,10 @@ DrumCanvas::DrumCanvas(MidiEditor* pr, QWidget* parent, int sx, DrumCanvas::~DrumCanvas() { //items.clearDelete(); + + if (must_delete_our_drum_map && ourDrumMap!=NULL) + delete [] ourDrumMap; + delete steprec; } //--------------------------------------------------------- @@ -193,7 +236,7 @@ Undo DrumCanvas::moveCanvasItems(MusEWidget::CItemList& items, int dp, int dx, D for(MusEWidget::iCItem ici = items.begin(); ici != items.end(); ++ici) { - MusEWidget::CItem* ci = ici->second; + MusEWidget::CItem* ci = ici->second; int x = ci->pos().x(); int y = ci->pos().y(); @@ -215,7 +258,7 @@ Undo DrumCanvas::moveCanvasItems(MusEWidget::CItemList& items, int dp, int dx, D doneList.push_back(ci); } ci->move(newpos); - + if(moving.size() == 1) itemReleased(curItem, newpos); @@ -256,10 +299,20 @@ UndoOp DrumCanvas::moveItem(MusEWidget::CItem* item, const QPoint& pos, DragType int ntick = editor->rasterVal(x) - part->tick(); if (ntick < 0) ntick = 0; - int npitch = y2pitch(pos.y()); + int nheight = y2pitch(pos.y()); Event newEvent = event.clone(); - - newEvent.setPitch(npitch); + + Track* dest_track = part->track(); + if (!instrument_map[nheight].tracks.contains(dest_track)) + { + printf ("TODO FIXME: tried to move an event into a different track. this is not supported yet, but will be soon. ignoring this one...\n"); + //FINDMICH + return UndoOp(); + } + + int ev_pitch = instrument_map[nheight].pitch; + + newEvent.setPitch(ev_pitch); newEvent.setTick(ntick); // Added by T356, removed by flo93: with operation groups, it happens that the @@ -280,13 +333,13 @@ UndoOp DrumCanvas::moveItem(MusEWidget::CItem* item, const QPoint& pos, DragType MusEWidget::CItem* DrumCanvas::newItem(const QPoint& p, int state) { int instr = y2pitch(p.y()); //drumInmap[y2pitch(p.y())]; - int velo = drumMap[instr].lv4; + int velo = ourDrumMap[instr].lv4; if (state == Qt::ShiftModifier) - velo = drumMap[instr].lv3; + velo = ourDrumMap[instr].lv3; else if (state == Qt::ControlModifier) - velo = drumMap[instr].lv2; + velo = ourDrumMap[instr].lv2; else if (state == (Qt::ControlModifier | Qt::ShiftModifier)) - velo = drumMap[instr].lv1; + velo = ourDrumMap[instr].lv1; int tick = editor->rasterVal(p.x()); return newItem(tick, instr, velo); } @@ -297,13 +350,22 @@ MusEWidget::CItem* DrumCanvas::newItem(const QPoint& p, int state) MusEWidget::CItem* DrumCanvas::newItem(int tick, int instrument, int velocity) { - tick -= curPart->tick(); - Event e(Note); - e.setTick(tick); - e.setPitch(instrument); - e.setVelo(velocity); - e.setLenTick(drumMap[instrument].len); - return new DEvent(e, curPart); + if (!old_style_drummap_mode && !instrument_map[instrument].tracks.contains(curPart->track())) + { + printf("FINDMICH: tried to create a new Item which cannot be inside the current track. returning NULL\n"); + return NULL; + } + else + { + tick -= curPart->tick(); + Event e(Note); + e.setTick(tick); + e.setPitch(instrument_map[instrument].pitch); + e.setVelo(velocity); + e.setLenTick(ourDrumMap[instrument].len); + + return new DEvent(e, curPart, instrument); + } } //--------------------------------------------------------- @@ -326,7 +388,9 @@ void DrumCanvas::newItem(MusEWidget::CItem* item, bool noSnap) { } void DrumCanvas::newItem(MusEWidget::CItem* item, bool noSnap, bool replace) - { +{ + if (item) + { DEvent* nevent = (DEvent*) item; Event event = nevent->event(); int x = item->x(); @@ -334,7 +398,7 @@ void DrumCanvas::newItem(MusEWidget::CItem* item, bool noSnap, bool replace) x = editor->rasterVal(x); event.setTick(x - nevent->part()->tick()); int npitch = event.pitch(); - event.setPitch(npitch); + //event.setPitch(npitch); // commented out by flo: has no effect // // check for existing event @@ -370,7 +434,7 @@ void DrumCanvas::newItem(MusEWidget::CItem* item, bool noSnap, bool replace) { operations.push_back(UndoOp(UndoOp::AddEvent,event, part, false, false)); - if (diff > 0)// part must be extended? + if (diff > 0) // part must be extended? { schedule_resize_all_same_len_clone_parts(part, event.endTick(), operations); printf("newItem: extending\n"); @@ -380,7 +444,10 @@ void DrumCanvas::newItem(MusEWidget::CItem* item, bool noSnap, bool replace) song->applyOperationGroup(operations); songChanged(SC_EVENT_INSERTED); //this forces an update of the itemlist, which is neccessary //to remove "forbidden" events from the list again - } + } + else + printf("THIS SHOULD NEVER HAPPEN: DrumCanvas::newItem called with NULL item!\n"); +} //--------------------------------------------------------- // deleteItem @@ -435,7 +502,7 @@ void DrumCanvas::drawItem(QPainter&p, const MusEWidget::CItem*item, const QRect& else { int velo = e->event().velo(); - DrumMap* dm = &drumMap[y2pitch(y)]; //Get the drum item + DrumMap* dm = &ourDrumMap[y2pitch(y)]; //Get the drum item QColor color; if (velo < dm->lv1) color.setRgb(240, 240, 255); @@ -526,8 +593,8 @@ void DrumCanvas::drawTopItem(QPainter& p, const QRect&) int DrumCanvas::y2pitch(int y) const { int pitch = y/TH; - if (pitch >= DRUM_MAPSIZE) - pitch = DRUM_MAPSIZE-1; + if (pitch >= instrument_map.size()) + pitch = instrument_map.size()-1; return pitch; } @@ -636,7 +703,8 @@ void DrumCanvas::cmd(int cmd) DEvent* devent = (DEvent*)(k->second); Event event = devent->event(); Event newEvent = event.clone(); - newEvent.setLenTick(drumMap[event.pitch()].len); + // newEvent.setLenTick(drumMap[event.pitch()].len); + newEvent.setLenTick(ourDrumMap[y2pitch(devent->y())].len); // Indicate no undo, and do not do port controller values and clone parts. audio->msgChangeEvent(event, newEvent, devent->part(), false, false, false); } @@ -738,19 +806,19 @@ void DrumCanvas::dragLeaveEvent(QDragLeaveEvent*) // keyPressed - called from DList //--------------------------------------------------------- -void DrumCanvas::keyPressed(int index, int velocity) +void DrumCanvas::keyPressed(int index, int velocity) //FINDMICH later { // called from DList - play event - int port = drumMap[index].port; - int channel = drumMap[index].channel; - int pitch = drumMap[index].anote; + int port = ourDrumMap[index].port; + int channel = ourDrumMap[index].channel; + int pitch = ourDrumMap[index].anote; // play note: MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity); audio->msgPlayMidiEvent(&e); if (_steprec && pos[0] >= start_tick /* && pos[0] < end_tick [removed by flo93: this is handled in steprec->record] */ && curPart) - steprec->record(curPart,index,drumMap[index].len,editor->raster(),velocity,MusEGlobal::globalKeyState&Qt::ControlModifier,MusEGlobal::globalKeyState&Qt::ShiftModifier); + steprec->record(curPart,index,ourDrumMap[index].len,editor->raster(),velocity,MusEGlobal::globalKeyState&Qt::ControlModifier,MusEGlobal::globalKeyState&Qt::ShiftModifier); } @@ -758,12 +826,12 @@ void DrumCanvas::keyPressed(int index, int velocity) // keyReleased //--------------------------------------------------------- -void DrumCanvas::keyReleased(int index, bool) +void DrumCanvas::keyReleased(int index, bool) //FINDMICH later { // called from DList - silence playing event - int port = drumMap[index].port; - int channel = drumMap[index].channel; - int pitch = drumMap[index].anote; + int port = ourDrumMap[index].port; + int channel = ourDrumMap[index].channel; + int pitch = ourDrumMap[index].anote; // release note: MidiPlayEvent e(0, port, channel, 0x90, pitch, 0); @@ -775,7 +843,12 @@ void DrumCanvas::keyReleased(int index, bool) //--------------------------------------------------------- void DrumCanvas::mapChanged(int spitch, int dpitch) - { +{ + // spitch may be the same as dpitch! and something in here must be executed + // even if they're same (i assume it's song->update(SC_DRUMMAP)) (flo93) + + if (old_style_drummap_mode) + { Undo operations; std::vector< std::pair<Part*, Event*> > delete_events; std::vector< std::pair<Part*, Event> > add_events; @@ -853,7 +926,71 @@ void DrumCanvas::mapChanged(int spitch, int dpitch) song->applyOperationGroup(operations, false); // do not indicate undo song->update(SC_DRUMMAP); //this update is neccessary, as it's not handled by applyOperationGroup() + } + else // if (!old_style_drummap_mode) + { + if (dpitch!=spitch) + { + DrumMap dm_temp = ourDrumMap[spitch]; + instrument_number_mapping_t im_temp = instrument_map[spitch]; + + global_drum_ordering_t order_temp; + for (global_drum_ordering_t::iterator it=global_drum_ordering.begin(); it!=global_drum_ordering.end();) + { + if (im_temp.pitch==it->second && im_temp.tracks.contains(it->first)) + { + order_temp.push_back(*it); + it=global_drum_ordering.erase(it); + } + else + it++; + } + + // the instrument represented by instrument_map[dpitch] is always the instrument + // which will be immediately AFTER our dragged instrument + for (global_drum_ordering_t::iterator it=global_drum_ordering.begin(); it!=global_drum_ordering.end(); it++) + if (instrument_map[dpitch].pitch==it->second && instrument_map[dpitch].tracks.contains(it->first)) + { + while (!order_temp.empty()) + it=global_drum_ordering.insert(it, order_temp.takeLast()); + + break; + } + + + + + + if (dpitch > spitch) + { + for (int i=spitch; i<dpitch-1; i++) + { + ourDrumMap[i]=ourDrumMap[i+1]; + instrument_map[i]=instrument_map[i+1]; + } + + ourDrumMap[dpitch-1] = dm_temp; + instrument_map[dpitch-1] = im_temp; + } + else if (spitch > dpitch) + { + for (int i=spitch; i>dpitch; i--) + { + ourDrumMap[i]=ourDrumMap[i-1]; + instrument_map[i]=instrument_map[i-1]; + } + + ourDrumMap[dpitch] = dm_temp; + instrument_map[dpitch] = im_temp; + } } + + + song->update(SC_DRUMMAP); // this causes a complete rebuild of ourDrumMap + // which also handles the changed order in all + // other drum editors + } +} //--------------------------------------------------------- // resizeEvent @@ -905,6 +1042,7 @@ void DrumCanvas::modifySelected(MusEWidget::NoteInfo::ValType type, int delta) printf("DrumCanvas::modifySelected - MusEWidget::NoteInfo::VAL_VELOFF not implemented\n"); break; case MusEWidget::NoteInfo::VAL_PITCH: + if (old_style_drummap_mode) { int pitch = event.pitch() - delta; // Reversing order since the drumlist is displayed in increasing order if (pitch > 127) @@ -913,6 +1051,8 @@ void DrumCanvas::modifySelected(MusEWidget::NoteInfo::ValType type, int delta) pitch = 0; newEvent.setPitch(pitch); } + else + printf("DrumCanvas::modifySelected - MusEWidget::NoteInfo::VAL_PITCH not implemented for new style drum editors\n"); break; } song->changeEvent(event, newEvent, part); @@ -990,8 +1130,8 @@ void DrumCanvas::keyPress(QKeyEvent* event) return; } else if (key == shortcuts[SHRT_ADDNOTE_1].key) { - newItem(newItem(cursorPos.x(), cursorPos.y(), drumMap[cursorPos.y()].lv1),false,true); - keyPressed(cursorPos.y(), drumMap[cursorPos.y()].lv1); + newItem(newItem(cursorPos.x(), cursorPos.y(), ourDrumMap[cursorPos.y()].lv1),false,true); + keyPressed(cursorPos.y(), ourDrumMap[cursorPos.y()].lv1); keyReleased(cursorPos.y(), false); cursorPos.setX(getNextStep(cursorPos.x(),1, _stepSize)); selectCursorEvent(getEventAtCursorPos()); @@ -1000,8 +1140,8 @@ void DrumCanvas::keyPress(QKeyEvent* event) return; } else if (key == shortcuts[SHRT_ADDNOTE_2].key) { - newItem(newItem(cursorPos.x(), cursorPos.y(), drumMap[cursorPos.y()].lv2),false,true); - keyPressed(cursorPos.y(), drumMap[cursorPos.y()].lv2); + newItem(newItem(cursorPos.x(), cursorPos.y(), ourDrumMap[cursorPos.y()].lv2),false,true); + keyPressed(cursorPos.y(), ourDrumMap[cursorPos.y()].lv2); keyReleased(cursorPos.y(), false); cursorPos.setX(getNextStep(cursorPos.x(),1, _stepSize)); selectCursorEvent(getEventAtCursorPos()); @@ -1010,8 +1150,8 @@ void DrumCanvas::keyPress(QKeyEvent* event) return; } else if (key == shortcuts[SHRT_ADDNOTE_3].key) { - newItem(newItem(cursorPos.x(), cursorPos.y(), drumMap[cursorPos.y()].lv3),false,true); - keyPressed(cursorPos.y(), drumMap[cursorPos.y()].lv3); + newItem(newItem(cursorPos.x(), cursorPos.y(), ourDrumMap[cursorPos.y()].lv3),false,true); + keyPressed(cursorPos.y(), ourDrumMap[cursorPos.y()].lv3); keyReleased(cursorPos.y(), false); cursorPos.setX(getNextStep(cursorPos.x(),1, _stepSize)); selectCursorEvent(getEventAtCursorPos()); @@ -1020,8 +1160,8 @@ void DrumCanvas::keyPress(QKeyEvent* event) return; } else if (key == shortcuts[SHRT_ADDNOTE_4].key) { - newItem(newItem(cursorPos.x(), cursorPos.y(), drumMap[cursorPos.y()].lv4),false,true); - keyPressed(cursorPos.y(), drumMap[cursorPos.y()].lv4); + newItem(newItem(cursorPos.x(), cursorPos.y(), ourDrumMap[cursorPos.y()].lv4),false,true); + keyPressed(cursorPos.y(), ourDrumMap[cursorPos.y()].lv4); keyReleased(cursorPos.y(), false); cursorPos.setX(getNextStep(cursorPos.x(),1, _stepSize)); selectCursorEvent(getEventAtCursorPos()); @@ -1069,17 +1209,19 @@ Event *DrumCanvas::getEventAtCursorPos() { if (_tool != MusEWidget::CursorTool) return 0; - EventList* el = curPart->events(); - iEvent lower = el->lower_bound(cursorPos.x()-curPart->tick()); - iEvent upper = el->upper_bound(cursorPos.x()-curPart->tick()); - for (iEvent i = lower; i != upper; ++i) { - Event &ev = i->second; - if(!ev.isNote()) - continue; - if (ev.pitch() == cursorPos.y()) { - return &ev; + if (instrument_map[cursorPos.y()].tracks.contains(curPart->track())) + { + EventList* el = curPart->events(); + iEvent lower = el->lower_bound(cursorPos.x()-curPart->tick()); + iEvent upper = el->upper_bound(cursorPos.x()-curPart->tick()); + int curPitch = instrument_map[cursorPos.y()].pitch; + for (iEvent i = lower; i != upper; ++i) { + Event &ev = i->second; + if (ev.isNote() && ev.pitch() == curPitch) + return &ev; } } + // else or if the for loop didn't find anything return 0; } //--------------------------------------------------------- @@ -1103,9 +1245,13 @@ void DrumCanvas::selectCursorEvent(Event *ev) void DrumCanvas::moveAwayUnused() { - using std::set; + if (!old_style_drummap_mode) + { + printf("THIS SHOULD NEVER HAPPEN: DrumCanvas::moveAwayUnused() cannot be used in new style mode\n"); + return; + } - set<int> used; + QSet<int> used; for (MusEWidget::iCItem it=items.begin(); it!=items.end(); it++) { const Event& ev=it->second->event(); @@ -1115,7 +1261,7 @@ void DrumCanvas::moveAwayUnused() } int count=0; - for (set<int>::iterator it=used.begin(); it!=used.end();) + for (QSet<int>::iterator it=used.begin(); it!=used.end();) { while ((*it != count) && (used.find(count)!=used.end())) count++; @@ -1132,14 +1278,167 @@ void DrumCanvas::moveAwayUnused() //--------------------------------------------------------- // midiNote //--------------------------------------------------------- -void DrumCanvas::midiNote(int pitch, int velo) +void DrumCanvas::midiNote(int pitch, int velo) //FINDMICH later. { - if (MusEGlobal::debugMsg) printf("DrumCanvas::midiNote: pitch=%i, velo=%i\n", pitch, velo); + if (debugMsg) printf("DrumCanvas::midiNote: pitch=%i, velo=%i\n", pitch, velo); if (_midiin && _steprec && curPart && !audio->isPlaying() && velo && pos[0] >= start_tick - /* && pos[0] < end_tick [removed by flo93: this is handled in steprec->record] */ + /* && pos[0] < end_tick [removed by flo93: this is handled in steprec->record()] */ && !(MusEGlobal::globalKeyState & Qt::AltModifier)) { - steprec->record(curPart,drumInmap[pitch],drumMap[(int)drumInmap[pitch]].len,editor->raster(),velo,MusEGlobal::globalKeyState&Qt::ControlModifier,MusEGlobal::globalKeyState&Qt::ShiftModifier); + steprec->record(curPart,drumInmap[pitch],ourDrumMap[(int)drumInmap[pitch]].len,editor->raster(),velo,MusEGlobal::globalKeyState&Qt::ControlModifier,MusEGlobal::globalKeyState&Qt::ShiftModifier); } } + + +int DrumCanvas::pitch_and_track_to_instrument(int pitch, Track* track) +{ + for (int i=0; i<instrument_map.size(); i++) + if (instrument_map[i].tracks.contains(track) && instrument_map[i].pitch==pitch) + return i; + + printf("ERROR: DrumCanvas::pitch_and_track_to_instrument() called with invalid arguments!\n"); + return -1; +} + +void DrumCanvas::propagate_drummap_change(int instr) +{ + const QSet<Track*>& tracks=instrument_map[instr].tracks; + int index=instrument_map[instr].pitch; + + for (QSet<Track*>::const_iterator it = tracks.begin(); it != tracks.end(); it++) + dynamic_cast<MidiTrack*>(*it)->drummap()[index] = ourDrumMap[instr]; +} + + +void DrumCanvas::rebuildOurDrumMap() +{ + using MusEUtil::drummaps_almost_equal; + + if (!old_style_drummap_mode) + { + TrackList* tl=song->tracks(); + QList< QSet<Track*> > track_groups; + + instrument_map.clear(); + + for (ciTrack track = tl->begin(); track!=tl->end(); track++) + { + ciPart p_it; + for (p_it=drumEditor->parts()->begin(); p_it!=drumEditor->parts()->end(); p_it++) + if (p_it->second->track() == *track) + break; + + if (p_it!=drumEditor->parts()->end()) // if *track is represented by some part in this editor + { + bool inserted=false; + + switch (drumEditor->group_mode()) + { + case DrumEdit::GROUP_SAME_CHANNEL: + for (QList< QSet<Track*> >::iterator group=track_groups.begin(); group!=track_groups.end(); group++) + if ( ((MidiTrack*)*group->begin())->outChannel() == ((MidiTrack*)*track)->outChannel() && + ((MidiTrack*)*group->begin())->outPort() == ((MidiTrack*)*track)->outPort() && + (drummaps_almost_equal(((MidiTrack*)*group->begin())->drummap(), ((MidiTrack*)*track)->drummap())) ) + { + group->insert(*track); + inserted=true; + break; + } + break; + + case DrumEdit::GROUP_MAX: + for (QList< QSet<Track*> >::iterator group=track_groups.begin(); group!=track_groups.end(); group++) + if (drummaps_almost_equal(((MidiTrack*)*group->begin())->drummap(), ((MidiTrack*)*track)->drummap())) + { + group->insert(*track); + inserted=true; + break; + } + break; + + case DrumEdit::DONT_GROUP: + inserted=false; + break; + + default: + printf("THIS SHOULD NEVER HAPPEN: group_mode() is invalid!\n"); + inserted=false; + } + + if (!inserted) + { + QSet<Track*> temp; + temp.insert(*track); + track_groups.push_back(temp); + } + } + } + + // from now, we assume that every track_group's entry only groups tracks with identical + // drum maps, but not necessarily identical hide-lists together. + QList< std::pair<MidiTrack*,int> > ignore_order_entries; + for (global_drum_ordering_t::iterator order_it=global_drum_ordering.begin(); order_it!=global_drum_ordering.end(); order_it++) + { + // if this entry should be ignored, ignore it. + if (ignore_order_entries.contains(*order_it)) + continue; + + // look if we have order_it->first (the MidiTrack*) in any of our track groups + QList< QSet<Track*> >::iterator group; + for (group=track_groups.begin(); group!=track_groups.end(); group++) + if (group->contains(order_it->first)) + break; + + if (group!=track_groups.end()) // we have + { + int pitch=order_it->second; + + bool mute=true; + bool hidden=true; + for (QSet<Track*>::iterator track=group->begin(); track!=group->end() && (mute || hidden); track++) + { + if (dynamic_cast<MidiTrack*>(*track)->drummap()[pitch].mute == false) + mute=false; + + if (dynamic_cast<MidiTrack*>(*track)->drummap_hidden()[pitch] == false) + hidden=false; + } + + if (!hidden) + { + for (QSet<Track*>::iterator track=group->begin(); track!=group->end(); track++) + dynamic_cast<MidiTrack*>(*track)->drummap()[pitch].mute=mute; + + if (dynamic_cast<MidiTrack*>(*group->begin())->drummap()[pitch].anote != pitch) + printf("THIS SHOULD NEVER HAPPEN: track's_drummap[pitch].anote (%i)!= pitch (%i) !!!\n",dynamic_cast<MidiTrack*>(*group->begin())->drummap()[pitch].anote,pitch); + + instrument_map.append(instrument_number_mapping_t(*group, pitch)); + } + + for (QSet<Track*>::iterator track=group->begin(); track!=group->end(); track++) + ignore_order_entries.append(std::pair<MidiTrack*,int>(dynamic_cast<MidiTrack*>(*track), pitch)); + } + // else ignore it + } + + + // maybe delete and then populate ourDrumMap + + if (must_delete_our_drum_map && ourDrumMap!=NULL) + delete [] ourDrumMap; + + int size = instrument_map.size(); + ourDrumMap=new DrumMap[size]; + must_delete_our_drum_map=true; + + for (int i=0;i<size;i++) + ourDrumMap[i] = dynamic_cast<MidiTrack*>(*instrument_map[i].tracks.begin())->drummap()[instrument_map[i].pitch]; + + if (debugMsg) printf("rebuilt drummap, size is now %i\n",size); + + songChanged(SC_EVENT_INSERTED); // force an update of the itemlist + + emit ourDrumMapChanged(); + } +} diff --git a/muse2/muse/midiedit/dcanvas.h b/muse2/muse/midiedit/dcanvas.h index c5c51310..9a45f6ac 100644 --- a/muse2/muse/midiedit/dcanvas.h +++ b/muse2/muse/midiedit/dcanvas.h @@ -26,6 +26,9 @@ #include "ecanvas.h" #include "song.h" #include "steprec.h" +#include <map> +#include <QList> +#include <QSet> #define TH 18 @@ -36,7 +39,9 @@ class QDropEvent; class QDragMoveEvent; class QDragLeaveEvent; +class DrumMap; class MidiEditor; +class DrumEdit; //--------------------------------------------------------- // DEvent @@ -45,12 +50,31 @@ class MidiEditor; class DEvent : public MusEWidget::CItem { public: - DEvent(Event e, Part* p); + DEvent(Event e, Part* p, int instr); }; class ScrollScale; class PianoRoll; + +struct instrument_number_mapping_t +{ + QSet<Track*> tracks; + int pitch; + + instrument_number_mapping_t() + { + pitch=-1; + tracks.clear(); + } + + instrument_number_mapping_t(const QSet<Track*>& tr, int p) + { + tracks=tr; + pitch=p; + } +}; + //--------------------------------------------------------- // DrumCanvas //--------------------------------------------------------- @@ -58,6 +82,13 @@ class PianoRoll; class DrumCanvas : public EventCanvas { Q_OBJECT + bool old_style_drummap_mode; + DrumMap* ourDrumMap; + bool must_delete_our_drum_map; //FINDMICH really delete it! + QVector<instrument_number_mapping_t> instrument_map; + + DrumEdit* drumEditor; + StepRec* steprec; // Cursor tool position @@ -88,9 +119,10 @@ class DrumCanvas : public EventCanvas { virtual void resizeEvent(QResizeEvent*); virtual void curPartChanged(); int getNextStep(unsigned int pos, int basicStep, int stepSize=1); - + signals: void newWidth(int); + void ourDrumMapChanged(); private slots: void midiNote(int pitch, int velo); @@ -110,7 +142,8 @@ class DrumCanvas : public EventCanvas { CMD_SELECT_ALL, CMD_SELECT_NONE, CMD_SELECT_INVERT, CMD_SELECT_ILOOP, CMD_SELECT_OLOOP, CMD_SELECT_PREV_PART, CMD_SELECT_NEXT_PART, CMD_DEL, CMD_FIXED_LEN, CMD_RIGHT, CMD_LEFT, CMD_RIGHT_NOSNAP, CMD_LEFT_NOSNAP, CMD_MODIFY_VELOCITY, CMD_CRESCENDO, - CMD_QUANTIZE, CMD_ERASE_EVENT, CMD_NOTE_SHIFT, CMD_DELETE_OVERLAPS, CMD_REORDER_LIST + CMD_QUANTIZE, CMD_ERASE_EVENT, CMD_NOTE_SHIFT, CMD_DELETE_OVERLAPS, CMD_REORDER_LIST, + CMD_GROUP_NONE, CMD_GROUP_CHAN, CMD_GROUP_MAX }; DrumCanvas(MidiEditor*, QWidget*, int, int, const char* name = 0); @@ -120,7 +153,12 @@ class DrumCanvas : public EventCanvas { virtual void keyPress(QKeyEvent* event); Event *getEventAtCursorPos(); void selectCursorEvent(Event *ev); - + int pitch_and_track_to_instrument(int pitch, Track* track); + DrumMap* getOurDrumMap() { return ourDrumMap; } //FINDMICH UGLY + int getOurDrumMapSize() { return instrument_map.size(); } //FINDMICH UGLY + + void propagate_drummap_change(int instrument); //FINDMICH move to drumedit + void rebuildOurDrumMap(); }; #endif diff --git a/muse2/muse/midiedit/dlist.cpp b/muse2/muse/midiedit/dlist.cpp index 8e9633c0..350f5e5e 100644 --- a/muse2/muse/midiedit/dlist.cpp +++ b/muse2/muse/midiedit/dlist.cpp @@ -37,7 +37,7 @@ #include "icons.h" #include "dlist.h" #include "song.h" -#include "scrollscale.h" +#include "dcanvas.h" //--------------------------------------------------------- // draw @@ -56,13 +56,13 @@ void DList::draw(QPainter& p, const QRect& rect) p.setPen(Qt::black); - for (int i = 0; i < DRUM_MAPSIZE; ++i) { + for (int i = 0; i < ourDrumMapSize; ++i) { int yy = i * TH; if (yy+TH < y) continue; if (yy > y + h) break; - DrumMap* dm = &drumMap[i]; + DrumMap* dm = &ourDrumMap[i]; if (dm == currentlySelected) p.fillRect(x, yy, w, TH, Qt::yellow); // else @@ -178,6 +178,12 @@ void DList::draw(QPainter& p, const QRect& rect) void DList::devicesPopupMenu(DrumMap* t, int x, int y, bool changeAll) { + if (!old_style_drummap_mode) + { + printf("THIS SHOULD NEVER HAPPEN: devicesPopupMenu() called in new style mode!\n"); + return; + } + QMenu* p = midiPortsPopup(); QAction* act = p->exec(mapToGlobal(QPoint(x, y)), 0); bool doemit = false; @@ -199,8 +205,8 @@ void DList::devicesPopupMenu(DrumMap* t, int x, int y, bool changeAll) // Delete all port controller events. song->changeAllPortDrumCtrlEvents(false); - for (int i = 0; i < DRUM_MAPSIZE; i++) - drumMap[i].port = n; + for (int i = 0; i < ourDrumMapSize; i++) + ourDrumMap[i].port = n; // Add all port controller events. song->changeAllPortDrumCtrlEvents(true); @@ -227,13 +233,14 @@ void DList::viewMousePressEvent(QMouseEvent* ev) int x = ev->x(); int y = ev->y(); int button = ev->button(); - unsigned pitch = y / TH; - DrumMap* dm = &drumMap[pitch]; + unsigned instrument = y / TH; + DrumMap* dm = &ourDrumMap[instrument]; + DrumMap dm_old = *dm; - setCurDrumInstrument(pitch); + setCurDrumInstrument(instrument); startY = y; - sPitch = pitch; + sInstrument = instrument; drag = START_DRAG; DCols col = DCols(x2col(x)); @@ -262,18 +269,18 @@ void DList::viewMousePressEvent(QMouseEvent* ev) if (button == Qt::LeftButton) dm->mute = !dm->mute; break; - case COL_PORT: + case COL_PORT: // this column isn't visible in new style drum mode if ((button == Qt::RightButton) || (button == Qt::LeftButton)) { bool changeAll = ev->modifiers() & Qt::ControlModifier; - devicesPopupMenu(dm, mapx(x), mapy(pitch * TH), changeAll); + devicesPopupMenu(dm, mapx(x), mapy(instrument * TH), changeAll); } break; case COL_VOL: val = dm->vol + incVal; if (val < 0) val = 0; - else if (val > 200) - val = 200; + else if (val > 999) //changed from 200 to 999 by flo93 + val = 999; dm->vol = (unsigned char)val; break; case COL_QNT: @@ -286,18 +293,22 @@ void DList::viewMousePressEvent(QMouseEvent* ev) val = 0; else if (val > 127) val = 127; - //Check if there is any other drumMap with the same inmap value (there should be one (and only one):-) - //If so, switch the inmap between the instruments - for (int i=0; i<DRUM_MAPSIZE; i++) { - if (drumMap[i].enote == val && &drumMap[i] != dm) { - drumInmap[int(dm->enote)] = i; - drumMap[i].enote = dm->enote; - break; - } - } - //TODO: Set all the notes on the track with pitch=dm->enote to pitch=val + + if (old_style_drummap_mode) + { + //Check if there is any other drumMap with the same inmap value (there should be one (and only one):-) + //If so, switch the inmap between the instruments + for (int i=0; i<ourDrumMapSize; i++) { + if (ourDrumMap[i].enote == val && &ourDrumMap[i] != dm) { + drumInmap[int(dm->enote)] = i; + ourDrumMap[i].enote = dm->enote; + break; + } + } + //TODO: Set all the notes on the track with instrument=dm->enote to instrument=val + drumInmap[val] = instrument; + } dm->enote = val; - drumInmap[val] = pitch; break; case COL_LEN: val = dm->len + incVal; @@ -306,6 +317,7 @@ void DList::viewMousePressEvent(QMouseEvent* ev) dm->len = val; break; case COL_ANOTE: + if (old_style_drummap_mode) //only allow changing in old style mode { val = dm->anote + incVal; if (val < 0) @@ -315,16 +327,19 @@ void DList::viewMousePressEvent(QMouseEvent* ev) if(val != dm->anote) { audio->msgIdle(true); - song->remapPortDrumCtrlEvents(pitch, val, -1, -1); + song->remapPortDrumCtrlEvents(instrument, val, -1, -1); audio->msgIdle(false); dm->anote = val; song->update(SC_DRUMMAP); } - int velocity = 127 * float(ev->x()) / width(); - emit keyPressed(pitch, velocity);//(dm->anote, shift); + } + + { + int velocity = 127 * float(ev->x()) / width(); + emit keyPressed(instrument, velocity);//(dm->anote, shift); } break; - case COL_CHANNEL: + case COL_CHANNEL: // this column isn't visible in new style drum mode val = dm->channel + incVal; if (val < 0) val = 0; @@ -336,8 +351,8 @@ void DList::viewMousePressEvent(QMouseEvent* ev) // Delete all port controller events. song->changeAllPortDrumCtrlEvents(false, true); - for (int i = 0; i < DRUM_MAPSIZE; i++) - drumMap[i].channel = val; + for (int i = 0; i < ourDrumMapSize; i++) + ourDrumMap[i].channel = val; // Add all port controller events. song->changeAllPortDrumCtrlEvents(true, true); audio->msgIdle(false); @@ -348,7 +363,7 @@ void DList::viewMousePressEvent(QMouseEvent* ev) if(val != dm->channel) { audio->msgIdle(true); - song->remapPortDrumCtrlEvents(pitch, -1, val, -1); + song->remapPortDrumCtrlEvents(instrument, -1, val, -1); audio->msgIdle(false); dm->channel = val; song->update(SC_DRUMMAP); @@ -388,13 +403,18 @@ void DList::viewMousePressEvent(QMouseEvent* ev) dm->lv4 = val; break; case COL_NAME: - emit keyPressed(pitch, 100); //Mapping done on other side, send index + emit keyPressed(instrument, 100); //Mapping done on other side, send index break; default: break; } - redraw(); + + if (!old_style_drummap_mode && dm_old != *dm) //something changed and we're in new style mode? + dcanvas->propagate_drummap_change(dm-ourDrumMap); + + song->update(SC_DRUMMAP); + //redraw(); //this is done by the songChanged slot } //--------------------------------------------------------- @@ -405,18 +425,18 @@ void DList::viewMouseDoubleClickEvent(QMouseEvent* ev) { int x = ev->x(); int y = ev->y(); - unsigned pitch = y / TH; + unsigned instrument = y / TH; int section = header->logicalIndexAt(x); if ((section == COL_NAME || section == COL_VOL || section == COL_LEN || section == COL_LV1 || - section == COL_LV2 || section == COL_LV3 || section == COL_LV4 || section == COL_CHANNEL || - section == COL_QNT) && (ev->button() == Qt::LeftButton)) + section == COL_LV2 || section == COL_LV3 || section == COL_LV4 || section == COL_QNT || + (section == COL_CHANNEL && old_style_drummap_mode) ) && (ev->button() == Qt::LeftButton)) { - lineEdit(pitch, section); + lineEdit(instrument, section); } - else if ((section == COL_ANOTE || section == COL_ENOTE) && (ev->button() == Qt::LeftButton)) - pitchEdit(pitch, section); + else if (((section == COL_ANOTE && old_style_drummap_mode) || section == COL_ENOTE) && (ev->button() == Qt::LeftButton)) + pitchEdit(instrument, section); else viewMousePressEvent(ev); } @@ -428,7 +448,7 @@ void DList::viewMouseDoubleClickEvent(QMouseEvent* ev) //--------------------------------------------------------- void DList::lineEdit(int line, int section) { - DrumMap* dm = &drumMap[line]; + DrumMap* dm = &ourDrumMap[line]; editEntry = dm; if (editor == 0) { editor = new DLineEdit(this); @@ -496,7 +516,7 @@ void DList::lineEdit(int line, int section) //--------------------------------------------------------- void DList::pitchEdit(int line, int section) { - DrumMap* dm = &drumMap[line]; + DrumMap* dm = &ourDrumMap[line]; editEntry = dm; if (pitch_editor == 0) { pitch_editor = new DPitchEdit(this); @@ -550,11 +570,11 @@ int DList::x2col(int x) const void DList::setCurDrumInstrument(int instr) { - if (instr < 0 || instr >= DRUM_MAPSIZE -1) + if (instr < 0 || instr >= ourDrumMapSize -1) return; // illegal instrument - DrumMap* dm = &drumMap[instr]; + DrumMap* dm = &ourDrumMap[instr]; if (currentlySelected != dm) { - currentlySelected = &drumMap[instr]; + currentlySelected = dm; emit curDrumInstrumentChanged(instr); song->update(SC_DRUMMAP); } @@ -575,17 +595,22 @@ void DList::sizeChange(int, int, int) void DList::returnPressed() { + if (editEntry==NULL) + { + printf("THIS SHOULD NEVER HAPPEN: editEntry is NULL in DList::returnPressed()!\n"); + return; + } + int val = -1; if (selectedColumn != COL_NAME) { - ///val = atoi(editor->text().ascii()); val = atoi(editor->text().toAscii().constData()); switch (selectedColumn) { case COL_VOL: - if (val > 200) //Check bounds for volume - val = 200; + if (val > 999) //changed from 200 to 999 by flo93 + val = 999; if (val < 0) val = 0; break; @@ -611,14 +636,14 @@ void DList::returnPressed() default: break; } } - + + DrumMap editEntryOld = *editEntry; switch(selectedColumn) { case COL_NAME: editEntry->name = editor->text(); break; case COL_LEN: - ///editEntry->len = atoi(editor->text().ascii()); editEntry->len = atoi(editor->text().toAscii().constData()); break; @@ -654,11 +679,16 @@ void DList::returnPressed() printf("Return pressed in unknown column\n"); break; } + + if (editEntryOld != *editEntry) + dcanvas->propagate_drummap_change(editEntry-ourDrumMap); + selectedColumn = -1; editor->hide(); editEntry = 0; setFocus(); - redraw(); + song->update(SC_DRUMMAP); + //redraw(); //this is done by the songChanged slot } //--------------------------------------------------------- @@ -667,44 +697,64 @@ void DList::returnPressed() void DList::pitchEdited() { + if (editEntry==NULL) + { + printf("THIS SHOULD NEVER HAPPEN: editEntry is NULL in DList::pitchEdited()!\n"); + return; + } + int val=pitch_editor->value(); - int pitch=(editEntry-drumMap); + int instrument=(editEntry-ourDrumMap); + DrumMap editEntryOld=*editEntry; switch(selectedColumn) { case COL_ANOTE: + if (old_style_drummap_mode) //should actually be always true, but to be sure... + { if(val != editEntry->anote) { audio->msgIdle(true); - song->remapPortDrumCtrlEvents(pitch, val, -1, -1); + song->remapPortDrumCtrlEvents(instrument, val, -1, -1); audio->msgIdle(false); editEntry->anote = val; song->update(SC_DRUMMAP); } - break; + } + else + printf("ERROR: THIS SHOULD NEVER HAPPEN: pitch edited of anote in new style mode!\n"); + break; case COL_ENOTE: + if (old_style_drummap_mode) + { //Check if there is any other drumMap with the same inmap value (there should be one (and only one):-) //If so, switch the inmap between the instruments - for (int i=0; i<DRUM_MAPSIZE; i++) { - if (drumMap[i].enote == val && &drumMap[i] != editEntry) { + for (int i=0; i<ourDrumMapSize; i++) { + if (ourDrumMap[i].enote == val && &ourDrumMap[i] != editEntry) { drumInmap[int(editEntry->enote)] = i; - drumMap[i].enote = editEntry->enote; + ourDrumMap[i].enote = editEntry->enote; break; } } - //TODO: Set all the notes on the track with pitch=dm->enote to pitch=val - editEntry->enote = val; - drumInmap[val] = pitch; - break; + //TODO: Set all the notes on the track with instrument=dm->enote to instrument=val + drumInmap[val] = instrument; + } + editEntry->enote = val; + break; default: - printf("Value changed in unknown column\n"); + printf("ERROR: THIS SHOULD NEVER HAPPEN: Value changed in unknown column\n"); break; } + + if (editEntryOld != *editEntry) + dcanvas->propagate_drummap_change(editEntry-ourDrumMap); + selectedColumn = -1; pitch_editor->hide(); editEntry = 0; setFocus(); - redraw(); + song->update(SC_DRUMMAP); + //redraw(); //this is done by the songChanged slot } //--------------------------------------------------------- @@ -739,14 +789,20 @@ void DList::songChanged(int flags) // DList //--------------------------------------------------------- -DList::DList(QHeaderView* h, QWidget* parent, int ymag) +DList::DList(QHeaderView* h, QWidget* parent, int ymag, DrumCanvas* dcanvas_, bool oldstyle) : MusEWidget::View(parent, 1, ymag) { setBg(Qt::white); + + dcanvas=dcanvas_; + ourDrumMap=dcanvas->getOurDrumMap(); + ourDrumMapSize=dcanvas->getOurDrumMapSize(); + old_style_drummap_mode=oldstyle; + connect(dcanvas, SIGNAL(ourDrumMapChanged()), SLOT(ourDrumMapChanged())); + if (!h){ h = new QHeaderView(Qt::Horizontal, parent);} header = h; - scroll = 0; //ORCAN- CHECK if really needed: header->setTracking(true); connect(header, SIGNAL(sectionResized(int,int,int)), SLOT(sizeChange(int,int,int))); @@ -757,7 +813,7 @@ DList::DList(QHeaderView* h, QWidget* parent, int ymag) pitch_editor = 0; editEntry = 0; // always select a drum instrument - currentlySelected = &drumMap[0]; + currentlySelected = &ourDrumMap[0]; selectedColumn = -1; } @@ -803,11 +859,21 @@ void DList::viewMouseReleaseEvent(QMouseEvent* ev) { if (drag == DRAG) { int y = ev->y(); - unsigned dPitch = y / TH; + int dInstrument; + if (old_style_drummap_mode) + dInstrument = y / TH; + else + dInstrument = (y+TH/2) / TH; + + if (dInstrument < 0) dInstrument=0; + if (dInstrument >= ourDrumMapSize) dInstrument=ourDrumMapSize-1; + + int cur_sel = (!old_style_drummap_mode && dInstrument>sInstrument) ? dInstrument-1 : dInstrument; + setCursor(QCursor(Qt::ArrowCursor)); - currentlySelected = &drumMap[int(dPitch)]; - emit curDrumInstrumentChanged(dPitch); - emit mapChanged(sPitch, dPitch); //Track pitch change done in canvas + currentlySelected = &ourDrumMap[cur_sel]; + emit curDrumInstrumentChanged((unsigned)cur_sel); + emit mapChanged(sInstrument, (unsigned)dInstrument); //Track instrument change done in canvas } drag = NORMAL; //?? redraw(); //commented out NOT by flo93; was already commented out @@ -816,16 +882,16 @@ void DList::viewMouseReleaseEvent(QMouseEvent* ev) int x = ev->x(); int y = ev->y(); bool shift = ev->modifiers() & Qt::ShiftModifier; - unsigned pitch = y / TH; + unsigned instrument = y / TH; DCols col = DCols(x2col(x)); switch (col) { case COL_NAME: - emit keyReleased(pitch, shift); + emit keyReleased(instrument, shift); break; case COL_ANOTE: - emit keyReleased(pitch, shift); + emit keyReleased(instrument, shift); break; default: break; @@ -844,3 +910,16 @@ int DList::getSelectedInstrument() } +void DList::ourDrumMapChanged() +{ + int selIdx = currentlySelected - ourDrumMap; + + ourDrumMap=dcanvas->getOurDrumMap(); + ourDrumMapSize=dcanvas->getOurDrumMapSize(); + + editEntry=NULL; + if (selIdx >= ourDrumMapSize) selIdx=ourDrumMapSize-1; + currentlySelected = &ourDrumMap[selIdx]; + + redraw(); +} diff --git a/muse2/muse/midiedit/dlist.h b/muse2/muse/midiedit/dlist.h index 0fb1fd0b..1d87f3dc 100644 --- a/muse2/muse/midiedit/dlist.h +++ b/muse2/muse/midiedit/dlist.h @@ -35,11 +35,10 @@ class QHeaderView; class QMouseEvent; class QPainter; -class ScrollScale; class Device; class QLineEdit; class DrumMap; - +class DrumCanvas; //--------------------------------------------------------- // DLineEdit @@ -86,9 +85,13 @@ class DPitchEdit: public Awl::PitchEdit class DList : public MusEWidget::View { Q_OBJECT - + + DrumCanvas* dcanvas; + DrumMap* ourDrumMap; + int ourDrumMapSize; + bool old_style_drummap_mode; + QHeaderView* header; - ScrollScale* scroll; QLineEdit* editor; DPitchEdit* pitch_editor; DrumMap* editEntry; @@ -98,7 +101,7 @@ class DList : public MusEWidget::View { int startY; int curY; - int sPitch; + int sInstrument; enum { NORMAL, START_DRAG, DRAG } drag; virtual void draw(QPainter& p, const QRect&); @@ -128,13 +131,14 @@ class DList : public MusEWidget::View { public slots: void tracklistChanged(); void songChanged(int); + void ourDrumMapChanged(); + public: void lineEdit(int line, int section); void pitchEdit(int line, int section); void setCurDrumInstrument(int n); - DList(QHeaderView*, QWidget* parent, int ymag); + DList(QHeaderView*, QWidget* parent, int ymag, DrumCanvas* dcanvas, bool oldstyle); ~DList(); - void setScroll(ScrollScale* s) { scroll = s; } int getSelectedInstrument(); enum DCols { COL_MUTE=0, COL_NAME, COL_VOL, COL_QNT, COL_ENOTE, COL_LEN, diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp index 8821d0d8..92cc765a 100644 --- a/muse2/muse/midiedit/drumedit.cpp +++ b/muse2/muse/midiedit/drumedit.cpp @@ -177,6 +177,8 @@ DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned ini selPart = 0; QSignalMapper *signalMapper = new QSignalMapper(this); + _group_mode = GROUP_SAME_CHANNEL; + //---------Pulldown Menu---------------------------- menuFile = menuBar()->addMenu(tr("&File")); @@ -253,8 +255,14 @@ DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned ini menuFunctions->setTearOffEnabled(true); - QAction* reorderListAction = menuFunctions->addAction(tr("Re-order list")); - menuFunctions->addSeparator(); + if (old_style_drummap_mode()) + { + QAction* reorderListAction = menuFunctions->addAction(tr("Re-order list")); + connect(reorderListAction, SIGNAL(triggered()), signalMapper, SLOT(map())); + signalMapper->setMapping(reorderListAction, DrumCanvas::CMD_REORDER_LIST); + menuFunctions->addSeparator(); + } + fixedAction = menuFunctions->addAction(tr("Set Fixed Length")); veloAction = menuFunctions->addAction(tr("Modify Velocity")); crescAction = menuFunctions->addAction(tr("Crescendo/Decrescendo")); @@ -263,7 +271,6 @@ DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned ini QAction* noteShiftAction = menuFunctions->addAction(tr("Move Notes")); QAction* delOverlapsAction = menuFunctions->addAction(tr("Delete Overlaps")); - connect(reorderListAction, SIGNAL(triggered()), signalMapper, SLOT(map())); connect(fixedAction, SIGNAL(triggered()), signalMapper, SLOT(map())); connect(veloAction, SIGNAL(triggered()), signalMapper, SLOT(map())); connect(crescAction, SIGNAL(triggered()), signalMapper, SLOT(map())); @@ -272,7 +279,6 @@ DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned ini connect(noteShiftAction, SIGNAL(triggered()), signalMapper, SLOT(map())); connect(delOverlapsAction, SIGNAL(triggered()), signalMapper, SLOT(map())); - signalMapper->setMapping(reorderListAction, DrumCanvas::CMD_REORDER_LIST); signalMapper->setMapping(fixedAction, DrumCanvas::CMD_FIXED_LEN); signalMapper->setMapping(veloAction, DrumCanvas::CMD_MODIFY_VELOCITY); signalMapper->setMapping(crescAction, DrumCanvas::CMD_CRESCENDO); @@ -281,10 +287,40 @@ DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned ini signalMapper->setMapping(noteShiftAction, DrumCanvas::CMD_NOTE_SHIFT); signalMapper->setMapping(delOverlapsAction, DrumCanvas::CMD_DELETE_OVERLAPS); + + QMenu* menuScriptPlugins = menuBar()->addMenu(tr("&Plugins")); song->populateScriptMenu(menuScriptPlugins, this); QMenu* settingsMenu = menuBar()->addMenu(tr("Window &Config")); + if (!old_style_drummap_mode()) + { + QMenu* menuGrouping=settingsMenu->addMenu(tr("Group")); + groupNoneAction = menuGrouping->addAction(tr("Don't group")); + groupChanAction = menuGrouping->addAction(tr("Group by channel")); + groupMaxAction = menuGrouping->addAction(tr("Group maximally")); + settingsMenu->addSeparator(); + + groupNoneAction->setCheckable(true); + groupChanAction->setCheckable(true); + groupMaxAction ->setCheckable(true); + + connect(groupNoneAction, SIGNAL(triggered()), signalMapper, SLOT(map())); + connect(groupChanAction, SIGNAL(triggered()), signalMapper, SLOT(map())); + connect(groupMaxAction, SIGNAL(triggered()), signalMapper, SLOT(map())); + + signalMapper->setMapping(groupNoneAction, DrumCanvas::CMD_GROUP_NONE); + signalMapper->setMapping(groupChanAction, DrumCanvas::CMD_GROUP_CHAN); + signalMapper->setMapping(groupMaxAction, DrumCanvas::CMD_GROUP_MAX); + + updateGroupingActions(); + } + else + { + groupNoneAction=NULL; + groupChanAction=NULL; + groupMaxAction =NULL; + } settingsMenu->addAction(subwinAction); settingsMenu->addAction(shareAction); settingsMenu->addAction(fullscreenAction); @@ -406,7 +442,7 @@ DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned ini gridS2->setSpacing(0); time = new MusEWidget::MTScale(&_raster, split1w2, xscale); canvas = new DrumCanvas(this, split1w2, xscale, yscale); - vscroll = new MusEWidget::ScrollScale(-4, 1, yscale, DRUM_MAPSIZE*TH, Qt::Vertical, split1w2); + vscroll = new MusEWidget::ScrollScale(-4, 1, yscale, dynamic_cast<DrumCanvas*>(canvas)->getOurDrumMapSize()*TH, Qt::Vertical, split1w2); int offset = -(MusEConfig::config.division/4); canvas->setOrigin(offset, 0); canvas->setCanvasTools(drumeditTools); @@ -414,6 +450,7 @@ DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned ini connect(canvas, SIGNAL(toolChanged(int)), tools2, SLOT(set(int))); connect(canvas, SIGNAL(horizontalZoomIn()), SLOT(horizontalZoomIn())); connect(canvas, SIGNAL(horizontalZoomOut()), SLOT(horizontalZoomOut())); + connect(canvas, SIGNAL(ourDrumMapChanged()), SLOT(ourDrumMapChanged())); time->setOrigin(offset, 0); QList<int> mops; @@ -454,7 +491,13 @@ DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned ini setHeaderToolTips(); setHeaderWhatsThis(); - dlist = new DList(header, split1w1, yscale); + if (!old_style_drummap_mode()) + { + header->hideSection(COL_OUTPORT); + header->hideSection(COL_OUTCHANNEL); + } + + dlist = new DList(header, split1w1, yscale, (DrumCanvas*)canvas, old_style_drummap_mode()); // p3.3.44 setCurDrumInstrument(dlist->getSelectedInstrument()); @@ -544,8 +587,12 @@ void DrumEdit::songChanged1(int bits) toolbar->setSolo(canvas->track()->solo()); return; } + if ( !old_style_drummap_mode() && + ( bits & (SC_DRUMMAP | SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED | + SC_PART_INSERTED | SC_PART_REMOVED | SC_PART_MODIFIED) ) ) + ((DrumCanvas*)(canvas))->rebuildOurDrumMap(); + songChanged(bits); - } //--------------------------------------------------------- @@ -951,7 +998,11 @@ void DrumEdit::cmd(int cmd) case DrumCanvas::CMD_REORDER_LIST: ((DrumCanvas*)(canvas))->moveAwayUnused(); break; //case DrumCanvas::CMD_FIXED_LEN: // this must be handled by the drum canvas, due to its // special nature (each drum has its own length) - + + case DrumCanvas::CMD_GROUP_NONE: _group_mode=DONT_GROUP; updateGroupingActions(); ((DrumCanvas*)(canvas))->rebuildOurDrumMap(); break; + case DrumCanvas::CMD_GROUP_CHAN: _group_mode=GROUP_SAME_CHANNEL; updateGroupingActions(); ((DrumCanvas*)(canvas))->rebuildOurDrumMap(); break; + case DrumCanvas::CMD_GROUP_MAX: _group_mode=GROUP_MAX; updateGroupingActions(); ((DrumCanvas*)(canvas))->rebuildOurDrumMap(); break; + default: ((DrumCanvas*)(canvas))->cmd(cmd); } } @@ -1322,3 +1373,32 @@ void DrumEdit::setStep(QString v) stepLenWidget->setFocusPolicy(Qt::NoFocus); canvas->setFocus(); } + +bool DrumEdit::old_style_drummap_mode() +{ + for (ciPart p = parts()->begin(); p != parts()->end(); ++p) + if (p->second->track()->type()==Track::DRUM) + return true; + + return false; +} + +void DrumEdit::ourDrumMapChanged() +{ + int vmin,vmax; + vscroll->range(&vmin, &vmax); + vscroll->setRange(vmin, dynamic_cast<DrumCanvas*>(canvas)->getOurDrumMapSize()*TH); +} + +void DrumEdit::updateGroupingActions() +{ + if (groupNoneAction==NULL || groupChanAction==NULL || groupMaxAction==NULL) + { + printf("THIS SHOULD NEVER HAPPEN: DrumEdit::updateGroupingActions() called, but one of the actions is NULL!\n"); + return; + } + + groupNoneAction->setChecked(_group_mode==DONT_GROUP); + groupChanAction->setChecked(_group_mode==GROUP_SAME_CHANNEL); + groupMaxAction ->setChecked(_group_mode==GROUP_MAX); +} diff --git a/muse2/muse/midiedit/drumedit.h b/muse2/muse/midiedit/drumedit.h index 06f7e131..743d6151 100644 --- a/muse2/muse/midiedit/drumedit.h +++ b/muse2/muse/midiedit/drumedit.h @@ -67,7 +67,13 @@ class Toolbar1; class DrumEdit : public MidiEditor { Q_OBJECT - + + public: + enum group_mode_t { DONT_GROUP, GROUP_SAME_CHANNEL, GROUP_MAX }; + + private: + group_mode_t _group_mode; + Event selEvent; MidiPart* selPart; int selTick; @@ -95,7 +101,7 @@ class DrumEdit : public MidiEditor { QAction *fixedAction, *veloAction, *crescAction, *quantizeAction; QAction *sallAction, *snoneAction, *invAction, *inAction , *outAction; QAction *prevAction, *nextAction; - + QAction *groupNoneAction, *groupChanAction, *groupMaxAction; void initShortcuts(); @@ -123,6 +129,7 @@ class DrumEdit : public MidiEditor { void configChanged(); void songChanged1(int); void setStep(QString); + void updateGroupingActions(); public slots: void setSelection(int, Event&, Part*); @@ -130,8 +137,9 @@ class DrumEdit : public MidiEditor { void execDeliveredScript(int); void execUserScript(int); CtrlEdit* addCtrl(); - + void ourDrumMapChanged(); virtual void updateHScrollRange(); + signals: void deleted(TopWin*); @@ -142,6 +150,9 @@ class DrumEdit : public MidiEditor { virtual void writeStatus(int, Xml&) const; static void readConfiguration(Xml& xml); static void writeConfiguration(int, Xml&); + + bool old_style_drummap_mode(); + group_mode_t group_mode() { return _group_mode; } }; #endif diff --git a/muse2/muse/midiedit/drummap.cpp b/muse2/muse/midiedit/drummap.cpp index 032c2bd6..8f49afc0 100644 --- a/muse2/muse/midiedit/drummap.cpp +++ b/muse2/muse/midiedit/drummap.cpp @@ -26,6 +26,8 @@ #include "xml.h" #include "song.h" +global_drum_ordering_t global_drum_ordering; + char drumOutmap[DRUM_MAPSIZE]; char drumInmap[128]; diff --git a/muse2/muse/midiedit/drummap.h b/muse2/muse/midiedit/drummap.h index 2c02ffcc..db512103 100644 --- a/muse2/muse/midiedit/drummap.h +++ b/muse2/muse/midiedit/drummap.h @@ -24,7 +24,8 @@ #ifndef __DRUMMAP_H__ #define __DRUMMAP_H__ -class QString; +#include <QString> +#include <QList> class Xml; @@ -44,8 +45,8 @@ struct DrumMap { bool mute; // bool selected; - //bool const operator==(const DrumMap& map) const; bool operator==(const DrumMap& map) const; + bool operator!=(const DrumMap& map) const { return !operator==(map); } }; #define DRUM_MAPSIZE 128 @@ -53,10 +54,15 @@ struct DrumMap { extern char drumOutmap[DRUM_MAPSIZE]; extern char drumInmap[DRUM_MAPSIZE]; extern DrumMap drumMap[DRUM_MAPSIZE]; +extern const DrumMap idrumMap[DRUM_MAPSIZE]; //FINDMICH dummy! extern void initDrumMap(); extern void writeDrumMap(int level, Xml& xml, bool external); extern void readDrumMap(Xml& xml, bool external); extern void resetGMDrumMap(); +class MidiTrack; +typedef QList< std::pair<MidiTrack*,int> > global_drum_ordering_t; + +extern global_drum_ordering_t global_drum_ordering; #endif diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index b96cb47f..b9b4794f 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -110,6 +110,10 @@ PianoCanvas::PianoCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy) connect(song, SIGNAL(midiNote(int, int)), SLOT(midiNote(int,int))); } +PianoCanvas::~PianoCanvas() +{ + delete steprec; +} //--------------------------------------------------------- // pitch2y //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h index a44a9a4a..b3a8a288 100644 --- a/muse2/muse/midiedit/prcanvas.h +++ b/muse2/muse/midiedit/prcanvas.h @@ -117,6 +117,7 @@ class PianoCanvas : public EventCanvas { }; PianoCanvas(MidiEditor*, QWidget*, int, int); + virtual ~PianoCanvas(); void cmd(int cmd); void setColorMode(int mode) { colorMode = mode; diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index b17f9b1d..64258f60 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -1257,6 +1257,11 @@ ScoreCanvas::ScoreCanvas(ScoreEdit* pr, QWidget* parent_widget) : View(parent_wi unsetCursor(); } +ScoreCanvas::~ScoreCanvas() +{ + delete steprec; +} + void ScoreCanvas::staffmode_treble_slot() { set_staffmode(current_staff, MODE_TREBLE); @@ -4581,15 +4586,35 @@ void ScoreCanvas::add_new_parts(const std::map< Part*, std::set<Part*> >& param) * because after A (and B) got resized, the B-resize is invalid! * o when changing toolbarstate when sharing and immediately after that * changing "share" status, the changed state isn't stored + * o arranger state and mixer state aren't stored (says tim) * ? pasting in editors sometimes fails oO? ( ERROR: reading eventlist * from clipboard failed. ignoring this one... ) [ not reproducible ] * * CURRENT TODO * ! o fix sigedit boxes (see also "important todo") * o fix valgrind problems + * * > o drum editor: channel-stuff + * o dialog for maintaining drum lists, hide etc + * o respect "_drummap_tied_to_patch": IMPLEMENT + * o save hide, ordering, track's drumlists + * o "copy drumlist" from one track to another + * o whenever changing the patch and maintained_automatically==true, + * the drumlist is replaced by the according one (for example, "jazz" drum kit's list) + * o whenever changing the drumlist and maintained_automatically==true, + * ask the user if he wants to proceed, and then set maintained_automatically to false + * o offer some way to set maintained_automatically to true again + * o move generation and deletion of ourDrumMap from DCanvas to DrumEditor and remove ugly wrapper functions + * + * o when playing back a flo-drum-track: treat as a MIDI track, + * EXCEPT that the drum list's mute entries are respected! + * o when recording or echoing a flo-drum-track: watch out for In-Notes! + * o update [midi]track::read/write, readproperties, writeprop... (drumlist etc), operator= * * IMPORTANT TODO + * o all places where i added doubleclick-edits: only react on left-click double clicks! + * o support "new style" reordering with old style drum tracks as well + * (not swapping but inserting!) * ! o fix sigedit boxes (see also "current todo") * o add "dotted quarter" quantize option (for 6/8 beat) * o ticks-to-quarter spinboxes diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h index 046fbf73..8f21e76b 100644 --- a/muse2/muse/midiedit/scoreedit.h +++ b/muse2/muse/midiedit/scoreedit.h @@ -811,7 +811,7 @@ class ScoreCanvas : public MusEWidget::View public: ScoreCanvas(ScoreEdit*, QWidget*); - ~ScoreCanvas(){}; + ~ScoreCanvas(); void add_staves(PartList* pl, bool all_in_one); void push_back_staff(staff_t& staff) { staves.push_back(staff); } //FINDMICH dirty. very dirty. diff --git a/muse2/muse/track.cpp b/muse2/muse/track.cpp index 18578d88..90e9beec 100644 --- a/muse2/muse/track.cpp +++ b/muse2/muse/track.cpp @@ -32,6 +32,7 @@ #include "audio.h" #include "globaldefs.h" #include "route.h" +#include "drummap.h" bool MidiTrack::_isVisible=true; //bool Track::_isVisible=true; @@ -392,6 +393,23 @@ MidiTrack::MidiTrack() _events = new EventList; _mpevents = new MPEventList; clefType=trebleClef; + + _drummap=new DrumMap[128]; + _drummap_hidden=new bool[128]; + + for (int i=0;i<128;i++) + { + int idx=idrumMap[i].anote; + if (idx < 0 || idx >= 128) + printf ("ERROR: THIS SHOULD NEVER HAPPEN: idrumMap[%i].anote is not within 0..127!\n", idx); + else + _drummap[idx]=idrumMap[i]; + + global_drum_ordering.push_back(std::pair<MidiTrack*,int>(this,idx)); + } + for (int i=0;i<128;i++) + _drummap_hidden[i]=false; + } //MidiTrack::MidiTrack(const MidiTrack& mt) @@ -412,12 +430,36 @@ MidiTrack::MidiTrack(const MidiTrack& mt, bool cloneParts) compression = mt.compression; _recEcho = mt.recEcho(); clefType=trebleClef; + + _drummap=new DrumMap[128]; + _drummap_hidden=new bool[128]; + memcpy(_drummap, mt._drummap, 128*sizeof(*_drummap)); + memcpy(_drummap_hidden, mt._drummap_hidden, 128*sizeof(*_drummap_hidden)); + + for (global_drum_ordering_t::iterator it=global_drum_ordering.begin(); it!=global_drum_ordering.end(); it++) + if (it->first == &mt) + { + it=global_drum_ordering.insert(it, *it); // duplicates the entry at it, set it to the first entry of both + it++; // make it point to the second entry + it->first=this; + } } MidiTrack::~MidiTrack() { delete _events; delete _mpevents; + delete [] _drummap; + delete [] _drummap_hidden; + + // remove ourselves from the global_drum_ordering list + // this is not really necessary, but cleaner + for (global_drum_ordering_t::iterator it=global_drum_ordering.begin(); it!=global_drum_ordering.end();) + if (it->first == this) + it=global_drum_ordering.erase(it); + else + it++; + } //--------------------------------------------------------- diff --git a/muse2/muse/track.h b/muse2/muse/track.h index f0f8ebde..752a79be 100644 --- a/muse2/muse/track.h +++ b/muse2/muse/track.h @@ -43,6 +43,7 @@ class SndFile; class MPEventList; class SynthI; class PluginI; +class DrumMap; //--------------------------------------------------------- // Track @@ -202,7 +203,7 @@ class Track { virtual bool canRecord() const { return false; } virtual AutomationType automationType() const = 0; virtual void setAutomationType(AutomationType t) = 0; - static void setVisible(bool ) { } + static void setVisible(bool) { } }; @@ -225,6 +226,12 @@ class MidiTrack : public Track { MPEventList* _mpevents; // tmp Events druring recording static bool _isVisible; clefTypes clefType; + + DrumMap* _drummap; + bool _drummap_tied_to_patch; //if true, changing patch also changes drummap + bool* _drummap_hidden; + + void init(); public: MidiTrack(); @@ -232,7 +239,6 @@ class MidiTrack : public Track { MidiTrack(const MidiTrack&, bool cloneParts); virtual ~MidiTrack(); - void init(); virtual AutomationType automationType() const; virtual void setAutomationType(AutomationType); @@ -293,6 +299,9 @@ class MidiTrack : public Track { void setClef(clefTypes i) { clefType = i; } clefTypes getClef() { return clefType; } + + DrumMap* drummap() { return _drummap; } + bool* drummap_hidden() { return _drummap_hidden; } }; //--------------------------------------------------------- diff --git a/muse2/muse/undo.cpp b/muse2/muse/undo.cpp index c0191362..63911fcf 100644 --- a/muse2/muse/undo.cpp +++ b/muse2/muse/undo.cpp @@ -775,6 +775,7 @@ void Song::doRedo2() UndoOp::UndoOp() { + type=UndoOp::DoNothing; } UndoOp::UndoOp(UndoType type_) @@ -1073,3 +1074,14 @@ void Song::doRedo3() dirty = true; } + +bool Undo::empty() const +{ + if (std::list<UndoOp>::empty()) return true; + + for (const_iterator it=begin(); it!=end(); it++) + if (it->type!=UndoOp::DoNothing) + return false; + + return true; +} diff --git a/muse2/muse/undo.h b/muse2/muse/undo.h index 5dca82b6..f2a523cc 100644 --- a/muse2/muse/undo.h +++ b/muse2/muse/undo.h @@ -119,7 +119,8 @@ struct UndoOp { }; class Undo : public std::list<UndoOp> { - void undoOp(UndoOp::UndoType, int data); + public: + bool empty() const; }; typedef Undo::iterator iUndoOp; |