247 lines
8.6 KiB
C++
247 lines
8.6 KiB
C++
// ResidualsSpecgramGraphicsScene class implementation
|
|
//
|
|
// The QGraphicsScene-derived residual bands spectrogram scene
|
|
//
|
|
// QATSH Copyright 2009 Jean-Philippe MEURET <jpmeuret@free.fr>
|
|
|
|
#include <iostream>
|
|
|
|
#include <QObject>
|
|
#include <QList>
|
|
#include <QRectF>
|
|
#include <QModelIndex>
|
|
|
|
#include <QPen>
|
|
#include <QGraphicsView>
|
|
#include <QGraphicsRectItem>
|
|
#include <QGraphicsItemGroup>
|
|
|
|
#include "ATSMath.h"
|
|
|
|
#include "ResidualsSpecgramGraphicsScene.h"
|
|
|
|
#include "ATSModelManager.h"
|
|
#include "ATSModel.h"
|
|
#include "ATSModelItems.h"
|
|
#include "ATSPropertiesProxyModel.h"
|
|
#include "ATSResidualsProxyModel.h"
|
|
|
|
|
|
ResidualsSpecgramGraphicsScene::ResidualsSpecgramGraphicsScene(QObject *parent)
|
|
: QGraphicsScene(parent), _pModelMgr(0)
|
|
{
|
|
}
|
|
|
|
ResidualsSpecgramGraphicsScene::~ResidualsSpecgramGraphicsScene()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
void ResidualsSpecgramGraphicsScene::setModelManager(ATSModelManager* pModelMgr)
|
|
{
|
|
// Save pointer to model for later.
|
|
_pModelMgr = pModelMgr;
|
|
|
|
// Connect to any model change.
|
|
if (_pModelMgr)
|
|
{
|
|
connect(_pModelMgr->residualsModel(), SIGNAL(modelReset()), this, SLOT(onModelReset()));
|
|
connect(_pModelMgr->residualsModel(),
|
|
SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
|
this, SLOT(onDataChanged(const QModelIndex&, const QModelIndex&)));
|
|
}
|
|
|
|
// Load scene from model : create graphic items from partials data
|
|
loadFromModel();
|
|
}
|
|
|
|
void ResidualsSpecgramGraphicsScene::onModelReset()
|
|
{
|
|
std::cout << "ResidualsSpecgramGraphicsScene::onModelReset()" << std::endl;
|
|
|
|
clear();
|
|
|
|
loadFromModel();
|
|
}
|
|
|
|
void ResidualsSpecgramGraphicsScene::onDataChanged(const QModelIndex& qmiTopLeft,
|
|
const QModelIndex& qmiBotRight)
|
|
{
|
|
// TODO : Check really changed rect if usefull here ...
|
|
|
|
// TODO : Update item properties (and add/remove items ?)
|
|
std::cout << "ResidualsSpecgramGraphicsScene::onDataChanged : Not yet implemented" << std::endl;
|
|
}
|
|
|
|
// Set amplitude color contrast in [0, 1]
|
|
void ResidualsSpecgramGraphicsScene::setAmplitudeContrast(double dContrast)
|
|
{
|
|
//std::cout << "ResidualsSpecgramGraphicsScene::setAmplitudeContrast("
|
|
// << dContrast << ")" << std::endl;
|
|
|
|
clear();
|
|
|
|
_cmAmplColorMap.setContrast(dContrast);
|
|
|
|
loadResidual();
|
|
|
|
emit colorMapChanged(&_cmAmplColorMap);
|
|
}
|
|
|
|
// Set amplitude color brightness in [0, 1]
|
|
void ResidualsSpecgramGraphicsScene::setAmplitudeBrightness(double dBrightness)
|
|
{
|
|
//std::cout << "ResidualsSpecgramGraphicsScene::setAmplitudeBrightness("
|
|
// << dBrightness << ")" << std::endl;
|
|
|
|
clear();
|
|
|
|
_cmAmplColorMap.setBrightness(dBrightness);
|
|
|
|
loadResidual();
|
|
|
|
emit colorMapChanged(&_cmAmplColorMap);
|
|
}
|
|
|
|
void ResidualsSpecgramGraphicsScene::loadFromModel()
|
|
{
|
|
ATSPropertiesProxyModel* pPropsModel = _pModelMgr->propertiesModel();
|
|
|
|
// Initialize scene rect from model
|
|
// (x = time from 0 to sound.duration, y = frequency from 0 to sound.residualBandsMaxFreq).
|
|
const QModelIndex miDuration =
|
|
pPropsModel->index(0, ATSFilePropertiesItem::eSoundPropDuration, QModelIndex());
|
|
const double dMaxTime = pPropsModel->data(miDuration, Qt::DisplayRole).toDouble();
|
|
const double dMinTime = 0.0;
|
|
|
|
const QModelIndex miMaxFreq =
|
|
pPropsModel->index(0, ATSFilePropertiesItem::eSoundPropMaxResidualFrequency, QModelIndex());
|
|
const double dMaxFreq = pPropsModel->data(miMaxFreq, Qt::DisplayRole).toDouble();
|
|
const double dMinFreq = 0.0;
|
|
|
|
setSceneRect(dMinTime, dMinFreq, dMaxTime - dMinTime, dMaxFreq - dMinFreq);
|
|
|
|
// std::cout << "ResidualsSpecgramGraphicsScene::loadFromModel : "
|
|
// << "duration = " << dMaxTime
|
|
// << ", max. freq. = " << dMaxFreq << std::endl;
|
|
|
|
// Reset amplitude color map.
|
|
const QModelIndex miMaxAmpl =
|
|
pPropsModel->index(0, ATSFilePropertiesItem::eSoundPropMaxResidualEnergy, QModelIndex());
|
|
const double dMinAmpl = 0.0;
|
|
const double dMaxAmpl = pPropsModel->data(miMaxAmpl, Qt::DisplayRole).toDouble();
|
|
_cmAmplColorMap.reset(ColorMap::eStyleStandard, 256, dMinAmpl, dMaxAmpl);
|
|
|
|
emit colorMapChanged(&_cmAmplColorMap);
|
|
|
|
// Reset time ruler spec.
|
|
const double dTimeRulerBaseStep = pow(10.0, floor(log10(dMaxTime - dMinTime)));
|
|
_rsTimeRulerSpec.reset(RulerSpec::eHorizontal, RulerSpec::ePositive, RulerSpec::ePositiveSide,
|
|
dMinTime, dMaxTime, 0.0, dTimeRulerBaseStep, 10.0,
|
|
QList<double>() << 2 << 5, QList<double>() << 0.6 << 0.3);
|
|
|
|
emit timeRangeChanged(&_rsTimeRulerSpec);
|
|
|
|
// Reset frequency ruler spec.
|
|
const double dFreqRulerBaseStep = pow(10.0, floor(log10(dMaxFreq - dMinFreq)));
|
|
_rsFreqRulerSpec.reset(RulerSpec::eVertical, RulerSpec::ePositive, RulerSpec::ePositiveSide,
|
|
dMinFreq, dMaxFreq, 0.0, dFreqRulerBaseStep, 10.0,
|
|
QList<double>() << 2 << 5, QList<double>() << 0.4 << 0.2);
|
|
|
|
emit frequencyRangeChanged(&_rsFreqRulerSpec);
|
|
|
|
// Draw residual.
|
|
loadResidual();
|
|
}
|
|
|
|
void ResidualsSpecgramGraphicsScene::loadResidual()
|
|
{
|
|
ATSPropertiesProxyModel* pPropsModel = _pModelMgr->propertiesModel();
|
|
|
|
// Create items from model (1 rectangle for each frame of each band,
|
|
// 1 item group of frame rectangle items for each band).
|
|
// a) Get the number of bands.
|
|
const QModelIndex miNbBands =
|
|
pPropsModel->index(0, ATSFilePropertiesItem::eSoundPropNbResidualBands, QModelIndex());
|
|
const int nBands = pPropsModel->data(miNbBands, Qt::DisplayRole).toInt();
|
|
|
|
// b) Get the number of frames.
|
|
const QModelIndex miNbFrames =
|
|
pPropsModel->index(0, ATSFilePropertiesItem::eSoundPropNbFrames, QModelIndex());
|
|
const int nFrames = pPropsModel->data(miNbFrames, Qt::DisplayRole).toInt();
|
|
|
|
// c) Get the sampling rate.
|
|
const QModelIndex miSampRate =
|
|
pPropsModel->index(0, ATSFilePropertiesItem::eSoundPropSamplingRate, QModelIndex());
|
|
const double dSampRate = pPropsModel->data(miSampRate, Qt::DisplayRole).toDouble();
|
|
|
|
// d) Get the frame size (in samples).
|
|
const QModelIndex miFrameSize =
|
|
pPropsModel->index(0, ATSFilePropertiesItem::eSoundPropFrameSize, QModelIndex());
|
|
const int nFrameSize = pPropsModel->data(miFrameSize, Qt::DisplayRole).toInt();
|
|
|
|
// e) Compute frame duration (s).
|
|
const double dFrameDur = nFrameSize / dSampRate;
|
|
|
|
// std::cout << "ResidualsSpecgramGraphicsScene::loadFromModel : "
|
|
// << "bands = " << nBands
|
|
// << ", frames = " << nFrames
|
|
// << ", samp. rate = " << dSampRate
|
|
// << ", frame size = " << nFrameSize
|
|
// << ", frame dur. = " << dFrameDur << std::endl;
|
|
|
|
// f) For each band :
|
|
ATSResidualsProxyModel* pResidsModel = _pModelMgr->residualsModel();
|
|
for (int nBandInd = 0; nBandInd < nBands; nBandInd++)
|
|
{
|
|
// g) Get index of "residual band" model item of index "nBandInd".
|
|
const QModelIndex miBand = pResidsModel->index(0, nBandInd, QModelIndex());
|
|
|
|
//std::cout << "ResidualsSpecgramGraphicsScene::loadFromModel : "
|
|
// << "Band #" << nBandInd << " : " << std::endl;
|
|
|
|
// h) For each frame :
|
|
QGraphicsItemGroup* pgigBand = new QGraphicsItemGroup;
|
|
for (int nFrameInd = 0; nFrameInd < nFrames; nFrameInd++)
|
|
{
|
|
// i) Get band start time, min/max frequency and energy for that frame
|
|
const QModelIndex miBandFrameStartTime =
|
|
pResidsModel->index(nFrameInd, ATSResidualBandItem::ePropTime, miBand);
|
|
const double dStartTime =
|
|
pResidsModel->data(miBandFrameStartTime, Qt::DisplayRole).toDouble();
|
|
|
|
const QModelIndex miBandFrameMinFreq =
|
|
pResidsModel->index(nFrameInd, ATSResidualBandItem::ePropMinFrequency, miBand);
|
|
const double dMinFreq =
|
|
pResidsModel->data(miBandFrameMinFreq, Qt::DisplayRole).toDouble();
|
|
|
|
const QModelIndex miBandFrameMaxFreq =
|
|
pResidsModel->index(nFrameInd, ATSResidualBandItem::ePropMaxFrequency, miBand);
|
|
const double dMaxFreq =
|
|
pResidsModel->data(miBandFrameMaxFreq, Qt::DisplayRole).toDouble();
|
|
|
|
const QModelIndex miBandFrameEnergy =
|
|
pResidsModel->index(nFrameInd, ATSResidualBandItem::ePropEnergy, miBand);
|
|
const double dEnergy =
|
|
pResidsModel->data(miBandFrameEnergy, Qt::DisplayRole).toDouble();
|
|
|
|
//std::cout << " Frame #" << nFrameInd
|
|
// << " : dStartTime = " << dStartTime
|
|
// << ", minFreq = " << dMinFreq
|
|
// << ", maxFreq = " << dMaxFreq
|
|
// << ", energy = " << dEnergy << std::endl;
|
|
|
|
// j) Create a rectangle item for a constant fill color (energy),
|
|
// with the right frequency range, along the whole frame.
|
|
QGraphicsRectItem* pgilBandFrame =
|
|
new QGraphicsRectItem(0.0, 0.0, dFrameDur, dMaxFreq - dMinFreq);
|
|
pgilBandFrame->setPos(dStartTime, dMinFreq);
|
|
pgilBandFrame->setPen(Qt::NoPen);
|
|
pgilBandFrame->setBrush(QBrush(_cmAmplColorMap.color(dEnergy)));
|
|
pgigBand->addToGroup(pgilBandFrame);
|
|
}
|
|
|
|
addItem(pgigBand);
|
|
}
|
|
}
|