diff options
author | Florian Jung <flo@windfisch.org> | 2012-02-29 15:25:27 +0000 |
---|---|---|
committer | Florian Jung <flo@windfisch.org> | 2012-02-29 15:25:27 +0000 |
commit | a5ced1d15d584b2c4f7489f181224582c38da0f4 (patch) | |
tree | 98a7e3b8b664cf579a834bf2b2e2e1f25fc2cf90 | |
parent | 3a26b16556a49196800298ed4219decc134c7061 (diff) |
changed custom column for "program" to display and edit real patches
instead of the raw values
-rw-r--r-- | muse2/muse/arranger/arranger.cpp | 2 | ||||
-rw-r--r-- | muse2/muse/arranger/tlist.cpp | 146 | ||||
-rw-r--r-- | muse2/muse/arranger/tlist.h | 1 | ||||
-rw-r--r-- | muse2/muse/instruments/minstrument.cpp | 119 | ||||
-rw-r--r-- | muse2/muse/instruments/minstrument.h | 41 | ||||
-rw-r--r-- | muse2/muse/midiedit/scoreedit.cpp | 16 | ||||
-rw-r--r-- | muse2/muse/widgets/arrangercolumns.cpp | 8 | ||||
-rw-r--r-- | muse2/muse/widgets/mtrackinfo.cpp | 15 |
8 files changed, 296 insertions, 52 deletions
diff --git a/muse2/muse/arranger/arranger.cpp b/muse2/muse/arranger/arranger.cpp index ccb3353f..41cbf06f 100644 --- a/muse2/muse/arranger/arranger.cpp +++ b/muse2/muse/arranger/arranger.cpp @@ -559,7 +559,7 @@ void Arranger::updateTListHeader() header->setResizeMode(COL_AUTOMATION, QHeaderView::Interactive); header->setResizeMode(COL_CLEF, QHeaderView::Interactive); for (unsigned i=0;i<custom_columns.size();i++) - header->setResizeMode(COL_CUSTOM_MIDICTRL_OFFSET+i, QHeaderView::Fixed); + header->setResizeMode(COL_CUSTOM_MIDICTRL_OFFSET+i, QHeaderView::Interactive); setHeaderToolTips(); setHeaderWhatsThis(); diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp index 2a1e1d72..212948c7 100644 --- a/muse2/muse/arranger/tlist.cpp +++ b/muse2/muse/arranger/tlist.cpp @@ -62,7 +62,6 @@ #include "midiedit/drummap.h" #include "synth.h" #include "config.h" -#include "popupmenu.h" #include "filedialog.h" #include "menutitleitem.h" #include "arranger.h" @@ -434,9 +433,23 @@ void TList::paint(const QRect& r) int val=mt->getFirstControllerValue(col_ctrl_no,MusECore::CTRL_VAL_UNKNOWN); if (val!=MusECore::CTRL_VAL_UNKNOWN) val-=mctl->bias(); - - p.drawText(r, Qt::AlignVCenter|Qt::AlignHCenter, - (val!=MusECore::CTRL_VAL_UNKNOWN)?QString::number(val):tr("off")); + + if (col_ctrl_no!=MusECore::CTRL_PROGRAM) + { + p.drawText(r, Qt::AlignVCenter|Qt::AlignHCenter, + (val!=MusECore::CTRL_VAL_UNKNOWN)?QString::number(val):tr("off")); + } + else + { + MusECore::MidiInstrument* instr = mp->instrument(); + QString name; + if (val!=MusECore::CTRL_VAL_UNKNOWN) + name = instr->getPatchName(mt->outChannel(), val, MusEGlobal::song->mtype(), mt->isDrumTrack()); + else + name = tr("<unknown>"); + + p.drawText(r, Qt::AlignVCenter|Qt::AlignHCenter, name); + } } } break; @@ -794,26 +807,63 @@ void TList::mouseDoubleClickEvent(QMouseEvent* ev) if (t->isMidiTrack()) { editTrack=t; - if (ctrl_edit==0) { - ctrl_edit=new QSpinBox(this); - ctrl_edit->setSpecialValueText(tr("off")); - connect(ctrl_edit, SIGNAL(editingFinished()), SLOT(ctrlValueFinished())); - } - + ctrl_num=Arranger::custom_columns[section-COL_CUSTOM_MIDICTRL_OFFSET].ctrl; MusECore::MidiTrack* mt=(MusECore::MidiTrack*)t; MusECore::MidiPort* mp = &MusEGlobal::midiPorts[mt->outPort()]; MusECore::MidiController* mctl = mp->midiController(ctrl_num); - ctrl_edit->setMinimum(mctl->minVal()-1); // -1 because of the specialValueText - ctrl_edit->setMaximum(mctl->maxVal()); - ctrl_edit->setValue(((MusECore::MidiTrack*)editTrack)->getFirstControllerValue(ctrl_num)-mctl->bias()); - int w=colw; - if (w < ctrl_edit->sizeHint().width()) w=ctrl_edit->sizeHint().width(); - ctrl_edit->setGeometry(colx, coly, w, colh); - editMode = true; - ctrl_edit->show(); - ctrl_edit->setFocus(); + + if (ctrl_num!=MusECore::CTRL_PROGRAM) + { + if (ctrl_edit==0) + { + ctrl_edit=new QSpinBox(this); + ctrl_edit->setSpecialValueText(tr("off")); + connect(ctrl_edit, SIGNAL(editingFinished()), SLOT(ctrlValueFinished())); + } + + ctrl_edit->setMinimum(mctl->minVal()-1); // -1 because of the specialValueText + ctrl_edit->setMaximum(mctl->maxVal()); + ctrl_edit->setValue(((MusECore::MidiTrack*)editTrack)->getFirstControllerValue(ctrl_num)-mctl->bias()); + int w=colw; + if (w < ctrl_edit->sizeHint().width()) w=ctrl_edit->sizeHint().width(); + ctrl_edit->setGeometry(colx, coly, w, colh); + editMode = true; + ctrl_edit->show(); + ctrl_edit->setFocus(); + } + else + { + MusECore::MidiInstrument* instr = mp->instrument(); + + PopupMenu* pup = new PopupMenu(true); + instr->populatePatchPopup(pup, mt->outChannel(), MusEGlobal::song->mtype(), mt->isDrumTrack()); + + if(pup->actions().count() == 0) + { + delete pup; + return; + } + + connect(pup, SIGNAL(triggered(QAction*)), SLOT(instrPopupActivated(QAction*))); + + QAction *act = pup->exec(ev->globalPos()); + if(act) + { + int val = act->data().toInt(); + if(val != -1) + { + MusECore::Event a(MusECore::Controller); + a.setTick(0); + a.setA(MusECore::CTRL_PROGRAM); + a.setB(val); + MusEGlobal::song->recordEvent(mt, a); + } + } + + delete pup; + } ev->accept(); } } @@ -1899,11 +1949,21 @@ void TList::mousePressEvent(QMouseEvent* ev) int val = mt->getFirstControllerValue(ctrl_num); int oldval=val; - val += delta; - if(val > maxval) - val = maxval; - if(val < minval-1) // "-1" because of "off" - val = minval-1; + + if (ctrl_num!=MusECore::CTRL_PROGRAM) + { + val += delta; + if(val > maxval) + val = maxval; + if(val < minval-1) // "-1" because of "off" + val = minval-1; + } + else + { + MusECore::MidiInstrument* instr = mp->instrument(); + if (delta>0) val=instr->getNextPatch(mt->outChannel(), val, MusEGlobal::song->mtype(), false); + else if (delta<0) val=instr->getPrevPatch(mt->outChannel(), val, MusEGlobal::song->mtype(), false); + } if (val != oldval) { @@ -2334,11 +2394,21 @@ void TList::wheelEvent(QWheelEvent* ev) int val = mt->getFirstControllerValue(ctrl_num); int oldval=val; - val += delta; - if(val > maxval) - val = maxval; - if(val < minval-1) // "-1" because of "off" - val = minval-1; + + if (ctrl_num!=MusECore::CTRL_PROGRAM) + { + val += delta; + if(val > maxval) + val = maxval; + if(val < minval-1) // "-1" because of "off" + val = minval-1; + } + else + { + MusECore::MidiInstrument* instr = mp->instrument(); + if (delta>0) val=instr->getNextPatch(mt->outChannel(), val, MusEGlobal::song->mtype(), false); + else if (delta<0) val=instr->getPrevPatch(mt->outChannel(), val, MusEGlobal::song->mtype(), false); + } if (val != oldval) { @@ -2525,6 +2595,24 @@ void TList::classesPopupMenu(MusECore::Track* t, int x, int y) } } +void TList::instrPopupActivated(QAction* act) +{ + MusECore::MidiTrack* mt = dynamic_cast<MusECore::MidiTrack*>(editTrack); + if(act && mt) + { + int val = act->data().toInt(); + if(val != -1) + { + MusECore::Event a(MusECore::Controller); + a.setTick(0); + a.setA(MusECore::CTRL_PROGRAM); + a.setB(val); + MusEGlobal::song->recordEvent(mt, a); + } + } +} + + void TList::setHeader(Header* h) { header=h; diff --git a/muse2/muse/arranger/tlist.h b/muse2/muse/arranger/tlist.h index 5ea6edb9..a113d221 100644 --- a/muse2/muse/arranger/tlist.h +++ b/muse2/muse/arranger/tlist.h @@ -121,6 +121,7 @@ class TList : public QWidget { void chanValueChanged(int); void chanValueFinished(); void ctrlValueFinished(); + void instrPopupActivated(QAction*); void songChanged(int flags); void changeAutomation(QAction*); void changeAutomationColor(QAction*); diff --git a/muse2/muse/instruments/minstrument.cpp b/muse2/muse/instruments/minstrument.cpp index 1349c9c9..bbb2a076 100644 --- a/muse2/muse/instruments/minstrument.cpp +++ b/muse2/muse/instruments/minstrument.cpp @@ -1103,6 +1103,125 @@ QString MidiInstrument::getPatchName(int channel, int prog, MType mode, bool dru return "<unknown>"; } + + + + + +unsigned MidiInstrument::getNextPatch(int channel, unsigned patch, MType songType, bool drum) +{ + QList<dumb_patchlist_entry_t> haystack=getPatches(channel,songType,drum); + if (haystack.empty()) return MusECore::CTRL_VAL_UNKNOWN; + + int prog=patch&0xFF; + int lbank=(patch>>8)&0xFF; + int hbank=(patch>>16)&0xFF; + + dumb_patchlist_entry_t needle=dumb_patchlist_entry_t(prog, (lbank!=0xFF)?lbank:-1, (hbank!=0xFF)?hbank:-1); + + QList<dumb_patchlist_entry_t>::iterator it; + for (it=haystack.begin(); it!=haystack.end(); it++) + if ((*it) == needle) + break; + + if (it==haystack.end()) //not found? use first entry + it=haystack.begin(); + else + { + for (;it!=haystack.end(); it++) + if ((*it)!=needle) + break; + if (it==haystack.end()) it=haystack.begin(); //wrap-over + } + + return (it->prog&0xFF) | + ((((it->lbank==-1)?0xFF:it->lbank)<<8)&0xFF00) | + ((((it->hbank==-1)?0xFF:it->hbank)<<16)&0xFF0000); +} + +unsigned MidiInstrument::getPrevPatch(int channel, unsigned patch, MType songType, bool drum) +{ + QList<dumb_patchlist_entry_t> haystack=getPatches(channel,songType,drum); + if (haystack.empty()) return MusECore::CTRL_VAL_UNKNOWN; + + int prog=patch&0xFF; + int lbank=(patch>>8)&0xFF; + int hbank=(patch>>16)&0xFF; + + dumb_patchlist_entry_t needle=dumb_patchlist_entry_t(prog, (lbank!=0xFF)?lbank:-1, (hbank!=0xFF)?hbank:-1); + + QList<dumb_patchlist_entry_t>::iterator it; + for (it=haystack.begin(); it!=haystack.end(); it++) + if ((*it) == needle) + break; + + if (it==haystack.end()) //not found? use first entry + it=haystack.begin(); + else + { + if (it==haystack.begin()) it=haystack.end(); //wrap-over + it--; + } + + return (it->prog&0xFF) | + ((((it->lbank==-1)?0xFF:it->lbank)<<8)&0xFF00) | + ((((it->hbank==-1)?0xFF:it->hbank)<<16)&0xFF0000); +} + +QList<dumb_patchlist_entry_t> MidiInstrument::getPatches(int channel, MType mode, bool drum) + { + int tmask = 1; + bool drumchan = channel == 9; + bool hb = false; + bool lb = false; + switch (mode) { + case MT_GS: + tmask = 2; + hb = true; + break; + case MT_XG: + hb = true; + lb = true; + tmask = 4; + break; + case MT_GM: + if(drumchan) + { + QList<dumb_patchlist_entry_t> tmp; + tmp.push_back(dumb_patchlist_entry_t(0,-1,-1)); + } + else + tmask = 1; + break; + default: + hb = true; // MSB bank matters + lb = true; // LSB bank matters + break; + } + + + QList<dumb_patchlist_entry_t> tmp; + + for (ciPatchGroup i = pg.begin(); i != pg.end(); ++i) { + const PatchList& pl = (*i)->patches; + for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) { + const Patch* mp = *ipl; + if ((mp->typ & tmask) && + ((drum && mode != MT_GM) || + (mp->drum == drumchan)) ) + { + int prog = mp->prog; + int lbank = (mp->lbank==-1 || !lb) ? -1 : mp->lbank; + int hbank = (mp->hbank==-1 || !hb) ? -1 : mp->hbank; + tmp.push_back(dumb_patchlist_entry_t(prog,lbank,hbank)); + } + } + } + + return tmp; + } + + //--------------------------------------------------------- // populatePatchPopup //--------------------------------------------------------- diff --git a/muse2/muse/instruments/minstrument.h b/muse2/muse/instruments/minstrument.h index f793a7b6..823b9895 100644 --- a/muse2/muse/instruments/minstrument.h +++ b/muse2/muse/instruments/minstrument.h @@ -122,6 +122,44 @@ struct patch_drummap_mapping_t patch_drummap_mapping_t& operator=(const patch_drummap_mapping_t& that); }; +struct dumb_patchlist_entry_t +{ + int prog; + int lbank; + int hbank; // "-1" means "unused" + + dumb_patchlist_entry_t(int p, int l, int h) + { + prog=p; + lbank=l; + hbank=h; + } + + bool operator<(const dumb_patchlist_entry_t& other) const + { + if (hbank < other.hbank) return true; + if (hbank > other.hbank) return false; + if (lbank < other.lbank) return true; + if (lbank > other.lbank) return false; + return (prog < other.prog); + } + + bool operator>(const dumb_patchlist_entry_t& other) const + { + return other < *this; + } + + bool operator==(const dumb_patchlist_entry_t& other) const + { + return (prog==other.prog && lbank==other.lbank && hbank==other.hbank); + } + + bool operator!=(const dumb_patchlist_entry_t& other) const + { + return (!(*this==other)); + } +}; + //--------------------------------------------------------- // MidiInstrument //--------------------------------------------------------- @@ -172,6 +210,9 @@ class MidiInstrument { void addSysex(SysEx* sysex) { _sysex.append(sysex); } const DrumMap* drummap_for_patch(int patch) const; + QList<dumb_patchlist_entry_t> getPatches(int channel, MType songType, bool drum); + unsigned getNextPatch(int channel, unsigned patch, MType songType, bool drum); + unsigned getPrevPatch(int channel, unsigned patch, MType songType, bool drum); EventList* midiInit() const { return _midiInit; } EventList* midiReset() const { return _midiReset; } diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index 2bbdda9c..955a73d0 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -4650,11 +4650,19 @@ 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 ] - * - * CURRENT TODO * o test drum controllers * o test old- and new drumtrack recording, steprecording * + * CURRENT TODO + * o column's widths aren't stored into configuration. fix that. + * o automatically send controller changes by the arranger columns + * if necessary (i.e., if no later controller overrides this) + * o make custom columns only look at CCs at tick0, not at "the firstCC" + * beacuse this probably causes confusion. + * o custom columns should also be able to store at cpos, not only at tick0 + * o storing <no_toplevels /> into a template file seems to ignore + * the arranger's "MDI-ness", sets is at subwin all the time! + * * o add controller editor "like search-and-replace": * acts on all specified type's events, and edits the value: * - apply some MIN or MAX on it @@ -4662,10 +4670,6 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo * - offset it * - only act on values in a certain value range * - maybe do curve-mapping - * o add "volume", "pan", "prog" etc columns to the arranger. - * ideally make them fully configurable: let the user add any - * controller together with any column label to the list. - * these will just set the controller at the very first tick. * o remove the silly song type! * o remove the song length spinbox * o logical/physical device mapping: diff --git a/muse2/muse/widgets/arrangercolumns.cpp b/muse2/muse/widgets/arrangercolumns.cpp index 883ba08c..5510e69c 100644 --- a/muse2/muse/widgets/arrangercolumns.cpp +++ b/muse2/muse/widgets/arrangercolumns.cpp @@ -33,7 +33,7 @@ ArrangerColumns::ArrangerColumns(QWidget* parent) : QDialog(parent) initList(); - connect(ctrlType,SIGNAL(activated(int)), SLOT(ctrlTypeChanged(int))); + connect(ctrlType,SIGNAL(currentIndexChanged(int)), SLOT(ctrlTypeChanged(int))); // connect(ctrlType,SIGNAL(activated(int)), SLOT(somethingChanged())); // called by ctrlTypeChanged connect(nameEdit,SIGNAL(textEdited(const QString&)), SLOT(somethingChanged())); connect(spinBoxHCtrlNo,SIGNAL(valueChanged(int)), SLOT(somethingChanged())); @@ -42,7 +42,11 @@ ArrangerColumns::ArrangerColumns(QWidget* parent) : QDialog(parent) connect(addBtn,SIGNAL(clicked()), SLOT(addEntry())); connect(delBtn,SIGNAL(clicked()), SLOT(delEntry())); - somethingChanged(); + if (listWidget->count()!=0) + listWidget->setCurrentRow(0); + else + itemSelected(-1); + ctrlTypeChanged(ctrlType->currentIndex()); } diff --git a/muse2/muse/widgets/mtrackinfo.cpp b/muse2/muse/widgets/mtrackinfo.cpp index f9d0e5a9..c02bd7f1 100644 --- a/muse2/muse/widgets/mtrackinfo.cpp +++ b/muse2/muse/widgets/mtrackinfo.cpp @@ -342,15 +342,9 @@ void MidiTrackInfo::heartBeat() nprogram = mp->lastValidHWCtrlState(outChannel, MusECore::CTRL_PROGRAM); if(nprogram == MusECore::CTRL_VAL_UNKNOWN) { - //const char* n = "<unknown>"; const QString n(tr("<unknown>")); - //if(strcmp(iPatch->text().toLatin1().constData(), n) != 0) if(iPatch->text() != n) - { - //printf("Arranger::midiTrackInfoHeartBeat setting patch <unknown>\n"); - iPatch->setText(n); - } } else { @@ -362,13 +356,8 @@ void MidiTrackInfo::heartBeat() if(iPatch->text() != n) iPatch->setText(n); } - else - if(iPatch->text() != name) - { - //printf("Arranger::midiTrackInfoHeartBeat setting patch name\n"); - + else if(iPatch->text() != name) iPatch->setText(name); - } } } else @@ -1101,11 +1090,9 @@ void MidiTrackInfo::instrPopup() int channel = track->outChannel(); int port = track->outPort(); MusECore::MidiInstrument* instr = MusEGlobal::midiPorts[port].instrument(); - //QMenu* pup = new QMenu; PopupMenu* pup = new PopupMenu(true); instr->populatePatchPopup(pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); - //populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); if(pup->actions().count() == 0) { |