You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1176 lines
36 KiB
1176 lines
36 KiB
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
|
|
|
/*
|
|
Rosegarden
|
|
A MIDI and audio sequencer and musical notation editor.
|
|
|
|
This program is Copyright 2000-2008
|
|
Guillaume Laurent <glaurent@telegraph-road.org>,
|
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
|
Richard Bown <richard.bown@ferventsoftware.com>
|
|
|
|
The moral rights of Guillaume Laurent, Chris Cannam, and Richard
|
|
Bown to claim authorship of this work have been asserted.
|
|
|
|
Other copyrights also apply to some parts of this work. Please
|
|
see the AUTHORS file and individual file headers for details.
|
|
|
|
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; either version 2 of the
|
|
License, or (at your option) any later version. See the file
|
|
COPYING included with this distribution for more information.
|
|
*/
|
|
|
|
|
|
#include "MIDIInstrumentParameterPanel.h"
|
|
#include <tqlayout.h>
|
|
|
|
#include "sound/Midi.h"
|
|
#include <klocale.h>
|
|
#include "misc/Debug.h"
|
|
#include "misc/Strings.h"
|
|
#include "base/Colour.h"
|
|
#include "base/Composition.h"
|
|
#include "base/ControlParameter.h"
|
|
#include "base/Instrument.h"
|
|
#include "base/MidiDevice.h"
|
|
#include "base/MidiProgram.h"
|
|
#include "document/RosegardenGUIDoc.h"
|
|
#include "gui/studio/StudioControl.h"
|
|
#include "gui/widgets/Rotary.h"
|
|
#include "InstrumentParameterPanel.h"
|
|
#include "sound/MappedEvent.h"
|
|
#include "sound/MappedInstrument.h"
|
|
#include <kcombobox.h>
|
|
#include <ksqueezedtextlabel.h>
|
|
#include <tqcheckbox.h>
|
|
#include <tqcolor.h>
|
|
#include <tqfontmetrics.h>
|
|
#include <tqframe.h>
|
|
#include <tqhbox.h>
|
|
#include <tqlabel.h>
|
|
#include <tqregexp.h>
|
|
#include <tqsignalmapper.h>
|
|
#include <tqstring.h>
|
|
#include <tqwidget.h>
|
|
#include <algorithm>
|
|
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
MIDIInstrumentParameterPanel::MIDIInstrumentParameterPanel(RosegardenGUIDoc *doc, TQWidget* parent):
|
|
InstrumentParameterPanel(doc, parent),
|
|
m_rotaryFrame(0),
|
|
m_rotaryMapper(new TQSignalMapper(TQT_TQOBJECT(this)))
|
|
{
|
|
m_mainGrid = new TQGridLayout(this, 10, 3, 2, 1);
|
|
|
|
m_connectionLabel = new KSqueezedTextLabel(this);
|
|
m_bankValue = new KComboBox(this);
|
|
m_channelValue = new KComboBox(this);
|
|
m_programValue = new KComboBox(this);
|
|
m_variationValue = new KComboBox(this);
|
|
m_bankCheckBox = new TQCheckBox(this);
|
|
m_programCheckBox = new TQCheckBox(this);
|
|
m_variationCheckBox = new TQCheckBox(this);
|
|
m_percussionCheckBox = new TQCheckBox(this);
|
|
|
|
m_bankValue->setSizeLimit(20);
|
|
m_programValue->setSizeLimit(20);
|
|
m_variationValue->setSizeLimit(20);
|
|
|
|
m_bankLabel = new TQLabel(i18n("Bank"), this);
|
|
m_variationLabel = new TQLabel(i18n("Variation"), this);
|
|
m_programLabel = new TQLabel(i18n("Program"), this);
|
|
TQLabel *channelLabel = new TQLabel(i18n("Channel out"), this);
|
|
TQLabel *percussionLabel = new TQLabel(i18n("Percussion"), this);
|
|
|
|
// Ensure a reasonable amount of space in the program dropdowns even
|
|
// if no instrument initially selected
|
|
TQFontMetrics metrics(m_programValue->font());
|
|
int width22 = metrics.width("1234567890123456789012");
|
|
int width25 = metrics.width("1234567890123456789012345");
|
|
|
|
m_bankValue->setMinimumWidth(width22);
|
|
m_programValue->setMinimumWidth(width22);
|
|
m_variationValue->setMinimumWidth(width22);
|
|
|
|
m_connectionLabel->setFixedWidth(width25);
|
|
m_connectionLabel->setAlignment(TQt::AlignCenter);
|
|
|
|
// Configure the empty final row to accomodate any extra vertical space.
|
|
|
|
m_mainGrid->setRowStretch(m_mainGrid->numRows() - 1, 1);
|
|
|
|
|
|
m_mainGrid->setColStretch(2, 1);
|
|
|
|
m_mainGrid->addMultiCellWidget(m_instrumentLabel, 0, 0, 0, 2, AlignCenter);
|
|
m_mainGrid->addMultiCellWidget(m_connectionLabel, 1, 1, 0, 2, AlignCenter);
|
|
|
|
m_mainGrid->addMultiCellWidget(channelLabel, 2, 2, 0, 1, AlignLeft);
|
|
m_mainGrid->addWidget(m_channelValue, 2, 2, AlignRight);
|
|
|
|
m_mainGrid->addMultiCellWidget(percussionLabel, 3, 3, 0, 1, AlignLeft);
|
|
m_mainGrid->addWidget(m_percussionCheckBox, 3, 2, AlignRight);
|
|
|
|
m_mainGrid->addWidget(m_bankLabel, 4, 0, AlignLeft);
|
|
m_mainGrid->addWidget(m_bankCheckBox, 4, 1, AlignRight);
|
|
m_mainGrid->addWidget(m_bankValue, 4, 2, AlignRight);
|
|
|
|
m_mainGrid->addWidget(m_programLabel, 5, 0, AlignLeft);
|
|
m_mainGrid->addWidget(m_programCheckBox, 5, 1, AlignRight);
|
|
m_mainGrid->addWidget(m_programValue, 5, 2, AlignRight);
|
|
|
|
m_mainGrid->addWidget(m_variationLabel, 6, 0);
|
|
m_mainGrid->addWidget(m_variationCheckBox, 6, 1);
|
|
m_mainGrid->addWidget(m_variationValue, 6, 2, AlignRight);
|
|
|
|
// Populate channel lists
|
|
//
|
|
for (int i = 0; i < 16; i++) {
|
|
m_channelValue->insertItem(TQString("%1").tqarg(i + 1));
|
|
}
|
|
|
|
m_channelValue->setSizeLimit(16);
|
|
|
|
// Disable these by default - they are activate by their
|
|
// checkboxes
|
|
//
|
|
m_programValue->setDisabled(true);
|
|
m_bankValue->setDisabled(true);
|
|
m_variationValue->setDisabled(true);
|
|
|
|
// Only active if we have an Instrument selected
|
|
//
|
|
m_percussionCheckBox->setDisabled(true);
|
|
m_programCheckBox->setDisabled(true);
|
|
m_bankCheckBox->setDisabled(true);
|
|
m_variationCheckBox->setDisabled(true);
|
|
|
|
// Connect up the toggle boxes
|
|
//
|
|
connect(m_percussionCheckBox, TQT_SIGNAL(toggled(bool)),
|
|
this, TQT_SLOT(slotTogglePercussion(bool)));
|
|
|
|
connect(m_programCheckBox, TQT_SIGNAL(toggled(bool)),
|
|
this, TQT_SLOT(slotToggleProgramChange(bool)));
|
|
|
|
connect(m_bankCheckBox, TQT_SIGNAL(toggled(bool)),
|
|
this, TQT_SLOT(slotToggleBank(bool)));
|
|
|
|
connect(m_variationCheckBox, TQT_SIGNAL(toggled(bool)),
|
|
this, TQT_SLOT(slotToggleVariation(bool)));
|
|
|
|
|
|
// Connect activations
|
|
//
|
|
connect(m_bankValue, TQT_SIGNAL(activated(int)),
|
|
this, TQT_SLOT(slotSelectBank(int)));
|
|
|
|
connect(m_variationValue, TQT_SIGNAL(activated(int)),
|
|
this, TQT_SLOT(slotSelectVariation(int)));
|
|
|
|
connect(m_programValue, TQT_SIGNAL(activated(int)),
|
|
this, TQT_SLOT(slotSelectProgram(int)));
|
|
|
|
connect(m_channelValue, TQT_SIGNAL(activated(int)),
|
|
this, TQT_SLOT(slotSelectChannel(int)));
|
|
|
|
// don't select any of the options in any dropdown
|
|
m_programValue->setCurrentItem( -1);
|
|
m_bankValue->setCurrentItem( -1);
|
|
m_channelValue->setCurrentItem( -1);
|
|
m_variationValue->setCurrentItem( -1);
|
|
|
|
connect(m_rotaryMapper, TQT_SIGNAL(mapped(int)),
|
|
this, TQT_SLOT(slotControllerChanged(int)));
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::setupForInstrument(Instrument *instrument)
|
|
{
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::setupForInstrument" << endl;
|
|
MidiDevice *md = dynamic_cast<MidiDevice*>
|
|
(instrument->getDevice());
|
|
if (!md) {
|
|
RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::setupForInstrument:"
|
|
<< " No MidiDevice for Instrument "
|
|
<< instrument->getId() << endl;
|
|
return ;
|
|
}
|
|
|
|
m_selectedInstrument = instrument;
|
|
|
|
// Set instrument name
|
|
//
|
|
m_instrumentLabel->setText(strtoqstr(instrument->getPresentationName()));
|
|
|
|
// Set Studio Device name
|
|
//
|
|
TQString connection(strtoqstr(md->getConnection()));
|
|
if (connection == "") {
|
|
m_connectionLabel->setText(i18n("[ %1 ]").tqarg(i18n("No connection")));
|
|
} else {
|
|
|
|
// remove trailing "(duplex)", "(read only)", "(write only)" etc
|
|
connection.replace(TQRegExp("\\s*\\([^)0-9]+\\)\\s*$"), "");
|
|
|
|
TQString text = i18n("[ %1 ]").tqarg(connection);
|
|
/*TQString origText(text);
|
|
|
|
TQFontMetrics metrics(m_connectionLabel->fontMetrics());
|
|
int maxwidth = metrics.width
|
|
("Program: [X] Acoustic Grand Piano 123");// kind of arbitrary!
|
|
|
|
int hlen = text.length() / 2;
|
|
while (metrics.width(text) > maxwidth && text.length() > 10) {
|
|
--hlen;
|
|
text = origText.left(hlen) + "..." + origText.right(hlen);
|
|
}
|
|
|
|
if (text.length() > origText.length() - 7) text = origText;*/
|
|
m_connectionLabel->setText(text);
|
|
}
|
|
|
|
// Enable all check boxes
|
|
//
|
|
m_percussionCheckBox->setDisabled(false);
|
|
m_programCheckBox->setDisabled(false);
|
|
m_bankCheckBox->setDisabled(false);
|
|
m_variationCheckBox->setDisabled(false);
|
|
|
|
// Activate all checkboxes
|
|
//
|
|
m_percussionCheckBox->setChecked(instrument->isPercussion());
|
|
m_programCheckBox->setChecked(instrument->sendsProgramChange());
|
|
m_bankCheckBox->setChecked(instrument->sendsBankSelect());
|
|
m_variationCheckBox->setChecked(instrument->sendsBankSelect());
|
|
|
|
// Basic parameters
|
|
//
|
|
m_channelValue->setCurrentItem((int)instrument->getMidiChannel());
|
|
|
|
// Check for program change
|
|
//
|
|
populateBankList();
|
|
populateProgramList();
|
|
populateVariationList();
|
|
|
|
// Setup the ControlParameters
|
|
//
|
|
setupControllers(md);
|
|
|
|
// Set all the positions by controller number
|
|
//
|
|
for (RotaryMap::iterator it = m_rotaries.begin() ;
|
|
it != m_rotaries.end(); ++it) {
|
|
MidiByte value = 0;
|
|
|
|
// Special cases
|
|
//
|
|
if (it->first == MIDI_CONTROLLER_PAN)
|
|
value = int(instrument->getPan());
|
|
else if (it->first == MIDI_CONTROLLER_VOLUME)
|
|
value = int(instrument->getVolume());
|
|
else {
|
|
try {
|
|
value = instrument->getControllerValue(
|
|
MidiByte(it->first));
|
|
} catch (...) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
setRotaryToValue(it->first, int(value));
|
|
}
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::setupControllers(MidiDevice *md)
|
|
{
|
|
if (!m_rotaryFrame) {
|
|
m_rotaryFrame = new TQFrame(this);
|
|
m_mainGrid->addMultiCellWidget(m_rotaryFrame, 8, 8, 0, 2, TQt::AlignHCenter);
|
|
m_rotaryGrid = new TQGridLayout(m_rotaryFrame, 10, 3, 8, 1);
|
|
m_rotaryGrid->addItem(new TQSpacerItem(10, 4), 0, 1);
|
|
}
|
|
|
|
// To cut down on flicker, we avoid destroying and recreating
|
|
// widgets as far as possible here. If a label already exists,
|
|
// we just set its text; if a rotary exists, we only replace it
|
|
// if we actually need a different one.
|
|
|
|
Composition &comp = m_doc->getComposition();
|
|
ControlList list = md->getControlParameters();
|
|
|
|
// sort by IPB position
|
|
//
|
|
std::sort(list.begin(), list.end(),
|
|
ControlParameter::ControlPositionCmp());
|
|
|
|
int count = 0;
|
|
RotaryMap::iterator rmi = m_rotaries.begin();
|
|
|
|
for (ControlList::iterator it = list.begin();
|
|
it != list.end(); ++it) {
|
|
if (it->getIPBPosition() == -1)
|
|
continue;
|
|
|
|
// Get the knob colour - only if the colour is non-default (>0)
|
|
//
|
|
TQColor knobColour = TQt::black; // special case for Rotary
|
|
if (it->getColourIndex() > 0) {
|
|
Colour c =
|
|
comp.getGeneralColourMap().getColourByIndex
|
|
(it->getColourIndex());
|
|
knobColour = TQColor(c.getRed(), c.getGreen(), c.getBlue());
|
|
}
|
|
|
|
Rotary *rotary = 0;
|
|
|
|
if (rmi != m_rotaries.end()) {
|
|
|
|
// Update the controller number that is associated with the
|
|
// existing rotary widget.
|
|
|
|
rmi->first = it->getControllerValue();
|
|
|
|
// Update the properties of the existing rotary widget.
|
|
|
|
rotary = rmi->second.first;
|
|
int redraw = 0; // 1 -> position, 2 -> all
|
|
|
|
if (rotary->getMinValue() != it->getMin()) {
|
|
rotary->setMinValue(it->getMin());
|
|
redraw = 1;
|
|
}
|
|
if (rotary->getMaxValue() != it->getMax()) {
|
|
rotary->setMaxValue(it->getMax());
|
|
redraw = 1;
|
|
}
|
|
if (rotary->getKnobColour() != knobColour) {
|
|
rotary->setKnobColour(knobColour);
|
|
redraw = 2;
|
|
}
|
|
if (redraw == 1 || rotary->getPosition() != it->getDefault()) {
|
|
rotary->setPosition(it->getDefault());
|
|
if (redraw == 1)
|
|
redraw = 0;
|
|
}
|
|
if (redraw == 2) {
|
|
rotary->tqrepaint();
|
|
}
|
|
|
|
// Update the controller name that is associated with
|
|
// with the existing rotary widget.
|
|
|
|
TQLabel *label = rmi->second.second;
|
|
label->setText(strtoqstr(it->getName()));
|
|
|
|
++rmi;
|
|
|
|
} else {
|
|
|
|
TQHBox *hbox = new TQHBox(m_rotaryFrame);
|
|
hbox->setSpacing(8);
|
|
|
|
float smallStep = 1.0;
|
|
|
|
float bigStep = 5.0;
|
|
if (it->getMax() - it->getMin() < 10)
|
|
bigStep = 1.0;
|
|
else if (it->getMax() - it->getMin() < 20)
|
|
bigStep = 2.0;
|
|
|
|
rotary = new Rotary
|
|
(hbox,
|
|
it->getMin(),
|
|
it->getMax(),
|
|
smallStep,
|
|
bigStep,
|
|
it->getDefault(),
|
|
20,
|
|
Rotary::NoTicks,
|
|
false,
|
|
it->getDefault() == 64); //!!! hacky
|
|
|
|
rotary->setKnobColour(knobColour);
|
|
|
|
// Add a label
|
|
TQLabel *label = new KSqueezedTextLabel(strtoqstr(it->getName()), hbox);
|
|
|
|
RG_DEBUG << "Adding new widget at " << (count / 2) << "," << (count % 2) << endl;
|
|
|
|
// Add the compound widget
|
|
//
|
|
m_rotaryGrid->addWidget(hbox, count / 2, (count % 2) * 2, AlignLeft);
|
|
hbox->show();
|
|
|
|
// Add to list
|
|
//
|
|
m_rotaries.push_back(std::pair<int, RotaryPair>
|
|
(it->getControllerValue(),
|
|
RotaryPair(rotary, label)));
|
|
|
|
// Connect
|
|
//
|
|
connect(rotary, TQT_SIGNAL(valueChanged(float)),
|
|
m_rotaryMapper, TQT_SLOT(map()));
|
|
|
|
rmi = m_rotaries.end();
|
|
}
|
|
|
|
// Add signal mapping
|
|
//
|
|
m_rotaryMapper->setMapping(TQT_TQOBJECT(rotary),
|
|
int(it->getControllerValue()));
|
|
|
|
count++;
|
|
}
|
|
|
|
if (rmi != m_rotaries.end()) {
|
|
for (RotaryMap::iterator rmj = rmi; rmj != m_rotaries.end(); ++rmj) {
|
|
delete rmj->second.first;
|
|
delete rmj->second.second;
|
|
}
|
|
m_rotaries = std::vector<std::pair<int, RotaryPair> >
|
|
(m_rotaries.begin(), rmi);
|
|
}
|
|
|
|
m_rotaryFrame->show();
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::setRotaryToValue(int controller, int value)
|
|
{
|
|
/*
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::setRotaryToValue - "
|
|
<< "controller = " << controller
|
|
<< ", value = " << value << std::endl;
|
|
*/
|
|
|
|
for (RotaryMap::iterator it = m_rotaries.begin() ; it != m_rotaries.end(); ++it) {
|
|
if (it->first == controller) {
|
|
it->second.first->setPosition(float(value));
|
|
return ;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::slotSelectChannel(int index)
|
|
{
|
|
if (m_selectedInstrument == 0)
|
|
return ;
|
|
|
|
m_selectedInstrument->setMidiChannel(index);
|
|
|
|
// don't use the emit - use this method instead
|
|
StudioControl::sendMappedInstrument(
|
|
MappedInstrument(m_selectedInstrument));
|
|
emit updateAllBoxes();
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::populateBankList()
|
|
{
|
|
if (m_selectedInstrument == 0)
|
|
return ;
|
|
|
|
m_bankValue->clear();
|
|
m_banks.clear();
|
|
|
|
MidiDevice *md = dynamic_cast<MidiDevice*>
|
|
(m_selectedInstrument->getDevice());
|
|
if (!md) {
|
|
RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::populateBankList:"
|
|
<< " No MidiDevice for Instrument "
|
|
<< m_selectedInstrument->getId() << endl;
|
|
return ;
|
|
}
|
|
|
|
int currentBank = -1;
|
|
BankList banks;
|
|
|
|
/*
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::populateBankList: "
|
|
<< "variation type is " << md->getVariationType() << endl;
|
|
*/
|
|
|
|
if (md->getVariationType() == MidiDevice::NoVariations) {
|
|
|
|
banks = md->getBanks(m_selectedInstrument->isPercussion());
|
|
|
|
if (!banks.empty()) {
|
|
if (m_bankLabel->isHidden()) {
|
|
m_bankLabel->show();
|
|
m_bankCheckBox->show();
|
|
m_bankValue->show();
|
|
}
|
|
} else {
|
|
m_bankLabel->hide();
|
|
m_bankCheckBox->hide();
|
|
m_bankValue->hide();
|
|
}
|
|
|
|
for (unsigned int i = 0; i < banks.size(); ++i) {
|
|
if (m_selectedInstrument->getProgram().getBank() == banks[i]) {
|
|
currentBank = i;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
MidiByteList bytes;
|
|
bool useMSB = (md->getVariationType() == MidiDevice::VariationFromLSB);
|
|
|
|
if (useMSB) {
|
|
bytes = md->getDistinctMSBs(m_selectedInstrument->isPercussion());
|
|
} else {
|
|
bytes = md->getDistinctLSBs(m_selectedInstrument->isPercussion());
|
|
}
|
|
|
|
if (bytes.size() < 2) {
|
|
if (!m_bankLabel->isHidden()) {
|
|
m_bankLabel->hide();
|
|
m_bankCheckBox->hide();
|
|
m_bankValue->hide();
|
|
}
|
|
} else {
|
|
if (m_bankLabel->isHidden()) {
|
|
m_bankLabel->show();
|
|
m_bankCheckBox->show();
|
|
m_bankValue->show();
|
|
}
|
|
}
|
|
|
|
if (useMSB) {
|
|
for (unsigned int i = 0; i < bytes.size(); ++i) {
|
|
BankList bl = md->getBanksByMSB
|
|
(m_selectedInstrument->isPercussion(), bytes[i]);
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::populateBankList: have " << bl.size() << " variations for msb " << bytes[i] << endl;
|
|
|
|
if (bl.size() == 0)
|
|
continue;
|
|
if (m_selectedInstrument->getMSB() == bytes[i]) {
|
|
currentBank = banks.size();
|
|
}
|
|
banks.push_back(bl[0]);
|
|
}
|
|
} else {
|
|
for (unsigned int i = 0; i < bytes.size(); ++i) {
|
|
BankList bl = md->getBanksByLSB
|
|
(m_selectedInstrument->isPercussion(), bytes[i]);
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::populateBankList: have " << bl.size() << " variations for lsb " << bytes[i] << endl;
|
|
if (bl.size() == 0)
|
|
continue;
|
|
if (m_selectedInstrument->getLSB() == bytes[i]) {
|
|
currentBank = banks.size();
|
|
}
|
|
banks.push_back(bl[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (BankList::const_iterator i = banks.begin();
|
|
i != banks.end(); ++i) {
|
|
m_banks.push_back(*i);
|
|
m_bankValue->insertItem(strtoqstr(i->getName()));
|
|
}
|
|
|
|
m_bankValue->setEnabled(m_selectedInstrument->sendsBankSelect());
|
|
|
|
if (currentBank < 0 && !banks.empty()) {
|
|
m_bankValue->setCurrentItem(0);
|
|
slotSelectBank(0);
|
|
} else {
|
|
m_bankValue->setCurrentItem(currentBank);
|
|
}
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::populateProgramList()
|
|
{
|
|
if (m_selectedInstrument == 0)
|
|
return ;
|
|
|
|
m_programValue->clear();
|
|
m_programs.clear();
|
|
|
|
MidiDevice *md = dynamic_cast<MidiDevice*>
|
|
(m_selectedInstrument->getDevice());
|
|
if (!md) {
|
|
RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::populateProgramList: No MidiDevice for Instrument "
|
|
<< m_selectedInstrument->getId() << endl;
|
|
return ;
|
|
}
|
|
|
|
/*
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::populateProgramList:"
|
|
<< " variation type is " << md->getVariationType() << endl;
|
|
*/
|
|
|
|
MidiBank bank( m_selectedInstrument->isPercussion(),
|
|
m_selectedInstrument->getMSB(),
|
|
m_selectedInstrument->getLSB());
|
|
|
|
if (m_selectedInstrument->sendsBankSelect()) {
|
|
bank = m_selectedInstrument->getProgram().getBank();
|
|
}
|
|
|
|
int currentProgram = -1;
|
|
|
|
ProgramList programs = md->getPrograms(bank);
|
|
|
|
if (!programs.empty()) {
|
|
if (m_programLabel->isHidden()) {
|
|
m_programLabel->show();
|
|
m_programCheckBox->show();
|
|
m_programValue->show();
|
|
}
|
|
} else {
|
|
m_programLabel->hide();
|
|
m_programCheckBox->hide();
|
|
m_programValue->hide();
|
|
}
|
|
|
|
for (unsigned int i = 0; i < programs.size(); ++i) {
|
|
std::string programName = programs[i].getName();
|
|
if (programName != "") {
|
|
m_programValue->insertItem(TQString("%1. %2")
|
|
.tqarg(programs[i].getProgram() + 1)
|
|
.tqarg(strtoqstr(programName)));
|
|
if (m_selectedInstrument->getProgram() == programs[i]) {
|
|
currentProgram = m_programs.size();
|
|
}
|
|
m_programs.push_back(programs[i]);
|
|
}
|
|
}
|
|
|
|
m_programValue->setEnabled(m_selectedInstrument->sendsProgramChange());
|
|
|
|
if (currentProgram < 0 && !m_programs.empty()) {
|
|
m_programValue->setCurrentItem(0);
|
|
slotSelectProgram(0);
|
|
} else {
|
|
m_programValue->setCurrentItem(currentProgram);
|
|
|
|
// Ensure that stored program change value is same as the one
|
|
// we're now showing (BUG 937371)
|
|
//
|
|
if (!m_programs.empty()) {
|
|
m_selectedInstrument->setProgramChange
|
|
((m_programs[m_programValue->currentItem()]).getProgram());
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::populateVariationList()
|
|
{
|
|
if (m_selectedInstrument == 0)
|
|
return ;
|
|
|
|
m_variationValue->clear();
|
|
m_variations.clear();
|
|
|
|
MidiDevice *md = dynamic_cast<MidiDevice*>
|
|
(m_selectedInstrument->getDevice());
|
|
if (!md) {
|
|
RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::populateVariationList: No MidiDevice for Instrument "
|
|
<< m_selectedInstrument->getId() << endl;
|
|
return ;
|
|
}
|
|
|
|
/*
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::populateVariationList:"
|
|
<< " variation type is " << md->getVariationType() << endl;
|
|
*/
|
|
|
|
if (md->getVariationType() == MidiDevice::NoVariations) {
|
|
if (!m_variationLabel->isHidden()) {
|
|
m_variationLabel->hide();
|
|
m_variationCheckBox->hide();
|
|
m_variationValue->hide();
|
|
}
|
|
return ;
|
|
}
|
|
|
|
bool useMSB = (md->getVariationType() == MidiDevice::VariationFromMSB);
|
|
MidiByteList variations;
|
|
|
|
if (useMSB) {
|
|
MidiByte lsb = m_selectedInstrument->getLSB();
|
|
variations = md->getDistinctMSBs(m_selectedInstrument->isPercussion(),
|
|
lsb);
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::populateVariationList: have " << variations.size() << " variations for lsb " << lsb << endl;
|
|
|
|
} else {
|
|
MidiByte msb = m_selectedInstrument->getMSB();
|
|
variations = md->getDistinctLSBs(m_selectedInstrument->isPercussion(),
|
|
msb);
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::populateVariationList: have " << variations.size() << " variations for msb " << msb << endl;
|
|
}
|
|
|
|
m_variationValue->setCurrentItem( -1);
|
|
|
|
MidiProgram defaultProgram;
|
|
|
|
if (useMSB) {
|
|
defaultProgram = MidiProgram
|
|
(MidiBank(m_selectedInstrument->isPercussion(),
|
|
0,
|
|
m_selectedInstrument->getLSB()),
|
|
m_selectedInstrument->getProgramChange());
|
|
} else {
|
|
defaultProgram = MidiProgram
|
|
(MidiBank(m_selectedInstrument->isPercussion(),
|
|
m_selectedInstrument->getMSB(),
|
|
0),
|
|
m_selectedInstrument->getProgramChange());
|
|
}
|
|
std::string defaultProgramName = md->getProgramName(defaultProgram);
|
|
|
|
int currentVariation = -1;
|
|
|
|
for (unsigned int i = 0; i < variations.size(); ++i) {
|
|
|
|
MidiProgram program;
|
|
|
|
if (useMSB) {
|
|
program = MidiProgram
|
|
(MidiBank(m_selectedInstrument->isPercussion(),
|
|
variations[i],
|
|
m_selectedInstrument->getLSB()),
|
|
m_selectedInstrument->getProgramChange());
|
|
} else {
|
|
program = MidiProgram
|
|
(MidiBank(m_selectedInstrument->isPercussion(),
|
|
m_selectedInstrument->getMSB(),
|
|
variations[i]),
|
|
m_selectedInstrument->getProgramChange());
|
|
}
|
|
|
|
std::string programName = md->getProgramName(program);
|
|
|
|
if (programName != "") { // yes, that is how you know whether it exists
|
|
/*
|
|
m_variationValue->insertItem(programName == defaultProgramName ?
|
|
i18n("(default)") :
|
|
strtoqstr(programName));
|
|
*/
|
|
m_variationValue->insertItem(TQString("%1. %2")
|
|
.tqarg(variations[i] + 1)
|
|
.tqarg(strtoqstr(programName)));
|
|
if (m_selectedInstrument->getProgram() == program) {
|
|
currentVariation = m_variations.size();
|
|
}
|
|
m_variations.push_back(variations[i]);
|
|
}
|
|
}
|
|
|
|
if (currentVariation < 0 && !m_variations.empty()) {
|
|
m_variationValue->setCurrentItem(0);
|
|
slotSelectVariation(0);
|
|
} else {
|
|
m_variationValue->setCurrentItem(currentVariation);
|
|
}
|
|
|
|
if (m_variations.size() < 2) {
|
|
if (!m_variationLabel->isHidden()) {
|
|
m_variationLabel->hide();
|
|
m_variationCheckBox->hide();
|
|
m_variationValue->hide();
|
|
}
|
|
|
|
} else {
|
|
//!!! seem to have problems here -- the grid tqlayout doesn't
|
|
//like us adding stuff in the middle so if we go from 1
|
|
//visible row (say program) to 2 (program + variation) the
|
|
//second one overlaps the control knobs
|
|
|
|
if (m_variationLabel->isHidden()) {
|
|
m_variationLabel->show();
|
|
m_variationCheckBox->show();
|
|
m_variationValue->show();
|
|
}
|
|
|
|
if (m_programValue->width() > m_variationValue->width()) {
|
|
m_variationValue->setMinimumWidth(m_programValue->width());
|
|
} else {
|
|
m_programValue->setMinimumWidth(m_variationValue->width());
|
|
}
|
|
}
|
|
|
|
m_variationValue->setEnabled(m_selectedInstrument->sendsBankSelect());
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::slotTogglePercussion(bool value)
|
|
{
|
|
if (m_selectedInstrument == 0) {
|
|
m_percussionCheckBox->setChecked(false);
|
|
emit updateAllBoxes();
|
|
return ;
|
|
}
|
|
|
|
m_selectedInstrument->setPercussion(value);
|
|
|
|
populateBankList();
|
|
populateProgramList();
|
|
populateVariationList();
|
|
|
|
sendBankAndProgram();
|
|
|
|
emit changeInstrumentLabel(m_selectedInstrument->getId(),
|
|
strtoqstr(m_selectedInstrument->
|
|
getProgramName()));
|
|
emit updateAllBoxes();
|
|
|
|
emit instrumentParametersChanged(m_selectedInstrument->getId());
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::slotToggleBank(bool value)
|
|
{
|
|
if (m_selectedInstrument == 0) {
|
|
m_bankCheckBox->setChecked(false);
|
|
emit updateAllBoxes();
|
|
return ;
|
|
}
|
|
|
|
m_variationCheckBox->setChecked(value);
|
|
m_selectedInstrument->setSendBankSelect(value);
|
|
|
|
m_bankValue->setDisabled(!value);
|
|
populateBankList();
|
|
populateProgramList();
|
|
populateVariationList();
|
|
|
|
sendBankAndProgram();
|
|
|
|
emit changeInstrumentLabel(m_selectedInstrument->getId(),
|
|
strtoqstr(m_selectedInstrument->
|
|
getProgramName()));
|
|
emit updateAllBoxes();
|
|
|
|
emit instrumentParametersChanged(m_selectedInstrument->getId());
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::slotToggleProgramChange(bool value)
|
|
{
|
|
if (m_selectedInstrument == 0) {
|
|
m_programCheckBox->setChecked(false);
|
|
emit updateAllBoxes();
|
|
return ;
|
|
}
|
|
|
|
m_selectedInstrument->setSendProgramChange(value);
|
|
|
|
m_programValue->setDisabled(!value);
|
|
populateProgramList();
|
|
populateVariationList();
|
|
|
|
if (value)
|
|
sendBankAndProgram();
|
|
|
|
emit changeInstrumentLabel(m_selectedInstrument->getId(),
|
|
strtoqstr(m_selectedInstrument->
|
|
getProgramName()));
|
|
emit updateAllBoxes();
|
|
|
|
emit instrumentParametersChanged(m_selectedInstrument->getId());
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::slotToggleVariation(bool value)
|
|
{
|
|
if (m_selectedInstrument == 0) {
|
|
m_variationCheckBox->setChecked(false);
|
|
emit updateAllBoxes();
|
|
return ;
|
|
}
|
|
|
|
m_bankCheckBox->setChecked(value);
|
|
m_selectedInstrument->setSendBankSelect(value);
|
|
|
|
m_variationValue->setDisabled(!value);
|
|
populateVariationList();
|
|
|
|
sendBankAndProgram();
|
|
|
|
emit changeInstrumentLabel(m_selectedInstrument->getId(),
|
|
strtoqstr(m_selectedInstrument->
|
|
getProgramName()));
|
|
emit updateAllBoxes();
|
|
|
|
emit instrumentParametersChanged(m_selectedInstrument->getId());
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::slotSelectBank(int index)
|
|
{
|
|
if (m_selectedInstrument == 0)
|
|
return ;
|
|
|
|
MidiDevice *md = dynamic_cast<MidiDevice*>
|
|
(m_selectedInstrument->getDevice());
|
|
if (!md) {
|
|
RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::slotSelectBank: No MidiDevice for Instrument "
|
|
<< m_selectedInstrument->getId() << endl;
|
|
return ;
|
|
}
|
|
|
|
const MidiBank *bank = &m_banks[index];
|
|
|
|
bool change = false;
|
|
|
|
if (md->getVariationType() != MidiDevice::VariationFromLSB) {
|
|
if (m_selectedInstrument->getLSB() != bank->getLSB()) {
|
|
m_selectedInstrument->setLSB(bank->getLSB());
|
|
change = true;
|
|
}
|
|
}
|
|
if (md->getVariationType() != MidiDevice::VariationFromMSB) {
|
|
if (m_selectedInstrument->getMSB() != bank->getMSB()) {
|
|
m_selectedInstrument->setMSB(bank->getMSB());
|
|
change = true;
|
|
}
|
|
}
|
|
|
|
populateProgramList();
|
|
|
|
if (change) {
|
|
sendBankAndProgram();
|
|
emit updateAllBoxes();
|
|
}
|
|
|
|
emit instrumentParametersChanged(m_selectedInstrument->getId());
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::slotSelectProgram(int index)
|
|
{
|
|
const MidiProgram *prg = &m_programs[index];
|
|
if (prg == 0) {
|
|
RG_DEBUG << "program change not found in bank" << endl;
|
|
return ;
|
|
}
|
|
|
|
bool change = false;
|
|
if (m_selectedInstrument->getProgramChange() != prg->getProgram()) {
|
|
m_selectedInstrument->setProgramChange(prg->getProgram());
|
|
change = true;
|
|
}
|
|
|
|
populateVariationList();
|
|
|
|
if (change) {
|
|
sendBankAndProgram();
|
|
emit changeInstrumentLabel(m_selectedInstrument->getId(),
|
|
strtoqstr(m_selectedInstrument->
|
|
getProgramName()));
|
|
emit updateAllBoxes();
|
|
}
|
|
|
|
emit instrumentParametersChanged(m_selectedInstrument->getId());
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::slotSelectVariation(int index)
|
|
{
|
|
MidiDevice *md = dynamic_cast<MidiDevice*>
|
|
(m_selectedInstrument->getDevice());
|
|
if (!md) {
|
|
RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::slotSelectVariation: No MidiDevice for Instrument "
|
|
<< m_selectedInstrument->getId() << endl;
|
|
return ;
|
|
}
|
|
|
|
if (index < 0 || index > int(m_variations.size())) {
|
|
RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::slotSelectVariation: index " << index << " out of range" << endl;
|
|
return ;
|
|
}
|
|
|
|
MidiByte v = m_variations[index];
|
|
|
|
bool change = false;
|
|
|
|
if (md->getVariationType() == MidiDevice::VariationFromLSB) {
|
|
if (m_selectedInstrument->getLSB() != v) {
|
|
m_selectedInstrument->setLSB(v);
|
|
change = true;
|
|
}
|
|
} else if (md->getVariationType() == MidiDevice::VariationFromMSB) {
|
|
if (m_selectedInstrument->getMSB() != v) {
|
|
m_selectedInstrument->setMSB(v);
|
|
change = true;
|
|
}
|
|
}
|
|
|
|
if (change) {
|
|
sendBankAndProgram();
|
|
}
|
|
|
|
emit instrumentParametersChanged(m_selectedInstrument->getId());
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::sendBankAndProgram()
|
|
{
|
|
if (m_selectedInstrument == 0)
|
|
return ;
|
|
|
|
MidiDevice *md = dynamic_cast<MidiDevice*>
|
|
(m_selectedInstrument->getDevice());
|
|
if (!md) {
|
|
RG_DEBUG << "WARNING: MIDIInstrumentParameterPanel::sendBankAndProgram: No MidiDevice for Instrument "
|
|
<< m_selectedInstrument->getId() << endl;
|
|
return ;
|
|
}
|
|
|
|
if (m_selectedInstrument->sendsBankSelect()) {
|
|
|
|
// Send the bank select message before any PC message
|
|
//
|
|
MappedEvent mEMSB(m_selectedInstrument->getId(),
|
|
MappedEvent::MidiController,
|
|
MIDI_CONTROLLER_BANK_MSB,
|
|
m_selectedInstrument->getMSB());
|
|
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::sendBankAndProgram - "
|
|
<< "sending MSB = "
|
|
<< int(m_selectedInstrument->getMSB())
|
|
<< endl;
|
|
|
|
StudioControl::sendMappedEvent(mEMSB);
|
|
|
|
MappedEvent mELSB(m_selectedInstrument->getId(),
|
|
MappedEvent::MidiController,
|
|
MIDI_CONTROLLER_BANK_LSB,
|
|
m_selectedInstrument->getLSB());
|
|
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::sendBankAndProgram - "
|
|
<< "sending LSB = "
|
|
<< int(m_selectedInstrument->getLSB())
|
|
<< endl;
|
|
|
|
StudioControl::sendMappedEvent(mELSB);
|
|
}
|
|
|
|
MappedEvent mE(m_selectedInstrument->getId(),
|
|
MappedEvent::MidiProgramChange,
|
|
m_selectedInstrument->getProgramChange(),
|
|
(MidiByte)0);
|
|
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::sendBankAndProgram - "
|
|
<< "sending program change = "
|
|
<< int(m_selectedInstrument->getProgramChange())
|
|
<< endl;
|
|
|
|
|
|
// Send the controller change
|
|
//
|
|
StudioControl::sendMappedEvent(mE);
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::slotControllerChanged(int controllerNumber)
|
|
{
|
|
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::slotControllerChanged - "
|
|
<< "controller = " << controllerNumber << "\n";
|
|
|
|
|
|
if (m_selectedInstrument == 0)
|
|
return ;
|
|
|
|
MidiDevice *md = dynamic_cast<MidiDevice*>
|
|
(m_selectedInstrument->getDevice());
|
|
if (!md)
|
|
return ;
|
|
|
|
/*
|
|
ControlParameter *controller =
|
|
md->getControlParameter(MidiByte(controllerNumber));
|
|
*/
|
|
|
|
int value = getValueFromRotary(controllerNumber);
|
|
|
|
if (value == -1) {
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::slotControllerChanged - "
|
|
<< "couldn't get value of rotary for controller "
|
|
<< controllerNumber << endl;
|
|
return ;
|
|
}
|
|
|
|
|
|
// two special cases
|
|
if (controllerNumber == int(MIDI_CONTROLLER_PAN)) {
|
|
float adjValue = value;
|
|
if (m_selectedInstrument->getType() == Instrument::Audio ||
|
|
m_selectedInstrument->getType() == Instrument::SoftSynth)
|
|
value += 100;
|
|
|
|
m_selectedInstrument->setPan(MidiByte(adjValue));
|
|
} else if (controllerNumber == int(MIDI_CONTROLLER_VOLUME)) {
|
|
m_selectedInstrument->setVolume(MidiByte(value));
|
|
} else // just set the controller (this will create it on the instrument if
|
|
// it doesn't exist)
|
|
{
|
|
m_selectedInstrument->setControllerValue(MidiByte(controllerNumber),
|
|
MidiByte(value));
|
|
|
|
RG_DEBUG << "SET CONTROLLER VALUE (" << controllerNumber << ") = " << value << endl;
|
|
}
|
|
/*
|
|
else
|
|
{
|
|
RG_DEBUG << "MIDIInstrumentParameterPanel::slotControllerChanged - "
|
|
<< "no controller retrieved\n";
|
|
return;
|
|
}
|
|
*/
|
|
|
|
MappedEvent mE(m_selectedInstrument->getId(),
|
|
MappedEvent::MidiController,
|
|
(MidiByte)controllerNumber,
|
|
(MidiByte)value);
|
|
StudioControl::sendMappedEvent(mE);
|
|
|
|
emit updateAllBoxes();
|
|
emit instrumentParametersChanged(m_selectedInstrument->getId());
|
|
|
|
}
|
|
|
|
int
|
|
MIDIInstrumentParameterPanel::getValueFromRotary(int rotary)
|
|
{
|
|
for (RotaryMap::iterator it = m_rotaries.begin(); it != m_rotaries.end(); ++it) {
|
|
if (it->first == rotary)
|
|
return int(it->second.first->getPosition());
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void
|
|
MIDIInstrumentParameterPanel::showAdditionalControls(bool showThem)
|
|
{
|
|
m_instrumentLabel->setShown(showThem);
|
|
int index = 0;
|
|
for (RotaryMap::iterator it = m_rotaries.begin(); it != m_rotaries.end(); ++it) {
|
|
it->second.first->parentWidget()->setShown(showThem || (index < 8));
|
|
//it->second.first->setShown(showThem || (index < 8));
|
|
//it->second.second->setShown(showThem || (index < 8));
|
|
index++;
|
|
}
|
|
}
|
|
|
|
}
|
|
#include "MIDIInstrumentParameterPanel.moc"
|