void
MIDIInstrumentParameterPanel::slotSelectProgram(int index)
{
    RG_DEBUG << "slotSelectProgram()";

    if (!getSelectedInstrument())
        return;

    MidiDevice *md =
            dynamic_cast<MidiDevice *>(getSelectedInstrument()->getDevice());
    if (!md)
        return;

    const MidiProgram *prg = &m_programs[index];

    // If there has been no change, bail.
    if (getSelectedInstrument()->getProgramChange() == prg->getProgram())
        return;

    getSelectedInstrument()->setProgramChange(prg->getProgram());

    // In Variations mode, select the 0th variation.

    // In Variations mode, it's very easy to select an "invalid"
    // program change.  I.e. one for which the bank is not valid.  Go
    // from one program/variation to a program that doesn't have that
    // variation.  We need to handle that here by selecting the 0th
    // variation.  That's what the user expects.

    if (md->getVariationType() == MidiDevice::VariationFromMSB) {
        MidiBank bank = getSelectedInstrument()->getProgram().getBank();
        // Get the list of MSB variations.
        BankList bankList = md->getBanksByLSB(
                getSelectedInstrument()->isPercussion(), bank.getLSB());
        if (!bankList.empty()) {
            // Pick the first MSB variation
            getSelectedInstrument()->setMSB(bankList.front().getMSB());
        }
    }
    if (md->getVariationType() == MidiDevice::VariationFromLSB) {
        MidiBank bank = getSelectedInstrument()->getProgram().getBank();
        // Get the list of LSB variations.
        BankList bankList = md->getBanksByMSB(
                getSelectedInstrument()->isPercussion(), bank.getMSB());
        if (!bankList.empty()) {
            // Pick the first LSB variation
            getSelectedInstrument()->setLSB(bankList.front().getLSB());
        }
    }

    getSelectedInstrument()->sendChannelSetup();

    // Just one change notification for the two potential changes.
    // See comments in slotSelectBank() for further discussion.
    getSelectedInstrument()->changed();
}
Beispiel #2
0
ProgramList
MidiDevice::getPrograms0thVariation(bool percussion, const MidiBank &bank) const
{
    // If we aren't in variations mode, just use getPrograms().
    if (m_variationType == NoVariations)
        return getPrograms(bank);

    // Get the variation bank list for this bank
    BankList bankList;
    if (m_variationType == VariationFromMSB) {
        bankList = getBanksByLSB(percussion, bank.getLSB());
    } else {
        bankList = getBanksByMSB(percussion, bank.getMSB());
    }

    if (!bankList.empty()) {
        MidiBank firstBank = bankList.front();
        return getPrograms(firstBank);
    }

    return ProgramList();
}
void
MIDIInstrumentParameterPanel::slotSelectBank(int index)
{
    RG_DEBUG << "slotSelectBank() begin...";

    if (!getSelectedInstrument())
        return;

    MidiDevice *md =
            dynamic_cast<MidiDevice *>(getSelectedInstrument()->getDevice());
    if (!md) {
        std::cerr << "WARNING: MIDIInstrumentParameterPanel::slotSelectBank(): No MidiDevice for Instrument " << getSelectedInstrument()->getId() << '\n';
        return;
    }

    const MidiBank &bank = m_banks[index];

    bool change = false;

    if (md->getVariationType() != MidiDevice::VariationFromLSB) {
        if (getSelectedInstrument()->getLSB() != bank.getLSB()) {
            getSelectedInstrument()->setLSB(bank.getLSB());
            change = true;
        }
    }
    if (md->getVariationType() != MidiDevice::VariationFromMSB) {
        if (getSelectedInstrument()->getMSB() != bank.getMSB()) {
            getSelectedInstrument()->setMSB(bank.getMSB());
            change = true;
        }
    }

    // If no change, bail.
    if (!change)
        return;

    // Make sure the Instrument is valid WRT the Device.

    // If the current bank/program is not valid for this device, fix it.
    if (!getSelectedInstrument()->isProgramValid()) {

        // If we're not in variations mode...
        if (md->getVariationType() == MidiDevice::NoVariations) {

            // ...go with the first program
            ProgramList programList = md->getPrograms(bank);
            if (!programList.empty()) {
                // Switch to the first program in this bank.
                getSelectedInstrument()->setProgram(programList.front());
            } else {
                // No programs for this bank.  Just go with 0.
                getSelectedInstrument()->setProgramChange(0);
            }

        } else {  // We're in variations mode...

            // This is the three-comboboxes (bank/program/variation) case.
            // It's an extremely difficult case to handle, so we're just
            // going to punt and give them the first program/variation in
            // the bank they just selected.

            // Get the variation bank list for this bank
            BankList bankList;
            if (md->getVariationType() == MidiDevice::VariationFromMSB) {
                bankList = md->getBanksByLSB(
                        getSelectedInstrument()->isPercussion(), bank.getLSB());
            } else {
                bankList = md->getBanksByMSB(
                        getSelectedInstrument()->isPercussion(), bank.getMSB());
            }
            if (!bankList.empty()) {
                // Pick the first bank
                MidiBank firstBank = bankList.front();
                // Get the program list
                ProgramList programList = md->getPrograms(firstBank);
                if (!programList.empty()) {
                    // Pick the first program
                    getSelectedInstrument()->setProgram(programList.front());
                }
            }

            // To make the above more complex, we could consider the
            // case where the Program Change happens to be valid for
            // some variation bank in the newly selected bank.  Then
            // go with the 0th variation bank that has that program
            // change.  But I think this is complicated enough.

        }
    }

    getSelectedInstrument()->sendChannelSetup();

    // This is why changed() isn't called within
    // the setters.  If it were, then each of the above changes would
    // result in a change notification going out.  Worst case, that
    // would be three change notifications and the first two would be
    // sent when the Instrument was in an inconsistent state.
    // Rule: Avoid sending change notifications from setters.
    // Why?  It reduces the number of notifications which improves
    // performance.  It avoids sending notifications when an object's
    // state is inconsistent.  It avoids endless loops.
    getSelectedInstrument()->changed();
}