From c4aca7b81e76e0f098ac0f855599bdf1e3cf1e22 Mon Sep 17 00:00:00 2001 From: "Tim E. Real" Date: Sat, 20 Oct 2012 04:10:19 +0000 Subject: Improved: Midi initializations. New settings options, can be 'quiet'. Complete rewrite of initializations coding. Improved: Midi controller graphs: Control selector 'S' popup now stay-open, AND NOW with multi-coloured dots. Bonus! Pianoroll and drum edit 'Ctrl' buttons ALSO now popup this very same menu. Improved: 'Old' drum track 'drum controllers' display and operation: Fixed several problems. --- muse2/ChangeLog | 15 + muse2/muse/app.cpp | 4 +- muse2/muse/arranger/tlist.cpp | 7 +- muse2/muse/audio.cpp | 2 +- muse2/muse/audio.h | 4 +- muse2/muse/conf.cpp | 9 + muse2/muse/confmport.cpp | 25 + muse2/muse/confmport.h | 3 + muse2/muse/ctrl/ctrlcanvas.cpp | 216 ++++++-- muse2/muse/ctrl/ctrlcanvas.h | 3 +- muse2/muse/ctrl/ctrlpanel.cpp | 593 +++++--------------- muse2/muse/ctrl/ctrlpanel.h | 2 + muse2/muse/gconfig.cpp | 3 + muse2/muse/gconfig.h | 3 + muse2/muse/helper.cpp | 203 ++++++- muse2/muse/helper.h | 5 +- muse2/muse/icons.cpp | 10 +- muse2/muse/icons.h | 2 + muse2/muse/midi.cpp | 54 +- muse2/muse/mididev.cpp | 143 +++-- muse2/muse/mididev.h | 4 +- muse2/muse/midiedit/drumedit.cpp | 202 ++++++- muse2/muse/midiedit/drumedit.h | 10 +- muse2/muse/midiedit/pianoroll.cpp | 222 +++++++- muse2/muse/midiedit/pianoroll.h | 9 +- muse2/muse/midiport.cpp | 243 +++++--- muse2/muse/midiport.h | 12 +- muse2/muse/midiseq.cpp | 5 - muse2/muse/mpevent.cpp | 6 - muse2/muse/route.cpp | 3 + muse2/muse/seqmsg.cpp | 75 ++- muse2/muse/song.cpp | 4 +- muse2/muse/widgets/CMakeLists.txt | 5 + muse2/muse/widgets/genset.cpp | 6 + muse2/muse/widgets/gensetbase.ui | 192 ++++--- muse2/muse/widgets/knob.h | 4 +- muse2/muse/widgets/knob_and_meter.cpp | 609 +++++++++++++++++++++ muse2/muse/widgets/knob_and_meter.h | 114 ++++ muse2/muse/widgets/midi_warn_init_pending.ui | 119 ++++ muse2/muse/widgets/midi_warn_init_pending_impl.cpp | 33 ++ muse2/muse/widgets/midi_warn_init_pending_impl.h | 40 ++ muse2/muse/widgets/musewidgetsplug.cpp | 3 + muse2/muse/widgets/synthconfigbase.ui | 153 +++--- muse2/share/templates/MusE.cfg | 167 +++++- muse2/xpm/bluedot.xpm | 49 +- muse2/xpm/checksquare.xpm | 34 ++ muse2/xpm/greendot.xpm | 44 +- muse2/xpm/orangedot.xpm | 21 + 48 files changed, 2810 insertions(+), 884 deletions(-) create mode 100644 muse2/muse/widgets/knob_and_meter.cpp create mode 100644 muse2/muse/widgets/knob_and_meter.h create mode 100644 muse2/muse/widgets/midi_warn_init_pending.ui create mode 100644 muse2/muse/widgets/midi_warn_init_pending_impl.cpp create mode 100644 muse2/muse/widgets/midi_warn_init_pending_impl.h create mode 100644 muse2/xpm/checksquare.xpm create mode 100644 muse2/xpm/orangedot.xpm 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)); @@ -1688,6 +1728,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 sList; - typedef std::list::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 sList; - typedef std::list::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 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 #include @@ -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 sList; + typedef std::list::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())); @@ -1219,13 +1221,202 @@ void DrumEdit::selectionChanged() deleteAction->setEnabled(flag); } +//--------------------------------------------------------- +// 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))); @@ -792,29 +794,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 + #include #include @@ -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,76 +171,182 @@ 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 clearDevice(); } +//--------------------------------------------------------- +// 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 //--------------------------------------------------------- @@ -240,6 +354,7 @@ void MidiPort::setMidiDevice(MidiDevice* dev) 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 @@ 0 0 - 525 - 549 + 544 + 593 @@ -37,7 +37,7 @@ - -1 + 6 @@ -1029,14 +1029,94 @@ Adjusts responsiveness of audio controls and Midi - - + + + + + Record new style drum tracks + + + + + + Record all instruments + + + + + + + Don't record hidden instruments + + + + + + + Don't record muted instruments + + + + + + + Don't record hidden or muted instruments + + + + + + + + + + Instrument initialization + + + + + + Send instrument initialization sequences + + + + + + + Warn if instrument initialization sequences pending + + + + + + + Send instrument controller default values if none in song, at init or rewind + + + + + + + + + + Qt::Vertical + + + + 191 + 166 + + + + + Ticks - - + + RTC Resolution @@ -1049,6 +1129,12 @@ Adjusts responsiveness of audio controls and + + + 0 + 0 + + 1024 @@ -1081,19 +1167,14 @@ Adjusts responsiveness of audio controls and - - - - Midi Resolution -(Ticks/Quarternote) - - - false - - - - + + + + 0 + 0 + + 3 @@ -1145,6 +1226,17 @@ Adjusts responsiveness of audio controls and + + + Midi Resolution +(Ticks/Quarternote) + + + false + + + + Displayed Resolution @@ -1155,8 +1247,14 @@ Adjusts responsiveness of audio controls and - + + + + 0 + 0 + + 3 @@ -1210,56 +1308,6 @@ Adjusts responsiveness of audio controls and - - - - Record new style drum tracks - - - - - - Record all instruments - - - - - - - Don't record hidden instruments - - - - - - - Don't record muted instruments - - - - - - - Don't record hidden or muted instruments - - - - - - - - - - Qt::Vertical - - - - 191 - 166 - - - - @@ -1629,8 +1677,8 @@ left button behave like the middle button in such areas. 0 0 - 481 - 386 + 96 + 26 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 +#include "knob_and_meter.h" +#include +#include "mmath.h" + +#include +#include +#include +#include +#include + +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 +#include +#include + +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 @@ + + + midiWarnInitPendingBase + + + + 0 + 0 + 371 + 207 + + + + + 0 + 0 + + + + Instrument initialization + + + + + + + 0 + 0 + + + + MusE should now send some Instrument Initialization Sequences. +The sequences (usually System Exclusive messages) are defined + by the selected instruments in the Settings -> 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? + + + Qt::AutoText + + + false + + + + + + + + 0 + 0 + + + + Don't ask me again + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::No|QDialogButtonBox::Yes + + + false + + + + + + + + + buttonBox + accepted() + midiWarnInitPendingBase + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + midiWarnInitPendingBase + reject() + + + 316 + 260 + + + 286 + 274 + + + + + 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 @@ 0 0 - 810 - 492 + 820 + 475 Midi Port and Soft Synth Configuration - - - - - Instances - - - - - - true - - - - Name - - - - - Type - - - - - Midi Port - - - - - - - - - - Remove Instance - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 113 - 20 - - - - - - - - - + @@ -170,6 +112,95 @@ + + + + Instances + + + + + + true + + + + Name + + + + + Type + + + + + Midi Port + + + + + + + + + + Remove Instance + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 113 + 20 + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &Apply + + + + + + + &OK + + + + + 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 @@ 934 488 - 000000ff00000000fd00000000000003a60000015a00000004000000040000000800000008fc0000000300000002000000050000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff000000000000000000000014004400720075006d00200074006f006f006c00730100000049ffffffff000000000000000000000014004500640069007400200054006f006f006c007301000000f7ffffffff000000000000000000000012007400720061006e00730070006f00720074010000019affffffff00000000000000000000000a00700061006e0069006301000002c0000000f8000000000000000000000002000000030000000c0063007500720073006f00720100000000ffffffff0000000000000000000000260050006f0073002f0053006e00610070002f0053006f006c006f002d0074006f006f006c00730100000081ffffffff000000000000000000000012004e006f0074006500200049006e0066006f01000001b9ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b0000026b0000000000000000 - 000000ff00000000fd00000000000004000000022900000004000000040000000800000008fc0000000300000002000000060000001800460069006c006500200042007500740074006f006e00730100000000ffffffff00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000085ffffffff000000000000000000000014004400720075006d00200074006f006f006c007301000000ceffffffff000000000000000000000014004500640069007400200054006f006f006c0073010000017cffffffff000000000000000000000012007400720061006e00730070006f00720074010000021fffffffff00000000000000000000000a00700061006e00690063010000034500000120000000000000000000000002000000030000000c0063007500720073006f00720100000000ffffffff0000000000000000000000260050006f0073002f0053006e00610070002f0053006f006c006f002d0074006f006f006c00730100000081ffffffff000000000000000000000012004e006f0074006500200049006e0066006f01000001b9ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000 + 000000ff00000000fd00000000000003a60000015a00000004000000040000000800000008fc0000000300000002000000050000001e +0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff000000000000000000000014004400720075006d0020007400 +6f006f006c00730100000049ffffffff000000000000000000000014004500640069007400200054006f006f006c007301000000f7ffffffff00000000000000 +0000000012007400720061006e00730070006f00720074010000019affffffff00000000000000000000000a00700061006e0069006301000002c0000000f800 +0000000000000000000002000000030000000c0063007500720073006f00720100000000ffffffff0000000000000000000000260050006f0073002f0053006e +00610070002f0053006f006c006f002d0074006f006f006c00730100000081ffffffff000000000000000000000012004e006f0074006500200049006e006600 +6f01000001b9ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300 +690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0100 +00013b0000026b0000000000000000 + 000000ff00000000fd00000000000004000000022900000004000000040000000800000008fc000000030000000200000006000 +0001800460069006c006500200042007500740074006f006e00730100000000ffffffff00000000000000000000001e0055006e0064006f002f0052006500640 +06f00200074006f006f006c00730100000085ffffffff000000000000000000000014004400720075006d00200074006f006f006c007301000000ceffffffff0 +00000000000000000000014004500640069007400200054006f006f006c0073010000017cffffffff000000000000000000000012007400720061006e0073007 +0006f00720074010000021fffffffff00000000000000000000000a00700061006e0069006301000003450000012000000000000000000000000200000003000 +0000c0063007500720073006f00720100000000ffffffff0000000000000000000000260050006f0073002f0053006e00610070002f0053006f006c006f002d0 +074006f006f006c00730100000081ffffffff000000000000000000000012004e006f0074006500200049006e0066006f01000001b9ffffffff0000000000000 +00000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010 +000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000 0 1 0 @@ -240,8 +256,23 @@ 852 460 - 000000ff00000000fd00000000000003540000013e00000004000000040000000800000008fc0000000300000002000000050000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000001e005000690061006e006f0072006f006c006c00200074006f006f006c00730100000049ffffffff000000000000000000000014004500640069007400200054006f006f006c007301000000b000000098000000000000000000000012007400720061006e00730070006f007200740100000148ffffffff00000000000000000000000a00700061006e00690063010000026e000000f800000000000000000000000200000002000000260050006f0073002f0053006e00610070002f0053006f006c006f002d0074006f006f006c00730100000000ffffffff000000000000000000000012004e006f0074006500200049006e0066006f0100000162ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002190000000000000000 - 000000ff00000000fd00000000000004000000022900000004000000040000000800000008fc0000000300000002000000060000001800460069006c006500200042007500740074006f006e00730100000000ffffffff00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000085ffffffff00000000000000000000001e005000690061006e006f0072006f006c006c00200074006f006f006c007301000000ceffffffff000000000000000000000014004500640069007400200054006f006f006c00730100000135ffffffff000000000000000000000012007400720061006e00730070006f0072007401000001baffffffff00000000000000000000000a00700061006e0069006301000002e00000012000000000000000000000000200000002000000260050006f0073002f0053006e00610070002f0053006f006c006f002d0074006f006f006c00730100000000ffffffff000000000000000000000012004e006f0074006500200049006e0066006f0100000162ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000 + 000000ff00000000fd00000000000003540000013e00000004000000040000000800000008fc000000030000000200000005 +0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000001e005000690061006e00 +6f0072006f006c006c00200074006f006f006c00730100000049ffffffff000000000000000000000014004500640069007400200054006f006f006c00730100 +0000b000000098000000000000000000000012007400720061006e00730070006f007200740100000148ffffffff00000000000000000000000a00700061006e +00690063010000026e000000f800000000000000000000000200000002000000260050006f0073002f0053006e00610070002f0053006f006c006f002d007400 +6f006f006c00730100000000ffffffff000000000000000000000012004e006f0074006500200049006e0066006f0100000162ffffffff000000000000000000 +000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e0061007400750072006501000000 +8bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002190000000000000000 + 000000ff00000000fd00000000000004000000022900000004000000040000000800000008fc000000030000000200000006000 +0001800460069006c006500200042007500740074006f006e00730100000000ffffffff00000000000000000000001e0055006e0064006f002f0052006500640 +06f00200074006f006f006c00730100000085ffffffff00000000000000000000001e005000690061006e006f0072006f006c006c00200074006f006f006c007 +301000000ceffffffff000000000000000000000014004500640069007400200054006f006f006c00730100000135ffffffff000000000000000000000012007 +400720061006e00730070006f0072007401000001baffffffff00000000000000000000000a00700061006e0069006301000002e000000120000000000000000 +00000000200000002000000260050006f0073002f0053006e00610070002f0053006f006c006f002d0074006f006f006c00730100000000ffffffff000000000 +000000000000012004e006f0074006500200049006e0066006f0100000162ffffffff000000000000000000000002000000030000000a00540065006d0070006 +f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006 +f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000 0 1 0 @@ -259,8 +290,25 @@ 867 544 - 000000ff00000000fd0000000000000363000001a700000004000000040000000800000008fc0000000300000002000000060000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000002800530074006500700020007200650063006f007200640069006e006700200074006f006f006c00730100000049ffffffff000000000000000000000014004500640069007400200054006f006f006c00730100000074ffffffff00000000000000000000002a005100750061006e007400690073006100740069006f006e002000730065007400740069006e0067007301000000dbffffffff000000000000000000000012007400720061006e00730070006f007200740100000224ffffffff00000000000000000000000a00700061006e006900630100000338000000420000000000000000000000020000000100000022004e006500770020006e006f00740065002000730065007400740069006e006700730100000000ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002d80000000000000000 - 000000ff00000000fd00000000000004000000023d00000004000000040000000800000008fc0000000300000002000000060000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff00000000000000000000002800530074006500700020007200650063006f007200640069006e006700200074006f006f006c007301000000d5ffffffff000000000000000000000014004500640069007400200054006f006f006c00730100000100ffffffff000000000000000000000012007400720061006e00730070006f007200740100000167ffffffff00000000000000000000000a00700061006e00690063010000028d000001730000000000000000000000020000000200000022004e006500770020006e006f00740065002000730065007400740069006e006700730100000000ffffffff00000000000000000000002a005100750061006e007400690073006100740069006f006e002000730065007400740069006e00670073010000027a00000186000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000 + 000000ff00000000fd0000000000000363000001a700000004000000040000000800000008fc000000030000000200000006 +0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff000000000000000000000028005300740065007000 +20007200650063006f007200640069006e006700200074006f006f006c00730100000049ffffffff000000000000000000000014004500640069007400200054 +006f006f006c00730100000074ffffffff00000000000000000000002a005100750061006e007400690073006100740069006f006e0020007300650074007400 +69006e0067007301000000dbffffffff000000000000000000000012007400720061006e00730070006f007200740100000224ffffffff000000000000000000 +00000a00700061006e006900630100000338000000420000000000000000000000020000000100000022004e006500770020006e006f00740065002000730065 +007400740069006e006700730100000000ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff00000000 +0000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f007300 +6900740069006f006e010000013b000002d80000000000000000 + 000000ff00000000fd00000000000004000000023d00000004000000040000000800000008fc000000030000000200000006000 +0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640 +06f00200074006f006f006c0073010000008cffffffff00000000000000000000002800530074006500700020007200650063006f007200640069006e0067002 +00074006f006f006c007301000000d5ffffffff000000000000000000000014004500640069007400200054006f006f006c00730100000100ffffffff0000000 +00000000000000012007400720061006e00730070006f007200740100000167ffffffff00000000000000000000000a00700061006e00690063010000028d000 +001730000000000000000000000020000000200000022004e006500770020006e006f00740065002000730065007400740069006e006700730100000000fffff +fff00000000000000000000002a005100750061006e007400690073006100740069006f006e002000730065007400740069006e00670073010000027a0000018 +6000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e006100740 +07500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c500000 +00000000000 0 1 0 @@ -271,8 +319,21 @@ 784 544 - 000000ff00000000fd0000000000000310000001b200000004000000040000000800000008fc0000000400000002000000050000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff000000000000000000000014004500640069007400200054006f006f006c00730100000049ffffffff000000000000000000000012007400720061006e00730070006f0072007401000000b0ffffffff00000000000000000000000a00700061006e0069006301000001d6ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e01000002010000010f000000000000000000000002000000020000001a0045006e00610062006c00650020006d006100730074006500720100000000ffffffff0000000000000000000000080049006e0066006f010000005dffffffff000000000000000000000002000000020000000a00540065006d0070006f0000000000ffffffff000000000000000000000012005300690067006e006100740075007200650000000000ffffffff00000000000000000000000200000000 - 000000ff00000000fd00000000000004000000024900000004000000040000000800000008fc0000000400000002000000060000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff00000000000000000000001a0045006e00610062006c00650020006d0061007300740065007201000000d5ffffffff000000000000000000000014004500640069007400200054006f006f006c0073010000013200000071000000000000000000000012007400720061006e00730070006f0072007401000001a3ffffffff00000000000000000000000a00700061006e0069006301000002c9ffffffff00000000000000000000000200000002000000080049006e0066006f0100000000ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000025d000001a300000000000000000000000200000000000000020000000200000012005300690067006e006100740075007200650000000000ffffffff00000000000000000000000a00540065006d0070006f00000000b0ffffffff0000000000000000 + 000000ff00000000fd0000000000000310000001b200000004000000040000000800000008fc000000040000000200000005 +0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff000000000000000000000014004500640069007400 +200054006f006f006c00730100000049ffffffff000000000000000000000012007400720061006e00730070006f0072007401000000b0ffffffff0000000000 +0000000000000a00700061006e0069006301000001d6ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e +01000002010000010f000000000000000000000002000000020000001a0045006e00610062006c00650020006d006100730074006500720100000000ffffffff +0000000000000000000000080049006e0066006f010000005dffffffff000000000000000000000002000000020000000a00540065006d0070006f0000000000 +ffffffff000000000000000000000012005300690067006e006100740075007200650000000000ffffffff00000000000000000000000200000000 + 000000ff00000000fd00000000000004000000024900000004000000040000000800000008fc000000040000000200000006000 +0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640 +06f00200074006f006f006c0073010000008cffffffff00000000000000000000001a0045006e00610062006c00650020006d006100730074006500720100000 +0d5ffffffff000000000000000000000014004500640069007400200054006f006f006c007301000001320000007100000000000000000000001200740072006 +1006e00730070006f0072007401000001a3ffffffff00000000000000000000000a00700061006e0069006301000002c9ffffffff00000000000000000000000 +200000002000000080049006e0066006f0100000000ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0 +10000025d000001a300000000000000000000000200000000000000020000000200000012005300690067006e006100740075007200650000000000ffffffff0 +0000000000000000000000a00540065006d0070006f00000000b0ffffffff0000000000000000 0 1 0 @@ -283,8 +344,19 @@ 797 478 - 000000ff00000000fd000000000000031d0000018200000004000000040000000800000008fc0000000200000002000000040000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000001c0057006100760065004500640069007400200074006f006f006c007301000000490000010f000000000000000000000012007400720061006e00730070006f007200740100000158ffffffff00000000000000000000000a00700061006e00690063010000027e0000009f000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000001e20000000000000000 - 000000ff00000000fd00000000000004000000025b00000004000000040000000800000008fc0000000200000002000000050000001800460069006c006500200042007500740074006f006e00730100000000ffffffff00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000085ffffffff00000000000000000000001c0057006100760065004500640069007400200074006f006f006c007301000000ceffffffff000000000000000000000012007400720061006e00730070006f0072007401000001d1ffffffff00000000000000000000000a00700061006e0069006301000002f700000109000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000 + 000000ff00000000fd000000000000031d0000018200000004000000040000000800000008fc000000020000000200000004 +0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000001c005700610076006500 +4500640069007400200074006f006f006c007301000000490000010f000000000000000000000012007400720061006e00730070006f007200740100000158ff +ffffff00000000000000000000000a00700061006e00690063010000027e0000009f000000000000000000000002000000030000000a00540065006d0070006f +0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f +006e006700200050006f0073006900740069006f006e010000013b000001e20000000000000000 + 000000ff00000000fd00000000000004000000025b00000004000000040000000800000008fc000000020000000200000005000 +0001800460069006c006500200042007500740074006f006e00730100000000ffffffff00000000000000000000001e0055006e0064006f002f0052006500640 +06f00200074006f006f006c00730100000085ffffffff00000000000000000000001c0057006100760065004500640069007400200074006f006f006c0073010 +00000ceffffffff000000000000000000000012007400720061006e00730070006f0072007401000001d1ffffffff00000000000000000000000a00700061006 +e0069006301000002f700000109000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff00000000000000000000001 +2005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f0 +06e010000013b000002c50000000000000000 0 1 0 @@ -294,8 +366,19 @@ 756 364 - 000000ff00000000fd00000000000002f40000013000000004000000040000000800000008fc0000000100000002000000070000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000000a00700061006e006900630100000049ffffffff000000000000000000000012007400720061006e00730070006f007200740100000074ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0000000175ffffffff00000000000000000000000a00540065006d0070006f0000000182ffffffff000000000000000000000012005300690067006e00610074007500720065000000019affffffff000000000000000000000022006c00690073007400200069006e007300650072007400200074006f006f006c0073010000019affffffff0000000000000000 - 000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc0000000100000002000000080000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff000000000000000000000022006c00690073007400200069006e007300650072007400200074006f006f006c007301000000d5ffffffff000000000000000000000012007400720061006e00730070006f007200740100000196ffffffff00000000000000000000000a00540065006d0070006f00000002c5ffffffff000000000000000000000012005300690067006e006100740075007200650000000350ffffffff00000000000000000000000a00700061006e0069006301000002bcffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e01000002e7000001190000000000000000 + 000000ff00000000fd00000000000002f40000013000000004000000040000000800000008fc000000010000000200000007 +0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000000a00700061006e006900 +630100000049ffffffff000000000000000000000012007400720061006e00730070006f007200740100000074ffffffff00000000000000000000001a005300 +6f006e006700200050006f0073006900740069006f006e0000000175ffffffff00000000000000000000000a00540065006d0070006f0000000182ffffffff00 +0000000000000000000012005300690067006e00610074007500720065000000019affffffff000000000000000000000022006c00690073007400200069006e +007300650072007400200074006f006f006c0073010000019affffffff0000000000000000 + 000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc000000010000000200000008000 +0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640 +06f00200074006f006f006c0073010000008cffffffff000000000000000000000022006c00690073007400200069006e007300650072007400200074006f006 +f006c007301000000d5ffffffff000000000000000000000012007400720061006e00730070006f007200740100000196ffffffff00000000000000000000000 +a00540065006d0070006f00000002c5ffffffff000000000000000000000012005300690067006e006100740075007200650000000350ffffffff00000000000 +000000000000a00700061006e0069006301000002bcffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0 +1000002e7000001190000000000000000 0 1 0 @@ -305,8 +388,17 @@ 784 544 - 000000ff00000000fd0000000000000310000001e400000004000000040000000800000008fc0000000100000002000000060000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000000a00700061006e006900630100000049ffffffff000000000000000000000012007400720061006e00730070006f007200740100000074ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000019affffffff00000000000000000000000a00540065006d0070006f01000001d5ffffffff000000000000000000000012005300690067006e006100740075007200650100000260ffffffff0000000000000000 - 000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc0000000100000002000000070000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff000000000000000000000012007400720061006e00730070006f0072007401000000d5ffffffff00000000000000000000000a00700061006e0069006301000001fbffffffff00000000000000000000000a00540065006d0070006f00000002c5ffffffff000000000000000000000012005300690067006e006100740075007200650000000350ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0100000226000001da0000000000000000 + 000000ff00000000fd0000000000000310000001e400000004000000040000000800000008fc000000010000000200000006 +0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000000a00700061006e006900 +630100000049ffffffff000000000000000000000012007400720061006e00730070006f007200740100000074ffffffff00000000000000000000001a005300 +6f006e006700200050006f0073006900740069006f006e010000019affffffff00000000000000000000000a00540065006d0070006f01000001d5ffffffff00 +0000000000000000000012005300690067006e006100740075007200650100000260ffffffff0000000000000000 + 000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc000000010000000200000007000 +0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640 +06f00200074006f006f006c0073010000008cffffffff000000000000000000000012007400720061006e00730070006f0072007401000000d5ffffffff00000 +000000000000000000a00700061006e0069006301000001fbffffffff00000000000000000000000a00540065006d0070006f00000002c5ffffffff000000000 +000000000000012005300690067006e006100740075007200650000000350ffffffff00000000000000000000001a0053006f006e006700200050006f0073006 +900740069006f006e0100000226000001da0000000000000000 0 1 0 @@ -316,8 +408,19 @@ 612 360 - 000000ff00000000fd00000000000002640000012c00000004000000040000000800000008fc0000000100000002000000070000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000000000000052000000000000000000000012007400720061006e00730070006f007200740100000052ffffffff00000000000000000000000a00700061006e006900630100000178ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e00000001a30000006800000000000000000000000a00540065006d0070006f00000000a6ffffffff000000000000000000000012005300690067006e006100740075007200650000000131ffffffff00000000000000000000002c004d006100730074006500720020004c0069007300740020004500640069007400200054006f006f006c007301000001a3000000920000000000000000 - 000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc0000000200000002000000070000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff00000000000000000000002c004d006100730074006500720020004c0069007300740020004500640069007400200054006f006f006c007301000000d5ffffffff000000000000000000000012005300690067006e0061007400750072006500000002d9ffffffff000000000000000000000012007400720061006e00730070006f007200740100000182ffffffff00000000000000000000000a00700061006e0069006301000002a8ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e01000002d30000012d000000000000000000000002000000010000000a00540065006d0070006f0000000000ffffffff0000000000000000 + 000000ff00000000fd00000000000002640000012c00000004000000040000000800000008fc000000010000000200000007 +0000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000000000000052000000000000000000000012007400720061006e00 +730070006f007200740100000052ffffffff00000000000000000000000a00700061006e006900630100000178ffffffff00000000000000000000001a005300 +6f006e006700200050006f0073006900740069006f006e00000001a30000006800000000000000000000000a00540065006d0070006f00000000a6ffffffff00 +0000000000000000000012005300690067006e006100740075007200650000000131ffffffff00000000000000000000002c004d006100730074006500720020 +004c0069007300740020004500640069007400200054006f006f006c007301000001a3000000920000000000000000 + 000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc000000020000000200000007000 +0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640 +06f00200074006f006f006c0073010000008cffffffff00000000000000000000002c004d006100730074006500720020004c006900730074002000450064006 +9007400200054006f006f006c007301000000d5ffffffff000000000000000000000012005300690067006e0061007400750072006500000002d9ffffffff000 +000000000000000000012007400720061006e00730070006f007200740100000182ffffffff00000000000000000000000a00700061006e0069006301000002a +8ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e01000002d30000012d0000000000000000000000020 +00000010000000a00540065006d0070006f0000000000ffffffff0000000000000000 0 1 0 @@ -327,8 +430,19 @@ 784 544 - 000000ff00000000fd0000000000000310000001e400000004000000040000000800000008fc0000000100000002000000070000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000000a00700061006e006900630100000049ffffffff000000000000000000000012007400720061006e00730070006f007200740100000074ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0100000191ffffffff00000000000000000000000a00540065006d0070006f010000019effffffff000000000000000000000012005300690067006e006100740075007200650100000229ffffffff000000000000000000000022006d00610072006b006500720020006500640069007400200074006f006f006c007301000002d9ffffffff0000000000000000 - 000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc0000000100000002000000080000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff000000000000000000000022006d00610072006b006500720020006500640069007400200074006f006f006c007301000000d5ffffffff000000000000000000000012007400720061006e00730070006f00720074010000011effffffff00000000000000000000000a00700061006e006900630100000244ffffffff00000000000000000000000a00540065006d0070006f00000002c5ffffffff000000000000000000000012005300690067006e006100740075007200650000000329ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000026f000001910000000000000000 + 000000ff00000000fd0000000000000310000001e400000004000000040000000800000008fc000000010000000200000007 +0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000000a00700061006e006900 +630100000049ffffffff000000000000000000000012007400720061006e00730070006f007200740100000074ffffffff00000000000000000000001a005300 +6f006e006700200050006f0073006900740069006f006e0100000191ffffffff00000000000000000000000a00540065006d0070006f010000019effffffff00 +0000000000000000000012005300690067006e006100740075007200650100000229ffffffff000000000000000000000022006d00610072006b006500720020 +006500640069007400200074006f006f006c007301000002d9ffffffff0000000000000000 + 000000ff00000000fd00000000000004000000027b00000004000000040000000800000008fc000000010000000200000008000 +0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640 +06f00200074006f006f006c0073010000008cffffffff000000000000000000000022006d00610072006b006500720020006500640069007400200074006f006 +f006c007301000000d5ffffffff000000000000000000000012007400720061006e00730070006f00720074010000011effffffff00000000000000000000000 +a00700061006e006900630100000244ffffffff00000000000000000000000a00540065006d0070006f00000002c5ffffffff000000000000000000000012005 +300690067006e006100740075007200650000000329ffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e0 +10000026f000001910000000000000000 0 1 0 @@ -338,8 +452,21 @@ 1024 553 - 000000ff00000000fd00000000000003ec0000008d00000004000000040000000800000008fc0000000200000002000000050000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000001a0061007200720061006e0067006500720054006f006f006c00730100000049ffffffff00000000000000000000002600560069007300690062006c006500200074007200610063006b0020007400790070006500730100000128000000f0000000000000000000000012007400720061006e00730070006f007200740100000218ffffffff00000000000000000000000a00700061006e00690063010000033e000000b6000000000000000000000002000000010000001e0041007200720061006e0067006500720054006f006f006c0062006100720100000000ffffffff0000000000000000 - 000000ff00000000fd00000000000004000000022900000004000000040000000800000008fc0000000300000002000000060000001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f005200650064006f00200074006f006f006c0073010000008cffffffff00000000000000000000001a0061007200720061006e0067006500720054006f006f006c007301000000d5ffffffff00000000000000000000002600560069007300690062006c006500200074007200610063006b00200074007900700065007301000001b4ffffffff000000000000000000000012007400720061006e00730070006f007200740100000293ffffffff00000000000000000000000a00700061006e0069006301000003b900000047000000000000000000000002000000010000001e0041007200720061006e0067006500720054006f006f006c0062006100720100000000ffffffff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e00610074007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c50000000000000000 + 000000ff00000000fd00000000000003ec0000008d00000004000000040000000800000008fc000000020000000200000005 +0000001e0055006e0064006f002f005200650064006f00200074006f006f006c00730100000000ffffffff00000000000000000000001a006100720072006100 +6e0067006500720054006f006f006c00730100000049ffffffff00000000000000000000002600560069007300690062006c006500200074007200610063006b +0020007400790070006500730100000128000000f0000000000000000000000012007400720061006e00730070006f007200740100000218ffffffff00000000 +000000000000000a00700061006e00690063010000033e000000b6000000000000000000000002000000010000001e0041007200720061006e00670065007200 +54006f006f006c0062006100720100000000ffffffff0000000000000000 + 000000ff00000000fd00000000000004000000022900000004000000040000000800000008fc000000030000000200000006000 +0001800460069006c006500200042007500740074006f006e007301000000000000008c00000000000000000000001e0055006e0064006f002f0052006500640 +06f00200074006f006f006c0073010000008cffffffff00000000000000000000001a0061007200720061006e0067006500720054006f006f006c00730100000 +0d5ffffffff00000000000000000000002600560069007300690062006c006500200074007200610063006b00200074007900700065007301000001b4fffffff +f000000000000000000000012007400720061006e00730070006f007200740100000293ffffffff00000000000000000000000a00700061006e0069006301000 +003b900000047000000000000000000000002000000010000001e0041007200720061006e0067006500720054006f006f006c0062006100720100000000fffff +fff000000000000000000000002000000030000000a00540065006d0070006f0100000000ffffffff000000000000000000000012005300690067006e0061007 +4007500720065010000008bffffffff00000000000000000000001a0053006f006e006700200050006f0073006900740069006f006e010000013b000002c5000 +0000000000000 0 1 1 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", +" ", +" ", +" ", +" .. ", +" .... ", +" ...... ", +" ........ ", +" ........ ", +" ........ ", +" ...... ", +" .... ", +" .. ", +" ", +" ", +" ", +" "}; -- cgit v1.2.3