diff options
Diffstat (limited to 'muse2')
80 files changed, 5519 insertions, 639 deletions
diff --git a/muse2/ChangeLog b/muse2/ChangeLog index 1445633b..4b9646f4 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -1,4 +1,20 @@ 03.01.2012: + - ADDED NEW STYLE DRUM TRACKS: (flo93) + + multiple tracks can be displayed in one editor + their drum sound columns can be reordered, mixed up, hidden. + drumtracks can be grouped by channel, not at all, or maximally + each track owns its own drummap + added drummap-definitions to instrument files (gs and xg.idf) + drumtracks' drummap can be automatically set according to + the currently used patch/program/bank + new-style-drumtracks can ignore muted, hidden or both sounds when + recording + + KNOWN ISSUES: when having multiple drumeditors open, the mute-column + may not work, because another editor is overriding this. + this is not a bug. + - Global Cut: Fixed crashes with markers. Re-did marker section in structure.cpp:adjustGlobalLists(). (Tim) TODO: Still get tempo, key, and sig not found warnings. 02.01.2012: diff --git a/muse2/muse/CMakeLists.txt b/muse2/muse/CMakeLists.txt index 187bd41e..36645db4 100644 --- a/muse2/muse/CMakeLists.txt +++ b/muse2/muse/CMakeLists.txt @@ -65,6 +65,7 @@ QT4_WRAP_CPP ( muse_moc_headers plugin.h song.h transport.h + trackdrummapupdater.h value.h steprec.h ) @@ -132,6 +133,7 @@ file (GLOB core_source_files thread.cpp ticksynth.cpp track.cpp + trackdrummapupdater.cpp transport.cpp undo.cpp value.cpp diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp index 836fe6fb..21426979 100644 --- a/muse2/muse/app.cpp +++ b/muse2/muse/app.cpp @@ -81,6 +81,7 @@ #include "tools.h" #include "widgets/unusedwavefiles.h" #include "functions.h" +#include "trackdrummapupdater.h" namespace MusECore { extern void initMidiSynth(); @@ -346,6 +347,7 @@ MusE::MusE(int /*argc*/, char** /*argv*/) : QMainWindow() MusEGlobal::heartBeatTimer->setObjectName("timer"); connect(MusEGlobal::heartBeatTimer, SIGNAL(timeout()), MusEGlobal::song, SLOT(beat())); connect(this, SIGNAL(activeTopWinChanged(MusEGui::TopWin*)), SLOT(activeTopWinChangedSlot(MusEGui::TopWin*))); + new MusECore::TrackDrummapUpdater(); // no need for keeping the reference, the thing autoconnects on its own. #ifdef ENABLE_PYTHON //--------------------------------------------------- @@ -1880,6 +1882,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 0b450612..2eab50a5 100644 --- a/muse2/muse/arranger/arrangerview.cpp +++ b/muse2/muse/arranger/arrangerview.cpp @@ -148,9 +148,9 @@ ArrangerView::ArrangerView(QWidget* parent) editDeleteSelectedAction = new QAction(QIcon(*edit_track_delIcon), tr("Delete Selected Tracks"), this); editDuplicateSelTrackAction = new QAction(QIcon(*edit_track_addIcon), tr("Duplicate 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); @@ -649,16 +649,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) @@ -682,6 +683,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 5c81101c..5407c2ab 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 57232d42..897ae1c8 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]); @@ -399,7 +400,7 @@ bool PartCanvas::moveItem(MusECore::Undo& operations, CItem* item, const QPoint& dpart->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it // so we must decrement it first :/ // 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) { @@ -411,7 +412,7 @@ bool PartCanvas::moveItem(MusECore::Undo& operations, CItem* item, const QPoint& // so we must increment it first :/ 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); @@ -552,6 +553,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); @@ -692,6 +694,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); @@ -887,9 +890,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) @@ -1303,6 +1303,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; @@ -2354,7 +2355,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 5d88ede9..fe8b4731 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; @@ -712,6 +717,7 @@ 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: case MusECore::Track::AUDIO_SOFTSYNTH: { MusECore::MidiTrack* track = (MusECore::MidiTrack*)t; @@ -732,7 +738,7 @@ void TList::portsPopupMenu(MusECore::Track* t, int x, int y) QMenu* p = MusECore::midiPortsPopup(this, port); // 0, port); - if (t->type()==MusECore::Track::MIDI || t->type()==MusECore::Track::DRUM) //FINDMICHJETZT + if (t->isMidiTrack()) { // extend that menu a bit @@ -1013,7 +1019,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]; @@ -1218,9 +1224,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; } @@ -1246,7 +1250,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; } @@ -1562,9 +1566,28 @@ 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) + { + QAction* tmp; + 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); + tmp=p->addAction(tr("Reset track's drumlist")); + tmp->setData(1013); + tmp->setEnabled(!((MusECore::MidiTrack*)t)->drummap_tied_to_patch()); + tmp=p->addAction(tr("Reset track's drumlist-ordering")); + tmp->setData(1016); + tmp->setEnabled(!((MusECore::MidiTrack*)t)->drummap_ordering_tied_to_patch()); + 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); + // 1016 is occupied. + p->addSeparator(); + } + QMenu* pnew = new QMenu(p); pnew->setTitle(tr("Insert Track")); pnew->setIcon(QIcon(*edit_track_addIcon)); @@ -1573,23 +1596,62 @@ 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 instrument defaults?"), + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) == QMessageBox::Ok) + { + ((MusECore::MidiTrack*)t)->set_drummap_tied_to_patch(true); + MusEGlobal::song->update(SC_DRUMMAP); + } + break; + + case 1016: + if (QMessageBox::warning(this, tr("Drum map"), + tr("Reset the track's drum map ordering?"), + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) == QMessageBox::Ok) + { + ((MusECore::MidiTrack*)t)->set_drummap_ordering_tied_to_patch(true); + 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; @@ -1691,6 +1753,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 //--------------------------------------------------------- @@ -2021,13 +2196,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 // @@ -2061,11 +2237,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 // @@ -2123,6 +2299,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..ce96d6fe 100644 --- a/muse2/muse/helper.cpp +++ b/muse2/muse/helper.cpp @@ -116,6 +116,242 @@ bool any_event_selected(const set<Part*>& parts, bool in_range) return !get_events(parts, in_range ? 3 : 1).empty(); } +bool drummaps_almost_equal(const DrumMap* one, const DrumMap* two, int len) +{ + for (int i=0; i<len; i++) + if (!one[i].almost_equals(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; +} + +bool parse_range(const QString& str, int* from, int* to) +{ + int idx = str.indexOf("-"); + if (idx<0) // no "-" in str + { + bool ok; + int i = str.toInt(&ok); + if (!ok) + { + *from=-1; *to=-1; + return false; + } + else + { + *from=i; *to=i; + return true; + } + } + else // there is a "-" in str + { + QString str1=str.mid(0,idx); + QString str2=str.mid(idx+1); + + bool ok; + int i = str1.toInt(&ok); + if (!ok) + { + *from=-1; *to=-1; + return false; + } + else + { + *from=i; + + i = str2.toInt(&ok); + if (!ok) + { + *from=-1; *to=-1; + return false; + } + else + { + *to=i; + return true; + } + } + } +} + +void write_new_style_drummap(int level, Xml& xml, const char* tagname, + DrumMap* drummap, bool* drummap_hidden, bool full) +{ + xml.tag(level++, tagname); + + for (int i=0;i<128;i++) + { + DrumMap* dm = &drummap[i]; + const DrumMap* idm = &iNewDrumMap[i]; + + 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 && 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 (drummap_hidden && + (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, tagname); +} + +void read_new_style_drummap(Xml& xml, const char* tagname, + DrumMap* drummap, bool* drummap_hidden) +{ + 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 read_new_style_drummap()!\n"); + else + { + dm = &drummap[pitch]; + hidden = drummap_hidden ? &drummap_hidden[pitch] : NULL; + } + } + 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 read_new_style_drummap()!\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") + { + if (hidden) *hidden = xml.parseInt(); + } + else + xml.unknown("read_new_style_drummap"); + 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("read_new_style_drummap"); + break; + + case Xml::TagEnd: + if (tag == tagname) + return; + + default: + break; + } + } +} + } // namespace MusECore namespace MusEGui { @@ -189,7 +425,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 +436,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 +760,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..2a26c08e 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,33 @@ 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(const DrumMap* one, const DrumMap* two, int drummap_size=128); + +// drummap_hidden may be NULL. +void write_new_style_drummap(int level, Xml& xml, const char* tagname, + DrumMap* drummap, bool* drummap_hidden=NULL, bool full=false); +void read_new_style_drummap(Xml& xml, const char* tagname, + DrumMap* drummap, bool* drummap_hidden=NULL); + + +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); + +bool parse_range(const QString& str, int* from, int* to); // returns true if successful, false on error + } 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/editinstrument.cpp b/muse2/muse/instruments/editinstrument.cpp index b90b872e..ac3ec68f 100644 --- a/muse2/muse/instruments/editinstrument.cpp +++ b/muse2/muse/instruments/editinstrument.cpp @@ -32,6 +32,9 @@ #include <QMessageBox> #include <QLineEdit> #include <QWhatsThis> +#include <QStringListModel> +#include <QScrollBar> +#include <list> #include "editinstrument.h" #include "minstrument.h" @@ -42,10 +45,14 @@ #include "gconfig.h" #include "icons.h" +#include "dlist.h" +#include "drummap.h" +#include "header.h" + namespace MusEGui { enum { - COL_NAME = 0, COL_TYPE, + COL_CNAME = 0, COL_TYPE, COL_HNUM, COL_LNUM, COL_MIN, COL_MAX, COL_DEF }; @@ -72,10 +79,10 @@ EditInstrument::EditInstrument(QWidget* parent, Qt::WFlags fl) // populate instrument list // Populate common controller list. for(int i = 0; i < 128; ++i) - { - QListWidgetItem *lci = new QListWidgetItem(MusECore::midiCtrlName(i)); - listController->addItem(lci); - } + { + QListWidgetItem *lci = new QListWidgetItem(MusECore::midiCtrlName(i)); + listController->addItem(lci); + } oldMidiInstrument = 0; oldPatchItem = 0; for (MusECore::iMidiInstrument i = MusECore::midiInstruments.begin(); i != MusECore::midiInstruments.end(); ++i) { @@ -105,8 +112,66 @@ EditInstrument::EditInstrument(QWidget* parent, Qt::WFlags fl) // workingInstrument.assign( *wip ); + dlist_header = new Header(dlistContainer, "header"); + dlist_header->setFixedHeight(31); + dlist_header->setColumnLabel(tr("Name"), COL_NAME, 120); + dlist_header->setColumnLabel(tr("Vol"), COL_VOLUME); + dlist_header->setColumnLabel(tr("Quant"), COL_QUANT, 30); + dlist_header->setColumnLabel(tr("E-Note"), COL_INPUTTRIGGER, 50); + dlist_header->setColumnLabel(tr("Len"), COL_NOTELENGTH); + dlist_header->setColumnLabel(tr("A-Note"), COL_NOTE, 50); + dlist_header->setColumnLabel(tr("LV1"), COL_LEVEL1); + dlist_header->setColumnLabel(tr("LV2"), COL_LEVEL2); + dlist_header->setColumnLabel(tr("LV3"), COL_LEVEL3); + dlist_header->setColumnLabel(tr("LV4"), COL_LEVEL4); + dlist_header->hideSection(COL_OUTPORT); + dlist_header->hideSection(COL_OUTCHANNEL); + dlist_header->hideSection(COL_HIDE); + dlist_header->hideSection(COL_MUTE); + dlist_header->hide(); + + + connect(patchFromBox, SIGNAL(valueChanged(int)), this, SLOT(patchCollectionSpinboxChanged(int))); + connect(patchToBox, SIGNAL(valueChanged(int)), this, SLOT(patchCollectionSpinboxChanged(int))); + connect(lbankFromBox, SIGNAL(valueChanged(int)), this, SLOT(patchCollectionSpinboxChanged(int))); + connect(lbankToBox, SIGNAL(valueChanged(int)), this, SLOT(patchCollectionSpinboxChanged(int))); + connect(hbankFromBox, SIGNAL(valueChanged(int)), this, SLOT(patchCollectionSpinboxChanged(int))); + connect(hbankToBox, SIGNAL(valueChanged(int)), this, SLOT(patchCollectionSpinboxChanged(int))); + connect(patchCheckbox, SIGNAL(toggled(bool)), this, SLOT(patchCollectionCheckboxChanged(bool))); + connect(lbankCheckbox, SIGNAL(toggled(bool)), this, SLOT(patchCollectionCheckboxChanged(bool))); + connect(hbankCheckbox, SIGNAL(toggled(bool)), this, SLOT(patchCollectionCheckboxChanged(bool))); + + connect(addCollBtn, SIGNAL(clicked()), this, SLOT(addPatchCollection())); + connect(rmCollBtn, SIGNAL(clicked()), this, SLOT(delPatchCollection())); + connect(copyCollBtn, SIGNAL(clicked()), this, SLOT(copyPatchCollection())); + connect(collUpBtn, SIGNAL(clicked()), this, SLOT(patchCollectionUp())); + connect(collDownBtn, SIGNAL(clicked()), this, SLOT(patchCollectionDown())); + + connect(patchCollections, SIGNAL(activated(const QModelIndex&)), this, SLOT(patchActivated(const QModelIndex&))); + connect(patchCollections, SIGNAL(clicked (const QModelIndex&)), this, SLOT(patchActivated(const QModelIndex&))); + + patch_coll_model=new QStringListModel(); + patchCollections->setModel(patch_coll_model); + patchCollections->setEditTriggers(QAbstractItemView::NoEditTriggers); + connect(instrumentList, SIGNAL(itemSelectionChanged()), SLOT(instrumentChanged())); connect(patchView, SIGNAL(itemSelectionChanged()), SLOT(patchChanged())); + + dlist_vscroll = new QScrollBar(Qt::Vertical, this); + dlist_vscroll->setMaximum(128*TH); + dlist_vscroll->hide(); + + dlist_grid = new QGridLayout(dlistContainer); + dlist_grid->setContentsMargins(0, 0, 0, 0); + dlist_grid->setSpacing(0); + dlist_grid->setRowStretch(1, 100); + dlist_grid->setColumnStretch(0, 100); + dlist_grid->addWidget(dlist_header, 0, 0); + dlist_grid->addWidget(dlist_vscroll, 1,1); + + dlist=NULL; + + //instrumentChanged(); changeInstrument(); @@ -151,6 +216,306 @@ EditInstrument::EditInstrument(QWidget* parent, Qt::WFlags fl) //connect(newSysex, SIGNAL(clicked()), SLOT(newSysexClicked())); } + +void EditInstrument::patchCollectionSpinboxChanged(int) +{ + if (patchFromBox->value() > patchToBox->value()) + patchToBox->setValue(patchFromBox->value()); + + if (lbankFromBox->value() > lbankToBox->value()) + lbankToBox->setValue(lbankFromBox->value()); + + if (hbankFromBox->value() > hbankToBox->value()) + hbankToBox->setValue(hbankFromBox->value()); + + storePatchCollection(); +} + +void EditInstrument::patchCollectionCheckboxChanged(bool) +{ + storePatchCollection(); +} + +void EditInstrument::storePatchCollection() +{ + using MusECore::patch_drummap_mapping_t; + + int idx=patchCollections->currentIndex().row(); + std::list<patch_drummap_mapping_t>* pdm = workingInstrument.get_patch_drummap_mapping(); + if (idx>=0 && (unsigned)idx<pdm->size()) + { + std::list<patch_drummap_mapping_t>::iterator it=pdm->begin(); + advance(it,idx); + + if (patchCheckbox->isChecked()) + { + it->affected_patches.first_program=patchFromBox->value()-1; + it->affected_patches.last_program=patchToBox->value()-1; + } + else + { + it->affected_patches.first_program=0; + it->affected_patches.last_program=127; + } + + if (lbankCheckbox->isChecked()) + { + it->affected_patches.first_lbank=lbankFromBox->value()-1; + it->affected_patches.last_lbank=lbankToBox->value()-1; + } + else + { + it->affected_patches.first_lbank=0; + it->affected_patches.last_lbank=127; + } + + if (hbankCheckbox->isChecked()) + { + it->affected_patches.first_hbank=hbankFromBox->value()-1; + it->affected_patches.last_hbank=hbankToBox->value()-1; + } + else + { + it->affected_patches.first_hbank=0; + it->affected_patches.last_hbank=127; + } + + workingInstrument.setDirty(true); + repopulatePatchCollections(); + } +} + +void EditInstrument::fetchPatchCollection() +{ + using MusECore::patch_drummap_mapping_t; + + int idx=patchCollections->currentIndex().row(); + std::list<patch_drummap_mapping_t>* pdm = workingInstrument.get_patch_drummap_mapping(); + if (idx>=0 && (unsigned)idx<pdm->size()) + { + std::list<patch_drummap_mapping_t>::iterator it=pdm->begin(); + advance(it,idx); + + patchFromBox->blockSignals(true); + patchToBox->blockSignals(true); + lbankFromBox->blockSignals(true); + lbankToBox->blockSignals(true); + hbankFromBox->blockSignals(true); + hbankToBox->blockSignals(true); + + patchFromBox->setValue(it->affected_patches.first_program+1); + patchToBox->setValue(it->affected_patches.last_program+1); + + lbankFromBox->setValue(it->affected_patches.first_lbank+1); + lbankToBox->setValue(it->affected_patches.last_lbank+1); + + hbankFromBox->setValue(it->affected_patches.first_hbank+1); + hbankToBox->setValue(it->affected_patches.last_hbank+1); + + patchFromBox->blockSignals(false); + patchToBox->blockSignals(false); + lbankFromBox->blockSignals(false); + lbankToBox->blockSignals(false); + hbankFromBox->blockSignals(false); + hbankToBox->blockSignals(false); + + + patchCheckbox->setChecked(it->affected_patches.first_program>0 || it->affected_patches.last_program < 127); + lbankCheckbox->setChecked(it->affected_patches.first_lbank>0 || it->affected_patches.last_lbank < 127); + hbankCheckbox->setChecked(it->affected_patches.first_hbank>0 || it->affected_patches.last_hbank < 127); + } +} + +void EditInstrument::patchActivated(const QModelIndex& idx) +{ + using MusECore::patch_drummap_mapping_t; + + if (idx.row()>=0) + { + using MusECore::DrumMap; + + std::list<patch_drummap_mapping_t>* tmp = workingInstrument.get_patch_drummap_mapping(); + std::list<patch_drummap_mapping_t>::iterator it=tmp->begin(); + if ((unsigned)idx.row()>=tmp->size()) + printf("THIS SHOULD NEVER HAPPEN: idx.row()>=tmp->size() in EditInstrument::patchActivated()\n"); + + advance(it, idx.row()); + DrumMap* dm=it->drummap; + + + if (dlist) + { + dlist->hide(); + delete dlist; + dlist=NULL; + } + + dlist=new DList(dlist_header,dlistContainer,1,dm); + + dlist->setYPos(dlist_vscroll->value()); + + connect(dlist_vscroll, SIGNAL(valueChanged(int)), dlist, SLOT(setYPos(int))); + dlist_grid->addWidget(dlist, 1, 0); + + + dlist_header->show(); + dlist->show(); + dlist_vscroll->show(); + + collUpBtn->setEnabled(idx.row()>0); + collDownBtn->setEnabled(idx.row()<patch_coll_model->rowCount()-1); + rmCollBtn->setEnabled(true); + copyCollBtn->setEnabled(true); + patchCollectionContainer->setEnabled(true); + + fetchPatchCollection(); + } +} + +void EditInstrument::addPatchCollection() +{ + using MusECore::patch_drummap_mapping_t; + + int idx=patchCollections->currentIndex().row(); + + std::list<patch_drummap_mapping_t>* tmp = workingInstrument.get_patch_drummap_mapping(); + std::list<patch_drummap_mapping_t>::iterator it=tmp->begin(); + advance(it,idx+1); + tmp->insert(it,patch_drummap_mapping_t()); + + repopulatePatchCollections(); + patchCollections->setCurrentIndex(patch_coll_model->index(idx+1)); + patchActivated(patchCollections->currentIndex()); + + workingInstrument.setDirty(true); +} + +void EditInstrument::delPatchCollection() +{ + using MusECore::patch_drummap_mapping_t; + + int idx=patchCollections->currentIndex().row(); + if (idx>=0) + { + if (dlist) + { + dlist->hide(); + delete dlist; + dlist=NULL; + } + + dlist_header->hide(); + dlist_vscroll->hide(); + + rmCollBtn->setEnabled(false); + copyCollBtn->setEnabled(false); + patchCollectionContainer->setEnabled(false); + collUpBtn->setEnabled(false); + collDownBtn->setEnabled(false); + + std::list<patch_drummap_mapping_t>* tmp = workingInstrument.get_patch_drummap_mapping(); + std::list<patch_drummap_mapping_t>::iterator it=tmp->begin(); + advance(it,idx); + tmp->erase(it); + + repopulatePatchCollections(); + + patchActivated(patchCollections->currentIndex()); + workingInstrument.setDirty(true); + } +} + +void EditInstrument::copyPatchCollection() +{ + using MusECore::patch_drummap_mapping_t; + + int idx=patchCollections->currentIndex().row(); + + std::list<patch_drummap_mapping_t>* tmp = workingInstrument.get_patch_drummap_mapping(); + std::list<patch_drummap_mapping_t>::iterator it=tmp->begin(); + advance(it,idx); + patch_drummap_mapping_t tmp2(*it); + it++; + tmp->insert(it,tmp2); + + patch_coll_model->insertRow(idx+1); + patch_coll_model->setData(patch_coll_model->index(idx+1), patch_coll_model->index(idx).data()); + patchCollections->setCurrentIndex(patch_coll_model->index(idx+1)); + patchActivated(patchCollections->currentIndex()); + workingInstrument.setDirty(true); +} + +void EditInstrument::patchCollectionUp() +{ + using MusECore::patch_drummap_mapping_t; + + std::list<patch_drummap_mapping_t>* pdm = workingInstrument.get_patch_drummap_mapping(); + int idx=patchCollections->currentIndex().row(); + + if (idx>=1) + { + std::list<patch_drummap_mapping_t>::iterator it=pdm->begin(); + advance(it,idx-1); + std::list<patch_drummap_mapping_t>::iterator it2=it; + it2++; + + //it2 is the element to move, it is the element to put before. + + pdm->insert(it,*it2); + pdm->erase(it2); + + repopulatePatchCollections(); + + patchCollections->setCurrentIndex(patch_coll_model->index(idx-1)); + patchActivated(patchCollections->currentIndex()); + + workingInstrument.setDirty(true); + } +} + +void EditInstrument::patchCollectionDown() +{ + using MusECore::patch_drummap_mapping_t; + + std::list<patch_drummap_mapping_t>* pdm = workingInstrument.get_patch_drummap_mapping(); + int idx=patchCollections->currentIndex().row(); + + if ((unsigned)idx<pdm->size()-1) + { + std::list<patch_drummap_mapping_t>::iterator it=pdm->begin(); + advance(it,idx); + std::list<patch_drummap_mapping_t>::iterator it2=it; + it2++; it2++; + + //it is the element to move, it2 is the element to put before (might be end()) + + pdm->insert(it2,*it); + pdm->erase(it); + + repopulatePatchCollections(); + + patchCollections->setCurrentIndex(patch_coll_model->index(idx+1)); + patchActivated(patchCollections->currentIndex()); + + workingInstrument.setDirty(true); + } +} + +void EditInstrument::repopulatePatchCollections() +{ + using MusECore::patch_drummap_mapping_t; + + int idx=patchCollections->currentIndex().row(); + QStringList strlist; + + std::list<patch_drummap_mapping_t>* pdm = workingInstrument.get_patch_drummap_mapping(); + for (std::list<patch_drummap_mapping_t>::iterator it=pdm->begin(); it!=pdm->end(); it++) + strlist << it->affected_patches.to_string(); + + patch_coll_model->setStringList(strlist); + patchCollections->setCurrentIndex(patch_coll_model->index(idx)); +} + //--------------------------------------------------------- // helpWhatsThis //--------------------------------------------------------- @@ -1014,6 +1379,25 @@ void EditInstrument::changeInstrument() */ + + repopulatePatchCollections(); + if (dlist) + { + dlist->hide(); + delete dlist; + dlist=NULL; + } + + dlist_header->hide(); + dlist_vscroll->hide(); + + rmCollBtn->setEnabled(false); + copyCollBtn->setEnabled(false); + patchCollectionContainer->setEnabled(false); + collUpBtn->setEnabled(false); + collDownBtn->setEnabled(false); + + } //--------------------------------------------------------- @@ -1801,9 +2185,9 @@ void EditInstrument::ctrlNameReturn() } c->setName(ctrlName->text()); - item->setText(COL_NAME, ctrlName->text()); + item->setText(COL_CNAME, ctrlName->text()); //c->setName(s); - //item->setText(COL_NAME, s); + //item->setText(COL_CNAME, s); workingInstrument.setDirty(true); } diff --git a/muse2/muse/instruments/editinstrument.h b/muse2/muse/instruments/editinstrument.h index ba53aae1..ab5edf39 100644 --- a/muse2/muse/instruments/editinstrument.h +++ b/muse2/muse/instruments/editinstrument.h @@ -31,9 +31,14 @@ class QDialog; class QMenu; class QCloseEvent; +class QGridLayout; +class QStringListModel; namespace MusEGui { +class Header; +class DList; + //--------------------------------------------------------- // EditInstrument //--------------------------------------------------------- @@ -44,6 +49,15 @@ class EditInstrument : public QMainWindow, public Ui::EditInstrumentBase { MusECore::MidiInstrument workingInstrument; QListWidgetItem* oldMidiInstrument; QTreeWidgetItem* oldPatchItem; + + Header* dlist_header; + DList* dlist; + QScrollBar* dlist_vscroll; + QGridLayout* dlist_grid; + QStringListModel* patch_coll_model; + + + void closeEvent(QCloseEvent*); int checkDirty(MusECore::MidiInstrument*, bool isClose = false); bool fileSave(MusECore::MidiInstrument*, const QString&); @@ -61,7 +75,6 @@ class EditInstrument : public QMainWindow, public Ui::EditInstrumentBase { void setDefaultPatchControls(int); QString getPatchName(int); void deleteInstrument(QListWidgetItem*); - ///QMenu* patchpopup; private slots: virtual void fileNew(); @@ -99,6 +112,18 @@ class EditInstrument : public QMainWindow, public Ui::EditInstrumentBase { //void newSysexClicked(); void ctrlNullParamHChanged(int); void ctrlNullParamLChanged(int); + + void patchCollectionSpinboxChanged(int); + void patchCollectionCheckboxChanged(bool); + void patchActivated(const QModelIndex&); + void addPatchCollection(); + void delPatchCollection(); + void copyPatchCollection(); + void patchCollectionUp(); + void patchCollectionDown(); + void repopulatePatchCollections(); + void storePatchCollection(); + void fetchPatchCollection(); public: EditInstrument(QWidget* parent = 0, Qt::WFlags fl = Qt::Window); diff --git a/muse2/muse/instruments/editinstrumentbase.ui b/muse2/muse/instruments/editinstrumentbase.ui index 3337cfc0..5295abb2 100644 --- a/muse2/muse/instruments/editinstrumentbase.ui +++ b/muse2/muse/instruments/editinstrumentbase.ui @@ -1370,6 +1370,404 @@ Typically, set to 127/127, or an unused </item> </layout> </widget> + <widget class="QWidget" name="drumTab"> + <attribute name="title"> + <string>Drummaps</string> + </attribute> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Patch Collections:</string> + </property> + </widget> + </item> + <item> + <widget class="QListView" name="patchCollections"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="addCollBtn"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Add</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="copyCollBtn"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Copy</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="rmCollBtn"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Remove</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="collUpBtn"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Up</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="collDownBtn"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Down</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <widget class="QWidget" name="patchCollectionContainer" native="true"> + <property name="enabled"> + <bool>false</bool> + </property> + <layout class="QGridLayout" name="gridLayout_"> + <property name="margin"> + <number>0</number> + </property> + <item row="0" column="0"> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QCheckBox" name="patchCheckbox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Patch:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="label_5"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>from</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QSpinBox" name="patchFromBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>128</number> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLabel" name="label_8"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>to</string> + </property> + </widget> + </item> + <item row="0" column="4"> + <widget class="QSpinBox" name="patchToBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>128</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="hbankCheckbox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Bank Hi:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="label_6"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>from</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QSpinBox" name="hbankFromBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>128</number> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QLabel" name="label_9"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>to</string> + </property> + </widget> + </item> + <item row="1" column="4"> + <widget class="QSpinBox" name="hbankToBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>128</number> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="lbankCheckbox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Bank Lo:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="label_7"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>from</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QSpinBox" name="lbankFromBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>128</number> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QLabel" name="label_10"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>to</string> + </property> + </widget> + </item> + <item row="2" column="4"> + <widget class="QSpinBox" name="lbankToBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>128</number> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QWidget" name="dlistContainer" native="true"/> + </item> + </layout> + </item> + </layout> + </widget> </widget> </widget> </item> @@ -1396,7 +1794,7 @@ Typically, set to 127/127, or an unused <x>0</x> <y>0</y> <width>802</width> - <height>21</height> + <height>25</height> </rect> </property> <property name="defaultUp"> @@ -1645,5 +2043,197 @@ Typically, set to 127/127, or an unused </hint> </hints> </connection> + <connection> + <sender>patchCheckbox</sender> + <signal>toggled(bool)</signal> + <receiver>label_5</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>214</x> + <y>411</y> + </hint> + <hint type="destinationlabel"> + <x>289</x> + <y>412</y> + </hint> + </hints> + </connection> + <connection> + <sender>patchCheckbox</sender> + <signal>toggled(bool)</signal> + <receiver>patchFromBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>214</x> + <y>411</y> + </hint> + <hint type="destinationlabel"> + <x>343</x> + <y>412</y> + </hint> + </hints> + </connection> + <connection> + <sender>patchCheckbox</sender> + <signal>toggled(bool)</signal> + <receiver>label_8</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>214</x> + <y>411</y> + </hint> + <hint type="destinationlabel"> + <x>390</x> + <y>412</y> + </hint> + </hints> + </connection> + <connection> + <sender>patchCheckbox</sender> + <signal>toggled(bool)</signal> + <receiver>patchToBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>214</x> + <y>411</y> + </hint> + <hint type="destinationlabel"> + <x>436</x> + <y>412</y> + </hint> + </hints> + </connection> + <connection> + <sender>lbankCheckbox</sender> + <signal>toggled(bool)</signal> + <receiver>lbankFromBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>221</x> + <y>469</y> + </hint> + <hint type="destinationlabel"> + <x>343</x> + <y>470</y> + </hint> + </hints> + </connection> + <connection> + <sender>lbankCheckbox</sender> + <signal>toggled(bool)</signal> + <receiver>lbankToBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>221</x> + <y>469</y> + </hint> + <hint type="destinationlabel"> + <x>436</x> + <y>470</y> + </hint> + </hints> + </connection> + <connection> + <sender>lbankCheckbox</sender> + <signal>toggled(bool)</signal> + <receiver>label_7</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>221</x> + <y>469</y> + </hint> + <hint type="destinationlabel"> + <x>289</x> + <y>470</y> + </hint> + </hints> + </connection> + <connection> + <sender>lbankCheckbox</sender> + <signal>toggled(bool)</signal> + <receiver>label_10</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>221</x> + <y>469</y> + </hint> + <hint type="destinationlabel"> + <x>390</x> + <y>470</y> + </hint> + </hints> + </connection> + <connection> + <sender>hbankCheckbox</sender> + <signal>toggled(bool)</signal> + <receiver>hbankFromBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>220</x> + <y>440</y> + </hint> + <hint type="destinationlabel"> + <x>343</x> + <y>441</y> + </hint> + </hints> + </connection> + <connection> + <sender>hbankCheckbox</sender> + <signal>toggled(bool)</signal> + <receiver>hbankToBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>220</x> + <y>440</y> + </hint> + <hint type="destinationlabel"> + <x>436</x> + <y>441</y> + </hint> + </hints> + </connection> + <connection> + <sender>hbankCheckbox</sender> + <signal>toggled(bool)</signal> + <receiver>label_6</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>220</x> + <y>440</y> + </hint> + <hint type="destinationlabel"> + <x>289</x> + <y>441</y> + </hint> + </hints> + </connection> + <connection> + <sender>hbankCheckbox</sender> + <signal>toggled(bool)</signal> + <receiver>label_9</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>220</x> + <y>440</y> + </hint> + <hint type="destinationlabel"> + <x>390</x> + <y>441</y> + </hint> + </hints> + </connection> </connections> </ui> diff --git a/muse2/muse/instruments/minstrument.cpp b/muse2/muse/instruments/minstrument.cpp index 22ed3737..1349c9c9 100644 --- a/muse2/muse/instruments/minstrument.cpp +++ b/muse2/muse/instruments/minstrument.cpp @@ -41,6 +41,8 @@ #include "midictrl.h" #include "gconfig.h" #include "popupmenu.h" +#include "drummap.h" +#include "helper.h" namespace MusECore { @@ -364,6 +366,7 @@ void MidiInstrument::init() MidiController* prog = new MidiController("Program", CTRL_PROGRAM, 0, 0xffffff, 0); _controller->add(prog); _dirty = false; + } MidiInstrument::MidiInstrument() @@ -408,8 +411,12 @@ MidiInstrument::~MidiInstrument() if (_initScript) delete _initScript; + + patch_drummap_mapping.clear(); } + + /* //--------------------------------------------------------- // uniqueCopy @@ -515,7 +522,11 @@ MidiInstrument& MidiInstrument::assign(const MidiInstrument& ins) _name = ins._name; _filePath = ins._filePath; - + + patch_drummap_mapping=ins.patch_drummap_mapping; + + + // Hmm, dirty, yes? But init sets it to false... //_dirty = ins._dirty; //_dirty = false; @@ -733,6 +744,160 @@ void MidiInstrument::readMidiState(Xml& xml) } } +void MidiInstrument::readDrummaps(Xml& xml) +{ + patch_drummap_mapping.clear(); + + for (;;) + { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) + { + case Xml::Error: + case Xml::End: + return; + + case Xml::TagStart: + if (tag == "entry") + patch_drummap_mapping.push_back(readDrummapsEntry(xml)); + else + xml.unknown("MidiInstrument::readDrummaps"); + break; + + case Xml::TagEnd: + if (tag == "Drummaps") + return; + + default: + break; + } + } + printf("ERROR: THIS CANNOT HAPPEN: exited infinite loop in MidiInstrument::readDrummaps()!\n" + " not returning anything. expect undefined behaviour or even crashes.\n"); +} + +patch_drummap_mapping_t MidiInstrument::readDrummapsEntry(Xml& xml) +{ + using std::list; + + patch_collection_t collection; + DrumMap* drummap=new DrumMap[128]; + for (int i=0;i<128;i++) + drummap[i]=iNewDrumMap[i]; + + for (;;) + { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) + { + case Xml::Error: + case Xml::End: + return patch_drummap_mapping_t(collection, drummap); + + case Xml::TagStart: + if (tag == "patch_collection") + collection=readDrummapsEntryPatchCollection(xml); + else if (tag == "drummap") + read_new_style_drummap(xml, "drummap", drummap); + else + xml.unknown("MidiInstrument::readDrummapsEntry"); + break; + + case Xml::TagEnd: + if (tag == "entry") + return patch_drummap_mapping_t(collection, drummap); + + default: + break; + } + } + printf("ERROR: THIS CANNOT HAPPEN: exited infinite loop in MidiInstrument::readDrummapsEntry()!\n" + " not returning anything. expect undefined behaviour or even crashes.\n"); + return patch_drummap_mapping_t(); +} + +patch_collection_t MidiInstrument::readDrummapsEntryPatchCollection(Xml& xml) +{ + int first_prog=0, last_prog=256; // this means: + int first_lbank=0, last_lbank=256; // "does not matter" + int first_hbank=0, last_hbank=256; + + for (;;) + { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) + { + case Xml::Error: + case Xml::End: + return patch_collection_t(-1,-1,-1,-1,-1,-1); // an invalid collection + + case Xml::TagStart: + xml.unknown("MidiInstrument::readDrummapsEntryPatchCollection"); + break; + + case Xml::Attribut: + if (tag == "prog") + parse_range(xml.s2(), &first_prog, &last_prog); + else if (tag == "lbank") + parse_range(xml.s2(), &first_lbank, &last_lbank); + else if (tag == "hbank") + parse_range(xml.s2(), &first_hbank, &last_hbank); + break; + + case Xml::TagEnd: + if (tag == "patch_collection") + return patch_collection_t(first_prog, last_prog, first_lbank, last_lbank, first_hbank, last_hbank); + + default: + break; + } + } + + printf("ERROR: THIS CANNOT HAPPEN: exited infinite loop in MidiInstrument::readDrummapsEntryPatchCollection()!\n" + " not returning anything. expect undefined behaviour or even crashes.\n"); +} + +void MidiInstrument::writeDrummaps(int level, Xml& xml) const +{ + xml.tag(level++, "Drummaps"); + + for (std::list<patch_drummap_mapping_t>::const_iterator it=patch_drummap_mapping.begin(); + it!=patch_drummap_mapping.end(); it++) + { + xml.tag(level++, "entry"); + + const patch_collection_t* ap = &it->affected_patches; + QString tmp="<patch_collection "; + if (ap->first_program==ap->last_program) + tmp+="prog=\""+QString::number(ap->first_program)+"\" "; + else if (! (ap->first_program==0 && ap->last_program>=127)) + tmp+="prog=\""+QString::number(ap->first_program)+"-"+QString::number(ap->last_program)+"\" "; + + if (ap->first_lbank==ap->last_lbank) + tmp+="lbank=\""+QString::number(ap->first_lbank)+"\" "; + else if (! (ap->first_lbank==0 && ap->last_lbank>=127)) + tmp+="lbank=\""+QString::number(ap->first_lbank)+"-"+QString::number(ap->last_lbank)+"\" "; + + if (ap->first_hbank==ap->last_hbank) + tmp+="hbank=\""+QString::number(ap->first_hbank)+"\" "; + else if (! (ap->first_hbank==0 && ap->last_hbank>=127)) + tmp+="hbank=\""+QString::number(ap->first_hbank)+"-"+QString::number(ap->last_hbank)+"\" "; + + tmp+="/>\n"; + + xml.nput(level, tmp.toAscii().data()); + + write_new_style_drummap(level, xml, "drummap", it->drummap); + + xml.etag(--level, "entry"); + } + + xml.etag(--level, "Drummaps"); +} + //--------------------------------------------------------- // read //--------------------------------------------------------- @@ -785,6 +950,9 @@ void MidiInstrument::read(Xml& xml) _controller->add(mc); } + else if (tag == "Drummaps") { + readDrummaps(xml); + } else if (tag == "Init") readEventList(xml, _midiInit, "Init"); else if (tag == "Reset") @@ -794,7 +962,7 @@ void MidiInstrument::read(Xml& xml) else if (tag == "InitScript") { if (_initScript) delete _initScript; - QByteArray ba = xml.parse1().toLatin1(); + QByteArray ba = xml.parse1().toLatin1(); const char* istr = ba.constData(); int len = strlen(istr) +1; if (len > 1) { @@ -872,6 +1040,9 @@ void MidiInstrument::write(int level, Xml& xml) //(*ic)->write(xml); ic->second->write(level, xml); //xml.etag("MidiInstrument"); + + writeDrummaps(level, xml); + level--; xml.etag(level, "MidiInstrument"); //xml.etag("muse"); @@ -996,71 +1167,104 @@ void MidiInstrument::populatePatchPopup(MusEGui::PopupMenu* menu, int chan, MTyp } } -} // namespace MusECore + } -/* -namespace MusEGui { +const DrumMap* MidiInstrument::drummap_for_patch(int patch) const +{ + using std::list; + + int program = (patch & 0x0000FF); + int lbank = (patch & 0x00FF00) >> 8; + int hbank = (patch & 0xFF0000) >> 16; + + for (list<patch_drummap_mapping_t>::const_iterator it=patch_drummap_mapping.begin(); + it!=patch_drummap_mapping.end(); it++) + { + const patch_collection_t* ap = &it->affected_patches; + // if the entry matches our patch + if ( (program >= ap->first_program && program <= ap->last_program) && + (hbank >= ap->first_hbank && hbank <= ap->last_hbank) && + (lbank >= ap->first_lbank && lbank <= ap->last_lbank) ) + { + return it->drummap; + } + } + + // if nothing was found + return iNewDrumMap; +} -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); - } - } - } - } -*/ +patch_drummap_mapping_t::patch_drummap_mapping_t() +{ + drummap=new DrumMap[128]; + for (int i=0;i<128;i++) + drummap[i]=iNewDrumMap[i]; +} + +patch_drummap_mapping_t::patch_drummap_mapping_t(const patch_drummap_mapping_t& that) +{ + drummap=new DrumMap[128]; + for (int i=0;i<128;i++) + drummap[i]=that.drummap[i]; + + affected_patches=that.affected_patches; +} + +patch_drummap_mapping_t& patch_drummap_mapping_t::operator=(const patch_drummap_mapping_t& that) +{ + if (drummap) + delete [] drummap; + + drummap=new DrumMap[128]; + for (int i=0;i<128;i++) + drummap[i]=that.drummap[i]; + + affected_patches=that.affected_patches; + + return *this; +} -} // namespace MusEGui +patch_drummap_mapping_t::~patch_drummap_mapping_t() +{ + delete [] drummap; +} + +QString patch_collection_t::to_string() +{ + QString tmp; + + if (first_program==0 && last_program>=127 && + first_lbank==0 && last_lbank>=127 && + first_hbank==0 && last_hbank>=127) + tmp="default"; + else + { + tmp+="prog: "; + if (first_program==last_program) + tmp+=QString::number(first_program+1); + else if (! (first_program==0 && last_program>=127)) + tmp+=QString::number(first_program+1)+"-"+QString::number(last_program+1); + else + tmp+="*"; + + tmp+=" bank="; + if (first_lbank==last_lbank) + tmp+=QString::number(first_lbank+1); + else if (! (first_lbank==0 && last_lbank>=127)) + tmp+=QString::number(first_lbank+1)+"-"+QString::number(last_lbank+1); + else + tmp+="*"; + + tmp+="/"; + if (first_hbank==last_hbank) + tmp+=QString::number(first_hbank+1); + else if (! (first_hbank==0 && last_hbank>=127)) + tmp+=QString::number(first_hbank+1)+"-"+QString::number(last_hbank+1); + else + tmp+="*"; + + } + return tmp; +} + +} // namespace MusECore diff --git a/muse2/muse/instruments/minstrument.h b/muse2/muse/instruments/minstrument.h index 385e67b4..f793a7b6 100644 --- a/muse2/muse/instruments/minstrument.h +++ b/muse2/muse/instruments/minstrument.h @@ -27,8 +27,7 @@ #include "globaldefs.h" #include <list> #include <vector> - -class QString; +#include <QString> namespace MusEGui { class PopupMenu; @@ -40,6 +39,7 @@ class MidiControllerList; class MidiPort; class MidiPlayEvent; class Xml; +class DrumMap; //--------------------------------------------------------- @@ -80,6 +80,48 @@ struct SysEx { unsigned char* data; }; + + +struct patch_collection_t +{ + int first_program; + int last_program; + int first_hbank; + int last_hbank; + int first_lbank; + int last_lbank; + + patch_collection_t(int p1=0, int p2=127, int l1=0, int l2=127, int h1=0, int h2=127) + { + first_program=p1; + last_program=p2; + first_lbank=l1; + last_lbank=l2; + first_hbank=h1; + last_hbank=h2; + } + + QString to_string(); +}; + +struct patch_drummap_mapping_t +{ + patch_collection_t affected_patches; + DrumMap* drummap; + + patch_drummap_mapping_t(const patch_collection_t& a, DrumMap* d) + { + affected_patches=a; + drummap=d; + } + + patch_drummap_mapping_t(const patch_drummap_mapping_t& that); + patch_drummap_mapping_t(); + ~patch_drummap_mapping_t(); + + patch_drummap_mapping_t& operator=(const patch_drummap_mapping_t& that); +}; + //--------------------------------------------------------- // MidiInstrument //--------------------------------------------------------- @@ -88,6 +130,7 @@ class MidiInstrument { PatchGroupList pg; MidiControllerList* _controller; QList<SysEx*> _sysex; + std::list<patch_drummap_mapping_t> patch_drummap_mapping; bool _dirty; int _nullvalue; @@ -103,6 +146,11 @@ class MidiInstrument { char* _initScript; QString _name; QString _filePath; + + void writeDrummaps(int level, Xml& xml) const; + void readDrummaps(Xml& xml); + patch_drummap_mapping_t readDrummapsEntry(Xml& xml); + patch_collection_t readDrummapsEntryPatchCollection(Xml& xml); public: MidiInstrument(); @@ -123,6 +171,8 @@ class MidiInstrument { void removeSysex(SysEx* sysex) { _sysex.removeAll(sysex); } void addSysex(SysEx* sysex) { _sysex.append(sysex); } + const DrumMap* drummap_for_patch(int patch) const; + EventList* midiInit() const { return _midiInit; } EventList* midiReset() const { return _midiReset; } EventList* midiState() const { return _midiState; } @@ -148,6 +198,7 @@ class MidiInstrument { void write(int level, Xml&); PatchGroupList* groups() { return &pg; } + std::list<patch_drummap_mapping_t>* get_patch_drummap_mapping() { return &patch_drummap_mapping; } }; //--------------------------------------------------------- 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..ad0226da 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,96 @@ 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; + + for (QSet<MusECore::Track*>::iterator it=instrument_map[spitch].tracks.begin(); + it!=instrument_map[spitch].tracks.end(); it++) + { + if (dynamic_cast<MusECore::MidiTrack*>(*it)) + dynamic_cast<MusECore::MidiTrack*>(*it)->set_drummap_ordering_tied_to_patch(false); + } + for (QSet<MusECore::Track*>::iterator it=instrument_map[dpitch].tracks.begin(); + it!=instrument_map[dpitch].tracks.end(); it++) + { + if (dynamic_cast<MusECore::MidiTrack*>(*it)) + dynamic_cast<MusECore::MidiTrack*>(*it)->set_drummap_ordering_tied_to_patch(false); + } + + 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 +1141,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 +1150,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 +1168,7 @@ void DrumCanvas::modifySelected(NoteInfo::ValType type, int delta) void DrumCanvas::curPartChanged() { + EventCanvas::curPartChanged(); editor->setWindowTitle(getCaption()); } @@ -994,8 +1230,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 +1240,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 +1250,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 +1260,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 +1309,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 +1345,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 +1361,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 +1379,262 @@ 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++) + { + MusECore::MidiTrack* mt=dynamic_cast<MusECore::MidiTrack*>(*it); + // if we're not only changing "mute" state... + if (!mt->drummap()[index].almost_equals(ourDrumMap[instr])) + mt->set_drummap_tied_to_patch(false); + mt->drummap()[index] = ourDrumMap[instr]; + if (update_druminmap) + mt->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..ae647709 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); @@ -122,6 +163,13 @@ class DrumCanvas : public EventCanvas { MusECore::Event *getEventAtCursorPos(); void selectCursorEvent(MusECore::Event *ev); + int pitch_and_track_to_instrument(int pitch, MusECore::Track* track); + + MusECore::DrumMap* getOurDrumMap() { return ourDrumMap; } + int getOurDrumMapSize() { return instrument_map.size(); } + QVector<instrument_number_mapping_t>& get_instrument_map() { return instrument_map; } + void propagate_drummap_change(int instrument, bool update_druminmap); + void rebuildOurDrumMap(); }; } // namespace MusEGui diff --git a/muse2/muse/midiedit/dlist.cpp b/muse2/muse/midiedit/dlist.cpp index 80009cc7..ad0d05dd 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(instrument); - setCurDrumInstrument(pitch); + 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,107 @@ 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; - } + + 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 + { + if (dcanvas) + { + //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; + mt->set_drummap_tied_to_patch(false); + } + // 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. + } + else + { + for (int i=0;i<128;i++) + if (ourDrumMap[i].enote==val) + { + ourDrumMap[i].enote=dm->enote; + break; } - //TODO: Set all the notes on the track with pitch=dm->enote to pitch=val + } + } + 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 +442,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 +463,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 +475,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 +490,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 +498,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 +506,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 +515,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 && dcanvas) // 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 && dcanvas) + { + 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 && dcanvas) //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 +582,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 +605,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 +627,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 +677,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 +695,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 +735,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 +761,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 +802,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 +845,16 @@ void DList::returnPressed() printf("Return pressed in unknown column\n"); break; } + + if (editEntryOld != *editEntry && dcanvas) + 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 +863,93 @@ 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 + { + if (dcanvas) + { + //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; + mt->set_drummap_tied_to_patch(false); + } + // 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. + } + else + { + for (int i=0;i<128;i++) + if (ourDrumMap[i].enote==val) + { + ourDrumMap[i].enote=editEntry->enote; + break; + } + } + } + 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) + 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 +984,13 @@ void DList::songChanged(int flags) // DList //--------------------------------------------------------- -DList::DList(QHeaderView* h, QWidget* parent, int ymag) - : MusEGui::View(parent, 1, ymag) - { +void DList::init(QHeaderView* h, QWidget* parent) +{ setBg(Qt::white); - if (!h){ - h = new QHeaderView(Qt::Horizontal, parent);} + 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,9 +1000,42 @@ 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; + +} + +DList::DList(QHeaderView* h, QWidget* parent, int ymag, DrumCanvas* dcanvas_, bool oldstyle) + : MusEGui::View(parent, 1, ymag) + { + dcanvas=dcanvas_; + ourDrumMap=dcanvas->getOurDrumMap(); + ourDrumMapSize=dcanvas->getOurDrumMapSize(); + old_style_drummap_mode=oldstyle; + connect(dcanvas, SIGNAL(ourDrumMapChanged(bool)), SLOT(ourDrumMapChanged(bool))); + + init(h, parent); + } + +DList::DList(QHeaderView* h, QWidget* parent, int ymag, MusECore::DrumMap* dm, int dmSize) + : MusEGui::View(parent, 1, ymag) + { + dcanvas=NULL; + ourDrumMap=dm; + ourDrumMapSize=dmSize; + old_style_drummap_mode=false; + + init(h, parent); } //--------------------------------------------------------- @@ -801,7 +1055,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 +1080,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 +1110,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 +1132,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..d864f23e 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,27 @@ class DrumMap; namespace MusEGui { class ScrollScale; +class DrumCanvas; + + +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 +}; + //--------------------------------------------------------- // DLineEdit @@ -89,9 +112,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 +128,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&); @@ -113,6 +140,8 @@ class DList : public View { int x2col(int x) const; void devicesPopupMenu(MusECore::DrumMap* t, int x, int y, bool changeAll); + void init(QHeaderView*, QWidget*); + //void setCurDrumInstrument(int n); private slots: @@ -131,18 +160,17 @@ 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, DrumCanvas* dcanvas, bool oldstyle); + DList(QHeaderView* h, QWidget* parent, int ymag, MusECore::DrumMap* dm, int dmSize=128); ~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..1f159d1a 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()); @@ -545,7 +644,7 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un void DrumEdit::songChanged1(int bits) { - if(_isDeleting) // Ignore while while deleting to prevent crash. + if(_isDeleting) // Ignore while deleting to prevent crash. return; if (bits & SC_SOLO) @@ -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..33491581 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" class QCloseEvent; class QLabel; @@ -64,18 +65,25 @@ class ScrollScale; class Splitter; class Toolbar1; - //--------------------------------------------------------- // DrumEdit //--------------------------------------------------------- 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 +101,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 +118,7 @@ class DrumEdit : public MidiEditor { void setHeaderToolTips(); void setHeaderWhatsThis(); - + private slots: void setRaster(int); void noteinfoChanged(MusEGui::NoteInfo::ValType type, int val); @@ -127,6 +136,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 +151,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 +164,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(); } }; } // namespace MusEGui diff --git a/muse2/muse/midiedit/drummap.cpp b/muse2/muse/midiedit/drummap.cpp index aa7ce759..d86bcd65 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,13 @@ namespace MusECore { const DrumMap blankdm = { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 127, 127, false }; +// this map should have 128 entries, as it's used for initalising iNewDrumMap as well. +// iNewDrumMap only has 128 entries. also, the every "out-note" ("anote") should be +// represented exactly once in idrumMap, and there shall be no duplicate or unused +// "out-notes". +// reason: iNewDrumMap is inited as follows: iterate through the full idrumMap[], +// iNewDrumMap[ idrumMap[i].anote ] = idrumMap[i] +// if you ever want to change this, you will need to fix the initNewDrumMap() function. 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 }, @@ -249,6 +259,55 @@ const DrumMap idrumMap[DRUM_MAPSIZE] = { { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 34, 34, false } }; +DrumMap iNewDrumMap[128]; + +void initNewDrumMap() +{ + bool done[128]; + for (int i=0;i<128;i++) done[i]=false; + + for (int i=0;i<DRUM_MAPSIZE;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 + { + if (done[idx]==true) + { + printf("ERROR: iNewDrumMap[%i] is already initalized!\n" + " this will be probably not a problem, but some programmer didn't read\n" + " flo's comment at drummap.cpp, above idrumMap[].\n", idx); + } + else + { + iNewDrumMap[idx]=idrumMap[i]; + done[idx]=true; + } + } + } + + for (int i=0;i<128;i++) + { + if (done[i]==false) + { + printf("ERROR: iNewDrumMap[%i] is uninitalized!\n" + " this will be probably not a problem, but some programmer didn't read\n" + " flo's comment at drummap.cpp, above idrumMap[].\n", i); + iNewDrumMap[i].name=""; + iNewDrumMap[i].vol=100; + iNewDrumMap[i].quant=16; + iNewDrumMap[i].len=32; + iNewDrumMap[i].lv1=70; + iNewDrumMap[i].lv2=90; + iNewDrumMap[i].lv3=127; + iNewDrumMap[i].lv4=110; + iNewDrumMap[i].enote=i; + iNewDrumMap[i].anote=i; + } + } +} + //--------------------------------------------------------- // initDrumMap @@ -302,11 +361,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 @@ -321,6 +379,14 @@ bool DrumMap::operator==(const DrumMap& map) const && mute == map.mute; } +bool DrumMap::almost_equals(const DrumMap& map) const +{ + DrumMap tmp=map; + tmp.mute=this->mute; + return tmp==*this; +} + + //--------------------------------------------------------- // writeDrumMap //--------------------------------------------------------- @@ -520,3 +586,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..7f28b068 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 { @@ -48,21 +49,45 @@ struct DrumMap { bool operator==(const DrumMap& map) const; bool operator!=(const DrumMap& map) const { return !operator==(map); } + bool almost_equals(const DrumMap& map) const; }; +// please let this at "128". idrumMap should have length 128 (see drummap.cpp for details) #define DRUM_MAPSIZE 128 +extern DrumMap iNewDrumMap[128]; +extern void initNewDrumMap(); + 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..7e40a41f 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); @@ -4658,17 +4663,23 @@ 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 test drum controllers + * o test old- and new drumtrack recording, steprecording + * * > 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 + * * 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 d9513a47..1f8aa27f 100644 --- a/muse2/muse/mixer/amixer.cpp +++ b/muse2/muse/mixer/amixer.cpp @@ -184,6 +184,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); @@ -198,6 +199,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); @@ -209,6 +211,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))); @@ -352,6 +355,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); @@ -430,7 +434,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++); } @@ -487,7 +491,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++); } @@ -636,6 +640,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) @@ -664,6 +670,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; @@ -719,6 +731,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 c6e79f17..54cd2e8c 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 97a4d7a1..6d7e419e 100644 --- a/muse2/muse/song.cpp +++ b/muse2/muse/song.cpp @@ -245,6 +245,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); @@ -330,7 +335,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; @@ -351,6 +356,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; @@ -389,6 +395,7 @@ void Song::duplicateTracks() int audio_found = 0; int midi_found = 0; int drum_found = 0; + int new_drum_found = 0; for(iTrack it = tl.begin(); it != tl.end(); ++it) if((*it)->selected()) { @@ -398,20 +405,20 @@ void Song::duplicateTracks() continue; if(type == Track::DRUM) - //if(track->isDrumTrack()) // For Flo later with new drum tracks. ++drum_found; - else - if(type == Track::MIDI) + else if(type == Track::NEW_DRUM) + ++new_drum_found; + else if(type == Track::MIDI) ++midi_found; else ++audio_found; } - if(audio_found == 0 && midi_found == 0 && drum_found == 0) + if(audio_found == 0 && midi_found == 0 && drum_found == 0 && new_drum_found==0) return; - MusEGui::DuplicateTracksDialog* dlg = new MusEGui::DuplicateTracksDialog(audio_found, midi_found, drum_found); + MusEGui::DuplicateTracksDialog* dlg = new MusEGui::DuplicateTracksDialog(audio_found, midi_found, drum_found, new_drum_found); int rv = dlg->exec(); if(rv == QDialog::Rejected) @@ -435,6 +442,8 @@ void Song::duplicateTracks() flags |= Track::ASSIGN_DEFAULT_ROUTES; if(dlg->copyParts()) flags |= Track::ASSIGN_PARTS; + if(dlg->copyDrumlist()) + flags |= Track::ASSIGN_DRUMLIST; delete dlg; @@ -675,7 +684,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; @@ -748,13 +757,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; @@ -1435,11 +1446,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; @@ -2235,6 +2248,7 @@ void Song::clear(bool signal, bool clear_all) // _tempo = 500000; // default tempo 120 dirty = false; initDrumMap(); + initNewDrumMap(); if (signal) { emit loopChanged(false); recordChanged(false); @@ -3083,6 +3097,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(); @@ -3320,6 +3335,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 ce5aadeb..22a3a86c 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 2a57a4e3..cdb81a8f 100644 --- a/muse2/muse/track.cpp +++ b/muse2/muse/track.cpp @@ -33,6 +33,9 @@ #include "audio.h" #include "globaldefs.h" #include "route.h" +#include "drummap.h" +#include "midictrl.h" +#include "helper.h" namespace MusECore { @@ -45,8 +48,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" }; @@ -331,6 +334,7 @@ void Track::setDefaultName(QString base) switch(_type) { case MIDI: case DRUM: + case NEW_DRUM: case WAVE: base = QString("Track"); break; @@ -522,6 +526,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, int flags) @@ -529,6 +538,12 @@ MidiTrack::MidiTrack(const MidiTrack& mt, int flags) { _events = new EventList; _mpevents = new MPEventList; + + _drummap=new DrumMap[128]; + _drummap_hidden=new bool[128]; + + init_drummap(true /* write drummap ordering information as well */); + internal_assign(mt, flags | Track::ASSIGN_PROPERTIES); } @@ -564,6 +579,14 @@ void MidiTrack::internal_assign(const Track& t, int flags) for(ciRoute ir = mt._outRoutes.begin(); ir != mt._outRoutes.end(); ++ir) // Amazingly, this single line seems to work. MusEGlobal::audio->msgAddRoute(Route(this, ir->channel), *ir); + + 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; + } } else if(flags & ASSIGN_DEFAULT_ROUTES) { @@ -614,6 +637,16 @@ void MidiTrack::internal_assign(const Track& t, int flags) } } + if (flags & ASSIGN_DRUMLIST) + { + for (int i=0;i<128;i++) // no memcpy allowed here. dunno exactly why, + _drummap[i]=mt._drummap[i]; // seems QString-related. + memcpy(_drummap_hidden, mt._drummap_hidden, 128*sizeof(bool)); + update_drum_in_map(); + _drummap_tied_to_patch=mt._drummap_tied_to_patch; + _drummap_ordering_tied_to_patch=mt._drummap_ordering_tied_to_patch; + // TODO FINDMICH "assign" ordering as well + } } void MidiTrack::assign(const Track& t, int flags) @@ -626,8 +659,21 @@ 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 //--------------------------------------------------------- @@ -635,7 +681,7 @@ MidiTrack::~MidiTrack() void MidiTrack::init() { _outPort = 0; - _outChannel = 0; + _outChannel = (type()==NEW_DRUM) ? 9 : 0; //_inPortMask = 0xffff; ///_inPortMask = 0xffffffff; @@ -648,6 +694,44 @@ void MidiTrack::init() _recEcho = true; } +void MidiTrack::init_drum_ordering() +{ + // first display entries with non-empty names, then with empty names. + + remove_ourselves_from_drum_ordering(); + + for (int i=0;i<128;i++) + if (_drummap[i].name!="" && _drummap[i].name!="?") // non-empty name? + MusEGlobal::global_drum_ordering.push_back(std::pair<MidiTrack*,int>(this,i)); + + for (int i=0;i<128;i++) + if (!(_drummap[i].name!="" && _drummap[i].name!="?")) // empty name? + MusEGlobal::global_drum_ordering.push_back(std::pair<MidiTrack*,int>(this,i)); +} + +void MidiTrack::init_drummap(bool write_ordering) +{ + for (int i=0;i<128;i++) + _drummap[i]=iNewDrumMap[i]; + + if (write_ordering) + init_drum_ordering(); + + update_drum_in_map(); + + for (int i=0;i<128;i++) + _drummap_hidden[i]=false; + + _drummap_tied_to_patch=true; + _drummap_ordering_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 //--------------------------------------------------------- @@ -905,8 +989,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); @@ -929,9 +1018,29 @@ 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.intTag(level, "ordering_tied", _drummap_ordering_tied_to_patch); + + xml.etag(level, "our_drum_settings"); +} + +void MidiTrack::writeOurDrumMap(int level, Xml& xml, bool full) const +{ + write_new_style_drummap(level, xml, "our_drummap", _drummap, _drummap_hidden, full); +} + //--------------------------------------------------------- // MidiTrack::read //--------------------------------------------------------- @@ -988,6 +1097,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) @@ -998,7 +1109,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; @@ -1009,6 +1120,46 @@ 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 == "ordering_tied") + _drummap_ordering_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; + _drummap_ordering_tied_to_patch=false; + read_new_style_drummap(xml, "our_drummap", _drummap, _drummap_hidden); + update_drum_in_map(); +} + //--------------------------------------------------------- // addPart @@ -1195,4 +1346,69 @@ void Track::writeRouting(int level, Xml& xml) const } } +int MidiTrack::getFirstControllerValue(int ctrl, int def) +{ + int val=def; + unsigned tick=-1; // maximum integer + + for (iPart pit=parts()->begin(); pit!=parts()->end(); pit++) + { + Part* part=pit->second; + if (part->tick() > tick) break; // ignore this and the rest. we won't find anything new. + for (iEvent eit=part->events()->begin(); eit!=part->events()->end(); eit++) + { + if (eit->first+part->tick() >= tick) break; + // else if (eit->first+part->tick() < tick) and + if (eit->second.type()==Controller && eit->second.dataA()==ctrl) + { + val = eit->second.dataB(); + tick = eit->first+part->tick(); + break; + } + } + } + + return val; +} + + +// returns true if the autoupdate changed something +bool MidiTrack::auto_update_drummap() +{ + if (_drummap_tied_to_patch) + { + int patch = getFirstControllerValue(CTRL_PROGRAM,0); + const DrumMap* new_drummap = MusEGlobal::midiPorts[_outPort].instrument()->drummap_for_patch(patch); + + if (!drummaps_almost_equal(new_drummap, this->drummap(), 128)) + { + for (int i=0;i<128;i++) + { + bool temp_mute=_drummap[i].mute; + _drummap[i]=new_drummap[i]; + _drummap[i].mute=temp_mute; + } + + if (_drummap_ordering_tied_to_patch) + init_drum_ordering(); + + return true; + } + } + + return false; +} + +void MidiTrack::set_drummap_tied_to_patch(bool val) +{ + _drummap_tied_to_patch=val; + if (val) auto_update_drummap(); +} + +void MidiTrack::set_drummap_ordering_tied_to_patch(bool val) +{ + _drummap_ordering_tied_to_patch=val; + if (val && _drummap_tied_to_patch) init_drum_ordering(); +} + } // namespace MusECore diff --git a/muse2/muse/track.h b/muse2/muse/track.h index b887ff52..5cc217b6 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,11 +55,11 @@ 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 }; enum AssignFlags { - ASSIGN_PROPERTIES=1, ASSIGN_PARTS=2, ASSIGN_PLUGINS=4, ASSIGN_STD_CTRLS=8, ASSIGN_PLUGIN_CTRLS=16, ASSIGN_ROUTES=32, ASSIGN_DEFAULT_ROUTES=64 }; + ASSIGN_PROPERTIES=1, ASSIGN_PARTS=2, ASSIGN_PLUGINS=4, ASSIGN_STD_CTRLS=8, ASSIGN_PLUGIN_CTRLS=16, ASSIGN_ROUTES=32, ASSIGN_DEFAULT_ROUTES=64, ASSIGN_DRUMLIST=128 }; private: TrackType _type; QString _comment; @@ -204,11 +205,12 @@ class Track { void setDefaultName(QString base = QString()); 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(); }; @@ -232,7 +234,24 @@ 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 + bool _drummap_ordering_tied_to_patch; //if true, changing patch also changes drummap-ordering + int drum_in_map[128]; + + void init(); void internal_assign(const Track&, int flags); + void init_drummap(bool write_ordering); // function without argument in public + void remove_ourselves_from_drum_ordering(); + void init_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(); @@ -241,7 +260,6 @@ class MidiTrack : public Track { virtual void assign(const Track&, int flags); - void init(); virtual AutomationType automationType() const; virtual void setAutomationType(AutomationType); @@ -299,9 +317,29 @@ class MidiTrack : public Track { virtual bool canRecord() const { return true; } static void setVisible(bool t) { _isVisible = t; } static bool visible() { return _isVisible; } + + int getFirstControllerValue(int ctrl, int def=-1); 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 + + bool auto_update_drummap(); + void set_drummap_tied_to_patch(bool); + bool drummap_tied_to_patch() { return _drummap_tied_to_patch; } + void set_drummap_ordering_tied_to_patch(bool); + bool drummap_ordering_tied_to_patch() { return _drummap_ordering_tied_to_patch; } + + //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/trackdrummapupdater.cpp b/muse2/muse/trackdrummapupdater.cpp new file mode 100644 index 00000000..35d5c056 --- /dev/null +++ b/muse2/muse/trackdrummapupdater.cpp @@ -0,0 +1,61 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: trackdrummapupdater.cpp,v 1.59.2.52 2011/12/27 20:25:58 flo93 Exp $ +// +// (C) Copyright 2011 Florian Jung (florian.a.jung (at) web.de) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//========================================================= + +#include "trackdrummapupdater.h" +#include "song.h" +#include "globals.h" + +namespace MusECore { + +using MusEGlobal::song; + +TrackDrummapUpdater::TrackDrummapUpdater() +{ + connect(song,SIGNAL(songChanged(int)), this, SLOT(songChanged(int))); +} + +void TrackDrummapUpdater::songChanged(int flags) +{ + if (flags & (SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED | + SC_PART_INSERTED | SC_PART_REMOVED | SC_PART_MODIFIED | + SC_EVENT_INSERTED | SC_EVENT_REMOVED | SC_EVENT_MODIFIED ) ) + { + bool changed=false; + for (iTrack t=song->tracks()->begin(); t!=song->tracks()->end(); t++) + { + MidiTrack* track=dynamic_cast<MidiTrack*>(*t); + if (track && track->auto_update_drummap()) + changed=true; + } + + if (changed) + { + // allow recursion. there will be no more recursion, because this + // is only executed when something other than SC_DRUMMAP happens + song->update(SC_DRUMMAP, true); + } + + } +} + +} //namespace MusECore diff --git a/muse2/muse/trackdrummapupdater.h b/muse2/muse/trackdrummapupdater.h new file mode 100644 index 00000000..caa2ac28 --- /dev/null +++ b/muse2/muse/trackdrummapupdater.h @@ -0,0 +1,43 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: trackdrummapupdater.h,v 1.59.2.52 2011/12/27 20:25:58 flo93 Exp $ +// +// (C) Copyright 2011 Florian Jung (florian.a.jung (at) web.de) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//========================================================= + +#ifndef __TRACKDRUMMAPUPDATER_H__ +#define __TRACKDRUMMAPUPDATER_H__ + +#include <QObject> + +namespace MusECore { + +class TrackDrummapUpdater : public QObject +{ + Q_OBJECT + + public: + TrackDrummapUpdater(); + + private slots: + void songChanged(int flags); +}; + +} //namespace MusECore +#endif diff --git a/muse2/muse/undo.h b/muse2/muse/undo.h index 61604d6f..3487da47 100644 --- a/muse2/muse/undo.h +++ b/muse2/muse/undo.h @@ -137,7 +137,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/muse/widgets/tracks_duplicate.cpp b/muse2/muse/widgets/tracks_duplicate.cpp index c50554b5..07cefe38 100644 --- a/muse2/muse/widgets/tracks_duplicate.cpp +++ b/muse2/muse/widgets/tracks_duplicate.cpp @@ -24,20 +24,19 @@ namespace MusEGui { -DuplicateTracksDialog::DuplicateTracksDialog(bool audio, bool /*midi*/, bool /*drum*/, QWidget* parent) +DuplicateTracksDialog::DuplicateTracksDialog(bool audio, bool /*midi*/, bool /*drum*/, bool newdrum, QWidget* parent) : QDialog(parent) { setupUi(this); - //standardCtrlsCheckBox->setEnabled(audio); - //pluginsCheckBox->setEnabled(audio); - //pluginCtrlsCheckBox->setEnabled(audio); standardCtrlsCheckBox->setVisible(audio); pluginsCheckBox->setVisible(audio); pluginCtrlsCheckBox->setVisible(audio); + copyDrumlistCheckBox->setVisible(newdrum); + connect(okPushButton, SIGNAL(clicked()), this, SLOT(accept())); connect(cancelPushButton, SIGNAL(clicked()), this, SLOT(reject())); } -} // namespace MusEGui
\ No newline at end of file +} // namespace MusEGui diff --git a/muse2/muse/widgets/tracks_duplicate.h b/muse2/muse/widgets/tracks_duplicate.h index 4cef089b..cdcfc479 100644 --- a/muse2/muse/widgets/tracks_duplicate.h +++ b/muse2/muse/widgets/tracks_duplicate.h @@ -39,7 +39,7 @@ class DuplicateTracksDialog : public QDialog, public Ui::DuplicateTracksBase //int exec(); public: - DuplicateTracksDialog(bool audio, bool midi, bool drum, QWidget* parent = 0); + DuplicateTracksDialog(bool audio, bool midi, bool drum, bool newdrum, QWidget* parent = 0); int copies() const { return copiesSpinBox->value(); } bool copyStdCtrls() const { return standardCtrlsCheckBox->isChecked(); } @@ -50,6 +50,7 @@ class DuplicateTracksDialog : public QDialog, public Ui::DuplicateTracksBase bool defaultRoutes() const { return defaultRoutesRadioButton->isChecked(); } bool copyParts() const { return copyPartsCheckBox->isChecked(); } + bool copyDrumlist() const { return copyDrumlistCheckBox->isChecked(); } }; } // namespace MusEGui diff --git a/muse2/muse/widgets/tracks_duplicate_base.ui b/muse2/muse/widgets/tracks_duplicate_base.ui index c993e370..a8ec5766 100644 --- a/muse2/muse/widgets/tracks_duplicate_base.ui +++ b/muse2/muse/widgets/tracks_duplicate_base.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>231</width> - <height>261</height> + <width>269</width> + <height>319</height> </rect> </property> <property name="windowTitle"> @@ -94,6 +94,13 @@ </widget> </item> <item> + <widget class="QCheckBox" name="copyDrumlistCheckBox"> + <property name="text"> + <string>Copy drumlist</string> + </property> + </widget> + </item> + <item> <widget class="Line" name="line"> <property name="orientation"> <enum>Qt::Horizontal</enum> diff --git a/muse2/muse/xml.cpp b/muse2/muse/xml.cpp index 45bed368..1a989366 100644 --- a/muse2/muse/xml.cpp +++ b/muse2/muse/xml.cpp @@ -225,7 +225,7 @@ Xml::Token Xml::parse() bool endFlag = false; nextc(); if (c == EOF) { - printf("unexpected EOF reading *.med file at level %d, line %d, <%s><%s><%s>\n", + printf("unexpected EOF reading xml file at level %d, line %d, <%s><%s><%s>\n", level, _line, _tag.toLatin1().constData(), _s1.toLatin1().constData(), _s2.toLatin1().constData()); return level == 0 ? End : Error; } diff --git a/muse2/share/instruments/gm.idf b/muse2/share/instruments/gm.idf index 04bf23ff..69e02503 100644 --- a/muse2/share/instruments/gm.idf +++ b/muse2/share/instruments/gm.idf @@ -161,6 +161,9 @@ <Patch name="Applaus" prog="126" /> <Patch name="Gunshot" prog="127" /> </PatchGroup> + <PatchGroup name="Drums"> + <Patch name="Drums" prog="0" drum="1" /> + </PatchGroup> <Controller name="Modulation" l="1" /> <Controller name="PortamentoTime" l="5" /> <Controller name="MainVolume" l="7" init="100" /> diff --git a/muse2/share/instruments/gs.idf b/muse2/share/instruments/gs.idf index 3368b7c9..9314e282 100644 --- a/muse2/share/instruments/gs.idf +++ b/muse2/share/instruments/gs.idf @@ -214,5 +214,372 @@ <Controller name="DrumChorusSend" type="NRPN" h="30" l="pitch" /> <Controller name="Pitch" type="Pitch" /> <Controller name="Program" type="Program" /> + <Drummaps> + <entry> + <patch_collection hbank="127" prog="0-7" /> + <drummap> + <entry pitch="27"> <name>High Q</name> </entry> + <entry pitch="28"> <name>Slap</name> </entry> + <entry pitch="29"> <name>Scratch Push</name> </entry> + <entry pitch="30"> <name>Scratch Pull</name> </entry> + <entry pitch="31"> <name>Sticks</name> </entry> + <entry pitch="32"> <name>Square Click</name> </entry> + <entry pitch="33"> <name>Metronome Click</name> </entry> + <entry pitch="34"> <name>Metronome Bell</name> </entry> + <entry pitch="35"> <name>Kick Drum 2</name> </entry> + <entry pitch="36"> <name>Kick Drum 1</name> </entry> + <entry pitch="38"> <name>Snare Drum 1</name> </entry> + <entry pitch="40"> <name>Snare Drum 2</name> </entry> + <entry pitch="41"> <name>Low Tom 2</name> </entry> + <entry pitch="43"> <name>Low Tom 1</name> </entry> + <entry pitch="45"> <name>Mid Tom 2</name> </entry> + <entry pitch="47"> <name>Mid Tom 1</name> </entry> + <entry pitch="48"> <name>High Tom 2</name> </entry> + <entry pitch="50"> <name>High Tom 1</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + <entry pitch="85"> <name>Castanets</name> </entry> + <entry pitch="86"> <name>Mute Surdo</name> </entry> + <entry pitch="87"> <name>Open Surdo</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="8-15" /> + <drummap> + <entry pitch="27"> <name>High Q</name> </entry> + <entry pitch="28"> <name>Slap</name> </entry> + <entry pitch="29"> <name>Scratch Push</name> </entry> + <entry pitch="30"> <name>Scratch Pull</name> </entry> + <entry pitch="31"> <name>Sticks</name> </entry> + <entry pitch="32"> <name>Square Click</name> </entry> + <entry pitch="33"> <name>Metronome Click</name> </entry> + <entry pitch="34"> <name>Metronome Bell</name> </entry> + <entry pitch="35"> <name>Kick Drum 2</name> </entry> + <entry pitch="36"> <name>Kick Drum 1</name> </entry> + <entry pitch="38"> <name>Snare Drum 1</name> </entry> + <entry pitch="40"> <name>Snare Drum 2</name> </entry> + <entry pitch="41"> <name>Room Low Tom 2</name> </entry> + <entry pitch="43"> <name>Room Low Tom 1</name> </entry> + <entry pitch="45"> <name>Room Mid Tom 2</name> </entry> + <entry pitch="47"> <name>Room Mid Tom 1</name> </entry> + <entry pitch="48"> <name>Room High Tom 2</name> </entry> + <entry pitch="50"> <name>Room High Tom 1</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + <entry pitch="85"> <name>Castanets</name> </entry> + <entry pitch="86"> <name>Mute Surdo</name> </entry> + <entry pitch="87"> <name>Open Surdo</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="16-23" /> + <drummap> + <entry pitch="27"> <name>High Q</name> </entry> + <entry pitch="28"> <name>Slap</name> </entry> + <entry pitch="29"> <name>Scratch Push</name> </entry> + <entry pitch="30"> <name>Scratch Pull</name> </entry> + <entry pitch="31"> <name>Sticks</name> </entry> + <entry pitch="32"> <name>Square Click</name> </entry> + <entry pitch="33"> <name>Metronome Click</name> </entry> + <entry pitch="34"> <name>Metronome Bell</name> </entry> + <entry pitch="35"> <name>Kick Drum 2</name> </entry> + <entry pitch="36"> <name>Mondo Kick</name> </entry> + <entry pitch="38"> <name>Gated Snare</name> </entry> + <entry pitch="40"> <name>Snare Drum 2</name> </entry> + <entry pitch="41"> <name>Room Low Tom 2</name> </entry> + <entry pitch="43"> <name>Room Low Tom 1</name> </entry> + <entry pitch="45"> <name>Room Mid Tom 2</name> </entry> + <entry pitch="47"> <name>Room Mid Tom 1</name> </entry> + <entry pitch="48"> <name>Room High Tom 2</name> </entry> + <entry pitch="50"> <name>Room High Tom 1</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + <entry pitch="85"> <name>Castanets</name> </entry> + <entry pitch="86"> <name>Mute Surdo</name> </entry> + <entry pitch="87"> <name>Open Surdo</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="24" /> + <drummap> + <entry pitch="27"> <name>High Q</name> </entry> + <entry pitch="28"> <name>Slap</name> </entry> + <entry pitch="29"> <name>Scratch Push</name> </entry> + <entry pitch="30"> <name>Scratch Pull</name> </entry> + <entry pitch="31"> <name>Sticks</name> </entry> + <entry pitch="32"> <name>Square Click</name> </entry> + <entry pitch="33"> <name>Metronome Click</name> </entry> + <entry pitch="34"> <name>Metronome Bell</name> </entry> + <entry pitch="35"> <name>Kick Drum 2</name> </entry> + <entry pitch="36"> <name>Elec. Bass Drum</name> </entry> + <entry pitch="38"> <name>Elec. Snare</name> </entry> + <entry pitch="40"> <name>Gated Snare</name> </entry> + <entry pitch="41"> <name>Elec. Low Tom 2</name> </entry> + <entry pitch="43"> <name>Elec. Low Tom 1</name> </entry> + <entry pitch="45"> <name>Elec. Mid Tom 2</name> </entry> + <entry pitch="47"> <name>Elec. Mid Tom 1</name> </entry> + <entry pitch="48"> <name>Elec. High Tom 2</name> </entry> + <entry pitch="50"> <name>Elec. High Tom 1</name> </entry> + <entry pitch="52"> <name>Reverse Cymbal</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + <entry pitch="85"> <name>Castanets</name> </entry> + <entry pitch="86"> <name>Mute Surdo</name> </entry> + <entry pitch="87"> <name>Open Surdo</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="25-31" /> + <drummap> + <entry pitch="27"> <name>High Q</name> </entry> + <entry pitch="28"> <name>Slap</name> </entry> + <entry pitch="29"> <name>Scratch Push</name> </entry> + <entry pitch="30"> <name>Scratch Pull</name> </entry> + <entry pitch="31"> <name>Sticks</name> </entry> + <entry pitch="32"> <name>Square Click</name> </entry> + <entry pitch="33"> <name>Metronome Click</name> </entry> + <entry pitch="34"> <name>Metronome Bell</name> </entry> + <entry pitch="35"> <name>Kick Drum 2</name> </entry> + <entry pitch="36"> <name>808 Bass Drum</name> </entry> + <entry pitch="37"> <name>808 Rim Shot</name> </entry> + <entry pitch="38"> <name>808 Snare Drum</name> </entry> + <entry pitch="40"> <name>Snare Drum 2</name> </entry> + <entry pitch="41"> <name>808 Low Tom 2</name> </entry> + <entry pitch="42"> <name>808 Closed Hi-Hat</name> </entry> + <entry pitch="43"> <name>808 Low Tom 1</name> </entry> + <entry pitch="44"> <name>808 Pedal Hi-Hat</name> </entry> + <entry pitch="45"> <name>808 Tom 2</name> </entry> + <entry pitch="46"> <name>808 Open Hi-Hat</name> </entry> + <entry pitch="47"> <name>808 Mid Tom 1</name> </entry> + <entry pitch="48"> <name>808 High Tom 2</name> </entry> + <entry pitch="49"> <name>808 Cymbal</name> </entry> + <entry pitch="50"> <name>808 High Tom 1</name> </entry> + <entry pitch="52"> <name>Reverse Cymbal</name> </entry> + <entry pitch="56"> <name>808 Cowbell</name> </entry> + <entry pitch="62"> <name>808 High Conga</name> </entry> + <entry pitch="63"> <name>808 Mid Conga</name> </entry> + <entry pitch="64"> <name>808 Low Conga</name> </entry> + <entry pitch="70"> <name>808 Maracas</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + <entry pitch="85"> <name>Castanets</name> </entry> + <entry pitch="86"> <name>Mute Surdo</name> </entry> + <entry pitch="87"> <name>Open Surdo</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="32-39" /> + <drummap> + <entry pitch="27"> <name>High Q</name> </entry> + <entry pitch="28"> <name>Slap</name> </entry> + <entry pitch="29"> <name>Scratch Push</name> </entry> + <entry pitch="30"> <name>Scratch Pull</name> </entry> + <entry pitch="31"> <name>Sticks</name> </entry> + <entry pitch="32"> <name>Square Click</name> </entry> + <entry pitch="33"> <name>Metronome Click</name> </entry> + <entry pitch="34"> <name>Metronome Bell</name> </entry> + <entry pitch="35"> <name>Jazz Bass Drum 2</name> </entry> + <entry pitch="36"> <name>Jazz Bass Drum 1</name> </entry> + <entry pitch="38"> <name>Snare Drum 1</name> </entry> + <entry pitch="40"> <name>Snare Drum 2</name> </entry> + <entry pitch="41"> <name>Low Tom 2</name> </entry> + <entry pitch="43"> <name>Low Tom 1</name> </entry> + <entry pitch="45"> <name>Mid Tom 2</name> </entry> + <entry pitch="47"> <name>Mid Tom 1</name> </entry> + <entry pitch="48"> <name>High Tom 2</name> </entry> + <entry pitch="50"> <name>High Tom 1</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + <entry pitch="85"> <name>Castanets</name> </entry> + <entry pitch="86"> <name>Mute Surdo</name> </entry> + <entry pitch="87"> <name>Open Surdo</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="40-47" /> + <drummap> + <entry pitch="27"> <name>High Q</name> </entry> + <entry pitch="28"> <name>Slap</name> </entry> + <entry pitch="29"> <name>Scratch Push</name> </entry> + <entry pitch="30"> <name>Scratch Pull</name> </entry> + <entry pitch="31"> <name>Sticks</name> </entry> + <entry pitch="32"> <name>Square Click</name> </entry> + <entry pitch="33"> <name>Metronome Click</name> </entry> + <entry pitch="34"> <name>Metronome Bell</name> </entry> + <entry pitch="35"> <name>Jazz Bass Drum 2</name> </entry> + <entry pitch="36"> <name>Jazz Bass Drum 1</name> </entry> + <entry pitch="38"> <name>Brush Tap</name> </entry> + <entry pitch="39"> <name>Brush Slap</name> </entry> + <entry pitch="40"> <name>Brush Swirl</name> </entry> + <entry pitch="41"> <name>Low Tom 2</name> </entry> + <entry pitch="43"> <name>Low Tom 1</name> </entry> + <entry pitch="45"> <name>Mid Tom 2</name> </entry> + <entry pitch="47"> <name>Mid Tom 1</name> </entry> + <entry pitch="48"> <name>High Tom 2</name> </entry> + <entry pitch="50"> <name>High Tom 1</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + <entry pitch="85"> <name>Castanets</name> </entry> + <entry pitch="86"> <name>Mute Surdo</name> </entry> + <entry pitch="87"> <name>Open Surdo</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="48-55" /> + <drummap> + <entry pitch="27"> <name>Closed Hi-Hat</name> </entry> + <entry pitch="28"> <name>Pedal Hi-Hat</name> </entry> + <entry pitch="29"> <name>Open Hi-Hat</name> </entry> + <entry pitch="30"> <name>Ride Cymbal</name> </entry> + <entry pitch="31"> <name>Sticks</name> </entry> + <entry pitch="32"> <name>Square Click</name> </entry> + <entry pitch="33"> <name>Metronome Click</name> </entry> + <entry pitch="34"> <name>Metronome Bell</name> </entry> + <entry pitch="35"> <name>Concert Bass Drum 2</name> </entry> + <entry pitch="36"> <name>Concert Bass Drum 1</name> </entry> + <entry pitch="38"> <name>Concert Snare Drum</name> </entry> + <entry pitch="39"> <name>Castanets</name> </entry> + <entry pitch="40"> <name>Concert Snare Drum</name> </entry> + <entry pitch="41"> <name>Timpani F</name> </entry> + <entry pitch="42"> <name>Timpani F#</name> </entry> + <entry pitch="43"> <name>Timpani G</name> </entry> + <entry pitch="44"> <name>Timpani G#</name> </entry> + <entry pitch="45"> <name>Timpani A</name> </entry> + <entry pitch="46"> <name>Timpani A#</name> </entry> + <entry pitch="47"> <name>Timpani B</name> </entry> + <entry pitch="48"> <name>Timpani C</name> </entry> + <entry pitch="49"> <name>Timpani C#</name> </entry> + <entry pitch="50"> <name>Timpani D</name> </entry> + <entry pitch="51"> <name>Timpani D#</name> </entry> + <entry pitch="52"> <name>Timpani E</name> </entry> + <entry pitch="53"> <name>Timpani F</name> </entry> + <entry pitch="57"> <name>Concert Cymbal 2</name> </entry> + <entry pitch="59"> <name>Concert Cymbal 1</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + <entry pitch="85"> <name>Castanets</name> </entry> + <entry pitch="86"> <name>Mute Surdo</name> </entry> + <entry pitch="87"> <name>Open Surdo</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="56-126" /> + <drummap> + <entry pitch="35"> <name></name> </entry> + <entry pitch="36"> <name></name> </entry> + <entry pitch="37"> <name></name> </entry> + <entry pitch="38"> <name></name> </entry> + <entry pitch="39"> <name>High Q</name> </entry> + <entry pitch="40"> <name>Slap</name> </entry> + <entry pitch="41"> <name>Scratch Push</name> </entry> + <entry pitch="42"> <name>Scratch Pull</name> </entry> + <entry pitch="43"> <name>Sticks</name> </entry> + <entry pitch="44"> <name>Square Click</name> </entry> + <entry pitch="45"> <name>Metronome Click</name> </entry> + <entry pitch="46"> <name>Metronome Bell</name> </entry> + <entry pitch="47"> <name>Guitar Fret Noise</name> </entry> + <entry pitch="48"> <name>Guitar Cut Noise Up</name> </entry> + <entry pitch="49"> <name>Guitar Cut Noise Down</name> </entry> + <entry pitch="50"> <name>Double Bass String Slap</name> </entry> + <entry pitch="51"> <name>Flute Key Click</name> </entry> + <entry pitch="52"> <name>Laughing</name> </entry> + <entry pitch="53"> <name>Screaming</name> </entry> + <entry pitch="54"> <name>Punch</name> </entry> + <entry pitch="55"> <name>Heartbeat</name> </entry> + <entry pitch="56"> <name>Footsteps 1</name> </entry> + <entry pitch="57"> <name>Footsteps 2</name> </entry> + <entry pitch="58"> <name>Applause</name> </entry> + <entry pitch="59"> <name>Door Creaking</name> </entry> + <entry pitch="60"> <name>Door Closing</name> </entry> + <entry pitch="61"> <name>Scratch</name> </entry> + <entry pitch="62"> <name>Wind Chimes</name> </entry> + <entry pitch="63"> <name>Car Engine</name> </entry> + <entry pitch="64"> <name>Car Brakes</name> </entry> + <entry pitch="65"> <name>Car Passing</name> </entry> + <entry pitch="66"> <name>Car Crash</name> </entry> + <entry pitch="67"> <name>Siren</name> </entry> + <entry pitch="68"> <name>Train</name> </entry> + <entry pitch="69"> <name>Jet Plane</name> </entry> + <entry pitch="70"> <name>Helicopter</name> </entry> + <entry pitch="71"> <name>Starship</name> </entry> + <entry pitch="72"> <name>Gun Shot</name> </entry> + <entry pitch="73"> <name>Machine Gun</name> </entry> + <entry pitch="74"> <name>Laser Gun</name> </entry> + <entry pitch="75"> <name>Explosion</name> </entry> + <entry pitch="76"> <name>Dog Bark</name> </entry> + <entry pitch="77"> <name>Horse Gallop</name> </entry> + <entry pitch="78"> <name>Birds Tweet</name> </entry> + <entry pitch="79"> <name>Rain</name> </entry> + <entry pitch="80"> <name>Thunder</name> </entry> + <entry pitch="81"> <name>Wind</name> </entry> + <entry pitch="82"> <name>Seashore</name> </entry> + <entry pitch="83"> <name>Stream</name> </entry> + <entry pitch="84"> <name>Bubble</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="127" /> + <drummap> + <entry pitch="52"> <name></name> </entry> + <entry pitch="53"> <name></name> </entry> + <entry pitch="55"> <name></name> </entry> + <entry pitch="57"> <name></name> </entry> + <entry pitch="58"> <name></name> </entry> + <entry pitch="59"> <name></name> </entry> + <entry pitch="73"> <name>Quijada</name> </entry> + <entry pitch="74"> <name></name> </entry> + <entry pitch="76"> <name>Laughing</name> </entry> + <entry pitch="77"> <name>Screaming</name> </entry> + <entry pitch="78"> <name>Punch</name> </entry> + <entry pitch="79"> <name>Heartbeat</name> </entry> + <entry pitch="80"> <name>Footsteps 1</name> </entry> + <entry pitch="81"> <name>Footsteps 2</name> </entry> + <entry pitch="82"> <name>Applause</name> </entry> + <entry pitch="83"> <name>Door Creaking</name> </entry> + <entry pitch="84"> <name>Door Closing</name> </entry> + <entry pitch="85"> <name>Scratch</name> </entry> + <entry pitch="86"> <name>Wind Chimes</name> </entry> + <entry pitch="87"> <name>Car Engine</name> </entry> + <entry pitch="88"> <name>Car Brakes</name> </entry> + <entry pitch="89"> <name>Car Passing</name> </entry> + <entry pitch="90"> <name>Car Crash</name> </entry> + <entry pitch="91"> <name>Siren</name> </entry> + <entry pitch="92"> <name>Train</name> </entry> + <entry pitch="93"> <name>Jet Plane</name> </entry> + <entry pitch="94"> <name>Helicopter</name> </entry> + <entry pitch="95"> <name>Starship</name> </entry> + <entry pitch="96"> <name>Gun Shot</name> </entry> + <entry pitch="97"> <name>Machine Gun</name> </entry> + <entry pitch="98"> <name>Laser Gun</name> </entry> + <entry pitch="99"> <name>Explosion</name> </entry> + <entry pitch="100"> <name>Dog Bark</name> </entry> + <entry pitch="101"> <name>Horse Gallop</name> </entry> + <entry pitch="102"> <name>Birds Tweet</name> </entry> + <entry pitch="103"> <name>Rain</name> </entry> + <entry pitch="104"> <name>Thunder</name> </entry> + <entry pitch="105"> <name>Wind</name> </entry> + <entry pitch="106"> <name>Seashore</name> </entry> + <entry pitch="107"> <name>Stream</name> </entry> + <entry pitch="108"> <name>Bubble</name> </entry> + </drummap> + </entry> + </Drummaps> </MidiInstrument> </muse> diff --git a/muse2/share/instruments/xg.idf b/muse2/share/instruments/xg.idf index 4f5f586e..c281df66 100644 --- a/muse2/share/instruments/xg.idf +++ b/muse2/share/instruments/xg.idf @@ -602,5 +602,506 @@ <Controller name="Drum VariationSendLev" type="NRPN" h="31" l="pitch" /> <Controller name="Pitch" type="Pitch" /> <Controller name="Program" type="Program" /> + + <Drummaps> + <entry> + <patch_collection hbank="127" prog="0" /> + <drummap> + <entry pitch="13"> <name>Mute Surdo</name> </entry> + <entry pitch="14"> <name>Open Surdo</name> </entry> + <entry pitch="15"> <name>High Q</name> </entry> + <entry pitch="16"> <name>Whip Slap</name> </entry> + <entry pitch="17"> <name>Scratch Push</name> </entry> + <entry pitch="18"> <name>Scratch Pull</name> </entry> + <entry pitch="19"> <name>Finger Snap</name> </entry> + <entry pitch="20"> <name>Click Noise</name> </entry> + <entry pitch="21"> <name>Metronome Click</name> </entry> + <entry pitch="22"> <name>Metronome Bell</name> </entry> + <entry pitch="23"> <name>Seq Click L</name> </entry> + <entry pitch="24"> <name>Seq Click H</name> </entry> + <entry pitch="25"> <name>Brush Tap</name> </entry> + <entry pitch="26"> <name>Brush Swirl L</name> </entry> + <entry pitch="27"> <name>Brush Slap</name> </entry> + <entry pitch="28"> <name>Brush Swirl H</name> </entry> + <entry pitch="29"> <name>Snare Roll</name> </entry> + <entry pitch="30"> <name>Castanet</name> </entry> + <entry pitch="31"> <name>Snare L</name> </entry> + <entry pitch="32"> <name>Sticks</name> </entry> + <entry pitch="33"> <name>Bass Drum L</name> </entry> + <entry pitch="34"> <name>Open Rim Shot</name> </entry> + <entry pitch="35"> <name>Bass Drum M</name> </entry> + <entry pitch="36"> <name>Bass Drum H</name> </entry> + <entry pitch="38"> <name>Snare M</name> </entry> + <entry pitch="40"> <name>Snare H</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="1-7" /> + <drummap> + <entry pitch="13"> <name>Mute Surdo</name> </entry> + <entry pitch="14"> <name>Open Surdo</name> </entry> + <entry pitch="15"> <name>High Q</name> </entry> + <entry pitch="16"> <name>Whip Slap</name> </entry> + <entry pitch="17"> <name>Scratch Push</name> </entry> + <entry pitch="18"> <name>Scratch Pull</name> </entry> + <entry pitch="19"> <name>Finger Snap</name> </entry> + <entry pitch="20"> <name>Click Noise</name> </entry> + <entry pitch="21"> <name>Metronome Click</name> </entry> + <entry pitch="22"> <name>Metronome Bell</name> </entry> + <entry pitch="23"> <name>Seq Click L</name> </entry> + <entry pitch="24"> <name>Seq Click H</name> </entry> + <entry pitch="25"> <name>Brush Tap</name> </entry> + <entry pitch="26"> <name>Brush Swirl L</name> </entry> + <entry pitch="27"> <name>Brush Slap</name> </entry> + <entry pitch="28"> <name>Brush Swirl H</name> </entry> + <entry pitch="29"> <name>Snare Roll 2</name> </entry> + <entry pitch="30"> <name>Castanet</name> </entry> + <entry pitch="31"> <name>Snare L 2</name> </entry> + <entry pitch="32"> <name>Sticks</name> </entry> + <entry pitch="33"> <name>Bass Drum L</name> </entry> + <entry pitch="34"> <name>Open Rim Shot 2</name> </entry> + <entry pitch="35"> <name>Bass Drum M 2</name> </entry> + <entry pitch="36"> <name>Bass Drum H 2</name> </entry> + <entry pitch="38"> <name>Snare M 2</name> </entry> + <entry pitch="40"> <name>Snare H 2</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="8-15" /> + <drummap> + <entry pitch="13"> <name>Mute Surdo</name> </entry> + <entry pitch="14"> <name>Open Surdo</name> </entry> + <entry pitch="15"> <name>High Q</name> </entry> + <entry pitch="16"> <name>Whip Slap</name> </entry> + <entry pitch="17"> <name>Scratch Push</name> </entry> + <entry pitch="18"> <name>Scratch Pull</name> </entry> + <entry pitch="19"> <name>Finger Snap</name> </entry> + <entry pitch="20"> <name>Click Noise</name> </entry> + <entry pitch="21"> <name>Metronome Click</name> </entry> + <entry pitch="22"> <name>Metronome Bell</name> </entry> + <entry pitch="23"> <name>Seq Click L</name> </entry> + <entry pitch="24"> <name>Seq Click H</name> </entry> + <entry pitch="25"> <name>Brush Tap</name> </entry> + <entry pitch="26"> <name>Brush Swirl L</name> </entry> + <entry pitch="27"> <name>Brush Slap</name> </entry> + <entry pitch="28"> <name>Brush Swirl H</name> </entry> + <entry pitch="29"> <name>Snare Roll</name> </entry> + <entry pitch="30"> <name>Castanet</name> </entry> + <entry pitch="31"> <name>Snare L</name> </entry> + <entry pitch="32"> <name>Sticks</name> </entry> + <entry pitch="33"> <name>Bass Drum L</name> </entry> + <entry pitch="34"> <name>Open Rim Shot</name> </entry> + <entry pitch="35"> <name>Bass Drum M</name> </entry> + <entry pitch="36"> <name>Room Bass Drum</name> </entry> + <entry pitch="38"> <name>Room Snare L</name> </entry> + <entry pitch="40"> <name>Room Snare H</name> </entry> + <entry pitch="41"> <name>Room Tom 1</name> </entry> + <entry pitch="43"> <name>Room Tom 2</name> </entry> + <entry pitch="45"> <name>Room Tom 3</name> </entry> + <entry pitch="47"> <name>Room Tom 4</name> </entry> + <entry pitch="48"> <name>Room Tom 5</name> </entry> + <entry pitch="50"> <name>Room Tom 6</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="16-23" /> + <drummap> + <entry pitch="13"> <name>Mute Surdo</name> </entry> + <entry pitch="14"> <name>Open Surdo</name> </entry> + <entry pitch="15"> <name>High Q</name> </entry> + <entry pitch="16"> <name>Whip Slap</name> </entry> + <entry pitch="17"> <name>Scratch Push</name> </entry> + <entry pitch="18"> <name>Scratch Pull</name> </entry> + <entry pitch="19"> <name>Finger Snap</name> </entry> + <entry pitch="20"> <name>Click Noise</name> </entry> + <entry pitch="21"> <name>Metronome Click</name> </entry> + <entry pitch="22"> <name>Metronome Bell</name> </entry> + <entry pitch="23"> <name>Seq Click L</name> </entry> + <entry pitch="24"> <name>Seq Click H</name> </entry> + <entry pitch="25"> <name>Brush Tap</name> </entry> + <entry pitch="26"> <name>Brush Swirl L</name> </entry> + <entry pitch="27"> <name>Brush Slap</name> </entry> + <entry pitch="28"> <name>Brush Swirl H</name> </entry> + <entry pitch="29"> <name>Snare Roll</name> </entry> + <entry pitch="30"> <name>Castanet</name> </entry> + <entry pitch="31"> <name>Rock Snare M</name> </entry> + <entry pitch="32"> <name>Sticks</name> </entry> + <entry pitch="33"> <name>Rock Bass Drum M</name> </entry> + <entry pitch="34"> <name>Open Rim Shot</name> </entry> + <entry pitch="35"> <name>Bass Drum H 3</name> </entry> + <entry pitch="36"> <name>Rock Bass Drum</name> </entry> + <entry pitch="38"> <name>Rock Snare L</name> </entry> + <entry pitch="40"> <name>Rock Snare Rim</name> </entry> + <entry pitch="41"> <name>Rock Tom 1</name> </entry> + <entry pitch="43"> <name>Rock Tom 2</name> </entry> + <entry pitch="45"> <name>Rock Tom 3</name> </entry> + <entry pitch="47"> <name>Rock Tom 4</name> </entry> + <entry pitch="48"> <name>Rock Tom 5</name> </entry> + <entry pitch="50"> <name>Rock Tom 6</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="24" /> + <drummap> + <entry pitch="13"> <name>Mute Surdo</name> </entry> + <entry pitch="14"> <name>Open Surdo</name> </entry> + <entry pitch="15"> <name>High Q</name> </entry> + <entry pitch="16"> <name>Whip Slap</name> </entry> + <entry pitch="17"> <name>Scratch Push</name> </entry> + <entry pitch="18"> <name>Scratch Pull</name> </entry> + <entry pitch="19"> <name>Finger Snap</name> </entry> + <entry pitch="20"> <name>Click Noise</name> </entry> + <entry pitch="21"> <name>Metronome Click</name> </entry> + <entry pitch="22"> <name>Metronome Bell</name> </entry> + <entry pitch="23"> <name>Seq Click L</name> </entry> + <entry pitch="24"> <name>Seq Click H</name> </entry> + <entry pitch="25"> <name>Brush Tap</name> </entry> + <entry pitch="26"> <name>Brush Swirl L</name> </entry> + <entry pitch="27"> <name>Brush Slap</name> </entry> + <entry pitch="28"> <name>Reverse Cymbal</name> </entry> + <entry pitch="29"> <name>Snare Roll</name> </entry> + <entry pitch="30"> <name>High Q</name> </entry> + <entry pitch="31"> <name>Snare M</name> </entry> + <entry pitch="32"> <name>Sticks</name> </entry> + <entry pitch="33"> <name>Bass Drum H 4</name> </entry> + <entry pitch="34"> <name>Open Rim Shot</name> </entry> + <entry pitch="35"> <name>Rock Bass Drum</name> </entry> + <entry pitch="36"> <name>Gated Bass Drum</name> </entry> + <entry pitch="38"> <name>Rock Snare L</name> </entry> + <entry pitch="40"> <name>Rock Snare H</name> </entry> + <entry pitch="41"> <name>Elec. Tom 1</name> </entry> + <entry pitch="43"> <name>Elec. Tom 2</name> </entry> + <entry pitch="45"> <name>Elec. Tom 3</name> </entry> + <entry pitch="47"> <name>Elec. Tom 4</name> </entry> + <entry pitch="48"> <name>Elec. Tom 5</name> </entry> + <entry pitch="50"> <name>Elec. Tom 6</name> </entry> + <entry pitch="78"> <name>Scratch Push</name> </entry> + <entry pitch="79"> <name>Scratch Pull</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="25-31" /> + <drummap> + <entry pitch="13"> <name>Mute Surdo</name> </entry> + <entry pitch="14"> <name>Open Surdo</name> </entry> + <entry pitch="15"> <name>High Q</name> </entry> + <entry pitch="16"> <name>Whip Slap</name> </entry> + <entry pitch="17"> <name>Scratch Push</name> </entry> + <entry pitch="18"> <name>Scratch Pull</name> </entry> + <entry pitch="19"> <name>Finger Snap</name> </entry> + <entry pitch="20"> <name>Click Noise</name> </entry> + <entry pitch="21"> <name>Metronome Click</name> </entry> + <entry pitch="22"> <name>Metronome Bell</name> </entry> + <entry pitch="23"> <name>Seq Click L</name> </entry> + <entry pitch="24"> <name>Seq Click H</name> </entry> + <entry pitch="25"> <name>Brush Tap</name> </entry> + <entry pitch="26"> <name>Brush Swirl L</name> </entry> + <entry pitch="27"> <name>Brush Slap</name> </entry> + <entry pitch="28"> <name>Reverse Cymbal</name> </entry> + <entry pitch="29"> <name>Snare Roll</name> </entry> + <entry pitch="30"> <name>High Q</name> </entry> + <entry pitch="31"> <name>Rock Snare H</name> </entry> + <entry pitch="32"> <name>Sticks</name> </entry> + <entry pitch="33"> <name>Bass Drum M</name> </entry> + <entry pitch="34"> <name>Open Rim Shot</name> </entry> + <entry pitch="35"> <name>Analog Bass Drum L</name> </entry> + <entry pitch="36"> <name>Analog Bass Drum H</name> </entry> + <entry pitch="37"> <name>Analog Side Stick</name> </entry> + <entry pitch="38"> <name>Analog Snare L</name> </entry> + <entry pitch="40"> <name>Analog Snare H</name> </entry> + <entry pitch="41"> <name>Analog Tom 1</name> </entry> + <entry pitch="42"> <name>Analog Hi-Hat Closed 1</name> </entry> + <entry pitch="43"> <name>Analog Tom 2</name> </entry> + <entry pitch="44"> <name>Analog Hi-Hat Closed 2</name> </entry> + <entry pitch="45"> <name>Analog Tom 3</name> </entry> + <entry pitch="46"> <name>Analog Hi-Hat Open</name> </entry> + <entry pitch="47"> <name>Analog Tom 4</name> </entry> + <entry pitch="48"> <name>Analog Tom 5</name> </entry> + <entry pitch="49"> <name>Analog Cymbal</name> </entry> + <entry pitch="50"> <name>Analog Tom 6</name> </entry> + <entry pitch="56"> <name>Analog Cowbell</name> </entry> + <entry pitch="62"> <name>Analog Conga H</name> </entry> + <entry pitch="63"> <name>Analog Conga M</name> </entry> + <entry pitch="64"> <name>Analog Conga L</name> </entry> + <entry pitch="70"> <name>Analog Maracas</name> </entry> + <entry pitch="75"> <name>Analog Claves</name> </entry> + <entry pitch="78"> <name>Scratch Push</name> </entry> + <entry pitch="79"> <name>Scratch Pull</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="32-39" /> + <drummap> + <entry pitch="13"> <name>Mute Surdo</name> </entry> + <entry pitch="14"> <name>Open Surdo</name> </entry> + <entry pitch="15"> <name>High Q</name> </entry> + <entry pitch="16"> <name>Whip Slap</name> </entry> + <entry pitch="17"> <name>Scratch Push</name> </entry> + <entry pitch="18"> <name>Scratch Pull</name> </entry> + <entry pitch="19"> <name>Finger Snap</name> </entry> + <entry pitch="20"> <name>Click Noise</name> </entry> + <entry pitch="21"> <name>Metronome Click</name> </entry> + <entry pitch="22"> <name>Metronome Bell</name> </entry> + <entry pitch="23"> <name>Seq Click L</name> </entry> + <entry pitch="24"> <name>Seq Click H</name> </entry> + <entry pitch="25"> <name>Brush Tap</name> </entry> + <entry pitch="26"> <name>Brush Swirl L</name> </entry> + <entry pitch="27"> <name>Brush Slap</name> </entry> + <entry pitch="28"> <name>Brush Swirl H</name> </entry> + <entry pitch="29"> <name>Snare Roll</name> </entry> + <entry pitch="30"> <name>Castanet</name> </entry> + <entry pitch="31"> <name>Snare L</name> </entry> + <entry pitch="32"> <name>Sticks</name> </entry> + <entry pitch="33"> <name>Bass Drum L</name> </entry> + <entry pitch="34"> <name>Open Rim Shot</name> </entry> + <entry pitch="35"> <name>Bass Drum M</name> </entry> + <entry pitch="36"> <name>Jazz Bass Drum</name> </entry> + <entry pitch="38"> <name>Snare M</name> </entry> + <entry pitch="40"> <name>Snare H</name> </entry> + <entry pitch="41"> <name>Jazz Tom 1</name> </entry> + <entry pitch="43"> <name>Jazz Tom 2</name> </entry> + <entry pitch="45"> <name>Jazz Tom 3</name> </entry> + <entry pitch="47"> <name>Jazz Tom 4</name> </entry> + <entry pitch="48"> <name>Jazz Tom 5</name> </entry> + <entry pitch="50"> <name>Jazz Tom 6</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="40-47" /> + <drummap> + <entry pitch="13"> <name>Mute Surdo</name> </entry> + <entry pitch="14"> <name>Open Surdo</name> </entry> + <entry pitch="15"> <name>High Q</name> </entry> + <entry pitch="16"> <name>Whip Slap</name> </entry> + <entry pitch="17"> <name>Scratch Push</name> </entry> + <entry pitch="18"> <name>Scratch Pull</name> </entry> + <entry pitch="19"> <name>Finger Snap</name> </entry> + <entry pitch="20"> <name>Click Noise</name> </entry> + <entry pitch="21"> <name>Metronome Click</name> </entry> + <entry pitch="22"> <name>Metronome Bell</name> </entry> + <entry pitch="23"> <name>Seq Click L</name> </entry> + <entry pitch="24"> <name>Seq Click H</name> </entry> + <entry pitch="25"> <name>Brush Tap</name> </entry> + <entry pitch="26"> <name>Brush Swirl L</name> </entry> + <entry pitch="27"> <name>Brush Slap</name> </entry> + <entry pitch="28"> <name>Brush Swirl H</name> </entry> + <entry pitch="29"> <name>Snare Roll</name> </entry> + <entry pitch="30"> <name>Castanet</name> </entry> + <entry pitch="31"> <name>Brush Slap L</name> </entry> + <entry pitch="32"> <name>Sticks</name> </entry> + <entry pitch="33"> <name>Bass Drum L</name> </entry> + <entry pitch="34"> <name>Open Rim Shot</name> </entry> + <entry pitch="35"> <name>Bass Drum M</name> </entry> + <entry pitch="36"> <name>Soft Bass Drum</name> </entry> + <entry pitch="38"> <name>Brush Slap</name> </entry> + <entry pitch="40"> <name>Brush Tap</name> </entry> + <entry pitch="41"> <name>Brush Tom 1</name> </entry> + <entry pitch="43"> <name>Brush Tom 2</name> </entry> + <entry pitch="45"> <name>Brush Tom 3</name> </entry> + <entry pitch="47"> <name>Brush Tom 4</name> </entry> + <entry pitch="48"> <name>Brush Tom 5</name> </entry> + <entry pitch="50"> <name>Brush Tom 6</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="127" prog="48-127" /> + <drummap> + <entry pitch="13"> <name>Mute Surdo</name> </entry> + <entry pitch="14"> <name>Open Surdo</name> </entry> + <entry pitch="15"> <name>High Q</name> </entry> + <entry pitch="16"> <name>Whip Slap</name> </entry> + <entry pitch="17"> <name>Scratch Push</name> </entry> + <entry pitch="18"> <name>Scratch Pull</name> </entry> + <entry pitch="19"> <name>Finger Snap</name> </entry> + <entry pitch="20"> <name>Click Noise</name> </entry> + <entry pitch="21"> <name>Metronome Click</name> </entry> + <entry pitch="22"> <name>Metronome Bell</name> </entry> + <entry pitch="23"> <name>Seq Click L</name> </entry> + <entry pitch="24"> <name>Seq Click H</name> </entry> + <entry pitch="25"> <name>Brush Tap</name> </entry> + <entry pitch="26"> <name>Brush Swirl L</name> </entry> + <entry pitch="27"> <name>Brush Slap</name> </entry> + <entry pitch="28"> <name>Brush Swirl H</name> </entry> + <entry pitch="29"> <name>Snare Roll</name> </entry> + <entry pitch="30"> <name>Castanet</name> </entry> + <entry pitch="31"> <name>Snare L</name> </entry> + <entry pitch="32"> <name>Sticks</name> </entry> + <entry pitch="33"> <name>Bass Drum L 2</name> </entry> + <entry pitch="34"> <name>Open Rim Shot</name> </entry> + <entry pitch="35"> <name>Gran Cassa</name> </entry> + <entry pitch="36"> <name>Gran Cassa Mute</name> </entry> + <entry pitch="38"> <name>Marching Snare H</name> </entry> + <entry pitch="40"> <name>Marching Snare M</name> </entry> + <entry pitch="41"> <name>Jazz Tom 1</name> </entry> + <entry pitch="43"> <name>Jazz Tom 2</name> </entry> + <entry pitch="45"> <name>Jazz Tom 3</name> </entry> + <entry pitch="47"> <name>Jazz Tom 4</name> </entry> + <entry pitch="48"> <name>Jazz Tom 5</name> </entry> + <entry pitch="49"> <name>Hand Cym. Open L</name> </entry> + <entry pitch="50"> <name>Jazz Tom 6</name> </entry> + <entry pitch="51"> <name>Hand Cym. Closed L</name> </entry> + <entry pitch="57"> <name>Hand Cym. Open H</name> </entry> + <entry pitch="59"> <name>Hand Cym. Closed H</name> </entry> + <entry pitch="82"> <name>Shaker</name> </entry> + <entry pitch="83"> <name>Jingle Bell</name> </entry> + <entry pitch="84"> <name>Belltree</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="126" prog="0" /> + <drummap> + <entry pitch="35"> <name></name> </entry> + <entry pitch="36"> <name>Guitar Cutting Noise</name> </entry> + <entry pitch="37"> <name>Guitar Cutting Noise 2</name> </entry> + <entry pitch="38"> <name>Dist. Cut Noise</name> </entry> + <entry pitch="39"> <name>String Slap</name> </entry> + <entry pitch="40"> <name>Bass Slide</name> </entry> + <entry pitch="41"> <name>Pick Scrape</name> </entry> + <entry pitch="42"> <name></name> </entry> + <entry pitch="43"> <name></name> </entry> + <entry pitch="44"> <name></name> </entry> + <entry pitch="45"> <name></name> </entry> + <entry pitch="46"> <name></name> </entry> + <entry pitch="47"> <name></name> </entry> + <entry pitch="48"> <name></name> </entry> + <entry pitch="49"> <name></name> </entry> + <entry pitch="50"> <name></name> </entry> + <entry pitch="51"> <name></name> </entry> + <entry pitch="52"> <name>FL.Key Click</name> </entry> + <entry pitch="53"> <name></name> </entry> + <entry pitch="54"> <name></name> </entry> + <entry pitch="55"> <name></name> </entry> + <entry pitch="56"> <name></name> </entry> + <entry pitch="57"> <name></name> </entry> + <entry pitch="58"> <name></name> </entry> + <entry pitch="59"> <name></name> </entry> + <entry pitch="60"> <name></name> </entry> + <entry pitch="61"> <name></name> </entry> + <entry pitch="62"> <name></name> </entry> + <entry pitch="63"> <name></name> </entry> + <entry pitch="64"> <name></name> </entry> + <entry pitch="65"> <name></name> </entry> + <entry pitch="66"> <name></name> </entry> + <entry pitch="67"> <name></name> </entry> + <entry pitch="68"> <name>Rain</name> </entry> + <entry pitch="69"> <name>Thunder</name> </entry> + <entry pitch="70"> <name>Wind</name> </entry> + <entry pitch="71"> <name>Stream</name> </entry> + <entry pitch="72"> <name>Bubble</name> </entry> + <entry pitch="73"> <name>Feed</name> </entry> + <entry pitch="74"> <name></name> </entry> + <entry pitch="75"> <name></name> </entry> + <entry pitch="76"> <name></name> </entry> + <entry pitch="77"> <name></name> </entry> + <entry pitch="78"> <name></name> </entry> + <entry pitch="79"> <name></name> </entry> + <entry pitch="80"> <name></name> </entry> + <entry pitch="81"> <name></name> </entry> + <entry pitch="82"> <name></name> </entry> + <entry pitch="83"> <name></name> </entry> + <entry pitch="84"> <name>Dog</name> </entry> + <entry pitch="85"> <name>Horse Gallop</name> </entry> + <entry pitch="86"> <name>Bird 2</name> </entry> + <entry pitch="87"> <name>Kitty</name> </entry> + <entry pitch="88"> <name>Growl</name> </entry> + <entry pitch="89"> <name>Haunted</name> </entry> + <entry pitch="90"> <name>Ghost</name> </entry> + <entry pitch="91"> <name>Maou</name> </entry> + </drummap> + </entry> + + <entry> + <patch_collection hbank="126" prog="1" /> + <drummap> + <entry pitch="35"> <name></name> </entry> + <entry pitch="36"> <name>Dial Tone</name> </entry> + <entry pitch="37"> <name>Door Creaking</name> </entry> + <entry pitch="38"> <name>Door Slam</name> </entry> + <entry pitch="39"> <name>Scratch</name> </entry> + <entry pitch="40"> <name>Scratch 2</name> </entry> + <entry pitch="41"> <name>Windchime</name> </entry> + <entry pitch="42"> <name>Telephone Ring 2</name> </entry> + <entry pitch="43"> <name></name> </entry> + <entry pitch="44"> <name></name> </entry> + <entry pitch="45"> <name></name> </entry> + <entry pitch="46"> <name></name> </entry> + <entry pitch="47"> <name></name> </entry> + <entry pitch="48"> <name></name> </entry> + <entry pitch="49"> <name></name> </entry> + <entry pitch="50"> <name></name> </entry> + <entry pitch="51"> <name></name> </entry> + <entry pitch="52"> <name>Engine Start</name> </entry> + <entry pitch="53"> <name>Tire Screech</name> </entry> + <entry pitch="54"> <name>Car Passing</name> </entry> + <entry pitch="55"> <name>Crash</name> </entry> + <entry pitch="56"> <name>Siren</name> </entry> + <entry pitch="57"> <name>Train</name> </entry> + <entry pitch="58"> <name>Jetplane</name> </entry> + <entry pitch="59"> <name>Starship</name> </entry> + <entry pitch="60"> <name>Burst Noise</name> </entry> + <entry pitch="61"> <name>Coaster</name> </entry> + <entry pitch="62"> <name>SbMarine</name> </entry> + <entry pitch="63"> <name></name> </entry> + <entry pitch="64"> <name></name> </entry> + <entry pitch="65"> <name></name> </entry> + <entry pitch="66"> <name></name> </entry> + <entry pitch="67"> <name></name> </entry> + <entry pitch="68"> <name>Laughing</name> </entry> + <entry pitch="69"> <name>Screaming</name> </entry> + <entry pitch="70"> <name>Punch</name> </entry> + <entry pitch="71"> <name>Heartbeat</name> </entry> + <entry pitch="72"> <name>Footsteps</name> </entry> + <entry pitch="73"> <name>Applaus2</name> </entry> + <entry pitch="74"> <name></name> </entry> + <entry pitch="75"> <name></name> </entry> + <entry pitch="76"> <name></name> </entry> + <entry pitch="77"> <name></name> </entry> + <entry pitch="78"> <name></name> </entry> + <entry pitch="79"> <name></name> </entry> + <entry pitch="80"> <name></name> </entry> + <entry pitch="81"> <name></name> </entry> + <entry pitch="82"> <name></name> </entry> + <entry pitch="83"> <name></name> </entry> + <entry pitch="84"> <name>Machine Gun</name> </entry> + <entry pitch="85"> <name>Laser Gun</name> </entry> + <entry pitch="86"> <name>Explosion</name> </entry> + <entry pitch="87"> <name>Firework</name> </entry> + </drummap> + </entry> + + </Drummaps> </MidiInstrument> </muse> 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", +" ", +" ", +" ", +" .... ", +" ........ ", +" ... ... ", +" ... ++++ ... ", +"... ++++++ ...", +".. ++++++ ..", +"... ++++++ ...", +" ... ++++ ... ", +" ... ... ", +" ........ ", +" .... ", +" ", +" "}; |