soundeditor/qatsh/DataSelectionWidget.cpp

325 lines
11 KiB
C++

// DataSelectionWidget class definition
//
// The partials / residual bands selector widget
//
// QATSH Copyright 2009 Jean-Philippe MEURET <jpmeuret@free.fr>
#include <iostream>
#include "ATSModelManager.h"
#include "ATSPartialsProxyModel.h"
#include "ATSResidualsProxyModel.h"
#include "DataSelectionWidget.h"
#include "ui_DataSelectionWidget.h"
// Note for partial amplitude-related data types (for each partial, independently) :
// * Peak=Max. amplitude = max(partial.amp(frame) for frame in [0, nFrames])
// * RMS power amplitude = sqrt(sum(partial.amp(frame)**2 for frame in [0, nFrames]) / nFrames)
// Partial are selected iif computedAmplitude >= 10**(UserThreshold_dB/20)
// Const data for available value types for each possible data types
static const int KNMaxValueTypes = 5;
static const int KNValueTypes[TypesAndConstants::eDataTypeNumber] = { 5, 4 };
static const char* KPSZValueTypeNames[TypesAndConstants::eDataTypeNumber][KNMaxValueTypes] =
{
// ePartial
{ "Maximum amplitude (raw)", "Maximum amplitude (dB)", "RMS power amplitude (dB)",
"Signal to Mask Ratio (dB)", "Frequency (Hz)" },
// eResidualBand
{ "Maximum energy (raw)", "Maximum energy (dB)", "RMS power energy (dB)",
"Frequency (Hz)", 0 }
};
enum { eMin=0, eMax, eMinMax };
static const double KDValueRanges[TypesAndConstants::eDataTypeNumber]
[KNMaxValueTypes][eMinMax] =
{
// ePartial
{ // min max
{ 0.0, 100000.0 }, // Maximum amplitude (raw)
{ -1000.0, 1000.0 }, // Maximum amplitude (dB)
{ -1000.0, 1000.0 }, // RMS power amplitude (dB)
{ -1000.0, 1000.0 }, // Signal to Mask Ratio (dB)
{ 0.0, 100000.0 } // Frequency (Hz)
},
// eResidualBand
{ // min max
{ 0.0, 100000.0 }, // Maximum energy (raw)
{ -1000.0, 1000.0 }, // Maximum energy (dB)
{ -1000.0, 1000.0 }, // RMS power energy (dB)
{ 0.0, 100000.0 }, // Frequency (Hz)
{ 0.0, 0.0 } // Not used
}
};
static const double KDValueDefaults[TypesAndConstants::eDataTypeNumber]
[KNMaxValueTypes][eMinMax] =
{
// ePartial
{ // min max
{ 0.0, 1.0 }, // Maximum amplitude (raw)
{ -30.0, 0.0 }, // Maximum amplitude (dB)
{ -30.0, 0.0 }, // RMS power amplitude (dB)
{ -30.0, 0.0 }, // Mean Signal to Mask Ratio (dB)
{ 20.0, 20000.0 } // Mean frequency (Hz)
},
// eResidualBand
{ // min max
{ 0.0, 10.0 }, // Maximum energy (raw)
{ -30.0, 0.0 }, // Maximum energy (dB)
{ -30.0, 0.0 }, // RMS power energy (dB)
{ 20.0, 20000.0 }, // Minimal frequency (Hz)
{ 0.0, 0.0 } // Not used
}
};
static const DataSelectionWidget::EValueThresholdType
KEValueThresholdTypes[TypesAndConstants::eDataTypeNumber][KNMaxValueTypes] =
{
// ePartial
{ DataSelectionWidget::ePeakAmplitude, DataSelectionWidget::eRMSPowerAmplitude,
DataSelectionWidget::eSignalToMaskRatio, DataSelectionWidget::eFrequency },
// eResidualBand
{ DataSelectionWidget::ePeakAmplitude, DataSelectionWidget::eRMSPowerAmplitude,
DataSelectionWidget::eFrequency, DataSelectionWidget::eThresholdTypeNumber }
};
// Constructor / Destructor ==========================================
DataSelectionWidget::DataSelectionWidget(QWidget *parent)
: QWidget(parent), _pui(new Ui::DataSelectionWidget), _pModelMgr(0),
_eDataType(TypesAndConstants::ePartial), _nMaxItemIndex(0)
{
_pui->setupUi(this);
// Enable control value synchronization
_bSynchronizeControls = true;
// Connect controls to local changed() slots for synchronisation
// 1) Index sliders
connect(_pui->qsdFromIndex, SIGNAL(valueChanged(int)),
this, SLOT(onFromIndexChanged(int)));
connect(_pui->qsdToIndex, SIGNAL(valueChanged(int)),
this, SLOT(onToIndexChanged(int)));
// 2) Index spin-boxes
connect(_pui->qsbFromIndex, SIGNAL(valueChanged(int)),
this, SLOT(onFromIndexChanged(int)));
connect(_pui->qsbToIndex, SIGNAL(valueChanged(int)),
this, SLOT(onToIndexChanged(int)));
// 3) Min / max value use
connect(_pui->qckMinValue, SIGNAL(stateChanged(int)),
this, SLOT(onUseMinValueChanged(int)));
connect(_pui->qckMaxValue, SIGNAL(stateChanged(int)),
this, SLOT(onUseMaxValueChanged(int)));
// 4) Value type combo-box.
connect(_pui->qcbValueType, SIGNAL(currentIndexChanged(int)),
this, SLOT(onValueTypeChanged(int)));
}
DataSelectionWidget::~DataSelectionWidget()
{
delete _pui;
}
// Model management ==================================================
void DataSelectionWidget::setModelManager(ATSModelManager* pModelMgr)
{
_pModelMgr = pModelMgr;
}
void DataSelectionWidget::resetControls()
{
_pui->qsdFromIndex->setMaximum(_nMaxItemIndex);
_pui->qsdToIndex->setMaximum(_nMaxItemIndex);
// Reset maximum value for index spin-boxes
_pui->qsbFromIndex->setMaximum(_nMaxItemIndex);
_pui->qsbToIndex->setMaximum(_nMaxItemIndex);
// Reset tick interval for sliders
_pui->qsdFromIndex->setTickInterval(_nMaxItemIndex > 3 ? (_nMaxItemIndex + 1) / 4 : 1);
_pui->qsdToIndex->setTickInterval(_nMaxItemIndex > 3 ? (_nMaxItemIndex + 1) / 4 : 1);
// Reset value type combo-box.
_pui->qcbValueType->clear();
for (int nValTypInd = 0; nValTypInd < KNValueTypes[_eDataType]; nValTypInd++)
_pui->qcbValueType->addItem(tr(KPSZValueTypeNames[_eDataType][nValTypInd]));
}
void DataSelectionWidget::switchDataType(TypesAndConstants::EDataType eDataType)
{
// Save new current data type.
_eDataType = eDataType;
// Determine new current number of data items.
switch(eDataType)
{
case TypesAndConstants::ePartial:
disconnect(_pModelMgr->residualsModel(), SIGNAL(modelReset()),
this, SLOT(onModelReset()));
connect(_pModelMgr->partialsModel(), SIGNAL(modelReset()),
this, SLOT(onModelReset()));
_nMaxItemIndex = _pModelMgr->partialsModel()->nbPartials() - 1;
break;
case TypesAndConstants::eResidualBand:
disconnect(_pModelMgr->partialsModel(), SIGNAL(modelReset()),
this, SLOT(onModelReset()));
connect(_pModelMgr->residualsModel(), SIGNAL(modelReset()),
this, SLOT(onModelReset()));
_nMaxItemIndex = _pModelMgr->residualsModel()->nbResiduals() - 1;
break;
default:
break;
}
// Reset maximum value for sliders
resetControls();
}
// State management ==================================================
DataSelectionWidget::SState DataSelectionWidget::getState() const
{
// Get state from controls
SState state;
state.nFromIndex = _pui->qsbFromIndex->value();
state.nToIndex = _pui->qsbToIndex->value();
state.nIndexStep = _pui->qsbIndexStep->value();
state.nValueTypeIndex = _pui->qcbValueType->currentIndex();
state.bUseMinValue = _pui->qckMinValue->isChecked();
state.dMinValue = _pui->qsbMinValue->value();
state.bUseMaxValue = _pui->qckMaxValue->isChecked();
state.dMaxValue = _pui->qsbMaxValue->value();
return state;
}
void DataSelectionWidget::setState(const SState& state)
{
// Check/fix/initialize the selector state as needed.
SState fixedState = state;
if (fixedState.nToIndex < 0 || fixedState.nToIndex > _nMaxItemIndex)
fixedState.nToIndex = _nMaxItemIndex;
if (fixedState.nFromIndex > fixedState.nToIndex)
fixedState.nFromIndex = fixedState.nToIndex;
// Set state to controls (auto-synchonization will do its job for the sliders).
_pui->qsbFromIndex->setValue(fixedState.nFromIndex);
_pui->qsbToIndex->setValue(fixedState.nToIndex);
_pui->qsbIndexStep->setValue(fixedState.nIndexStep);
_pui->qcbValueType->setCurrentIndex(fixedState.nValueTypeIndex);
_pui->qckMinValue->setChecked(fixedState.bUseMinValue);
_pui->qsbMinValue->setValue(fixedState.dMinValue);
_pui->qckMaxValue->setChecked(fixedState.bUseMaxValue);
_pui->qsbMaxValue->setValue(fixedState.dMaxValue);
}
// Slots to synchronize with model ====================================
void DataSelectionWidget::onModelReset()
{
// Simply re-initialize controls for the current data type.
resetControls();
}
// Slots to synchronize control values/state===========================
void DataSelectionWidget::onFromIndexChanged(int nNewIndex)
{
// Nothing to do if control synchronization is blocked.
if (!_bSynchronizeControls)
return;
// Synchronize attached controls.
_bSynchronizeControls = false;
_pui->qsbFromIndex->setValue(nNewIndex);
_pui->qsdFromIndex->setValue(nNewIndex);
_bSynchronizeControls = true;
// From can't be greater than To
if (nNewIndex > _pui->qsbToIndex->value())
_pui->qsbToIndex->setValue(nNewIndex);
// Warn everyone of the selection change.
emit dataIndexSelectionChanged(_eDataType, nNewIndex, _pui->qsbToIndex->value());
}
void DataSelectionWidget::onToIndexChanged(int nNewIndex)
{
// Nothing to do if control synchronization is blocked.
if (!_bSynchronizeControls)
return;
// Synchronize attached controls.
_bSynchronizeControls = false;
_pui->qsbToIndex->setValue(nNewIndex);
_pui->qsdToIndex->setValue(nNewIndex);
_bSynchronizeControls = true;
// To can't be lower than From
if (nNewIndex < _pui->qsbFromIndex->value())
_pui->qsbFromIndex->setValue(nNewIndex);
// Warn everyone of the selection change.
emit dataIndexSelectionChanged(_eDataType, _pui->qsbFromIndex->value(), nNewIndex);
}
void DataSelectionWidget::onUseMinValueChanged(int nNewState)
{
// Enable or disable min value spin-box
_pui->qsbMinValue->setEnabled(nNewState != Qt::Unchecked);
// Warn everyone of the selection change.
emit dataValueSelectionChanged
(_eDataType, KEValueThresholdTypes[_eDataType][_pui->qcbValueType->currentIndex()],
_pui->qckMinValue->isChecked(), _pui->qsbMinValue->value(),
_pui->qckMaxValue->isChecked(), _pui->qsbMaxValue->value());
}
void DataSelectionWidget::onUseMaxValueChanged(int nNewState)
{
// Enable or disable min value spin-box
_pui->qsbMaxValue->setEnabled(nNewState != Qt::Unchecked);
// Warn everyone of the selection change.
emit dataValueSelectionChanged
(_eDataType, KEValueThresholdTypes[_eDataType][_pui->qcbValueType->currentIndex()],
_pui->qckMinValue->isChecked(), _pui->qsbMinValue->value(),
_pui->qckMaxValue->isChecked(), _pui->qsbMaxValue->value());
}
void DataSelectionWidget::onValueTypeChanged(int nNewIndex)
{
// Reset min/max and default value for min and max values.
_pui->qsbMinValue->setMinimum(KDValueRanges[_eDataType][nNewIndex][eMin]);
_pui->qsbMinValue->setMaximum(KDValueRanges[_eDataType][nNewIndex][eMax]);
_pui->qsbMinValue->setValue(KDValueDefaults[_eDataType][nNewIndex][eMin]);
_pui->qsbMaxValue->setMinimum(KDValueRanges[_eDataType][nNewIndex][eMin]);
_pui->qsbMaxValue->setMaximum(KDValueRanges[_eDataType][nNewIndex][eMax]);
_pui->qsbMaxValue->setValue(KDValueDefaults[_eDataType][nNewIndex][eMax]);
}
// Event management ==================================================
void DataSelectionWidget::changeEvent(QEvent *e)
{
switch (e->type()) {
case QEvent::LanguageChange:
_pui->retranslateUi(this);
break;
default:
break;
}
}