soundeditor/qatsh/ResidualsSpecgramGraphicsSc...

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);
}
}