Chris@62: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@62: Chris@62: /* Chris@62: Sonic Visualiser Chris@62: An audio file viewer and annotation editor. Chris@62: Centre for Digital Music, Queen Mary, University of London. Chris@62: This file copyright 2006 Chris Cannam. Chris@62: Chris@62: This program is free software; you can redistribute it and/or Chris@62: modify it under the terms of the GNU General Public License as Chris@62: published by the Free Software Foundation; either version 2 of the Chris@62: License, or (at your option) any later version. See the file Chris@62: COPYING included with this distribution for more information. Chris@62: */ Chris@62: Chris@62: #include "PluginParameterDialog.h" Chris@62: Chris@62: #include "PluginParameterBox.h" Chris@140: #include "WindowTypeSelector.h" Chris@62: Chris@106: #include "vamp-sdk/Plugin.h" Chris@147: #include "vamp-sdk/PluginHostAdapter.h" Chris@106: Chris@62: #include Chris@62: #include Chris@62: #include Chris@62: #include Chris@143: #include Chris@149: #include Chris@62: #include Chris@69: #include Chris@69: #include Chris@143: #include Chris@62: Chris@71: PluginParameterDialog::PluginParameterDialog(Vamp::PluginBase *plugin, Chris@69: int sourceChannels, Chris@69: int targetChannels, Chris@69: int defaultChannel, Chris@106: QString output, Chris@140: bool showWindowSize, Chris@140: bool showFrequencyDomainOptions, Chris@62: QWidget *parent) : Chris@62: QDialog(parent), Chris@62: m_plugin(plugin), Chris@69: m_channel(defaultChannel), Chris@145: m_stepSize(0), Chris@145: m_blockSize(0), Chris@145: m_windowType(HanningWindow), Chris@62: m_parameterBox(0) Chris@62: { Chris@122: setWindowTitle(tr("Plugin Parameters")); Chris@122: Chris@62: QGridLayout *grid = new QGridLayout; Chris@62: setLayout(grid); Chris@62: Chris@62: QGroupBox *pluginBox = new QGroupBox; Chris@62: pluginBox->setTitle(tr("Plugin")); Chris@62: grid->addWidget(pluginBox, 0, 0); Chris@62: Chris@62: QGridLayout *subgrid = new QGridLayout; Chris@62: pluginBox->setLayout(subgrid); Chris@62: Chris@63: subgrid->setSpacing(0); Chris@63: subgrid->setMargin(10); Chris@63: Chris@62: QFont font(pluginBox->font()); Chris@62: font.setBold(true); Chris@62: Chris@62: QLabel *nameLabel = new QLabel(plugin->getDescription().c_str()); Chris@146: nameLabel->setWordWrap(true); Chris@62: nameLabel->setFont(font); Chris@62: Chris@62: QLabel *makerLabel = new QLabel(plugin->getMaker().c_str()); Chris@146: makerLabel->setWordWrap(true); Chris@62: Chris@106: QLabel *outputLabel = 0; Chris@106: Chris@106: if (output != "") { Chris@106: Chris@147: Vamp::PluginHostAdapter *fePlugin = dynamic_cast(m_plugin); Chris@106: Chris@106: if (fePlugin) { Chris@106: Chris@106: std::vector od = Chris@106: fePlugin->getOutputDescriptors(); Chris@106: Chris@106: if (od.size() > 1) { Chris@106: Chris@106: for (size_t i = 0; i < od.size(); ++i) { Chris@106: if (od[i].name == output.toStdString()) { Chris@106: outputLabel = new QLabel(od[i].description.c_str()); Chris@146: outputLabel->setWordWrap(true); Chris@106: break; Chris@106: } Chris@106: } Chris@106: } Chris@106: } Chris@106: } Chris@106: Chris@62: QLabel *versionLabel = new QLabel(QString("%1") Chris@62: .arg(plugin->getPluginVersion())); Chris@146: versionLabel->setWordWrap(true); Chris@62: Chris@62: QLabel *copyrightLabel = new QLabel(plugin->getCopyright().c_str()); Chris@146: copyrightLabel->setWordWrap(true); Chris@62: Chris@63: QLabel *typeLabel = new QLabel(plugin->getType().c_str()); Chris@146: typeLabel->setWordWrap(true); Chris@63: typeLabel->setFont(font); Chris@63: Chris@147: QLabel *label = new QLabel(tr("Name:")); Chris@147: label->setAlignment(Qt::AlignTop | Qt::AlignLeft); Chris@147: subgrid->addWidget(label, 0, 0); Chris@62: subgrid->addWidget(nameLabel, 0, 1); Chris@62: Chris@147: label = new QLabel(tr("Type:")); Chris@147: label->setAlignment(Qt::AlignTop | Qt::AlignLeft); Chris@147: subgrid->addWidget(label, 1, 0); Chris@63: subgrid->addWidget(typeLabel, 1, 1); Chris@62: Chris@106: int outputOffset = 0; Chris@106: if (outputLabel) { Chris@147: label = new QLabel(tr("Output:")); Chris@147: label->setAlignment(Qt::AlignTop | Qt::AlignLeft); Chris@147: subgrid->addWidget(label, 2, 0); Chris@106: subgrid->addWidget(outputLabel, 2, 1); Chris@106: outputOffset = 1; Chris@106: } Chris@62: Chris@147: label = new QLabel(tr("Maker:")); Chris@147: label->setAlignment(Qt::AlignTop | Qt::AlignLeft); Chris@147: subgrid->addWidget(label, 2 + outputOffset, 0); Chris@106: subgrid->addWidget(makerLabel, 2 + outputOffset, 1); Chris@63: Chris@147: label = new QLabel(tr("Copyright: ")); Chris@147: label->setAlignment(Qt::AlignTop | Qt::AlignLeft); Chris@147: subgrid->addWidget(label, 3 + outputOffset, 0); Chris@106: subgrid->addWidget(copyrightLabel, 3 + outputOffset, 1); Chris@106: Chris@147: label = new QLabel(tr("Version:")); Chris@147: label->setAlignment(Qt::AlignTop | Qt::AlignLeft); Chris@147: subgrid->addWidget(label, 4 + outputOffset, 0); Chris@106: subgrid->addWidget(versionLabel, 4 + outputOffset, 1); Chris@62: Chris@62: subgrid->setColumnStretch(1, 2); Chris@62: Chris@62: QGroupBox *paramBox = new QGroupBox; Chris@62: paramBox->setTitle(tr("Plugin Parameters")); Chris@62: grid->addWidget(paramBox, 1, 0); Chris@62: grid->setRowStretch(1, 10); Chris@62: Chris@62: QHBoxLayout *paramLayout = new QHBoxLayout; Chris@63: paramLayout->setMargin(0); Chris@62: paramBox->setLayout(paramLayout); Chris@62: Chris@149: QScrollArea *scroll = new QScrollArea; Chris@149: scroll->setWidgetResizable(true); Chris@149: scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); Chris@149: scroll->setFrameShape(QFrame::NoFrame); Chris@149: paramLayout->addWidget(scroll); Chris@149: Chris@62: m_parameterBox = new PluginParameterBox(m_plugin); Chris@64: connect(m_parameterBox, SIGNAL(pluginConfigurationChanged(QString)), Chris@64: this, SIGNAL(pluginConfigurationChanged(QString))); Chris@149: scroll->setWidget(m_parameterBox); Chris@62: Chris@143: m_advanced = new QFrame; Chris@143: QVBoxLayout *advancedLayout = new QVBoxLayout; Chris@143: advancedLayout->setMargin(0); Chris@143: m_advanced->setLayout(advancedLayout); Chris@143: grid->addWidget(m_advanced, 2, 0); Chris@143: Chris@143: bool haveAdvanced = false; Chris@143: Chris@69: if (sourceChannels != targetChannels) { Chris@69: Chris@69: // At the moment we can only cope with the case where Chris@69: // sourceChannels > targetChannels and targetChannels == 1 Chris@69: Chris@69: if (sourceChannels < targetChannels) { Chris@69: Chris@69: QMessageBox::warning Chris@69: (parent, Chris@69: tr("Channel mismatch"), Chris@69: tr("This plugin requires at least %1 input channels, but only %2 %3 available. The plugin probably will not work correctly.").arg(targetChannels).arg(sourceChannels).arg(sourceChannels != 1 ? tr("are") : tr("is")), Chris@69: QMessageBox::Ok, Chris@69: QMessageBox::NoButton); Chris@69: Chris@69: } else { Chris@69: Chris@69: QGroupBox *channelBox = new QGroupBox; Chris@69: channelBox->setTitle(tr("Channels")); Chris@143: advancedLayout->addWidget(channelBox); Chris@143: haveAdvanced = true; Chris@69: Chris@69: QVBoxLayout *channelLayout = new QVBoxLayout; Chris@69: channelBox->setLayout(channelLayout); Chris@69: Chris@69: if (targetChannels != 1) { Chris@69: Chris@69: channelLayout->addWidget Chris@69: (new QLabel(tr("This plugin accepts no more than %1 input channels,\nbut %2 are available. Only the first %3 will be used.\n") Chris@69: .arg(targetChannels) Chris@69: .arg(sourceChannels) Chris@69: .arg(targetChannels))); Chris@69: Chris@69: } else { Chris@69: Chris@69: channelLayout->addWidget(new QLabel(tr("This plugin only has a single channel input,\nbut the source has %1 channels.").arg(sourceChannels))); Chris@69: Chris@69: QComboBox *channelCombo = new QComboBox; Chris@76: channelCombo->addItem(tr("Use mean of source channels")); Chris@69: for (int i = 0; i < sourceChannels; ++i) { Chris@69: channelCombo->addItem(tr("Use channel %1 only").arg(i + 1)); Chris@69: } Chris@69: Chris@69: connect(channelCombo, SIGNAL(activated(int)), Chris@69: this, SLOT(channelComboChanged(int))); Chris@69: Chris@69: channelLayout->addWidget(channelCombo); Chris@69: } Chris@69: } Chris@69: } Chris@69: Chris@140: if (showWindowSize) { Chris@140: Chris@147: Vamp::PluginHostAdapter *fePlugin = dynamic_cast(m_plugin); Chris@140: int size = 1024; Chris@140: int increment = 1024; Chris@140: if (fePlugin) { Chris@140: size = fePlugin->getPreferredBlockSize(); Chris@146: std::cerr << "Feature extraction plugin \"" << fePlugin->getDescription() << "\" reports preferred block size as " << size << std::endl; Chris@140: if (size == 0) size = 1024; Chris@140: increment = fePlugin->getPreferredStepSize(); Chris@146: if (increment == 0) { Chris@146: if (fePlugin->getInputDomain() == Vamp::Plugin::TimeDomain) { Chris@146: increment = size; Chris@146: } else { Chris@146: increment = size/2; Chris@146: } Chris@146: } Chris@146: } else { Chris@147: std::cerr << "Plugin " << plugin << " is not a feature extraction plugin (it's a " << typeid(*plugin).name() << ")" << std::endl;//!!! Chris@140: } Chris@140: Chris@140: QGroupBox *windowBox = new QGroupBox; Chris@140: windowBox->setTitle(tr("Processing")); Chris@143: advancedLayout->addWidget(windowBox); Chris@143: haveAdvanced = true; Chris@140: Chris@140: QGridLayout *windowLayout = new QGridLayout; Chris@140: windowBox->setLayout(windowLayout); Chris@140: Chris@140: if (showFrequencyDomainOptions) { Chris@140: windowLayout->addWidget(new QLabel(tr("Window size:")), 0, 0); Chris@140: } else { Chris@140: windowLayout->addWidget(new QLabel(tr("Audio frames per block:")), 0, 0); Chris@140: } Chris@140: Chris@143: std::cerr << "size: " << size << ", increment: " << increment << std::endl; Chris@143: Chris@145: //!!! deal with block and step sizes (coming from the plugin's Chris@145: // preferences) that don't fit into the default list Chris@145: Chris@140: QComboBox *blockSizeCombo = new QComboBox; Chris@140: blockSizeCombo->setEditable(true); Chris@147: bool found = false; Chris@143: for (int i = 0; i < 14; ++i) { Chris@140: int val = pow(2, i + 3); Chris@140: blockSizeCombo->addItem(QString("%1").arg(val)); Chris@147: if (val == size) { Chris@147: blockSizeCombo->setCurrentIndex(i); Chris@147: found = true; Chris@147: } Chris@147: } Chris@147: if (!found) { Chris@147: blockSizeCombo->addItem(QString("%1").arg(size)); Chris@147: blockSizeCombo->setCurrentIndex(blockSizeCombo->count() - 1); Chris@140: } Chris@143: blockSizeCombo->setValidator(new QIntValidator(1, pow(2, 18), this)); Chris@146: connect(blockSizeCombo, SIGNAL(textChanged(QString)), Chris@145: this, SLOT(blockSizeComboChanged(QString))); Chris@140: windowLayout->addWidget(blockSizeCombo, 0, 1); Chris@140: Chris@148: windowLayout->addWidget(new QLabel(tr("Window increment:")), 1, 0); Chris@148: Chris@148: QComboBox *incrementCombo = new QComboBox; Chris@148: incrementCombo->setEditable(true); Chris@148: found = false; Chris@148: for (int i = 0; i < 14; ++i) { Chris@148: int val = pow(2, i + 3); Chris@148: incrementCombo->addItem(QString("%1").arg(val)); Chris@148: if (val == increment) { Chris@148: incrementCombo->setCurrentIndex(i); Chris@148: found = true; Chris@148: } Chris@148: } Chris@148: if (!found) { Chris@148: incrementCombo->addItem(QString("%1").arg(increment)); Chris@148: incrementCombo->setCurrentIndex(incrementCombo->count() - 1); Chris@148: } Chris@148: incrementCombo->setValidator(new QIntValidator(1, pow(2, 18), this)); Chris@148: connect(incrementCombo, SIGNAL(textChanged(QString)), Chris@148: this, SLOT(incrementComboChanged(QString))); Chris@148: windowLayout->addWidget(incrementCombo, 1, 1); Chris@148: Chris@140: if (showFrequencyDomainOptions) { Chris@140: Chris@140: windowLayout->addWidget(new QLabel(tr("Window shape:")), 2, 0); Chris@140: WindowTypeSelector *windowTypeSelector = new WindowTypeSelector; Chris@145: connect(windowTypeSelector, SIGNAL(windowTypeChanged(WindowType type)), Chris@145: this, SLOT(windowTypeChanged(type))); Chris@140: windowLayout->addWidget(windowTypeSelector, 2, 1); Chris@140: } Chris@140: } Chris@140: Chris@62: QHBoxLayout *hbox = new QHBoxLayout; Chris@140: grid->addLayout(hbox, 4, 0); Chris@143: Chris@143: bool advancedVisible = false; Chris@143: Chris@143: if (haveAdvanced) { Chris@143: Chris@143: m_advancedButton = new QPushButton(tr("Advanced >>")); Chris@143: m_advancedButton->setCheckable(true); Chris@143: connect(m_advancedButton, SIGNAL(clicked()), this, SLOT(advancedToggled())); Chris@143: Chris@143: QSettings settings; Chris@143: settings.beginGroup("PluginParameterDialog"); Chris@143: advancedVisible = settings.value("advancedvisible", false).toBool(); Chris@143: settings.endGroup(); Chris@143: Chris@143: m_advanced->setVisible(false); Chris@143: Chris@143: hbox->addWidget(m_advancedButton); Chris@143: } Chris@143: Chris@62: QPushButton *ok = new QPushButton(tr("OK")); Chris@62: QPushButton *cancel = new QPushButton(tr("Cancel")); Chris@62: hbox->addStretch(10); Chris@62: hbox->addWidget(ok); Chris@62: hbox->addWidget(cancel); Chris@62: connect(ok, SIGNAL(clicked()), this, SLOT(accept())); Chris@62: connect(cancel, SIGNAL(clicked()), this, SLOT(reject())); Chris@143: Chris@143: if (advancedVisible) { Chris@143: m_advancedButton->setChecked(true); Chris@143: advancedToggled(); Chris@143: } Chris@62: } Chris@62: Chris@62: PluginParameterDialog::~PluginParameterDialog() Chris@62: { Chris@62: } Chris@62: Chris@69: void Chris@145: PluginParameterDialog::getProcessingParameters(size_t &blockSize) const Chris@145: { Chris@145: blockSize = m_blockSize; Chris@145: return; Chris@145: } Chris@145: Chris@145: void Chris@145: PluginParameterDialog::getProcessingParameters(size_t &stepSize, Chris@145: size_t &blockSize, Chris@145: WindowType &windowType) const Chris@145: { Chris@145: stepSize = m_stepSize; Chris@145: blockSize = m_blockSize; Chris@145: windowType = m_windowType; Chris@146: return; Chris@145: } Chris@145: Chris@145: void Chris@145: PluginParameterDialog::blockSizeComboChanged(QString text) Chris@145: { Chris@145: m_blockSize = text.toInt(); Chris@146: std::cerr << "Block size changed to " << m_blockSize << std::endl; Chris@145: } Chris@145: Chris@145: void Chris@145: PluginParameterDialog::incrementComboChanged(QString text) Chris@145: { Chris@145: m_stepSize = text.toInt(); Chris@146: //!!! rename increment to step size throughout Chris@147: std::cerr << "Increment changed to " << m_stepSize << std::endl; Chris@145: } Chris@145: Chris@145: void Chris@145: PluginParameterDialog::windowTypeChanged(WindowType type) Chris@145: { Chris@145: m_windowType = type; Chris@145: } Chris@145: Chris@145: void Chris@143: PluginParameterDialog::advancedToggled() Chris@143: { Chris@143: bool visible = !m_advanced->isVisible(); Chris@143: Chris@143: m_advanced->setVisible(visible); Chris@143: Chris@143: if (visible) m_advancedButton->setText(tr("Advanced <<")); Chris@143: else m_advancedButton->setText(tr("Advanced >>")); Chris@143: Chris@143: QSettings settings; Chris@143: settings.beginGroup("PluginParameterDialog"); Chris@143: settings.setValue("advancedvisible", visible); Chris@143: settings.endGroup(); Chris@143: Chris@143: std::cerr << "resize to " << sizeHint().width() << " x " << sizeHint().height() << std::endl; Chris@143: Chris@149: setMinimumHeight(sizeHint().height()); Chris@149: if (visible) setMaximumHeight(sizeHint().height()); Chris@143: } Chris@143: Chris@143: void Chris@69: PluginParameterDialog::channelComboChanged(int index) Chris@69: { Chris@69: m_channel = index - 1; Chris@69: } Chris@69: