summaryrefslogtreecommitdiff
path: root/muse2
diff options
context:
space:
mode:
Diffstat (limited to 'muse2')
-rw-r--r--muse2/ChangeLog15
-rw-r--r--muse2/muse/app.cpp4
-rw-r--r--muse2/muse/arranger/tlist.cpp7
-rw-r--r--muse2/muse/audio.cpp2
-rw-r--r--muse2/muse/audio.h4
-rw-r--r--muse2/muse/conf.cpp9
-rw-r--r--muse2/muse/confmport.cpp25
-rw-r--r--muse2/muse/confmport.h3
-rw-r--r--muse2/muse/ctrl/ctrlcanvas.cpp216
-rw-r--r--muse2/muse/ctrl/ctrlcanvas.h3
-rw-r--r--muse2/muse/ctrl/ctrlpanel.cpp593
-rw-r--r--muse2/muse/ctrl/ctrlpanel.h2
-rw-r--r--muse2/muse/gconfig.cpp3
-rw-r--r--muse2/muse/gconfig.h3
-rw-r--r--muse2/muse/helper.cpp203
-rw-r--r--muse2/muse/helper.h5
-rw-r--r--muse2/muse/icons.cpp10
-rw-r--r--muse2/muse/icons.h2
-rw-r--r--muse2/muse/midi.cpp54
-rw-r--r--muse2/muse/mididev.cpp143
-rw-r--r--muse2/muse/mididev.h4
-rw-r--r--muse2/muse/midiedit/drumedit.cpp202
-rw-r--r--muse2/muse/midiedit/drumedit.h10
-rw-r--r--muse2/muse/midiedit/pianoroll.cpp222
-rw-r--r--muse2/muse/midiedit/pianoroll.h9
-rw-r--r--muse2/muse/midiport.cpp243
-rw-r--r--muse2/muse/midiport.h12
-rw-r--r--muse2/muse/midiseq.cpp5
-rw-r--r--muse2/muse/mpevent.cpp6
-rw-r--r--muse2/muse/route.cpp3
-rw-r--r--muse2/muse/seqmsg.cpp75
-rw-r--r--muse2/muse/song.cpp4
-rw-r--r--muse2/muse/widgets/CMakeLists.txt5
-rw-r--r--muse2/muse/widgets/genset.cpp6
-rw-r--r--muse2/muse/widgets/gensetbase.ui192
-rw-r--r--muse2/muse/widgets/knob.h4
-rw-r--r--muse2/muse/widgets/knob_and_meter.cpp609
-rw-r--r--muse2/muse/widgets/knob_and_meter.h114
-rw-r--r--muse2/muse/widgets/midi_warn_init_pending.ui119
-rw-r--r--muse2/muse/widgets/midi_warn_init_pending_impl.cpp33
-rw-r--r--muse2/muse/widgets/midi_warn_init_pending_impl.h40
-rw-r--r--muse2/muse/widgets/musewidgetsplug.cpp3
-rw-r--r--muse2/muse/widgets/synthconfigbase.ui153
-rw-r--r--muse2/share/templates/MusE.cfg167
-rw-r--r--muse2/xpm/bluedot.xpm49
-rw-r--r--muse2/xpm/checksquare.xpm34
-rw-r--r--muse2/xpm/greendot.xpm44
-rw-r--r--muse2/xpm/orangedot.xpm21
48 files changed, 2810 insertions, 884 deletions
diff --git a/muse2/ChangeLog b/muse2/ChangeLog
index 9494ba7d..365ef501 100644
--- a/muse2/ChangeLog
+++ b/muse2/ChangeLog
@@ -1,3 +1,18 @@
+19.10.2012:
+ * Improved: Midi initializations. New settings options, can be 'quiet'. Complete rewrite of initializations coding. (Tim)
+ * Improved: Midi controller graphs: Control selector 'S' popup now stay-open, AND NOW with multi-coloured dots:
+ Blank: Controller has no current 'manual' value (it is 'Off'), and no stored automation values.
+ Blue: Controller has a current 'manual' value (it is not 'Off'), but no stored automation values.
+ Green: Controller has no current 'manual' value, but does have stored automation values.
+ Gold: Controller has a current 'manual' value AND has stored automation values.
+ Bonus! Pianoroll and drum edit 'Ctrl' buttons ALSO now popup this very same menu. No more clumsy
+ adding of controllers - now just hold the ctrl key and select away and... "bing bing bing 1 2 3". (Tim)
+ * Improved: 'Old' drum track 'drum controllers' display and operation: Fixed several problems: Incorrect mapping to drum map etc. (Tim)
+ Now if more than one drum is pointing to the same 'anote', the others are overlaid as grey slivers. (TODO Not quite done.)
+ TODO: Although THESE "drum controllers" are improved, there are conceptual problems with NON-drum controllers old drum map:
+ If a NON-drum controller such as pan is adjusted, what then? If the drum map contains more than one port/channel/anote
+ it should be sent to ALL of them BUT we would like a 'track override' which when turned off, 'pan' could be locally
+ adjusted for EACH drum having different ports/channels/anotes. (So in theory drum track channel should be reinstated.)
09.10.2012:
- Fixed old fluidsynth bug: Drum patch numbers incorrect. (Tim)
Confusion due to special fluidsynth drum bank = 129. Changed FluidSynth::getFirstPatch,
diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp
index dd94f743..296b4eff 100644
--- a/muse2/muse/app.cpp
+++ b/muse2/muse/app.cpp
@@ -1107,6 +1107,9 @@ void MusE::loadProjectFile(const QString& name, bool songTemplate, bool doReadMi
QApplication::restoreOverrideCursor();
+ // Prompt and send init sequences.
+ MusEGlobal::audio->msgInitMidiDevices(false);
+
if (MusEGlobal::song->getSongInfo().length()>0 && MusEGlobal::song->showSongInfoOnStartup()) {
startSongInfo(false);
}
@@ -1285,7 +1288,6 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool doReadM
}
}
}
-
}
//---------------------------------------------------------
diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp
index dc65b0c1..b3be35ea 100644
--- a/muse2/muse/arranger/tlist.cpp
+++ b/muse2/muse/arranger/tlist.cpp
@@ -369,7 +369,7 @@ void TList::paint(const QRect& r)
drawCenteredPixmap(p, blacksquareIcon, r);
else
if (track->solo())
- drawCenteredPixmap(p, bluedotIcon, r);
+ drawCenteredPixmap(p, checkSquareIcon, r);
break;
case COL_TIMELOCK:
if (track->isMidiTrack()
@@ -1151,7 +1151,10 @@ void TList::portsPopupMenu(MusECore::Track* t, int x, int y)
MusEGlobal::audio->msgIdle(false);
MusEGlobal::audio->msgUpdateSoloStates(); // (p4.0.14) p4.0.17
MusEGlobal::song->update(SC_MIDI_TRACK_PROP); //
- }
+ }
+
+ // Prompt and send init sequences.
+ MusEGlobal::audio->msgInitMidiDevices(false);
}
break;
diff --git a/muse2/muse/audio.cpp b/muse2/muse/audio.cpp
index b03366e1..b9f1ee8c 100644
--- a/muse2/muse/audio.cpp
+++ b/muse2/muse/audio.cpp
@@ -706,7 +706,7 @@ void Audio::processMsg(AudioMsg* msg)
}
break;
case SEQM_INIT_DEVICES:
- initDevices();
+ initDevices(msg->a);
break;
case SEQM_MIDI_LOCAL_OFF:
sendLocalOff();
diff --git a/muse2/muse/audio.h b/muse2/muse/audio.h
index 7c3d73ce..a403e5bf 100644
--- a/muse2/muse/audio.h
+++ b/muse2/muse/audio.h
@@ -278,7 +278,7 @@ class Audio {
void msgUndo();
void msgRedo();
void msgLocalOff();
- void msgInitMidiDevices();
+ void msgInitMidiDevices(bool force = true);
void msgResetMidiDevices();
void msgIdle(bool);
void msgBounce();
@@ -330,7 +330,7 @@ class Audio {
bool freewheel() const { return _freewheel; }
void setFreewheel(bool val);
int getFrameOffset() const { return frameOffset; }
- void initDevices();
+ void initDevices(bool force = true);
AudioOutput* audioMaster() const { return _audioMaster; }
AudioOutput* audioMonitor() const { return _audioMonitor; }
diff --git a/muse2/muse/conf.cpp b/muse2/muse/conf.cpp
index 21a50e3d..4c14cff0 100644
--- a/muse2/muse/conf.cpp
+++ b/muse2/muse/conf.cpp
@@ -888,6 +888,12 @@ void readConfiguration(Xml& xml, bool doReadMidiPortConfig, bool doReadGlobalCon
MusEGlobal::config.guiDivision = xml.parseInt();
else if (tag == "rtcTicks")
MusEGlobal::config.rtcTicks = xml.parseInt();
+ else if (tag == "midiSendInit")
+ MusEGlobal::config.midiSendInit = xml.parseInt();
+ else if (tag == "warnInitPending")
+ MusEGlobal::config.warnInitPending = xml.parseInt();
+ else if (tag == "midiSendCtlDefaults")
+ MusEGlobal::config.midiSendCtlDefaults = xml.parseInt();
else if (tag == "minMeter")
MusEGlobal::config.minMeter = xml.parseInt();
else if (tag == "minSlider")
@@ -1206,6 +1212,9 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const
xml.intTag(level, "division", MusEGlobal::config.division);
xml.intTag(level, "rtcTicks", MusEGlobal::config.rtcTicks);
+ xml.intTag(level, "midiSendInit", MusEGlobal::config.midiSendInit);
+ xml.intTag(level, "warnInitPending", MusEGlobal::config.warnInitPending);
+ xml.intTag(level, "midiSendCtlDefaults", MusEGlobal::config.midiSendCtlDefaults);
xml.intTag(level, "minMeter", MusEGlobal::config.minMeter);
xml.doubleTag(level, "minSlider", MusEGlobal::config.minSlider);
xml.intTag(level, "freewheelMode", MusEGlobal::config.freewheelMode);
diff --git a/muse2/muse/confmport.cpp b/muse2/muse/confmport.cpp
index cd5c95e9..b0e68b09 100644
--- a/muse2/muse/confmport.cpp
+++ b/muse2/muse/confmport.cpp
@@ -69,12 +69,33 @@ enum { DEVCOL_NO = 0, DEVCOL_GUI, DEVCOL_REC, DEVCOL_PLAY, DEVCOL_INSTR, DEVCOL_
//---------------------------------------------------------
// closeEvent
//---------------------------------------------------------
+
void MPConfig::closeEvent(QCloseEvent *event)
{
+ apply();
QSettings settings("MusE", "MusE-qt");
settings.setValue("MPConfig/geometry", saveGeometry());
QWidget::closeEvent(event);
}
+
+//---------------------------------------------------------
+// apply
+//---------------------------------------------------------
+
+void MPConfig::apply()
+{
+ MusEGlobal::audio->msgInitMidiDevices(false); // false = Don't force
+}
+
+//---------------------------------------------------------
+// okClicked
+//---------------------------------------------------------
+
+void MPConfig::okClicked()
+{
+ close();
+}
+
//---------------------------------------------------------
// changeDefInputRoutes
//---------------------------------------------------------
@@ -1116,6 +1137,10 @@ MPConfig::MPConfig(QWidget* parent)
connect(synthList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), SLOT(addInstanceClicked()));
connect(removeInstance, SIGNAL(clicked()), SLOT(removeInstanceClicked()));
connect(instanceList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), SLOT(removeInstanceClicked()));
+
+ connect(applyButton, SIGNAL(clicked()), SLOT(apply()));
+ connect(okButton, SIGNAL(clicked()), SLOT(okClicked()));
+
songChanged(SC_CONFIG);
}
diff --git a/muse2/muse/confmport.h b/muse2/muse/confmport.h
index 04147090..39e29bb6 100644
--- a/muse2/muse/confmport.h
+++ b/muse2/muse/confmport.h
@@ -68,6 +68,9 @@ class MPConfig : public QDialog, Ui::SynthConfigBase {
void removeInstanceClicked();
void changeDefInputRoutes(QAction* act);
void changeDefOutputRoutes(QAction* act);
+ void apply();
+ void okClicked();
+
public slots:
void closeEvent(QCloseEvent*e);
diff --git a/muse2/muse/ctrl/ctrlcanvas.cpp b/muse2/muse/ctrl/ctrlcanvas.cpp
index 1b243204..1774174f 100644
--- a/muse2/muse/ctrl/ctrlcanvas.cpp
+++ b/muse2/muse/ctrl/ctrlcanvas.cpp
@@ -40,6 +40,7 @@
#include "ctrlpanel.h"
#include "midiedit/drummap.h"
#include "drumedit.h"
+#include "drummap.h"
static MusECore::MidiCtrlValList veloList(MusECore::CTRL_VELOCITY); // dummy
@@ -513,13 +514,13 @@ void CtrlCanvas::partControllers(const MusECore::MidiPart* part, int num, int* d
if(!mt->isDrumTrack() && curDrumPitch != -1)
printf("keyfilter != -1 in non drum track?\n");
- if((mt->type() == MusECore::Track::DRUM) && (curDrumPitch > 0) && ((num & 0xff) == 0xff))
+ if((mt->type() == MusECore::Track::DRUM) && (curDrumPitch >= 0) && ((num & 0xff) == 0xff))
{
di = (num & ~0xff) | curDrumPitch;
n = (num & ~0xff) | MusEGlobal::drumMap[curDrumPitch].anote; // 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?
+ 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;
@@ -598,7 +599,7 @@ void CtrlCanvas::updateItems()
if(_cnum == MusECore::CTRL_VELOCITY && e.type() == MusECore::Note)
{
newev = 0;
- if (curDrumPitch == -1) // and NOT >0
+ 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.
@@ -609,8 +610,40 @@ void CtrlCanvas::updateItems()
if(newev && e.selected())
selection.push_back(newev);
}
- else if (e.type() == MusECore::Controller && e.dataA() == _didx)
+ else if (e.type() == MusECore::Controller)
{
+ int ctl = e.dataA();
+ if(part->track() && part->track()->type() == MusECore::Track::DRUM && (_cnum & 0xff) == 0xff)
+ {
+ //MusECore::MidiPort* port = &MusEGlobal::midiPorts[part->track()->outPort()];
+ if(curDrumPitch < 0)
+ //if(curDrumPitch >= 0)
+ continue;
+
+ //{
+ //MusECore::MidiPort* port = &MusEGlobal::midiPorts[MusEGlobal::drumMap[curDrumPitch].port];
+ //MusECore::MidiPort* port = &MusEGlobal::midiPorts[MusEGlobal::drumMap[ctl & 0x7f].port];
+ int port = MusEGlobal::drumMap[ctl & 0x7f].port;
+ int chan = MusEGlobal::drumMap[ctl & 0x7f].channel;
+ //MusECore::MidiPort* cur_port = &MusEGlobal::midiPorts[MusEGlobal::drumMap[curDrumPitch].port];
+ int cur_port = MusEGlobal::drumMap[curDrumPitch].port;
+ int cur_chan = MusEGlobal::drumMap[curDrumPitch].channel;
+ if((port != cur_port) || (chan != cur_chan))
+ continue;
+ // Is it a drum controller event, according to the track port's instrument?
+ //MusECore::MidiController *mc = port->drumController(ctl);
+ //if(!mc)
+ // continue;
+ //if(mc)
+ //{
+ //if(MusEGlobal::drumMap[ctl & 0x7f].channel != e.
+ // continue;
+ ctl = (ctl & ~0xff) | MusEGlobal::drumMap[ctl & 0x7f].anote;
+ //}
+ //}
+ }
+ if(ctl == _dnum)
+ {
if(mcvl && last.empty())
{
lastce = new CEvent(MusECore::Event(), part, mcvl->value(part->tick()));
@@ -624,6 +657,7 @@ void CtrlCanvas::updateItems()
if(e.selected())
selection.push_back(lastce);
last = e;
+ }
}
}
}
@@ -1577,18 +1611,23 @@ void CtrlCanvas::pdrawItems(QPainter& p, const QRect& rect, const MusECore::Midi
MusECore::MidiTrack* mt = part->track();
MusECore::MidiPort* mp;
+ int cnum = _cnum;
+ bool is_drum_ctl = (mt->type() == MusECore::Track::DRUM) && (curDrumPitch >= 0) && ((_cnum & 0xff) == 0xff);
- if((mt->type() == MusECore::Track::DRUM) && (curDrumPitch > 0) && ((_cnum & 0xff) == 0xff))
- mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[curDrumPitch].port];
+ if(is_drum_ctl)
+ {
+ mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[curDrumPitch].port];
+ cnum = (_cnum & ~0xff) | MusEGlobal::drumMap[curDrumPitch].anote;
+ }
else
mp = &MusEGlobal::midiPorts[mt->outPort()];
- MusECore::MidiController* mc = mp->midiController(_cnum);
+ MusECore::MidiController* mc = mp->midiController(cnum);
int min;
int max;
int bias;
- if(_cnum == MusECore::CTRL_PROGRAM)
+ if(cnum == MusECore::CTRL_PROGRAM)
{
min = 1;
max = 128;
@@ -1609,14 +1648,15 @@ void CtrlCanvas::pdrawItems(QPainter& p, const QRect& rect, const MusECore::Midi
CEvent* e = *i;
// Draw unselected part controller events (lines) on top of selected part events (bars).
if(e->part() != part)
- {
continue;
- }
MusECore::Event ev = e->event();
+ // Draw drum controllers from another drum on top of ones from this drum.
+ if(is_drum_ctl && ev.type() == MusECore::Controller && ev.dataA() != _didx)
+ continue;
int tick = mapx(!ev.empty() ? ev.tick() + e->part()->tick() : 0);
int val = e->val();
int pval = val;
- if(_cnum == MusECore::CTRL_PROGRAM)
+ if(cnum == MusECore::CTRL_PROGRAM)
{
if((val & 0xff) == 0xff)
// What to do here? prog = 0xff should not be allowed, but may still be encountered.
@@ -1629,7 +1669,7 @@ void CtrlCanvas::pdrawItems(QPainter& p, const QRect& rect, const MusECore::Midi
lval = MusECore::CTRL_VAL_UNKNOWN;
else
{
- if(_cnum == MusECore::CTRL_PROGRAM)
+ if(cnum == MusECore::CTRL_PROGRAM)
lval = wh - ((pval - min - bias) * wh / (max - min));
else
lval = wh - ((val - min - bias) * wh / (max - min));
@@ -1662,7 +1702,7 @@ void CtrlCanvas::pdrawItems(QPainter& p, const QRect& rect, const MusECore::Midi
lval = MusECore::CTRL_VAL_UNKNOWN;
else
{
- if(_cnum == MusECore::CTRL_PROGRAM)
+ if(cnum == MusECore::CTRL_PROGRAM)
lval = wh - ((pval - min - bias) * wh / (max - min));
else
lval = wh - ((val - min - bias) * wh / (max - min));
@@ -1689,6 +1729,123 @@ void CtrlCanvas::pdrawItems(QPainter& p, const QRect& rect, const MusECore::Midi
}
//---------------------------------------------------------
+// pdrawExtraDrumCtrlItems
+//---------------------------------------------------------
+
+void CtrlCanvas::pdrawExtraDrumCtrlItems(QPainter& p, const QRect& rect, const MusECore::MidiPart* part, int drum_ctl)
+{
+ int x = rect.x() - 1; // compensate for 3 pixel line width
+ int w = rect.width() + 2;
+ int wh = height();
+
+ noEvents=true;
+
+ {
+ if(!part)
+ return;
+
+ MusECore::MidiTrack* mt = part->track();
+ MusECore::MidiPort* mp;
+ int cnum = _cnum;
+ bool is_drum_ctl = (mt->type() == MusECore::Track::DRUM) && (curDrumPitch >= 0) && ((_cnum & 0xff) == 0xff);
+
+ if(is_drum_ctl)
+ {
+ mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[curDrumPitch].port];
+ cnum = (_cnum & ~0xff) | MusEGlobal::drumMap[curDrumPitch].anote;
+ }
+ else
+ mp = &MusEGlobal::midiPorts[mt->outPort()];
+
+ MusECore::MidiController* mc = mp->midiController(cnum);
+
+ int min;
+ int max;
+ int bias;
+ if(cnum == MusECore::CTRL_PROGRAM)
+ {
+ min = 1;
+ max = 128;
+ bias = 0;
+ }
+ else
+ {
+ min = mc->minVal();
+ max = mc->maxVal();
+ bias = mc->bias();
+ }
+ int x1 = rect.x();
+ int lval = MusECore::CTRL_VAL_UNKNOWN;
+ //bool selected = false;
+ for (iCEvent i = items.begin(); i != items.end(); ++i)
+ {
+ noEvents=false;
+ CEvent* e = *i;
+ // Draw unselected part controller events (lines) on top of selected part events (bars).
+ if(e->part() != part)
+ continue;
+ MusECore::Event ev = e->event();
+ // Draw drum controllers from another drum on top of ones from this drum.
+ // FIXME TODO Finish this off, not correct yet.
+ if(drum_ctl == -1 && is_drum_ctl && ev.type() == MusECore::Controller && ev.dataA() != _didx)
+ continue;
+ if(drum_ctl != -1 && (!is_drum_ctl || (ev.type() == MusECore::Controller && ev.dataA() == _didx)))
+ continue;
+ int tick = mapx(!ev.empty() ? ev.tick() + e->part()->tick() : 0);
+ int val = e->val();
+ int pval = val;
+ if(cnum == MusECore::CTRL_PROGRAM)
+ {
+ if((val & 0xff) == 0xff)
+ // What to do here? prog = 0xff should not be allowed, but may still be encountered.
+ pval = 1;
+ else
+ pval = (val & 0x7f) + 1;
+ }
+ if (tick <= x) {
+ if (val == MusECore::CTRL_VAL_UNKNOWN)
+ lval = MusECore::CTRL_VAL_UNKNOWN;
+ else
+ {
+ if(cnum == MusECore::CTRL_PROGRAM)
+ lval = wh - ((pval - min - bias) * wh / (max - min));
+ else
+ lval = wh - ((val - min - bias) * wh / (max - min));
+ }
+ //selected = e->selected();
+ continue;
+ }
+ if (tick > x+w)
+ break;
+
+ if (lval != MusECore::CTRL_VAL_UNKNOWN)
+ {
+ p.setPen(Qt::gray);
+ p.drawLine(x1, lval, tick, lval);
+ }
+
+ x1 = tick;
+ if (val == MusECore::CTRL_VAL_UNKNOWN)
+ lval = MusECore::CTRL_VAL_UNKNOWN;
+ else
+ {
+ if(cnum == MusECore::CTRL_PROGRAM)
+ lval = wh - ((pval - min - bias) * wh / (max - min));
+ else
+ lval = wh - ((val - min - bias) * wh / (max - min));
+ }
+ //selected = e->selected();
+ }
+
+ if (lval != MusECore::CTRL_VAL_UNKNOWN)
+ {
+ p.setPen(Qt::gray);
+ p.drawLine(x1, lval, x + w, lval);
+ }
+ }
+}
+
+//---------------------------------------------------------
// pdraw
//---------------------------------------------------------
@@ -1744,6 +1901,21 @@ void CtrlCanvas::pdraw(QPainter& p, const QRect& rect)
// Draw items for all parts - other than current part
pdrawItems(p, rect, part, velo, !velo);
}
+
+ // Special: Draw fg drum controller items for non-current selected drum, for the current part
+ // FIXME TODO Finish this off, not correct yet.
+ if(curPart && curPart->track() && curPart->track()->type() == MusECore::Track::DRUM &&
+ curDrumPitch >= 0 && ((_cnum & 0xff) == 0xff))
+ {
+ int port = MusEGlobal::drumMap[curDrumPitch].port;
+ int anote = MusEGlobal::drumMap[curDrumPitch].anote;
+ for(int i = 0; i < DRUM_MAPSIZE; ++i)
+ {
+ if(i != curDrumPitch && MusEGlobal::drumMap[i].port == port && MusEGlobal::drumMap[i].anote == anote)
+ pdrawExtraDrumCtrlItems(p, rect, curPart, anote);
+ }
+ }
+
if(velo)
{
// Draw fg velocity items for the current part
@@ -1883,24 +2055,6 @@ void CtrlCanvas::setCurDrumPitch(int instrument)
else
curDrumPitch = -2; // this means "invalid", but not "unused"
}
-
- // DELETETHIS
- //printf("CtrlCanvas::setCurDrumPitch curDrumPitch:%d\n", curDrumPitch);
-
- //
- // check if current controller is only valid for
- // a specific drum instrument
- //
- // Removed by T356.
- //if(curTrack && (curTrack->type() == MusECore::Track::DRUM) && ((_controller->num() & 0xff) == 0xff)) {
- //if(curTrack && (curTrack->type() == MusECore::Track::DRUM) && ((_cnum & 0xff) == 0xff)) {
- // reset to default
- // TODO: check, if new drum instrument has a similar controller
- // configured
- // _cnum = MusECore::CTRL_VELOCITY;
- // }
- // Removed by T356
- //songChanged(-1);
}
void CtrlCanvas::curPartHasChanged(MusECore::Part*)
diff --git a/muse2/muse/ctrl/ctrlcanvas.h b/muse2/muse/ctrl/ctrlcanvas.h
index e38edc22..d1ee2e04 100644
--- a/muse2/muse/ctrl/ctrlcanvas.h
+++ b/muse2/muse/ctrl/ctrlcanvas.h
@@ -132,7 +132,8 @@ class CtrlCanvas : public MusEGui::View {
void deleteVal(int x1, int x2, int y);
bool setCurTrackAndPart();
- void pdrawItems(QPainter&, const QRect&, const MusECore::MidiPart*, bool, bool);
+ void pdrawItems(QPainter& p, const QRect& rect, const MusECore::MidiPart* part, bool velo, bool fg);
+ void pdrawExtraDrumCtrlItems(QPainter& p, const QRect& rect, const MusECore::MidiPart* part, int drum_ctl);
void partControllers(const MusECore::MidiPart*, int, int*, int*, MusECore::MidiController**, MusECore::MidiCtrlValList**);
diff --git a/muse2/muse/ctrl/ctrlpanel.cpp b/muse2/muse/ctrl/ctrlpanel.cpp
index 0fc66b3a..cb14200e 100644
--- a/muse2/muse/ctrl/ctrlpanel.cpp
+++ b/muse2/muse/ctrl/ctrlpanel.cpp
@@ -56,6 +56,7 @@
#include "audio.h"
#include "menutitleitem.h"
#include "popupmenu.h"
+#include "helper.h"
namespace MusEGui {
@@ -197,12 +198,7 @@ void CtrlPanel::heartBeat()
// Auto bias...
v -= _ctrl->bias();
if (double(v) != _knob->value())
- {
- // Added by Tim. p3.3.6
- //printf("CtrlPanel::heartBeat setting knob\n");
-
_knob->setValue(double(v));
- }
}
}
else if(v != _val)
@@ -522,469 +518,174 @@ void CtrlPanel::setHeight(int h)
setFixedHeight(h);
}
-#if 0 // DELETETHIS. yeah, really!
-// when flo added the new style drumtracks in trunk, he changed a
-// lot of things. he didn't update that disabled area here, so
-// after releasing 2.0, when we continue developing on trunk,
-// then the below code is not only disabled but INVALID (as in WRONG)
-
-/* 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;
- CI(const QString& ss, bool u) : s(ss), used(u) {}
- };
-
-//---------------------------------------------------------
-// ctrlPopup
-//---------------------------------------------------------
-
+//---------------------------------------------------
+// ctrlPopup
+//---------------------------------------------------
+
void CtrlPanel::ctrlPopup()
{
- //---------------------------------------------------
- // build list of midi controllers for current
- // MusECore::MidiPort/channel
- //---------------------------------------------------
-
MusECore::PartList* parts = editor->parts();
MusECore::Part* part = editor->curCanvasPart();
- MusECore::MidiTrack* track = (MusECore::MidiTrack*)(part->track());
- int channel = track->outChannel();
- MusECore::MidiPort* port = &MusEGlobal::midiPorts[track->outPort()];
- 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();
- pop->addAction(tr("Velocity"))->setData(1);
+ int curDrumPitch = ctrlcanvas->getCurDrumPitch();
- MidiCtrlValListList* cll = port->controller();
- int min = channel << 24;
- int max = min + 0x1000000;
-
- std::list<CI> sList;
- typedef std::list<CI>::iterator isList;
-
- for (MusECore::iMidiCtrlValList i = cll->lower_bound(min); i != cll->lower_bound(max); ++i) {
- MidiCtrlValList* cl = i->second;
- MusECore::MidiController* c = port->midiController(cl->num());
- // dont show drum specific controller if not a drum track
- if ((c->num() & 0xff) == 0xff) {
- 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) {
- if (i->s == c->name())
- break;
- }
- if (i == sList.end()) {
- bool used = false;
- for (MusECore::iPart ip = parts->begin(); ip != parts->end(); ++ip) {
- MusECore::EventList* el = ip->second->events();
- for (MusECore::iEvent ie = el->begin(); ie != el->end(); ++ie) {
- MusECore::Event e = ie->second;
- if ((e.type() == MusECore::Controller) && (e.dataA() == cl->num())) {
- used = true;
- break;
- }
- }
- if (used)
- break;
- }
- sList.push_back(CI(c->name(), used));
- }
- }
- for (isList i = sList.begin(); i != sList.end(); ++i) {
- if (i->used)
- pop->addAction(QIcon(*greendotIcon), i->s);
- else
- pop->addAction(i->s);
- }
-
- pop->addAction(QIcon(*configureIcon), tr("add new ..."))->setData(2);
- QAction *act = pop->exec(selCtrl->mapToGlobal(QPoint(0,0)));
+ PopupMenu* pup = new PopupMenu(true); // true = enable stay open. Don't bother with parent.
+ int est_width = populateMidiCtrlMenu(pup, parts, part, curDrumPitch);
+ QPoint ep = mapToGlobal(QPoint(0,0));
+ //int newx = ep.x() - ctrlMainPop->width(); // Too much! Width says 640. Maybe because it hasn't been shown yet .
+ int newx = ep.x() - est_width;
+ if(newx < 0)
+ newx = 0;
+ ep.setX(newx);
+ connect(pup, SIGNAL(triggered(QAction*)), SLOT(ctrlPopupTriggered(QAction*)));
+ pup->exec(ep);
+ delete pup;
selCtrl->setDown(false);
-
- if (!act)
- {
- delete pop;
- return;
- }
-
- int rv = act->data().toInt();
- QString s = act->text();
- delete pop;
-
- if (rv == 1) { // special case velocity
- emit controllerChanged(MusECore::CTRL_VELOCITY);
- }
- else if (rv == 2) {
- //
- // add new controller
- //
- QMenu* pop1 = new QMenu(this);
- //pop1->setCheckable(false); // Qt4 doc says not needed.
- //
- // populate popup with all controllers available for
- // current instrument
- //
- MidiInstrument* instr = port->instrument();
- MusECore::MidiControllerList* mcl = instr->controller();
- for (iMusECore::MidiController ci = mcl->begin(); ci != mcl->end(); ++ci)
- {
- int num = ci->second->num();
- 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());
- }
- QAction *act2 = pop1->exec(selCtrl->mapToGlobal(QPoint(0,0)));
- if (act2) {
- QString s = act2->text();
- MusECore::MidiController* c;
- for (iMusECore::MidiController ci = mcl->begin(); ci != mcl->end(); ++ci) {
- c = ci->second;
- if (c->name() == s) {
- int num = c->num();
- 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())
- {
- MidiCtrlValList* vl = new MidiCtrlValList(num);
-
- cll->add(channel, vl);
- emit controllerChanged(c->num());
- //MusEGlobal::song->update(SC_MIDI_CONTROLLER_ADD);
- }
- else
- emit controllerChanged(c->num());
- break;
- }
- }
- }
- delete pop1;
- }
- else {
- ///QString s = act->text();
- MusECore::iMidiCtrlValList i = cll->begin();
- for (; i != cll->end(); ++i) {
- MidiCtrlValList* cl = i->second;
- MusECore::MidiController* c = port->midiController(cl->num());
- if (c->name() == s) {
- emit controllerChanged(c->num());
- break;
- }
- }
- if (i == cll->end()) {
- printf("CtrlPanel: controller %s not found!", s.toLatin1().constData());
- }
- }
}
-#else // p4.0.25 Tim
-struct CI {
- int num;
- QString s;
- bool used;
- bool instrument;
- CI(int n, const QString& ss, bool u, bool i) : num(n), s(ss), used(u), instrument(i) {}
- };
-
-void CtrlPanel::ctrlPopup()
- {
- //---------------------------------------------------
- // build list of midi controllers for current
- // MusECore::MidiPort/channel
- //---------------------------------------------------
-
- MusECore::PartList* parts = editor->parts();
- MusECore::Part* part = editor->curCanvasPart();
- MusECore::MidiTrack* track = (MusECore::MidiTrack*)(part->track());
- int channel = track->outChannel();
- MusECore::MidiPort* port = &MusEGlobal::midiPorts[track->outPort()];
- 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();
-
- MusECore::MidiCtrlValListList* cll = port->controller();
- int min = channel << 24;
- int max = min + 0x1000000;
-
- std::list<CI> sList;
- typedef std::list<CI>::iterator isList;
-
- for (MusECore::iMidiCtrlValList it = cll->lower_bound(min); it != cll->lower_bound(max); ++it) {
- MusECore::MidiCtrlValList* cl = it->second;
- MusECore::MidiController* c = port->midiController(cl->num());
- // dont show drum specific controller if not a drum track
- if ((c->num() & 0xff) == 0xff) {
- 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) {
- //if (i->s == c->name())
- if (i->num == c->num())
- break;
- }
- if (i == sList.end()) {
- bool used = false;
- for (MusECore::iPart ip = parts->begin(); ip != parts->end(); ++ip) {
- MusECore::EventList* el = ip->second->events();
- for (MusECore::iEvent ie = el->begin(); ie != el->end(); ++ie) {
- MusECore::Event e = ie->second;
- if ((e.type() == MusECore::Controller) && (e.dataA() == cl->num())) {
- used = true;
- break;
- }
- }
- if (used)
- break;
- }
- //sList.push_back(CI(c->name(), used));
- bool isinstr = ( mcl->find(c->num()) != mcl->end() );
- int cnum = c->num();
- // Need to distinguish between global default controllers and
- // instrument defined controllers. Instrument takes priority over global
- // ie they 'overtake' definition of a global controller such that the
- // global def is no longer available.
- sList.push_back(CI(cnum,
- isinstr ? MusECore::midiCtrlNumString(cnum, true) + c->name() : MusECore::midiCtrlName(cnum, true),
- used, isinstr));
- }
- }
-
- MusEGui::PopupMenu* ctrlMainPop = new MusEGui::PopupMenu;
-
- //ctrlMainPop->addSeparator();
- ctrlMainPop->addAction(new MusEGui::MenuTitleItem(tr("Instrument-defined"), ctrlMainPop));
-
- //ctrlMainPop->addAction(QIcon(*configureIcon), tr("Add ..."))->setData(max + 1);
-
- // Add instrument-defined controllers.
- for (isList i = sList.begin(); i != sList.end(); ++i)
- {
- if(!i->instrument)
- continue;
- if (i->used)
- ctrlMainPop->addAction(QIcon(*greendotIcon), i->s)->setData(i->num);
- else
- ctrlMainPop->addAction(i->s)->setData(i->num);
- }
-
- ctrlMainPop->addAction(QIcon(*configureIcon), tr("Add ..."))->setData(max + 1);
- //ctrlMainPop->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit instruments"))->setData(max + 2);
-
- ctrlMainPop->addSeparator();
- ctrlMainPop->addAction(new MusEGui::MenuTitleItem(tr("Others"), ctrlMainPop));
-
- //ctrlMainPop->addAction(QIcon(*configureIcon), tr("Add ..."))->setData(max + 3);
-
- ctrlMainPop->addAction(tr("Velocity"))->setData(max);
-
- // Add global default controllers (all controllers not found in instrument).
- for (isList i = sList.begin(); i != sList.end(); ++i)
- {
- if(i->instrument)
- continue;
- if (i->used)
- ctrlMainPop->addAction(QIcon(*greendotIcon), i->s)->setData(i->num);
- else
- ctrlMainPop->addAction(i->s)->setData(i->num);
- }
-
- ctrlMainPop->addAction(QIcon(*configureIcon), tr("Add ..."))->setData(max + 3);
+//---------------------------------------------------------
+// ctrlPopupTriggered
+//---------------------------------------------------------
- //connect(ctrlMainPop, SIGNAL(hovered(QAction*)), SLOT(ctrlMainPopHovered(QAction*)));
-
- QAction *act = ctrlMainPop->exec(selCtrl->mapToGlobal(QPoint(0,0)));
- selCtrl->setDown(false);
-
- if (!act)
- {
- delete ctrlMainPop;
- return;
- }
-
- int rv = act->data().toInt();
- delete ctrlMainPop;
-
- if (rv == max) { // special case velocity
- emit controllerChanged(MusECore::CTRL_VELOCITY);
- }
- else if (rv == max + 1) { // add new instrument controller
-
- MusEGui::PopupMenu * ctrlSubPop = new MusEGui::PopupMenu(this);
- ctrlSubPop->addAction(new MusEGui::MenuTitleItem(tr("Instrument-defined"), ctrlSubPop));
-
- //
- // populate popup with all controllers available for
- // current instrument
- //
-
- //ctrlSubPop->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit instruments"))->setData(max + 2);
-
- for (MusECore::iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci)
+void CtrlPanel::ctrlPopupTriggered(QAction* act)
+{
+ if(!act || (act->data().toInt() == -1))
+ return;
+
+ MusECore::Part* part = editor->curCanvasPart();
+ MusECore::MidiTrack* track = (MusECore::MidiTrack*)(part->track());
+ int channel = track->outChannel();
+ MusECore::MidiPort* port = &MusEGlobal::midiPorts[track->outPort()];
+ 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();
+
+ MusECore::MidiCtrlValListList* cll = port->controller();
+ int min = channel << 24;
+ int max = min + 0x1000000;
+
+ int rv = act->data().toInt();
+
+ if (rv == max) { // special case velocity
+ emit controllerChanged(MusECore::CTRL_VELOCITY);
+ }
+ else if (rv == max + 1) { // add new instrument controller
+
+ PopupMenu * ctrlSubPop = new PopupMenu(this, true); // true = enable stay open
+ ctrlSubPop->addAction(new MenuTitleItem(tr("Instrument-defined"), ctrlSubPop));
+
+ //
+ // populate popup with all controllers available for
+ // current instrument
+ //
+
+ for (MusECore::iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci)
+ {
+ int num = ci->second->num();
+ if((num & 0xff) == 0xff)
{
- int num = ci->second->num();
- if((num & 0xff) == 0xff)
- {
- 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;
- }
-
- if(cll->find(channel, num) == cll->end())
- ctrlSubPop->addAction(MusECore::midiCtrlNumString(num, true) + ci->second->name())->setData(num);
- }
-
- // Don't allow editing instrument if it's a synth
- if(!port->device() || port->device()->deviceType() != MusECore::MidiDevice::SYNTH_MIDI)
- ctrlSubPop->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit instrument ..."))->setData(max + 2);
-
- //connect(ctrlSubPop, SIGNAL(hovered(QAction*)), SLOT(ctrlSubPopHovered(QAction*)));
-
- QAction *act2 = ctrlSubPop->exec(selCtrl->mapToGlobal(QPoint(0,0)));
- if (act2)
+ 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;
+ }
+
+ if(cll->find(channel, num) == cll->end())
+ ctrlSubPop->addAction(MusECore::midiCtrlNumString(num, true) + ci->second->name())->setData(num);
+ }
+
+ // Don't allow editing instrument if it's a synth
+ if(!port->device() || port->device()->deviceType() != MusECore::MidiDevice::SYNTH_MIDI)
+ ctrlSubPop->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit instrument ..."))->setData(max + 2);
+
+ QAction *act2 = ctrlSubPop->exec(selCtrl->mapToGlobal(QPoint(0,0)));
+ if (act2)
+ {
+ int rv2 = act2->data().toInt();
+
+ if (rv2 == max + 2) // edit instrument
+ MusEGlobal::muse->startEditInstrument();
+ else // select new instrument control
+ {
+ MusECore::MidiController* c;
+ for (MusECore::iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci)
{
- int rv2 = act2->data().toInt();
-
- if (rv2 == max + 2) // edit instrument
- MusEGlobal::muse->startEditInstrument();
- else // select new instrument control
- {
- MusECore::MidiController* c;
- for (MusECore::iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci)
- {
- c = ci->second;
- int num = c->num();
- 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;
-
- if(cll->find(channel, num) == cll->end())
- {
- MusECore::MidiCtrlValList* vl = new MusECore::MidiCtrlValList(num);
-
- cll->add(channel, vl);
- emit controllerChanged(c->num());
- //MusEGlobal::song->update(SC_MIDI_CONTROLLER_ADD);
- }
- else
- emit controllerChanged(c->num());
- break;
- }
- }
- }
- delete ctrlSubPop;
- }
-
- //else if (rv == max + 2) // edit instrument
- // MusEGlobal::muse->startEditInstrument();
-
- else if (rv == max + 3) { // add new other controller
- MusEGui::PopupMenu* ctrlSubPop = new MusEGui::PopupMenu(this);
- ctrlSubPop->addAction(new MusEGui::MenuTitleItem(tr("Common Controls"), ctrlSubPop));
-
- for(int num = 0; num < 127; ++num)
- if(cll->find(channel, num) == cll->end())
- ctrlSubPop->addAction(MusECore::midiCtrlName(num, true))->setData(num);
- QAction *act2 = ctrlSubPop->exec(selCtrl->mapToGlobal(QPoint(0,0)));
- if (act2) {
- int rv2 = act2->data().toInt();
- int num = rv2;
+ c = ci->second;
+ int num = c->num();
if (isDrum && ((num & 0xff) == 0xff) && curDrumPitch!=-1)
num = (num & ~0xff) + MusEGlobal::drumMap[curDrumPitch].anote;
- if (isNewDrum && ((num & 0xff) == 0xff) && curDrumPitch!=-1)
+ else if (isNewDrum && ((num & 0xff) == 0xff) && curDrumPitch!=-1)
num = (num & ~0xff) + curDrumPitch; //FINDMICHJETZT does this work?
-
+
+ if(num != rv2)
+ continue;
+
if(cll->find(channel, num) == cll->end())
{
MusECore::MidiCtrlValList* vl = new MusECore::MidiCtrlValList(num);
cll->add(channel, vl);
- emit controllerChanged(rv2);
- //MusEGlobal::song->update(SC_MIDI_CONTROLLER_ADD);
+ emit controllerChanged(c->num());
}
else
- emit controllerChanged(rv2);
- }
- delete ctrlSubPop;
+ emit controllerChanged(c->num());
+ break;
}
- else { // Select a control
- //QString s = act->text();
- MusECore::iMidiCtrlValList i = cll->begin();
- for (; i != cll->end(); ++i) {
- MusECore::MidiCtrlValList* cl = i->second;
- MusECore::MidiController* c = port->midiController(cl->num());
- //if (c->name() == s) {
- if (c->num() == rv) {
- emit controllerChanged(c->num());
- break;
- }
- }
- if (i == cll->end()) {
- //printf("CtrlPanel: controller %s not found!", s.toLatin1().constData());
- printf("CtrlPanel: controller number %d not found!", rv);
- }
- }
- }
-#endif
+ }
+ }
+ delete ctrlSubPop;
+ }
+
+ //else if (rv == max + 2) // edit instrument
+ // MusEGlobal::muse->startEditInstrument();
+
+ else if (rv == max + 3) { // add new other controller
+ PopupMenu* ctrlSubPop = new PopupMenu(this, true); // true = enable stay open
+ ctrlSubPop->addAction(new MenuTitleItem(tr("Common Controls"), ctrlSubPop));
+
+ for(int num = 0; num < 127; ++num)
+ if(cll->find(channel, num) == cll->end())
+ ctrlSubPop->addAction(MusECore::midiCtrlName(num, true))->setData(num);
+ QAction *act2 = ctrlSubPop->exec(selCtrl->mapToGlobal(QPoint(0,0)));
+ if (act2) {
+ int rv2 = act2->data().toInt();
+ int num = rv2;
+ 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);
+
+ cll->add(channel, vl);
+ emit controllerChanged(rv2);
+ }
+ else
+ emit controllerChanged(rv2);
+ }
+ delete ctrlSubPop;
+ }
+ else { // Select a control
+ MusECore::iMidiCtrlValList i = cll->begin();
+ for (; i != cll->end(); ++i) {
+ MusECore::MidiCtrlValList* cl = i->second;
+ MusECore::MidiController* c = port->midiController(cl->num());
+ if (c->num() == rv) {
+ emit controllerChanged(c->num());
+ break;
+ }
+ }
+ if (i == cll->end()) {
+ printf("CtrlPanel: controller number %d not found!", rv);
+ }
+ }
+
+}
//---------------------------------------------------------
// ctrlRightClicked
diff --git a/muse2/muse/ctrl/ctrlpanel.h b/muse2/muse/ctrl/ctrlpanel.h
index 1a5245dc..58b8d8c7 100644
--- a/muse2/muse/ctrl/ctrlpanel.h
+++ b/muse2/muse/ctrl/ctrlpanel.h
@@ -26,6 +26,7 @@
#include <QWidget>
class QPushButton;
+class QAction;
namespace MusECore {
class MidiController;
@@ -68,6 +69,7 @@ class CtrlPanel: public QWidget {
void ctrlChanged(double val);
void labelDoubleClicked();
void ctrlRightClicked(const QPoint& p, int id);
+ void ctrlPopupTriggered(QAction* act);
protected slots:
virtual void heartBeat();
diff --git a/muse2/muse/gconfig.cpp b/muse2/muse/gconfig.cpp
index ff5545ef..c88c3fc5 100644
--- a/muse2/muse/gconfig.cpp
+++ b/muse2/muse/gconfig.cpp
@@ -127,6 +127,9 @@ GlobalConfigValues config = {
384, // division;
1024, // rtcTicks
+ true, // midiSendInit Send instrument initialization sequences
+ true, // warnInitPending Warn instrument initialization sequences pending
+ false, // midiSendCtlDefaults Send instrument controller defaults at position 0 if none in song
-60, // int minMeter;
-60.0, // double minSlider;
false, // use Jack freewheel
diff --git a/muse2/muse/gconfig.h b/muse2/muse/gconfig.h
index a9d2c0a0..6fa85846 100644
--- a/muse2/muse/gconfig.h
+++ b/muse2/muse/gconfig.h
@@ -136,6 +136,9 @@ struct GlobalConfigValues {
int division;
int rtcTicks;
+ bool midiSendInit; // Send instrument initialization sequences
+ bool warnInitPending; // Warn instrument initialization sequences pending
+ bool midiSendCtlDefaults; // Send instrument controller defaults at position 0 if none in song
int minMeter;
double minSlider;
bool freewheelMode;
diff --git a/muse2/muse/helper.cpp b/muse2/muse/helper.cpp
index ae2b0352..21986831 100644
--- a/muse2/muse/helper.cpp
+++ b/muse2/muse/helper.cpp
@@ -40,6 +40,8 @@
#include "audiodev.h"
#include "midi.h"
#include "midiseq.h"
+#include "popupmenu.h"
+#include "menutitleitem.h"
#include <QMenu>
#include <QApplication>
@@ -733,12 +735,8 @@ void populateMidiPorts()
}
#else // this code is disabled
-// DELETETHIS uhm, yeah... do we need this?
-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!
+
+// Please don't remove this section as it may be improved.
// -------------------------------------------------------------------------------------------------------
// populateMidiPorts()
@@ -865,5 +863,198 @@ void populateMidiPorts()
#endif // populateMidiPorts
+struct CI {
+ int num;
+ QString s;
+ bool used;
+ bool off;
+ bool instrument;
+ CI(int n, const QString& ss, bool u, bool o, bool i) : num(n), s(ss), used(u), off(o), instrument(i) {}
+ };
+
+//---------------------------------------------------
+// populateMidiCtrlMenu
+// Returns estimated width of the completed menu.
+//---------------------------------------------------
+
+int populateMidiCtrlMenu(PopupMenu* menu, MusECore::PartList* part_list, MusECore::Part* cur_part, int curDrumPitch)
+ {
+ //---------------------------------------------------
+ // build list of midi controllers for current
+ // MusECore::MidiPort/channel
+ //---------------------------------------------------
+
+ MusECore::MidiTrack* track = (MusECore::MidiTrack*)(cur_part->track());
+ int channel = track->outChannel();
+ MusECore::MidiPort* port = &MusEGlobal::midiPorts[track->outPort()];
+ 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();
+
+ MusECore::MidiCtrlValListList* cll = port->controller();
+ int min = channel << 24;
+ int max = min + 0x1000000;
+
+ int est_width = 0;
+
+ std::list<CI> sList;
+ typedef std::list<CI>::iterator isList;
+
+ for (MusECore::iMidiCtrlValList it = cll->lower_bound(min); it != cll->lower_bound(max); ++it) {
+ MusECore::MidiCtrlValList* cl = it->second;
+ MusECore::MidiController* c = port->midiController(cl->num());
+ bool isDrumCtrl = ((c->num() & 0xff) == 0xff);
+
+ // dont show drum specific controller if not a drum track
+ if (isDrumCtrl) {
+ 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) {
+ //if (i->s == c->name())
+ if (i->num == c->num())
+ break;
+ }
+
+ //printf("\n** c->num():%d cl->num:%d\n", c->num(), cl->num());
+ if (i == sList.end()) {
+ bool off = cl->hwVal() == MusECore::CTRL_VAL_UNKNOWN; // Does it have a value or is it 'off'
+ bool used = false;
+ for (MusECore::iPart ip = part_list->begin(); ip != part_list->end(); ++ip) {
+ MusECore::EventList* el = ip->second->events();
+ for (MusECore::iEvent ie = el->begin(); ie != el->end(); ++ie) {
+ MusECore::Event e = ie->second;
+ if(e.type() != MusECore::Controller)
+ continue;
+ //e.dump();
+ int ctl_num = e.dataA();
+ if(!isNewDrum)
+ {
+ // Is it a drum controller event, according to the track port's instrument?
+ MusECore::MidiController *mc = port->drumController(ctl_num);
+ if(mc)
+ {
+ if((ctl_num & 0xff) != curDrumPitch)
+ continue;
+ // Change the controller event's index into the drum map to an instrument note.
+ ctl_num = (ctl_num & ~0xff) | MusEGlobal::drumMap[ctl_num & 0x7f].anote;
+ }
+ }
+ if(ctl_num == cl->num())
+ {
+ used = true;
+ break;
+ }
+
+ }
+ if (used)
+ break;
+ }
+ bool isinstr = ( mcl->find(c->num()) != mcl->end() );
+ int cnum = c->num();
+ // Need to distinguish between global default controllers and
+ // instrument defined controllers. Instrument takes priority over global
+ // ie they 'overtake' definition of a global controller such that the
+ // global def is no longer available.
+ sList.push_back(CI(cnum,
+ isinstr ? MusECore::midiCtrlNumString(cnum, true) + c->name() : MusECore::midiCtrlName(cnum, true),
+ used, off, isinstr));
+ }
+ }
+
+ QString stext = QWidget::tr("Instrument-defined");
+ int fmw = menu->fontMetrics().width(stext);
+ if(fmw > est_width)
+ est_width = fmw;
+
+ menu->addAction(new MenuTitleItem(stext, menu));
+
+ // Add instrument-defined controllers.
+ for (isList i = sList.begin(); i != sList.end(); ++i)
+ {
+ if(!i->instrument)
+ continue;
+
+ fmw = menu->fontMetrics().width(i->s);
+ if(fmw > est_width)
+ est_width = fmw;
+
+ if (i->used && !i->off)
+ menu->addAction(QIcon(*orangedotIcon), i->s)->setData(i->num);
+ else if (i->used)
+ menu->addAction(QIcon(*greendotIcon), i->s)->setData(i->num);
+ else if(!i->off)
+ menu->addAction(QIcon(*bluedotIcon), i->s)->setData(i->num);
+ else
+ menu->addAction(i->s)->setData(i->num);
+ }
+
+ stext = QWidget::tr("Add ...");
+ fmw = menu->fontMetrics().width(stext);
+ if(fmw > est_width)
+ est_width = fmw;
+ menu->addAction(QIcon(*configureIcon), stext)->setData(max + 1);
+
+ menu->addSeparator();
+
+ stext = QWidget::tr("Others");
+ fmw = menu->fontMetrics().width(stext);
+ if(fmw > est_width)
+ est_width = fmw;
+ menu->addAction(new MenuTitleItem(stext, menu));
+
+ stext = QWidget::tr("Velocity");
+ fmw = menu->fontMetrics().width(stext);
+ if(fmw > est_width)
+ est_width = fmw;
+ menu->addAction(stext)->setData(max);
+
+ // Add global default controllers (all controllers not found in instrument).
+ for (isList i = sList.begin(); i != sList.end(); ++i)
+ {
+ if(i->instrument)
+ continue;
+
+ fmw = menu->fontMetrics().width(i->s);
+ if(fmw > est_width)
+ est_width = fmw;
+
+ if (i->used && !i->off)
+ menu->addAction(QIcon(*orangedotIcon), i->s)->setData(i->num);
+ else if (i->used)
+ menu->addAction(QIcon(*greendotIcon), i->s)->setData(i->num);
+ else if(!i->off)
+ menu->addAction(QIcon(*bluedotIcon), i->s)->setData(i->num);
+ else
+ menu->addAction(i->s)->setData(i->num);
+ }
+
+ stext = QWidget::tr("Add ...");
+ fmw = menu->fontMetrics().width(stext);
+ if(fmw > est_width)
+ est_width = fmw;
+ menu->addAction(QIcon(*configureIcon), stext)->setData(max + 3);
+
+ est_width += 60; // Add about 60 for the coloured lights on the left.
+
+ return est_width;
+ }
+
+
+
} // namespace MusEGui
diff --git a/muse2/muse/helper.h b/muse2/muse/helper.h
index 8671dce3..0eab7ee2 100644
--- a/muse2/muse/helper.h
+++ b/muse2/muse/helper.h
@@ -38,7 +38,7 @@ class QWidget;
namespace MusECore {
class Part;
class Track;
-
+class PartList;
QString pitch2string(int v);
Part* partFromSerialNumber(int serial);
@@ -63,6 +63,8 @@ void record_controller_change_and_maybe_send(unsigned tick, int ctrl_num, int va
}
namespace MusEGui {
+class PopupMenu;
+
QMenu* populateAddSynth(QWidget* parent);
QActionGroup* populateAddTrack(QMenu* addTrack, bool populateAll=false, bool evenIgnoreDrumPreference=false);
QStringList localizedStringListFromCharArray(const char** array, const char* context);
@@ -73,6 +75,7 @@ QString projectPathFromFilename(QString filename);
QString projectExtensionFromFilename(QString filename);
QString getUniqueUntitledName();
void populateMidiPorts();
+int populateMidiCtrlMenu(PopupMenu* menu, MusECore::PartList* part_list, MusECore::Part* cur_part, int curDrumPitch);
}
#endif
diff --git a/muse2/muse/icons.cpp b/muse2/muse/icons.cpp
index cfe30495..dab1067b 100644
--- a/muse2/muse/icons.cpp
+++ b/muse2/muse/icons.cpp
@@ -189,9 +189,11 @@
//#include "xpm/darkgreendot.xpm"
#include "xpm/bluedot.xpm"
#include "xpm/graydot.xpm"
+#include "xpm/orangedot.xpm"
#include "xpm/off.xpm"
#include "xpm/blacksquare.xpm"
#include "xpm/blacksqcheck.xpm"
+#include "xpm/checksquare.xpm"
#include "xpm/mastertrackS.xpm"
#include "xpm/localoffS.xpm"
@@ -425,9 +427,11 @@ QPixmap* greendotIcon;
//QPixmap* darkgreendotIcon;
QPixmap* graydotIcon;
QPixmap* bluedotIcon;
+QPixmap* orangedotIcon;
QPixmap* offIcon;
QPixmap* blacksquareIcon;
QPixmap* blacksqcheckIcon;
+QPixmap* checkSquareIcon;
QPixmap* addtrack_addmiditrackIcon;
QPixmap* addtrack_audiogroupIcon;
@@ -648,9 +652,11 @@ void initIcons()
//darkgreendotIcon = new MPIXMAP(darkgreendot_xpm, NULL);
bluedotIcon = new MPIXMAP(bluedot_xpm, NULL);
graydotIcon = new MPIXMAP(graydot_xpm, NULL);
+ orangedotIcon = new MPIXMAP(orangedot_xpm, NULL);
offIcon = new MPIXMAP(off_xpm, NULL);
blacksquareIcon = new MPIXMAP(blacksquare_xpm, NULL);
blacksqcheckIcon = new MPIXMAP(blacksqcheck_xpm, NULL);
+ checkSquareIcon = new MPIXMAP(checksquare_xpm, NULL);
mastertrackSIcon = new MPIXMAP(mastertrackS_xpm, NULL);
localoffSIcon = new MPIXMAP(localoffS_xpm, NULL);
@@ -885,10 +891,12 @@ void deleteIcons()
//delete darkgreendotIcon;
delete bluedotIcon;
delete graydotIcon;
+ delete orangedotIcon;
delete offIcon;
delete blacksquareIcon;
delete blacksqcheckIcon;
-
+ delete checkSquareIcon;
+
delete mastertrackSIcon;
delete localoffSIcon;
delete miditransformSIcon;
diff --git a/muse2/muse/icons.h b/muse2/muse/icons.h
index 3ee7cfea..a6c95577 100644
--- a/muse2/muse/icons.h
+++ b/muse2/muse/icons.h
@@ -170,9 +170,11 @@ extern QPixmap* greendotIcon;
//extern QPixmap* darkgreendotIcon;
extern QPixmap* graydotIcon;
extern QPixmap* bluedotIcon;
+extern QPixmap* orangedotIcon;
extern QPixmap* offIcon;
extern QPixmap* blacksquareIcon;
extern QPixmap* blacksqcheckIcon;
+extern QPixmap* checkSquareIcon;
extern QPixmap* mastertrackSIcon;
extern QPixmap* localoffSIcon;
diff --git a/muse2/muse/midi.cpp b/muse2/muse/midi.cpp
index f1d5124d..33b98c00 100644
--- a/muse2/muse/midi.cpp
+++ b/muse2/muse/midi.cpp
@@ -169,7 +169,7 @@ QString nameSysex(unsigned int len, const unsigned char* buf)
case 0x43: s = "Yamaha: "; break;
case 0x44: s = "Casio"; break;
case 0x45: s = "Akai"; break;
- case MUSE_SYNTH_SYSEX_MFG_ID: s = "MusE Soft Synth"; break; // p4.0.27
+ case MUSE_SYNTH_SYSEX_MFG_ID: s = "MusE Soft Synth"; break;
case 0x7d: s = "Educational Use"; break;
case 0x7e: s = "Universal: Non Real Time"; break;
case 0x7f: s = "Universal: Real Time"; break;
@@ -521,7 +521,7 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track,
printf("ERROR: THIS SHOULD NEVER HAPPEN: k==i in midi.cpp:buildMidiEventList()\n");
else
mel.erase(k);
- i = mel.begin(); // p4.0.34
+ i = mel.begin();
continue;
}
}
@@ -592,49 +592,15 @@ void Audio::panic()
//---------------------------------------------------------
// initDevices
-// - called on seek to position 0
+// - called when instrument init sequences plus controller
+// defaults should be checked and/or sent
// - called from arranger pulldown menu
//---------------------------------------------------------
-void Audio::initDevices()
+void Audio::initDevices(bool force)
{
- //
- // mark all used ports
- //
- bool activePorts[MIDI_PORTS];
- for (int i = 0; i < MIDI_PORTS; ++i)
- activePorts[i] = false;
-
- MusECore::MidiTrackList* tracks = MusEGlobal::song->midis();
- for (MusECore::iMidiTrack it = tracks->begin(); it != tracks->end(); ++it) {
- MusECore::MidiTrack* track = *it;
- activePorts[track->outPort()] = true;
- }
- if (MusEGlobal::song->click())
- activePorts[MusEGlobal::clickPort] = true;
-
- //
- // test for explicit instrument initialization
- //
-
for (int i = 0; i < MIDI_PORTS; ++i) {
- if (!activePorts[i])
- continue;
-
- MusECore::MidiPort* port = &MusEGlobal::midiPorts[i];
- MusECore::MidiInstrument* instr = port->instrument();
- MidiDevice* md = port->device();
-
- if (instr && md) {
- EventList* events = instr->midiInit();
- if (events->empty())
- continue;
- for (iEvent ie = events->begin(); ie != events->end(); ++ie) {
- MusECore::MidiPlayEvent ev(0, i, 0, ie->second);
- md->putEvent(ev);
- }
- activePorts[i] = false; // no standard initialization
- }
+ MusEGlobal::midiPorts[i].sendPendingInitializations(force);
}
}
@@ -992,12 +958,12 @@ void Audio::processMidi()
RouteList* irl = track->inRoutes();
for(ciRoute r = irl->begin(); r != irl->end(); ++r)
{
- if(!r->isValid() || (r->type != Route::MIDI_PORT_ROUTE)) // p3.3.49
+ if(!r->isValid() || (r->type != Route::MIDI_PORT_ROUTE))
continue;
- int devport = r->midiPort; //
+ int devport = r->midiPort;
if (devport == -1)
continue;
- MidiDevice* dev = MusEGlobal::midiPorts[devport].device(); //
+ MidiDevice* dev = MusEGlobal::midiPorts[devport].device();
if(!dev)
continue;
int channelMask = r->channel;
@@ -1316,7 +1282,7 @@ void Audio::processMidi()
for(iMidiDevice id = MusEGlobal::midiDevices.begin(); id != MusEGlobal::midiDevices.end(); ++id)
{
// We are done with the 'frozen' recording fifos, remove the events.
- (*id)->afterProcess(); // p4.0.34
+ (*id)->afterProcess();
// ALSA devices handled by another thread.
if((*id)->deviceType() != MidiDevice::ALSA_MIDI)
diff --git a/muse2/muse/mididev.cpp b/muse2/muse/mididev.cpp
index 9f303e43..e8f88960 100644
--- a/muse2/muse/mididev.cpp
+++ b/muse2/muse/mididev.cpp
@@ -37,12 +37,14 @@
#include "config.h"
#include "gconfig.h"
#include "globals.h"
+#include "globaldefs.h"
#include "audio.h"
#include "audiodev.h"
#include "midiseq.h"
#include "sync.h"
#include "midiitransform.h"
#include "part.h"
+#include "drummap.h"
namespace MusEGlobal {
MusECore::MidiDeviceList midiDevices;
@@ -131,6 +133,13 @@ MidiDevice::MidiDevice(const QString& n)
init();
}
+void MidiDevice::setPort(int p)
+{
+ _port = p;
+ if(_port != -1)
+ MusEGlobal::midiPorts[_port].clearInitSent();
+}
+
//---------------------------------------------------------
// filterEvent
// return true if event filtered
@@ -372,7 +381,7 @@ void MidiDeviceList::remove(MidiDevice* dev)
// sendNullRPNParams
//---------------------------------------------------------
-bool MidiDevice::sendNullRPNParams(int chn, bool nrpn)
+bool MidiDevice::sendNullRPNParams(unsigned time, int port, int chn, bool nrpn)
{
if(_port == -1)
return false;
@@ -386,16 +395,16 @@ bool MidiDevice::sendNullRPNParams(int chn, bool nrpn)
if(nvh != 0xff)
{
if(nrpn)
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f));
+ putMidiEvent(MidiPlayEvent(time, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f));
else
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f));
+ putMidiEvent(MidiPlayEvent(time, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f));
}
if(nvl != 0xff)
{
if(nrpn)
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_LNRPN, nvl & 0x7f));
+ putMidiEvent(MidiPlayEvent(time, port, chn, ME_CONTROLLER, CTRL_LNRPN, nvl & 0x7f));
else
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_LRPN, nvl & 0x7f));
+ putMidiEvent(MidiPlayEvent(time, port, chn, ME_CONTROLLER, CTRL_LRPN, nvl & 0x7f));
}
return true;
}
@@ -437,22 +446,25 @@ bool MidiDevice::putEvent(const MidiPlayEvent& ev)
//return true;
return false;
+ unsigned t = ev.time();
+ int port = ev.port();
+
if (ev.type() == ME_CONTROLLER) {
int a = ev.dataA();
int b = ev.dataB();
int chn = ev.channel();
if (a == CTRL_PITCH) {
- return putMidiEvent(MidiPlayEvent(0, 0, chn, ME_PITCHBEND, b, 0));
+ return putMidiEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, b, 0));
}
if (a == CTRL_PROGRAM) {
int hb = (b >> 16) & 0xff;
int lb = (b >> 8) & 0xff;
int pr = b & 0x7f;
if (hb != 0xff)
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_HBANK, hb));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb));
if (lb != 0xff)
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_LBANK, lb));
- return putMidiEvent(MidiPlayEvent(0, 0, chn, ME_PROGRAM, pr, 0));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LBANK, lb));
+ return putMidiEvent(MidiPlayEvent(t, port, chn, ME_PROGRAM, pr, 0));
}
#if 1 // if ALSA cannot handle RPN NRPN etc. DELETETHIS? remove the wrapping #if #endif
@@ -464,52 +476,52 @@ bool MidiDevice::putEvent(const MidiPlayEvent& ev)
int ctrlL = a & 0x7f;
int dataH = (b >> 7) & 0x7f;
int dataL = b & 0x7f;
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, ctrlH, dataH));
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, ctrlL, dataL));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlH, dataH));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlL, dataL));
}
else if (a < CTRL_NRPN_OFFSET) { // RPN 7-Bit Controller
int ctrlH = (a >> 8) & 0x7f;
int ctrlL = a & 0x7f;
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH));
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL));
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_HDATA, b));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, b));
// Select null parameters so that subsequent data controller
// events do not upset the last *RPN controller. Tim.
- sendNullRPNParams(chn, false);
+ sendNullRPNParams(t, port, chn, false);
}
else if (a < CTRL_INTERNAL_OFFSET) { // NRPN 7-Bit Controller
int ctrlH = (a >> 8) & 0x7f;
int ctrlL = a & 0x7f;
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH));
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL));
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_HDATA, b));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, b));
- sendNullRPNParams(chn, true);
+ sendNullRPNParams(t, port, chn, true);
}
else if (a < CTRL_NRPN14_OFFSET) { // RPN14 Controller
int ctrlH = (a >> 8) & 0x7f;
int ctrlL = a & 0x7f;
int dataH = (b >> 7) & 0x7f;
int dataL = b & 0x7f;
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH));
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL));
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_HDATA, dataH));
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_LDATA, dataL));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL));
- sendNullRPNParams(chn, false);
+ sendNullRPNParams(t, port, chn, false);
}
else if (a < CTRL_NONE_OFFSET) { // NRPN14 Controller
int ctrlH = (a >> 8) & 0x7f;
int ctrlL = a & 0x7f;
int dataH = (b >> 7) & 0x7f;
int dataL = b & 0x7f;
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH));
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL));
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_HDATA, dataH));
- putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_LDATA, dataL));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH));
+ putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL));
- sendNullRPNParams(chn, true);
+ sendNullRPNParams(t, port, chn, true);
}
else {
printf("putEvent: unknown controller type 0x%x\n", a);
@@ -649,6 +661,7 @@ void MidiDevice::handleSeek()
return;
MidiPort* mp = &MusEGlobal::midiPorts[_port];
+ MidiInstrument* instr = mp->instrument();
MidiCtrlValListList* cll = mp->controller();
int pos = MusEGlobal::audio->tickPos();
@@ -691,10 +704,56 @@ void MidiDevice::handleSeek()
// Send new controller values
//---------------------------------------------------
+ // Find channels on this port used in the song...
+ bool usedChans[MIDI_CHANNELS];
+ int usedChanCount = 0;
+ for(int i = 0; i < MIDI_CHANNELS; ++i)
+ usedChans[i] = false;
+ if(MusEGlobal::song->click() && MusEGlobal::clickPort == _port)
+ {
+ usedChans[MusEGlobal::clickChan] = true;
+ ++usedChanCount;
+ }
+ bool drum_found = false;
+ for(ciMidiTrack imt = MusEGlobal::song->midis()->begin(); imt != MusEGlobal::song->midis()->end(); ++imt)
+ {
+ if((*imt)->type() == MusECore::Track::DRUM)
+ {
+ if(!drum_found)
+ {
+ drum_found = true;
+ for(int i = 0; i < DRUM_MAPSIZE; ++i)
+ {
+ if(MusEGlobal::drumMap[i].port != _port || usedChans[MusEGlobal::drumMap[i].channel])
+ continue;
+ usedChans[MusEGlobal::drumMap[i].channel] = true;
+ ++usedChanCount;
+ if(usedChanCount >= MIDI_CHANNELS)
+ break; // All are used, done searching.
+ }
+ }
+ }
+ else
+ {
+ if((*imt)->outPort() != _port || usedChans[(*imt)->outChannel()])
+ continue;
+ usedChans[(*imt)->outChannel()] = true;
+ ++usedChanCount;
+ }
+
+ if(usedChanCount >= MIDI_CHANNELS)
+ break; // All are used. Done searching.
+ }
+
for(iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl)
{
MidiCtrlValList* vl = ivl->second;
+ int chan = ivl->first >> 24;
+ if(!usedChans[chan]) // Channel not used in song?
+ continue;
+ int ctlnum = vl->num();
iMidiCtrlVal imcv = vl->iValue(pos);
+ //bool done = false;
if(imcv != vl->end())
{
Part* p = imcv->second.part;
@@ -707,10 +766,30 @@ void MidiDevice::handleSeek()
unsigned t = (unsigned)imcv->first;
// Do not add values that are outside of the part.
if(p && t >= p->tick() && t < (p->tick() + p->lenTick()) )
- //_playEvents.add(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val));
+ {
+ //_playEvents.add(MidiPlayEvent(0, _port, chan, ME_CONTROLLER, ctlnum, imcv->second.val));
// Use sendEvent to get the optimizations and limiting. But force if there's a value at this exact position.
- mp->sendEvent(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val), imcv->first == pos);
- //mp->sendEvent(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val), pos == 0 || imcv->first == pos);
+ mp->sendEvent(MidiPlayEvent(0, _port, chan, ME_CONTROLLER, ctlnum, imcv->second.val), imcv->first == pos);
+ //mp->sendEvent(MidiPlayEvent(0, _port, chan, ME_CONTROLLER, ctlnum, imcv->second.val), pos == 0 || imcv->first == pos);
+ //done = true;
+ }
+ }
+
+ // Either no value was found, or they were outside parts, or pos is in the unknown area before the first value.
+ // Send instrument default initial values. NOT for syntis. Use midiState and/or initParams for that.
+ //if((imcv == vl->end() || !done) && !MusEGlobal::song->record() && instr && !isSynti())
+ // Darn, without refinement we can only do this at position 0, due to possible 'skipped' values outside parts, above.
+ if(imcv == vl->end() && MusEGlobal::config.midiSendCtlDefaults && !MusEGlobal::song->record() && pos == 0 && instr && !isSynti())
+ {
+ MidiControllerList* mcl = instr->controller();
+ ciMidiController imc = mcl->find(vl->num());
+ if(imc != mcl->end())
+ {
+ MidiController* mc = imc->second;
+ if(mc->initVal() != CTRL_VAL_UNKNOWN)
+ // Use sendEvent to get the optimizations and limiting. No force sending. Note the addition of bias.
+ mp->sendEvent(MidiPlayEvent(0, _port, chan, ME_CONTROLLER, ctlnum, mc->initVal() + mc->bias()), false);
+ }
}
}
diff --git a/muse2/muse/mididev.h b/muse2/muse/mididev.h
index 18a58623..2fbd817c 100644
--- a/muse2/muse/mididev.h
+++ b/muse2/muse/mididev.h
@@ -99,7 +99,7 @@ class MidiDevice {
virtual void setName(const QString& s) { _name = s; }
int midiPort() const { return _port; }
- void setPort(int p) { _port = p; }
+ void setPort(int p);
int rwFlags() const { return _rwFlags; }
int openFlags() const { return _openFlags; }
@@ -140,7 +140,7 @@ class MidiDevice {
void setSysexFIFOProcessed(bool v) { _sysexFIFOProcessed = v; }
bool sysexReadingChunks() { return _sysexReadingChunks; }
void setSysexReadingChunks(bool v) { _sysexReadingChunks = v; }
- bool sendNullRPNParams(int, bool);
+ bool sendNullRPNParams(unsigned time, int port, int chan, bool);
};
//---------------------------------------------------------
diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp
index 4d7fa906..7a86f010 100644
--- a/muse2/muse/midiedit/drumedit.cpp
+++ b/muse2/muse/midiedit/drumedit.cpp
@@ -61,6 +61,8 @@
#include "gconfig.h"
#include "functions.h"
#include "helper.h"
+#include "popupmenu.h"
+#include "menutitleitem.h"
#include "widgets/function_dialogs/quantize.h"
namespace MusEGui {
@@ -455,7 +457,7 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un
//---------------------------------------------------
split1 = new MusEGui::Splitter(Qt::Vertical, mainw, "split1");
- QPushButton* ctrl = new QPushButton(tr("ctrl"), mainw);
+ ctrl = new QPushButton(tr("ctrl"), mainw);
ctrl->setObjectName("Ctrl");
ctrl->setFont(MusEGlobal::config.fonts[3]);
ctrl->setFocusPolicy(Qt::NoFocus);
@@ -598,7 +600,7 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un
connect(info, SIGNAL(returnPressed()), SLOT(focusCanvas()));
connect(info, SIGNAL(escapePressed()), SLOT(focusCanvas()));
- connect(ctrl, SIGNAL(clicked()), SLOT(addCtrl()));
+ connect(ctrl, SIGNAL(clicked()), SLOT(addCtrlClicked()));
QClipboard* cb = QApplication::clipboard();
connect(cb, SIGNAL(dataChanged()), SLOT(clipboardChanged()));
@@ -1220,12 +1222,201 @@ void DrumEdit::selectionChanged()
}
//---------------------------------------------------------
+// ctrlPopupTriggered
+//---------------------------------------------------------
+
+void DrumEdit::ctrlPopupTriggered(QAction* act)
+{
+ // TODO Merge most of this with duplicate code in piano roll,
+ // maybe by putting it in a new function near populateMidiCtrlMenu.
+
+ if(!act || (act->data().toInt() == -1))
+ return;
+
+ int newCtlNum = -1;
+ MusECore::Part* part = curCanvasPart();
+ MusECore::MidiTrack* track = (MusECore::MidiTrack*)(part->track());
+ int channel = track->outChannel();
+ MusECore::MidiPort* port = &MusEGlobal::midiPorts[track->outPort()];
+ int curDrumPitch = curDrumInstrument();
+ 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();
+
+ MusECore::MidiCtrlValListList* cll = port->controller();
+ int min = channel << 24;
+ int max = min + 0x1000000;
+
+ int rv = act->data().toInt();
+
+ if (rv == max) { // special case velocity
+ newCtlNum = MusECore::CTRL_VELOCITY;
+ }
+ else if (rv == max + 1) { // add new instrument controller
+
+ PopupMenu * ctrlSubPop = new PopupMenu(this, true); // true = enable stay open
+ ctrlSubPop->addAction(new MenuTitleItem(tr("Instrument-defined"), ctrlSubPop));
+
+ //
+ // populate popup with all controllers available for
+ // current instrument
+ //
+
+ for (MusECore::iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci)
+ {
+ int num = ci->second->num();
+ if((num & 0xff) == 0xff)
+ {
+ 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;
+ }
+
+ if(cll->find(channel, num) == cll->end())
+ ctrlSubPop->addAction(MusECore::midiCtrlNumString(num, true) + ci->second->name())->setData(num);
+ }
+
+ // Don't allow editing instrument if it's a synth
+ if(!port->device() || port->device()->deviceType() != MusECore::MidiDevice::SYNTH_MIDI)
+ ctrlSubPop->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit instrument ..."))->setData(max + 2);
+
+ QAction *act2 = ctrlSubPop->exec(ctrl->mapToGlobal(QPoint(0,0)));
+ if (act2)
+ {
+ int rv2 = act2->data().toInt();
+
+ if (rv2 == max + 2) // edit instrument
+ MusEGlobal::muse->startEditInstrument();
+ else // select new instrument control
+ {
+ MusECore::MidiController* c;
+ for (MusECore::iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci)
+ {
+ c = ci->second;
+ int num = c->num();
+ 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;
+
+ if(cll->find(channel, num) == cll->end())
+ {
+ MusECore::MidiCtrlValList* vl = new MusECore::MidiCtrlValList(num);
+
+ cll->add(channel, vl);
+ newCtlNum = c->num();
+ }
+ else
+ newCtlNum = c->num();
+ break;
+ }
+ }
+ }
+ delete ctrlSubPop;
+ }
+
+ //else if (rv == max + 2) // edit instrument
+ // MusEGlobal::muse->startEditInstrument();
+
+ else if (rv == max + 3) { // add new other controller
+ PopupMenu* ctrlSubPop = new PopupMenu(this, true); // true = enable stay open
+ ctrlSubPop->addAction(new MenuTitleItem(tr("Common Controls"), ctrlSubPop));
+
+ for(int num = 0; num < 127; ++num)
+ if(cll->find(channel, num) == cll->end())
+ ctrlSubPop->addAction(MusECore::midiCtrlName(num, true))->setData(num);
+ QAction *act2 = ctrlSubPop->exec(ctrl->mapToGlobal(QPoint(0,0)));
+ if (act2) {
+ int rv2 = act2->data().toInt();
+ int num = rv2;
+ 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);
+
+ cll->add(channel, vl);
+ newCtlNum = rv2;
+ }
+ else
+ newCtlNum = rv2;
+ }
+ delete ctrlSubPop;
+ }
+ else { // Select a control
+ MusECore::iMidiCtrlValList i = cll->begin();
+ for (; i != cll->end(); ++i) {
+ MusECore::MidiCtrlValList* cl = i->second;
+ MusECore::MidiController* c = port->midiController(cl->num());
+ if (c->num() == rv) {
+ newCtlNum = c->num();
+ break;
+ }
+ }
+ if (i == cll->end()) {
+ printf("DrumEdit: controller number %d not found!", rv);
+ }
+ }
+
+ if(newCtlNum != -1)
+ {
+ CtrlEdit* ctrlEdit = new CtrlEdit(split1, this, xscale, true, "drumCtrlEdit");
+ ctrlEdit->setController(newCtlNum);
+ setupNewCtrl(ctrlEdit);
+ }
+}
+
+//---------------------------------------------------------
+// addCtrlClicked
+//---------------------------------------------------------
+
+void DrumEdit::addCtrlClicked()
+{
+ PopupMenu* pup = new PopupMenu(true); // true = enable stay open. Don't bother with parent.
+ connect(pup, SIGNAL(triggered(QAction*)), SLOT(ctrlPopupTriggered(QAction*)));
+
+ int est_width = populateMidiCtrlMenu(pup, parts(), curCanvasPart(), curDrumInstrument());
+
+ QPoint ep = ctrl->mapToGlobal(QPoint(0,0));
+ //int newx = ep.x() - pup->width(); // Too much! Width says 640. Maybe because it hasn't been shown yet .
+ int newx = ep.x() - est_width;
+ if(newx < 0)
+ newx = 0;
+ ep.setX(newx);
+ pup->exec(ep);
+ delete pup;
+
+ ctrl->setDown(false);
+}
+
+//---------------------------------------------------------
// addCtrl
//---------------------------------------------------------
-CtrlEdit* DrumEdit::addCtrl()
+CtrlEdit* DrumEdit::addCtrl(int ctl_num)
{
CtrlEdit* ctrlEdit = new CtrlEdit(split1, this, xscale, true, "drumCtrlEdit");
+ ctrlEdit->setController(ctl_num);
+ setupNewCtrl(ctrlEdit);
+ return ctrlEdit;
+ }
+
+//---------------------------------------------------------
+// setupNewCtrl
+//---------------------------------------------------------
+
+void DrumEdit::setupNewCtrl(CtrlEdit* ctrlEdit)
+{
connect(hscroll, SIGNAL(scrollChanged(int)), ctrlEdit, SLOT(setXPos(int)));
connect(hscroll, SIGNAL(scaleChanged(int)), ctrlEdit, SLOT(setXMag(int)));
connect(ctrlEdit, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned)));
@@ -1255,9 +1446,8 @@ CtrlEdit* DrumEdit::addCtrl()
ctrlEdit->show();
ctrlEditList.push_back(ctrlEdit);
- return ctrlEdit;
- }
-
+}
+
//---------------------------------------------------------
// removeCtrl
//---------------------------------------------------------
diff --git a/muse2/muse/midiedit/drumedit.h b/muse2/muse/midiedit/drumedit.h
index 7ebf2fd9..63246e2e 100644
--- a/muse2/muse/midiedit/drumedit.h
+++ b/muse2/muse/midiedit/drumedit.h
@@ -35,7 +35,9 @@
#include "shortcuts.h"
#include "event.h"
#include "dcanvas.h"
+#include "midictrl.h"
+class QAction;
class QCloseEvent;
class QLabel;
class QMenu;
@@ -44,6 +46,7 @@ class QResizeEvent;
class QToolButton;
class QWidget;
class QComboBox;
+class QPushButton;
namespace MusECore {
@@ -110,6 +113,7 @@ class DrumEdit : public MidiEditor {
MusEGui::Header* header;
QToolBar* tools;
QComboBox *stepLenWidget;
+ QPushButton* ctrl;
static int _rasterInit;
static int _dlistWidthInit, _dcanvasWidthInit;
@@ -123,6 +127,7 @@ class DrumEdit : public MidiEditor {
QAction *groupNoneAction, *groupChanAction, *groupMaxAction;
void initShortcuts();
+ void setupNewCtrl(CtrlEdit* ctrlEdit);
virtual void closeEvent(QCloseEvent*);
QWidget* genToolbar(QWidget* parent);
@@ -147,6 +152,8 @@ class DrumEdit : public MidiEditor {
void configChanged();
void songChanged1(MusECore::SongChangedFlags_t);
void setStep(QString);
+ void addCtrlClicked();
+ void ctrlPopupTriggered(QAction* act);
void updateGroupingActions();
void set_ignore_hide(bool);
@@ -165,7 +172,6 @@ class DrumEdit : public MidiEditor {
void execDeliveredScript(int);
void execUserScript(int);
void focusCanvas();
- CtrlEdit* addCtrl();
void ourDrumMapChanged(bool);
virtual void updateHScrollRange();
@@ -180,6 +186,8 @@ class DrumEdit : public MidiEditor {
static void readConfiguration(MusECore::Xml& xml);
static void writeConfiguration(int, MusECore::Xml&);
+ CtrlEdit* addCtrl(int ctl_num = MusECore::CTRL_VELOCITY);
+
bool old_style_drummap_mode() { return _old_style_drummap_mode; }
group_mode_t group_mode() { return _group_mode; }
bool ignore_hide() { return _ignore_hide; }
diff --git a/muse2/muse/midiedit/pianoroll.cpp b/muse2/muse/midiedit/pianoroll.cpp
index 9ede827e..44b0cc66 100644
--- a/muse2/muse/midiedit/pianoroll.cpp
+++ b/muse2/muse/midiedit/pianoroll.cpp
@@ -62,6 +62,8 @@
#include "audio.h"
#include "functions.h"
#include "helper.h"
+#include "popupmenu.h"
+#include "menutitleitem.h"
#include "cmd.h"
@@ -314,7 +316,7 @@ PianoRoll::PianoRoll(MusECore::PartList* pl, QWidget* parent, const char* name,
hsplitter->setChildrenCollapsible(true);
hsplitter->setHandleWidth(2);
- QPushButton* ctrl = new QPushButton(tr("ctrl"), mainw);
+ ctrl = new QPushButton(tr("ctrl"), mainw);
ctrl->setObjectName("Ctrl");
ctrl->setFont(MusEGlobal::config.fonts[3]);
ctrl->setToolTip(tr("Add Controller View"));
@@ -401,7 +403,7 @@ PianoRoll::PianoRoll(MusECore::PartList* pl, QWidget* parent, const char* name,
connect(tools2, SIGNAL(toolChanged(int)), canvas, SLOT(setTool(int)));
- connect(ctrl, SIGNAL(clicked()), SLOT(addCtrl()));
+ connect(ctrl, SIGNAL(clicked()), SLOT(addCtrlClicked()));
connect(info, SIGNAL(valueChanged(MusEGui::NoteInfo::ValType, int)), SLOT(noteinfoChanged(MusEGui::NoteInfo::ValType, int)));
connect(info, SIGNAL(deltaModeChanged(bool)), SLOT(deltaModeChanged(bool)));
@@ -793,29 +795,217 @@ void PianoRoll::noteinfoChanged(MusEGui::NoteInfo::ValType type, int val)
}
//---------------------------------------------------------
+// ctrlPopupTriggered
+//---------------------------------------------------------
+
+void PianoRoll::ctrlPopupTriggered(QAction* act)
+{
+ // TODO Merge most of this with duplicate code in drum edit,
+ // maybe by putting it in a new function near populateMidiCtrlMenu.
+
+ if(!act || (act->data().toInt() == -1))
+ return;
+
+ int newCtlNum = -1;
+ MusECore::Part* part = curCanvasPart();
+ MusECore::MidiTrack* track = (MusECore::MidiTrack*)(part->track());
+ int channel = track->outChannel();
+ MusECore::MidiPort* port = &MusEGlobal::midiPorts[track->outPort()];
+ int curDrumPitch = curDrumInstrument();
+ 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();
+
+ MusECore::MidiCtrlValListList* cll = port->controller();
+ int min = channel << 24;
+ int max = min + 0x1000000;
+
+ int rv = act->data().toInt();
+
+ if (rv == max) { // special case velocity
+ newCtlNum = MusECore::CTRL_VELOCITY;
+ }
+ else if (rv == max + 1) { // add new instrument controller
+
+ PopupMenu * ctrlSubPop = new PopupMenu(this, true); // true = enable stay open
+ ctrlSubPop->addAction(new MenuTitleItem(tr("Instrument-defined"), ctrlSubPop));
+
+ //
+ // populate popup with all controllers available for
+ // current instrument
+ //
+
+ for (MusECore::iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci)
+ {
+ int num = ci->second->num();
+ if((num & 0xff) == 0xff)
+ {
+ 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;
+ }
+
+ if(cll->find(channel, num) == cll->end())
+ ctrlSubPop->addAction(MusECore::midiCtrlNumString(num, true) + ci->second->name())->setData(num);
+ }
+
+ // Don't allow editing instrument if it's a synth
+ if(!port->device() || port->device()->deviceType() != MusECore::MidiDevice::SYNTH_MIDI)
+ ctrlSubPop->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit instrument ..."))->setData(max + 2);
+
+ QAction *act2 = ctrlSubPop->exec(ctrl->mapToGlobal(QPoint(0,0)));
+ if (act2)
+ {
+ int rv2 = act2->data().toInt();
+
+ if (rv2 == max + 2) // edit instrument
+ MusEGlobal::muse->startEditInstrument();
+ else // select new instrument control
+ {
+ MusECore::MidiController* c;
+ for (MusECore::iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci)
+ {
+ c = ci->second;
+ int num = c->num();
+ 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;
+
+ if(cll->find(channel, num) == cll->end())
+ {
+ MusECore::MidiCtrlValList* vl = new MusECore::MidiCtrlValList(num);
+
+ cll->add(channel, vl);
+ newCtlNum = c->num();
+ }
+ else
+ newCtlNum = c->num();
+ break;
+ }
+ }
+ }
+ delete ctrlSubPop;
+ }
+
+ //else if (rv == max + 2) // edit instrument
+ // MusEGlobal::muse->startEditInstrument();
+
+ else if (rv == max + 3) { // add new other controller
+ PopupMenu* ctrlSubPop = new PopupMenu(this, true); // true = enable stay open
+ ctrlSubPop->addAction(new MenuTitleItem(tr("Common Controls"), ctrlSubPop));
+
+ for(int num = 0; num < 127; ++num)
+ if(cll->find(channel, num) == cll->end())
+ ctrlSubPop->addAction(MusECore::midiCtrlName(num, true))->setData(num);
+ QAction *act2 = ctrlSubPop->exec(ctrl->mapToGlobal(QPoint(0,0)));
+ if (act2) {
+ int rv2 = act2->data().toInt();
+ int num = rv2;
+ 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);
+
+ cll->add(channel, vl);
+ newCtlNum = rv2;
+ }
+ else
+ newCtlNum = rv2;
+ }
+ delete ctrlSubPop;
+ }
+ else { // Select a control
+ MusECore::iMidiCtrlValList i = cll->begin();
+ for (; i != cll->end(); ++i) {
+ MusECore::MidiCtrlValList* cl = i->second;
+ MusECore::MidiController* c = port->midiController(cl->num());
+ if (c->num() == rv) {
+ newCtlNum = c->num();
+ break;
+ }
+ }
+ if (i == cll->end()) {
+ printf("PianoRoll: controller number %d not found!", rv);
+ }
+ }
+
+ if(newCtlNum != -1)
+ {
+ CtrlEdit* ctrlEdit = new CtrlEdit(ctrlLane, this, xscale, false, "pianoCtrlEdit");
+ ctrlEdit->setController(newCtlNum);
+ setupNewCtrl(ctrlEdit);
+ }
+}
+
+//---------------------------------------------------------
+// addCtrlClicked
+//---------------------------------------------------------
+
+void PianoRoll::addCtrlClicked()
+{
+ PopupMenu* pup = new PopupMenu(true); // true = enable stay open. Don't bother with parent.
+ connect(pup, SIGNAL(triggered(QAction*)), SLOT(ctrlPopupTriggered(QAction*)));
+
+ int est_width = populateMidiCtrlMenu(pup, parts(), curCanvasPart(), -1); // _curDrumInstrument);
+
+ QPoint ep = ctrl->mapToGlobal(QPoint(0,0));
+ //int newx = ep.x() - ctrlMainPop->width(); // Too much! Width says 640. Maybe because it hasn't been shown yet .
+ int newx = ep.x() - est_width;
+ if(newx < 0)
+ newx = 0;
+ ep.setX(newx);
+ pup->exec(ep);
+ delete pup;
+
+ ctrl->setDown(false);
+}
+
+//---------------------------------------------------------
// addCtrl
//---------------------------------------------------------
-CtrlEdit* PianoRoll::addCtrl()
+CtrlEdit* PianoRoll::addCtrl(int ctl_num)
{
CtrlEdit* ctrlEdit = new CtrlEdit(ctrlLane/* formerly splitter*/, this, xscale, false, "pianoCtrlEdit"); // ccharrett
- connect(tools2, SIGNAL(toolChanged(int)), ctrlEdit, SLOT(setTool(int)));
- connect(hscroll, SIGNAL(scrollChanged(int)), ctrlEdit, SLOT(setXPos(int)));
- connect(hscroll, SIGNAL(scaleChanged(int)), ctrlEdit, SLOT(setXMag(int)));
- connect(ctrlEdit, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned)));
- connect(ctrlEdit, SIGNAL(destroyedCtrl(CtrlEdit*)), SLOT(removeCtrl(CtrlEdit*)));
- connect(ctrlEdit, SIGNAL(yposChanged(int)), toolbar, SLOT(setInt(int)));
-
- ctrlEdit->setTool(tools2->curTool());
- ctrlEdit->setXPos(hscroll->pos());
- ctrlEdit->setXMag(hscroll->getScaleValue());
-
- ctrlEdit->show();
- ctrlEditList.push_back(ctrlEdit);
+ ctrlEdit->setController(ctl_num);
+ setupNewCtrl(ctrlEdit);
return ctrlEdit;
}
//---------------------------------------------------------
+// setupNewCtrl
+//---------------------------------------------------------
+
+void PianoRoll::setupNewCtrl(CtrlEdit* ctrlEdit)
+{
+ connect(tools2, SIGNAL(toolChanged(int)), ctrlEdit, SLOT(setTool(int)));
+ connect(hscroll, SIGNAL(scrollChanged(int)), ctrlEdit, SLOT(setXPos(int)));
+ connect(hscroll, SIGNAL(scaleChanged(int)), ctrlEdit, SLOT(setXMag(int)));
+ connect(ctrlEdit, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned)));
+ connect(ctrlEdit, SIGNAL(destroyedCtrl(CtrlEdit*)), SLOT(removeCtrl(CtrlEdit*)));
+ connect(ctrlEdit, SIGNAL(yposChanged(int)), toolbar, SLOT(setInt(int)));
+
+ ctrlEdit->setTool(tools2->curTool());
+ ctrlEdit->setXPos(hscroll->pos());
+ ctrlEdit->setXMag(hscroll->getScaleValue());
+
+ ctrlEdit->show();
+ ctrlEditList.push_back(ctrlEdit);
+}
+
+//---------------------------------------------------------
// removeCtrl
//---------------------------------------------------------
diff --git a/muse2/muse/midiedit/pianoroll.h b/muse2/muse/midiedit/pianoroll.h
index 9c699724..75e3c9af 100644
--- a/muse2/muse/midiedit/pianoroll.h
+++ b/muse2/muse/midiedit/pianoroll.h
@@ -35,6 +35,7 @@
#include "midieditor.h"
#include "tools.h"
#include "event.h"
+#include "midictrl.h"
class QAction;
class QLabel;
@@ -129,7 +130,8 @@ class PianoRoll : public MidiEditor {
MusEGui::Splitter* splitter;
MusEGui::Splitter* hsplitter;
MusEGui::Splitter* ctrlLane;
-
+ QPushButton* ctrl;
+
QToolButton* speaker;
QToolBar* tools;
MusEGui::EditToolBar* tools2;
@@ -146,6 +148,7 @@ class PianoRoll : public MidiEditor {
void initShortcuts();
+ void setupNewCtrl(CtrlEdit* ctrlEdit);
void setEventColorMode(int);
QWidget* genToolbar(QWidget* parent);
virtual void closeEvent(QCloseEvent*);
@@ -171,6 +174,8 @@ class PianoRoll : public MidiEditor {
void toggleTrackInfo();
void updateTrackInfo();
void deltaModeChanged(bool);
+ void addCtrlClicked();
+ void ctrlPopupTriggered(QAction* act);
signals:
void isDeleting(MusEGui::TopWin*);
@@ -180,7 +185,6 @@ class PianoRoll : public MidiEditor {
void execDeliveredScript(int id);
void execUserScript(int id);
void focusCanvas();
- CtrlEdit* addCtrl();
public:
PianoRoll(MusECore::PartList*, QWidget* parent = 0, const char* name = 0, unsigned initPos = INT_MAX);
@@ -189,6 +193,7 @@ class PianoRoll : public MidiEditor {
virtual void writeStatus(int, MusECore::Xml&) const;
static void readConfiguration(MusECore::Xml&);
static void writeConfiguration(int, MusECore::Xml&);
+ CtrlEdit* addCtrl(int ctl_num = MusECore::CTRL_VELOCITY);
};
} // namespace MusEGui
diff --git a/muse2/muse/midiport.cpp b/muse2/muse/midiport.cpp
index b36781bc..c1288e6e 100644
--- a/muse2/muse/midiport.cpp
+++ b/muse2/muse/midiport.cpp
@@ -21,6 +21,8 @@
//
//=========================================================
+#include <set>
+
#include <QMenu>
#include <QApplication>
@@ -30,13 +32,17 @@
#include "midi.h"
#include "minstrument.h"
#include "xml.h"
+#include "gconfig.h"
#include "globals.h"
+#include "globaldefs.h"
#include "mpevent.h"
#include "synth.h"
#include "app.h"
#include "song.h"
#include "menutitleitem.h"
#include "icons.h"
+#include "track.h"
+#include "drummap.h"
namespace MusEGlobal {
MusECore::MidiPort midiPorts[MIDI_PORTS];
@@ -68,6 +74,7 @@ void initMidiPorts()
MidiPort::MidiPort()
: _state("not configured")
{
+ _initializationsSent = false;
_defaultInChannels = (1 << MIDI_CHANNELS) -1; // p4.0.17 Default is now to connect to all channels.
_defaultOutChannels = 0;
_device = 0;
@@ -143,6 +150,7 @@ void MidiPort::setMidiDevice(MidiDevice* dev)
_instrument = genericMidiInstrument;
_device->setPort(-1);
_device->close();
+ _initializationsSent = false;
}
if (dev) {
for (int i = 0; i < MIDI_PORTS; ++i) {
@@ -163,70 +171,7 @@ void MidiPort::setMidiDevice(MidiDevice* dev)
}
_state = _device->open();
_device->setPort(portno());
-
- // By T356. Send all instrument controller initial (default) values to all midi channels now,
- // except where explicitly initialized in the song.
- // By sending ALL instrument controller initial values, even if those controllers are NOT
- // in the song, we can ensure better consistency between songs.
- // For example: A song is loaded which has a 'reverb level' controller initial value of '100'.
- // Then a song is loaded which has no such controller (hence no explicit initial value).
- // The 'reverb level' controller would still be at '100', and could adversely affect the song,
- // but if the instrument has an available initial value of say '0', it will be used instead.
- //
-
- // NOT for syntis. Use midiState and/or initParams for that.
- if(_instrument && !_device->isSynti())
- {
- MidiControllerList* cl = _instrument->controller();
- MidiController* mc;
- for(ciMidiController imc = cl->begin(); imc != cl->end(); ++imc)
- {
- mc = imc->second;
- for(int chan = 0; chan < MIDI_CHANNELS; ++chan)
- {
- ciMidiCtrlValList i;
- // Look for an initial value for this midi controller, on this midi channel, in the song...
- for(i = _controller->begin(); i != _controller->end(); ++i)
- {
- int channel = i->first >> 24;
- int cntrl = i->first & 0xffffff;
- int val = i->second->hwVal();
- if(channel == chan && cntrl == mc->num() && val != CTRL_VAL_UNKNOWN)
- break;
- }
- // If no initial value was found for this midi controller, on this midi channel, in the song...
- if(i == _controller->end())
- {
- // If the instrument's midi controller has an initial value, send it now.
- if(mc->initVal() != CTRL_VAL_UNKNOWN)
- {
- int ctl = mc->num();
- // Note the addition of bias!
- // Retry added. Use default attempts and delay.
- _device->putEventWithRetry(MidiPlayEvent(0, portno(), chan,
- ME_CONTROLLER, ctl, mc->initVal() + mc->bias()));
- // Set it once so the 'last HW value' is set, and control knobs are positioned at the value...
- // Set it again so that control labels show 'off'...
- setHwCtrlStates(chan, ctl, CTRL_VAL_UNKNOWN, mc->initVal() + mc->bias());
- }
- }
- }
- }
- }
-
- // init HW controller state
- for (iMidiCtrlValList i = _controller->begin(); i != _controller->end(); ++i) {
- int channel = i->first >> 24;
- int cntrl = i->first & 0xffffff;
- int val = i->second->hwVal();
- if (val != CTRL_VAL_UNKNOWN) {
- // Retry added. Use default attempts and delay.
- _device->putEventWithRetry(MidiPlayEvent(0, portno(), channel,
- ME_CONTROLLER, cntrl, val));
- // Set it once so the 'last HW value' is set, and control knobs are positioned at the value...
- setHwCtrlState(channel, cntrl, val);
- }
- }
+ _initializationsSent = false;
}
else
@@ -234,12 +179,182 @@ void MidiPort::setMidiDevice(MidiDevice* dev)
}
//---------------------------------------------------------
+// sendPendingInitializations
+// Return true if success.
+//---------------------------------------------------------
+
+bool MidiPort::sendPendingInitializations(bool force)
+{
+ if(!_device || !(_device->openFlags() & 1)) // Not writable?
+ return false;
+
+ bool rv = true;
+ int port = portno();
+
+ //
+ // test for explicit instrument initialization
+ //
+
+ unsigned last_tick = 0;
+ MusECore::MidiInstrument* instr = instrument();
+ if(instr && MusEGlobal::config.midiSendInit && (force || !_initializationsSent))
+ {
+ // Send the Instrument Init sequences.
+ EventList* events = instr->midiInit();
+ if(!events->empty())
+ {
+ for(iEvent ie = events->begin(); ie != events->end(); ++ie)
+ {
+ unsigned tick = ie->second.tick();
+ if(tick > last_tick)
+ last_tick = tick;
+ MusECore::MidiPlayEvent ev(tick, port, 0, ie->second);
+ _device->putEvent(ev);
+ }
+ // Give a bit of time for the last Init sysex to settle?
+ last_tick += 100;
+ }
+ _initializationsSent = true; // Mark as having been sent.
+ }
+
+ // Send the Instrument controller default values.
+ sendInitialControllers(last_tick);
+
+ return rv;
+}
+
+//---------------------------------------------------------
+// sendInitialControllers
+// Return true if success.
+//---------------------------------------------------------
+
+bool MidiPort::sendInitialControllers(unsigned start_time)
+{
+ bool rv = true;
+ int port = portno();
+
+ // Find all channels of this port used in the song...
+ bool usedChans[MIDI_CHANNELS];
+ int usedChanCount = 0;
+ for(int i = 0; i < MIDI_CHANNELS; ++i)
+ usedChans[i] = false;
+ if(MusEGlobal::song->click() && MusEGlobal::clickPort == port)
+ {
+ usedChans[MusEGlobal::clickChan] = true;
+ ++usedChanCount;
+ }
+ bool drum_found = false;
+ for(ciMidiTrack imt = MusEGlobal::song->midis()->begin(); imt != MusEGlobal::song->midis()->end(); ++imt)
+ {
+ if((*imt)->type() == MusECore::Track::DRUM)
+ {
+ if(!drum_found)
+ {
+ drum_found = true;
+ for(int i = 0; i < DRUM_MAPSIZE; ++i)
+ {
+ if(MusEGlobal::drumMap[i].port != port || usedChans[MusEGlobal::drumMap[i].channel])
+ continue;
+ usedChans[MusEGlobal::drumMap[i].channel] = true;
+ ++usedChanCount;
+ if(usedChanCount >= MIDI_CHANNELS)
+ break; // All are used, done searching.
+ }
+ }
+ }
+ else
+ {
+ if((*imt)->outPort() != port || usedChans[(*imt)->outChannel()])
+ continue;
+ usedChans[(*imt)->outChannel()] = true;
+ ++usedChanCount;
+ }
+
+ if(usedChanCount >= MIDI_CHANNELS)
+ break; // All are used, done searching.
+ }
+
+ // NOT for syntis. Use midiState and/or initParams for that.
+ if(MusEGlobal::config.midiSendInit && MusEGlobal::config.midiSendCtlDefaults && _instrument && !_device->isSynti())
+ {
+ MidiControllerList* cl = _instrument->controller();
+ MidiController* mc;
+ for(ciMidiController imc = cl->begin(); imc != cl->end(); ++imc)
+ {
+ mc = imc->second;
+ for(int chan = 0; chan < MIDI_CHANNELS; ++chan)
+ {
+ if(!usedChans[chan])
+ continue; // This channel on this port is not used in the song.
+ ciMidiCtrlValList i;
+ // Look for an initial value for this midi controller, on this midi channel, in the song...
+ for(i = _controller->begin(); i != _controller->end(); ++i)
+ {
+ int channel = i->first >> 24;
+ int cntrl = i->first & 0xffffff;
+ int val = i->second->hwVal();
+ if(channel == chan && cntrl == mc->num() && val != CTRL_VAL_UNKNOWN)
+ break;
+ }
+ // If no initial value was found for this midi controller, on this midi channel, in the song...
+ if(i == _controller->end())
+ {
+ // If the instrument's midi controller has an initial value, send it now.
+ if(mc->initVal() != CTRL_VAL_UNKNOWN)
+ {
+ int ctl = mc->num();
+ // Note the addition of bias!
+ // Retry added. Use default attempts and delay.
+ _device->putEventWithRetry(MidiPlayEvent(start_time, port, chan,
+ ME_CONTROLLER, ctl, mc->initVal() + mc->bias()));
+ // Set it once so the 'last HW value' is set, and control knobs are positioned at the value...
+ // Set it again so that control labels show 'off'...
+ setHwCtrlStates(chan, ctl, CTRL_VAL_UNKNOWN, mc->initVal() + mc->bias());
+ }
+ }
+ }
+ }
+ }
+
+ // init HW controller state
+ for (iMidiCtrlValList i = _controller->begin(); i != _controller->end(); ++i)
+ {
+ int channel = i->first >> 24;
+ if(!usedChans[channel])
+ continue; // This channel on this port is not used in the song.
+ int cntrl = i->first & 0xffffff;
+ int val = i->second->hwVal();
+ if (val != CTRL_VAL_UNKNOWN)
+ {
+ // Retry added. Use default attempts and delay.
+ _device->putEventWithRetry(MidiPlayEvent(start_time, port, channel,
+ ME_CONTROLLER, cntrl, val));
+ // Set it once so the 'last HW value' is set, and control knobs are positioned at the value...
+ setHwCtrlState(channel, cntrl, val);
+ }
+ }
+
+ return rv;
+}
+
+//---------------------------------------------------------
+// setInstrument
+//---------------------------------------------------------
+
+void MidiPort::setInstrument(MidiInstrument* i)
+{
+ _instrument = i;
+ _initializationsSent = false;
+}
+
+//---------------------------------------------------------
// clearDevice
//---------------------------------------------------------
void MidiPort::clearDevice()
{
_device = 0;
+ _initializationsSent = false;
_state = "not configured";
}
diff --git a/muse2/muse/midiport.h b/muse2/muse/midiport.h
index 0faccce2..3acaa6ee 100644
--- a/muse2/muse/midiport.h
+++ b/muse2/muse/midiport.h
@@ -59,6 +59,9 @@ class MidiPort {
// When creating a new midi track, add these global default channel routes to/from this port. Ignored if 0.
int _defaultInChannels; // These are bit-wise channel masks.
int _defaultOutChannels; //
+ // Whether Init sysexes and default controller values have been sent. To be reset whenever
+ // something about the port changes like device, Jack routes, or instrument.
+ bool _initializationsSent;
RouteList _inRoutes, _outRoutes;
@@ -98,7 +101,7 @@ class MidiPort {
void setMidiDevice(MidiDevice* dev);
const QString& portname() const;
MidiInstrument* instrument() const { return _instrument; }
- void setInstrument(MidiInstrument* i) { _instrument = i; }
+ void setInstrument(MidiInstrument* i);
MidiController* midiController(int num) const;
MidiCtrlValList* addManagedController(int channel, int ctrl);
void tryCtrlInitVal(int chan, int ctl, int val);
@@ -136,6 +139,13 @@ class MidiPort {
unsigned char s, unsigned char f, unsigned char sf, int devid = -1);
void sendMMCStop(int devid = -1);
void sendMMCDeferredPlay(int devid = -1);
+
+ // Send Instrument Init sequences and controller defaults etc.
+ bool sendPendingInitializations(bool force = true); // Per port
+ // Send initial controller values. Called by above method, and elsewhere.
+ bool sendInitialControllers(unsigned start_time = 0);
+ bool initSent() const { return _initializationsSent; }
+ void clearInitSent() { _initializationsSent = false; }
bool sendHwCtrlState(const MidiPlayEvent&, bool forceSend = false );
bool sendEvent(const MidiPlayEvent&, bool forceSend = false );
diff --git a/muse2/muse/midiseq.cpp b/muse2/muse/midiseq.cpp
index 2cfc1917..32e9de4c 100644
--- a/muse2/muse/midiseq.cpp
+++ b/muse2/muse/midiseq.cpp
@@ -203,11 +203,6 @@ void MidiSeq::processStop()
void MidiSeq::processSeek()
{
- int pos = MusEGlobal::audio->tickPos();
- // TODO Try to move this into MusEGlobal::audio::seek().
- if (pos == 0 && !MusEGlobal::song->record())
- MusEGlobal::audio->initDevices();
-
//---------------------------------------------------
// set all controller
//---------------------------------------------------
diff --git a/muse2/muse/mpevent.cpp b/muse2/muse/mpevent.cpp
index 1ad09ff3..c1b0e5dc 100644
--- a/muse2/muse/mpevent.cpp
+++ b/muse2/muse/mpevent.cpp
@@ -211,13 +211,7 @@ bool MEvent::operator<(const MEvent& e) const
// notes
if (channel() == e.channel())
- {
-// REMOVE Tim.
-// return (type() == ME_NOTEOFF
-// || (type() == ME_NOTEON && dataB() == 0)
-// || type() != ME_NOTEON; // Make note-ons last so that controllers such as program come before notes played. 1/31/2012 Tim.
return sortingWeight() < e.sortingWeight();
- }
int map[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 14, 15 };
return map[channel()] < map[e.channel()];
diff --git a/muse2/muse/route.cpp b/muse2/muse/route.cpp
index 18672159..223b763a 100644
--- a/muse2/muse/route.cpp
+++ b/muse2/muse/route.cpp
@@ -265,6 +265,9 @@ void addRoute(Route src, Route dst)
#ifdef ROUTE_DEBUG
fprintf(stderr, "addRoute: dst Jack src Jack midi name: %s pushing destination route\n", src.device->name().toLatin1().constData());
#endif
+ if(src.device->midiPort() != -1)
+ // Initializations sysex etc. need to be sent to the new connection.
+ MusEGlobal::midiPorts[src.device->midiPort()].clearInitSent();
routes->push_back(dst);
}
else
diff --git a/muse2/muse/seqmsg.cpp b/muse2/muse/seqmsg.cpp
index f60a2d51..fcffc332 100644
--- a/muse2/muse/seqmsg.cpp
+++ b/muse2/muse/seqmsg.cpp
@@ -39,6 +39,8 @@
#include "arranger.h"
#include "plugin.h"
#include "driver/jackmidi.h"
+#include "midi_warn_init_pending_impl.h"
+#include "gconfig.h"
namespace MusECore {
@@ -1114,11 +1116,82 @@ void Audio::msgResetMidiDevices()
// msgInitMidiDevices
//---------------------------------------------------------
-void Audio::msgInitMidiDevices()
+void Audio::msgInitMidiDevices(bool force)
{
+ //
+ // test for explicit instrument initialization
+ //
+
+ if(!force && MusEGlobal::config.warnInitPending)
+ {
+ bool found = false;
+ if(MusEGlobal::song->click())
+ {
+ MidiPort* mp = &MusEGlobal::midiPorts[MusEGlobal::clickPort];
+ if(mp->device() &&
+ (mp->device()->openFlags() & 1) &&
+ mp->instrument() && !mp->instrument()->midiInit()->empty() &&
+ !mp->initSent())
+ found = true;
+ }
+
+ if(!found)
+ {
+ for(int i = 0; i < MIDI_PORTS; ++i)
+ {
+ MidiPort* mp = &MusEGlobal::midiPorts[i];
+ if(mp->device() && (mp->device()->openFlags() & 1) &&
+ mp->instrument() && !mp->instrument()->midiInit()->empty() &&
+ !mp->initSent())
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if(found)
+ {
+ MusEGui::MidiWarnInitPendingDialog dlg;
+ int rv = dlg.exec();
+ bool warn = !dlg.dontAsk();
+ if(warn != MusEGlobal::config.warnInitPending)
+ {
+ MusEGlobal::config.warnInitPending = warn;
+ //MusEGlobal::muse->changeConfig(true); // Save settings? No, wait till close.
+ }
+ if(rv != QDialog::Accepted)
+ {
+ if(MusEGlobal::config.midiSendInit)
+ MusEGlobal::config.midiSendInit = false;
+ //return;
+ }
+ else
+ {
+ if(!MusEGlobal::config.midiSendInit)
+ MusEGlobal::config.midiSendInit = true;
+ }
+ }
+ }
+
+// We can either try to do it in one cycle with one message,
+// or by idling the sequencer (gaining safe access to all structures)
+// for as much time as we need.
+// Here we COULD get away with the audio 'hiccup' that idling causes,
+// because it's unlikely someone would initialize during play...
+// But no midi is processed, so let's switch this only if requiring
+// large numbers of init values causes a problem later...
+#if 1
AudioMsg msg;
msg.id = SEQM_INIT_DEVICES;
+ msg.a = force;
sendMessage(&msg, false);
+#else
+ msgIdle(true);
+ initDevices(force);
+ msgIdle(false);
+#endif
+
}
//---------------------------------------------------------
diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp
index 8f189759..036892f0 100644
--- a/muse2/muse/song.cpp
+++ b/muse2/muse/song.cpp
@@ -2113,8 +2113,8 @@ void Song::clear(bool signal, bool clear_all)
// Clear all midi port controller values.
for(int i = 0; i < MIDI_PORTS; ++i)
- // Don't remove the controllers, just the values.
- MusEGlobal::midiPorts[i].controller()->clearDelete(false);
+ // Remove the controllers AND the values so we start with a clean slate.
+ MusEGlobal::midiPorts[i].controller()->clearDelete(true);
_masterFlag = true;
loopFlag = false;
diff --git a/muse2/muse/widgets/CMakeLists.txt b/muse2/muse/widgets/CMakeLists.txt
index 0e9d369d..3aad8b92 100644
--- a/muse2/muse/widgets/CMakeLists.txt
+++ b/muse2/muse/widgets/CMakeLists.txt
@@ -54,12 +54,14 @@ QT4_WRAP_CPP (widget_mocs
hitscale.h
intlabel.h
knob.h
+ knob_and_meter.h
lcombo.h
menutitleitem.h
meter.h
metronome.h
midi_audio_control.h
midisyncimpl.h
+ midi_warn_init_pending_impl.h
mixdowndialog.h
mlabel.h
mtscale.h
@@ -125,6 +127,7 @@ file (GLOB widgets_ui_files
itransformbase.ui
metronomebase.ui
midisync.ui
+ midi_warn_init_pending.ui
midi_audio_control_base.ui
mittransposebase.ui
mixdowndialogbase.ui
@@ -170,12 +173,14 @@ file (GLOB widgets_source_files
hitscale.cpp
intlabel.cpp
knob.cpp
+ knob_and_meter.cpp
lcombo.cpp
menutitleitem.cpp
meter.cpp
metronome.cpp
midi_audio_control.cpp
midisyncimpl.cpp
+ midi_warn_init_pending_impl.cpp
mixdowndialog.cpp
mlabel.cpp
mmath.cpp
diff --git a/muse2/muse/widgets/genset.cpp b/muse2/muse/widgets/genset.cpp
index 5d94a41d..5c4b2dfb 100644
--- a/muse2/muse/widgets/genset.cpp
+++ b/muse2/muse/widgets/genset.cpp
@@ -153,6 +153,9 @@ void GlobalSettingsConfig::updateSettings()
}
}
+ midiSendInit->setChecked(MusEGlobal::config.midiSendInit);
+ midiWarnInitPending->setChecked(MusEGlobal::config.warnInitPending);
+ midiSendCtlDefaults->setChecked(MusEGlobal::config.midiSendCtlDefaults);
guiRefreshSelect->setValue(MusEGlobal::config.guiRefresh);
minSliderSelect->setValue(int(MusEGlobal::config.minSlider));
minMeterSelect->setValue(MusEGlobal::config.minMeter);
@@ -269,6 +272,9 @@ void GlobalSettingsConfig::apply()
MusEGlobal::config.useOutputLimiter = outputLimiterCheckBox->isChecked();
MusEGlobal::config.vstInPlace = vstInPlaceCheckBox->isChecked();
MusEGlobal::config.rtcTicks = rtcResolutions[rtcticks];
+ MusEGlobal::config.midiSendInit = midiSendInit->isChecked();
+ MusEGlobal::config.warnInitPending = midiWarnInitPending->isChecked();
+ MusEGlobal::config.midiSendCtlDefaults = midiSendCtlDefaults->isChecked();
MusEGlobal::config.projectBaseFolder = projDirEntry->text();
diff --git a/muse2/muse/widgets/gensetbase.ui b/muse2/muse/widgets/gensetbase.ui
index c204b9f4..30d823ec 100644
--- a/muse2/muse/widgets/gensetbase.ui
+++ b/muse2/muse/widgets/gensetbase.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>525</width>
- <height>549</height>
+ <width>544</width>
+ <height>593</height>
</rect>
</property>
<property name="windowTitle">
@@ -37,7 +37,7 @@
</property>
<layout class="QHBoxLayout" name="qhboxProjDir">
<property name="spacing">
- <number>-1</number>
+ <number>6</number>
</property>
<item>
<widget class="QLabel" name="textLabel_ProjDir">
@@ -1029,14 +1029,94 @@ Adjusts responsiveness of audio controls and
<attribute name="title">
<string>Midi</string>
</attribute>
- <layout class="QVBoxLayout" name="verticalLayout_7">
- <item>
+ <layout class="QGridLayout" name="gridLayout_7">
+ <item row="2" column="0">
+ <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>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="dontRecMutedButton">
+ <property name="text">
+ <string>Don't record muted instruments</string>
+ </property>
+ </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 row="1" column="0">
+ <widget class="QGroupBox" name="groupBox_5">
+ <property name="title">
+ <string>Instrument initialization</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QCheckBox" name="midiSendInit">
+ <property name="text">
+ <string>Send instrument initialization sequences</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="midiWarnInitPending">
+ <property name="text">
+ <string>Warn if instrument initialization sequences pending</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="midiSendCtlDefaults">
+ <property name="text">
+ <string>Send instrument controller default values if none in song, at init or rewind</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <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>
+ <item row="0" column="0">
<widget class="QGroupBox" name="GroupBox2">
<property name="title">
<string>Ticks</string>
</property>
- <layout class="QGridLayout">
- <item row="0" column="0">
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0" rowspan="2">
<widget class="QLabel" name="TextLabel3">
<property name="text">
<string>RTC Resolution
@@ -1049,6 +1129,12 @@ Adjusts responsiveness of audio controls and
</item>
<item row="0" column="1">
<widget class="QComboBox" name="rtcResolutionSelect">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<item>
<property name="text">
<string>1024</string>
@@ -1081,19 +1167,14 @@ Adjusts responsiveness of audio controls and
</item>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="midiResLabel">
- <property name="text">
- <string>Midi Resolution
-(Ticks/Quarternote)</string>
- </property>
- <property name="wordWrap">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
+ <item row="1" column="1" rowspan="2">
<widget class="QComboBox" name="midiDivisionSelect">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<property name="currentIndex">
<number>3</number>
</property>
@@ -1145,6 +1226,17 @@ Adjusts responsiveness of audio controls and
</widget>
</item>
<item row="2" column="0">
+ <widget class="QLabel" name="midiResLabel">
+ <property name="text">
+ <string>Midi Resolution
+(Ticks/Quarternote)</string>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
<widget class="QLabel" name="TextLabel4">
<property name="text">
<string>Displayed Resolution
@@ -1155,8 +1247,14 @@ Adjusts responsiveness of audio controls and
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="3" column="1">
<widget class="QComboBox" name="guiDivisionSelect">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<property name="currentIndex">
<number>3</number>
</property>
@@ -1210,56 +1308,6 @@ Adjusts responsiveness of audio controls and
</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>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="dontRecMutedButton">
- <property name="text">
- <string>Don't record muted instruments</string>
- </property>
- </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">
@@ -1629,8 +1677,8 @@ left button behave like the middle button in such areas.</string>
<rect>
<x>0</x>
<y>0</y>
- <width>481</width>
- <height>386</height>
+ <width>96</width>
+ <height>26</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
diff --git a/muse2/muse/widgets/knob.h b/muse2/muse/widgets/knob.h
index 114284d0..fcaedfaa 100644
--- a/muse2/muse/widgets/knob.h
+++ b/muse2/muse/widgets/knob.h
@@ -49,7 +49,7 @@ class Knob : public SliderBase, public ScaleIf
gainType,
};
- private:
+ protected:
bool hasScale;
int d_borderWidth;
@@ -81,7 +81,7 @@ class Knob : public SliderBase, public ScaleIf
void recalcAngle();
void valueChange();
void rangeChange();
- void drawKnob(QPainter *p, const QRect &r);
+ virtual void drawKnob(QPainter *p, const QRect &r);
void drawMarker(QPainter *p, double arc, const QColor &c);
virtual void paintEvent(QPaintEvent *);
diff --git a/muse2/muse/widgets/knob_and_meter.cpp b/muse2/muse/widgets/knob_and_meter.cpp
new file mode 100644
index 00000000..482becae
--- /dev/null
+++ b/muse2/muse/widgets/knob_and_meter.cpp
@@ -0,0 +1,609 @@
+//======================================================================
+// MusE
+// Linux Music Editor
+// knob_and_meter.cpp
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
+//
+// 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 <stdio.h>
+#include "knob_and_meter.h"
+#include <cmath>
+#include "mmath.h"
+
+#include <QPainter>
+#include <QPainterPath>
+#include <QPalette>
+#include <QPaintEvent>
+#include <QResizeEvent>
+
+namespace MusEGui {
+
+//---------------------------------------------------------
+// The QwtKnob widget imitates look and behaviour of a volume knob on a radio.
+// It contains
+// a scale around the knob which is set up automatically or can
+// be configured manually (see @^QwtScaleIf@).
+// Automatic scrolling is enabled when the user presses a mouse
+// button on the scale. For a description of signals, slots and other
+// members, see QwtSliderBase@.
+//---------------------------------------------------------
+
+
+//---------------------------------------------------------
+// KnobWithMeter
+//---------------------------------------------------------
+
+KnobWithMeter::KnobWithMeter(QWidget* parent, const char* name)
+ : Knob(parent, name)
+ {
+// hasScale = false;
+//
+// d_borderWidth = 4;
+// d_shineWidth = 3;
+// d_totalAngle = 270.0;
+// d_scaleDist = 1;
+// d_symbol = Line;
+// d_maxScaleTicks = 11;
+// d_knobWidth = 30;
+// _faceColSel = FALSE;
+// d_faceColor = palette().color(QPalette::Window);
+// d_rimColor = palette().mid().color();
+// d_shinyColor = palette().mid().color();
+// d_curFaceColor = d_faceColor;
+// d_altFaceColor = d_faceColor;
+// d_markerColor = palette().dark().color().darker(125);
+// d_dotWidth = 8;
+//
+// l_slope = 0;
+// l_const = 100;
+//
+// setMinimumSize(30,30);
+// setUpdateTime(50);
+ }
+
+//------------------------------------------------------------
+// QwtKnob::setTotalAngle
+// Set the total angle by which the knob can be turned
+//
+// Syntax
+// void QwtKnob::setTotalAngle(double angle)
+//
+// Parameters
+// double angle -- angle in degrees.
+//
+// Description
+// The default angle is 270 degrees. It is possible to specify
+// an angle of more than 360 degrees so that the knob can be
+// turned several times around its axis.
+//------------------------------------------------------------
+
+// void Knob::setTotalAngle (double angle)
+// {
+// if (angle < 10.0)
+// d_totalAngle = 10.0;
+// else
+// d_totalAngle = angle;
+// d_scale.setAngleRange( -0.5 * d_totalAngle, 0.5 * d_totalAngle);
+// }
+//
+//------------------------------------------------------------
+// Knob::setRange
+// Set the range and step size of the knob
+//
+// Sets the paramaters that define the shininess of the ring
+// surrounding the knob and then proceeds by passing the
+// parameters to the parent class' setRange() function.
+//------------------------------------------------------------
+
+// void Knob::setRange(double vmin, double vmax, double vstep, int pagesize)
+// {
+// //if(vmin == d_minValue && vmax == d_maxValue && vstep == d_step && pageSize == d_pageSize) // p4.0.45
+// // return;
+//
+// // divide by zero protection. probably too cautious
+// if (! (vmin == vmax || qMax(-vmin, vmax) == 0))
+// {
+// if (vmin * vmax < 0)
+// l_slope = 80.0 / qMax(-vmin, vmax);
+// else
+// {
+// l_slope = 80.0 / (vmax - vmin);
+// l_const = 100 - l_slope * vmin;
+// }
+// }
+// SliderBase::setRange(vmin, vmax, vstep, pagesize);
+// }
+//
+//------------------------------------------------------------
+// QwtKnob::drawKnob
+// const QRect &r -- borders of the knob
+//------------------------------------------------------------
+
+void KnobWithMeter::drawKnob(QPainter* p, const QRect& r)
+ {
+ const QPalette& pal = palette();
+
+ QRect aRect;
+ aRect.setRect(kRect.x() + d_borderWidth,
+ kRect.y() + d_borderWidth,
+ kRect.width() - 2*d_borderWidth,
+ kRect.height() - 2*d_borderWidth);
+
+ int width = kRect.width();
+ int height = kRect.height();
+ int size = qMin(width, height);
+
+ p->setRenderHint(QPainter::Antialiasing, true);
+
+ QPainterPath drawingPath, updatePath, finalPath, cornerPath;
+
+ //
+ // draw the rim
+ //
+
+ QLinearGradient linearg(QPoint(r.x(),r.y()), QPoint(size, size));
+ linearg.setColorAt(1 - M_PI_4, d_faceColor.lighter(125));
+ linearg.setColorAt(M_PI_4, d_faceColor.darker(175));
+ p->setBrush(linearg);
+ p->setPen(Qt::NoPen);
+ p->drawEllipse(r.x(),r.y(),size,size);
+
+
+ //
+ // draw shiny surrounding
+ //
+
+ QPen pn;
+ pn.setCapStyle(Qt::FlatCap);
+
+ pn.setColor(d_shinyColor.lighter(l_const + abs(value() * l_slope)));
+ pn.setWidth(d_shineWidth * 2);
+ p->setPen(pn);
+ p->drawArc(aRect, 0, 360 * 16);
+
+ //
+ // draw button face
+ //
+
+ QRadialGradient gradient(size/2, size/2, size-d_borderWidth, size/2-d_borderWidth, size/2-d_borderWidth);
+ gradient.setColorAt(0, d_curFaceColor.lighter(150));
+ gradient.setColorAt(1, d_curFaceColor.darker(150));
+ p->setBrush(gradient);
+ p->setPen(Qt::NoPen);
+ p->drawEllipse(aRect);
+
+ //
+ // draw marker
+ //
+ //drawMarker(p, d_angle, isEnabled() ? d_markerColor : Qt::gray);
+ drawMarker(p, d_angle, pal.currentColorGroup() == QPalette::Disabled ?
+ pal.color(QPalette::Disabled, QPalette::WindowText) : d_markerColor);
+ }
+
+//------------------------------------------------------------
+//.F QwtSliderBase::valueChange
+// Notify change of value
+//
+//.u Parameters
+// double x -- new value
+//
+//.u Description
+// Sets the slider's value to the nearest multiple
+// of the step size.
+//------------------------------------------------------------
+
+// void Knob::valueChange()
+// {
+// recalcAngle();
+// d_newVal++;
+// repaint(kRect);
+// SliderBase::valueChange();
+// }
+//
+//------------------------------------------------------------
+//.F QwtKnob::getValue
+// Determine the value corresponding to a specified position
+//
+//.u Parameters:
+// const QPoint &p -- point
+//
+//.u Description:
+// Called by QwtSliderBase
+//------------------------------------------------------------
+
+// double Knob::getValue(const QPoint &p)
+// {
+// double newValue;
+// double oneTurn;
+// double eqValue;
+// double arc;
+//
+// const QRect& r = rect();
+//
+// double dx = double((r.x() + r.width() / 2) - p.x() );
+// double dy = double((r.y() + r.height() / 2) - p.y() );
+//
+// arc = atan2(-dx,dy) * 180.0 / M_PI;
+//
+// newValue = 0.5 * (minValue() + maxValue())
+// + (arc + d_nTurns * 360.0) * (maxValue() - minValue())
+// / d_totalAngle;
+//
+// oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_totalAngle;
+// eqValue = value() + d_mouseOffset;
+//
+// if (fabs(newValue - eqValue) > 0.5 * oneTurn)
+// {
+// if (newValue < eqValue)
+// newValue += oneTurn;
+// else
+// newValue -= oneTurn;
+// }
+//
+// return newValue;
+//
+// }
+//
+
+
+//------------------------------------------------------------
+//.-
+//.F QwtKnob::setScrollMode
+// Determine the scrolling mode and direction
+// corresponding to a specified position
+//
+//.u Parameters
+// const QPoint &p -- point in question
+//
+//.u Description
+// Called by QwtSliderBase
+//------------------------------------------------------------
+// void Knob::getScrollMode( QPoint &p, const Qt::MouseButton &/*button*/, int &scrollMode, int &direction)// prevent compiler warning : unsused parameter
+// {
+// int dx, dy, r;
+// double arc;
+//
+// /*Qt::ButtonState but= button ;*/ // prevent compiler warning : unsused variable
+// r = kRect.width() / 2;
+//
+// dx = kRect.x() + r - p.x();
+// dy = kRect.y() + r - p.y();
+//
+// if ( (dx * dx) + (dy * dy) <= (r * r)) // point is inside the knob
+// {
+// scrollMode = ScrMouse;
+// direction = 0;
+// }
+// else // point lies outside
+// {
+// scrollMode = ScrTimer;
+// arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
+// if ( arc < d_angle)
+// direction = -1;
+// else if (arc > d_angle)
+// direction = 1;
+// else
+// direction = 0;
+// }
+// return;
+// }
+//
+
+
+//------------------------------------------------------------
+//.F QwtKnob::rangeChange
+// Notify a change of the range
+//
+//.u Description
+// Called by QwtSliderBase
+//------------------------------------------------------------
+
+// void Knob::rangeChange()
+// {
+// if (!hasUserScale())
+// {
+// d_scale.setScale(minValue(), maxValue(),
+// d_maxMajor, d_maxMinor);
+// }
+// recalcAngle();
+// resize(size());
+// repaint();
+// }
+
+void KnobWithMeter::mousePressEvent(QMouseEvent *e)
+{
+// if (e->button() == Qt::MidButton || e->modifiers() & Qt::ControlModifier) {
+// int xpos = e->x() - width() /2;
+// double v = float(e->y()) / height() * 1.2;
+//
+// double halfRange = (maxValue() - minValue())/2;
+// double midValue = minValue() + halfRange;
+// // apply to range
+// if (xpos < 0) { // left values
+// v = -v;
+// }
+// setValue(v * halfRange + midValue);
+// SliderBase::valueChange();
+// emit sliderMoved(value(),id()); // sliderMoved is used by auxChanged
+//
+// // fake a left-click to make the knob still "stick" to
+// // the mouse.
+// QMouseEvent temp(e->type(), e->pos(), Qt::LeftButton, e->buttons(), e->modifiers());
+// SliderBase::mousePressEvent(&temp);
+// return;
+// }
+ Knob::mousePressEvent(e);
+}
+
+//---------------------------------------------------------
+// resizeEvent
+//---------------------------------------------------------
+
+void KnobWithMeter::resizeEvent(QResizeEvent* ev)
+ {
+ Knob::resizeEvent(ev);
+// int width, width_2;
+//
+// const QRect& r = rect();
+//
+// // printf("resize %d %d %d\n", r.height(), r.width(), d_knobWidth);
+//
+// // width = MusECore::qwtMin(MusECore::qwtMin(r.height(), r.width()), d_knobWidth);
+// width = MusECore::qwtMin(r.height(), r.width());
+// width_2 = width / 2;
+//
+// int x = r.x() + r.width() / 2 - width_2;
+// int y = r.y() + r.height() / 2 - width_2;
+//
+// kRect.setRect(x, y, width, width);
+//
+// x = kRect.x() - d_scaleDist;
+// y = kRect.y() - d_scaleDist;
+// int w = width + 2 * d_scaleDist;
+//
+// d_scale.setGeometry(x, y, w, ScaleDraw::Round);
+ }
+
+//------------------------------------------------------------
+// paintEvent
+//------------------------------------------------------------
+
+void KnobWithMeter::paintEvent(QPaintEvent* e)
+ {
+/* QPainter p(this);
+ const QRect &r = e->rect();
+
+ if ((r == kRect) && d_newVal ) { // event from valueChange()
+ if (d_newVal > 1) // lost paintEvents()?
+ drawKnob(&p, kRect);
+ else {
+ drawMarker(&p, d_oldAngle, d_curFaceColor);
+ drawMarker(&p, d_angle, d_markerColor);
+ }
+ }
+ else {
+ p.eraseRect(rect());
+ if (hasScale)
+ d_scale.draw(&p);
+ drawKnob(&p, kRect);
+ }
+ d_newVal = 0;
+*/
+
+ const QRect &r = e->rect();
+ QPainter p(this);
+ p.setRenderHint(QPainter::Antialiasing, true);
+ if(hasScale)
+ d_scale.draw(&p);
+
+ ///drawKnob(&p, kRect);
+ drawKnob(&p, r);
+
+ //drawMarker(&p, d_oldAngle, d_curFaceColor);
+ //drawMarker(&p, d_angle, d_markerColor);
+
+ d_newVal = 0;
+ }
+
+//------------------------------------------------------------
+//.-
+//.F QwtKnob::drawMarker
+// Draw the marker at the knob's front
+//
+//.u Parameters
+//.p QPainter *p -- painter
+// double arc -- angle of the marker
+// const QColor &c -- marker color
+//
+//.u Syntax
+// void QwtKnob::drawMarker(QPainter *p)
+//
+//------------------------------------------------------------
+// void Knob::drawMarker(QPainter *p, double arc, const QColor &c)
+// {
+//
+// QPen pn;
+// int radius;
+// double rb,re;
+// double rarc;
+//
+// rarc = arc * M_PI / 180.0;
+// double ca = cos(rarc);
+// double sa = - sin(rarc);
+//
+// radius = kRect.width() / 2 - d_borderWidth + d_shineWidth;
+// if (radius < 3) radius = 3;
+// int ym = kRect.y() + radius + d_borderWidth - d_shineWidth;
+// int xm = kRect.x() + radius + d_borderWidth - d_shineWidth;
+//
+// switch (d_symbol)
+// {
+// case Dot:
+//
+// p->setBrush(c);
+// p->setPen(Qt::NoPen);
+// rb = double(MusECore::qwtMax(radius - 4 - d_dotWidth / 2, 0));
+// p->drawEllipse(xm - int(rint(sa * rb)) - d_dotWidth / 2,
+// ym - int(rint(ca * rb)) - d_dotWidth / 2,
+// d_dotWidth, d_dotWidth);
+//
+// break;
+//
+// case Line:
+//
+// pn.setColor(c);
+// pn.setWidth(2);
+// p->setPen(pn);
+//
+// rb = MusECore::qwtMax(double((radius - 1) / 3.0), 0.0);
+// re = MusECore::qwtMax(double(radius - 1), 0.0);
+//
+// p->setRenderHint(QPainter::Antialiasing, true);
+// p->drawLine( xm,
+// ym,
+// xm - int(rint(sa * re)),
+// ym - int(rint(ca * re)));
+//
+// break;
+// }
+//
+//
+// }
+//
+
+//------------------------------------------------------------
+//
+//.F QwtKnob::setKnobWidth
+// Change the knob's width.
+//
+//.u Syntax
+//.f void QwtKnob::setKnobWidth(int w)
+//
+//.u Parameters
+//.p int w -- new width
+//
+//.u Description
+// The specified width must be >= 5, or it will be clipped.
+//
+//------------------------------------------------------------
+// void Knob::setKnobWidth(int w)
+// {
+// d_knobWidth = MusECore::qwtMax(w,5);
+// resize(size());
+// repaint();
+// }
+//
+//------------------------------------------------------------
+//
+//.F QwtKnob::setBorderWidth
+// Set the knob's border width
+//
+//.u Syntax
+//.f void QwtKnob::setBorderWidth(int bw)
+//
+//.u Parameters
+//.p int bw -- new border width
+//
+//------------------------------------------------------------
+// void Knob::setBorderWidth(int bw)
+// {
+// d_borderWidth = MusECore::qwtMax(bw, 0);
+// resize(size());
+// repaint();
+// }
+
+//------------------------------------------------------------
+//.-
+//.F QwtKnob::recalcAngle
+// Recalculate the marker angle corresponding to the
+// current value
+//
+//.u Syntax
+//.f void QwtKnob::recalcAngle()
+//
+//------------------------------------------------------------
+// void Knob::recalcAngle()
+// {
+// d_oldAngle = d_angle;
+//
+// //
+// // calculate the angle corresponding to the value
+// //
+// if (maxValue() == minValue())
+// {
+// d_angle = 0;
+// d_nTurns = 0;
+// }
+// else
+// {
+// d_angle = (value() - 0.5 * (minValue() + maxValue()))
+// / (maxValue() - minValue()) * d_totalAngle;
+// d_nTurns = floor((d_angle + 180.0) / 360.0);
+// d_angle = d_angle - d_nTurns * 360.0;
+//
+// }
+//
+// }
+//
+//------------------------------------------------------------
+// setFaceColor
+//------------------------------------------------------------
+// void Knob::setFaceColor(const QColor c)
+// {
+// d_faceColor = c;
+// if(!_faceColSel)
+// //update(FALSE);
+// repaint();
+// }
+
+//------------------------------------------------------------
+// setAltFaceColor
+//------------------------------------------------------------
+// void Knob::setAltFaceColor(const QColor c)
+// {
+// d_altFaceColor = c;
+// if(_faceColSel)
+// //update(FALSE);
+// repaint();
+// }
+
+//------------------------------------------------------------
+// selectFaceColor
+//------------------------------------------------------------
+// void Knob::selectFaceColor(bool alt)
+// {
+// _faceColSel = alt;
+// if(alt)
+// d_curFaceColor = d_altFaceColor;
+// else
+// d_curFaceColor = d_faceColor;
+// //update(FALSE);
+// repaint();
+// }
+
+//------------------------------------------------------------
+// setMarkerColor
+//------------------------------------------------------------
+// void Knob::setMarkerColor(const QColor c)
+// {
+// d_markerColor = c;
+// //update(FALSE);
+// repaint();
+// }
+
+} // namespace MusEGui
diff --git a/muse2/muse/widgets/knob_and_meter.h b/muse2/muse/widgets/knob_and_meter.h
new file mode 100644
index 00000000..989c8567
--- /dev/null
+++ b/muse2/muse/widgets/knob_and_meter.h
@@ -0,0 +1,114 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// knob_and_meter.h
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
+//
+// 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 __KNOB_AND_METER_H__
+#define __KNOB_AND_METER_H__
+
+#include "knob.h"
+#include "sclif.h"
+#include <QColor>
+#include <QResizeEvent>
+#include <QPaintEvent>
+
+namespace MusEGui {
+
+//---------------------------------------------------------
+// KnobWithMeter
+//---------------------------------------------------------
+
+class KnobWithMeter : public Knob
+ {
+ Q_OBJECT
+
+// public:
+// enum Symbol { Line, Dot };
+//
+// enum KnobType {
+// panType,
+// auxType,
+// gainType,
+// };
+//
+// private:
+// bool hasScale;
+//
+// int d_borderWidth;
+// int d_shineWidth;
+// int d_scaleDist;
+// int d_maxScaleTicks;
+// int d_newVal;
+// int d_knobWidth;
+// int d_dotWidth;
+//
+// Symbol d_symbol;
+// double d_angle;
+// double d_oldAngle;
+// double d_totalAngle;
+// double d_nTurns;
+//
+// double l_const;
+// double l_slope;
+//
+// QRect kRect;
+// bool _faceColSel;
+// QColor d_faceColor;
+// QColor d_shinyColor;
+// QColor d_rimColor;
+// QColor d_curFaceColor;
+// QColor d_altFaceColor;
+// QColor d_markerColor;
+//
+// void recalcAngle();
+// void valueChange();
+// void rangeChange();
+ void drawKnob(QPainter *p, const QRect &r);
+// void drawMarker(QPainter *p, double arc, const QColor &c);
+
+ virtual void paintEvent(QPaintEvent *e);
+ virtual void resizeEvent(QResizeEvent *e);
+ virtual void mousePressEvent(QMouseEvent *e);
+// double getValue(const QPoint &p);
+// void getScrollMode( QPoint &p, const Qt::MouseButton &button, int &scrollMode, int &direction );
+// void scaleChange() { repaint(); }
+// void fontChange(const QFont &) { repaint(); }
+
+ public:
+ KnobWithMeter(QWidget* parent = 0, const char *name = 0);
+ ~KnobWithMeter() {}
+
+// void setRange(double vmin, double vmax, double vstep = 0.0,
+// int pagesize = 1);
+// void setKnobWidth(int w);
+// void setTotalAngle (double angle);
+// void setBorderWidth(int bw);
+// void selectFaceColor(bool alt);
+// bool selectedFaceColor() { return _faceColSel; }
+// QColor faceColor() { return d_faceColor; }
+// void setFaceColor(const QColor c);
+// QColor altFaceColor() { return d_altFaceColor; }
+// void setAltFaceColor(const QColor c);
+// QColor markerColor() { return d_markerColor; }
+// void setMarkerColor(const QColor c);
+ };
+
+} // namespace MusEGui
+
+#endif
diff --git a/muse2/muse/widgets/midi_warn_init_pending.ui b/muse2/muse/widgets/midi_warn_init_pending.ui
new file mode 100644
index 00000000..7b88811b
--- /dev/null
+++ b/muse2/muse/widgets/midi_warn_init_pending.ui
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>midiWarnInitPendingBase</class>
+ <widget class="QDialog" name="midiWarnInitPendingBase">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>371</width>
+ <height>207</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Instrument initialization</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>MusE should now send some Instrument Initialization Sequences.
+The sequences (usually System Exclusive messages) are defined
+ by the selected instruments in the Settings -&gt; Midi Ports dialog,
+ such as the GM (default), GS, or XG instruments.
+
+Typically you should answer yes here.
+You can always do it manually from the Midi menu.
+
+Continue?</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::AutoText</enum>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="dontAskAgain">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Don't ask me again</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::No|QDialogButtonBox::Yes</set>
+ </property>
+ <property name="centerButtons">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>midiWarnInitPendingBase</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>midiWarnInitPendingBase</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/muse2/muse/widgets/midi_warn_init_pending_impl.cpp b/muse2/muse/widgets/midi_warn_init_pending_impl.cpp
new file mode 100644
index 00000000..41e9b51f
--- /dev/null
+++ b/muse2/muse/widgets/midi_warn_init_pending_impl.cpp
@@ -0,0 +1,33 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// midi_warn_init_pending_impl.cpp
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
+//
+// 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 "midi_warn_init_pending_impl.h"
+
+namespace MusEGui {
+
+MidiWarnInitPendingDialog::MidiWarnInitPendingDialog()
+{
+ setupUi(this);
+}
+
+} // namespace MusEGui
+
diff --git a/muse2/muse/widgets/midi_warn_init_pending_impl.h b/muse2/muse/widgets/midi_warn_init_pending_impl.h
new file mode 100644
index 00000000..d24ee129
--- /dev/null
+++ b/muse2/muse/widgets/midi_warn_init_pending_impl.h
@@ -0,0 +1,40 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// midi_warn_init_pending_impl.h
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
+//
+// 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 __MIDI_WARN_INIT_PENDING_IMPL_H__
+#define __MIDI_WARN_INIT_PENDING_IMPL_H__
+
+#include "ui_midi_warn_init_pending.h"
+
+namespace MusEGui {
+
+class MidiWarnInitPendingDialog : public QDialog, public Ui::midiWarnInitPendingBase
+{
+ Q_OBJECT
+
+public:
+ MidiWarnInitPendingDialog();
+ bool dontAsk() const { return dontAskAgain->isChecked(); }
+};
+
+} // namespace MusEGui
+
+#endif \ No newline at end of file
diff --git a/muse2/muse/widgets/musewidgetsplug.cpp b/muse2/muse/widgets/musewidgetsplug.cpp
index 83a9fca9..70cdcd0f 100644
--- a/muse2/muse/widgets/musewidgetsplug.cpp
+++ b/muse2/muse/widgets/musewidgetsplug.cpp
@@ -155,6 +155,9 @@ MusEGlobal::GlobalConfigValues config = {
384, // division;
1024, // rtcTicks
+ true, // midiSendInit Send instrument initialization sequences
+ true, // warnInitPending Warn instrument initialization sequences pending
+ false, // midiSendCtlDefaults Send instrument controller defaults at position 0 if none in song
-60, // int minMeter;
-60.0, // double minSlider;
false, // use Jack freewheel
diff --git a/muse2/muse/widgets/synthconfigbase.ui b/muse2/muse/widgets/synthconfigbase.ui
index 500241a8..266518e4 100644
--- a/muse2/muse/widgets/synthconfigbase.ui
+++ b/muse2/muse/widgets/synthconfigbase.ui
@@ -6,72 +6,14 @@
<rect>
<x>0</x>
<y>0</y>
- <width>810</width>
- <height>492</height>
+ <width>820</width>
+ <height>475</height>
</rect>
</property>
<property name="windowTitle">
<string>Midi Port and Soft Synth Configuration</string>
</property>
- <layout class="QGridLayout">
- <item row="1" column="1">
- <widget class="QGroupBox" name="GroupBox3">
- <property name="title">
- <string>Instances</string>
- </property>
- <layout class="QGridLayout">
- <item row="0" column="0">
- <widget class="QTreeWidget" name="instanceList">
- <property name="allColumnsShowFocus">
- <bool>true</bool>
- </property>
- <column>
- <property name="text">
- <string>Name</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Type</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Midi Port</string>
- </property>
- </column>
- </widget>
- </item>
- <item row="1" column="0">
- <layout class="QHBoxLayout">
- <item>
- <widget class="QPushButton" name="removeInstance">
- <property name="text">
- <string>Remove Instance</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="Spacer2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>113</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
+ <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox10">
<property name="title">
@@ -170,6 +112,95 @@
</layout>
</widget>
</item>
+ <item row="1" column="1">
+ <widget class="QGroupBox" name="GroupBox3">
+ <property name="title">
+ <string>Instances</string>
+ </property>
+ <layout class="QGridLayout">
+ <item row="0" column="0">
+ <widget class="QTreeWidget" name="instanceList">
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Midi Port</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QPushButton" name="removeInstance">
+ <property name="text">
+ <string>Remove Instance</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="Spacer2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>113</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="applyButton">
+ <property name="text">
+ <string>&amp;Apply</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton">
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
diff --git a/muse2/share/templates/MusE.cfg b/muse2/share/templates/MusE.cfg
index 927234e0..4d5840d6 100644
--- a/muse2/share/templates/MusE.cfg
+++ b/muse2/share/templates/MusE.cfg
@@ -227,8 +227,24 @@
<topwin>
<width>934</width>
<height>488</height>
- <nonshared_toolbars>000000ff00000000fd00000000000003a60000015a00000004000000040000000800000008fc0000000300000002000000050000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff000000000000000000000014004400720075006d00200074006f006f006c00730100000049ffffffff000000000000000000000014004500640069007400200054006f006f006c007301000000f7ffffffff000000000000000000000012007400720061006e00730070006f00720074010000019affffffff00000000000000000000000a00700061006e0069006301000002c0000000f8000000000000000000000002000000030000000c0063007500720073006f00720100000000ffffffff0000000000000000000000260050006f0073002f0053006e00610070002f0053006f006c006f002d0074006f006f006c00730100000081ffffffff000000000000000000000012004e006f0074006500200049006e0066006f01000001b9ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b0000026b0000000000000000</nonshared_toolbars>
- <shared_toolbars>000000ff00000000fd00000000000004000000022900000004000000040000000800000008fc0000000300000002000000060000001800460069006c006500200042007500740074006f006e00730100000000ffffffff00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000085ffffffff000000000000000000000014004400720075006d00200074006f006f006c007301000000ceffffffff000000000000000000000014004500640069007400200054006f006f006c0073010000017cffffffff000000000000000000000012007400720061006e00730070006f00720074010000021fffffffff00000000000000000000000a00700061006e00690063010000034500000120000000000000000000000002000000030000000c0063007500720073006f00720100000000ffffffff0000000000000000000000260050006f0073002f0053006e00610070002f0053006f006c006f002d0074006f006f006c00730100000081ffffffff000000000000000000000012004e006f0074006500200049006e0066006f01000001b9ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000</shared_toolbars>
+ <nonshared_toolbars>000000ff00000000fd00000000000003a60000015a00000004000000040000000800000008fc0000000300000002000000050000001e
+0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff000000000000000000000014004400720075006d0020007400
+6f006f006c00730100000049ffffffff000000000000000000000014004500640069007400200054006f006f006c007301000000f7ffffffff00000000000000
+0000000012007400720061006e00730070006f00720074010000019affffffff00000000000000000000000a00700061006e0069006301000002c0000000f800
+0000000000000000000002000000030000000c0063007500720073006f00720100000000ffffffff0000000000000000000000260050006f0073002f0053006e
+00610070002f0053006f006c006f002d0074006f006f006c00730100000081ffffffff000000000000000000000012004e006f0074006500200049006e006600
+6f01000001b9ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300
+690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0100
+00013b0000026b0000000000000000</nonshared_toolbars>
+ <shared_toolbars>000000ff00000000fd00000000000004000000022900000004000000040000000800000008fc000000030000000200000006000
+0001800460069006c006500200042007500740074006f006e00730100000000ffffffff00000000000000000000001e0055006e0064006f002f0052006500640
+06f00200074006f006f006c00730100000085ffffffff000000000000000000000014004400720075006d00200074006f006f006c007301000000ceffffffff0
+00000000000000000000014004500640069007400200054006f006f006c0073010000017cffffffff000000000000000000000012007400720061006e0073007
+0006f00720074010000021fffffffff00000000000000000000000a00700061006e0069006301000003450000012000000000000000000000000200000003000
+0000c0063007500720073006f00720100000000ffffffff0000000000000000000000260050006f0073002f0053006e00610070002f0053006f006c006f002d0
+074006f006f006c00730100000081ffffffff000000000000000000000012004e006f0074006500200049006e0066006f01000001b9ffffffff0000000000000
+00000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010
+000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000</shared_toolbars>
<shares_when_free>0</shares_when_free>
<shares_when_subwin>1</shares_when_subwin>
<default_subwin>0</default_subwin>
@@ -240,8 +256,23 @@
<topwin>
<width>852</width>
<height>460</height>
- <nonshared_toolbars>000000ff00000000fd00000000000003540000013e00000004000000040000000800000008fc0000000300000002000000050000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000001e005000690061006e006f0072006f006c006c00200074006f006f006c00730100000049ffffffff000000000000000000000014004500640069007400200054006f006f006c007301000000b000000098000000000000000000000012007400720061006e00730070006f007200740100000148ffffffff00000000000000000000000a00700061006e00690063010000026e000000f800000000000000000000000200000002000000260050006f0073002f0053006e00610070002f0053006f006c006f002d0074006f006f006c00730100000000ffffffff000000000000000000000012004e006f0074006500200049006e0066006f0100000162ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002190000000000000000</nonshared_toolbars>
- <shared_toolbars>000000ff00000000fd00000000000004000000022900000004000000040000000800000008fc0000000300000002000000060000001800460069006c006500200042007500740074006f006e00730100000000ffffffff00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000085ffffffff00000000000000000000001e005000690061006e006f0072006f006c006c00200074006f006f006c007301000000ceffffffff000000000000000000000014004500640069007400200054006f006f006c00730100000135ffffffff000000000000000000000012007400720061006e00730070006f0072007401000001baffffffff00000000000000000000000a00700061006e0069006301000002e00000012000000000000000000000000200000002000000260050006f0073002f0053006e00610070002f0053006f006c006f002d0074006f006f006c00730100000000ffffffff000000000000000000000012004e006f0074006500200049006e0066006f0100000162ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000</shared_toolbars>
+ <nonshared_toolbars>000000ff00000000fd00000000000003540000013e00000004000000040000000800000008fc000000030000000200000005
+0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000001e005000690061006e00
+6f0072006f006c006c00200074006f006f006c00730100000049ffffffff000000000000000000000014004500640069007400200054006f006f006c00730100
+0000b000000098000000000000000000000012007400720061006e00730070006f007200740100000148ffffffff00000000000000000000000a00700061006e
+00690063010000026e000000f800000000000000000000000200000002000000260050006f0073002f0053006e00610070002f0053006f006c006f002d007400
+6f006f006c00730100000000ffffffff000000000000000000000012004e006f0074006500200049006e0066006f0100000162ffffffff000000000000000000
+000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e0061007400750072006501000000
+8bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002190000000000000000</nonshared_toolbars>
+ <shared_toolbars>000000ff00000000fd00000000000004000000022900000004000000040000000800000008fc000000030000000200000006000
+0001800460069006c006500200042007500740074006f006e00730100000000ffffffff00000000000000000000001e0055006e0064006f002f0052006500640
+06f00200074006f006f006c00730100000085ffffffff00000000000000000000001e005000690061006e006f0072006f006c006c00200074006f006f006c007
+301000000ceffffffff000000000000000000000014004500640069007400200054006f006f006c00730100000135ffffffff000000000000000000000012007
+400720061006e00730070006f0072007401000001baffffffff00000000000000000000000a00700061006e0069006301000002e000000120000000000000000
+00000000200000002000000260050006f0073002f0053006e00610070002f0053006f006c006f002d0074006f006f006c00730100000000ffffffff000000000
+000000000000012004e006f0074006500200049006e0066006f0100000162ffffffff000000000000000000000002000000030000000a00540065006d0070006
+f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006
+f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000</shared_toolbars>
<shares_when_free>0</shares_when_free>
<shares_when_subwin>1</shares_when_subwin>
<default_subwin>0</default_subwin>
@@ -259,8 +290,25 @@
<topwin>
<width>867</width>
<height>544</height>
- <nonshared_toolbars>000000ff00000000fd0000000000000363000001a700000004000000040000000800000008fc0000000300000002000000060000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000002800530074006500700020007200650063006f007200640069006e006700200074006f006f006c00730100000049ffffffff000000000000000000000014004500640069007400200054006f006f006c00730100000074ffffffff00000000000000000000002a005100750061006e007400690073006100740069006f006e002000730065007400740069006e0067007301000000dbffffffff000000000000000000000012007400720061006e00730070006f007200740100000224ffffffff00000000000000000000000a00700061006e006900630100000338000000420000000000000000000000020000000100000022004e006500770020006e006f00740065002000730065007400740069006e006700730100000000ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002d80000000000000000</nonshared_toolbars>
- <shared_toolbars>000000ff00000000fd00000000000004000000023d00000004000000040000000800000008fc0000000300000002000000060000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff00000000000000000000002800530074006500700020007200650063006f007200640069006e006700200074006f006f006c007301000000d5ffffffff000000000000000000000014004500640069007400200054006f006f006c00730100000100ffffffff000000000000000000000012007400720061006e00730070006f007200740100000167ffffffff00000000000000000000000a00700061006e00690063010000028d000001730000000000000000000000020000000200000022004e006500770020006e006f00740065002000730065007400740069006e006700730100000000ffffffff00000000000000000000002a005100750061006e007400690073006100740069006f006e002000730065007400740069006e00670073010000027a00000186000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000</shared_toolbars>
+ <nonshared_toolbars>000000ff00000000fd0000000000000363000001a700000004000000040000000800000008fc000000030000000200000006
+0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff000000000000000000000028005300740065007000
+20007200650063006f007200640069006e006700200074006f006f006c00730100000049ffffffff000000000000000000000014004500640069007400200054
+006f006f006c00730100000074ffffffff00000000000000000000002a005100750061006e007400690073006100740069006f006e0020007300650074007400
+69006e0067007301000000dbffffffff000000000000000000000012007400720061006e00730070006f007200740100000224ffffffff000000000000000000
+00000a00700061006e006900630100000338000000420000000000000000000000020000000100000022004e006500770020006e006f00740065002000730065
+007400740069006e006700730100000000ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff00000000
+0000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f007300
+6900740069006f006e010000013b000002d80000000000000000</nonshared_toolbars>
+ <shared_toolbars>000000ff00000000fd00000000000004000000023d00000004000000040000000800000008fc000000030000000200000006000
+0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640
+06f00200074006f006f006c0073010000008cffffffff00000000000000000000002800530074006500700020007200650063006f007200640069006e0067002
+00074006f006f006c007301000000d5ffffffff000000000000000000000014004500640069007400200054006f006f006c00730100000100ffffffff0000000
+00000000000000012007400720061006e00730070006f007200740100000167ffffffff00000000000000000000000a00700061006e00690063010000028d000
+001730000000000000000000000020000000200000022004e006500770020006e006f00740065002000730065007400740069006e006700730100000000fffff
+fff00000000000000000000002a005100750061006e007400690073006100740069006f006e002000730065007400740069006e00670073010000027a0000018
+6000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e006100740
+07500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c500000
+00000000000</shared_toolbars>
<shares_when_free>0</shares_when_free>
<shares_when_subwin>1</shares_when_subwin>
<default_subwin>0</default_subwin>
@@ -271,8 +319,21 @@
<topwin>
<width>784</width>
<height>544</height>
- <nonshared_toolbars>000000ff00000000fd0000000000000310000001b200000004000000040000000800000008fc0000000400000002000000050000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff000000000000000000000014004500640069007400200054006f006f006c00730100000049ffffffff000000000000000000000012007400720061006e00730070006f0072007401000000b0ffffffff00000000000000000000000a00700061006e0069006301000001d6ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e01000002010000010f000000000000000000000002000000020000001a0045006e00610062006c00650020006d006100730074006500720100000000ffffffff0000000000000000000000080049006e0066006f010000005dffffffff000000000000000000000002000000020000000a00540065006d0070006f0000000000ffffffff000000000000000000000012005300690067006e006100740075007200650000000000ffffffff00000000000000000000000200000000</nonshared_toolbars>
- <shared_toolbars>000000ff00000000fd00000000000004000000024900000004000000040000000800000008fc0000000400000002000000060000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff00000000000000000000001a0045006e00610062006c00650020006d0061007300740065007201000000d5ffffffff000000000000000000000014004500640069007400200054006f006f006c0073010000013200000071000000000000000000000012007400720061006e00730070006f0072007401000001a3ffffffff00000000000000000000000a00700061006e0069006301000002c9ffffffff00000000000000000000000200000002000000080049006e0066006f0100000000ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000025d000001a300000000000000000000000200000000000000020000000200000012005300690067006e006100740075007200650000000000ffffffff00000000000000000000000a00540065006d0070006f00000000b0ffffffff0000000000000000</shared_toolbars>
+ <nonshared_toolbars>000000ff00000000fd0000000000000310000001b200000004000000040000000800000008fc000000040000000200000005
+0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff000000000000000000000014004500640069007400
+200054006f006f006c00730100000049ffffffff000000000000000000000012007400720061006e00730070006f0072007401000000b0ffffffff0000000000
+0000000000000a00700061006e0069006301000001d6ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e
+01000002010000010f000000000000000000000002000000020000001a0045006e00610062006c00650020006d006100730074006500720100000000ffffffff
+0000000000000000000000080049006e0066006f010000005dffffffff000000000000000000000002000000020000000a00540065006d0070006f0000000000
+ffffffff000000000000000000000012005300690067006e006100740075007200650000000000ffffffff00000000000000000000000200000000</nonshared_toolbars>
+ <shared_toolbars>000000ff00000000fd00000000000004000000024900000004000000040000000800000008fc000000040000000200000006000
+0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640
+06f00200074006f006f006c0073010000008cffffffff00000000000000000000001a0045006e00610062006c00650020006d006100730074006500720100000
+0d5ffffffff000000000000000000000014004500640069007400200054006f006f006c007301000001320000007100000000000000000000001200740072006
+1006e00730070006f0072007401000001a3ffffffff00000000000000000000000a00700061006e0069006301000002c9ffffffff00000000000000000000000
+200000002000000080049006e0066006f0100000000ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0
+10000025d000001a300000000000000000000000200000000000000020000000200000012005300690067006e006100740075007200650000000000ffffffff0
+0000000000000000000000a00540065006d0070006f00000000b0ffffffff0000000000000000</shared_toolbars>
<shares_when_free>0</shares_when_free>
<shares_when_subwin>1</shares_when_subwin>
<default_subwin>0</default_subwin>
@@ -283,8 +344,19 @@
<topwin>
<width>797</width>
<height>478</height>
- <nonshared_toolbars>000000ff00000000fd000000000000031d0000018200000004000000040000000800000008fc0000000200000002000000040000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000001c0057006100760065004500640069007400200074006f006f006c007301000000490000010f000000000000000000000012007400720061006e00730070006f007200740100000158ffffffff00000000000000000000000a00700061006e00690063010000027e0000009f000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000001e20000000000000000</nonshared_toolbars>
- <shared_toolbars>000000ff00000000fd00000000000004000000025b00000004000000040000000800000008fc0000000200000002000000050000001800460069006c006500200042007500740074006f006e00730100000000ffffffff00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000085ffffffff00000000000000000000001c0057006100760065004500640069007400200074006f006f006c007301000000ceffffffff000000000000000000000012007400720061006e00730070006f0072007401000001d1ffffffff00000000000000000000000a00700061006e0069006301000002f700000109000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000</shared_toolbars>
+ <nonshared_toolbars>000000ff00000000fd000000000000031d0000018200000004000000040000000800000008fc000000020000000200000004
+0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000001c005700610076006500
+4500640069007400200074006f006f006c007301000000490000010f000000000000000000000012007400720061006e00730070006f007200740100000158ff
+ffffff00000000000000000000000a00700061006e00690063010000027e0000009f000000000000000000000002000000030000000a00540065006d0070006f
+0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f
+006e006700200050006f0073006900740069006f006e010000013b000001e20000000000000000</nonshared_toolbars>
+ <shared_toolbars>000000ff00000000fd00000000000004000000025b00000004000000040000000800000008fc000000020000000200000005000
+0001800460069006c006500200042007500740074006f006e00730100000000ffffffff00000000000000000000001e0055006e0064006f002f0052006500640
+06f00200074006f006f006c00730100000085ffffffff00000000000000000000001c0057006100760065004500640069007400200074006f006f006c0073010
+00000ceffffffff000000000000000000000012007400720061006e00730070006f0072007401000001d1ffffffff00000000000000000000000a00700061006
+e0069006301000002f700000109000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff00000000000000000000001
+2005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f0
+06e010000013b000002c50000000000000000</shared_toolbars>
<shares_when_free>0</shares_when_free>
<shares_when_subwin>1</shares_when_subwin>
<default_subwin>0</default_subwin>
@@ -294,8 +366,19 @@
<topwin>
<width>756</width>
<height>364</height>
- <nonshared_toolbars>000000ff00000000fd00000000000002f40000013000000004000000040000000800000008fc0000000100000002000000070000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000000a00700061006e006900630100000049ffffffff000000000000000000000012007400720061006e00730070006f007200740100000074ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0000000175ffffffff00000000000000000000000a00540065006d0070006f0000000182ffffffff000000000000000000000012005300690067006e00610074007500720065000000019affffffff000000000000000000000022006c00690073007400200069006e007300650072007400200074006f006f006c0073010000019affffffff0000000000000000</nonshared_toolbars>
- <shared_toolbars>000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc0000000100000002000000080000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff000000000000000000000022006c00690073007400200069006e007300650072007400200074006f006f006c007301000000d5ffffffff000000000000000000000012007400720061006e00730070006f007200740100000196ffffffff00000000000000000000000a00540065006d0070006f00000002c5ffffffff000000000000000000000012005300690067006e006100740075007200650000000350ffffffff00000000000000000000000a00700061006e0069006301000002bcffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e01000002e7000001190000000000000000</shared_toolbars>
+ <nonshared_toolbars>000000ff00000000fd00000000000002f40000013000000004000000040000000800000008fc000000010000000200000007
+0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000000a00700061006e006900
+630100000049ffffffff000000000000000000000012007400720061006e00730070006f007200740100000074ffffffff00000000000000000000001a005300
+6f006e006700200050006f0073006900740069006f006e0000000175ffffffff00000000000000000000000a00540065006d0070006f0000000182ffffffff00
+0000000000000000000012005300690067006e00610074007500720065000000019affffffff000000000000000000000022006c00690073007400200069006e
+007300650072007400200074006f006f006c0073010000019affffffff0000000000000000</nonshared_toolbars>
+ <shared_toolbars>000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc000000010000000200000008000
+0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640
+06f00200074006f006f006c0073010000008cffffffff000000000000000000000022006c00690073007400200069006e007300650072007400200074006f006
+f006c007301000000d5ffffffff000000000000000000000012007400720061006e00730070006f007200740100000196ffffffff00000000000000000000000
+a00540065006d0070006f00000002c5ffffffff000000000000000000000012005300690067006e006100740075007200650000000350ffffffff00000000000
+000000000000a00700061006e0069006301000002bcffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0
+1000002e7000001190000000000000000</shared_toolbars>
<shares_when_free>0</shares_when_free>
<shares_when_subwin>1</shares_when_subwin>
<default_subwin>0</default_subwin>
@@ -305,8 +388,17 @@
<topwin>
<width>784</width>
<height>544</height>
- <nonshared_toolbars>000000ff00000000fd0000000000000310000001e400000004000000040000000800000008fc0000000100000002000000060000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000000a00700061006e006900630100000049ffffffff000000000000000000000012007400720061006e00730070006f007200740100000074ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000019affffffff00000000000000000000000a00540065006d0070006f01000001d5ffffffff000000000000000000000012005300690067006e006100740075007200650100000260ffffffff0000000000000000</nonshared_toolbars>
- <shared_toolbars>000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc0000000100000002000000070000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff000000000000000000000012007400720061006e00730070006f0072007401000000d5ffffffff00000000000000000000000a00700061006e0069006301000001fbffffffff00000000000000000000000a00540065006d0070006f00000002c5ffffffff000000000000000000000012005300690067006e006100740075007200650000000350ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0100000226000001da0000000000000000</shared_toolbars>
+ <nonshared_toolbars>000000ff00000000fd0000000000000310000001e400000004000000040000000800000008fc000000010000000200000006
+0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000000a00700061006e006900
+630100000049ffffffff000000000000000000000012007400720061006e00730070006f007200740100000074ffffffff00000000000000000000001a005300
+6f006e006700200050006f0073006900740069006f006e010000019affffffff00000000000000000000000a00540065006d0070006f01000001d5ffffffff00
+0000000000000000000012005300690067006e006100740075007200650100000260ffffffff0000000000000000</nonshared_toolbars>
+ <shared_toolbars>000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc000000010000000200000007000
+0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640
+06f00200074006f006f006c0073010000008cffffffff000000000000000000000012007400720061006e00730070006f0072007401000000d5ffffffff00000
+000000000000000000a00700061006e0069006301000001fbffffffff00000000000000000000000a00540065006d0070006f00000002c5ffffffff000000000
+000000000000012005300690067006e006100740075007200650000000350ffffffff00000000000000000000001a0053006f006e006700200050006f0073006
+900740069006f006e0100000226000001da0000000000000000</shared_toolbars>
<shares_when_free>0</shares_when_free>
<shares_when_subwin>1</shares_when_subwin>
<default_subwin>0</default_subwin>
@@ -316,8 +408,19 @@
<topwin>
<width>612</width>
<height>360</height>
- <nonshared_toolbars>000000ff00000000fd00000000000002640000012c00000004000000040000000800000008fc0000000100000002000000070000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000000000000052000000000000000000000012007400720061006e00730070006f007200740100000052ffffffff00000000000000000000000a00700061006e006900630100000178ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e00000001a30000006800000000000000000000000a00540065006d0070006f00000000a6ffffffff000000000000000000000012005300690067006e006100740075007200650000000131ffffffff00000000000000000000002c004d006100730074006500720020004c0069007300740020004500640069007400200054006f006f006c007301000001a3000000920000000000000000</nonshared_toolbars>
- <shared_toolbars>000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc0000000200000002000000070000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff00000000000000000000002c004d006100730074006500720020004c0069007300740020004500640069007400200054006f006f006c007301000000d5ffffffff000000000000000000000012005300690067006e0061007400750072006500000002d9ffffffff000000000000000000000012007400720061006e00730070006f007200740100000182ffffffff00000000000000000000000a00700061006e0069006301000002a8ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e01000002d30000012d000000000000000000000002000000010000000a00540065006d0070006f0000000000ffffffff0000000000000000</shared_toolbars>
+ <nonshared_toolbars>000000ff00000000fd00000000000002640000012c00000004000000040000000800000008fc000000010000000200000007
+0000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000000000000052000000000000000000000012007400720061006e00
+730070006f007200740100000052ffffffff00000000000000000000000a00700061006e006900630100000178ffffffff00000000000000000000001a005300
+6f006e006700200050006f0073006900740069006f006e00000001a30000006800000000000000000000000a00540065006d0070006f00000000a6ffffffff00
+0000000000000000000012005300690067006e006100740075007200650000000131ffffffff00000000000000000000002c004d006100730074006500720020
+004c0069007300740020004500640069007400200054006f006f006c007301000001a3000000920000000000000000</nonshared_toolbars>
+ <shared_toolbars>000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc000000020000000200000007000
+0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640
+06f00200074006f006f006c0073010000008cffffffff00000000000000000000002c004d006100730074006500720020004c006900730074002000450064006
+9007400200054006f006f006c007301000000d5ffffffff000000000000000000000012005300690067006e0061007400750072006500000002d9ffffffff000
+000000000000000000012007400720061006e00730070006f007200740100000182ffffffff00000000000000000000000a00700061006e0069006301000002a
+8ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e01000002d30000012d0000000000000000000000020
+00000010000000a00540065006d0070006f0000000000ffffffff0000000000000000</shared_toolbars>
<shares_when_free>0</shares_when_free>
<shares_when_subwin>1</shares_when_subwin>
<default_subwin>0</default_subwin>
@@ -327,8 +430,19 @@
<topwin>
<width>784</width>
<height>544</height>
- <nonshared_toolbars>000000ff00000000fd0000000000000310000001e400000004000000040000000800000008fc0000000100000002000000070000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000000a00700061006e006900630100000049ffffffff000000000000000000000012007400720061006e00730070006f007200740100000074ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0100000191ffffffff00000000000000000000000a00540065006d0070006f010000019effffffff000000000000000000000012005300690067006e006100740075007200650100000229ffffffff000000000000000000000022006d00610072006b006500720020006500640069007400200074006f006f006c007301000002d9ffffffff0000000000000000</nonshared_toolbars>
- <shared_toolbars>000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc0000000100000002000000080000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff000000000000000000000022006d00610072006b006500720020006500640069007400200074006f006f006c007301000000d5ffffffff000000000000000000000012007400720061006e00730070006f00720074010000011effffffff00000000000000000000000a00700061006e006900630100000244ffffffff00000000000000000000000a00540065006d0070006f00000002c5ffffffff000000000000000000000012005300690067006e006100740075007200650000000329ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000026f000001910000000000000000</shared_toolbars>
+ <nonshared_toolbars>000000ff00000000fd0000000000000310000001e400000004000000040000000800000008fc000000010000000200000007
+0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000000a00700061006e006900
+630100000049ffffffff000000000000000000000012007400720061006e00730070006f007200740100000074ffffffff00000000000000000000001a005300
+6f006e006700200050006f0073006900740069006f006e0100000191ffffffff00000000000000000000000a00540065006d0070006f010000019effffffff00
+0000000000000000000012005300690067006e006100740075007200650100000229ffffffff000000000000000000000022006d00610072006b006500720020
+006500640069007400200074006f006f006c007301000002d9ffffffff0000000000000000</nonshared_toolbars>
+ <shared_toolbars>000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc000000010000000200000008000
+0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640
+06f00200074006f006f006c0073010000008cffffffff000000000000000000000022006d00610072006b006500720020006500640069007400200074006f006
+f006c007301000000d5ffffffff000000000000000000000012007400720061006e00730070006f00720074010000011effffffff00000000000000000000000
+a00700061006e006900630100000244ffffffff00000000000000000000000a00540065006d0070006f00000002c5ffffffff000000000000000000000012005
+300690067006e006100740075007200650000000329ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0
+10000026f000001910000000000000000</shared_toolbars>
<shares_when_free>0</shares_when_free>
<shares_when_subwin>1</shares_when_subwin>
<default_subwin>0</default_subwin>
@@ -338,8 +452,21 @@
<topwin>
<width>1024</width>
<height>553</height>
- <nonshared_toolbars>000000ff00000000fd00000000000003ec0000008d00000004000000040000000800000008fc0000000200000002000000050000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000001a0061007200720061006e0067006500720054006f006f006c00730100000049ffffffff00000000000000000000002600560069007300690062006c006500200074007200610063006b0020007400790070006500730100000128000000f0000000000000000000000012007400720061006e00730070006f007200740100000218ffffffff00000000000000000000000a00700061006e00690063010000033e000000b6000000000000000000000002000000010000001e0041007200720061006e0067006500720054006f006f006c0062006100720100000000ffffffff0000000000000000</nonshared_toolbars>
- <shared_toolbars>000000ff00000000fd00000000000004000000022900000004000000040000000800000008fc0000000300000002000000060000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff00000000000000000000001a0061007200720061006e0067006500720054006f006f006c007301000000d5ffffffff00000000000000000000002600560069007300690062006c006500200074007200610063006b00200074007900700065007301000001b4ffffffff000000000000000000000012007400720061006e00730070006f007200740100000293ffffffff00000000000000000000000a00700061006e0069006301000003b900000047000000000000000000000002000000010000001e0041007200720061006e0067006500720054006f006f006c0062006100720100000000ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000</shared_toolbars>
+ <nonshared_toolbars>000000ff00000000fd00000000000003ec0000008d00000004000000040000000800000008fc000000020000000200000005
+0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000001a006100720072006100
+6e0067006500720054006f006f006c00730100000049ffffffff00000000000000000000002600560069007300690062006c006500200074007200610063006b
+0020007400790070006500730100000128000000f0000000000000000000000012007400720061006e00730070006f007200740100000218ffffffff00000000
+000000000000000a00700061006e00690063010000033e000000b6000000000000000000000002000000010000001e0041007200720061006e00670065007200
+54006f006f006c0062006100720100000000ffffffff0000000000000000</nonshared_toolbars>
+ <shared_toolbars>000000ff00000000fd00000000000004000000022900000004000000040000000800000008fc000000030000000200000006000
+0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640
+06f00200074006f006f006c0073010000008cffffffff00000000000000000000001a0061007200720061006e0067006500720054006f006f006c00730100000
+0d5ffffffff00000000000000000000002600560069007300690062006c006500200074007200610063006b00200074007900700065007301000001b4fffffff
+f000000000000000000000012007400720061006e00730070006f007200740100000293ffffffff00000000000000000000000a00700061006e0069006301000
+003b900000047000000000000000000000002000000010000001e0041007200720061006e0067006500720054006f006f006c0062006100720100000000fffff
+fff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e0061007
+4007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c5000
+0000000000000</shared_toolbars>
<shares_when_free>0</shares_when_free>
<shares_when_subwin>1</shares_when_subwin>
<default_subwin>1</default_subwin>
diff --git a/muse2/xpm/bluedot.xpm b/muse2/xpm/bluedot.xpm
index a92558f9..7c14b1dd 100644
--- a/muse2/xpm/bluedot.xpm
+++ b/muse2/xpm/bluedot.xpm
@@ -1,34 +1,21 @@
/* XPM */
static const char * bluedot_xpm[] = {
-"18 18 13 1",
+"12 16 2 1",
" c None",
-". c #F10606",
-"+ c #414141",
-"@ c #852A2A",
-"# c #473E3E",
-"$ c #723030",
-"% c #CB1212",
-"& c #4E3C3C",
-"* c #E20A0A",
-"= c #A51F1F",
-"- c #9E2121",
-"; c #832A2A",
-"> c #9C2222",
-" ",
-" ",
-" . ",
-" .. ",
-" ... ",
-" +++++++++@... ",
-" #+++++++$..% ",
-" &# ..*+ ",
-" .= ...-+ ",
-" ;.. ....++ ",
-" +... ... ++ ",
-" ++....... ++ ",
-" ++ ..... ++ ",
-" ++ .... ++ ",
-" ++ .. ++ ",
-" +++++>.+++++ ",
-" ++++++++++++ ",
-" "};
+". c #009AFF",
+" ",
+" ",
+" ",
+" .. ",
+" .... ",
+" ...... ",
+" ........ ",
+" ........ ",
+" ........ ",
+" ...... ",
+" .... ",
+" .. ",
+" ",
+" ",
+" ",
+" "};
diff --git a/muse2/xpm/checksquare.xpm b/muse2/xpm/checksquare.xpm
new file mode 100644
index 00000000..7628cafc
--- /dev/null
+++ b/muse2/xpm/checksquare.xpm
@@ -0,0 +1,34 @@
+/* XPM */
+static const char * checksquare_xpm[] = {
+"18 18 13 1",
+" c None",
+". c #F10606",
+"+ c #414141",
+"@ c #852A2A",
+"# c #473E3E",
+"$ c #723030",
+"% c #CB1212",
+"& c #4E3C3C",
+"* c #E20A0A",
+"= c #A51F1F",
+"- c #9E2121",
+"; c #832A2A",
+"> c #9C2222",
+" ",
+" ",
+" . ",
+" .. ",
+" ... ",
+" +++++++++@... ",
+" #+++++++$..% ",
+" &# ..*+ ",
+" .= ...-+ ",
+" ;.. ....++ ",
+" +... ... ++ ",
+" ++....... ++ ",
+" ++ ..... ++ ",
+" ++ .... ++ ",
+" ++ .. ++ ",
+" +++++>.+++++ ",
+" ++++++++++++ ",
+" "};
diff --git a/muse2/xpm/greendot.xpm b/muse2/xpm/greendot.xpm
index 9f02394f..bac27c28 100644
--- a/muse2/xpm/greendot.xpm
+++ b/muse2/xpm/greendot.xpm
@@ -1,25 +1,21 @@
/* XPM */
-static const char *greendot_xpm[] = {
-/* width height num_colors chars_per_pixel */
-" 12 16 2 1",
-/* colors */
-". c none",
-"# c #00ff00",
-/* pixels */
-"............",
-"............",
-"............",
-".....##.....",
-"....####....",
-"...######...",
-"..########..",
-"..########..",
-"..########..",
-"...######...",
-"....####....",
-".....##.....",
-"............",
-"............",
-"............",
-"............"
-};
+static const char * greendot_xpm[] = {
+"12 16 2 1",
+" c None",
+". c #00FF00",
+" ",
+" ",
+" ",
+" .. ",
+" .... ",
+" ...... ",
+" ........ ",
+" ........ ",
+" ........ ",
+" ...... ",
+" .... ",
+" .. ",
+" ",
+" ",
+" ",
+" "};
diff --git a/muse2/xpm/orangedot.xpm b/muse2/xpm/orangedot.xpm
new file mode 100644
index 00000000..f67b9064
--- /dev/null
+++ b/muse2/xpm/orangedot.xpm
@@ -0,0 +1,21 @@
+/* XPM */
+static const char * orangedot_xpm[] = {
+"12 16 2 1",
+" c None",
+". c #FFBA00",
+" ",
+" ",
+" ",
+" .. ",
+" .... ",
+" ...... ",
+" ........ ",
+" ........ ",
+" ........ ",
+" ...... ",
+" .... ",
+" .. ",
+" ",
+" ",
+" ",
+" "};