    //=============================================================================
    //  MuseScore
    //  Linux Music Score Editor
    //  $Id: mixer.cpp 5651 2012-05-19 15:57:26Z lasconic $
    //
    //  Copyright (C) 2002-2016 Werner Schweer and others
    //
    //  This program is free software; you can redistribute it and/or modify
    //  it under the terms of the GNU General Public License version 2.
    //
    //  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., 675 Mass Ave, Cambridge, MA 02139, USA.
    //=============================================================================

    #include "musescore.h"
    #include "libmscore/score.h"
    #include "libmscore/part.h"
    #include "mixer.h"
    #include "seq.h"
    #include "libmscore/undo.h"
    #include "synthcontrol.h"
    #include "synthesizer/msynthesizer.h"
    #include "preferences.h"
    #include <qmessagebox.h>
    #include <accessibletoolbutton.h>

    namespace Ms {

    #define _setValue(__x, __y) \
          __x->blockSignals(true); \
          __x->setValue(__y); \
          __x->blockSignals(false);

    #define _setChecked(__x, __y) \
          __x->blockSignals(true); \
          __x->setChecked(__y); \
          __x->blockSignals(false);

    //---------------------------------------------------------
    //   PartEdit
    //---------------------------------------------------------

    PartEdit::PartEdit(QWidget* parent)
       : QWidget(parent, Qt::Dialog)
          {
          setupUi(this);
          connect(patch,          SIGNAL(activated(int)),           SLOT(patchChanged(int)));
          connect(volume,         SIGNAL(valueChanged(double,int)), SLOT(volChanged(double)));
          connect(pan,            SIGNAL(valueChanged(double,int)), SLOT(panChanged(double)));
          connect(chorus,         SIGNAL(valueChanged(double,int)), SLOT(chorusChanged(double)));
          connect(reverb,         SIGNAL(valueChanged(double,int)), SLOT(reverbChanged(double)));
          connect(mute,           SIGNAL(toggled(bool)),            SLOT(muteChanged(bool)));
          connect(solo,           SIGNAL(toggled(bool)),            SLOT(soloToggled(bool)));
          connect(drumset,        SIGNAL(toggled(bool)),            SLOT(drumsetToggled(bool)));
          connect(portSpinBox,    SIGNAL(valueChanged(int)),        SLOT(midiChannelChanged(int)));
          connect(channelSpinBox, SIGNAL(valueChanged(int)),        SLOT(midiChannelChanged(int)));
          connect(expand,         SIGNAL(toggled(bool)),            SLOT(expandToggled(bool)));

          expandToggled(false);
          }

    //---------------------------------------------------------
    //   expandToggled
    //---------------------------------------------------------

    void PartEdit::expandToggled(bool val)
          {
          details->setVisible(val);
          }

    //---------------------------------------------------------
    //   setPart
    //---------------------------------------------------------

    void PartEdit::setPart(Part* p, Channel* a)
          {
          Channel dummy;
          channel = a;
          part    = p;
          QString s = part->partName();
          if (!a->name.isEmpty()) {
                if (a->name != "normal") {
                      s += "-";
                      s += qApp->translate("InstrumentsXML", a->name.toUtf8().data());
                      }
                }
          partName->setText(s);
          _setValue(volume, a->volume);
          volume->setDclickValue1(dummy.volume);
          volume->setDclickValue2(dummy.volume);
          _setValue(reverb, a->reverb);
          reverb->setDclickValue1(dummy.reverb);
          reverb->setDclickValue2(dummy.reverb);
          _setValue(chorus, a->chorus);

          chorus->setDclickValue1(dummy.chorus);
          chorus->setDclickValue2(dummy.chorus);
          _setValue(pan, a->pan);

          pan->setDclickValue1(0);
          pan->setDclickValue2(0);
          for (int i = 0; i < patch->count(); ++i) {
                MidiPatch* p = (MidiPatch*)patch->itemData(i, Qt::UserRole).value<void*>();
                if (a->synti == p->synti && a->program == p->prog && a->bank == p->bank) {
                      patch->setCurrentIndex(i);
                      break;
                      }
                }
          _setChecked(drumset, p->instrument()->useDrumset());
          _setValue(portSpinBox,    part->masterScore()->midiMapping(a->channel)->port + 1);
          _setValue(channelSpinBox, part->masterScore()->midiMapping(a->channel)->channel + 1);

          QHBoxLayout* hb = voiceButtonBox;
          int idx = 0;
          for (Staff* staff : *part->staves()) {
                for (int voice = 0; voice < VOICES; ++voice) {
                      if (!voiceButtons.value(idx)) {
                            QToolButton* tb = new QToolButton;
                            tb->setText(QString("%1").arg(voice+1));
                            tb->setCheckable(true);
                            tb->setChecked(staff->playbackVoice(voice));
                            tb->setFocusPolicy(Qt::ClickFocus);
                            tb->setToolButtonStyle(Qt::ToolButtonTextOnly);
                            QPalette p(tb->palette());
                            p.setColor(QPalette::Base, MScore::selectColor[voice]);
                            tb->setPalette(p);
                            hb->addWidget(tb);
                            voiceButtons.append(tb);
                            connect(tb, SIGNAL(clicked()), SLOT(playbackVoiceChanged()));
                            }
                      ++idx;
                      }
                hb->addStretch(5);
                }
          while (voiceButtons.value(idx)) {
                QToolButton* tb = voiceButtons.value(idx);
                if (!tb)
                      break;
                voiceButtons.takeAt(idx);
                delete tb;
                }
          }

    //---------------------------------------------------------
    //   playbackVoiceChanged
    //---------------------------------------------------------

    void PartEdit::playbackVoiceChanged()
          {
          int idx = 0;
          Score* score = part->score();
          score->startCmd();
          for (Staff* staff : *part->staves()) {
                for (int voice = 0; voice < VOICES; ++voice) {
                      QToolButton* tb = voiceButtons[idx];
                      bool val = tb->isChecked();
                      if (val != staff->playbackVoice(voice)) {
                            switch (voice) {
                                  case 0:
                                  printf("undo\n");
                                        score->undoChangeProperty(staff, P_ID::PLAYBACK_VOICE1, val);
                                        break;
                                  case 1:
                                        score->undoChangeProperty(staff, P_ID::PLAYBACK_VOICE2, val);
                                        break;
                                  case 2:
                                        score->undoChangeProperty(staff, P_ID::PLAYBACK_VOICE3, val);
                                        break;
                                  case 3:
                                        score->undoChangeProperty(staff, P_ID::PLAYBACK_VOICE4, val);
                                        break;
                                  }
                            }
                      ++idx;
                      }
                }
          score->endCmd();
          }

    //---------------------------------------------------------
    //   Mixer
    //---------------------------------------------------------

    Mixer::Mixer(QWidget* parent)
       : QScrollArea(parent)
          {
          setObjectName("Mixer");
          setWidgetResizable(true);
          setWindowFlags(Qt::Tool);
          setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);

          QWidget* area = new QWidget(this);
          vb = new QVBoxLayout;
          vb->setMargin(0);
          vb->setSpacing(0);
          area->setLayout(vb);
          setWidget(area);

          enablePlay = new EnablePlayForWidget(this);
          readSettings();
          retranslate(true);
          }

    //---------------------------------------------------------
    //   retranslate
    //---------------------------------------------------------

    void Mixer::retranslate(bool firstTime)
          {
          setWindowTitle(tr("Mixer"));
          if (!firstTime) {
                for (int i = 0; i < vb->count(); i++) {
                      PartEdit* p = partEdit(i);
                      if (p) p->retranslateUi(p);
                      }
                }
          }

    //---------------------------------------------------------
    //   closeEvent
    //---------------------------------------------------------

    void Mixer::closeEvent(QCloseEvent* ev)
          {
          emit closed(false);
          QWidget::closeEvent(ev);
          }

    //---------------------------------------------------------
    //   showEvent
    //---------------------------------------------------------

    void Mixer::showEvent(QShowEvent* e)
          {
          enablePlay->showEvent(e);
          QScrollArea::showEvent(e);
          activateWindow();
          setFocus();
          }

    //---------------------------------------------------------
    //   eventFilter
    //---------------------------------------------------------

    bool Mixer::eventFilter(QObject* obj, QEvent* e)
          {
          if (enablePlay->eventFilter(obj, e))
                return true;
          return QScrollArea::eventFilter(obj, e);
          }

    void Mixer::keyPressEvent(QKeyEvent* ev) {
          if (ev->key() == Qt::Key_Escape && ev->modifiers() == Qt::NoModifier) {
                close();
                return;
                }
          QWidget::keyPressEvent(ev);
          }

    //---------------------------------------------------------
    //   changeEvent
    //---------------------------------------------------------

    void Mixer::changeEvent(QEvent *event)
          {
          QScrollArea::changeEvent(event);
          if (event->type() == QEvent::LanguageChange)
                retranslate();
          }

    //---------------------------------------------------------
    //   updateAll
    //---------------------------------------------------------

    void Mixer::updateAll(MasterScore* score)
          {
          cs = score;
          int n = -vb->count();
          if (n < 0) {
                QLayoutItem* wi = vb->itemAt(vb->count()-1);
                vb->removeItem(wi);
                delete wi;
                n += 1;
                }
          if (cs) {
                QList<MidiMapping>* mm = cs->midiMapping();
                n += mm->size();
                }
          while (n < 0) {
                QLayoutItem* wi = vb->itemAt(0);
                vb->removeItem(wi);
                delete wi->widget();
                delete wi;
                ++n;
                }
          while (n > 0) {
                PartEdit* pe = new PartEdit;
                connect(pe, SIGNAL(soloChanged(bool)), SLOT(updateSolo(bool)));
                vb->addWidget(pe);
                --n;
                }
          vb->addStretch(5);
          patchListChanged();
          }

    //---------------------------------------------------------
    //   partEdit
    //---------------------------------------------------------

    PartEdit* Mixer::partEdit(int index)
          {
          if (index < vb->count()) {
                QWidgetItem* wi = (QWidgetItem*)(vb->itemAt(index));
                return (PartEdit*) wi->widget();
                }
          return 0;
          }

    //---------------------------------------------------------
    //   patchListChanged
    //---------------------------------------------------------

    void Mixer::patchListChanged()
          {
          if (!cs)
                return;

          int idx = 0;
          QList<MidiMapping>* mm = cs->midiMapping();
          const QList<MidiPatch*> pl = synti->getPatchInfo();
          for (const MidiMapping& m : *mm) {
                QLayoutItem* wi  = (QWidgetItem*)(vb->itemAt(idx));
                if (!wi->widget())
                      continue;
                PartEdit* pe     = (PartEdit*)(wi->widget());
                bool drum        = m.part->instrument()->useDrumset();
                pe->patch->clear();
                for (const MidiPatch* p : pl) {
                      if (p->drum == drum)
                            pe->patch->addItem(p->name, QVariant::fromValue<void*>((void*)p));
                      }
                pe->setPart(m.part, m.articulation);
                idx++;
                }
          // Update solo & mute only after creating all controls (we need to sync all controls)
          idx = 0;
          for (const MidiMapping& m : *mm) {
                QLayoutItem* wi = (QWidgetItem*)(vb->itemAt(idx));
                if (!wi->widget())
                      continue;
                PartEdit* pe    = (PartEdit*)(wi->widget());
                pe->mute->setChecked(m.articulation->mute);
                pe->solo->setChecked(m.articulation->solo);
                idx++;
                }
          }

    //---------------------------------------------------------
    //   midiPrefsChanged
    //---------------------------------------------------------

    void Mixer::midiPrefsChanged(bool showMidiControls)
          {
          if (!cs)
                return;
          for (int i = 0; i < vb->count(); i++ ){
                QWidgetItem* wi = (QWidgetItem*)(vb->itemAt(i));
                PartEdit* pe    = (PartEdit*)(wi->widget());
                pe->channelLabel  ->setVisible(showMidiControls);
                pe->portLabel     ->setVisible(showMidiControls);
                pe->channelSpinBox->setVisible(showMidiControls);
                pe->portSpinBox   ->setVisible(showMidiControls);

                if (!showMidiControls)
                      pe->hboxLayout->setSpacing(20);
                else
                      pe->hboxLayout->setSpacing(5);
                }
          }

    //---------------------------------------------------------
    //   showMixer
    //---------------------------------------------------------

    void MuseScore::showMixer(bool val)
          {
          QAction* a = getAction("toggle-mixer");
          if (mixer == 0) {
                mixer = new Mixer(this);
                mscore->stackUnder(mixer);
                if (synthControl)
                      connect(synthControl, SIGNAL(soundFontChanged()), mixer, SLOT(patchListChanged()));
                connect(synti, SIGNAL(soundFontChanged()), mixer, SLOT(patchListChanged()));
                connect(mixer, SIGNAL(closed(bool)), a, SLOT(setChecked(bool)));
                }
          mixer->updateAll(cs->masterScore());
          mixer->setVisible(val);
          }

    //---------------------------------------------------------
    //   patchChanged
    //---------------------------------------------------------

    void PartEdit::patchChanged(int n, bool syncControls)
          {
          if (part == 0)
                return;

          const MidiPatch* p = (MidiPatch*)patch->itemData(n, Qt::UserRole).value<void*>();
          if (p == 0) {
                qDebug("PartEdit::patchChanged: no patch");
                return;
                }
          Score* score = part->score();
          if (score) {
                score->startCmd();
                score->undo(new ChangePatch(score, channel, p));
                score->setLayoutAll();
                score->endCmd();
                }
          channel->updateInitList();
          sync(syncControls);
          }

    //---------------------------------------------------------
    //   volChanged
    //---------------------------------------------------------

    void PartEdit::volChanged(double val, bool syncControls)
          {
          int iv = lrint(val);
          seq->setController(channel->channel, CTRL_VOLUME, iv);
          channel->volume = iv;
          channel->updateInitList();
          sync(syncControls);
          }

    //---------------------------------------------------------
    //   panChanged
    //---------------------------------------------------------

    void PartEdit::panChanged(double val, bool syncControls)
          {
          int iv = lrint(val);
          seq->setController(channel->channel, CTRL_PANPOT, iv);
          channel->pan = iv;
          channel->updateInitList();
          sync(syncControls);
          }

    //---------------------------------------------------------
    //   reverbChanged
    //---------------------------------------------------------

    void PartEdit::reverbChanged(double val, bool syncControls)
          {
          int iv = lrint(val);
          seq->setController(channel->channel, CTRL_REVERB_SEND, iv);
          channel->reverb = iv;
          channel->updateInitList();
          sync(syncControls);
          }

    //---------------------------------------------------------
    //   chorusChanged
    //---------------------------------------------------------

    void PartEdit::chorusChanged(double val, bool syncControls)
          {
          int iv = lrint(val);
          seq->setController(channel->channel, CTRL_CHORUS_SEND, iv);
          channel->chorus = iv;
          channel->updateInitList();
          sync(syncControls);
          }

    //---------------------------------------------------------
    //   muteChanged
    //---------------------------------------------------------

    void PartEdit::muteChanged(bool val, bool syncControls)
          {
          if (val)
                seq->stopNotes(channel->channel);
          channel->mute = val;
          sync(syncControls);
          }

    //---------------------------------------------------------
    //   soloToggled
    //---------------------------------------------------------

    void PartEdit::soloToggled(bool val, bool syncControls)
          {
          channel->solo     = val;
          channel->soloMute = !val;
          if (val) {
                mute->setChecked(false);
                for (Part* p : part->score()->parts()) {
                      const InstrumentList* il = p->instruments();
                      for (auto i = il->begin(); i != il->end(); ++i) {
                            const Instrument* instr = i->second;
                            for (Channel* a : instr->channel()) {
                                  a->soloMute = (channel != a && !a->solo);
                                  a->solo     = (channel == a || a->solo);
                                  if (a->soloMute)
                                        seq->stopNotes(a->channel);
                                  }
                            }
                      }
                emit soloChanged(true);
                }
          else { //do nothing except if it's the last solo to be switched off
                bool found = false;
                for (Part* p : part->score()->parts()) {
                      const InstrumentList* il = p->instruments();
                      for (auto i = il->begin(); i != il->end(); ++i) {
                            const Instrument* instr = i->second;
                            for (Channel* a : instr->channel()) {
                                  if (a->solo){
                                        found = true;
                                        break;
                                        }
                                  }
                            }
                      }
                if (!found){
                      foreach(Part* p, part->score()->parts()) {
                            const InstrumentList* il = p->instruments();
                            for (auto i = il->begin(); i != il->end(); ++i) {
                                  const Instrument* instr = i->second;
                                  for (Channel* a : instr->channel()) {
                                        a->soloMute = false;
                                        a->solo     = false;
                                        }
                                  }
                            }
                      emit soloChanged(false);
                      }
                }
          sync(syncControls);
          }

    //---------------------------------------------------------
    //   drumsetToggled
    //---------------------------------------------------------

    void PartEdit::drumsetToggled(bool val, bool syncControls)
          {
          if (part == 0)
                return;

          Score* score = part->score();
          score->startCmd();

          part->undoChangeProperty(P_ID::USE_DRUMSET, val);
          patch->clear();
          const QList<MidiPatch*> pl = synti->getPatchInfo();
          for (const MidiPatch* p : pl) {
                if (p->drum == val)
                      patch->addItem(p->name, QVariant::fromValue<void*>((void*)p));
                }

          // switch to first instrument
          const MidiPatch* p = (MidiPatch*)patch->itemData(0, Qt::UserRole).value<void*>();
          if (p == 0) {
                qDebug("PartEdit::patchChanged: no patch");
                return;
                }
          score->undo(new ChangePatch(score, channel, p));
          score->setLayoutAll();
          score->endCmd();
          sync(syncControls);
          }

    //---------------------------------------------------------
    //   updateSolo
    //---------------------------------------------------------

    void Mixer::updateSolo(bool val)
          {
          for (int i = 0; i < vb->count(); i++ ){
                QWidgetItem* wi = (QWidgetItem*)(vb->itemAt(i));
                PartEdit* pe    = (PartEdit*)(wi->widget());
                if (pe)
                      pe->mute->setEnabled(!val);
                }
          }

    //---------------------------------------------------------
    //   writeSettings
    //---------------------------------------------------------

    void Mixer::writeSettings()
          {
          MuseScore::saveGeometry(this);
          }

    //---------------------------------------------------------
    //   readSettings
    //---------------------------------------------------------

    void Mixer::readSettings()
          {
          resize(QSize(480, 600)); //ensure default size if no geometry in settings
          MuseScore::restoreGeometry(this);
          }

    //---------------------------------------------------------
    //   sync
    //   synchronizes controls with same MIDI port and channel
    //---------------------------------------------------------

    void PartEdit::sync(bool syncControls)
          {
          if (!syncControls)
                return;
          int count = this->parentWidget()->layout()->count();
          for(int i = 0; i < count; i++) {
                QWidgetItem* wi = (QWidgetItem*)(this->parentWidget()->layout()->itemAt(i));
                PartEdit* pe    = (PartEdit*)(wi->widget());
                if (pe != 0 && pe != this
                    && this->channelSpinBox->value() == pe->channelSpinBox->value()
                    && this->portSpinBox->value() == pe->portSpinBox->value()) {

                      if (volume->value() != pe->volume->value()) {
                            _setValue(pe->volume, this->volume->value());
                            emit pe->volChanged(this->volume->value(), false);
                            }
                      if (pan->value() != pe->pan->value()) {
                            _setValue(pe->pan, this->pan->value());
                            emit pe->panChanged(this->pan->value(), false);
                            }
                      if (reverb->value() != pe->reverb->value()) {
                            _setValue(pe->reverb, this->reverb->value());
                            emit pe->reverbChanged(this->reverb->value(), false);
                            }
                      if (chorus->value() != pe->chorus->value()) {
                            _setValue(pe->chorus, this->chorus->value());
                           emit pe->chorusChanged(this->chorus->value(), false);
                            }
                      if (mute->isChecked() != pe->mute->isChecked()) {
                            _setChecked(pe->mute, channel->mute);
                            emit pe->muteChanged(channel->mute, false);
                            }
                      if (solo->isChecked() != pe->solo->isChecked()) {
                            _setChecked(pe->solo, channel->solo);
                            emit pe->soloToggled(channel->solo, false);
                            }

                      if (drumset->isChecked() != pe->drumset->isChecked()) {
                            _setChecked(pe->drumset, drumset->isChecked());
                            emit pe->drumsetToggled(drumset->isChecked(), false);
                            }
                      if (patch->currentIndex() != pe->patch->currentIndex()) {
                            pe->patch->blockSignals(true);
                            pe->patch->setCurrentIndex(this->patch->currentIndex());
                            pe->patch->blockSignals(false);
                            }
                      }
                }
          }

    //---------------------------------------------------------
    //   midiChannelChanged
    //   handles MIDI port & channel change
    //---------------------------------------------------------

    void PartEdit::midiChannelChanged(int)
          {
          if (part == 0)
                return;
          seq->stopNotes(channel->channel);
          int p =    portSpinBox->value() - 1;
          int c = channelSpinBox->value() - 1;

          // 1 is for going up, -1 for going down
          int direction = copysign(1, c - part->masterScore()->midiMapping(channel->channel)->channel);

          // Channel 9 is special for drums
          if (part->instrument()->useDrumset() && c != 9) {
                _setValue(channelSpinBox, 10);
                return;
                }
          else if (!part->instrument()->useDrumset() && c == 9) {
                c = 9 + direction;
                }

          if (c == 16) {
                c = 0;
                p++;
                }

          int newChannel = p*16+c;

          // If there is an instrument with the same MIDI port and channel, sync this instrument to a found one
          bool needSync = true;
          int elementsInMixer = parentWidget()->layout()->count();
          for (int i = 0; i < elementsInMixer; i++) {
                QWidgetItem* wi = (QWidgetItem*)(this->parentWidget()->layout()->itemAt(i));
                PartEdit* pe    = (PartEdit*)(wi->widget());
                if (pe != 0 && pe != this
                            && pe->channelSpinBox->value() == this->channelSpinBox->value()
                            && pe->portSpinBox->value() == this->portSpinBox->value()) {
                      // Show datails if parameters are different
                      QString detailedText;
                      if (patch->currentIndex() != pe->patch->currentIndex())
                            detailedText += QString(tr("Sound: '%1'' vs '%2'\n")).arg(patch->itemText(patch->currentIndex()), pe->patch->itemText(pe->patch->currentIndex()));
                      if (this->volume->value() != pe->volume->value())
                            detailedText += QString(tr("Volume: %1 vs %2\n")).arg(QString::number(volume->value()),  QString::number(pe->volume->value()));
                      if (this->pan->value() != pe->pan->value())
                            detailedText += QString(tr("Pan: %1 vs %2\n")).arg(QString::number(pan->value()),  QString::number(pe->pan->value()));
                      if (this->reverb->value() != pe->reverb->value())
                            detailedText += QString(tr("Reverb: %1 vs %2\n")).arg(QString::number(reverb->value()),  QString::number(pe->reverb->value()));
                      if (this->chorus->value() != pe->chorus->value())
                            detailedText += QString(tr("Chorus: %1 vs %2\n")).arg(QString::number(chorus->value()),  QString::number(pe->chorus->value()));
                      if (this->solo->isChecked() != pe->solo->isChecked())
                            detailedText += QString(tr("Solo: %1 vs %2\n")).arg(solo->isChecked()?"Yes":"No", pe->solo->isChecked()?"Yes":"No");
                      if (this->mute->isChecked() != pe->mute->isChecked())
                            detailedText += QString(tr("Mute: %1 vs %2\n")).arg(mute->isChecked()?"Yes":"No", pe->mute->isChecked()?"Yes":"No");

                      if (!detailedText.isEmpty())
                            detailedText = QString(tr("Instrument '%1'    Instrument '%2'\n")).arg(this->partName->text(), pe->partName->text())+ detailedText;
                      QMessageBox msgBox;
                      msgBox.setIcon(QMessageBox::Warning);
                      QString text = QString(tr("There is already an instrument '%1' with MIDI port = %2 and channel = %3.")).arg(pe->partName->text(), QString::number(pe->portSpinBox->value()), QString::number(pe->channelSpinBox->value()));
                      msgBox.setText(text);
                      msgBox.setInformativeText(tr("Do you want to synchronize current instrument with an existing one?"));
                      msgBox.setDetailedText(detailedText);
                      msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
                      QPushButton *assignFreeChannel = msgBox.addButton(tr("Assign next free MIDI channel"), QMessageBox::HelpRole);
                      msgBox.setDefaultButton(QMessageBox::Ok);
                      if (msgBox.exec() == QMessageBox::Cancel) {
                            _setValue(channelSpinBox, part->masterScore()->midiMapping(channel->channel)->channel + 1);
                            _setValue(portSpinBox,    part->masterScore()->midiMapping(channel->channel)->port + 1);
                            needSync = false;
                            break;
                            }

                      if (msgBox.clickedButton() == assignFreeChannel) {
                            newChannel = part->masterScore()->getNextFreeMidiMapping();
                            break;
                            }
                      // Sync
                      _setValue(channelSpinBox, newChannel % 16 + 1);
                      _setValue(portSpinBox,    newChannel / 16 + 1);
                      part->masterScore()->midiMapping(channel->channel)->channel = newChannel % 16;
                      part->masterScore()->midiMapping(channel->channel)->port    = newChannel / 16;
                      channel->volume = lrint(pe->volume->value());
                      channel->pan    = lrint(pe->pan->value());
                      channel->reverb = lrint(pe->reverb->value());
                      channel->chorus = lrint(pe->chorus->value());
                      channel->mute = pe->mute->isChecked();
                      channel->solo = pe->solo->isChecked();

                      MidiPatch* newPatch = (MidiPatch*)pe->patch->itemData(pe->patch->currentIndex(), Qt::UserRole).value<void*>();
                      if (newPatch == 0)
                            return;
                      patch->setCurrentIndex(pe->patch->currentIndex());
                      channel->program = newPatch->prog;
                      channel->bank    = newPatch->bank;
                      channel->synti   = newPatch->synti;

                      part->masterScore()->setSoloMute();
                      part->score()->setInstrumentsChanged(true);
                      part->score()->setLayoutAll();
                      break;
                      }
                }
          channel->updateInitList();
          if (needSync) {
                _setValue(channelSpinBox, newChannel % 16 + 1);
                _setValue(portSpinBox,    newChannel / 16 + 1);
                part->masterScore()->midiMapping(channel->channel)->channel = newChannel % 16;
                part->masterScore()->midiMapping(channel->channel)->port    = newChannel / 16;
                part->score()->setInstrumentsChanged(true);
                part->score()->setLayoutAll();
                seq->initInstruments();
                }
          else {
                // Initializing an instrument with new channel
                foreach(const MidiCoreEvent& e, channel->init) {
                      if (e.type() == ME_INVALID)
                            continue;
                      NPlayEvent event(e.type(), channel->channel, e.dataA(), e.dataB());
                      seq->sendEvent(event);
                      }
                }

          // Update MIDI Out ports
          int maxPort = max(p, part->score()->masterScore()->midiPortCount());
          part->score()->masterScore()->setMidiPortCount(maxPort);
          if (seq->driver() && (preferences.useJackMidi || preferences.useAlsaAudio))
                seq->driver()->updateOutPortCount(maxPort + 1);
          }
    }

↑ V678 An object is used as an argument to its own method. Consider checking the first actual argument of the 'retranslateUi' function.