Changeset - 6b14ef397a98
[Not reviewed]
gain-offset
0 4 0
Hasan Yavuz Ă–ZDERYA - 7 years ago 2018-07-22 08:34:09
hy@ozderya.net
some optimization for when no gain or offset is enabled
4 files changed with 81 insertions and 31 deletions:
0 comments (0 inline, 0 general)
src/channelinfomodel.cpp
Show inline comments
 
@@ -59,36 +59,51 @@ const QColor colors[NUMOF_COLORS] =
 
};
 

	
 
ChannelInfoModel::ChannelInfoModel(unsigned numberOfChannels, QObject* parent) :
 
    QAbstractTableModel(parent)
 
{
 
    _numOfChannels = 0;
 
    setNumOfChannels(numberOfChannels);
 
}
 

	
 
ChannelInfoModel::ChannelInfoModel(const ChannelInfoModel& other) :
 
    ChannelInfoModel(other.rowCount(), other.parent())
 
{
 
    // TODO: why not set (copy) info list directly instead?
 
    for (int i = 0; i < other.rowCount(); i++)
 
    {
 
        setData(index(i, COLUMN_NAME),
 
                other.data(other.index(i, COLUMN_NAME), Qt::EditRole),
 
                Qt::EditRole);
 
        setData(index(i, COLUMN_NAME),
 
                other.data(other.index(i, COLUMN_NAME), Qt::ForegroundRole),
 
                Qt::ForegroundRole);
 

	
 
        setData(index(i, COLUMN_VISIBILITY),
 
                other.data(other.index(i, COLUMN_VISIBILITY), Qt::CheckStateRole),
 
                Qt::CheckStateRole);
 
        // TODO: gain and offset
 

	
 
        setData(index(i, COLUMN_GAIN),
 
                other.data(other.index(i, COLUMN_GAIN), Qt::CheckStateRole),
 
                Qt::CheckStateRole);
 
        setData(index(i, COLUMN_GAIN),
 
                other.data(other.index(i, COLUMN_GAIN), Qt::EditRole),
 
                Qt::EditRole);
 

	
 
        setData(index(i, COLUMN_OFFSET),
 
                other.data(other.index(i, COLUMN_OFFSET), Qt::CheckStateRole),
 
                Qt::CheckStateRole);
 
        setData(index(i, COLUMN_OFFSET),
 
                other.data(other.index(i, COLUMN_OFFSET), Qt::EditRole),
 
                Qt::EditRole);
 
    }
 
}
 

	
 
ChannelInfoModel::ChannelInfoModel(const QStringList& channelNames) :
 
    ChannelInfoModel(channelNames.length(), NULL)
 
{
 
    for (int i = 0; i < channelNames.length(); i++)
 
    {
 
        setData(index(i, COLUMN_NAME), channelNames[i], Qt::EditRole);
 
    }
 
}
 

	
 
@@ -279,78 +294,79 @@ bool ChannelInfoModel::setData(const QMo
 

	
 
    auto &info = infos[index.row()];
 

	
 
    // set color
 
    if (role == Qt::ForegroundRole)
 
    {
 
        info.color = value.value<QColor>();
 
        emit dataChanged(index, index, QVector<int>({Qt::ForegroundRole}));
 
        return true;
 
    }
 

	
 
    // set name
 
    bool r = false;
 
    if (index.column() == COLUMN_NAME)
 
    {
 
        if (role == Qt::DisplayRole || role == Qt::EditRole)
 
        {
 
            info.name = value.toString();
 
            emit dataChanged(index, index, QVector<int>({role}));
 
            return true;
 
            r = true;
 
        }
 
    } // set visibility
 
    else if (index.column() == COLUMN_VISIBILITY)
 
    {
 
        if (role == Qt::CheckStateRole)
 
        {
 
            bool checked = value.toInt() == Qt::Checked;
 
            info.visibility = checked;
 
            emit dataChanged(index, index, QVector<int>({role}));
 
            return true;
 
            r = true;
 
        }
 
    }
 
    else if (index.column() == COLUMN_GAIN)
 
    {
 
        if (role == Qt::DisplayRole || role == Qt::EditRole)
 
        {
 
            info.gain = value.toDouble();
 
            emit dataChanged(index, index, QVector<int>({role}));
 
            return true;
 
            r = true;
 
        }
 
        else if (role == Qt::CheckStateRole)
 
        {
 
            bool checked = value.toInt() == Qt::Checked;
 
            info.gainEn = checked;
 
            emit dataChanged(index, index, QVector<int>({role}));
 
            return true;
 
            if (_gainOrOffsetEn != checked) updateGainOrOffsetEn();
 
            r = true;
 
        }
 
    }
 
    else if (index.column() == COLUMN_OFFSET)
 
    {
 
        if (role == Qt::DisplayRole || role == Qt::EditRole)
 
        {
 
            info.offset = value.toDouble();
 
            emit dataChanged(index, index, QVector<int>({role}));
 
            return true;
 
            r = true;
 
        }
 
        else if (role == Qt::CheckStateRole)
 
        {
 
            bool checked = value.toInt() == Qt::Checked;
 
            info.offsetEn = checked;
 
            emit dataChanged(index, index, QVector<int>({role}));
 
            return true;
 
            if (_gainOrOffsetEn != checked) updateGainOrOffsetEn();
 
            r = true;
 
        }
 
    }
 

	
 
    // invalid index/role
 
    return false;
 
    if (r)
 
    {
 
        emit dataChanged(index, index, QVector<int>({role}));
 
    }
 

	
 
    return r;
 
}
 

	
 
void ChannelInfoModel::setNumOfChannels(unsigned number)
 
{
 
    if (number == _numOfChannels) return;
 

	
 
    bool isInserting = number > _numOfChannels;
 
    if (isInserting)
 
    {
 
        beginInsertRows(QModelIndex(), _numOfChannels, number-1);
 
    }
 
    else
 
@@ -371,24 +387,25 @@ void ChannelInfoModel::setNumOfChannels(
 
    // make sure newly available channels are visible, we don't
 
    // remember visibility option intentionally so that user doesn't
 
    // get confused
 
    if (number > _numOfChannels)
 
    {
 
        for (unsigned ci = _numOfChannels; ci < number; ci++)
 
        {
 
            infos[ci].visibility = true;
 
        }
 
    }
 

	
 
    _numOfChannels = number;
 
    updateGainOrOffsetEn();
 

	
 
    if (isInserting)
 
    {
 
        endInsertRows();
 
    }
 
    else
 
    {
 
        endRemoveRows();
 
    }
 
}
 

	
 
void ChannelInfoModel::resetInfos()
 
@@ -398,24 +415,25 @@ void ChannelInfoModel::resetInfos()
 
    {
 
        infos[ci] = ChannelInfo(ci);
 
    }
 
    endResetModel();
 
}
 

	
 
// TODO: fix repetitive code, ChannelInfoModel::reset* functions
 
void ChannelInfoModel::resetNames()
 
{
 
    beginResetModel();
 
    for (unsigned ci = 0; (int) ci < infos.length(); ci++)
 
    {
 
        // TODO: do not create a full object every time (applies to other reset methods as well)
 
        infos[ci].name = ChannelInfo(ci).name;
 
    }
 
    endResetModel();
 
}
 

	
 
void ChannelInfoModel::resetColors()
 
{
 
    beginResetModel();
 
    for (unsigned ci = 0; (int) ci < infos.length(); ci++)
 
    {
 
        infos[ci].color = ChannelInfo(ci).color;
 
    }
 
@@ -431,38 +449,55 @@ void ChannelInfoModel::resetVisibility(b
 
    }
 
    endResetModel();
 
}
 

	
 
void ChannelInfoModel::resetGains()
 
{
 
    beginResetModel();
 
    for (unsigned ci = 0; (int) ci < infos.length(); ci++)
 
    {
 
        infos[ci].gain = ChannelInfo(ci).gain;
 
        infos[ci].gainEn = ChannelInfo(ci).gainEn;
 
    }
 
    updateGainOrOffsetEn();
 
    endResetModel();
 
}
 

	
 
void ChannelInfoModel::resetOffsets()
 
{
 
    beginResetModel();
 
    for (unsigned ci = 0; (int) ci < infos.length(); ci++)
 
    {
 
        infos[ci].offset = ChannelInfo(ci).offset;
 
        infos[ci].offsetEn = ChannelInfo(ci).offsetEn;
 
    }
 
    updateGainOrOffsetEn();
 
    endResetModel();
 
}
 

	
 
bool ChannelInfoModel::gainOrOffsetEn() const
 
{
 
    return _gainOrOffsetEn;
 
}
 

	
 
void ChannelInfoModel::updateGainOrOffsetEn()
 
{
 
    _gainOrOffsetEn = false;
 
    for (int ci = 0; ci < _numOfChannels; ci++)
 
    {
 
        auto& info = infos[ci];
 
        _gainOrOffsetEn |= (info.gainEn || info.offsetEn);
 
    }
 
}
 

	
 
void ChannelInfoModel::saveSettings(QSettings* settings) const
 
{
 
    settings->beginGroup(SettingGroup_Channels);
 
    settings->beginWriteArray(SG_Channels_Channel);
 

	
 
    // save all channel information regardless of current number of channels
 
    for (unsigned ci = 0; (int) ci < infos.length(); ci++)
 
    {
 
        settings->setArrayIndex(ci);
 
        auto& info = infos[ci];
 
        settings->setValue(SG_Channels_Name, info.name);
 
        settings->setValue(SG_Channels_Color, info.color);
 
@@ -503,15 +538,17 @@ void ChannelInfoModel::loadSettings(QSet
 
            {
 
                auto roles = QVector<int>({
 
                    Qt::DisplayRole, Qt::EditRole, Qt::ForegroundRole, Qt::CheckStateRole});
 
                emit dataChanged(index(ci, 0), index(ci, COLUMN_COUNT-1), roles);
 
            }
 
        }
 
        else
 
        {
 
            infos.append(chanInfo);
 
        }
 
    }
 

	
 
    updateGainOrOffsetEn();
 

	
 
    settings->endArray();
 
    settings->endGroup();
 
}
src/channelinfomodel.h
Show inline comments
 
@@ -41,24 +41,26 @@ public:
 

	
 
    explicit ChannelInfoModel(unsigned numberOfChannels, QObject *parent = 0);
 
    ChannelInfoModel(const ChannelInfoModel& other);
 
    explicit ChannelInfoModel(const QStringList& channelNames);
 

	
 
    QString name     (unsigned i) const;
 
    QColor  color    (unsigned i) const;
 
    bool    isVisible(unsigned i) const;
 
    bool    gainEn   (unsigned i) const;
 
    double  gain     (unsigned i) const;
 
    bool    offsetEn (unsigned i) const;
 
    double  offset   (unsigned i) const;
 
    /// Returns true if any of the channels have gain or offset enabled
 
    bool gainOrOffsetEn() const;
 
    /// Returns a list of channel names
 
    QStringList channelNames() const;
 

	
 
    // implemented from QAbstractItemModel
 
    int           rowCount(const QModelIndex &parent = QModelIndex()) const;
 
    int           columnCount(const QModelIndex &parent = QModelIndex()) const;
 
    QVariant      data(const QModelIndex &index, int role = Qt::DisplayRole) const;
 
    bool          setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
 
    Qt::ItemFlags flags(const QModelIndex &index) const;
 
    QVariant      headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
 

	
 
    void setNumOfChannels(unsigned number);
 
@@ -91,15 +93,25 @@ private:
 
        QColor color;
 
        double gain, offset;
 
        bool gainEn, offsetEn;
 
    };
 

	
 
    unsigned _numOfChannels;     ///< @note this is not necessarily the length of `infos`
 

	
 
    /**
 
     * Channel info is added here but never removed so that we can
 
     * remember user entered info (names, colors etc.).
 
     */
 
    QList<ChannelInfo> infos;
 

	
 
    /**
 
     * Cache for gain and offset enabled variables of channels. If gain and/or
 
     * offset is not enabled for *any* of the channels this is false otherwise
 
     * true.
 
     */
 
    bool _gainOrOffsetEn;
 

	
 
    /// Updates `_gainOrOffsetEn` by scanning all channel infos.
 
    void updateGainOrOffsetEn();
 
};
 

	
 
#endif // CHANNELINFOMODEL_H
src/stream.cpp
Show inline comments
 
@@ -135,41 +135,40 @@ void Stream::setNumChannels(unsigned nc,
 
    if (nc != oldNum)
 
    {
 
        _infoModel.setNumOfChannels(nc);
 
        // TODO: how about X change?
 
        emit numChannelsChanged(nc);
 
    }
 

	
 
    Sink::setNumChannels(nc, x);
 
}
 

	
 
const SamplePack* Stream::applyGainOffset(const SamplePack& pack) const
 
{
 
    SamplePack* mPack = nullptr;
 
    Q_ASSERT(infoModel()->gainOrOffsetEn());
 

	
 
    SamplePack* mPack = new SamplePack(pack);
 
    unsigned ns = pack.numSamples();
 

	
 
    for (unsigned ci = 0; ci < numChannels(); ci++)
 
    {
 
        bool gainEn = channels[ci]->info()->gainEn(ci);
 
        bool offsetEn = channels[ci]->info()->offsetEn(ci);
 
        double* mdata;
 
        // TODO: we could use some kind of map (int32, int64 would suffice) to speed things up
 
        bool gainEn = infoModel()->gainEn(ci);
 
        bool offsetEn = infoModel()->offsetEn(ci);
 
        if (gainEn || offsetEn)
 
        {
 
            if (mPack == nullptr)
 
                mPack = new SamplePack(pack);
 
            double* mdata = mPack->data(ci);
 

	
 
            mdata = mPack->data(ci);
 

	
 
            double gain = channels[ci]->info()->gain(ci);
 
            double offset = channels[ci]->info()->offset(ci);
 
            double gain = infoModel()->gain(ci);
 
            double offset = infoModel()->offset(ci);
 

	
 
            if (gainEn)
 
            {
 
                for (unsigned i = 0; i < ns; i++)
 
                {
 
                    mdata[i] *= gain;
 
                }
 
            }
 
            if (offsetEn)
 
            {
 
                for (unsigned i = 0; i < ns; i++)
 
                {
 
@@ -187,25 +186,27 @@ void Stream::feedIn(const SamplePack& pa
 
    Q_ASSERT(pack.numChannels() == numChannels() &&
 
             pack.hasX() == hasX());
 

	
 
    if (_paused) return;
 

	
 
    unsigned ns = pack.numSamples();
 
    if (_hasx)
 
    {
 
        static_cast<RingBuffer*>(xData)->addSamples(pack.xData(), ns);
 
    }
 

	
 
    // modified pack that gain and offset is applied to
 
    const SamplePack* mPack = applyGainOffset(pack);
 
    const SamplePack* mPack = nullptr;
 
    if (infoModel()->gainOrOffsetEn())
 
        mPack = applyGainOffset(pack);
 

	
 
    for (unsigned ci = 0; ci < numChannels(); ci++)
 
    {
 
        auto buf = static_cast<RingBuffer*>(channels[ci]->yData());
 
        double* data = (mPack == nullptr) ? pack.data(ci) : mPack->data(ci);
 
        buf->addSamples(data, ns);
 
    }
 

	
 
    Sink::feedIn((mPack == nullptr) ? pack : *mPack);
 

	
 
    if (mPack != nullptr) delete mPack;
 
    emit dataAdded();
src/stream.h
Show inline comments
 
@@ -93,25 +93,25 @@ private:
 
    unsigned _numSamples;
 
    bool _paused;
 

	
 
    bool _hasx;
 
    ResizableBuffer* xData;
 
    QList<StreamChannel*> channels;
 

	
 
    ChannelInfoModel _infoModel;
 

	
 
    /**
 
     * Applies gain and offset to given pack.
 
     *
 
     * If gain or offset isn't enabled this function returns `nullptr`. If gain
 
     * or offset is enabled for at least 1 channel input pack is copied and
 
     * modified. Result is returned. Caller is responsible for deleting
 
     * returned `SamplePack`.
 
     * Caller is responsible for deleting returned `SamplePack`.
 
     *
 
     * @note Should be called only when gain or offset is enabled. Guard with
 
     * `ChannelInfoModel::gainOrOffsetEn()`.
 
     *
 
     * @param pack input data
 
     * @return `nullptr` if no gain or offset is enabled otherwise modified data
 
     * @return modified data
 
     */
 
    const SamplePack* applyGainOffset(const SamplePack& pack) const;
 
};
 

	
 

	
 
#endif // STREAM_H
0 comments (0 inline, 0 general)