diff options
65 files changed, 2907 insertions, 608 deletions
diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp index d65a071f..f63eb6e2 100644 --- a/muse2/muse/app.cpp +++ b/muse2/muse/app.cpp @@ -1880,6 +1880,7 @@ void MusE::startEditor(MusECore::Track* t) switch (t->type()) { case MusECore::Track::MIDI: startPianoroll(); break; case MusECore::Track::DRUM: startDrumEditor(); break; + case MusECore::Track::NEW_DRUM: startDrumEditor(); break; case MusECore::Track::WAVE: startWaveEditor(); break; default: break; diff --git a/muse2/muse/appearance.cpp b/muse2/muse/appearance.cpp index 37b5726f..e60db239 100644 --- a/muse2/muse/appearance.cpp +++ b/muse2/muse/appearance.cpp @@ -1,5 +1,4 @@ //========================================================= -//========================================================= // MusE // Linux Music Editor // $Id: appearance.cpp,v 1.11.2.5 2009/11/14 03:37:48 terminator356 Exp $ @@ -217,6 +216,7 @@ Appearance::Appearance(Arranger* a, QWidget* parent) new IdListViewItem(0x411, id, "background"); new IdListViewItem(0x412, id, "midi background"); new IdListViewItem(0x413, id, "drum background"); + new IdListViewItem(0x41e, id, "new drum background"); new IdListViewItem(0x414, id, "wave background"); new IdListViewItem(0x415, id, "output background"); new IdListViewItem(0x416, id, "input background"); @@ -225,6 +225,7 @@ Appearance::Appearance(Arranger* a, QWidget* parent) new IdListViewItem(0x419, id, "synth background"); new IdListViewItem(0x41a, id, "selected track background"); new IdListViewItem(0x41b, id, "selected track foreground"); + // 0x41e is already used (between 413 and 414) id = new IdListViewItem(0, itemList, "BigTime"); new IdListViewItem(0x100, id, "background"); new IdListViewItem(0x101, id, "foreground"); @@ -238,12 +239,14 @@ Appearance::Appearance(Arranger* a, QWidget* parent) new IdListViewItem(0x500, id, "background"); new IdListViewItem(0x501, id, "midi label"); new IdListViewItem(0x502, id, "drum label"); + new IdListViewItem(0x509, id, "new drum label"); new IdListViewItem(0x503, id, "wave label"); new IdListViewItem(0x504, id, "audio output label"); new IdListViewItem(0x505, id, "audio input label"); new IdListViewItem(0x506, id, "group label"); new IdListViewItem(0x507, id, "aux label"); new IdListViewItem(0x508, id, "synth label"); + // 0x509 is already used (between 502 and 503) colorNameLineEdit->setEnabled(false); @@ -844,6 +847,7 @@ void Appearance::colorItemSelectionChanged() case 0x411: color = &config->trackBg; break; case 0x412: color = &config->midiTrackBg; break; case 0x413: color = &config->drumTrackBg; break; + case 0x41e: color = &config->newDrumTrackBg;break; case 0x414: color = &config->waveTrackBg; break; case 0x415: color = &config->outputTrackBg; break; case 0x416: color = &config->inputTrackBg; break; @@ -854,16 +858,19 @@ void Appearance::colorItemSelectionChanged() case 0x41b: color = &config->selectTrackFg; break; case 0x41c: color = &config->partCanvasBg; break; case 0x41d: color = &config->ctrlGraphFg; break; + // 0x41e is already used (between 413 and 414) case 0x500: color = &config->mixerBg; break; case 0x501: color = &config->midiTrackLabelBg; break; case 0x502: color = &config->drumTrackLabelBg; break; + case 0x509: color = &config->newDrumTrackLabelBg;break; case 0x503: color = &config->waveTrackLabelBg; break; case 0x504: color = &config->outputTrackLabelBg; break; case 0x505: color = &config->inputTrackLabelBg; break; case 0x506: color = &config->groupTrackLabelBg; break; case 0x507: color = &config->auxTrackLabelBg; break; case 0x508: color = &config->synthTrackLabelBg; break; + // 0x509 is already used (between 502 and 503) default: color = 0; diff --git a/muse2/muse/arranger/arrangerview.cpp b/muse2/muse/arranger/arrangerview.cpp index aff3d056..d6266531 100644 --- a/muse2/muse/arranger/arrangerview.cpp +++ b/muse2/muse/arranger/arrangerview.cpp @@ -147,9 +147,9 @@ ArrangerView::ArrangerView(QWidget* parent) editInsertEMAction = new QAction(QIcon(*editpasteIconSet), tr("&Insert Empty Measure"), this); editDeleteSelectedAction = new QAction(QIcon(*edit_track_delIcon), tr("Delete Selected Tracks"), this); - editShrinkPartsAction = new QAction(tr("Shrink selected parts"), this); //FINDMICH TODO tooltips! + editShrinkPartsAction = new QAction(tr("Shrink selected parts"), this); editExpandPartsAction = new QAction(tr("Expand selected parts"), this); - editCleanPartsAction = new QAction(tr("Clean selected parts"), this); + editCleanPartsAction = new QAction(tr("Purge hidden events from selected parts"), this); addTrack = new QMenu(tr("Add Track"), this); @@ -641,16 +641,17 @@ void ArrangerView::clearScoreMenuMappers() void ArrangerView::populateAddTrack() { - QActionGroup *grp = MusEGui::populateAddTrack(addTrack, true); + QActionGroup *grp = MusEGui::populateAddTrack(addTrack, true, true); connect(addTrack, SIGNAL(triggered(QAction *)), SLOT(addNewTrack(QAction *))); trackMidiAction = grp->actions()[0]; trackDrumAction = grp->actions()[1]; - trackWaveAction = grp->actions()[2]; - trackAOutputAction = grp->actions()[3]; - trackAGroupAction = grp->actions()[4]; - trackAInputAction = grp->actions()[5]; - trackAAuxAction = grp->actions()[6]; + trackNewStyleDrumAction = grp->actions()[2]; + trackWaveAction = grp->actions()[3]; + trackAOutputAction = grp->actions()[4]; + trackAGroupAction = grp->actions()[5]; + trackAInputAction = grp->actions()[6]; + trackAAuxAction = grp->actions()[7]; } void ArrangerView::addNewTrack(QAction* action) @@ -674,6 +675,7 @@ void ArrangerView::updateShortcuts() trackMidiAction->setShortcut(shortcuts[SHRT_ADD_MIDI_TRACK].key); trackDrumAction->setShortcut(shortcuts[SHRT_ADD_DRUM_TRACK].key); + trackNewStyleDrumAction->setShortcut(shortcuts[SHRT_ADD_NEW_STYLE_DRUM_TRACK].key); trackWaveAction->setShortcut(shortcuts[SHRT_ADD_WAVE_TRACK].key); trackAOutputAction->setShortcut(shortcuts[SHRT_ADD_AUDIO_OUTPUT].key); trackAGroupAction->setShortcut(shortcuts[SHRT_ADD_AUDIO_GROUP].key); diff --git a/muse2/muse/arranger/arrangerview.h b/muse2/muse/arranger/arrangerview.h index c56767a6..0dac67e4 100644 --- a/muse2/muse/arranger/arrangerview.h +++ b/muse2/muse/arranger/arrangerview.h @@ -90,7 +90,7 @@ class ArrangerView : public TopWin QAction *strGlobalCutAction, *strGlobalInsertAction, *strGlobalSplitAction; QAction *strGlobalCutSelAction, *strGlobalInsertSelAction, *strGlobalSplitSelAction; - QAction *trackMidiAction, *trackDrumAction, *trackWaveAction, *trackAOutputAction, *trackAGroupAction; + QAction *trackMidiAction, *trackDrumAction, *trackNewStyleDrumAction, *trackWaveAction, *trackAOutputAction, *trackAGroupAction; QAction *trackAInputAction, *trackAAuxAction; QAction *editCutAction, *editCopyAction, *editCopyRangeAction; QAction *editPasteAction, *editPasteCloneAction, *editPasteDialogAction, *editPasteCloneDialogAction; diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp index 05b7b12a..fc0014e2 100644 --- a/muse2/muse/arranger/pcanvas.cpp +++ b/muse2/muse/arranger/pcanvas.cpp @@ -243,6 +243,7 @@ void PartCanvas::viewMouseDoubleClickEvent(QMouseEvent* event) switch(track->type()) { case MusECore::Track::MIDI: case MusECore::Track::DRUM: + case MusECore::Track::NEW_DRUM: { MusECore::MidiPart* part = new MusECore::MidiPart((MusECore::MidiTrack*)track); part->setTick(pos[1]); @@ -397,13 +398,13 @@ bool PartCanvas::moveItem(MusECore::Undo& operations, CItem* item, const QPoint& if (t == MOVE_COPY || t == MOVE_CLONE) { // These will not increment ref count, and will not chain clones... - // TODO FINDMICH: is this still correct (by flo93)? i doubt it! + // TODO: is this comment still correct (by flo93)? i doubt it! operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddPart,dpart)); } else if (t == MOVE_MOVE) { dpart->setSelected(spart->selected()); // These will increment ref count if not a clone, and will chain clones... - // TODO FINDMICH: is this still correct (by flo93)? i doubt it! + // TODO: is this comment still correct (by flo93)? i doubt it! operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyPart,spart, dpart, true, false)); spart->setSelected(false); @@ -544,6 +545,7 @@ CItem* PartCanvas::newItem(const QPoint& pos, int) switch(track->type()) { case MusECore::Track::MIDI: case MusECore::Track::DRUM: + case MusECore::Track::NEW_DRUM: pa = new MusECore::MidiPart((MusECore::MidiTrack*)track); pa->setTick(x); pa->setLenTick(0); @@ -684,6 +686,7 @@ QMenu* PartCanvas::genItemPopup(CItem* item) act_mexport->setData(16); } break; + case MusECore::Track::NEW_DRUM: case MusECore::Track::DRUM: { partPopup->addAction(MusEGlobal::muse->arranger()->parentWin->startDrumEditAction); partPopup->addAction(MusEGlobal::muse->arranger()->parentWin->startListEditAction); @@ -879,9 +882,6 @@ void PartCanvas::mousePress(QMouseEvent* event) QPoint pt = event->pos(); CItem* item = items.find(pt); - //if (item == 0 && _tool!=AutomationTool) // FINDMICHJETZT. neccessary? (flo93) - // return; - switch (_tool) { default: if (item) @@ -1295,6 +1295,7 @@ void PartCanvas::keyPress(QKeyEvent* event) // else track is midi switch (track->type()) { + case MusECore::Track::NEW_DRUM: case MusECore::Track::DRUM: type = 3; break; @@ -2346,7 +2347,7 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, MusECore::EventList* ev using std::pair; MusECore::iEvent ito(events->lower_bound(to)); - bool isdrum = (mt->type() == MusECore::Track::DRUM); + bool isdrum = (mt->type() == MusECore::Track::DRUM || mt->type() == MusECore::Track::NEW_DRUM); // draw controllers ------------------------------------------ p.setPen(QColor(192,192,color_brightness/2)); diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp index 568bac05..8cc2a05a 100644 --- a/muse2/muse/arranger/tlist.cpp +++ b/muse2/muse/arranger/tlist.cpp @@ -62,6 +62,7 @@ #include "synth.h" #include "config.h" #include "popupmenu.h" +#include "filedialog.h" #include "menutitleitem.h" #ifdef DSSI_SUPPORT @@ -227,6 +228,9 @@ void TList::paint(const QRect& r) case MusECore::Track::DRUM: bg = MusEGlobal::config.drumTrackBg; break; + case MusECore::Track::NEW_DRUM: + bg = MusEGlobal::config.newDrumTrackBg; + break; case MusECore::Track::WAVE: bg = MusEGlobal::config.waveTrackBg; break; @@ -282,6 +286,7 @@ void TList::paint(const QRect& r) case MusECore::Track::MIDI: pm = addtrack_addmiditrackIcon; break; + case MusECore::Track::NEW_DRUM: case MusECore::Track::DRUM: pm = addtrack_drumtrackIcon; break; @@ -585,6 +590,11 @@ void TList::portsPopupMenu(MusECore::Track* t, int x, int y) switch(t->type()) { case MusECore::Track::MIDI: case MusECore::Track::DRUM: + case MusECore::Track::NEW_DRUM: + // FINDMICHJETZT: this is a notice for flo's experimental + // branch! don't forget NEW_DRUM here! + // please don't remove this. i'll do it when + // the time is there. case MusECore::Track::AUDIO_SOFTSYNTH: { MusECore::MidiTrack* track = (MusECore::MidiTrack*)t; @@ -887,7 +897,7 @@ void TList::oportPropertyPopupMenu(MusECore::Track* t, int x, int y) } - if (t->type() != MusECore::Track::MIDI && t->type() != MusECore::Track::DRUM) + if (t->type() != MusECore::Track::MIDI && t->type() != MusECore::Track::DRUM && t->type() != MusECore::Track::NEW_DRUM) return; int oPort = ((MusECore::MidiTrack*)t)->outPort(); MusECore::MidiPort* port = &MusEGlobal::midiPorts[oPort]; @@ -1079,9 +1089,7 @@ MusECore::TrackList TList::getRecEnabledTracks() void TList::changeAutomation(QAction* act) { //printf("changeAutomation %d\n", act->data().toInt()); - - //if (editAutomation->type() == MusECore::Track::MIDI) { // commented out by flo93 - if ( (editAutomation->type() == MusECore::Track::MIDI) || (editAutomation->type() == MusECore::Track::DRUM) ) { + if ( (editAutomation->type() == MusECore::Track::MIDI) || (editAutomation->type() == MusECore::Track::DRUM) || (editAutomation->type() == MusECore::Track::NEW_DRUM) ) { printf("this is wrong, we can't edit automation for midi tracks from arranger yet!\n"); return; } @@ -1107,7 +1115,7 @@ void TList::changeAutomation(QAction* act) //--------------------------------------------------------- void TList::changeAutomationColor(QAction* act) { - if (editAutomation->type() == MusECore::Track::MIDI) { + if ( (editAutomation->type() == MusECore::Track::MIDI) || (editAutomation->type() == MusECore::Track::DRUM) || (editAutomation->type() == MusECore::Track::NEW_DRUM) ) { printf("this is wrong, we can't edit automation for midi tracks from arranger yet!\n"); return; } @@ -1423,9 +1431,21 @@ void TList::mousePressEvent(QMouseEvent* ev) QMenu* p = new QMenu; //p->clear(); // Leave room for normal track IDs - base these at AUDIO_SOFTSYNTH. - p->addAction(QIcon(*automation_clear_dataIcon), tr("Delete Track"))->setData(MusECore::Track::AUDIO_SOFTSYNTH + 1); - p->addAction(QIcon(*track_commentIcon), tr("Track Comment"))->setData(MusECore::Track::AUDIO_SOFTSYNTH + 2); + p->addAction(QIcon(*automation_clear_dataIcon), tr("Delete Track"))->setData(1001); + p->addAction(QIcon(*track_commentIcon), tr("Track Comment"))->setData(1002); p->addSeparator(); + + if (t->type()==MusECore::Track::NEW_DRUM) + { + p->addAction(tr("Save track's drumlist"))->setData(1010); + p->addAction(tr("Save track's drumlist differences to initial state"))->setData(1011); + p->addAction(tr("Load track's drumlist"))->setData(1012); + p->addAction(tr("Reset track's drumlist"))->setData(1013); + p->addAction(tr("Copy track's drumlist to all selected tracks"))->setData(1014); + p->addAction(tr("Copy track's drumlist's differences to all selected tracks"))->setData(1015); + p->addSeparator(); + } + QMenu* pnew = new QMenu(p); pnew->setTitle(tr("Insert Track")); pnew->setIcon(QIcon(*edit_track_addIcon)); @@ -1434,23 +1454,52 @@ void TList::mousePressEvent(QMouseEvent* ev) QAction* act = p->exec(ev->globalPos(), 0); if (act) { int n = act->data().toInt(); - if(n >= MusECore::Track::AUDIO_SOFTSYNTH && n < MENU_ADD_SYNTH_ID_BASE) + if(n >= 1000) { - n -= MusECore::Track::AUDIO_SOFTSYNTH; switch (n) { - case 1: // delete track + case 1001: // delete track MusEGlobal::song->removeTrack0(t); MusEGlobal::audio->msgUpdateSoloStates(); break; - case 2: // show track comment + case 1002: // show track comment { TrackComment* tc = new TrackComment(t, 0); tc->show(); //QToolTip::add( this, "FOOOOOOOOOOOOO" ); } break; - + + case 1010: + saveTrackDrummap((MusECore::MidiTrack*)t, true); + break; + + case 1011: + saveTrackDrummap((MusECore::MidiTrack*)t, false); + break; + + case 1012: + loadTrackDrummap((MusECore::MidiTrack*)t); + break; + + case 1013: + if (QMessageBox::warning(this, tr("Drum map"), + tr("Reset the track's drum map with GM defaults?"), + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) == QMessageBox::Ok) + { + ((MusECore::MidiTrack*)t)->init_drummap(); + MusEGlobal::song->update(SC_DRUMMAP); + } + break; + + case 1014: + copyTrackDrummap((MusECore::MidiTrack*)t, true); + break; + + case 1015: + copyTrackDrummap((MusECore::MidiTrack*)t, false); + break; + default: printf("action %d\n", n); break; @@ -1552,6 +1601,119 @@ void TList::mousePressEvent(QMouseEvent* ev) redraw(); } +void TList::loadTrackDrummap(MusECore::MidiTrack* t, const char* fn_) +{ + QString fn; + + if (fn_==NULL) + fn=MusEGui::getOpenFileName("drummaps", MusEGlobal::drum_map_file_pattern, + this, tr("Muse: Load Track's Drum Map"), 0); + else + fn=QString(fn_); + + if (fn.isEmpty()) + { + printf("ERROR: TList::loadTrackDrummap(): empty filename\n"); + return; + } + + bool popenFlag; + FILE* f = MusEGui::fileOpen(this, fn, QString(".map"), "r", popenFlag, true); + if (f == 0) + { + printf("ERROR: TList::loadTrackDrummap() could not open file %s!\n", fn.toAscii().data()); + return; + } + + MusECore::Xml xml(f); + int mode = 0; + for (;;) { + MusECore::Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) { + case MusECore::Xml::Error: + case MusECore::Xml::End: + return; + case MusECore::Xml::TagStart: + if (mode == 0 && tag == "muse") + mode = 1; + else if (mode == 1 && tag == "our_drummap") { + t->readOurDrumMap(xml, true); + mode = 0; + } + else + xml.unknown("TList::loadTrackDrummap"); + break; + case MusECore::Xml::Attribut: + break; + case MusECore::Xml::TagEnd: + if (!mode && tag == "muse") + goto ende; + default: + break; + } + } + ende: + if (popenFlag) + pclose(f); + else + fclose(f); + + MusEGlobal::song->update(SC_DRUMMAP); +} + +void TList::saveTrackDrummap(MusECore::MidiTrack* t, bool full, const char* fn_) +{ + QString fn; + if (fn_==NULL) + fn = MusEGui::getSaveFileName(QString("drummaps"), MusEGlobal::drum_map_file_save_pattern, + this, tr("MusE: Store Track's Drum Map")); + else + fn = QString(fn_); + + if (fn.isEmpty()) + return; + + bool popenFlag; + FILE* f = MusEGui::fileOpen(this, fn, QString(".map"), "w", popenFlag, false, true); + if (f == 0) + return; + + MusECore::Xml xml(f); + xml.header(); + xml.tag(0, "muse version=\"1.0\""); + t->writeOurDrumMap(1, xml, full); + xml.tag(0, "/muse"); + + if (popenFlag) + pclose(f); + else + fclose(f); +} + +void TList::copyTrackDrummap(MusECore::MidiTrack* t, bool full) +{ + char* tmp1 = tmpnam(NULL); + char tmp2[1000]; + strcpy(tmp2, tmp1); + strcat(tmp2, ".map"); + if (MusEGlobal::debugMsg) + printf("in TList::copyTrackDrummap(); filename is %s\n",tmp2); + + saveTrackDrummap(t, full, tmp2); + + for (MusECore::iTrack it = MusEGlobal::song->tracks()->begin(); it!=MusEGlobal::song->tracks()->end(); it++) + if ((*it)->selected() && (*it)->type()==MusECore::Track::NEW_DRUM) + { + if (MusEGlobal::debugMsg) + printf(" processing track...\n"); + + loadTrackDrummap((MusECore::MidiTrack*)(*it), tmp2); + } + + remove(tmp2); +} + //--------------------------------------------------------- // selectTrack //--------------------------------------------------------- @@ -1879,13 +2041,14 @@ void TList::classesPopupMenu(MusECore::Track* t, int x, int y) p.clear(); p.addAction(QIcon(*addtrack_addmiditrackIcon), tr("Midi"))->setData(MusECore::Track::MIDI); p.addAction(QIcon(*addtrack_drumtrackIcon), tr("Drum"))->setData(MusECore::Track::DRUM); + p.addAction(QIcon(*addtrack_drumtrackIcon), tr("New style drum"))->setData(MusECore::Track::NEW_DRUM); QAction* act = p.exec(mapToGlobal(QPoint(x, y)), 0); if (!act) return; int n = act->data().toInt(); - if (MusECore::Track::TrackType(n) == MusECore::Track::MIDI && t->type() == MusECore::Track::DRUM) { + if ((MusECore::Track::TrackType(n) == MusECore::Track::MIDI || MusECore::Track::TrackType(n) == MusECore::Track::NEW_DRUM) && t->type() == MusECore::Track::DRUM) { // // Drum -> Midi // @@ -1919,11 +2082,11 @@ void TList::classesPopupMenu(MusECore::Track* t, int x, int y) } } - t->setType(MusECore::Track::MIDI); + t->setType(MusECore::Track::TrackType(n)); MusEGlobal::audio->msgIdle(false); MusEGlobal::song->update(SC_EVENT_MODIFIED); } - else if (MusECore::Track::TrackType(n) == MusECore::Track::DRUM && t->type() == MusECore::Track::MIDI) { + else if (MusECore::Track::TrackType(n) == MusECore::Track::DRUM && (t->type() == MusECore::Track::MIDI || t->type() == MusECore::Track::NEW_DRUM)) { // // Midi -> Drum // @@ -1981,6 +2144,13 @@ void TList::classesPopupMenu(MusECore::Track* t, int x, int y) MusEGlobal::audio->msgIdle(false); MusEGlobal::song->update(SC_EVENT_MODIFIED); } + else // MIDI -> NEW_DRUM or vice versa. added by flo. + { + MusEGlobal::audio->msgIdle(true); + t->setType(MusECore::Track::TrackType(n)); + MusEGlobal::audio->msgIdle(false); + MusEGlobal::song->update(SC_TRACK_MODIFIED); + } } } // namespace MusEGui diff --git a/muse2/muse/arranger/tlist.h b/muse2/muse/arranger/tlist.h index 5ae3fbe9..53f708e7 100644 --- a/muse2/muse/arranger/tlist.h +++ b/muse2/muse/arranger/tlist.h @@ -119,6 +119,9 @@ class TList : public QWidget { void songChanged(int flags); void changeAutomation(QAction*); void changeAutomationColor(QAction*); + void loadTrackDrummap(MusECore::MidiTrack*, const char* filename=NULL); + void saveTrackDrummap(MusECore::MidiTrack*, bool full, const char* filename=NULL); + void copyTrackDrummap(MusECore::MidiTrack*, bool full); signals: ///void selectionChanged(); diff --git a/muse2/muse/conf.cpp b/muse2/muse/conf.cpp index ea2b33f3..e9ec1396 100644 --- a/muse2/muse/conf.cpp +++ b/muse2/muse/conf.cpp @@ -813,6 +813,8 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig MusEGlobal::config.midiTrackLabelBg = readColor(xml); else if (tag == "drumTrackLabelBg") MusEGlobal::config.drumTrackLabelBg = readColor(xml); + else if (tag == "newDrumTrackLabelBg") + MusEGlobal::config.newDrumTrackLabelBg = readColor(xml); else if (tag == "waveTrackLabelBg") MusEGlobal::config.waveTrackLabelBg = readColor(xml); else if (tag == "outputTrackLabelBg") @@ -832,6 +834,8 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig MusEGlobal::config.ctrlGraphFg = readColor(xml); else if (tag == "drumTrackBg") MusEGlobal::config.drumTrackBg = readColor(xml); + else if (tag == "newDrumTrackBg") + MusEGlobal::config.newDrumTrackBg = readColor(xml); else if (tag == "waveTrackBg") MusEGlobal::config.waveTrackBg = readColor(xml); else if (tag == "outputTrackBg") @@ -949,6 +953,8 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig MusEGlobal::config.startMode = xml.parseInt(); else if (tag == "startSong") MusEGlobal::config.startSong = xml.parse1(); + else if (tag == "newDrumRecordCondition") + MusEGlobal::config.newDrumRecordCondition = MusECore::newDrumRecordCondition_t(xml.parseInt()); else if (tag == "projectBaseFolder") MusEGlobal::config.projectBaseFolder = xml.parse1(); else if (tag == "projectStoreInFolder") @@ -963,6 +969,8 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig MusEGlobal::config.rangeMarkerWithoutMMB = xml.parseInt(); else if (tag == "addHiddenTracks") MusEGlobal::config.addHiddenTracks = xml.parseInt(); + else if (tag == "drumTrackPreference") + MusEGlobal::config.drumTrackPreference = (MusEGlobal::drumTrackPreference_t) xml.parseInt(); else if (tag == "unhideTracks") MusEGlobal::config.unhideTracks = xml.parseInt(); @@ -1280,6 +1288,7 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const xml.intTag(level, "importMidiSplitParts", MusEGlobal::config.importMidiSplitParts); xml.intTag(level, "startMode", MusEGlobal::config.startMode); xml.strTag(level, "startSong", MusEGlobal::config.startSong); + xml.intTag(level, "newDrumRecordCondition", MusEGlobal::config.newDrumRecordCondition); xml.strTag(level, "projectBaseFolder", MusEGlobal::config.projectBaseFolder); xml.intTag(level, "projectStoreInFolder", MusEGlobal::config.projectStoreInFolder); xml.intTag(level, "useProjectSaveDialog", MusEGlobal::config.useProjectSaveDialog); @@ -1305,6 +1314,7 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const xml.intTag(level, "unhideTracks", MusEGlobal::config.unhideTracks); xml.intTag(level, "addHiddenTracks", MusEGlobal::config.addHiddenTracks); + xml.intTag(level, "drumTrackPreference", MusEGlobal::config.drumTrackPreference); xml.intTag(level, "waveTracksVisible", MusECore::WaveTrack::visible()); xml.intTag(level, "auxTracksVisible", MusECore::AudioAux::visible()); @@ -1349,6 +1359,7 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const xml.colorTag(level, "mixerBg", MusEGlobal::config.mixerBg); xml.colorTag(level, "midiTrackLabelBg", MusEGlobal::config.midiTrackLabelBg); xml.colorTag(level, "drumTrackLabelBg", MusEGlobal::config.drumTrackLabelBg); + xml.colorTag(level, "newDrumTrackLabelBg",MusEGlobal::config.newDrumTrackLabelBg); xml.colorTag(level, "waveTrackLabelBg", MusEGlobal::config.waveTrackLabelBg); xml.colorTag(level, "outputTrackLabelBg", MusEGlobal::config.outputTrackLabelBg); xml.colorTag(level, "inputTrackLabelBg", MusEGlobal::config.inputTrackLabelBg); @@ -1359,6 +1370,7 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const xml.colorTag(level, "midiTrackBg", MusEGlobal::config.midiTrackBg); xml.colorTag(level, "ctrlGraphFg", MusEGlobal::config.ctrlGraphFg); xml.colorTag(level, "drumTrackBg", MusEGlobal::config.drumTrackBg); + xml.colorTag(level, "newDrumTrackBg",MusEGlobal::config.newDrumTrackBg); xml.colorTag(level, "waveTrackBg", MusEGlobal::config.waveTrackBg); xml.colorTag(level, "outputTrackBg", MusEGlobal::config.outputTrackBg); xml.colorTag(level, "inputTrackBg", MusEGlobal::config.inputTrackBg); @@ -1607,6 +1619,8 @@ void MidiFileConfig::updateValues() optNoteOffs->setChecked(MusEGlobal::config.expOptimNoteOffs); twoByteTimeSigs->setChecked(MusEGlobal::config.exp2ByteTimeSigs); splitPartsCheckBox->setChecked(MusEGlobal::config.importMidiSplitParts); + newDrumsCheckbox->setChecked(MusEGlobal::config.importMidiNewStyleDrum); + oldDrumsCheckbox->setChecked(!MusEGlobal::config.importMidiNewStyleDrum); } //--------------------------------------------------------- @@ -1626,6 +1640,7 @@ void MidiFileConfig::okClicked() MusEGlobal::config.expOptimNoteOffs = optNoteOffs->isChecked(); MusEGlobal::config.exp2ByteTimeSigs = twoByteTimeSigs->isChecked(); MusEGlobal::config.importMidiSplitParts = splitPartsCheckBox->isChecked(); + MusEGlobal::config.importMidiNewStyleDrum = newDrumsCheckbox->isChecked(); MusEGlobal::muse->changeConfig(true); // write config file close(); @@ -1659,6 +1674,7 @@ void MixerConfig::write(int level, MusECore::Xml& xml) xml.intTag(level, "showMidiTracks", showMidiTracks); xml.intTag(level, "showDrumTracks", showDrumTracks); + xml.intTag(level, "showNewDrumTracks", showNewDrumTracks); xml.intTag(level, "showInputTracks", showInputTracks); xml.intTag(level, "showOutputTracks", showOutputTracks); xml.intTag(level, "showWaveTracks", showWaveTracks); @@ -1691,6 +1707,8 @@ void MixerConfig::read(MusECore::Xml& xml) showMidiTracks = xml.parseInt(); else if (tag == "showDrumTracks") showDrumTracks = xml.parseInt(); + else if (tag == "showNewDrumTracks") + showNewDrumTracks = xml.parseInt(); else if (tag == "showInputTracks") showInputTracks = xml.parseInt(); else if (tag == "showOutputTracks") diff --git a/muse2/muse/ctrl/ctrlcanvas.cpp b/muse2/muse/ctrl/ctrlcanvas.cpp index 96143b10..ddecdbf6 100644 --- a/muse2/muse/ctrl/ctrlcanvas.cpp +++ b/muse2/muse/ctrl/ctrlcanvas.cpp @@ -39,6 +39,7 @@ #include "gconfig.h" #include "ctrlpanel.h" #include "midiedit/drummap.h" +#include "drumedit.h" static MusECore::MidiCtrlValList veloList(MusECore::CTRL_VELOCITY); // dummy @@ -211,6 +212,11 @@ CtrlCanvas::CtrlCanvas(MidiEditor* e, QWidget* parent, int xmag, noEvents=false; //_isFirstMove = true; //_lastDelta = QPoint(0, 0); + + if (dynamic_cast<DrumEdit*>(editor) && dynamic_cast<DrumEdit*>(editor)->old_style_drummap_mode()==false) + filterTrack=true; + else + filterTrack=false; ctrl = &veloList; _controller = &MusECore::veloCtrl; @@ -229,10 +235,10 @@ CtrlCanvas::CtrlCanvas(MidiEditor* e, QWidget* parent, int xmag, connect(MusEGlobal::song, SIGNAL(songChanged(int)), SLOT(songChanged(int))); connect(MusEGlobal::muse, SIGNAL(configChanged()), SLOT(configChanged())); - curDrumInstrument = editor->curDrumInstrument(); - //printf("CtrlCanvas::CtrlCanvas curDrumInstrument:%d\n", curDrumInstrument); + setCurDrumPitch(editor->curDrumInstrument()); + //printf("CtrlCanvas::CtrlCanvas curDrumPitch:%d\n", curDrumPitch); - connect(editor, SIGNAL(curDrumInstrumentChanged(int)), SLOT(setCurDrumInstrument(int))); + connect(editor, SIGNAL(curDrumInstrumentChanged(int)), SLOT(setCurDrumPitch(int))); updateItems(); } @@ -329,7 +335,7 @@ void CtrlCanvas::setMidiController(int num) _panel->setHWController(curTrack, &MusECore::veloCtrl); else _panel->setHWController(curTrack, _controller); - } + } } //--------------------------------------------------------- @@ -538,15 +544,21 @@ void CtrlCanvas::partControllers(const MusECore::MidiPart* part, int num, int* d int di; int n; - if((mt->type() != MusECore::Track::DRUM) && curDrumInstrument != -1) + if(!mt->isDrumTrack() && curDrumPitch != -1) printf("keyfilter != -1 in non drum track?\n"); - if((mt->type() == MusECore::Track::DRUM) && (curDrumInstrument != -1) && ((num & 0xff) == 0xff)) + if((mt->type() == MusECore::Track::DRUM) && (curDrumPitch > 0) && ((num & 0xff) == 0xff)) { - di = (num & ~0xff) | curDrumInstrument; - n = (num & ~0xff) | MusEGlobal::drumMap[curDrumInstrument].anote; // construct real controller number - //num = (num & ~0xff) | curDrumInstrument); // construct real controller number - mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[curDrumInstrument].port]; + di = (num & ~0xff) | curDrumPitch; + n = (num & ~0xff) | MusEGlobal::drumMap[curDrumPitch].anote; // construct real controller number + //num = (num & ~0xff) | curDrumPitch); // construct real controller number + mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[curDrumPitch].port]; + } + else if ((mt->type() == MusECore::Track::NEW_DRUM) && (curDrumPitch > 0) && ((num & 0xff) == 0xff)) //FINDMICHJETZT does this work? + { + di = (num & ~0xff) | curDrumPitch; + n = (num & ~0xff) | curDrumPitch; + mp = &MusEGlobal::midiPorts[mt->outPort()]; } else { @@ -602,6 +614,10 @@ void CtrlCanvas::updateItems() CEvent* lastce = 0; MusECore::MidiPart* part = (MusECore::MidiPart*)(p->second); + + if (filterTrack && part->track() != curTrack) + continue; + MusECore::EventList* el = part->events(); //MusECore::MidiController* mc; MusECore::MidiCtrlValList* mcvl; @@ -618,15 +634,15 @@ void CtrlCanvas::updateItems() if(_cnum == MusECore::CTRL_VELOCITY && e.type() == MusECore::Note) { - //printf("CtrlCanvas::updateItems MusECore::CTRL_VELOCITY curDrumInstrument:%d\n", curDrumInstrument); + //printf("CtrlCanvas::updateItems MusECore::CTRL_VELOCITY curDrumPitch:%d\n", curDrumPitch); newev = 0; - if(curDrumInstrument == -1) + if (curDrumPitch == -1) // and NOT >0 { // This is interesting - it would allow ALL drum note velocities to be shown. // But currently the drum list ALWAYS has a selected item so this is not supposed to happen. items.add(newev = new CEvent(e, part, e.velo())); } - else if (e.dataA() == curDrumInstrument) //same note + else if (e.dataA() == curDrumPitch) //same note. if curDrumPitch==-2, this never is true items.add(newev = new CEvent(e, part, e.velo())); if(newev && e.selected()) selection.push_back(newev); @@ -677,7 +693,7 @@ void CtrlCanvas::updateSelections() void CtrlCanvas::viewMousePressEvent(QMouseEvent* event) { - if(!_controller) // p4.0.27 + if(!_controller || curDrumPitch==-2) // p4.0.27 return; start = event->pos(); @@ -785,7 +801,7 @@ void CtrlCanvas::viewMousePressEvent(QMouseEvent* event) void CtrlCanvas::viewMouseMoveEvent(QMouseEvent* event) { - if(!_controller) // p4.0.27 + if(!_controller || curDrumPitch==-2) // p4.0.27 return; QPoint pos = event->pos(); @@ -796,7 +812,7 @@ void CtrlCanvas::viewMouseMoveEvent(QMouseEvent* event) if (!moving) break; drag = DRAG_LASSO; - // weiter mit DRAG_LASSO: + // fallthrough case DRAG_LASSO: lasso.setRect(start.x(), start.y(), dist.x(), dist.y()); redraw(); @@ -858,7 +874,7 @@ void CtrlCanvas::viewMouseReleaseEvent(QMouseEvent* event) case DRAG_LASSO_START: lasso.setRect(-1, -1, -1, -1); - + //fallthrough case DRAG_LASSO: if(_controller) // p4.0.27 { @@ -1691,8 +1707,8 @@ void CtrlCanvas::pdrawItems(QPainter& p, const QRect& rect, const MusECore::Midi MusECore::MidiTrack* mt = part->track(); MusECore::MidiPort* mp; - if((mt->type() == MusECore::Track::DRUM) && (curDrumInstrument != -1) && ((_cnum & 0xff) == 0xff)) - mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[curDrumInstrument].port]; + if((mt->type() == MusECore::Track::DRUM) && (curDrumPitch > 0) && ((_cnum & 0xff) == 0xff)) + mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[curDrumPitch].port]; else mp = &MusEGlobal::midiPorts[mt->outPort()]; @@ -1858,7 +1874,7 @@ void CtrlCanvas::pdraw(QPainter& p, const QRect& rect) { MusECore::MidiPart* part = (MusECore::MidiPart*)(ip->second); //if((velo && part == curPart) || (!velo && part != curPart)) - if(part == curPart) + if(part == curPart || (filterTrack && part->track() != curTrack)) continue; // Draw items for all parts - other than current part pdrawItems(p, rect, part, velo, !velo); @@ -1924,10 +1940,14 @@ void CtrlCanvas::drawOverlay(QPainter& p) int y = fontMetrics().lineSpacing() + 2; p.drawText(2, y, s); - if (noEvents) { + if (curDrumPitch==-2) + { + p.drawText(2 , y * 2, tr("Make the current part's track match the selected drumlist entry")); + } + else if (noEvents) { //p.setFont(MusEGlobal::config.fonts[3]); //p.setPen(Qt::black); - //p.drawText(width()/2-100,height()/2-10, tr("Use shift + pencil or line tool to draw new events")); + //p.drawText(width()/2-100,height()/2-10, "Use shift + pencil or line tool to draw new events"); p.drawText(2 , y * 2, tr("Drawing hint: Hold Ctrl to affect only existing events")); } } @@ -1946,9 +1966,16 @@ QRect CtrlCanvas::overlayRect() const //r.translate(2, 2); // top/left margin int y = fm.lineSpacing() + 2; r.translate(2, y); - if (noEvents) + if (curDrumPitch==-2) { - QRect r2(fm.boundingRect(QString(tr("Use shift + pencil or line tool to draw new events")))); + QRect r2(fm.boundingRect(QString(tr("Make the current part's track match the selected drumlist entry")))); + //r2.translate(width()/2-100, height()/2-10); + r2.translate(2, y * 2); + r |= r2; + } + else if (noEvents) + { + QRect r2(fm.boundingRect(QString(tr("Use pencil or line tool to draw new events")))); //r2.translate(width()/2-100, height()/2-10); r2.translate(2, y * 2); r |= r2; @@ -1979,13 +2006,24 @@ void CtrlCanvas::draw(QPainter& p, const QRect& rect) } //--------------------------------------------------------- -// setCurDrumInstrument +// setCurDrumPitch //--------------------------------------------------------- -void CtrlCanvas::setCurDrumInstrument(int di) +void CtrlCanvas::setCurDrumPitch(int instrument) +{ + DrumEdit* drumedit = dynamic_cast<DrumEdit*>(editor); + if (drumedit == NULL || drumedit->old_style_drummap_mode()) + curDrumPitch = instrument; + else // new style drummap mode { - curDrumInstrument = di; - //printf("CtrlCanvas::setCurDrumInstrument curDrumInstrument:%d\n", curDrumInstrument); + if (drumedit->get_instrument_map()[instrument].tracks.contains(curTrack)) + curDrumPitch = drumedit->get_instrument_map()[instrument].pitch; + else + curDrumPitch = -2; // this means "invalid", but not "unused" + } + + + //printf("CtrlCanvas::setCurDrumPitch curDrumPitch:%d\n", curDrumPitch); // // check if current controller is only valid for @@ -2001,6 +2039,13 @@ void CtrlCanvas::setCurDrumInstrument(int di) // } // Removed by T356 //songChanged(-1); - } +} + +void CtrlCanvas::curPartHasChanged(MusECore::Part*) +{ + setCurTrackAndPart(); + setCurDrumPitch(editor->curDrumInstrument()); + songChanged(SC_EVENT_MODIFIED); +} } // namespace MusEGui diff --git a/muse2/muse/ctrl/ctrlcanvas.h b/muse2/muse/ctrl/ctrlcanvas.h index f9fcb54f..50b71bbe 100644 --- a/muse2/muse/ctrl/ctrlcanvas.h +++ b/muse2/muse/ctrl/ctrlcanvas.h @@ -121,6 +121,7 @@ class CtrlCanvas : public MusEGui::View { int line2y; bool drawLineMode; bool noEvents; + bool filterTrack; void viewMousePressEvent(QMouseEvent* event); void viewMouseMoveEvent(QMouseEvent*); @@ -161,7 +162,7 @@ class CtrlCanvas : public MusEGui::View { QPoint start; MusEGui::Tool tool; unsigned pos[3]; - int curDrumInstrument; //Used by the drum-editor to view velocity of only one key (one drum) + int curDrumPitch; //Used by the drum-editor to view velocity of only one key (one drum) void leaveEvent(QEvent*e); QPoint raster(const QPoint&) const; @@ -181,12 +182,13 @@ class CtrlCanvas : public MusEGui::View { private slots: void songChanged(int type); void configChanged(); - void setCurDrumInstrument(int); + void setCurDrumPitch(int); public slots: void setTool(int t); void setPos(int, unsigned, bool adjustScrollbar); void setController(int ctrl); + void curPartHasChanged(MusECore::Part*); signals: void followEvent(int); @@ -201,6 +203,7 @@ class CtrlCanvas : public MusEGui::View { MusECore::MidiCtrlValList* ctrlValList() { return ctrl; } MusECore::MidiController* controller() { return _controller; } MusECore::MidiTrack* track() const { return curTrack; } + int getCurDrumPitch() const { return curDrumPitch; } }; } // namespace MusEGui diff --git a/muse2/muse/ctrl/ctrledit.cpp b/muse2/muse/ctrl/ctrledit.cpp index 7c960dd8..5fbdecaf 100644 --- a/muse2/muse/ctrl/ctrledit.cpp +++ b/muse2/muse/ctrl/ctrledit.cpp @@ -55,8 +55,10 @@ CtrlEdit::CtrlEdit(QWidget* parent, MidiEditor* e, int xmag, setObjectName(name); setAttribute(Qt::WA_DeleteOnClose); QHBoxLayout* hbox = new QHBoxLayout; - panel = new CtrlPanel(0, e, "panel"); - canvas = new CtrlCanvas(e, 0, xmag, "ctrlcanvas", panel); + canvas = new CtrlCanvas(e, 0, xmag, "ctrlcanvas"); + panel = new CtrlPanel(0, e, canvas, "panel"); + canvas->setPanel(panel); + QWidget* vscale = new MusEGui::VScale; hbox->setContentsMargins(0, 0, 0, 0); @@ -180,4 +182,9 @@ void CtrlEdit::setController(const QString& name) } } +void CtrlEdit::curPartHasChanged(MusECore::Part* p) +{ + canvas->curPartHasChanged(p); +} + } // namespace MusEGui diff --git a/muse2/muse/ctrl/ctrledit.h b/muse2/muse/ctrl/ctrledit.h index 1f7a67a9..a0a941cc 100644 --- a/muse2/muse/ctrl/ctrledit.h +++ b/muse2/muse/ctrl/ctrledit.h @@ -60,6 +60,7 @@ class CtrlEdit : public QWidget { void setXMag(int val) { canvas->setXMag(val); } void setCanvasWidth(int w); void setController(int /*n*/); + void curPartHasChanged(MusECore::Part*); signals: void timeChanged(unsigned); diff --git a/muse2/muse/ctrl/ctrlpanel.cpp b/muse2/muse/ctrl/ctrlpanel.cpp index 1889c608..e46f949c 100644 --- a/muse2/muse/ctrl/ctrlpanel.cpp +++ b/muse2/muse/ctrl/ctrlpanel.cpp @@ -64,7 +64,7 @@ namespace MusEGui { // CtrlPanel //--------------------------------------------------------- -CtrlPanel::CtrlPanel(QWidget* parent, MidiEditor* e, const char* name) +CtrlPanel::CtrlPanel(QWidget* parent, MidiEditor* e, CtrlCanvas* c, const char* name) : QWidget(parent) { setObjectName(name); @@ -72,6 +72,7 @@ CtrlPanel::CtrlPanel(QWidget* parent, MidiEditor* e, const char* name) //ctrlMainPop = 0; //ctrlSubPop = 0; editor = e; + ctrlcanvas = c; setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); QVBoxLayout* vbox = new QVBoxLayout; QHBoxLayout* bbox = new QHBoxLayout; @@ -173,11 +174,11 @@ void CtrlPanel::heartBeat() { int outport; int chan; - int cdi = editor->curDrumInstrument(); - if(_track->type() == MusECore::Track::DRUM && ((_ctrl->num() & 0xff) == 0xff) && cdi != -1) + int cdp = ctrlcanvas->getCurDrumPitch(); + if(_track->type() == MusECore::Track::DRUM && ((_ctrl->num() & 0xff) == 0xff) && cdp != -1) { - outport = MusEGlobal::drumMap[cdi].port; - chan = MusEGlobal::drumMap[cdi].channel; + outport = MusEGlobal::drumMap[cdp].port; + chan = MusEGlobal::drumMap[cdp].channel; } else { @@ -251,11 +252,11 @@ void CtrlPanel::labelDoubleClicked() int outport; int chan; - int cdi = editor->curDrumInstrument(); - if(_track->type() == MusECore::Track::DRUM && ((_ctrl->num() & 0xff) == 0xff) && cdi != -1) + int cdp = ctrlcanvas->getCurDrumPitch(); + if(_track->type() == MusECore::Track::DRUM && ((_ctrl->num() & 0xff) == 0xff) && cdp != -1) { - outport = MusEGlobal::drumMap[cdi].port; - chan = MusEGlobal::drumMap[cdi].channel; + outport = MusEGlobal::drumMap[cdp].port; + chan = MusEGlobal::drumMap[cdp].channel; } else { @@ -355,11 +356,11 @@ void CtrlPanel::ctrlChanged(double val) int outport; int chan; - int cdi = editor->curDrumInstrument(); - if(_track->type() == MusECore::Track::DRUM && ((_ctrl->num() & 0xff) == 0xff) && cdi != -1) + int cdp = ctrlcanvas->getCurDrumPitch(); + if(_track->type() == MusECore::Track::DRUM && ((_ctrl->num() & 0xff) == 0xff) && cdp != -1) { - outport = MusEGlobal::drumMap[cdi].port; - chan = MusEGlobal::drumMap[cdi].channel; + outport = MusEGlobal::drumMap[cdp].port; + chan = MusEGlobal::drumMap[cdp].channel; } else { @@ -424,13 +425,19 @@ void CtrlPanel::setHWController(MusECore::MidiTrack* t, MusECore::MidiController MusECore::MidiPort* mp; int ch; - int cdi = editor->curDrumInstrument(); + int cdp = ctrlcanvas->getCurDrumPitch(); _dnum = _ctrl->num(); - if(_track->type() == MusECore::Track::DRUM && ((_dnum & 0xff) == 0xff) && cdi != -1) + if(_track->type() == MusECore::Track::DRUM && ((_dnum & 0xff) == 0xff) && cdp != -1) { - _dnum = (_dnum & ~0xff) | MusEGlobal::drumMap[cdi].anote; - mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[cdi].port]; - ch = MusEGlobal::drumMap[cdi].channel; + _dnum = (_dnum & ~0xff) | MusEGlobal::drumMap[cdp].anote; + mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[cdp].port]; + ch = MusEGlobal::drumMap[cdp].channel; + } + else if(_track->type() == MusECore::Track::NEW_DRUM && ((_dnum & 0xff) == 0xff) && cdp != -1) + { + _dnum = (_dnum & ~0xff) | cdp; //FINDMICHJETZT does that work? + mp = &MusEGlobal::midiPorts[_track->outPort()]; + ch = _track->outChannel(); } else { @@ -542,6 +549,21 @@ void CtrlPanel::setHeight(int h) } #if 0 +/* WARNING: INVALID CODE! *\ + * the code which has been disabled by the above #if 0 is partly * + * OBSOLETE! it lacks support for new-style drum tracks, especially * + * the drum-controller-handling for these! * + * * + * when you ever enable that code again, first check the changes * + * flo93 did somewhere between revision 1188 and 1188+something * + * (let's say, 1195; it's NOT the revision in which this comment * + * has been introduced) in experimental to the currently enabled * + * code below. then apply similar changes to the currently disabled * +\* code here! */ +#error "INVALID CODE. please check the comment in ctrlpanel.cpp which starts with 'WARNING: INVALID CODE'" +just to be sure: dear compiler, please refuse to compile. +dear user: read the comment above! + struct CI { QString s; bool used; @@ -564,8 +586,9 @@ void CtrlPanel::ctrlPopup() MusECore::MidiTrack* track = (MusECore::MidiTrack*)(part->track()); int channel = track->outChannel(); MusECore::MidiPort* port = &MusEGlobal::midiPorts[track->outPort()]; - int curDrumInstrument = editor->curDrumInstrument(); + int curDrumPitch = ctrlcanvas->getCurDrumPitch(); bool isDrum = track->type() == MusECore::Track::DRUM; + bool isNewDrum = track->type() == MusECore::Track::NEW_DRUM; QMenu* pop = new QMenu; //pop->clear(); @@ -583,12 +606,20 @@ void CtrlPanel::ctrlPopup() MusECore::MidiController* c = port->midiController(cl->num()); // dont show drum specific controller if not a drum track if ((c->num() & 0xff) == 0xff) { - if (!isDrum) - continue; - // only show controller for curDrumInstrument: - if ((cl->num() & 0xff) != MusEGlobal::drumMap[curDrumInstrument].anote) { - continue; - } + if (isDrum) + { + // only show controller for curDrumPitch: + if ((curDrumPitch == -1) || ((cl->num() & 0xff) != MusEGlobal::drumMap[curDrumPitch].anote)) + continue; + } + else if (isNewDrum) + { + // only show controller for curDrumPitch: FINDMICH does this work? + if ((curDrumPitch == -1) || ((cl->num() & 0xff) != curDrumPitch)) + continue; + } + else + continue; } isList i = sList.begin(); for (; i != sList.end(); ++i) { @@ -651,8 +682,10 @@ void CtrlPanel::ctrlPopup() for (iMusECore::MidiController ci = mcl->begin(); ci != mcl->end(); ++ci) { int num = ci->second->num(); - if (isDrum && ((num & 0xff) == 0xff)) - num = (num & ~0xff) + MusEGlobal::drumMap[curDrumInstrument].anote; + if (isDrum && ((num & 0xff) == 0xff) && curDrumPitch!=-1) + num = (num & ~0xff) + MusEGlobal::drumMap[curDrumPitch].anote; + if (isNewDrum && ((num & 0xff) == 0xff) && curDrumPitch!=-1) //FINDMICHJETZT does this work? + num = (num & ~0xff) + curDrumPitch; if(cll->find(channel, num) == cll->end()) pop1->addAction(ci->second->name()); @@ -665,8 +698,10 @@ void CtrlPanel::ctrlPopup() c = ci->second; if (c->name() == s) { int num = c->num(); - if (isDrum && ((num & 0xff) == 0xff)) - num = (num & ~0xff) + MusEGlobal::drumMap[curDrumInstrument].anote; + if (isDrum && ((num & 0xff) == 0xff) && curDrumPitch!=-1) + num = (num & ~0xff) + MusEGlobal::drumMap[curDrumPitch].anote; + if (isNewDrum && ((num & 0xff) == 0xff) && curDrumPitch!=-1) //FINDMICHJETZT does this work? + num = (num & ~0xff) + curDrumPitch; if(cll->find(channel, num) == cll->end()) { @@ -722,8 +757,9 @@ void CtrlPanel::ctrlPopup() MusECore::MidiTrack* track = (MusECore::MidiTrack*)(part->track()); int channel = track->outChannel(); MusECore::MidiPort* port = &MusEGlobal::midiPorts[track->outPort()]; - int curDrumInstrument = editor->curDrumInstrument(); + int curDrumPitch = ctrlcanvas->getCurDrumPitch(); bool isDrum = track->type() == MusECore::Track::DRUM; + bool isNewDrum = track->type() == MusECore::Track::NEW_DRUM; MusECore::MidiInstrument* instr = port->instrument(); MusECore::MidiControllerList* mcl = instr->controller(); @@ -739,12 +775,20 @@ void CtrlPanel::ctrlPopup() MusECore::MidiController* c = port->midiController(cl->num()); // dont show drum specific controller if not a drum track if ((c->num() & 0xff) == 0xff) { - if (!isDrum) - continue; - // only show controller for curDrumInstrument: - if ((cl->num() & 0xff) != MusEGlobal::drumMap[curDrumInstrument].anote) { - continue; - } + if (isDrum) + { + // only show controller for curDrumPitch: + if ((curDrumPitch == -1) || ((cl->num() & 0xff) != MusEGlobal::drumMap[curDrumPitch].anote)) + continue; + } + else if (isNewDrum) + { + // only show controller for curDrumPitch: FINDMICH does this work? + if ((curDrumPitch == -1) || ((cl->num() & 0xff) != curDrumPitch)) + continue; + } + else + continue; } isList i = sList.begin(); for (; i != sList.end(); ++i) { @@ -854,10 +898,12 @@ void CtrlPanel::ctrlPopup() int num = ci->second->num(); if((num & 0xff) == 0xff) { - // dont show drum specific controller if not a drum track - if(!isDrum) + if (isDrum && curDrumPitch!=-1) + num = (num & ~0xff) + MusEGlobal::drumMap[curDrumPitch].anote; + else if (isNewDrum && curDrumPitch!=-1) + num = (num & ~0xff) + curDrumPitch; //FINDMICH does this work? + else // dont show drum specific controller if not a drum track continue; - num = (num & ~0xff) + MusEGlobal::drumMap[curDrumInstrument].anote; } if(cll->find(channel, num) == cll->end()) @@ -884,8 +930,10 @@ void CtrlPanel::ctrlPopup() { c = ci->second; int num = c->num(); - if (isDrum && ((num & 0xff) == 0xff)) - num = (num & ~0xff) + MusEGlobal::drumMap[curDrumInstrument].anote; + if (isDrum && ((num & 0xff) == 0xff) && curDrumPitch!=-1) + num = (num & ~0xff) + MusEGlobal::drumMap[curDrumPitch].anote; + else if (isNewDrum && ((num & 0xff) == 0xff) && curDrumPitch!=-1) + num = (num & ~0xff) + curDrumPitch; //FINDMICHJETZT does this work? if(num != rv2) continue; @@ -921,8 +969,11 @@ void CtrlPanel::ctrlPopup() if (act2) { int rv2 = act2->data().toInt(); int num = rv2; - if (isDrum && ((num & 0xff) == 0xff)) - num = (num & ~0xff) + MusEGlobal::drumMap[curDrumInstrument].anote; + if (isDrum && ((num & 0xff) == 0xff) && curDrumPitch!=-1) + num = (num & ~0xff) + MusEGlobal::drumMap[curDrumPitch].anote; + if (isNewDrum && ((num & 0xff) == 0xff) && curDrumPitch!=-1) + num = (num & ~0xff) + curDrumPitch; //FINDMICHJETZT does this work? + if(cll->find(channel, num) == cll->end()) { MusECore::MidiCtrlValList* vl = new MusECore::MidiCtrlValList(num); @@ -969,11 +1020,11 @@ void CtrlPanel::ctrlRightClicked(const QPoint& p, int /*id*/) if(!editor->curCanvasPart() || !_ctrl) return; - int cdi = editor->curDrumInstrument(); + int cdp = ctrlcanvas->getCurDrumPitch(); int ctlnum = _ctrl->num(); - if(_track->type() == MusECore::Track::DRUM && ((ctlnum & 0xff) == 0xff) && cdi != -1) - //ctlnum = (ctlnum & ~0xff) | MusEGlobal::drumMap[cdi].enote; - ctlnum = (ctlnum & ~0xff) | cdi; + if(_track->type() == MusECore::Track::DRUM && ((ctlnum & 0xff) == 0xff) && cdp != -1) + //ctlnum = (ctlnum & ~0xff) | MusEGlobal::drumMap[cdp].enote; + ctlnum = (ctlnum & ~0xff) | cdp; MusECore::MidiPart* part = dynamic_cast<MusECore::MidiPart*>(editor->curCanvasPart()); MusEGlobal::song->execMidiAutomationCtlPopup(0, part, p, ctlnum); diff --git a/muse2/muse/ctrl/ctrlpanel.h b/muse2/muse/ctrl/ctrlpanel.h index c28708cb..ab6c1777 100644 --- a/muse2/muse/ctrl/ctrlpanel.h +++ b/muse2/muse/ctrl/ctrlpanel.h @@ -37,6 +37,7 @@ namespace MusEGui { class DoubleLabel; class Knob; class MidiEditor; +class CtrlCanvas; //--------------------------------------------------------- // CtrlPanel @@ -48,6 +49,7 @@ class CtrlPanel: public QWidget { //QMenu* pop; QPushButton* selCtrl; MidiEditor* editor; + CtrlCanvas* ctrlcanvas; MusECore::MidiTrack* _track; MusECore::MidiController* _ctrl; @@ -77,7 +79,7 @@ class CtrlPanel: public QWidget { void ctrlPopup(); public: - CtrlPanel(QWidget*, MidiEditor*, const char* name = 0); + CtrlPanel(QWidget*, MidiEditor*, CtrlCanvas*, const char* name = 0); void setHWController(MusECore::MidiTrack* t, MusECore::MidiController* ctrl); }; diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp index 77825f52..71621b0d 100644 --- a/muse2/muse/functions.cpp +++ b/muse2/muse/functions.cpp @@ -177,7 +177,7 @@ bool quantize_notes(const set<Part*>& parts) { if (!MusEGui::quantize_dialog->exec()) return false; -// (1<<MusEGui::quantize_dialog->raster_power2) + int raster = MusEGui::rasterVals[MusEGui::quantize_dialog->raster_index]; quantize_notes(parts, MusEGui::quantize_dialog->range, (MusEGlobal::config.division*4)/raster, MusEGui::quantize_dialog->quant_len, MusEGui::quantize_dialog->strength, MusEGui::quantize_dialog->swing, @@ -568,16 +568,16 @@ unsigned quantize_tick(unsigned tick, unsigned raster, int swing) int tick_dest2 = tick_dest1 + raster + raster*swing/100; int tick_dest3 = tick_dest1 + raster*2; - int tick_diff1 = tick_dest1 - tick; - int tick_diff2 = tick_dest2 - tick; - int tick_diff3 = tick_dest3 - tick; + int tick_diff1 = abs(tick_dest1 - (int)tick); + int tick_diff2 = abs(tick_dest2 - (int)tick); + int tick_diff3 = abs(tick_dest3 - (int)tick); - if ((abs(tick_diff1) <= abs(tick_diff2)) && (abs(tick_diff1) <= abs(tick_diff3))) //tick_dest1 is the nearest tick - return tick_dest1; - else if ((abs(tick_diff2) <= abs(tick_diff1)) && (abs(tick_diff2) <= abs(tick_diff3))) //tick_dest2 is the nearest tick + if ((tick_diff3 <= tick_diff1) && (tick_diff3 <= tick_diff2)) //tick_dest3 is the nearest tick + return tick_dest3; + else if ((tick_diff2 <= tick_diff1) && (tick_diff2 <= tick_diff3)) //tick_dest2 is the nearest tick return tick_dest2; else - return tick_dest3; + return tick_dest1; } bool quantize_notes(const set<Part*>& parts, int range, int raster, bool quant_len, int strength, int swing, int threshold) diff --git a/muse2/muse/gconfig.cpp b/muse2/muse/gconfig.cpp index f05abbf2..68ac6315 100644 --- a/muse2/muse/gconfig.cpp +++ b/muse2/muse/gconfig.cpp @@ -103,6 +103,7 @@ GlobalConfigValues config = { QColor(74, 150, 194), // midiTrackLabelBg; // Med blue QColor(74, 150, 194), // drumTrackLabelBg; // Med blue + QColor(74, 150, 194), // newDrumTrackLabelBg; // Med blue QColor(213, 128, 202), // waveTrackLabelBg; // magenta QColor(84, 185, 58), // outputTrackLabelBg; // green QColor(199, 75, 64), // inputTrackLabelBg; // red @@ -112,6 +113,7 @@ GlobalConfigValues config = { QColor(215, 220, 230), // midiTrackBg; QColor(215, 220, 230), // drumTrackBg; + QColor(215, 220, 230), // newDrumTrackBg; QColor(220, 209, 217), // waveTrackBg; QColor(197, 220, 206), // outputTrackBg; QColor(220, 214, 206), // inputTrackBg; @@ -138,6 +140,7 @@ GlobalConfigValues config = { false, // midi export file 2 byte timesigs instead of 4 true, // optimize midi export file note offs true, // Split imported tracks into multiple parts. + true, // importMidiNewStyleDrum 1, // startMode QString(""), // start song path 384, // gui division @@ -149,13 +152,13 @@ GlobalConfigValues config = { QString("Mixer A"), QRect(0, 0, 300, 500), // Mixer1 true, true, true, true, - true, true, true, true + true, true, true, true, true }, { QString("Mixer B"), QRect(200, 200, 300, 500), // Mixer2 true, true, true, true, - true, true, true, true + true, true, true, true, true }, true, // TransportVisible; false, // BigTimeVisible; @@ -187,9 +190,10 @@ GlobalConfigValues config = { false, // popupsDefaultStayOpen false, // leftMouseButtonCanDecrease false, // rangeMarkerWithoutMMB + MusECore::DONT_REC_MUTED_OR_HIDDEN, true, // addHiddenTracks - true // unhideTracks - + true, // unhideTracks + MusEGlobal::PREFER_NEW // drumTrackPreference }; //GlobalConfigValues globalConfig = config; diff --git a/muse2/muse/gconfig.h b/muse2/muse/gconfig.h index 95b88170..4ba9efea 100644 --- a/muse2/muse/gconfig.h +++ b/muse2/muse/gconfig.h @@ -34,10 +34,26 @@ namespace MusECore { class Xml; + +enum newDrumRecordCondition_t +{ + REC_ALL = 0, + DONT_REC_HIDDEN = 1, + DONT_REC_MUTED = 2, + DONT_REC_MUTED_OR_HIDDEN = 3 +}; + } namespace MusEGlobal { +enum drumTrackPreference_t +{ + PREFER_OLD = 0, + PREFER_NEW = 1, + ONLY_OLD = 2, + ONLY_NEW = 3 +}; //--------------------------------------------------------- // MixerConfig //--------------------------------------------------------- @@ -47,6 +63,7 @@ struct MixerConfig { QRect geometry; bool showMidiTracks; bool showDrumTracks; + bool showNewDrumTracks; bool showInputTracks; bool showOutputTracks; bool showWaveTracks; @@ -83,6 +100,7 @@ struct GlobalConfigValues { QColor midiTrackLabelBg; QColor drumTrackLabelBg; + QColor newDrumTrackLabelBg; QColor waveTrackLabelBg; QColor outputTrackLabelBg; QColor inputTrackLabelBg; @@ -92,6 +110,7 @@ struct GlobalConfigValues { QColor midiTrackBg; QColor drumTrackBg; + QColor newDrumTrackBg; QColor waveTrackBg; QColor outputTrackBg; QColor inputTrackBg; @@ -118,6 +137,7 @@ struct GlobalConfigValues { bool exp2ByteTimeSigs; // Export 2 byte time sigs instead of 4 bytes bool expOptimNoteOffs; // Save space by replacing note offs with note on velocity 0 bool importMidiSplitParts; // Split imported tracks into multiple parts. + bool importMidiNewStyleDrum; // Use new style drum tracks int startMode; // 0 - start with last song // 1 - start with default template @@ -164,9 +184,10 @@ struct GlobalConfigValues { bool popupsDefaultStayOpen; bool leftMouseButtonCanDecrease; bool rangeMarkerWithoutMMB; + MusECore::newDrumRecordCondition_t newDrumRecordCondition; bool addHiddenTracks; bool unhideTracks; - + drumTrackPreference_t drumTrackPreference; }; diff --git a/muse2/muse/helper.cpp b/muse2/muse/helper.cpp index b1f37e36..05cecc08 100644 --- a/muse2/muse/helper.cpp +++ b/muse2/muse/helper.cpp @@ -116,6 +116,55 @@ 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; +} + + +QSet<Part*> parts_at_tick(unsigned tick) +{ + using MusEGlobal::song; + + QSet<Track*> tmp; + for (iTrack it=song->tracks()->begin(); it!=song->tracks()->end(); it++) + tmp.insert(*it); + + return parts_at_tick(tick, tmp); +} + +QSet<Part*> parts_at_tick(unsigned tick, Track* track) +{ + QSet<Track*> tmp; + tmp.insert(track); + + return parts_at_tick(tick, tmp); +} + +QSet<Part*> parts_at_tick(unsigned tick, const QSet<Track*>& tracks) +{ + QSet<Part*> result; + + for (QSet<Track*>::const_iterator it=tracks.begin(); it!=tracks.end(); it++) + { + Track* track=*it; + + for (iPart p_it=track->parts()->begin(); p_it!=track->parts()->end(); p_it++) + if (tick >= p_it->second->tick() && tick <= p_it->second->endTick()) + result.insert(p_it->second); + } + + return result; +} + + } // namespace MusECore namespace MusEGui { @@ -189,7 +238,7 @@ QMenu* populateAddSynth(QWidget* parent) // this is also used in "mixer" //--------------------------------------------------------- -QActionGroup* populateAddTrack(QMenu* addTrack, bool populateAll) +QActionGroup* populateAddTrack(QMenu* addTrack, bool populateAll, bool evenIgnoreDrumPreference) { QActionGroup* grp = new QActionGroup(addTrack); if (MusEGlobal::config.addHiddenTracks) @@ -200,12 +249,38 @@ QActionGroup* populateAddTrack(QMenu* addTrack, bool populateAll) qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Midi Track"))); midi->setData(MusECore::Track::MIDI); grp->addAction(midi); - } - if (populateAll || MusECore::MidiTrack::visible()) { - QAction* drum = addTrack->addAction(QIcon(*addtrack_drumtrackIcon), - qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Drum Track"))); - drum->setData(MusECore::Track::DRUM); - grp->addAction(drum); + + + if (!evenIgnoreDrumPreference && (MusEGlobal::config.drumTrackPreference==MusEGlobal::PREFER_OLD || MusEGlobal::config.drumTrackPreference==MusEGlobal::ONLY_OLD)) + { + QAction* drum = addTrack->addAction(QIcon(*addtrack_drumtrackIcon), + qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Drum Track"))); + drum->setData(MusECore::Track::DRUM); + grp->addAction(drum); + } + + if (!evenIgnoreDrumPreference && (MusEGlobal::config.drumTrackPreference==MusEGlobal::PREFER_NEW || MusEGlobal::config.drumTrackPreference==MusEGlobal::ONLY_NEW)) + { + QAction* newdrum = addTrack->addAction(QIcon(*addtrack_drumtrackIcon), + qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Drum Track"))); + newdrum->setData(MusECore::Track::NEW_DRUM); + grp->addAction(newdrum); + } + + if (evenIgnoreDrumPreference || MusEGlobal::config.drumTrackPreference==MusEGlobal::PREFER_NEW) + { + QAction* drum = addTrack->addAction(QIcon(*addtrack_drumtrackIcon), + qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Old Style Drum Track"))); + drum->setData(MusECore::Track::DRUM); + grp->addAction(drum); + } + if (evenIgnoreDrumPreference || MusEGlobal::config.drumTrackPreference==MusEGlobal::PREFER_OLD) + { + QAction* newdrum = addTrack->addAction(QIcon(*addtrack_drumtrackIcon), + qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add New Style Drum Track"))); + newdrum->setData(MusECore::Track::NEW_DRUM); + grp->addAction(newdrum); + } } if (populateAll || MusECore::WaveTrack::visible()) { QAction* wave = addTrack->addAction(QIcon(*addtrack_wavetrackIcon), @@ -498,7 +573,13 @@ void populateMidiPorts() } -#else +#else // this code is disabled + +DISABLED AND MAYBE OUT-OF-DATE CODE! +the code below is disabled for a longer period of time, +there were certain changes and merges. dunno if that code +works at all. before activating it again, intensively +verify whether its still okay! // ------------------------------------------------------------------------------------------------------- // populateMidiPorts() diff --git a/muse2/muse/helper.h b/muse2/muse/helper.h index f9c9a78c..8ef39346 100644 --- a/muse2/muse/helper.h +++ b/muse2/muse/helper.h @@ -24,8 +24,11 @@ #define __HELPER_H__ #include <set> +#include <QSet> #include <QStringList> +#include "drummap.h" + class QActionGroup; class QString; class QMenu; @@ -34,14 +37,23 @@ class QWidget; namespace MusECore { class Part; +class Track; + + QString pitch2string(int v); Part* partFromSerialNumber(int serial); bool any_event_selected(const std::set<Part*>&, bool in_range=false); + +bool drummaps_almost_equal(DrumMap* one, DrumMap* two, int drummap_size=128); + +QSet<Part*> parts_at_tick(unsigned tick); +QSet<Part*> parts_at_tick(unsigned tick, const Track* track); +QSet<Part*> parts_at_tick(unsigned tick, const QSet<Track*>& tracks); } namespace MusEGui { QMenu* populateAddSynth(QWidget* parent); -QActionGroup* populateAddTrack(QMenu* addTrack, bool populateAll=false); +QActionGroup* populateAddTrack(QMenu* addTrack, bool populateAll=false, bool evenIgnoreDrumPreference=false); QStringList localizedStringListFromCharArray(const char** array, const char* context); QString getFilterExtension(const QString &filter); QString browseProjectFolder(QWidget* parent = 0); diff --git a/muse2/muse/icons.cpp b/muse2/muse/icons.cpp index 1cf28259..5e2cfce5 100644 --- a/muse2/muse/icons.cpp +++ b/muse2/muse/icons.cpp @@ -124,6 +124,10 @@ #include "xpm/routing_midi_input_button_slim.xpm" #include "xpm/routing_midi_output_button_slim.xpm" +#include "xpm/eye.xpm" +#include "xpm/eye_gray.xpm" +#include "xpm/eye_crossed.xpm" + #include "xpm/up.xpm" #include "xpm/down.xpm" #include "xpm/bold.xpm" @@ -344,6 +348,9 @@ QPixmap* homeIcon; QPixmap* backIcon; QPixmap* forwardIcon; QPixmap* muteIcon; +QPixmap* eyeIcon; +QPixmap* eyeCrossedIcon; +QPixmap* eyeGrayIcon; QPixmap* upIcon; QPixmap* downIcon; QPixmap* boldIcon; @@ -548,6 +555,9 @@ void initIcons() backIcon = new MPIXMAP(back_xpm, "go-previous"); forwardIcon = new MPIXMAP(forward_xpm, "go-next"); muteIcon = new MPIXMAP(editmuteS_xpm, "audio-volume-muted"); + eyeIcon = new MPIXMAP(eye_xpm, NULL); + eyeCrossedIcon = new MPIXMAP(eye_crossed_xpm, NULL); + eyeGrayIcon = new MPIXMAP(eye_gray_xpm, NULL); upIcon = new MPIXMAP(up_xpm, "go-up"); downIcon = new MPIXMAP(down_xpm, "go-down"); boldIcon = new MPIXMAP(bold_xpm, "format-text-bold"); diff --git a/muse2/muse/icons.h b/muse2/muse/icons.h index 8d55882b..115a79fc 100644 --- a/muse2/muse/icons.h +++ b/muse2/muse/icons.h @@ -87,6 +87,9 @@ extern QPixmap* homeIcon; extern QPixmap* backIcon; extern QPixmap* forwardIcon; extern QPixmap* muteIcon; +extern QPixmap* eyeIcon; +extern QPixmap* eyeCrossedIcon; +extern QPixmap* eyeGrayIcon; extern QPixmap* upIcon; extern QPixmap* downIcon; extern QPixmap* boldIcon; diff --git a/muse2/muse/importmidi.cpp b/muse2/muse/importmidi.cpp index 0bc477dc..bd3c8a9f 100644 --- a/muse2/muse/importmidi.cpp +++ b/muse2/muse/importmidi.cpp @@ -180,7 +180,12 @@ bool MusE::importMidi(const QString name, bool merge) MusECore::MidiTrack* track = new MusECore::MidiTrack(); if ((*t)->isDrumTrack) + { + if (MusEGlobal::config.importMidiNewStyleDrum) + track->setType(MusECore::Track::NEW_DRUM); + else track->setType(MusECore::Track::DRUM); + } track->setOutChannel(channel); track->setOutPort(port); @@ -199,15 +204,18 @@ bool MusE::importMidi(const QString name, bool merge) // Hmm. buildMidiEventList already takes care of this. // But it seems to work. How? Must test. if (channel == 9 && MusEGlobal::song->mtype() != MT_UNKNOWN) { + if (MusEGlobal::config.importMidiNewStyleDrum) + track->setType(MusECore::Track::NEW_DRUM); + else + { track->setType(MusECore::Track::DRUM); - // - // remap drum pitch with drumOutmap (was: Inmap. flo93 thought this was wrong) - // + + // remap drum pitch with drumOutmap MusECore::EventList* tevents = track->events(); for (MusECore::iEvent i = tevents->begin(); i != tevents->end(); ++i) { MusECore::Event ev = i->second; if (ev.isNote()) { - int pitch = MusEGlobal::drumOutmap[ev.pitch()]; // flo93 + int pitch = MusEGlobal::drumOutmap[ev.pitch()]; ev.setPitch(pitch); } else @@ -216,10 +224,11 @@ bool MusE::importMidi(const QString name, bool merge) int ctl = ev.dataA(); MusECore::MidiController *mc = mport->drumController(ctl); if(mc) - ev.setA((ctl & ~0xff) | MusEGlobal::drumOutmap[ctl & 0x7f]); // flo93 + ev.setA((ctl & ~0xff) | MusEGlobal::drumOutmap[ctl & 0x7f]); } - } } + } + } processTrack(track); diff --git a/muse2/muse/instruments/minstrument.cpp b/muse2/muse/instruments/minstrument.cpp index 22ed3737..a01903ae 100644 --- a/muse2/muse/instruments/minstrument.cpp +++ b/muse2/muse/instruments/minstrument.cpp @@ -996,71 +996,6 @@ void MidiInstrument::populatePatchPopup(MusEGui::PopupMenu* menu, int chan, MTyp } } -} // namespace MusECore - -/* -namespace MusEGui { - -void populatePatchPopup(MusECore::MidiInstrument* midiInstrument, PopupMenu* menu, int chan, MType songType, bool drum) - { - menu->clear(); - int mask = 0; - bool drumchan = chan == 9; - switch (songType) { - case MT_XG: mask = 4; break; - case MT_GS: mask = 2; break; - case MT_GM: - if(drumchan) - { - int id = (0xff << 16) + (0xff << 8) + 0x00; // First patch - QAction* act = menu->addAction(MusECore::gmdrumname); - //act->setCheckable(true); - act->setData(id); - return; - } - mask = 1; - break; - case MT_UNKNOWN: mask = 7; break; - } - if (midiInstrument->groups()->size() > 1) { - for (MusECore::ciPatchGroup i = midiInstrument->groups()->begin(); i != midiInstrument->groups()->end(); ++i) { - MusECore::PatchGroup* pgp = *i; - //QMenu* pm = menu->addMenu(pgp->name); - PopupMenu* pm = new PopupMenu(pgp->name, menu, menu->stayOpen()); // Use the parent stayOpen here. - menu->addMenu(pm); - pm->setFont(MusEGlobal::config.fonts[0]); - const MusECore::PatchList& pl = pgp->patches; - for (MusECore::ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) { - const MusECore::Patch* mp = *ipl; - if ((mp->typ & mask) && - ((drum && songType != MT_GM) || - (mp->drum == drumchan)) ) - { - int id = ((mp->hbank & 0xff) << 16) - + ((mp->lbank & 0xff) << 8) + (mp->prog & 0xff); - QAction* act = pm->addAction(mp->name); - //act->setCheckable(true); - act->setData(id); - } - - } - } - } - else if (midiInstrument->groups()->size() == 1 ){ - // no groups - const MusECore::PatchList& pl = midiInstrument->groups()->front()->patches; - for (MusECore::ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) { - const MusECore::Patch* mp = *ipl; - if (mp->typ & mask) { - int id = ((mp->hbank & 0xff) << 16) - + ((mp->lbank & 0xff) << 8) + (mp->prog & 0xff); - QAction* act = menu->addAction(mp->name); - //act->setCheckable(true); - act->setData(id); - } - } - } - } -*/ + } -} // namespace MusEGui +} // namespace MusECore diff --git a/muse2/muse/liste/editevent.cpp b/muse2/muse/liste/editevent.cpp index fa58bafd..c31ecb3a 100644 --- a/muse2/muse/liste/editevent.cpp +++ b/muse2/muse/liste/editevent.cpp @@ -614,12 +614,12 @@ EditCtrlDialog::EditCtrlDialog(int tick, const MusECore::Event& event, } ///pop = new QMenu(this); - //pop->setCheckable(false);//not necessary in Qt4 + //pop->setCheckable(false); //not necessary in Qt4 MusECore::MidiTrack* track = part->track(); int portn = track->outPort(); MusECore::MidiPort* port = &MusEGlobal::midiPorts[portn]; - bool isDrum = track->type() == MusECore::Track::DRUM; + bool isDrum = track->isDrumTrack(); MusECore::MidiCtrlValListList* cll = port->controller(); ctrlList->clear(); @@ -835,7 +835,7 @@ void EditCtrlDialog::updatePatch() int port = track->outPort(); int channel = track->outChannel(); MusECore::MidiInstrument* instr = MusEGlobal::midiPorts[port].instrument(); - patchName->setText(instr->getPatchName(channel, val, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM)); + patchName->setText(instr->getPatchName(channel, val, MusEGlobal::song->mtype(), track->isDrumTrack())); int hb = ((val >> 16) & 0xff) + 1; if (hb == 0x100) @@ -873,8 +873,8 @@ void EditCtrlDialog::instrPopup() //QMenu* pup = new QMenu(this); MusEGui::PopupMenu* pup = new MusEGui::PopupMenu(this); - //populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); - instr->populatePatchPopup(pup, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); + //populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); + instr->populatePatchPopup(pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); if(pup->actions().count() == 0) { diff --git a/muse2/muse/midi.cpp b/muse2/muse/midi.cpp index 754d19f3..85a47ead 100644 --- a/muse2/muse/midi.cpp +++ b/muse2/muse/midi.cpp @@ -261,9 +261,7 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track, e.setPitch(instr); } else - { e.setPitch(ev.dataA()); - } e.setVelo(ev.dataB()); e.setLenTick(0); @@ -276,6 +274,7 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track, } else e.setPitch(ev.dataA()); + e.setVelo(0); e.setVeloOff(ev.dataB()); e.setLenTick(0); @@ -372,7 +371,7 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track, int ctl = ev.dataA(); e.setA(ctl); - if(track->type() == Track::DRUM) + if(track->type() == Track::DRUM) { // Is it a drum controller event, according to the track port's instrument? MidiController *mc = MusEGlobal::midiPorts[track->outPort()].drumController(ctl); @@ -735,6 +734,12 @@ void Audio::collectEvents(MusECore::MidiTrack* track, unsigned int cts, unsigned if (ev.isNote() && MusEGlobal::drumMap[instr].mute) continue; } + else if (track->type() == Track::NEW_DRUM) { + int instr = ev.pitch(); + // ignore muted drums + if (ev.isNote() && track->drummap()[instr].mute) + continue; + } unsigned tick = ev.tick() + offset; unsigned frame = MusEGlobal::tempomap.tick2frame(tick) + frameOffset; switch (ev.type()) { @@ -744,19 +749,15 @@ void Audio::collectEvents(MusECore::MidiTrack* track, unsigned int cts, unsigned int pitch = ev.pitch(); int velo = ev.velo(); if (track->type() == Track::DRUM) { - // // Map drum-notes to the drum-map values - // int instr = ev.pitch(); pitch = MusEGlobal::drumMap[instr].anote; port = MusEGlobal::drumMap[instr].port; //This changes to non-default port channel = MusEGlobal::drumMap[instr].channel; velo = int(double(velo) * (double(MusEGlobal::drumMap[instr].vol) / 100.0)) ; } - else { - // + else if (track->type() != Track::NEW_DRUM) { // transpose non drum notes - // pitch += (track->transposition + MusEGlobal::song->globalPitchShift()); } @@ -806,7 +807,7 @@ void Audio::collectEvents(MusECore::MidiTrack* track, unsigned int cts, unsigned case Controller: { - if (track->type() == Track::DRUM) + if (track->type() == Track::DRUM) { int ctl = ev.dataA(); // Is it a drum controller event, according to the track port's instrument? @@ -978,7 +979,7 @@ void Audio::processMidi() // //Apply drum inkey: - if (track->type() == Track::DRUM) + if (track->type() == Track::DRUM) { int pitch = event.dataA(); //Map note that is played according to MusEGlobal::drumInmap @@ -989,7 +990,19 @@ void Audio::processMidi() event.setA(MusEGlobal::drumMap[(unsigned int)MusEGlobal::drumInmap[pitch]].anote); event.setChannel(channel); } - else + else if (track->type() == Track::NEW_DRUM) + { + event.setA(track->map_drum_in(event.dataA())); + + if (MusEGlobal::config.newDrumRecordCondition & MusECore::DONT_REC_HIDDEN && + track->drummap_hidden()[event.dataA()] ) + continue; // skip that event, proceed with the next + + if (MusEGlobal::config.newDrumRecordCondition & MusECore::DONT_REC_MUTED && + track->drummap()[event.dataA()].mute ) + continue; // skip that event, proceed with the next + } + else { //Track transpose if non-drum prePitch = event.dataA(); int pitch = prePitch + track->transposition; @@ -1012,10 +1025,9 @@ void Audio::processMidi() event.setB(velo); } } - else - if(event.type() == MusECore::ME_CONTROLLER) + else if(event.type() == MusECore::ME_CONTROLLER) { - if(track->type() == Track::DRUM) + if(track->type() == Track::DRUM) { ctl = event.dataA(); // Regardless of what port the event came from, is it a drum controller event @@ -1035,6 +1047,24 @@ void Audio::processMidi() event.setChannel(channel); } } + else if (track->type() == Track::NEW_DRUM) //FINDMICHJETZT TEST + { + ctl = event.dataA(); + if (tport->drumController(ctl)) // is it a drum controller? + { + int pitch = ctl & 0x7f; // pitch is now the incoming pitch + pitch = track->map_drum_in(pitch); // pitch is now the mapped (recorded) pitch + event.setA((ctl & ~0xff) | pitch); // map the drum ctrl's value accordingly + + if (MusEGlobal::config.newDrumRecordCondition & MusECore::DONT_REC_HIDDEN && + track->drummap_hidden()[pitch] ) + continue; // skip that event, proceed with the next + + if (MusEGlobal::config.newDrumRecordCondition & MusECore::DONT_REC_MUTED && + track->drummap()[pitch].mute ) + continue; // skip that event, proceed with the next + } + } } // MusE uses a fixed clocks per quarternote of 24. @@ -1078,7 +1108,7 @@ void Audio::processMidi() // to the track port so buildMidiEventList will accept it. Even though // the port may have no device "<none>". // - if (track->type() == Track::DRUM) + if (track->type() == Track::DRUM) //FINDMICHJETZT no changes. TEST { // Is it a drum controller event? if(mc) diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index 7b5949a4..4c033946 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -22,6 +22,7 @@ #include <QPainter> #include <QApplication> +#include <QMessageBox> #include <QClipboard> #include <QDrag> #include <QDragLeaveEvent> @@ -34,12 +35,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,20 +51,23 @@ #include "shortcuts.h" #include "icons.h" #include "functions.h" +#include "helper.h" #define CARET 10 #define CARET2 5 +using MusEGlobal::debugMsg; +using MusEGlobal::heavyDebugMsg; + namespace MusEGui { //--------------------------------------------------------- // DEvent //--------------------------------------------------------- -DEvent::DEvent(MusECore::Event e, MusECore::Part* p) +DEvent::DEvent(MusECore::Event e, MusECore::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)); @@ -81,7 +85,14 @@ CItem* DrumCanvas::addItem(MusECore::Part* part, MusECore::Event& event) return NULL; } - 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 NULL; + } + + DEvent* ev = new DEvent(event, part, instr); items.add(ev); int diff = event.endTick()-part->lenTick(); @@ -105,6 +116,37 @@ DrumCanvas::DrumCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy, const char* name) : EventCanvas(pr, parent, sx, sy, name) { + drumEditor=dynamic_cast<DrumEdit*>(pr); + + _setCurPartIfOnlyOneEventIsSelected=false; + + 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 = MusEGlobal::drumMap; + must_delete_our_drum_map=false; + + instrument_number_mapping_t temp; + for (MusECore::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; @@ -118,6 +160,11 @@ DrumCanvas::DrumCanvas(MidiEditor* pr, QWidget* parent, int sx, DrumCanvas::~DrumCanvas() { //items.clearDelete(); + + if (must_delete_our_drum_map && ourDrumMap!=NULL) + delete [] ourDrumMap; + + delete steprec; } //--------------------------------------------------------- @@ -197,7 +244,7 @@ MusECore::Undo DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, Dra for(iCItem ici = items.begin(); ici != items.end(); ++ici) { - CItem* ci = ici->second; + CItem* ci = ici->second; int x = ci->pos().x(); int y = ci->pos().y(); @@ -215,11 +262,15 @@ MusECore::Undo DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, Dra // Do not process if the event has already been processed (meaning it's an event in a clone part)... if (idl == doneList.end()) { - operations.push_back(moveItem(ci, newpos, dtype)); + if (moveItem(operations, ci, newpos, dtype) == false) //error? + { + QMessageBox::warning(this, tr("Moving items failed"), tr("The selection couldn't be moved, because at least one note would be moved into a track which is different from both the original track and the current part's track.\nChanging the current part with ALT+LEFT/RIGHT may help.")); + return MusECore::Undo(); //return empty list + } doneList.push_back(ci); } ci->move(newpos); - + if(moving.size() == 1) itemReleased(curItem, newpos); @@ -247,23 +298,44 @@ MusECore::Undo DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, Dra // moveItem //--------------------------------------------------------- -MusECore::UndoOp DrumCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) +bool DrumCanvas::moveItem(MusECore::Undo& operations, CItem* item, const QPoint& pos, DragType dtype) { DEvent* nevent = (DEvent*) item; - MusECore::MidiPart* part = (MusECore::MidiPart*)nevent->part(); + MusECore::MidiPart* part = (MusECore::MidiPart*)nevent->part(); + MusECore::MidiPart* dest_part = part; + int nheight = y2pitch(pos.y()); + if (nheight<0) nheight=0; + if (nheight>=getOurDrumMapSize()) nheight=getOurDrumMapSize()-1; + + if (!instrument_map[nheight].tracks.contains(dest_part->track())) + { + if (debugMsg) + printf("trying to move an event into a different track. checking if curPart is set correctly...\n"); + + if (!instrument_map[nheight].tracks.contains(curPart->track())) + { + printf ("ERROR: tried to move an event into a track which is different from both the initial part's and the curPart's track! ignoring this one...\n"); + return false; + } + else + dest_part=(MusECore::MidiPart*)curPart; + } + MusECore::Event event = nevent->event(); int x = pos.x(); if (x < 0) x = 0; - int ntick = editor->rasterVal(x) - part->tick(); + int ntick = editor->rasterVal(x) - dest_part->tick(); if (ntick < 0) ntick = 0; - int npitch = y2pitch(pos.y()); MusECore::Event newEvent = event.clone(); - newEvent.setPitch(npitch); + + 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 @@ -272,10 +344,19 @@ MusECore::UndoOp DrumCanvas::moveItem(CItem* item, const QPoint& pos, DragType d // printf("DrumCanvas::moveItem Error! New event end:%d exceeds length:%d of part:%s\n", newEvent.endTick(), part->lenTick(), part->name().toLatin1().constData()); if (dtype == MOVE_COPY || dtype == MOVE_CLONE) - return MusECore::UndoOp(MusECore::UndoOp::AddEvent, newEvent, part, false, false); + operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddEvent, newEvent, dest_part, false, false)); else - return MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false); + { + if (dest_part == part) + operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false)); + else + { + operations.push_back(MusECore::UndoOp(MusECore::UndoOp::DeleteEvent, event, part, false, false)); + operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddEvent, newEvent, dest_part, false, false)); + } } + return true; +} //--------------------------------------------------------- // newItem @@ -284,13 +365,16 @@ MusECore::UndoOp DrumCanvas::moveItem(CItem* item, const QPoint& pos, DragType d CItem* DrumCanvas::newItem(const QPoint& p, int state) { int instr = y2pitch(p.y()); //MusEGlobal::drumInmap[y2pitch(p.y())]; - int velo = MusEGlobal::drumMap[instr].lv4; + if ((instr<0) || (instr>=getOurDrumMapSize())) + return NULL; + + int velo = ourDrumMap[instr].lv4; if (state == Qt::ShiftModifier) - velo = MusEGlobal::drumMap[instr].lv3; + velo = ourDrumMap[instr].lv3; else if (state == Qt::ControlModifier) - velo = MusEGlobal::drumMap[instr].lv2; + velo = ourDrumMap[instr].lv2; else if (state == (Qt::ControlModifier | Qt::ShiftModifier)) - velo = MusEGlobal::drumMap[instr].lv1; + velo = ourDrumMap[instr].lv1; int tick = editor->rasterVal(p.x()); return newItem(tick, instr, velo); } @@ -301,13 +385,36 @@ CItem* DrumCanvas::newItem(const QPoint& p, int state) CItem* DrumCanvas::newItem(int tick, int instrument, int velocity) { + if ((instrument<0) || (instrument>=getOurDrumMapSize())) + return NULL; + + if (!old_style_drummap_mode && !instrument_map[instrument].tracks.contains(curPart->track())) + { + if (debugMsg) + printf("tried to create a new Item which cannot be inside the current track. looking for destination part...\n"); + + QSet<MusECore::Part*> parts = parts_at_tick(tick, instrument_map[instrument].tracks); + + if (parts.count() != 1) + { + QMessageBox::warning(this, tr("Creating event failed"), tr("Couldn't create the event, because the currently selected part isn't the same track, and the selected instrument could be either on no or on multiple parts, which is ambiguous.\nSelect the destination part, then try again.")); + return NULL; + } + else + { + setCurrentPart(*parts.begin()); + } + } + // else or if we found an alternative part (which has now been set as curPart) + tick -= curPart->tick(); MusECore::Event e(MusECore::Note); e.setTick(tick); - e.setPitch(instrument); + e.setPitch(instrument_map[instrument].pitch); e.setVelo(velocity); - e.setLenTick(MusEGlobal::drumMap[instrument].len); - return new DEvent(e, curPart); + e.setLenTick(ourDrumMap[instrument].len); + + return new DEvent(e, curPart, instrument); } //--------------------------------------------------------- @@ -330,7 +437,9 @@ void DrumCanvas::newItem(CItem* item, bool noSnap) { } void DrumCanvas::newItem(CItem* item, bool noSnap, bool replace) - { +{ + if (item) + { DEvent* nevent = (DEvent*) item; MusECore::Event event = nevent->event(); int x = item->x(); @@ -338,7 +447,7 @@ void DrumCanvas::newItem(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 @@ -374,7 +483,7 @@ void DrumCanvas::newItem(CItem* item, bool noSnap, bool replace) { operations.push_back(MusECore::UndoOp(MusECore::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"); @@ -384,7 +493,10 @@ void DrumCanvas::newItem(CItem* item, bool noSnap, bool replace) MusEGlobal::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 @@ -439,7 +551,7 @@ void DrumCanvas::drawItem(QPainter&p, const CItem*item, const QRect& rect) else { int velo = e->event().velo(); - MusECore::DrumMap* dm = &MusEGlobal::drumMap[y2pitch(y)]; //Get the drum item + MusECore::DrumMap* dm = &ourDrumMap[y2pitch(y)]; //Get the drum item QColor color; if (velo < dm->lv1) color.setRgb(240, 240, 255); @@ -530,8 +642,10 @@ 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; + else if (pitch<0) + pitch = 0; return pitch; } @@ -640,7 +754,8 @@ void DrumCanvas::cmd(int cmd) DEvent* devent = (DEvent*)(k->second); MusECore::Event event = devent->event(); MusECore::Event newEvent = event.clone(); - newEvent.setLenTick(MusEGlobal::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. MusEGlobal::audio->msgChangeEvent(event, newEvent, devent->part(), false, false, false); } @@ -744,19 +859,37 @@ void DrumCanvas::dragLeaveEvent(QDragLeaveEvent*) void DrumCanvas::keyPressed(int index, int velocity) { + using MusECore::MidiTrack; + + if ((index<0) || (index>=getOurDrumMapSize())) + return; + // called from DList - play event - int port = MusEGlobal::drumMap[index].port; - int channel = MusEGlobal::drumMap[index].channel; - int pitch = MusEGlobal::drumMap[index].anote; + int port = old_style_drummap_mode ? ourDrumMap[index].port : dynamic_cast<MidiTrack*>(*instrument_map[index].tracks.begin())->outPort(); + int channel = old_style_drummap_mode ? ourDrumMap[index].channel : dynamic_cast<MidiTrack*>(*instrument_map[index].tracks.begin())->outChannel(); + int pitch = old_style_drummap_mode ? ourDrumMap[index].anote : instrument_map[index].pitch; // play note: MusECore::MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity); MusEGlobal::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,MusEGlobal::drumMap[index].len,editor->raster(),velocity,MusEGlobal::globalKeyState&Qt::ControlModifier,MusEGlobal::globalKeyState&Qt::ShiftModifier); - - } + + + if (_steprec) /* && pos[0] >= start_tick && pos[0] < end_tick [removed by flo93: this is handled in steprec->record] */ + { + if ( curPart && instrument_map[index].tracks.contains(curPart->track()) ) + steprec->record(curPart,instrument_map[index].pitch,ourDrumMap[index].len,editor->raster(),velocity,MusEGlobal::globalKeyState&Qt::ControlModifier,MusEGlobal::globalKeyState&Qt::ShiftModifier, -1 /* invalid pitch as "really played" -> the "insert rest" feature is never triggered */); + else + { + QSet<MusECore::Part*> parts = parts_at_tick(pos[0], instrument_map[index].tracks); + + if (parts.count() != 1) + QMessageBox::warning(this, tr("Recording event failed"), tr("Couldn't record the event, because the currently selected part isn't the same track, and the instrument to be recorded could be either on no or on multiple parts, which is ambiguous.\nSelect the destination part, then try again.")); + else + steprec->record(*parts.begin(), instrument_map[index].pitch,ourDrumMap[index].len,editor->raster(),velocity,MusEGlobal::globalKeyState&Qt::ControlModifier,MusEGlobal::globalKeyState&Qt::ShiftModifier, -1 /* invalid pitch as "really played" -> the "insert rest" feature is never triggered */); + + } + } +} //--------------------------------------------------------- // keyReleased @@ -764,10 +897,15 @@ void DrumCanvas::keyPressed(int index, int velocity) void DrumCanvas::keyReleased(int index, bool) { + using MusECore::MidiTrack; + + if ((index<0) || (index>=getOurDrumMapSize())) + return; + // called from DList - silence playing event - int port = MusEGlobal::drumMap[index].port; - int channel = MusEGlobal::drumMap[index].channel; - int pitch = MusEGlobal::drumMap[index].anote; + int port = old_style_drummap_mode ? ourDrumMap[index].port : dynamic_cast<MidiTrack*>(*instrument_map[index].tracks.begin())->outPort(); + int channel = old_style_drummap_mode ? ourDrumMap[index].channel : dynamic_cast<MidiTrack*>(*instrument_map[index].tracks.begin())->outChannel(); + int pitch = old_style_drummap_mode ? ourDrumMap[index].anote : instrument_map[index].pitch; // release note: MusECore::MidiPlayEvent e(0, port, channel, 0x90, pitch, 0); @@ -779,7 +917,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) + { MusECore::Undo operations; std::vector< std::pair<MusECore::Part*, MusECore::Event*> > delete_events; std::vector< std::pair<MusECore::Part*, MusECore::Event> > add_events; @@ -857,7 +1000,83 @@ void DrumCanvas::mapChanged(int spitch, int dpitch) MusEGlobal::song->applyOperationGroup(operations, false); // do not indicate undo MusEGlobal::song->update(SC_DRUMMAP); //this update is neccessary, as it's not handled by applyOperationGroup() + } + else // if (!old_style_drummap_mode) + { + if (dpitch!=spitch) + { + using MusEGlobal::global_drum_ordering_t; + using MusEGlobal::global_drum_ordering; + + MusECore::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. or it's invalid + if (dpitch < getOurDrumMapSize()) + { + 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; + } + } + else + { + global_drum_ordering_t::iterator it=global_drum_ordering.end(); + while (!order_temp.empty()) + it=global_drum_ordering.insert(it, order_temp.takeLast()); + } + + + + + + 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; + } } + + + MusEGlobal::song->update(SC_DRUMMAP); // this causes a complete rebuild of ourDrumMap + // which also handles the changed order in all + // other drum editors + } +} //--------------------------------------------------------- // resizeEvent @@ -909,6 +1128,7 @@ void DrumCanvas::modifySelected(NoteInfo::ValType type, int delta) printf("DrumCanvas::modifySelected - NoteInfo::VAL_VELOFF not implemented\n"); break; case 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) @@ -917,6 +1137,8 @@ void DrumCanvas::modifySelected(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; } MusEGlobal::song->changeEvent(event, newEvent, part); @@ -933,6 +1155,7 @@ void DrumCanvas::modifySelected(NoteInfo::ValType type, int delta) void DrumCanvas::curPartChanged() { + EventCanvas::curPartChanged(); editor->setWindowTitle(getCaption()); } @@ -994,8 +1217,8 @@ void DrumCanvas::keyPress(QKeyEvent* event) return; } else if (key == shortcuts[SHRT_ADDNOTE_1].key) { - newItem(newItem(cursorPos.x(), cursorPos.y(), MusEGlobal::drumMap[cursorPos.y()].lv1),false,true); - keyPressed(cursorPos.y(), MusEGlobal::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()); @@ -1004,8 +1227,8 @@ void DrumCanvas::keyPress(QKeyEvent* event) return; } else if (key == shortcuts[SHRT_ADDNOTE_2].key) { - newItem(newItem(cursorPos.x(), cursorPos.y(), MusEGlobal::drumMap[cursorPos.y()].lv2),false,true); - keyPressed(cursorPos.y(), MusEGlobal::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()); @@ -1014,8 +1237,8 @@ void DrumCanvas::keyPress(QKeyEvent* event) return; } else if (key == shortcuts[SHRT_ADDNOTE_3].key) { - newItem(newItem(cursorPos.x(), cursorPos.y(), MusEGlobal::drumMap[cursorPos.y()].lv3),false,true); - keyPressed(cursorPos.y(), MusEGlobal::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()); @@ -1024,8 +1247,8 @@ void DrumCanvas::keyPress(QKeyEvent* event) return; } else if (key == shortcuts[SHRT_ADDNOTE_4].key) { - newItem(newItem(cursorPos.x(), cursorPos.y(), MusEGlobal::drumMap[cursorPos.y()].lv4),false,true); - keyPressed(cursorPos.y(), MusEGlobal::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()); @@ -1073,17 +1296,19 @@ MusECore::Event *DrumCanvas::getEventAtCursorPos() { if (_tool != CursorTool) return 0; - MusECore::EventList* el = curPart->events(); - MusECore::iEvent lower = el->lower_bound(cursorPos.x()-curPart->tick()); - MusECore::iEvent upper = el->upper_bound(cursorPos.x()-curPart->tick()); - for (MusECore::iEvent i = lower; i != upper; ++i) { - MusECore::Event &ev = i->second; - if(!ev.isNote()) - continue; - if (ev.pitch() == cursorPos.y()) { - return &ev; + if (instrument_map[cursorPos.y()].tracks.contains(curPart->track())) + { + MusECore::EventList* el = curPart->events(); + MusECore::iEvent lower = el->lower_bound(cursorPos.x()-curPart->tick()); + MusECore::iEvent upper = el->upper_bound(cursorPos.x()-curPart->tick()); + int curPitch = instrument_map[cursorPos.y()].pitch; + for (MusECore::iEvent i = lower; i != upper; ++i) { + MusECore::Event &ev = i->second; + if (ev.isNote() && ev.pitch() == curPitch) + return &ev; } } + // else or if the for loop didn't find anything return 0; } //--------------------------------------------------------- @@ -1107,9 +1332,13 @@ void DrumCanvas::selectCursorEvent(MusECore::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 (iCItem it=items.begin(); it!=items.end(); it++) { const MusECore::Event& ev=it->second->event(); @@ -1119,7 +1348,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++; @@ -1137,15 +1366,258 @@ void DrumCanvas::moveAwayUnused() // midiNote //--------------------------------------------------------- void DrumCanvas::midiNote(int pitch, int velo) - { - if (MusEGlobal::debugMsg) printf("DrumCanvas::midiNote: pitch=%i, velo=%i\n", pitch, velo); +{ + using MusECore::Track; + using MusECore::Part; + + if (debugMsg) printf("DrumCanvas::midiNote: pitch=%i, velo=%i\n", pitch, velo); - if (_midiin && _steprec && curPart - && !MusEGlobal::audio->isPlaying() && velo && pos[0] >= start_tick - /* && pos[0] < end_tick [removed by flo93: this is handled in steprec->record] */ - && !(MusEGlobal::globalKeyState & Qt::AltModifier)) { - steprec->record(curPart,MusEGlobal::drumInmap[pitch],MusEGlobal::drumMap[(int)MusEGlobal::drumInmap[pitch]].len,editor->raster(),velo,MusEGlobal::globalKeyState&Qt::ControlModifier,MusEGlobal::globalKeyState&Qt::ShiftModifier); + if (_midiin && _steprec && !MusEGlobal::audio->isPlaying() && velo && !(MusEGlobal::globalKeyState & Qt::AltModifier) /* && pos[0] >= start_tick && pos[0] < end_tick [removed by flo93: this is handled in steprec->record()] */ ) + { + if (pitch == MusEGlobal::rcSteprecNote) // skip the fancy code below, simply record a rest + { + if (curPart) + steprec->record(curPart,0xdead,0xbeef,editor->raster(),velo,MusEGlobal::globalKeyState&Qt::ControlModifier,MusEGlobal::globalKeyState&Qt::ShiftModifier, pitch); } + else + { + QSet<Track*> possible_dest_tracks; + Part* rec_part=NULL; + int rec_index=-1; + + int ourDrumMapSize=getOurDrumMapSize(); + int i; + for (i=0;i<ourDrumMapSize;i++) + { + if ( instrument_map[i].tracks.contains(curPart->track()) && ourDrumMap[i].enote==pitch) + { + rec_part=curPart; + rec_index=i; + break; + } + else if (ourDrumMap[i].enote==pitch) + possible_dest_tracks.unite(instrument_map[i].tracks); + } + + if (rec_part == NULL) // if recording to curPart isn't possible + { + QSet<Part*> possible_dest_parts = parts_at_tick(pos[0], possible_dest_tracks); + + if (possible_dest_parts.count() != 1) + QMessageBox::warning(this, tr("Recording event failed"), tr("Couldn't record the event, because the currently selected part isn't the same track, and the instrument to be recorded could be either on no or on multiple parts, which is ambiguous.\nSelect the destination part, then try again.")); + else + { + rec_part = *possible_dest_parts.begin(); + Track* dest_track=rec_part->track(); + + for (i=0;i<ourDrumMapSize;i++) + if ( instrument_map[i].tracks.contains(dest_track) && ourDrumMap[i].enote==pitch) + { + rec_index=i; + break; + } + + if (rec_index==-1) + { + printf("ERROR: THIS SHOULD NEVER HAPPEN: i found a destination part for step recording, but now i can't find the instrument any more in DrumCanvas::midiNote()?!\n"); + QMessageBox::critical(this, tr("Internal error"), tr("Wtf, some nasty internal error which is actually impossible occurred. Check console output. Nothing recorded.")); + rec_part=NULL; + } + } + } + + if (rec_part != NULL) + steprec->record(rec_part,instrument_map[rec_index].pitch,ourDrumMap[rec_index].len,editor->raster(),velo,MusEGlobal::globalKeyState&Qt::ControlModifier,MusEGlobal::globalKeyState&Qt::ShiftModifier, pitch); + } + } +} + + +int DrumCanvas::pitch_and_track_to_instrument(int pitch, MusECore::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; + + if (heavyDebugMsg) printf("DrumCanvas::pitch_and_track_to_instrument() called with invalid arguments.\n"); + return -1; +} + +void DrumCanvas::propagate_drummap_change(int instr, bool update_druminmap) +{ + const QSet<MusECore::Track*>& tracks=instrument_map[instr].tracks; + int index=instrument_map[instr].pitch; + + for (QSet<MusECore::Track*>::const_iterator it = tracks.begin(); it != tracks.end(); it++) + { + dynamic_cast<MusECore::MidiTrack*>(*it)->drummap()[index] = ourDrumMap[instr]; + if (update_druminmap) + dynamic_cast<MusECore::MidiTrack*>(*it)->update_drum_in_map(); + } +} + + +void DrumCanvas::rebuildOurDrumMap() +{ + using MusECore::drummaps_almost_equal; + using MusECore::Track; + using MusECore::MidiTrack; + using MusECore::TrackList; + using MusECore::ciTrack; + using MusECore::ciPart; + using MusECore::DrumMap; + using MusEGlobal::global_drum_ordering_t; + using MusEGlobal::global_drum_ordering; + + + if (!old_style_drummap_mode) + { + bool need_update = false; + + TrackList* tl=MusEGlobal::song->tracks(); + QList< QSet<Track*> > track_groups; + QVector<instrument_number_mapping_t> old_instrument_map = instrument_map; + + 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; + + if (drumEditor->ignore_hide()) hidden=false; + + 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++) + { + DrumMap* dm = &dynamic_cast<MidiTrack*>(*track)->drummap()[pitch]; + if (dm->mute != mute) + { + dm->mute=mute; + need_update = true; + } + } + + 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 (instrument_map!=old_instrument_map) + { + if (debugMsg) printf("rebuilt drummap and instrument map, size is now %i\n",size); + + songChanged(SC_EVENT_INSERTED); // force an update of the itemlist + emit ourDrumMapChanged(true); + } + else + emit ourDrumMapChanged(false); + + if (need_update) + MusEGlobal::song->update(SC_DRUMMAP, true); // i know, this causes a recursion, which possibly + // isn't the most elegant solution here. but it will + // never be an infinite recursion + } +} } // namespace MusEGui diff --git a/muse2/muse/midiedit/dcanvas.h b/muse2/muse/midiedit/dcanvas.h index 5417a187..0fd4c9e0 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,11 +39,11 @@ class QDropEvent; class QDragMoveEvent; class QDragLeaveEvent; +class DrumMap; namespace MusEGui { class MidiEditor; -class PianoRoll; -class ScrollScale; +class DrumEdit; //--------------------------------------------------------- // DEvent @@ -49,9 +52,38 @@ class ScrollScale; class DEvent : public CItem { public: - DEvent(MusECore::Event e, MusECore::Part* p); + DEvent(MusECore::Event e, MusECore::Part* p, int instr); }; + +struct instrument_number_mapping_t //FINDMICH TODO move into a suitable namespace! +{ + QSet<MusECore::Track*> tracks; + int pitch; + + instrument_number_mapping_t() + { + pitch=-1; + tracks.clear(); + } + + instrument_number_mapping_t(const QSet<MusECore::Track*>& tr, int p) + { + tracks=tr; + pitch=p; + } + + bool operator==(const instrument_number_mapping_t& that) //TODO maybe compare the Track* serial numbers, not the pointers themselves? + { + return (this->tracks == that.tracks && this->pitch==that.pitch); + } + + bool operator!=(const instrument_number_mapping_t& that) + { + return !operator==(that); + } +}; + //--------------------------------------------------------- // DrumCanvas //--------------------------------------------------------- @@ -59,6 +91,13 @@ class DEvent : public CItem { class DrumCanvas : public EventCanvas { Q_OBJECT + bool old_style_drummap_mode; + MusECore::DrumMap* ourDrumMap; + bool must_delete_our_drum_map; //FINDMICH really delete it! + QVector<instrument_number_mapping_t> instrument_map; + + DrumEdit* drumEditor; + MusECore::StepRec* steprec; // Cursor tool position @@ -71,7 +110,7 @@ class DrumCanvas : public EventCanvas { void drawTopItem(QPainter& p, const QRect& rect); virtual void drawMoving(QPainter&, const CItem*, const QRect&); virtual MusECore::Undo moveCanvasItems(CItemList&, int, int, DragType); - virtual MusECore::UndoOp moveItem(CItem*, const QPoint&, DragType); + virtual bool moveItem(MusECore::Undo&, CItem*, const QPoint&, DragType); virtual CItem* newItem(const QPoint&, int); virtual void resizeItem(CItem*, bool, bool); virtual void newItem(CItem*, bool); @@ -89,9 +128,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(bool /*instrumentMap changed as well?*/); private slots: void midiNote(int pitch, int velo); @@ -111,7 +151,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); @@ -121,7 +162,12 @@ class DrumCanvas : public EventCanvas { virtual void keyPress(QKeyEvent* event); MusECore::Event *getEventAtCursorPos(); void selectCursorEvent(MusECore::Event *ev); - + int pitch_and_track_to_instrument(int pitch, MusECore::Track* track); + MusECore::DrumMap* getOurDrumMap() { return ourDrumMap; } //FINDMICH UGLY + int getOurDrumMapSize() { return instrument_map.size(); } //FINDMICH UGLY + QVector<instrument_number_mapping_t>& get_instrument_map() { return instrument_map; } //FINDMICH UGLY + void propagate_drummap_change(int instrument, bool update_druminmap); //FINDMICH move to drumedit + void rebuildOurDrumMap(); }; } // namespace MusEGui diff --git a/muse2/muse/midiedit/dlist.cpp b/muse2/muse/midiedit/dlist.cpp index 80009cc7..2eb5e64a 100644 --- a/muse2/muse/midiedit/dlist.cpp +++ b/muse2/muse/midiedit/dlist.cpp @@ -35,11 +35,12 @@ #include "pitchedit.h" #include "midiport.h" #include "drummap.h" +#include "drumedit.h" #include "helper.h" #include "icons.h" #include "dlist.h" #include "song.h" -#include "scrollscale.h" +#include "dcanvas.h" namespace MusEGui { @@ -60,13 +61,13 @@ void DList::draw(QPainter& p, const QRect& rect) p.setPen(Qt::black); - for (int i = 0; i < DRUM_MAPSIZE; ++i) { - int yy = i * TH; + for (int instrument = 0; instrument < ourDrumMapSize; ++instrument) { + int yy = instrument * TH; if (yy+TH < y) continue; if (yy > y + h) break; - MusECore::DrumMap* dm = &MusEGlobal::drumMap[i]; + MusECore::DrumMap* dm = &ourDrumMap[instrument]; if (dm == currentlySelected) p.fillRect(x, yy, w, TH, Qt::yellow); // else @@ -75,6 +76,10 @@ void DList::draw(QPainter& p, const QRect& rect) p.save(); p.setWorldMatrixEnabled(false); for (int k = 0; k < h->count(); ++k) { + if (h->isSectionHidden(k)) + continue; + + int x = h->sectionPosition(k); int w = h->sectionSize(k); //QRect r = p.combinedTransform().mapRect(QRect(x+2, yy, w-4, TH)); // Gives inconsistent positions. Source shows wrong operation for our needs. @@ -85,33 +90,72 @@ void DList::draw(QPainter& p, const QRect& rect) //p.save(); //p.setWorldMatrixEnabled(false); switch (k) { - case COL_VOL: + case COL_VOLUME: s.setNum(dm->vol); break; - case COL_QNT: + case COL_QUANT: s.setNum(dm->quant); break; - case COL_LEN: + case COL_NOTELENGTH: s.setNum(dm->len); break; - case COL_ANOTE: + case COL_NOTE: s = MusECore::pitch2string(dm->anote); break; - case COL_ENOTE: + case COL_INPUTTRIGGER: s = MusECore::pitch2string(dm->enote); break; - case COL_LV1: + case COL_LEVEL1: s.setNum(dm->lv1); break; - case COL_LV2: + case COL_LEVEL2: s.setNum(dm->lv2); break; - case COL_LV3: + case COL_LEVEL3: s.setNum(dm->lv3); break; - case COL_LV4: + case COL_LEVEL4: s.setNum(dm->lv4); break; + case COL_HIDE: + { + bool hidden=false; + bool shown=false; + QSet<MusECore::Track*>* group = &dcanvas->get_instrument_map()[instrument].tracks; + int pitch = dcanvas->get_instrument_map()[instrument].pitch; + + for (QSet<MusECore::Track*>::iterator track=group->begin(); track!=group->end() && !(hidden&&shown); track++) + if (dynamic_cast<MusECore::MidiTrack*>(*track)->drummap_hidden()[pitch]) + hidden=true; + else + shown=true; + + if (!hidden && !shown) + printf("THIS SHOULD NEVER HAPPEN: in DList::draw(): instrument %i's track group is empty. strange...\n", instrument); + + const QPixmap* pm = NULL; + + if (shown && !hidden) + pm = eyeIcon; + else if (!shown && hidden) + pm = eyeCrossedIcon; + else if (shown && hidden) + pm = eyeGrayIcon; + else //if (!shown && !hidden) + pm = NULL; + + if (pm) + { + // p.setPen(Qt::red); + p.drawPixmap( + r.x() + r.width()/2 - pm->width()/2, + r.y() + r.height()/2 - pm->height()/2, + *pm); + // p.setPen(Qt::black); + } + + break; + } case COL_MUTE: if (dm->mute) { p.setPen(Qt::red); @@ -127,10 +171,10 @@ void DList::draw(QPainter& p, const QRect& rect) s = dm->name; align = Qt::AlignVCenter | Qt::AlignLeft; break; - case COL_CHANNEL: + case COL_OUTCHANNEL: s.setNum(dm->channel+1); break; - case COL_PORT: + case COL_OUTPORT: s.sprintf("%d:%s", dm->port+1, MusEGlobal::midiPorts[dm->port].portname().toLatin1().constData()); align = Qt::AlignVCenter | Qt::AlignLeft; break; @@ -182,6 +226,12 @@ void DList::draw(QPainter& p, const QRect& rect) void DList::devicesPopupMenu(MusECore::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 = MusECore::midiPortsPopup(this, t->port); QAction* act = p->exec(mapToGlobal(QPoint(x, y)), 0); bool doemit = false; @@ -219,8 +269,8 @@ void DList::devicesPopupMenu(MusECore::DrumMap* t, int x, int y, bool changeAll) // Delete all port controller events. MusEGlobal::song->changeAllPortDrumCtrlEvents(false); - for (int i = 0; i < DRUM_MAPSIZE; i++) - MusEGlobal::drumMap[i].port = n; + for (int i = 0; i < ourDrumMapSize; i++) + ourDrumMap[i].port = n; // Add all port controller events. MusEGlobal::song->changeAllPortDrumCtrlEvents(true); @@ -246,16 +296,21 @@ void DList::viewMousePressEvent(QMouseEvent* ev) int x = ev->x(); int y = ev->y(); int button = ev->button(); - unsigned pitch = y / TH; - MusECore::DrumMap* dm = &MusEGlobal::drumMap[pitch]; + int instrument = y / TH; + if (instrument >= ourDrumMapSize) instrument=ourDrumMapSize-1; + if (instrument < 0) instrument=0; + if (ourDrumMapSize==0) return; - setCurDrumInstrument(pitch); + setCurDrumInstrument(instrument); + + MusECore::DrumMap* dm = &ourDrumMap[instrument]; + MusECore::DrumMap dm_old = *dm; startY = y; - sPitch = pitch; + sInstrument = instrument; drag = START_DRAG; - DCols col = DCols(x2col(x)); + DrumColumn col = DrumColumn(x2col(x)); int val; int incVal = 0; @@ -269,7 +324,7 @@ void DList::viewMousePressEvent(QMouseEvent* ev) // In that case, treat it as if a return was pressed if (button == Qt::LeftButton) { - if (((editEntry && editEntry != dm) || col != selectedColumn) && editEntry != 0) { + if (editEntry && (editEntry != dm || col != selectedColumn)) { returnPressed(); } } @@ -277,54 +332,94 @@ void DList::viewMousePressEvent(QMouseEvent* ev) switch (col) { case COL_NONE: break; + case COL_HIDE: + if (button == Qt::LeftButton) + { + bool hidden=true; + QSet<MusECore::Track*>* group = &dcanvas->get_instrument_map()[instrument].tracks; + int pitch = dcanvas->get_instrument_map()[instrument].pitch; + + for (QSet<MusECore::Track*>::iterator track=group->begin(); track!=group->end(); track++) + if (dynamic_cast<MusECore::MidiTrack*>(*track)->drummap_hidden()[pitch] == false) + { + hidden=false; + break; + } + + for (QSet<MusECore::Track*>::iterator track=group->begin(); track!=group->end(); track++) + dynamic_cast<MusECore::MidiTrack*>(*track)->drummap_hidden()[pitch] = !hidden; + } + break; case COL_MUTE: if (button == Qt::LeftButton) dm->mute = !dm->mute; break; - case COL_PORT: + case COL_OUTPORT: // 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: + case COL_VOLUME: val = dm->vol + incVal; if (val < 0) val = 0; - else if (val > 999) + else if (val > 999) //changed from 200 to 999 by flo93 val = 999; dm->vol = (unsigned char)val; break; - case COL_QNT: + case COL_QUANT: dm->quant += incVal; // ?? range break; - case COL_ENOTE: + case COL_INPUTTRIGGER: val = dm->enote + incVal; if (val < 0) val = 0; else if (val > 127) val = 127; - //Check if there is any other MusEGlobal::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 (MusEGlobal::drumMap[i].enote == val && &MusEGlobal::drumMap[i] != dm) { - MusEGlobal::drumInmap[int(dm->enote)] = i; - MusEGlobal::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) { + MusEGlobal::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 + MusEGlobal::drumInmap[val] = instrument; + } + else + { + //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 (QSet<MusECore::Track*>::iterator it = dcanvas->get_instrument_map()[instrument].tracks.begin(); it!=dcanvas->get_instrument_map()[instrument].tracks.end(); it++) + { + MusECore::MidiTrack* mt = dynamic_cast<MusECore::MidiTrack*>(*it); + mt->drummap()[mt->map_drum_in(val)].enote=dm->enote; + } + // propagating this is unneccessary as it's already done. + // updating the drumInmap is unneccessary, as the propagate call below + // does this for us. + // updating ourDrumMap is unneccessary because the song->update(SC_DRUMMAP) + // does this for us. + } + dm->enote = val; - MusEGlobal::drumInmap[val] = pitch; break; - case COL_LEN: + + case COL_NOTELENGTH: val = dm->len + incVal; if (val < 0) val = 0; dm->len = val; break; - case COL_ANOTE: + case COL_NOTE: + if (old_style_drummap_mode) //only allow changing in old style mode { val = dm->anote + incVal; if (val < 0) @@ -334,16 +429,16 @@ void DList::viewMousePressEvent(QMouseEvent* ev) if(val != dm->anote) { MusEGlobal::audio->msgIdle(true); - MusEGlobal::song->remapPortDrumCtrlEvents(pitch, val, -1, -1); + MusEGlobal::song->remapPortDrumCtrlEvents(instrument, val, -1, -1); MusEGlobal::audio->msgIdle(false); dm->anote = val; MusEGlobal::song->update(SC_DRUMMAP); } - - emit keyPressed(pitch, 100); } + + emit keyPressed(instrument, 100); break; - case COL_CHANNEL: + case COL_OUTCHANNEL: // this column isn't visible in new style drum mode val = dm->channel + incVal; if (val < 0) val = 0; @@ -355,8 +450,8 @@ void DList::viewMousePressEvent(QMouseEvent* ev) // Delete all port controller events. MusEGlobal::song->changeAllPortDrumCtrlEvents(false, true); - for (int i = 0; i < DRUM_MAPSIZE; i++) - MusEGlobal::drumMap[i].channel = val; + for (int i = 0; i < ourDrumMapSize; i++) + ourDrumMap[i].channel = val; // Add all port controller events. MusEGlobal::song->changeAllPortDrumCtrlEvents(true, true); MusEGlobal::audio->msgIdle(false); @@ -367,14 +462,14 @@ void DList::viewMousePressEvent(QMouseEvent* ev) if(val != dm->channel) { MusEGlobal::audio->msgIdle(true); - MusEGlobal::song->remapPortDrumCtrlEvents(pitch, -1, val, -1); + MusEGlobal::song->remapPortDrumCtrlEvents(instrument, -1, val, -1); MusEGlobal::audio->msgIdle(false); dm->channel = val; MusEGlobal::song->update(SC_DRUMMAP); } } break; - case COL_LV1: + case COL_LEVEL1: val = dm->lv1 + incVal; if (val < 0) val = 0; @@ -382,7 +477,7 @@ void DList::viewMousePressEvent(QMouseEvent* ev) val = 127; dm->lv1 = val; break; - case COL_LV2: + case COL_LEVEL2: val = dm->lv2 + incVal; if (val < 0) val = 0; @@ -390,7 +485,7 @@ void DList::viewMousePressEvent(QMouseEvent* ev) val = 127; dm->lv2 = val; break; - case COL_LV3: + case COL_LEVEL3: val = dm->lv3 + incVal; if (val < 0) val = 0; @@ -398,7 +493,7 @@ void DList::viewMousePressEvent(QMouseEvent* ev) val = 127; dm->lv3 = val; break; - case COL_LV4: + case COL_LEVEL4: val = dm->lv4 + incVal; if (val < 0) val = 0; @@ -407,17 +502,63 @@ void DList::viewMousePressEvent(QMouseEvent* ev) dm->lv4 = val; break; case COL_NAME: - { - int velo = 127 * (ev->x() - header->sectionPosition(COL_NAME)) / (header->sectionSize(COL_NAME) - 10); - if (velo < 0) velo = 0; - if (velo > 127 ) velo = 127; - emit keyPressed(pitch, velo); //Mapping done on other side, send index + if (button == Qt::LeftButton) + { + int velo = 127 * (ev->x() - header->sectionPosition(COL_NAME)) / (header->sectionSize(COL_NAME) - 10); + if (velo < 0) velo = 0; + if (velo > 127 ) velo = 127; + emit keyPressed(instrument, velo); //Mapping done on other side, send index + } + else if (button == Qt::MidButton) // hide that instrument + { + QSet<MusECore::Track*>* group = &dcanvas->get_instrument_map()[instrument].tracks; + int pitch = dcanvas->get_instrument_map()[instrument].pitch; + for (QSet<MusECore::Track*>::iterator track=group->begin(); track!=group->end(); track++) + dynamic_cast<MusECore::MidiTrack*>(*track)->drummap_hidden()[pitch] = true; + } + else if (button == Qt::RightButton) + { + bool hidden=false; + bool shown=false; + QSet<MusECore::Track*>* group = &dcanvas->get_instrument_map()[instrument].tracks; + int pitch = dcanvas->get_instrument_map()[instrument].pitch; + + for (QSet<MusECore::Track*>::iterator track=group->begin(); track!=group->end() && !(hidden&&shown); track++) + if (dynamic_cast<MusECore::MidiTrack*>(*track)->drummap_hidden()[pitch]) + hidden=true; + else + shown=true; + + QMenu* popup = new QMenu(NULL /* intendedly not "this" */); + QAction* hideAction = popup->addAction(tr("hide this instrument")); + QAction* showAction = popup->addAction(tr("show this instrument")); + showAction->setToolTip(tr("this turns a grayed out eye into a blue eye")); + + if (!hidden) + showAction->setEnabled(false); + if (!shown) + hideAction->setEnabled(false); + + QAction* result = popup->exec(ev->globalPos()); + if (result==hideAction) + for (QSet<MusECore::Track*>::iterator track=group->begin(); track!=group->end(); track++) + dynamic_cast<MusECore::MidiTrack*>(*track)->drummap_hidden()[pitch] = true; + else if (result==showAction) + for (QSet<MusECore::Track*>::iterator track=group->begin(); track!=group->end(); track++) + dynamic_cast<MusECore::MidiTrack*>(*track)->drummap_hidden()[pitch] = false; + + delete popup; + } 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(instrument, (dm_old.enote != dm->enote)); + + MusEGlobal::song->update(SC_DRUMMAP); + //redraw(); //this is done by the songChanged slot } //--------------------------------------------------------- @@ -428,18 +569,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)) + if ((section == COL_NAME || section == COL_VOLUME || section == COL_NOTELENGTH || section == COL_LEVEL1 || + section == COL_LEVEL2 || section == COL_LEVEL3 || section == COL_LEVEL4 || section == COL_QUANT || + (section == COL_OUTCHANNEL && 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_NOTE && old_style_drummap_mode) || section == COL_INPUTTRIGGER) && (ev->button() == Qt::LeftButton)) + pitchEdit(instrument, section); else viewMousePressEvent(ev); } @@ -451,7 +592,11 @@ void DList::viewMouseDoubleClickEvent(QMouseEvent* ev) //--------------------------------------------------------- void DList::lineEdit(int line, int section) { - MusECore::DrumMap* dm = &MusEGlobal::drumMap[line]; + if (line >= ourDrumMapSize) line=ourDrumMapSize-1; + if (line < 0) line=0; + if (ourDrumMapSize==0) return; + + MusECore::DrumMap* dm = &ourDrumMap[line]; editEntry = dm; if (editor == 0) { editor = new DLineEdit(this); @@ -469,37 +614,37 @@ void DList::lineEdit(int line, int section) editor->setText(dm->name); break; - case COL_VOL: { + case COL_VOLUME: { editor->setText(QString::number(dm->vol)); break; } - case COL_LEN: { + case COL_NOTELENGTH: { editor->setText(QString::number(dm->len)); break; } - case COL_LV1: + case COL_LEVEL1: editor->setText(QString::number(dm->lv1)); break; - case COL_LV2: + case COL_LEVEL2: editor->setText(QString::number(dm->lv2)); break; - case COL_LV3: + case COL_LEVEL3: editor->setText(QString::number(dm->lv3)); break; - case COL_LV4: + case COL_LEVEL4: editor->setText(QString::number(dm->lv4)); break; - case COL_QNT: + case COL_QUANT: editor->setText(QString::number(dm->quant)); break; - case COL_CHANNEL: + case COL_OUTCHANNEL: editor->setText(QString::number(dm->channel+1)); break; } @@ -519,7 +664,11 @@ void DList::lineEdit(int line, int section) //--------------------------------------------------------- void DList::pitchEdit(int line, int section) { - MusECore::DrumMap* dm = &MusEGlobal::drumMap[line]; + if (line >= ourDrumMapSize) line=ourDrumMapSize-1; + if (line < 0) line=0; + if (ourDrumMapSize==0) return; + + MusECore::DrumMap* dm = &ourDrumMap[line]; editEntry = dm; if (pitch_editor == 0) { pitch_editor = new DPitchEdit(this); @@ -533,11 +682,11 @@ void DList::pitchEdit(int line, int section) int colh = rmapy(TH); selectedColumn = section; //Store selected column to have an idea of which one was selected when return is pressed switch (section) { - case COL_ENOTE: + case COL_INPUTTRIGGER: pitch_editor->setValue(dm->enote); break; - case COL_ANOTE: + case COL_NOTE: pitch_editor->setValue(dm->anote); break; } @@ -573,13 +722,14 @@ int DList::x2col(int x) const void DList::setCurDrumInstrument(int instr) { - if (instr < 0 || instr >= DRUM_MAPSIZE -1) + if (instr < 0 || instr >= ourDrumMapSize) return; // illegal instrument - MusECore::DrumMap* dm = &MusEGlobal::drumMap[instr]; + MusECore::DrumMap* dm = &ourDrumMap[instr]; if (currentlySelected != dm) { - currentlySelected = &MusEGlobal::drumMap[instr]; + currentlySelected = dm; emit curDrumInstrumentChanged(instr); - MusEGlobal::song->update(SC_DRUMMAP); + //MusEGlobal::song->update(SC_DRUMMAP); //FINDMICHJETZT what for?? wtf? + redraw(); // FINDMICHJETZT using redraw() instead of the above. } } @@ -598,32 +748,37 @@ 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 > 999) //Check bounds for volume + case COL_VOLUME: + if (val > 999) //changed from 200 to 999 by flo93 val = 999; if (val < 0) val = 0; break; - case COL_LV1: - case COL_LV2: - case COL_LV3: - case COL_LV4: + case COL_LEVEL1: + case COL_LEVEL2: + case COL_LEVEL3: + case COL_LEVEL4: if (val > 127) //Check bounds for lv1-lv4 values val = 127; if (val < 0) val = 0; break; - case COL_CHANNEL: + case COL_OUTCHANNEL: val--; if (val >= 16) val = 15; @@ -634,42 +789,42 @@ void DList::returnPressed() default: break; } } - + + MusECore::DrumMap editEntryOld = *editEntry; switch(selectedColumn) { case COL_NAME: editEntry->name = editor->text(); break; - case COL_LEN: - ///editEntry->len = atoi(editor->text().ascii()); + case COL_NOTELENGTH: editEntry->len = atoi(editor->text().toAscii().constData()); break; - case COL_VOL: + case COL_VOLUME: editEntry->vol = val; break; - case COL_LV1: + case COL_LEVEL1: editEntry->lv1 = val; break; - case COL_LV2: + case COL_LEVEL2: editEntry->lv2 = val; break; - case COL_LV3: + case COL_LEVEL3: editEntry->lv3 = val; break; - case COL_LV4: + case COL_LEVEL4: editEntry->lv4 = val; break; - case COL_QNT: + case COL_QUANT: editEntry->quant = val; break; - case COL_CHANNEL: + case COL_OUTCHANNEL: editEntry->channel = val; break; @@ -677,11 +832,16 @@ void DList::returnPressed() printf("Return pressed in unknown column\n"); break; } + + if (editEntryOld != *editEntry) + dcanvas->propagate_drummap_change(editEntry-ourDrumMap, false); + selectedColumn = -1; editor->hide(); editEntry = 0; setFocus(); - redraw(); + MusEGlobal::song->update(SC_DRUMMAP); + //redraw(); //this is done by the songChanged slot } //--------------------------------------------------------- @@ -690,44 +850,80 @@ 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-MusEGlobal::drumMap); + int instrument=(editEntry-ourDrumMap); + MusECore::DrumMap editEntryOld=*editEntry; switch(selectedColumn) { - case COL_ANOTE: + case COL_NOTE: + if (old_style_drummap_mode) //should actually be always true, but to be sure... + { if(val != editEntry->anote) { MusEGlobal::audio->msgIdle(true); - MusEGlobal::song->remapPortDrumCtrlEvents(pitch, val, -1, -1); + MusEGlobal::song->remapPortDrumCtrlEvents(instrument, val, -1, -1); MusEGlobal::audio->msgIdle(false); editEntry->anote = val; MusEGlobal::song->update(SC_DRUMMAP); } - break; - - case COL_ENOTE: + } + else + printf("ERROR: THIS SHOULD NEVER HAPPEN: pitch edited of anote in new style mode!\n"); + break; + + case COL_INPUTTRIGGER: + if (old_style_drummap_mode) + { //Check if there is any other MusEGlobal::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 (MusEGlobal::drumMap[i].enote == val && &MusEGlobal::drumMap[i] != editEntry) { + for (int i=0; i<ourDrumMapSize; i++) { + if (ourDrumMap[i].enote == val && &ourDrumMap[i] != editEntry) { MusEGlobal::drumInmap[int(editEntry->enote)] = i; - MusEGlobal::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; - MusEGlobal::drumInmap[val] = pitch; - break; + //TODO: Set all the notes on the track with instrument=dm->enote to instrument=val + MusEGlobal::drumInmap[val] = instrument; + } + else + { + //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 (QSet<MusECore::Track*>::iterator it = dcanvas->get_instrument_map()[instrument].tracks.begin(); it!=dcanvas->get_instrument_map()[instrument].tracks.end(); it++) + { + MusECore::MidiTrack* mt = dynamic_cast<MusECore::MidiTrack*>(*it); + mt->drummap()[mt->map_drum_in(val)].enote=editEntry->enote; + } + // propagating this is unneccessary as it's already done. + // updating the drumInmap is unneccessary, as the propagate call below + // does this for us. + // updating ourDrumMap is unneccessary because the song->update(SC_DRUMMAP) + // does this for us. + } + 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, (editEntryOld.enote!=editEntry->enote)); + selectedColumn = -1; pitch_editor->hide(); editEntry = 0; setFocus(); - redraw(); + MusEGlobal::song->update(SC_DRUMMAP); + //redraw(); //this is done by the songChanged slot } //--------------------------------------------------------- @@ -762,14 +958,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) : MusEGui::View(parent, 1, ymag) { setBg(Qt::white); + + dcanvas=dcanvas_; + ourDrumMap=dcanvas->getOurDrumMap(); + ourDrumMapSize=dcanvas->getOurDrumMapSize(); + old_style_drummap_mode=oldstyle; + connect(dcanvas, SIGNAL(ourDrumMapChanged(bool)), SLOT(ourDrumMapChanged(bool))); + 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))); @@ -779,8 +981,16 @@ DList::DList(QHeaderView* h, QWidget* parent, int ymag) editor = 0; pitch_editor = 0; editEntry = 0; - // always select a drum instrument - currentlySelected = &MusEGlobal::drumMap[0]; + if (ourDrumMapSize!=0) + { + // always select a drum instrument + currentlySelected = &ourDrumMap[0]; + } + else + { + currentlySelected = NULL; + } + selectedColumn = -1; } @@ -801,7 +1011,7 @@ void DList::viewMouseMoveEvent(QMouseEvent* ev) curY = ev->y(); int delta = curY - startY; switch (drag) { - case START_DRAG: + case START_DRAG: // this cannot happen if ourDrumMapSize==0 if (delta < 0) delta = -delta; if (delta <= 2) @@ -826,14 +1036,28 @@ void DList::viewMouseReleaseEvent(QMouseEvent* ev) { if (drag == DRAG) { int y = ev->y(); - int dPitch = y / TH; - if (dPitch < 0) dPitch=0; - if (dPitch >= DRUM_MAPSIZE) dPitch=DRUM_MAPSIZE-1; + int dInstrument; + if (old_style_drummap_mode) + dInstrument = y / TH; + else + dInstrument = (y+TH/2) / TH; + + if (dInstrument < 0) dInstrument=0; + if (old_style_drummap_mode) + { + if (dInstrument >= ourDrumMapSize) dInstrument=ourDrumMapSize-1; + } + else + { + if (dInstrument > ourDrumMapSize) dInstrument=ourDrumMapSize; // allow moving something below the last element + } + + int cur_sel = (!old_style_drummap_mode && dInstrument>sInstrument) ? dInstrument-1 : dInstrument; setCursor(QCursor(Qt::ArrowCursor)); - currentlySelected = &MusEGlobal::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 @@ -842,16 +1066,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)); + DrumColumn col = DrumColumn(x2col(x)); switch (col) { case COL_NAME: - emit keyReleased(pitch, shift); + emit keyReleased(instrument, shift); break; - case COL_ANOTE: - emit keyReleased(pitch, shift); + case COL_NOTE: + emit keyReleased(instrument, shift); break; default: break; @@ -864,9 +1088,51 @@ void DList::viewMouseReleaseEvent(QMouseEvent* ev) int DList::getSelectedInstrument() { - if (currentlySelected == 0) + if (currentlySelected == NULL) return -1; return MusEGlobal::drumInmap[int(currentlySelected->enote)]; } + +void DList::ourDrumMapChanged(bool instrMapChanged) +{ + int selIdx = currentlySelected ? (currentlySelected - ourDrumMap) : -1; + int editIdx = editEntry ? (editEntry - ourDrumMap) : -1; + + ourDrumMap=dcanvas->getOurDrumMap(); + ourDrumMapSize=dcanvas->getOurDrumMapSize(); + + if (instrMapChanged) + { + if (editEntry!=NULL) + { + printf("THIS SHOULD NEVER HAPPEN: DList::ourDrumMapChanged(true) caused editEntry to be\n" + " invalidated. The current active editor will have no\n" + " effect, expect potential breakage...\n"); + editEntry=NULL; + } + } + else // that is: if (!instrMapChanged) + { + // if the instrumentMap has not changed, then its size and so + // ourDrumMapSize cannot have changed as well. + if (editIdx >= ourDrumMapSize) + { + printf("THIS SHOULD NEVER HAPPEN: editIdx got out of bounds although ourDrumMapSize\n" + " cannot have changed (actually)\n"); + editIdx=-1; + } + editEntry=(editIdx>=0) ? &ourDrumMap[editIdx] : NULL; + } + + if (selIdx >= ourDrumMapSize) selIdx=ourDrumMapSize-1; + if (selIdx < 0) selIdx=0; + currentlySelected = (ourDrumMapSize!=0) ? &ourDrumMap[selIdx] : NULL; + + if (ourDrumMapSize==0) + drag = NORMAL; + + redraw(); +} + } // namespace MusEGui diff --git a/muse2/muse/midiedit/dlist.h b/muse2/muse/midiedit/dlist.h index 99e9460f..35a67023 100644 --- a/muse2/muse/midiedit/dlist.h +++ b/muse2/muse/midiedit/dlist.h @@ -35,6 +35,8 @@ class QHeaderView; class QLineEdit; class QMouseEvent; class QPainter; +class Device; +class QLineEdit; namespace MusECore { class DrumMap; @@ -43,6 +45,7 @@ class DrumMap; namespace MusEGui { class ScrollScale; +class DrumCanvas; //--------------------------------------------------------- // DLineEdit @@ -89,9 +92,13 @@ class DPitchEdit: public Awl::PitchEdit class DList : public View { Q_OBJECT - + + MusEGui::DrumCanvas* dcanvas; + MusECore::DrumMap* ourDrumMap; + int ourDrumMapSize; + bool old_style_drummap_mode; + QHeaderView* header; - ScrollScale* scroll; QLineEdit* editor; DPitchEdit* pitch_editor; MusECore::DrumMap* editEntry; @@ -101,7 +108,7 @@ class DList : public View { int startY; int curY; - int sPitch; + int sInstrument; enum { NORMAL, START_DRAG, DRAG } drag; virtual void draw(QPainter& p, const QRect&); @@ -131,18 +138,16 @@ class DList : public View { public slots: void tracklistChanged(); void songChanged(int); + void ourDrumMapChanged(bool); + 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, MusEGui::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, - COL_ANOTE, COL_CHANNEL, COL_PORT, - COL_LV1, COL_LV2, COL_LV3, COL_LV4, COL_NONE=-1}; }; } // namespace MusEGui diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp index 52e63da0..3bb48705 100644 --- a/muse2/muse/midiedit/drumedit.cpp +++ b/muse2/muse/midiedit/drumedit.cpp @@ -83,27 +83,12 @@ static const char* map_file_save_pattern[] = { int DrumEdit::_rasterInit = 96; int DrumEdit::_dlistWidthInit = 50; int DrumEdit::_dcanvasWidthInit = 300; +bool DrumEdit::_ignore_hide_init = false; static const int xscale = -10; static const int yscale = 1; static const int drumeditTools = MusEGui::PointerTool | MusEGui::PencilTool | MusEGui::RubberTool | MusEGui::CursorTool | MusEGui::DrawTool; -enum DrumColumn { - COL_MUTE = 0, - COL_NAME, - COL_VOLUME, - COL_QUANT, - COL_INPUTTRIGGER, - COL_NOTELENGTH, - COL_NOTE, - COL_OUTCHANNEL, - COL_OUTPORT, - COL_LEVEL1, - COL_LEVEL2, - COL_LEVEL3, - COL_LEVEL4, - COL_NONE = -1 -}; //--------------------------------------------------------- // setHeaderWhatsThis @@ -111,6 +96,7 @@ enum DrumColumn { void DrumEdit::setHeaderWhatsThis() { + header->setWhatsThis(COL_HIDE, tr("hide instrument")); header->setWhatsThis(COL_MUTE, tr("mute instrument")); header->setWhatsThis(COL_NAME, tr("sound name")); header->setWhatsThis(COL_VOLUME, tr("volume percent")); @@ -132,6 +118,7 @@ void DrumEdit::setHeaderWhatsThis() void DrumEdit::setHeaderToolTips() { + header->setToolTip(COL_HIDE, tr("hide instrument")); header->setToolTip(COL_MUTE, tr("mute instrument")); header->setToolTip(COL_NAME, tr("sound name")); header->setToolTip(COL_VOLUME, tr("volume percent")); @@ -182,21 +169,10 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un selPart = 0; QSignalMapper *signalMapper = new QSignalMapper(this); + _group_mode = GROUP_SAME_CHANNEL; + _ignore_hide = _ignore_hide_init; + //---------Pulldown Menu---------------------------- - menuFile = menuBar()->addMenu(tr("&File")); - - loadAction = menuFile->addAction(QIcon(*openIcon), tr("Load Map")); - saveAction = menuFile->addAction(QIcon(*saveIcon), tr("Save Map")); - resetAction = menuFile->addAction(tr("Reset GM Map")); - - connect(loadAction, SIGNAL(triggered()), signalMapper, SLOT(map())); - connect(saveAction, SIGNAL(triggered()), signalMapper, SLOT(map())); - connect(resetAction, SIGNAL(triggered()), signalMapper, SLOT(map())); - - signalMapper->setMapping(loadAction, DrumCanvas::CMD_LOAD); - signalMapper->setMapping(saveAction, DrumCanvas::CMD_SAVE); - signalMapper->setMapping(resetAction, DrumCanvas::CMD_RESET); - menuEdit = menuBar()->addMenu(tr("&Edit")); menuEdit->addActions(MusEGlobal::undoRedo->actions()); @@ -257,9 +233,71 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un menuFunctions = menuBar()->addMenu(tr("Fu&nctions")); menuFunctions->setTearOffEnabled(true); + - QAction* reorderListAction = menuFunctions->addAction(tr("Re-order list")); - menuFunctions->addSeparator(); + + // throw out new-style and midi tracks if there are old-style tracks present + bool has_old_style_tracks=false; + for (MusECore::ciPart p = parts()->begin(); p != parts()->end(); ++p) + if (p->second->track()->type()==MusECore::Track::DRUM) + { + has_old_style_tracks=true; + break; + } + + if (has_old_style_tracks) + { + bool thrown_out=false; + bool again; + do + { + again=false; + for (MusECore::ciPart p = parts()->begin(); p != parts()->end();p++) + if (p->second->track()->type()!=MusECore::Track::DRUM) + { + parts()->remove(p->second); + thrown_out=true; + again=true; + break; + } + } while (again); + + if (thrown_out) + { + QTimer* timer = new QTimer(this); + timer->setSingleShot(true); + connect(timer,SIGNAL(timeout()), this, SLOT(display_old_new_conflict_message())); + timer->start(10); + } + } + + _old_style_drummap_mode=has_old_style_tracks; + + + + + if (old_style_drummap_mode()) + { + loadAction = menuFunctions->addAction(QIcon(*openIcon), tr("Load Map")); + saveAction = menuFunctions->addAction(QIcon(*saveIcon), tr("Save Map")); + resetAction = menuFunctions->addAction(tr("Reset GM Map")); + + connect(loadAction, SIGNAL(triggered()), signalMapper, SLOT(map())); + connect(saveAction, SIGNAL(triggered()), signalMapper, SLOT(map())); + connect(resetAction, SIGNAL(triggered()), signalMapper, SLOT(map())); + + signalMapper->setMapping(loadAction, DrumCanvas::CMD_LOAD); + signalMapper->setMapping(saveAction, DrumCanvas::CMD_SAVE); + signalMapper->setMapping(resetAction, DrumCanvas::CMD_RESET); + + QAction* reorderListAction = menuFunctions->addAction(tr("Re-order map")); + connect(reorderListAction, SIGNAL(triggered()), signalMapper, SLOT(map())); + signalMapper->setMapping(reorderListAction, DrumCanvas::CMD_REORDER_LIST); + menuFunctions->addSeparator(); + } + else + loadAction=saveAction=resetAction=NULL; + fixedAction = menuFunctions->addAction(tr("Set Fixed Length")); veloAction = menuFunctions->addAction(tr("Modify Velocity")); crescAction = menuFunctions->addAction(tr("Crescendo/Decrescendo")); @@ -268,7 +306,6 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un 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())); @@ -277,7 +314,6 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un 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); @@ -286,10 +322,54 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un signalMapper->setMapping(noteShiftAction, DrumCanvas::CMD_NOTE_SHIFT); signalMapper->setMapping(delOverlapsAction, DrumCanvas::CMD_DELETE_OVERLAPS); + + QMenu* menuScriptPlugins = menuBar()->addMenu(tr("&Plugins")); MusEGlobal::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")); + QMenu* menuShowHide=settingsMenu->addMenu(tr("Show/Hide")); + QAction* ignoreHideAction = menuShowHide->addAction(tr("Also show hidden instruments")); + menuShowHide->addSeparator(); + QAction* showAllAction = menuShowHide->addAction(tr("Show all instruments")); + QAction* hideAllAction = menuShowHide->addAction(tr("Hide all instruments")); + QAction* hideUnusedAction = menuShowHide->addAction(tr("Only show used instruments")); + QAction* hideEmptyAction = menuShowHide->addAction(tr("Only show instruments with non-empty name or used instruments")); + settingsMenu->addSeparator(); + + groupNoneAction->setCheckable(true); + groupChanAction->setCheckable(true); + groupMaxAction ->setCheckable(true); + ignoreHideAction->setCheckable(true); + ignoreHideAction->setChecked(_ignore_hide); + + connect(groupNoneAction, SIGNAL(triggered()), signalMapper, SLOT(map())); + connect(groupChanAction, SIGNAL(triggered()), signalMapper, SLOT(map())); + connect(groupMaxAction, SIGNAL(triggered()), signalMapper, SLOT(map())); + connect(ignoreHideAction, SIGNAL(toggled(bool)), SLOT(set_ignore_hide(bool))); + connect(showAllAction, SIGNAL(triggered()), this, SLOT(showAllInstruments())); + connect(hideAllAction, SIGNAL(triggered()), this, SLOT(hideAllInstruments())); + connect(hideUnusedAction, SIGNAL(triggered()), this, SLOT(hideUnusedInstruments())); + connect(hideEmptyAction, SIGNAL(triggered()), this, SLOT(hideEmptyInstruments())); + + 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); @@ -299,25 +379,31 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un //--------------------------------------------------- // Toolbars //--------------------------------------------------- + + if (old_style_drummap_mode()) + { + QToolBar* maptools = addToolBar(tr("Drum map tools")); + maptools->setObjectName("Drum map tools"); + + QToolButton *ldm = new QToolButton(); + ldm->setToolTip(tr("Load Drummap")); + ldm->setIcon(*openIcon); + connect(ldm, SIGNAL(clicked()), SLOT(load())); + maptools->addWidget(ldm); + + QToolButton *sdm = new QToolButton(); + sdm->setToolTip(tr("Store Drummap")); + sdm->setIcon(*saveIcon); + connect(sdm, SIGNAL(clicked()), SLOT(save())); + maptools->addWidget(sdm); + + maptools->addAction(QWhatsThis::createAction()); + } + tools = addToolBar(tr("Drum tools")); tools->setObjectName("Drum tools"); - - QToolButton *ldm = new QToolButton(); - ldm->setToolTip(tr("Load Drummap")); - ldm->setIcon(*openIcon); - connect(ldm, SIGNAL(clicked()), SLOT(load())); - tools->addWidget(ldm); - - QToolButton *sdm = new QToolButton(); - sdm->setToolTip(tr("Store Drummap")); - sdm->setIcon(*saveIcon); - connect(sdm, SIGNAL(clicked()), SLOT(save())); - tools->addWidget(sdm); - - tools->addAction(QWhatsThis::createAction()); - tools->addSeparator(); tools->addActions(MusEGlobal::undoRedo->actions()); tools->addSeparator(); @@ -411,7 +497,7 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un gridS2->setSpacing(0); time = new MusEGui::MTScale(&_raster, split1w2, xscale); canvas = new DrumCanvas(this, split1w2, xscale, yscale); - vscroll = new MusEGui::ScrollScale(-4, 1, yscale, DRUM_MAPSIZE*TH, Qt::Vertical, split1w2); + vscroll = new MusEGui::ScrollScale(-4, 1, yscale, dynamic_cast<DrumCanvas*>(canvas)->getOurDrumMapSize()*TH, Qt::Vertical, split1w2); int offset = -(MusEGlobal::config.division/4); canvas->setOrigin(offset, 0); canvas->setCanvasTools(drumeditTools); @@ -419,6 +505,7 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un 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(bool)), SLOT(ourDrumMapChanged(bool))); time->setOrigin(offset, 0); QList<int> mops; @@ -442,6 +529,7 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un // header = new MusEGui::Header(split1w1, "header"); header->setFixedHeight(31); + header->setColumnLabel(tr("H"), COL_HIDE, 20); header->setColumnLabel(tr("M"), COL_MUTE, 20); header->setColumnLabel(tr("Sound"), COL_NAME, 120); header->setColumnLabel(tr("Vol"), COL_VOLUME); @@ -459,7 +547,18 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un setHeaderToolTips(); setHeaderWhatsThis(); - dlist = new DList(header, split1w1, yscale); + if (!old_style_drummap_mode()) + { + header->hideSection(COL_OUTPORT); + header->hideSection(COL_OUTCHANNEL); + } + + if (!old_style_drummap_mode() && _ignore_hide) + header->showSection(COL_HIDE); + else + header->hideSection(COL_HIDE); + + dlist = new DList(header, split1w1, yscale, (DrumCanvas*)canvas, old_style_drummap_mode()); // p3.3.44 setCurDrumInstrument(dlist->getSelectedInstrument()); @@ -553,8 +652,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); - } //--------------------------------------------------------- @@ -711,6 +814,7 @@ void DrumEdit::writeStatus(int level, MusECore::Xml& xml) const xml.intTag(level, "xmag", hscroll->mag()); xml.intTag(level, "ypos", vscroll->pos()); xml.intTag(level, "ymag", vscroll->mag()); + xml.intTag(level, "ignore_hide", _ignore_hide); xml.tag(level, "/drumedit"); } @@ -758,6 +862,8 @@ void DrumEdit::readStatus(MusECore::Xml& xml) vscroll->setMag(xml.parseInt()); else if (tag == "ypos") vscroll->setPos(xml.parseInt()); + else if (tag == "ignore_hide") + _ignore_hide=xml.parseInt(); else xml.unknown("DrumEdit"); break; @@ -794,6 +900,8 @@ void DrumEdit::readConfiguration(MusECore::Xml& xml) _dcanvasWidthInit = xml.parseInt(); else if (tag == "dlistwidth") _dlistWidthInit = xml.parseInt(); + else if (tag == "ignore_hide_init") + _ignore_hide_init = xml.parseInt(); else if (tag == "topwin") TopWin::readConfiguration(DRUM, xml); else @@ -819,6 +927,7 @@ void DrumEdit::writeConfiguration(int level, MusECore::Xml& xml) xml.intTag(level, "raster", _rasterInit); xml.intTag(level, "dlistwidth", _dlistWidthInit); xml.intTag(level, "dcanvaswidth", _dcanvasWidthInit); + xml.intTag(level, "ignore_hide_init", _ignore_hide_init); TopWin::writeConfiguration(DRUM, level,xml); xml.tag(level, "/drumedit"); } @@ -963,7 +1072,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); } } @@ -1005,6 +1118,7 @@ CtrlEdit* DrumEdit::addCtrl() connect(tools2, SIGNAL(toolChanged(int)), ctrlEdit, SLOT(setTool(int))); connect(dlist, SIGNAL(curDrumInstrumentChanged(int)), SLOT(setCurDrumInstrument(int))); connect(dlist, SIGNAL(curDrumInstrumentChanged(int)), canvas, SLOT(setCurDrumInstrument(int))); + connect(canvas, SIGNAL(curPartHasChanged(MusECore::Part*)), ctrlEdit, SLOT(curPartHasChanged(MusECore::Part*))); //printf("DrumEdit::addCtrl curDrumInstrument:%d\n", dlist->getSelectedInstrument()); @@ -1138,7 +1252,7 @@ void DrumEdit::keyPressEvent(QKeyEvent* event) return; } else if (key == Qt::Key_F2) { - dlist->lineEdit(dlist->getSelectedInstrument(),(int)DList::COL_NAME); + dlist->lineEdit(dlist->getSelectedInstrument(),(int)COL_NAME); return; } else if (key == shortcuts[SHRT_INSTRUMENT_STEP_UP].key) { @@ -1286,8 +1400,8 @@ void DrumEdit::keyPressEvent(QKeyEvent* event) void DrumEdit::initShortcuts() { - loadAction->setShortcut(shortcuts[SHRT_OPEN].key); - saveAction->setShortcut(shortcuts[SHRT_SAVE].key); + if (loadAction) loadAction->setShortcut(shortcuts[SHRT_OPEN].key); + if (saveAction) saveAction->setShortcut(shortcuts[SHRT_SAVE].key); cutAction->setShortcut(shortcuts[SHRT_CUT].key); copyAction->setShortcut(shortcuts[SHRT_COPY].key); @@ -1335,4 +1449,152 @@ void DrumEdit::setStep(QString v) canvas->setFocus(); } +void DrumEdit::ourDrumMapChanged(bool instrMapChanged) +{ + if (instrMapChanged) + { + 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); +} + +void DrumEdit::set_ignore_hide(bool val) +{ + _ignore_hide=val; + _ignore_hide_init=val; + // this may only called be from the action's toggled signal. + // if called otherwise, the action's checked state isn't updated! + + if (!old_style_drummap_mode() && _ignore_hide) + header->showSection(COL_HIDE); + else + header->hideSection(COL_HIDE); + + ((DrumCanvas*)(canvas))->rebuildOurDrumMap(); +} + +void DrumEdit::showAllInstruments() +{ + using MusECore::MidiTrack; + + QSet<MidiTrack*> tracks; + for (MusECore::ciPart p = parts()->begin(); p != parts()->end(); ++p) + tracks.insert((MidiTrack*)p->second->track()); + + for (QSet<MidiTrack*>::iterator it=tracks.begin(); it!=tracks.end(); it++) + { + MidiTrack* track=*it; + + for (int i=0;i<128;i++) + track->drummap_hidden()[i]=false; + } + + MusEGlobal::song->update(SC_DRUMMAP); +} + +void DrumEdit::hideAllInstruments() +{ + using MusECore::MidiTrack; + + QSet<MidiTrack*> tracks; + for (MusECore::ciPart p = parts()->begin(); p != parts()->end(); ++p) + tracks.insert((MidiTrack*)p->second->track()); + + for (QSet<MidiTrack*>::iterator it=tracks.begin(); it!=tracks.end(); it++) + { + MidiTrack* track=*it; + + for (int i=0;i<128;i++) + track->drummap_hidden()[i]=true; + } + + MusEGlobal::song->update(SC_DRUMMAP); +} + +void DrumEdit::hideUnusedInstruments() +{ + using MusECore::MidiTrack; + using MusECore::ciEvent; + using MusECore::EventList; + using MusECore::ciPart; + + QSet<MidiTrack*> tracks; + for (MusECore::ciPart p = parts()->begin(); p != parts()->end(); ++p) + tracks.insert((MidiTrack*)p->second->track()); + + for (QSet<MidiTrack*>::iterator it=tracks.begin(); it!=tracks.end(); it++) + { + MidiTrack* track=*it; + + bool hide[128]; + for (int i=0;i<128;i++) hide[i]=true; + + for (MusECore::ciPart p = parts()->begin(); p != parts()->end(); ++p) + if (p->second->track() == track) + { + const EventList* el = p->second->cevents(); + for (ciEvent ev=el->begin(); ev!=el->end(); ev++) + hide[ev->second.pitch()]=false; + } + + for (int i=0;i<128;i++) + track->drummap_hidden()[i]=hide[i]; + } + + MusEGlobal::song->update(SC_DRUMMAP); +} + +void DrumEdit::hideEmptyInstruments() +{ + using MusECore::MidiTrack; + using MusECore::ciEvent; + using MusECore::EventList; + using MusECore::ciPart; + + QSet<MidiTrack*> tracks; + for (MusECore::ciPart p = parts()->begin(); p != parts()->end(); ++p) + tracks.insert((MidiTrack*)p->second->track()); + + for (QSet<MidiTrack*>::iterator it=tracks.begin(); it!=tracks.end(); it++) + { + MidiTrack* track=*it; + + bool hide[128]; + for (int i=0;i<128;i++) hide[i]=track->drummap()[i].name.isEmpty(); + + for (MusECore::ciPart p = parts()->begin(); p != parts()->end(); ++p) + if (p->second->track() == track) + { + const EventList* el = p->second->cevents(); + for (ciEvent ev=el->begin(); ev!=el->end(); ev++) + hide[ev->second.pitch()]=false; + } + + for (int i=0;i<128;i++) + track->drummap_hidden()[i]=hide[i]; + } + + MusEGlobal::song->update(SC_DRUMMAP); +} + + +void DrumEdit::display_old_new_conflict_message() +{ + QMessageBox::information(this, tr("Not all parts are displayed"), tr("You selected both old-style-drumtracks and others (that is: new-style or midi tracks), but they cannot displayed in the same drum edit.\nI'll only display the old-style drumtracks in this editor, dropping the others.")); +} + } // namespace MusEGui diff --git a/muse2/muse/midiedit/drumedit.h b/muse2/muse/midiedit/drumedit.h index 7ad5aabd..5bdd54a8 100644 --- a/muse2/muse/midiedit/drumedit.h +++ b/muse2/muse/midiedit/drumedit.h @@ -33,6 +33,7 @@ #include "header.h" #include "shortcuts.h" #include "event.h" +#include "dcanvas.h" //FINDMICH UGLY. remove! class QCloseEvent; class QLabel; @@ -64,6 +65,23 @@ class ScrollScale; class Splitter; class Toolbar1; +enum DrumColumn { + COL_HIDE = 0, + COL_MUTE, + COL_NAME, + COL_VOLUME, + COL_QUANT, + COL_INPUTTRIGGER, + COL_NOTELENGTH, + COL_NOTE, + COL_OUTCHANNEL, + COL_OUTPORT, + COL_LEVEL1, + COL_LEVEL2, + COL_LEVEL3, + COL_LEVEL4, + COL_NONE = -1 +}; //--------------------------------------------------------- // DrumEdit @@ -71,11 +89,19 @@ 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; + bool _ignore_hide; + bool _old_style_drummap_mode; + MusECore::Event selEvent; MusECore::MidiPart* selPart; int selTick; - QMenu* menuEdit, *menuFunctions, *menuFile, *menuSelect; + QMenu* menuEdit, *menuFunctions, *menuSelect; MusEGui::NoteInfo* info; QToolButton* srec; @@ -93,13 +119,14 @@ class DrumEdit : public MidiEditor { static int _rasterInit; static int _dlistWidthInit, _dcanvasWidthInit; + static bool _ignore_hide_init; QAction *loadAction, *saveAction, *resetAction; QAction *cutAction, *copyAction, *copyRangeAction, *pasteAction, *pasteDialogAction, *deleteAction; QAction *fixedAction, *veloAction, *crescAction, *quantizeAction; QAction *sallAction, *snoneAction, *invAction, *inAction , *outAction; QAction *prevAction, *nextAction; - + QAction *groupNoneAction, *groupChanAction, *groupMaxAction; void initShortcuts(); @@ -109,7 +136,7 @@ class DrumEdit : public MidiEditor { void setHeaderToolTips(); void setHeaderWhatsThis(); - + private slots: void setRaster(int); void noteinfoChanged(MusEGui::NoteInfo::ValType type, int val); @@ -127,6 +154,14 @@ class DrumEdit : public MidiEditor { void configChanged(); void songChanged1(int); void setStep(QString); + void updateGroupingActions(); + void set_ignore_hide(bool); + void showAllInstruments(); + void hideAllInstruments(); + void hideUnusedInstruments(); + void hideEmptyInstruments(); + + void display_old_new_conflict_message(); public slots: void setSelection(int, MusECore::Event&, MusECore::Part*); @@ -134,8 +169,9 @@ class DrumEdit : public MidiEditor { void execDeliveredScript(int); void execUserScript(int); CtrlEdit* addCtrl(); - + void ourDrumMapChanged(bool); virtual void updateHScrollRange(); + signals: void isDeleting(MusEGui::TopWin*); @@ -146,6 +182,12 @@ class DrumEdit : public MidiEditor { virtual void writeStatus(int, MusECore::Xml&) const; static void readConfiguration(MusECore::Xml& xml); static void writeConfiguration(int, MusECore::Xml&); + + bool old_style_drummap_mode() { return _old_style_drummap_mode; } + group_mode_t group_mode() { return _group_mode; } + bool ignore_hide() { return _ignore_hide; } + + QVector<instrument_number_mapping_t>& get_instrument_map() { return static_cast<DrumCanvas*>(canvas)->get_instrument_map(); } //FINDMICH UGLY }; } // namespace MusEGui diff --git a/muse2/muse/midiedit/drummap.cpp b/muse2/muse/midiedit/drummap.cpp index aa7ce759..2705a252 100644 --- a/muse2/muse/midiedit/drummap.cpp +++ b/muse2/muse/midiedit/drummap.cpp @@ -26,10 +26,13 @@ #include "xml.h" #include "song.h" +#include <QSet> + namespace MusEGlobal { char drumOutmap[DRUM_MAPSIZE]; char drumInmap[128]; MusECore::DrumMap drumMap[DRUM_MAPSIZE]; +global_drum_ordering_t global_drum_ordering; } namespace MusECore { @@ -40,6 +43,15 @@ namespace MusECore { const DrumMap blankdm = { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 127, 127, false }; +// this map must have 128 entries, as it's used for initalising new-style-drummaps as well. +// new-style-drummaps only have 128 entries. also, the every "out-note" ("anote") must be +// represented exactly once in that map, and there may be no duplicate or unused "out-notes". +// reason: the track's drummap are inited as follows: iterate through the full idrumMap[], +// tracks_drummap[ idrumMap[i].anote ] = idrumMap[i] +// if you ever want to change this, you will need to go through track.cpp/.h and +// {dlist,dcanvas,drumedit,drummap}{.cpp,.h} (and possibly some more) and find every usage +// of idrumMap by new style drummaps, and fix the problem. a possible fix would be duplicating +// idrumMap, change idrumMap, and use the duplicate for the new style stuff instead. const DrumMap idrumMap[DRUM_MAPSIZE] = { { QString("Acoustic Bass Drum"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 35, 35, false }, { QString("Bass Drum 1"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 36, 36, false }, @@ -302,11 +314,10 @@ void resetGMDrumMap() // operator == //--------------------------------------------------------- -//bool const DrumMap::operator==(const DrumMap& map) const bool DrumMap::operator==(const DrumMap& map) const { return - (name == map.name) + name == map.name && vol == map.vol && quant == map.quant && len == map.len @@ -520,3 +531,137 @@ void readDrumMap(Xml& xml, bool external) } } // namespace MusECore + + +namespace MusEGlobal { + +void global_drum_ordering_t::cleanup() +{ + using MusEGlobal::song; + using MusECore::MidiTrack; + using MusECore::ciTrack; + + QSet<MidiTrack*> tracks; + for (ciTrack it = song->tracks()->begin(); it != song->tracks()->end(); it++) + tracks.insert( dynamic_cast<MidiTrack*>(*it) ); + + for (iterator it = begin(); it != end();) + { + if (!tracks.contains(it->first)) + it=erase(it); + else + it++; + } +} + +void global_drum_ordering_t::write(int level, MusECore::Xml& xml) +{ + cleanup(); + + xml.tag(level++, "drum_ordering"); + + for (iterator it = begin(); it != end(); it++) + write_single(level, xml, *it); + + xml.etag(level, "drum_ordering"); +} + +void global_drum_ordering_t::write_single(int level, MusECore::Xml& xml, const entry_t& entry) +{ + xml.tag(level++, "entry"); + xml.strTag(level, "track", entry.first->name()); + xml.intTag(level, "instrument", entry.second); + xml.etag(level, "entry"); +} + +void global_drum_ordering_t::read(MusECore::Xml& xml) +{ + using MusECore::Xml; + + clear(); + + for (;;) + { + Xml::Token token = xml.parse(); + if (token == Xml::Error || token == Xml::End) + break; + + const QString& tag = xml.s1(); + switch (token) + { + case Xml::TagStart: + if (tag == "entry") + append(read_single(xml)); + else + xml.unknown("global_drum_ordering_t"); + break; + + case Xml::TagEnd: + if (tag == "drum_ordering") + return; + + default: + break; + } + } +} + +global_drum_ordering_t::entry_t global_drum_ordering_t::read_single(MusECore::Xml& xml) +{ + using MusECore::Xml; + using MusEGlobal::song; + using MusECore::ciTrack; + + entry_t entry; + entry.first=NULL; + entry.second=-1; + + for (;;) + { + Xml::Token token = xml.parse(); + if (token == Xml::Error || token == Xml::End) + break; + + const QString& tag = xml.s1(); + switch (token) + { + case Xml::TagStart: + if (tag == "track") + { + QString track_name=xml.parse1(); + + ciTrack it; + for (it = song->tracks()->begin(); it != song->tracks()->end(); it++) + if (track_name == (*it)->name()) + break; + + if (it != song->tracks()->end()) + entry.first=dynamic_cast<MusECore::MidiTrack*>(*it); + } + else if (tag == "instrument") + entry.second=xml.parseInt(); + else + xml.unknown("global_drum_ordering_t (single entry)"); + break; + + case Xml::TagEnd: + if (tag == "entry") + goto end_of_read_single; + + default: + break; + } + } + + end_of_read_single: + + if (entry.first == NULL) + printf("ERROR: global_drum_ordering_t::read_single() couldn't find the specified track!\n"); + + if (entry.second < 0 || entry.second > 127) + printf("ERROR: global_drum_ordering_t::read_single(): instrument number is out of bounds (%i)!\n", entry.second); + + return entry; +} + +} // namespace MusEGlobal diff --git a/muse2/muse/midiedit/drummap.h b/muse2/muse/midiedit/drummap.h index 990f8fe2..3b6ffaf3 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> namespace MusECore { @@ -50,19 +51,40 @@ struct DrumMap { bool operator!=(const DrumMap& map) const { return !operator==(map); } }; +// please let this at "128". idrumMap must have length 128 (see drummap.cpp for details) #define DRUM_MAPSIZE 128 +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; } // namespace MusECore namespace MusEGlobal { extern char drumOutmap[DRUM_MAPSIZE]; extern char drumInmap[DRUM_MAPSIZE]; extern MusECore::DrumMap drumMap[DRUM_MAPSIZE]; + + +class global_drum_ordering_t : public QList< std::pair<MusECore::MidiTrack*,int> > +{ + public: + void cleanup(); + void write(int level, MusECore::Xml& xml); + void read(MusECore::Xml& xml); + + private: + typedef std::pair<MusECore::MidiTrack*,int> entry_t; + + void write_single(int level, MusECore::Xml& xml, const entry_t& entry); + entry_t read_single(MusECore::Xml& xml); +}; + +extern global_drum_ordering_t global_drum_ordering; + } #endif diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp index 80d901bb..3eeb4f84 100644 --- a/muse2/muse/midiedit/ecanvas.cpp +++ b/muse2/muse/midiedit/ecanvas.cpp @@ -57,6 +57,7 @@ EventCanvas::EventCanvas(MidiEditor* pr, QWidget* parent, int sx, _steprec = false; _midiin = false; _playEvents = false; + _setCurPartIfOnlyOneEventIsSelected = true; curVelo = 70; setBg(Qt::white); @@ -224,7 +225,7 @@ void EventCanvas::songChanged(int flags) start_tick = MusEGlobal::song->roundDownBar(start_tick); end_tick = MusEGlobal::song->roundUpBar(end_tick); - if (n == 1) { + if (n == 1 && _setCurPartIfOnlyOneEventIsSelected) { x = nevent->x(); event = nevent->event(); part = (MusECore::MidiPart*)nevent->part(); @@ -234,6 +235,7 @@ void EventCanvas::songChanged(int flags) curPartChanged(); } } + emit selectionChanged(x, event, part); if (curPart == 0) curPart = (MusECore::MidiPart*)(editor->parts()->begin()->second); diff --git a/muse2/muse/midiedit/ecanvas.h b/muse2/muse/midiedit/ecanvas.h index a67b7a14..ad19480e 100644 --- a/muse2/muse/midiedit/ecanvas.h +++ b/muse2/muse/midiedit/ecanvas.h @@ -69,13 +69,14 @@ class EventCanvas : public Canvas { int curVelo; bool _steprec; bool _midiin; + bool _setCurPartIfOnlyOneEventIsSelected; void updateSelection(); virtual CItem* addItem(MusECore::Part*, MusECore::Event&) = 0; // Added by T356. virtual QPoint raster(const QPoint&) const; virtual MusECore::Undo moveCanvasItems(CItemList&, int, int, DragType) = 0; - virtual MusECore::UndoOp moveItem(CItem*, const QPoint&, DragType) = 0; + virtual bool moveItem(MusECore::Undo&, CItem*, const QPoint&, DragType) = 0; virtual void endMoveItems(const QPoint&, DragType, int dir); public slots: diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index 0348bcbe..fe7f6979 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -116,6 +116,10 @@ PianoCanvas::PianoCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy) connect(MusEGlobal::song, SIGNAL(midiNote(int, int)), SLOT(midiNote(int,int))); } +PianoCanvas::~PianoCanvas() +{ + delete steprec; +} //--------------------------------------------------------- // pitch2y //--------------------------------------------------------- @@ -423,7 +427,7 @@ MusECore::Undo PianoCanvas::moveCanvasItems(MusEGui::CItemList& items, int dp, i // Do not process if the event has already been processed (meaning it's an event in a clone part)... if (idl == doneList.end()) { - operations.push_back(moveItem(ci, newpos, dtype)); + moveItem(operations, ci, newpos, dtype); // always returns true. if not, change is necessary here! doneList.push_back(ci); } ci->move(newpos); @@ -456,7 +460,7 @@ MusECore::Undo PianoCanvas::moveCanvasItems(MusEGui::CItemList& items, int dp, i // called after moving an object //--------------------------------------------------------- -MusECore::UndoOp PianoCanvas::moveItem(MusEGui::CItem* item, const QPoint& pos, DragType dtype) +bool PianoCanvas::moveItem(MusECore::Undo& operations, MusEGui::CItem* item, const QPoint& pos, DragType dtype) { NEvent* nevent = (NEvent*) item; MusECore::Event event = nevent->event(); @@ -492,10 +496,12 @@ MusECore::UndoOp PianoCanvas::moveItem(MusEGui::CItem* item, const QPoint& pos, // printf("PianoCanvas::moveItem Error! New event end:%d exceeds length:%d of part:%s\n", newEvent.endTick(), part->lenTick(), part->name().toLatin1().constData()); if (dtype == MOVE_COPY || dtype == MOVE_CLONE) - return MusECore::UndoOp(MusECore::UndoOp::AddEvent, newEvent, part, false, false); + operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddEvent, newEvent, part, false, false)); else - return MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false); - } + operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false)); + + return true; +} //--------------------------------------------------------- // newItem(p, state) @@ -734,8 +740,8 @@ void PianoCanvas::pianoPressed(int pitch, int velocity, bool shift) MusECore::MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity); MusEGlobal::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,pitch,editor->raster(),editor->raster(),velocity,MusEGlobal::globalKeyState&Qt::ControlModifier,shift); + if (_steprec && curPart /* && pos[0] >= start_tick && pos[0] < end_tick [removed by flo93: this is handled in steprec->record] */) + steprec->record(curPart,pitch,editor->raster(),editor->raster(),velocity,MusEGlobal::globalKeyState&Qt::ControlModifier,shift, -1 /* anything which is != rcSteprecNote */); } //--------------------------------------------------------- @@ -1075,6 +1081,7 @@ void PianoCanvas::itemMoved(const MusEGui::CItem* item, const QPoint& pos) void PianoCanvas::curPartChanged() { + EventCanvas::curPartChanged(); editor->setWindowTitle(getCaption()); } diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h index 42de7c95..35e4975f 100644 --- a/muse2/muse/midiedit/prcanvas.h +++ b/muse2/muse/midiedit/prcanvas.h @@ -73,7 +73,7 @@ class PianoCanvas : public EventCanvas { void drawTopItem(QPainter &p, const QRect &rect); virtual void drawMoving(QPainter&, const CItem*, const QRect&); virtual MusECore::Undo moveCanvasItems(CItemList&, int, int, DragType); - virtual MusECore::UndoOp moveItem(CItem*, const QPoint&, DragType); + virtual bool moveItem(MusECore::Undo&, CItem*, const QPoint&, DragType); virtual CItem* newItem(const QPoint&, int); virtual void resizeItem(CItem*, bool noSnap, bool); virtual void newItem(CItem*, bool noSnap); @@ -120,6 +120,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 44cfc114..c10adafd 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -1325,6 +1325,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); @@ -4650,6 +4655,20 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo // every time something changes. +/* STUFF I WANT TO WORK + * + * x multiple new drum tracks can be displayed seperately in ONE drum + * editor + * x reorder drummap + * ? support and correctly map e-note on record and steprec + * ? only record nonmuted/whatever notes + * ? support drum controllers + * x refuse to mix up old-style and new-style drum tracks in ONE editor + * o drummap saving and loading (per-track) + * o drummap import/export + * o drummap automatically adapting to the chosen midi synth / patch + */ + /* BUGS and potential bugs * o tied notes don't work properly when there's a key-change in * between, for example, when a cis is tied to a des @@ -4658,17 +4677,52 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo * (could be solved by storing the current window when quitting/saving whatever) * ? pasting in editors sometimes fails oO? ( ERROR: reading eventlist * from clipboard failed. ignoring this one... ) [ not reproducible ] - * ! o using super glue while a score editor displaying the glued parts - * is open lets muse segfault. this may or may not be fixed in - * the release branch :/ - * + * * CURRENT TODO + * o drum controllers + * update ctrlcanvas/panel + * test! + * * drum editor is buggy. propagate_drum_map may operate on old values + * ("BUGGY! problem is: while changing entries, ourDrumMap + * may be reallocated which causes abort()s and/or bugs.") + * [ seems to work now, needs further testing! ] + * > o my record flag handling + * o once, using super glue while a score editor displaying the glued + * parts is open let muse segfault. this may or may not be fixed + * now. check! + * state of revision #1337: no segfaults, but the score editors + * close and lots of "ERROR" messages. + * + * o drum editor: channel-stuff + * o clearly state in the changelog: when having multiple drumeditors open, + * the mute-column may not work, because another editor is overriding this. + * > o respect "_drummap_tied_to_patch": IMPLEMENT + * 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 fix valgrind problems (the two "FINDMICHJETZT" lines in scoreedit.cpp) * > o add a songposition scrollbar-toolbar (in different sizes) * this might be equivalent to "redo transport menu" (below). * > o add toolbar(s) for tempo- etc spinboxes from the transport window * + * + * o find and fix FINDMICHJETZT + * o fix all segfaults and non-working stuff! + * - creating, changing types to and from, erasing NEW_DRUM tracks + * - move parts around + * - playing them. mute? + * - recording/echoing/steprec them + * - load, save them + * o fix valgrind problems + * * IMPORTANT TODO + * o allow steprec-insert-rest-note to be set to "off" / "unused" + * 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 support edge-scrolling when opening a lasso * 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 37765dda..7a16d19f 100644 --- a/muse2/muse/midiedit/scoreedit.h +++ b/muse2/muse/midiedit/scoreedit.h @@ -832,7 +832,7 @@ class ScoreCanvas : public MusEGui::View public: ScoreCanvas(ScoreEdit*, QWidget*); - ~ScoreCanvas(){}; + ~ScoreCanvas(); void add_staves(MusECore::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/mixer/amixer.cpp b/muse2/muse/mixer/amixer.cpp index d03cc81e..08999777 100644 --- a/muse2/muse/mixer/amixer.cpp +++ b/muse2/muse/mixer/amixer.cpp @@ -183,6 +183,7 @@ AudioMixerApp::AudioMixerApp(QWidget* parent, MusEGlobal::MixerConfig* c) showMidiTracksId = new QAction(tr("Show Midi Tracks"), actionItems); showDrumTracksId = new QAction(tr("Show Drum Tracks"), actionItems); + showNewDrumTracksId = new QAction(tr("Show New Style Drum Tracks"), actionItems); showWaveTracksId = new QAction(tr("Show Wave Tracks"), actionItems); QAction *separator = new QAction(this); @@ -197,6 +198,7 @@ AudioMixerApp::AudioMixerApp(QWidget* parent, MusEGlobal::MixerConfig* c) showMidiTracksId->setCheckable(true); showDrumTracksId->setCheckable(true); + showNewDrumTracksId->setCheckable(true); showWaveTracksId->setCheckable(true); showInputTracksId->setCheckable(true); showOutputTracksId->setCheckable(true); @@ -208,6 +210,7 @@ AudioMixerApp::AudioMixerApp(QWidget* parent, MusEGlobal::MixerConfig* c) //connect(actionItems, SIGNAL(selected(QAction*)), this, SLOT(showTracksChanged(QAction*))); connect(showMidiTracksId, SIGNAL(triggered(bool)), SLOT(showMidiTracksChanged(bool))); connect(showDrumTracksId, SIGNAL(triggered(bool)), SLOT(showDrumTracksChanged(bool))); + connect(showNewDrumTracksId, SIGNAL(triggered(bool)), SLOT(showNewDrumTracksChanged(bool))); connect(showWaveTracksId, SIGNAL(triggered(bool)), SLOT(showWaveTracksChanged(bool))); connect(showInputTracksId, SIGNAL(triggered(bool)), SLOT(showInputTracksChanged(bool))); connect(showOutputTracksId, SIGNAL(triggered(bool)), SLOT(showOutputTracksChanged(bool))); @@ -351,6 +354,7 @@ void AudioMixerApp::updateMixer(UpdateAction action) showMidiTracksId->setChecked(cfg->showMidiTracks); showDrumTracksId->setChecked(cfg->showDrumTracks); + showNewDrumTracksId->setChecked(cfg->showNewDrumTracks); showInputTracksId->setChecked(cfg->showInputTracks); showOutputTracksId->setChecked(cfg->showOutputTracks); showWaveTracksId->setChecked(cfg->showWaveTracks); @@ -429,7 +433,7 @@ void AudioMixerApp::updateMixer(UpdateAction action) for (MusECore::iMidiTrack i = mtl->begin(); i != mtl->end(); ++i) { MusECore::MidiTrack* mt = *i; - if((mt->type() == MusECore::Track::MIDI && cfg->showMidiTracks) || (mt->type() == MusECore::Track::DRUM && cfg->showDrumTracks)) + if((mt->type() == MusECore::Track::MIDI && cfg->showMidiTracks) || (mt->type() == MusECore::Track::DRUM && cfg->showDrumTracks) || (mt->type() == MusECore::Track::NEW_DRUM && cfg->showNewDrumTracks)) addStrip(*i, idx++); } @@ -486,7 +490,7 @@ void AudioMixerApp::updateMixer(UpdateAction action) for (MusECore::iMidiTrack i = mtl->begin(); i != mtl->end(); ++i) { MusECore::MidiTrack* mt = *i; - if((mt->type() == MusECore::Track::MIDI && cfg->showMidiTracks) || (mt->type() == MusECore::Track::DRUM && cfg->showDrumTracks)) + if((mt->type() == MusECore::Track::MIDI && cfg->showMidiTracks) || (mt->type() == MusECore::Track::DRUM && cfg->showDrumTracks) || (mt->type() == MusECore::Track::NEW_DRUM && cfg->showNewDrumTracks)) addStrip(*i, idx++); } @@ -635,6 +639,8 @@ void AudioMixerApp::showTracksChanged(QAction* id) cfg->showMidiTracks = val; else if (id == showDrumTracksId) cfg->showDrumTracks = val; + else if (id == showNewDrumTracksId) + cfg->showNewDrumTracks = val; else if (id == showInputTracksId) cfg->showInputTracks = val; else if (id == showOutputTracksId) @@ -663,6 +669,12 @@ void AudioMixerApp::showDrumTracksChanged(bool v) updateMixer(UPDATE_ALL); } +void AudioMixerApp::showNewDrumTracksChanged(bool v) +{ + cfg->showNewDrumTracks = v; + updateMixer(UPDATE_ALL); +} + void AudioMixerApp::showWaveTracksChanged(bool v) { cfg->showWaveTracks = v; @@ -718,6 +730,7 @@ void AudioMixerApp::write(int level, MusECore::Xml& xml) xml.intTag(level, "showMidiTracks", cfg->showMidiTracks); xml.intTag(level, "showDrumTracks", cfg->showDrumTracks); + xml.intTag(level, "showNewDrumTracks", cfg->showNewDrumTracks); xml.intTag(level, "showInputTracks", cfg->showInputTracks); xml.intTag(level, "showOutputTracks", cfg->showOutputTracks); xml.intTag(level, "showWaveTracks", cfg->showWaveTracks); diff --git a/muse2/muse/mixer/amixer.h b/muse2/muse/mixer/amixer.h index a52e4264..e1c70ca3 100644 --- a/muse2/muse/mixer/amixer.h +++ b/muse2/muse/mixer/amixer.h @@ -99,6 +99,7 @@ class AudioMixerApp : public QMainWindow { QAction* showMidiTracksId; QAction* showDrumTracksId; + QAction* showNewDrumTracksId; QAction* showInputTracksId; QAction* showOutputTracksId; QAction* showWaveTracksId; @@ -132,6 +133,7 @@ class AudioMixerApp : public QMainWindow { //void showTracksChanged(QAction*); void showMidiTracksChanged(bool); void showDrumTracksChanged(bool); + void showNewDrumTracksChanged(bool); void showWaveTracksChanged(bool); void showInputTracksChanged(bool); void showOutputTracksChanged(bool); diff --git a/muse2/muse/mixer/strip.cpp b/muse2/muse/mixer/strip.cpp index e8b52887..d574adb6 100644 --- a/muse2/muse/mixer/strip.cpp +++ b/muse2/muse/mixer/strip.cpp @@ -151,6 +151,10 @@ void Strip::setLabelText() //c = QColor(0, 160, 255); // Med blue c = MusEGlobal::config.drumTrackLabelBg; break; + case MusECore::Track::NEW_DRUM: + //c = QColor(0, 160, 255); // Med blue + c = MusEGlobal::config.newDrumTrackLabelBg; + break; default: return; } diff --git a/muse2/muse/part.cpp b/muse2/muse/part.cpp index da01a5d5..33519e11 100644 --- a/muse2/muse/part.cpp +++ b/muse2/muse/part.cpp @@ -38,7 +38,7 @@ namespace MusECore { -int Part::snGen; +int Part::snGen=0; //--------------------------------------------------------- // unchainClone @@ -929,6 +929,7 @@ void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len, bool doClo break; case Track::MIDI: case Track::DRUM: + case Track::NEW_DRUM: { Undo operations; @@ -975,6 +976,7 @@ void Track::splitPart(Part* part, int tickpos, Part*& p1, Part*& p2) break; case MIDI: case DRUM: + case NEW_DRUM: l1 = tickpos - part->tick(); l2 = part->lenTick() - l1; break; @@ -998,6 +1000,7 @@ void Track::splitPart(Part* part, int tickpos, Part*& p1, Part*& p2) break; case MIDI: case DRUM: + case NEW_DRUM: p1->setLenTick(l1); p2->setTick(tickpos); p2->setLenTick(l2); diff --git a/muse2/muse/remote/pyapi.cpp b/muse2/muse/remote/pyapi.cpp index de8f15ef..90818a44 100644 --- a/muse2/muse/remote/pyapi.cpp +++ b/muse2/muse/remote/pyapi.cpp @@ -697,7 +697,8 @@ PyObject* getAudioTrackVolume(PyObject*, PyObject* args) if (t == NULL) return NULL; - if (t->type() == Track::DRUM || t->type() == Track::MIDI) + //if (t->type() == Track::DRUM || t->type() == Track::MIDI || t->type() == Track::NEW_DRUM) + if (t->isMidiTrack()) // changed by flo. should do the same thing and is better maintainable return NULL; AudioTrack* track = (AudioTrack*) t; @@ -1091,7 +1092,8 @@ bool Song::event(QEvent* _e) if (t == NULL) return false; - if (t->type() == Track::DRUM || t->type() == Track::MIDI) + if (t->isMidiTrack()) // changed by flo. is better maintainable + //if (t->type() == Track::DRUM || t->type() == Track::NEW_DRUM || t->type() == Track::MIDI) return false; AudioTrack* track = (AudioTrack*) t; diff --git a/muse2/muse/shortcuts.cpp b/muse2/muse/shortcuts.cpp index cefb198e..95df7292 100644 --- a/muse2/muse/shortcuts.cpp +++ b/muse2/muse/shortcuts.cpp @@ -99,6 +99,7 @@ void initShortCuts() defShrt(SHRT_OPEN_MIDI_TRANSFORM, Qt::CTRL + Qt::Key_T, QT_TRANSLATE_NOOP("shortcuts", "Open midi transformer"), ARRANG_SHRT, "open_midi_transform"); defShrt(SHRT_ADD_MIDI_TRACK, Qt::CTRL + Qt::Key_J, QT_TRANSLATE_NOOP("shortcuts", "Add midi track"), ARRANG_SHRT, "add_midi_track"); defShrt(SHRT_ADD_DRUM_TRACK, 0, QT_TRANSLATE_NOOP("shortcuts", "Add drum track"), ARRANG_SHRT, "add_drum_track"); + defShrt(SHRT_ADD_NEW_STYLE_DRUM_TRACK, 0, QT_TRANSLATE_NOOP("shortcuts", "Add new style drum track"), ARRANG_SHRT, "add_new_style_drum_track"); defShrt(SHRT_ADD_WAVE_TRACK, 0, QT_TRANSLATE_NOOP("shortcuts", "Add wave track"), ARRANG_SHRT, "add_wave_track"); defShrt(SHRT_ADD_AUDIO_OUTPUT, 0, QT_TRANSLATE_NOOP("shortcuts", "Add audio output"), ARRANG_SHRT, "add_audio_output"); defShrt(SHRT_ADD_AUDIO_GROUP, 0, QT_TRANSLATE_NOOP("shortcuts", "Add audio group"), ARRANG_SHRT, "add_audio_group"); diff --git a/muse2/muse/shortcuts.h b/muse2/muse/shortcuts.h index 626c4fb8..dc2e6f22 100644 --- a/muse2/muse/shortcuts.h +++ b/muse2/muse/shortcuts.h @@ -174,6 +174,7 @@ enum { SHRT_ADD_MIDI_TRACK, //Default: Ctrl+J SHRT_ADD_DRUM_TRACK, //Default: undefined + SHRT_ADD_NEW_STYLE_DRUM_TRACK, //Default: undefined SHRT_ADD_WAVE_TRACK, //Default: undefined SHRT_ADD_AUDIO_OUTPUT, //Default: undefined SHRT_ADD_AUDIO_GROUP, //Default: undefined diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp index 8b8f6e15..484e2d42 100644 --- a/muse2/muse/song.cpp +++ b/muse2/muse/song.cpp @@ -243,6 +243,11 @@ Track* Song::addTrack(Undo& operations, Track::TrackType type, Track* insertAt) track->setType(Track::MIDI); if (MusEGlobal::config.unhideTracks) MidiTrack::setVisible(true); break; + case Track::NEW_DRUM: + track = new MidiTrack(); + track->setType(Track::NEW_DRUM); + ((MidiTrack*)track)->setOutChannel(9); + break; case Track::DRUM: track = new MidiTrack(); track->setType(Track::DRUM); @@ -328,7 +333,7 @@ Track* Song::addTrack(Undo& operations, Track::TrackType type, Track* insertAt) { defOutFound = true; mt->setOutPort(i); - if(type != Track::DRUM) // p4.0.17 Leave drum tracks at channel 10. + if(type != Track::DRUM && type != Track::NEW_DRUM) // p4.0.17 Leave drum tracks at channel 10. mt->setOutChannel(ch); updateFlags |= SC_ROUTE; break; @@ -349,6 +354,7 @@ Track* Song::addTrack(Undo& operations, Track::TrackType type, Track* insertAt) switch(type) { //case Track::MIDI: //case Track::DRUM: + //case Track::NEW_DRUM: //case Track::AUDIO_OUTPUT: // break; @@ -512,7 +518,7 @@ void Song::remapPortDrumCtrlEvents(int mapidx, int newnote, int newchan, int new { MidiPart* part = (MidiPart*)(ip->second); const EventList* el = part->cevents(); - // unsigned len = part->lenTick(); // unneeded, see below. + // unsigned len = part->lenTick(); // Commented out by flo, see below for(ciEvent ie = el->begin(); ie != el->end(); ++ie) { const Event& ev = ie->second; @@ -585,13 +591,15 @@ void Song::changeAllPortDrumCtrlEvents(bool add, bool drumonly) { MidiPart* part = (MidiPart*)(ip->second); const EventList* el = part->cevents(); - unsigned len = part->lenTick(); + // unsigned len = part->lenTick(); // Commented out by flo, see below for(ciEvent ie = el->begin(); ie != el->end(); ++ie) { const Event& ev = ie->second; // Added by T356. Do not handle events which are past the end of the part. - if(ev.tick() >= len) - break; + // Commented out by flo: yes, DO handle them! these are "hidden events" + // which may be revealed later again! + // if(ev.tick() >= len) + // break; if(ev.type() != Controller) continue; @@ -1272,11 +1280,13 @@ void Song::rewindStart() // update //--------------------------------------------------------- -void Song::update(int flags) +void Song::update(int flags, bool allowRecursion) { static int level = 0; // DEBUG - if (level) { - printf("Song::update %08x, level %d\n", flags, level); + if (level && !allowRecursion) { + printf("THIS SHOULD NEVER HAPPEN: unallowed recursion in Song::update(%08x), level %d!\n" + " the songChanged() signal is NOT emitted. this will\n" + " probably cause windows being not up-to-date.\n", flags, level); return; } ++level; @@ -2911,6 +2921,7 @@ void Song::insertTrack2(Track* track, int idx) switch(track->type()) { case Track::MIDI: case Track::DRUM: + case Track::NEW_DRUM: _midis.push_back((MidiTrack*)track); // Added by T356. //((MidiTrack*)track)->addPortCtrlEvents(); @@ -3148,6 +3159,7 @@ void Song::removeTrack2(Track* track) switch(track->type()) { case Track::MIDI: case Track::DRUM: + case Track::NEW_DRUM: // Added by T356. //((MidiTrack*)track)->removePortCtrlEvents(); removePortCtrlEvents(((MidiTrack*)track)); diff --git a/muse2/muse/song.h b/muse2/muse/song.h index 2c07396c..047dbac3 100644 --- a/muse2/muse/song.h +++ b/muse2/muse/song.h @@ -384,7 +384,9 @@ class Song : public QObject { public slots: void seekTo(int tick); - void update(int flags = -1); + void update(int flags = -1, bool allowRecursion=false); // use allowRecursion with care! this + // could lock up muse if you aren't sure + // that your recursion will be finite! void beat(); void undo(); diff --git a/muse2/muse/songfile.cpp b/muse2/muse/songfile.cpp index 9a3c11f5..5726345e 100644 --- a/muse2/muse/songfile.cpp +++ b/muse2/muse/songfile.cpp @@ -1050,6 +1050,12 @@ void Song::read(Xml& xml, bool isTemplate) track->read(xml); insertTrack0(track, -1); } + else if (tag == "newdrumtrack") { + MidiTrack* track = new MidiTrack(); + track->setType(Track::NEW_DRUM); + track->read(xml); + insertTrack0(track, -1); + } else if (tag == "wavetrack") { MusECore::WaveTrack* track = new MusECore::WaveTrack(); track->read(xml); @@ -1115,6 +1121,8 @@ void Song::read(Xml& xml, bool isTemplate) } else if (tag == "drummap") readDrumMap(xml, false); + else if (tag == "drum_ordering") + MusEGlobal::global_drum_ordering.read(xml); else xml.unknown("Song"); break; @@ -1207,6 +1215,7 @@ void Song::write(int level, Xml& xml) const _markerList->write(level, xml); writeDrumMap(level, xml, false); + MusEGlobal::global_drum_ordering.write(level, xml); xml.tag(level, "/song"); // Restore backup of the clone list, to retain any 'copy' items, diff --git a/muse2/muse/steprec.cpp b/muse2/muse/steprec.cpp index ea3feae7..723fe650 100644 --- a/muse2/muse/steprec.cpp +++ b/muse2/muse/steprec.cpp @@ -55,13 +55,23 @@ void StepRec::timeout() } } -void StepRec::record(Part* part, int pitch, int len, int step, int velo, bool ctrl, bool shift) +void StepRec::record(Part* part, int pitch, int len, int step, int velo, bool ctrl, bool shift, int incoming_pitch) { unsigned tick = MusEGlobal::song->cpos(); unsigned lasttick=0; Undo operations; - if (pitch!=MusEGlobal::rcSteprecNote) + if (tick < part->tick()) //insert note before the part to insert? + { + if (MusEGlobal::debugMsg) + printf("StepRec::record(): tick (%i) is before part (begin tick is %i), ignoring...\n",tick, part->tick()); + return; + } + + // if incoming_pitch wasn't specified, set it to pitch + if (incoming_pitch == 1337) incoming_pitch=pitch; + + if (incoming_pitch!=MusEGlobal::rcSteprecNote) { chord_timer->stop(); @@ -132,7 +142,7 @@ void StepRec::record(Part* part, int pitch, int len, int step, int velo, bool ct goto steprec_record_foot; // this is actually unneccessary, but for clarity } - else // equals if (pitch==MusEGlobal::rcSteprecNote) + else // equals if (incoming_pitch==MusEGlobal::rcSteprecNote) { bool held_notes=false; if (note_held_down!=NULL) diff --git a/muse2/muse/steprec.h b/muse2/muse/steprec.h index ba42c49c..a82cab20 100644 --- a/muse2/muse/steprec.h +++ b/muse2/muse/steprec.h @@ -37,7 +37,7 @@ class StepRec : public QObject public: StepRec(bool* note_held_down_array); - void record(Part* part, int pitch, int len, int step, int velo=80, bool ctrl=false, bool shift=false); + void record(Part* part, int recorded_pitch, int len, int step, int velo=80, bool ctrl=false, bool shift=false, int incoming_pitch=1337); private slots: void timeout(); diff --git a/muse2/muse/track.cpp b/muse2/muse/track.cpp index e9aa0cf6..4dd2e0c5 100644 --- a/muse2/muse/track.cpp +++ b/muse2/muse/track.cpp @@ -33,6 +33,7 @@ #include "audio.h" #include "globaldefs.h" #include "route.h" +#include "drummap.h" namespace MusECore { @@ -45,8 +46,8 @@ bool Track::_tmpSoloChainNoDec = false; //int Track::_tmpIsAuxProcRefCount = 0; const char* Track::_cname[] = { - "Midi", "Drum", "Wave", "AudioOut", "AudioIn", "AudioGroup", - "AudioAux", "AudioSynth" + "Midi", "Drum", "NewStyleDrum", "Wave", + "AudioOut", "AudioIn", "AudioGroup", "AudioAux", "AudioSynth" }; @@ -352,6 +353,7 @@ void Track::setDefaultName() switch(_type) { case MIDI: case DRUM: + case NEW_DRUM: case WAVE: base = QString("Track"); break; @@ -536,6 +538,11 @@ MidiTrack::MidiTrack() _events = new EventList; _mpevents = new MPEventList; clefType=trebleClef; + + _drummap=new DrumMap[128]; + _drummap_hidden=new bool[128]; + + init_drummap(true /* write drummap ordering information as well */); } //MidiTrack::MidiTrack(const MidiTrack& mt) @@ -556,14 +563,41 @@ 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)); + update_drum_in_map(); + + for (MusEGlobal::global_drum_ordering_t::iterator it=MusEGlobal::global_drum_ordering.begin(); it!=MusEGlobal::global_drum_ordering.end(); it++) + if (it->first == &mt) + { + it=MusEGlobal::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_drum_ordering(); } +void MidiTrack::remove_ourselves_from_drum_ordering() +{ + for (MusEGlobal::global_drum_ordering_t::iterator it=MusEGlobal::global_drum_ordering.begin(); it!=MusEGlobal::global_drum_ordering.end();) + if (it->first == this) + it=MusEGlobal::global_drum_ordering.erase(it); + else + it++; +} + //--------------------------------------------------------- // init //--------------------------------------------------------- @@ -571,7 +605,7 @@ MidiTrack::~MidiTrack() void MidiTrack::init() { _outPort = 0; - _outChannel = 0; + _outChannel = (type()==NEW_DRUM) ? 9 : 0; //_inPortMask = 0xffff; ///_inPortMask = 0xffffffff; @@ -584,6 +618,34 @@ void MidiTrack::init() _recEcho = true; } +void MidiTrack::init_drummap(bool write_ordering) +{ + 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]; + + if (write_ordering) + MusEGlobal::global_drum_ordering.push_back(std::pair<MidiTrack*,int>(this,idx)); + } + + update_drum_in_map(); + + for (int i=0;i<128;i++) + _drummap_hidden[i]=false; + + _drummap_tied_to_patch=true; +} + +void MidiTrack::update_drum_in_map() +{ + for (int i=0;i<127;i++) + drum_in_map[(int)_drummap[i].enote]=i; +} + //--------------------------------------------------------- // height //--------------------------------------------------------- @@ -841,8 +903,13 @@ void MidiTrack::write(int level, Xml& xml) const if (type() == DRUM) tag = "drumtrack"; - else + else if (type() == MIDI) tag = "miditrack"; + else if (type() == NEW_DRUM) + tag = "newdrumtrack"; + else + printf("THIS SHOULD NEVER HAPPEN: non-midi-type in MidiTrack::write()\n"); + xml.tag(level++, tag); Track::writeProperties(level, xml); @@ -865,9 +932,77 @@ void MidiTrack::write(int level, Xml& xml) const const PartList* pl = cparts(); for (ciPart p = pl->begin(); p != pl->end(); ++p) p->second->write(level, xml); + + writeOurDrumSettings(level, xml); + xml.etag(level, tag); } +void MidiTrack::writeOurDrumSettings(int level, Xml& xml) const +{ + xml.tag(level++, "our_drum_settings"); + + writeOurDrumMap(level, xml, false); + + xml.intTag(level, "tied", _drummap_tied_to_patch); + + xml.etag(level, "our_drum_settings"); +} + +void MidiTrack::writeOurDrumMap(int level, Xml& xml, bool full) const +{ + xml.tag(level++, "our_drummap"); + + for (int i=0;i<128;i++) + { + int j; + for (j=0;j<128;j++) + if (idrumMap[j].anote == i) break; + + if (j==128) + printf("THIS SHOULD NEVER HAPPEN: couldn't find initial drum map entry in MidiTrack::writeOurDrumMap()\n"); + else + { + DrumMap* dm = &_drummap[i]; + const DrumMap* idm = &idrumMap[j]; + + if ( (dm->name != idm->name) || (dm->vol != idm->vol) || + (dm->quant != idm->quant) || (dm->len != idm->len) || + (dm->lv1 != idm->lv1) || (dm->lv2 != idm->lv2) || + (dm->lv3 != idm->lv3) || (dm->lv4 != idm->lv4) || + (dm->enote != idm->enote) || (dm->mute != idm->mute) || + _drummap_hidden[i] || full) + { + xml.tag(level++, "entry pitch=\"%d\"", i); + + // when any of these "if"s changes, also update the large "if" + // above (this scope's parent) + if (full || dm->name != idm->name) xml.strTag(level, "name", dm->name); + if (full || dm->vol != idm->vol) xml.intTag(level, "vol", dm->vol); + if (full || dm->quant != idm->quant) xml.intTag(level, "quant", dm->quant); + if (full || dm->len != idm->len) xml.intTag(level, "len", dm->len); + if (full || dm->lv1 != idm->lv1) xml.intTag(level, "lv1", dm->lv1); + if (full || dm->lv2 != idm->lv2) xml.intTag(level, "lv2", dm->lv2); + if (full || dm->lv3 != idm->lv3) xml.intTag(level, "lv3", dm->lv3); + if (full || dm->lv4 != idm->lv4) xml.intTag(level, "lv4", dm->lv4); + if (full || dm->enote != idm->enote) xml.intTag(level, "enote", dm->enote); + if (full || dm->mute != idm->mute) xml.intTag(level, "mute", dm->mute); + if (full || _drummap_hidden[i]) xml.intTag(level, "hide", _drummap_hidden[i]); + + // anote is ignored anyway, as dm->anote == i, and this is + // already stored in the begin tag (pitch=...) + + // channel and port are ignored as well, as they're not used + // in new-style-drum-mode + + xml.tag(level--, "/entry"); + } + } + } + + xml.etag(level, "our_drummap"); +} + //--------------------------------------------------------- // MidiTrack::read //--------------------------------------------------------- @@ -924,6 +1059,8 @@ void MidiTrack::read(Xml& xml) setAutomationType(AutomationType(xml.parseInt())); else if (tag == "clef") clefType = (clefTypes)xml.parseInt(); + else if (tag == "our_drum_settings") + readOurDrumSettings(xml); else if (Track::readProperties(xml, tag)) { // version 1.0 compatibility: if (tag == "track" && xml.majorVersion() == 1 && xml.minorVersion() == 0) @@ -934,7 +1071,7 @@ void MidiTrack::read(Xml& xml) case Xml::Attribut: break; case Xml::TagEnd: - if (tag == "miditrack" || tag == "drumtrack") + if (tag == "miditrack" || tag == "drumtrack" || tag == "newdrumtrack") { setInPortAndChannelMask(portmask, chanmask); // Support old files. return; @@ -945,6 +1082,133 @@ void MidiTrack::read(Xml& xml) } } +void MidiTrack::readOurDrumSettings(Xml& xml) +{ + for (;;) + { + Xml::Token token = xml.parse(); + if (token == Xml::Error || token == Xml::End) + break; + const QString& tag = xml.s1(); + switch (token) + { + case Xml::TagStart: + if (tag == "tied") + _drummap_tied_to_patch = xml.parseInt(); + else if (tag == "our_drummap") + readOurDrumMap(xml); + else + xml.unknown("MidiTrack::readOurDrumSettings"); + break; + + case Xml::TagEnd: + if (tag == "our_drum_settings") + return; + + default: + break; + } + } +} + +void MidiTrack::readOurDrumMap(Xml& xml, bool dont_init) +{ + if (!dont_init) init_drummap(false); + _drummap_tied_to_patch=false; + + for (;;) + { + Xml::Token token = xml.parse(); + if (token == Xml::Error || token == Xml::End) + break; + const QString& tag = xml.s1(); + switch (token) + { + case Xml::TagStart: + if (tag == "entry") // then read that entry with a nested loop + { + DrumMap* dm=NULL; + bool* hidden=NULL; + for (;;) // nested loop + { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) + { + case Xml::Error: + case Xml::End: + goto end_of_nested_for; + + case Xml::Attribut: + if (tag == "pitch") + { + int pitch = xml.s2().toInt() & 0x7f; + if (pitch < 0 || pitch > 127) + printf("ERROR: THIS SHOULD NEVER HAPPEN: invalid pitch in MidiTrack::readOurDrumMap()!\n"); + else + { + dm = &_drummap[pitch]; + hidden = &_drummap_hidden[pitch]; + } + } + break; + + case Xml::TagStart: + if (dm==NULL) + printf("ERROR: THIS SHOULD NEVER HAPPEN: no valid 'pitch' attribute in <entry> tag, but sub-tags follow in MidiTrack::readOurDrumMap()!\n"); + else if (tag == "name") + dm->name = xml.parse(QString("name")); + else if (tag == "vol") + dm->vol = (unsigned char)xml.parseInt(); + else if (tag == "quant") + dm->quant = xml.parseInt(); + else if (tag == "len") + dm->len = xml.parseInt(); + else if (tag == "lv1") + dm->lv1 = xml.parseInt(); + else if (tag == "lv2") + dm->lv2 = xml.parseInt(); + else if (tag == "lv3") + dm->lv3 = xml.parseInt(); + else if (tag == "lv4") + dm->lv4 = xml.parseInt(); + else if (tag == "enote") + dm->enote = xml.parseInt(); + else if (tag == "mute") + dm->mute = xml.parseInt(); + else if (tag == "hide") + *hidden = xml.parseInt(); + else + xml.unknown("MidiTrack::readOurDrumMap"); + break; + + case Xml::TagEnd: + if (tag == "entry") + goto end_of_nested_for; + + default: + break; + } + } // end of nested loop + end_of_nested_for: ; + } // end of 'if (tag == "entry")' + else + xml.unknown("MidiTrack::readOurDrumMap"); + break; + + case Xml::TagEnd: + if (tag == "our_drummap") + { + update_drum_in_map(); + return; + } + + default: + break; + } + } +} + //--------------------------------------------------------- // addPart diff --git a/muse2/muse/track.h b/muse2/muse/track.h index 04cf71c2..f2e12e3a 100644 --- a/muse2/muse/track.h +++ b/muse2/muse/track.h @@ -45,6 +45,7 @@ class PluginI; class SndFile; class SynthI; class Xml; +class DrumMap; //--------------------------------------------------------- @@ -54,7 +55,7 @@ class Xml; class Track { public: enum TrackType { - MIDI=0, DRUM, WAVE, AUDIO_OUTPUT, AUDIO_INPUT, AUDIO_GROUP, + MIDI=0, DRUM, NEW_DRUM, WAVE, AUDIO_OUTPUT, AUDIO_INPUT, AUDIO_GROUP, AUDIO_AUX, AUDIO_SOFTSYNTH }; private: @@ -202,11 +203,12 @@ class Track { void setDefaultName(); int channels() const { return _channels; } virtual void setChannels(int n); - bool isMidiTrack() const { return type() == MIDI || type() == DRUM; } + bool isMidiTrack() const { return type() == MIDI || type() == DRUM || type() == NEW_DRUM; } + bool isDrumTrack() const { return type() == DRUM || type() == NEW_DRUM; } 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) { } bool isVisible(); }; @@ -230,6 +232,20 @@ class MidiTrack : public Track { MPEventList* _mpevents; // tmp Events druring recording static bool _isVisible; clefTypes clefType; + + DrumMap* _drummap; // _drummap[foo].anote is always equal to foo + bool* _drummap_hidden; // _drummap und _drummap_hidden will be an array[128] + bool _drummap_tied_to_patch; //if true, changing patch also changes drummap + int drum_in_map[128]; + + void init(); + void init_drummap(bool write_ordering); // function without argument in public + void remove_ourselves_from_drum_ordering(); + + void writeOurDrumSettings(int level, Xml& xml) const; + void readOurDrumSettings(Xml& xml); + //void writeOurDrumMap(int level, Xml& xml, bool full) const; //below in public: + //void readOurDrumMap(Xml& xml, bool dont_init=false); //below in public: public: MidiTrack(); @@ -237,7 +253,6 @@ class MidiTrack : public Track { MidiTrack(const MidiTrack&, bool cloneParts); virtual ~MidiTrack(); - void init(); virtual AutomationType automationType() const; virtual void setAutomationType(AutomationType); @@ -298,6 +313,18 @@ class MidiTrack : public Track { void setClef(clefTypes i) { clefType = i; } clefTypes getClef() { return clefType; } + + DrumMap* drummap() { return _drummap; } + bool* drummap_hidden() { return _drummap_hidden; } + int map_drum_in(int enote) { return drum_in_map[enote]; } + void update_drum_in_map(); + + void init_drummap() { init_drummap(false); } // function with argument in private + + //void writeOurDrumSettings(int level, Xml& xml) const; // above in private: + //void readOurDrumSettings(Xml& xml); // above in private: + void writeOurDrumMap(int level, Xml& xml, bool full) const; + void readOurDrumMap(Xml& xml, bool dont_init=false); }; //--------------------------------------------------------- diff --git a/muse2/muse/undo.h b/muse2/muse/undo.h index ce73ac9a..dffa1f55 100644 --- a/muse2/muse/undo.h +++ b/muse2/muse/undo.h @@ -124,7 +124,7 @@ struct UndoOp { class Undo : public std::list<UndoOp> { public: bool empty() const; -}; + }; typedef Undo::iterator iUndoOp; typedef Undo::reverse_iterator riUndoOp; diff --git a/muse2/muse/widgets/canvas.cpp b/muse2/muse/widgets/canvas.cpp index 41c5f4a4..9a1935a3 100644 --- a/muse2/muse/widgets/canvas.cpp +++ b/muse2/muse/widgets/canvas.cpp @@ -750,11 +750,6 @@ void Canvas::viewMousePressEvent(QMouseEvent* event) switch (_tool) { case PointerTool: if (curItem) { - if (curItem->part() != curPart) { - curPart = curItem->part(); - curPartId = curPart->sn(); - curPartChanged(); - } itemPressed(curItem); // Changed by T356. Alt is default reserved for moving the whole window in KDE. Changed to Shift-Alt. // Hmm, nope, shift-alt is also reserved sometimes. Must find a way to bypass, @@ -1226,6 +1221,12 @@ void Canvas::viewMouseReleaseEvent(QMouseEvent* event) case DRAG_MOVE_START: case DRAG_COPY_START: case DRAG_CLONE_START: + if (curItem->part() != curPart) { + curPart = curItem->part(); + curPartId = curPart->sn(); + curPartChanged(); + } + if (!ctrl) deselectAll(); diff --git a/muse2/muse/widgets/canvas.h b/muse2/muse/widgets/canvas.h index 38024feb..2ab4820c 100644 --- a/muse2/muse/widgets/canvas.h +++ b/muse2/muse/widgets/canvas.h @@ -172,7 +172,7 @@ class Canvas : public View { virtual void itemPressed(const CItem*) {} virtual void itemReleased(const CItem*, const QPoint&) {} virtual void itemMoved(const CItem*, const QPoint&) {} - virtual void curPartChanged() {} + virtual void curPartChanged() { emit curPartHasChanged(curPart); } public slots: void setTool(int t); @@ -188,6 +188,8 @@ class Canvas : public View { void horizontalScrollNoLimit(unsigned); void horizontalZoomIn(); void horizontalZoomOut(); + void curPartHasChanged(MusECore::Part*); + public: Canvas(QWidget* parent, int sx, int sy, const char* name = 0); virtual ~Canvas(); diff --git a/muse2/muse/widgets/configmidifilebase.ui b/muse2/muse/widgets/configmidifilebase.ui index ca64f2d8..3eb7063e 100644 --- a/muse2/muse/widgets/configmidifilebase.ui +++ b/muse2/muse/widgets/configmidifilebase.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>548</width> - <height>353</height> + <width>546</width> + <height>367</height> </rect> </property> <property name="windowTitle"> @@ -42,6 +42,27 @@ </property> </widget> </item> + <item row="1" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QRadioButton" name="newDrumsCheckbox"> + <property name="text"> + <string>Use new-style drum tracks</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="oldDrumsCheckbox"> + <property name="text"> + <string>Use old-style drum tracks</string> + </property> + </widget> + </item> + </layout> + </item> </layout> </widget> </item> diff --git a/muse2/muse/widgets/genset.cpp b/muse2/muse/widgets/genset.cpp index ec2c8637..422f5110 100644 --- a/muse2/muse/widgets/genset.cpp +++ b/muse2/muse/widgets/genset.cpp @@ -65,6 +65,13 @@ GlobalSettingsConfig::GlobalSettingsConfig(QWidget* parent) startSongGroup->addButton(startLastButton, 0); startSongGroup->addButton(startEmptyButton, 1); startSongGroup->addButton(startSongButton, 2); + + recDrumGroup = new QButtonGroup(this); + recDrumGroup->addButton(recordAllButton, MusECore::REC_ALL); + recDrumGroup->addButton(dontRecHiddenButton, MusECore::DONT_REC_HIDDEN); + recDrumGroup->addButton(dontRecMutedButton, MusECore::DONT_REC_MUTED); + recDrumGroup->addButton(dontRecBothButton, MusECore::DONT_REC_MUTED_OR_HIDDEN); + for (unsigned i = 0; i < sizeof(rtcResolutions)/sizeof(*rtcResolutions); ++i) { if (rtcResolutions[i] == MusEGlobal::config.rtcTicks) { rtcResolutionSelect->setCurrentIndex(i); @@ -124,6 +131,8 @@ Shorter periods are desirable.</string> startSongEntry->setText(MusEGlobal::config.startSong); startSongGroup->button(MusEGlobal::config.startMode)->setChecked(true); + recDrumGroup->button(MusEGlobal::config.newDrumRecordCondition)->setChecked(true); + showTransport->setChecked(MusEGlobal::config.transportVisible); showBigtime->setChecked(MusEGlobal::config.bigTimeVisible); //showMixer->setChecked(MusEGlobal::config.mixerVisible); @@ -175,6 +184,14 @@ Shorter periods are desirable.</string> addHiddenCheckBox->setChecked(MusEGlobal::config.addHiddenTracks); unhideTracksCheckBox->setChecked(MusEGlobal::config.unhideTracks); + + switch (MusEGlobal::config.drumTrackPreference) + { + case MusEGlobal::ONLY_NEW: onlyNewDrumBtn->setChecked(true); break; + case MusEGlobal::ONLY_OLD: onlyOldDrumBtn->setChecked(true); break; + case MusEGlobal::PREFER_NEW: preferNewDrumBtn->setChecked(true); break; + case MusEGlobal::PREFER_OLD: preferOldDrumBtn->setChecked(true); break; + } //updateSettings(); // TESTING @@ -269,6 +286,8 @@ void GlobalSettingsConfig::updateSettings() startSongEntry->setText(MusEGlobal::config.startSong); startSongGroup->button(MusEGlobal::config.startMode)->setChecked(true); + recDrumGroup->button(MusEGlobal::config.newDrumRecordCondition)->setChecked(true); + showTransport->setChecked(MusEGlobal::config.transportVisible); showBigtime->setChecked(MusEGlobal::config.bigTimeVisible); //showMixer->setChecked(MusEGlobal::config.mixerVisible); @@ -321,6 +340,14 @@ void GlobalSettingsConfig::updateSettings() addHiddenCheckBox->setChecked(MusEGlobal::config.addHiddenTracks); unhideTracksCheckBox->setChecked(MusEGlobal::config.unhideTracks); + switch (MusEGlobal::config.drumTrackPreference) + { + case MusEGlobal::ONLY_NEW: onlyNewDrumBtn->setChecked(true); break; + case MusEGlobal::ONLY_OLD: onlyOldDrumBtn->setChecked(true); break; + case MusEGlobal::PREFER_NEW: preferNewDrumBtn->setChecked(true); break; + case MusEGlobal::PREFER_OLD: preferOldDrumBtn->setChecked(true); break; + } + updateMdiSettings(); } @@ -366,6 +393,8 @@ void GlobalSettingsConfig::apply() MusEGlobal::config.startSong = startSongEntry->text(); MusEGlobal::config.startMode = startSongGroup->checkedId(); + MusEGlobal::config.newDrumRecordCondition = MusECore::newDrumRecordCondition_t(recDrumGroup->checkedId()); + int das = dummyAudioSize->currentIndex(); MusEGlobal::config.dummyAudioBufSize = dummyAudioBufSizes[das]; MusEGlobal::config.dummyAudioSampleRate = dummyAudioRate->value(); @@ -461,6 +490,16 @@ void GlobalSettingsConfig::apply() MusEGlobal::muse->setHeartBeat(); // set guiRefresh MusEGlobal::midiSeq->msgSetRtc(); // set midi tick rate + if (onlyNewDrumBtn->isChecked()) + MusEGlobal::config.drumTrackPreference=MusEGlobal::ONLY_NEW; + else if (onlyOldDrumBtn->isChecked()) + MusEGlobal::config.drumTrackPreference=MusEGlobal::ONLY_OLD; + else if (preferOldDrumBtn->isChecked()) + MusEGlobal::config.drumTrackPreference=MusEGlobal::PREFER_OLD; + else if (preferNewDrumBtn->isChecked()) + MusEGlobal::config.drumTrackPreference=MusEGlobal::PREFER_NEW; + + applyMdiSettings(); MusEGlobal::muse->changeConfig(true); // save settings diff --git a/muse2/muse/widgets/genset.h b/muse2/muse/widgets/genset.h index b076a27f..53f5c2c1 100644 --- a/muse2/muse/widgets/genset.h +++ b/muse2/muse/widgets/genset.h @@ -62,6 +62,7 @@ class GlobalSettingsConfig : public QDialog, public Ui::GlobalSettingsDialogBase protected: void showEvent(QShowEvent*); QButtonGroup *startSongGroup; + QButtonGroup *recDrumGroup; std::list<MdiSettings*> mdisettings; public: diff --git a/muse2/muse/widgets/gensetbase.ui b/muse2/muse/widgets/gensetbase.ui index 124ee72a..aec753f1 100644 --- a/muse2/muse/widgets/gensetbase.ui +++ b/muse2/muse/widgets/gensetbase.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>556</width> - <height>527</height> + <height>552</height> </rect> </property> <property name="windowTitle"> @@ -1024,13 +1024,7 @@ Adjusts responsiveness of audio controls and <attribute name="title"> <string>Midi</string> </attribute> - <layout class="QVBoxLayout"> - <property name="spacing"> - <number>6</number> - </property> - <property name="margin"> - <number>11</number> - </property> + <layout class="QVBoxLayout" name="verticalLayout_7"> <item> <widget class="QGroupBox" name="GroupBox2"> <property name="title"> @@ -1208,22 +1202,59 @@ Adjusts responsiveness of audio controls and </item> </widget> </item> - <item row="3" column="1"> - <spacer name="verticalSpacer_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_3"> + <property name="title"> + <string>Record new style drum tracks</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QRadioButton" name="recordAllButton"> + <property name="text"> + <string>Record all instruments</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="dontRecHiddenButton"> + <property name="text"> + <string>Don't record hidden instruments</string> </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> + </widget> + </item> + <item> + <widget class="QRadioButton" name="dontRecMutedButton"> + <property name="text"> + <string>Don't record muted instruments</string> </property> - </spacer> + </widget> + </item> + <item> + <widget class="QRadioButton" name="dontRecBothButton"> + <property name="text"> + <string>Don't record hidden or muted instruments</string> + </property> + </widget> </item> </layout> </widget> </item> + <item> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>191</width> + <height>166</height> + </size> + </property> + </spacer> + </item> </layout> </widget> <widget class="QWidget" name="tab3"> @@ -1411,19 +1442,6 @@ left button behave like the middle button in such areas.</string> </property> </widget> </item> - <item row="9" column="0"> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> <item row="7" column="1"> <widget class="QCheckBox" name="addHiddenCheckBox"> <property name="text"> @@ -1455,6 +1473,56 @@ left button behave like the middle button in such areas.</string> </layout> </widget> </item> + <item> + <widget class="QGroupBox" name="groupBox_4"> + <property name="title"> + <string>Drum tracks</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QRadioButton" name="onlyOldDrumBtn"> + <property name="text"> + <string>Only offer old-style drumtracks</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QRadioButton" name="onlyNewDrumBtn"> + <property name="text"> + <string>Only offer new-style drumtracks</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QRadioButton" name="preferOldDrumBtn"> + <property name="text"> + <string>Prefer old-style drumtracks</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QRadioButton" name="preferNewDrumBtn"> + <property name="text"> + <string>Prefer new-style drumtracks</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> </layout> </widget> <widget class="QWidget" name="tab_2"> @@ -1513,8 +1581,8 @@ left button behave like the middle button in such areas.</string> <rect> <x>0</x> <y>0</y> - <width>512</width> - <height>378</height> + <width>486</width> + <height>375</height> </rect> </property> <layout class="QHBoxLayout" name="horizontalLayout_3"> diff --git a/muse2/muse/widgets/mtrackinfo.cpp b/muse2/muse/widgets/mtrackinfo.cpp index a01fbd5f..f9d0e5a9 100644 --- a/muse2/muse/widgets/mtrackinfo.cpp +++ b/muse2/muse/widgets/mtrackinfo.cpp @@ -226,6 +226,7 @@ void MidiTrackInfo::heartBeat() { case MusECore::Track::MIDI: case MusECore::Track::DRUM: + case MusECore::Track::NEW_DRUM: { MusECore::MidiTrack* track = (MusECore::MidiTrack*)selected; @@ -354,7 +355,7 @@ void MidiTrackInfo::heartBeat() else { MusECore::MidiInstrument* instr = mp->instrument(); - QString name = instr->getPatchName(outChannel, nprogram, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); + QString name = instr->getPatchName(outChannel, nprogram, MusEGlobal::song->mtype(), track->isDrumTrack()); if(name.isEmpty()) { const QString n("???"); @@ -400,7 +401,7 @@ void MidiTrackInfo::heartBeat() //else //{ MusECore::MidiInstrument* instr = mp->instrument(); - QString name = instr->getPatchName(outChannel, program, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); + QString name = instr->getPatchName(outChannel, program, MusEGlobal::song->mtype(), track->isDrumTrack()); if(iPatch->text() != name) iPatch->setText(name); @@ -577,8 +578,12 @@ void MidiTrackInfo::setLabelText() //pal.setColor(trackNameLabel->backgroundRole(), QColor(0, 160, 255)); // Med blue if(track->type() == MusECore::Track::DRUM) c = MusEGlobal::config.drumTrackLabelBg; - else + else if (track->type() == MusECore::Track::MIDI) c = MusEGlobal::config.midiTrackLabelBg; + else if (track->type() == MusECore::Track::NEW_DRUM) + c = MusEGlobal::config.newDrumTrackLabelBg; + else + printf("THIS SHOULD NEVER HAPPEN: track is not a MIDI track in MidiTrackInfo::setLabelText()!\n"); QLinearGradient gradient(trackNameLabel->geometry().topLeft(), trackNameLabel->geometry().bottomLeft()); //gradient.setColorAt(0, c.darker()); @@ -775,7 +780,7 @@ void MidiTrackInfo::iProgHBankChanged() MusEGlobal::audio->msgPlayMidiEvent(&ev); MusECore::MidiInstrument* instr = mp->instrument(); - iPatch->setText(instr->getPatchName(channel, program, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM)); + iPatch->setText(instr->getPatchName(channel, program, MusEGlobal::song->mtype(), track->isDrumTrack())); // updateTrackInfo(); } @@ -853,7 +858,7 @@ void MidiTrackInfo::iProgLBankChanged() MusEGlobal::audio->msgPlayMidiEvent(&ev); MusECore::MidiInstrument* instr = mp->instrument(); - iPatch->setText(instr->getPatchName(channel, program, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM)); + iPatch->setText(instr->getPatchName(channel, program, MusEGlobal::song->mtype(), track->isDrumTrack())); // updateTrackInfo(); } @@ -931,7 +936,7 @@ void MidiTrackInfo::iProgramChanged() MusEGlobal::audio->msgPlayMidiEvent(&ev); MusECore::MidiInstrument* instr = mp->instrument(); - iPatch->setText(instr->getPatchName(channel, program, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM)); + iPatch->setText(instr->getPatchName(channel, program, MusEGlobal::song->mtype(), track->isDrumTrack())); } // updateTrackInfo(); @@ -1099,8 +1104,8 @@ void MidiTrackInfo::instrPopup() //QMenu* pup = new QMenu; PopupMenu* pup = new PopupMenu(true); - instr->populatePatchPopup(pup, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); - //populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); + instr->populatePatchPopup(pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); + //populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); if(pup->actions().count() == 0) { @@ -1429,7 +1434,7 @@ void MidiTrackInfo::updateTrackInfo(int flags) else { MusECore::MidiInstrument* instr = mp->instrument(); - iPatch->setText(instr->getPatchName(outChannel, nprogram, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM)); + iPatch->setText(instr->getPatchName(outChannel, nprogram, MusEGlobal::song->mtype(), track->isDrumTrack())); } } else @@ -1445,7 +1450,7 @@ void MidiTrackInfo::updateTrackInfo(int flags) //else //{ MusECore::MidiInstrument* instr = mp->instrument(); - iPatch->setText(instr->getPatchName(outChannel, program, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM)); + iPatch->setText(instr->getPatchName(outChannel, program, MusEGlobal::song->mtype(), track->isDrumTrack())); int hb = ((program >> 16) & 0xff) + 1; if (hb == 0x100) diff --git a/muse2/muse/widgets/musewidgetsplug.cpp b/muse2/muse/widgets/musewidgetsplug.cpp index 8fc29d45..6cdc3812 100644 --- a/muse2/muse/widgets/musewidgetsplug.cpp +++ b/muse2/muse/widgets/musewidgetsplug.cpp @@ -131,6 +131,7 @@ MusEGlobal::GlobalConfigValues config = { QColor(0, 160, 255), // midiTrackLabelBg; // Med blue QColor(0, 160, 255), // drumTrackLabelBg; // Med blue + QColor(0, 160, 255), // newDrumTrackLabelBg; // Med blue Qt::magenta, // waveTrackLabelBg; Qt::green, // outputTrackLabelBg; Qt::red, // inputTrackLabelBg; @@ -140,6 +141,7 @@ MusEGlobal::GlobalConfigValues config = { QColor(220, 220, 220), // midiTrackBg; QColor(220, 220, 220), // drumTrackBg; + QColor(220, 220, 220), // newDrumTrackBg; QColor(220, 220, 220), // waveTrackBg; QColor(189, 220, 193), // outputTrackBg; QColor(189, 220, 193), // inputTrackBg; @@ -166,6 +168,7 @@ MusEGlobal::GlobalConfigValues config = { false, // midi export file 2 byte timesigs instead of 4 true, // optimize midi export file note offs true, // Split imported tracks into multiple parts. + true, // importMidiNewStyleDrum 1, // startMode QString(""), // start song path 384, // gui division @@ -177,13 +180,13 @@ MusEGlobal::GlobalConfigValues config = { QString("Mixer A"), QRect(0, 0, 300, 500), // Mixer1 true, true, true, true, - true, true, true, true + true, true, true, true, true }, { QString("Mixer B"), QRect(200, 200, 300, 500), // Mixer2 true, true, true, true, - true, true, true, true + true, true, true, true, true }, true, // TransportVisible; false, // BigTimeVisible; @@ -207,17 +210,18 @@ MusEGlobal::GlobalConfigValues config = { true, // showDidYouKnow false, // vstInPlace Enable VST in-place processing 44100, // Dummy audio preferred sample rate - 512 // Dummy audio buffer size + 512, // Dummy audio buffer size QString("./"), // projectBaseFolder true, // projectStoreInFolder true, // useProjectSaveDialog 64, // minControlProcessPeriod false, // popupsDefaultStayOpen false, // leftMouseButtonCanDecrease - false, // rangeMarkerWithoutMMBCheckBox + false, // rangeMarkerWithoutMMB + MusECore::DONT_REC_MUTED_OR_HIDDEN, true, // addHiddenTracks - true // unhideTracks - + true, // unhideTracks + MusEGlobal::PREFER_NEW // drumTrackPreference }; //--------------------------------------------------------- diff --git a/muse2/xpm/eye.xpm b/muse2/xpm/eye.xpm new file mode 100644 index 00000000..74e5bcc1 --- /dev/null +++ b/muse2/xpm/eye.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char * eye_xpm[] = { +"16 16 3 1", +" c None", +". c #000000", +"+ c #0000FD", +" ", +" ", +" ", +" .... ", +" ........ ", +" ... ... ", +" ... ++++ ... ", +"... ++++++ ...", +".. ++++++ ..", +"... ++++++ ...", +" ... ++++ ... ", +" ... ... ", +" ........ ", +" .... ", +" ", +" "}; diff --git a/muse2/xpm/eye_crossed.xpm b/muse2/xpm/eye_crossed.xpm new file mode 100644 index 00000000..65dca19c --- /dev/null +++ b/muse2/xpm/eye_crossed.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static const char * eye_crossed_xpm[] = { +"16 16 4 1", +" c None", +". c #E10E08", +"+ c #000000", +"@ c #0000FD", +" ", +" .. ", +" ....", +" ++++ .... ", +" ++++++.... ", +" +++ ....+ ", +" +++ @@....+++ ", +"+++ @@.... +++", +"++ @....@ ++", +"+++ ....@@ +++", +" +++....@@ +++ ", +" +.... +++ ", +" ....++++++ ", +" .... ++++ ", +" .. ", +" "}; diff --git a/muse2/xpm/eye_gray.xpm b/muse2/xpm/eye_gray.xpm new file mode 100644 index 00000000..8d5a7d9d --- /dev/null +++ b/muse2/xpm/eye_gray.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char * eye_gray_xpm[] = { +"16 16 3 1", +" c None", +". c #292929", +"+ c #535353", +" ", +" ", +" ", +" .... ", +" ........ ", +" ... ... ", +" ... ++++ ... ", +"... ++++++ ...", +".. ++++++ ..", +"... ++++++ ...", +" ... ++++ ... ", +" ... ... ", +" ........ ", +" .... ", +" ", +" "}; |