summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2012-02-29 15:25:27 +0000
committerFlorian Jung <flo@windfisch.org>2012-02-29 15:25:27 +0000
commita5ced1d15d584b2c4f7489f181224582c38da0f4 (patch)
tree98a7e3b8b664cf579a834bf2b2e2e1f25fc2cf90
parent3a26b16556a49196800298ed4219decc134c7061 (diff)
changed custom column for "program" to display and edit real patches
instead of the raw values
-rw-r--r--muse2/muse/arranger/arranger.cpp2
-rw-r--r--muse2/muse/arranger/tlist.cpp146
-rw-r--r--muse2/muse/arranger/tlist.h1
-rw-r--r--muse2/muse/instruments/minstrument.cpp119
-rw-r--r--muse2/muse/instruments/minstrument.h41
-rw-r--r--muse2/muse/midiedit/scoreedit.cpp16
-rw-r--r--muse2/muse/widgets/arrangercolumns.cpp8
-rw-r--r--muse2/muse/widgets/mtrackinfo.cpp15
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)
{