view data/model/AggregateWaveModel.cpp @ 1833:21c792334c2e sensible-delimited-data-strings

Rewrite all the DelimitedDataString stuff so as to return vectors of individual cell strings rather than having the classes add the delimiters themselves. Rename accordingly to names based on StringExport. Take advantage of this in the CSV writer code so as to properly quote cells that contain delimiter characters.
author Chris Cannam
date Fri, 03 Apr 2020 17:11:05 +0100
parents dffc70996f54
children
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

/*
    Sonic Visualiser
    An audio file viewer and annotation editor.
    Centre for Digital Music, Queen Mary, University of London.
    This file copyright 2007 QMUL.
    
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.
*/

#include "AggregateWaveModel.h"

#include <iostream>

#include <QTextStream>

using namespace std;

//#define DEBUG_AGGREGATE_WAVE_FILE_MODEL 1

PowerOfSqrtTwoZoomConstraint
AggregateWaveModel::m_zoomConstraint;

AggregateWaveModel::AggregateWaveModel(ChannelSpecList channelSpecs) :
    m_components(channelSpecs)
{
    sv_samplerate_t overallRate = 0;

    for (int channel = 0; in_range_for(m_components, channel); ++channel) {

        auto model = ModelById::getAs<RangeSummarisableTimeValueModel>
            (m_components[channel].model);

        if (!model) {
            SVCERR << "AggregateWaveModel: WARNING: component for channel "
                   << channel << " is not found or is of wrong model type"
                   << endl;
            continue;
        }

        sv_samplerate_t rate = model->getSampleRate();

        if (!rate) {
            SVCERR << "AggregateWaveModel: WARNING: component for channel "
                   << channel << " reports zero sample rate" << endl;

        } else if (!overallRate) {

            overallRate = rate;

        } else if (rate != overallRate) {
            SVCERR << "AggregateWaveModel: WARNING: component for channel "
                   << channel << " has different sample rate from earlier "
                   << "channels (has " << rate << ", expected " << overallRate
                   << ")" << endl;
        }

        connect(model.get(), SIGNAL(modelChanged(ModelId)),
                this, SLOT(componentModelChanged(ModelId)));
        connect(model.get(), SIGNAL(modelChangedWithin(ModelId, sv_frame_t, sv_frame_t)),
                this, SLOT(componentModelChangedWithin(ModelId, sv_frame_t, sv_frame_t)));
        connect(model.get(), SIGNAL(completionChanged(ModelId)),
                this, SLOT(componentModelCompletionChanged(ModelId)));
    }
}

AggregateWaveModel::~AggregateWaveModel()
{
    SVDEBUG << "AggregateWaveModel::~AggregateWaveModel" << endl;
}

bool
AggregateWaveModel::isOK() const
{
    if (m_components.empty()) {
        return false;
    }
    for (const auto &c: m_components) {
        auto model = ModelById::get(c.model);
        if (!model || !model->isOK()) {
            return false;
        }
    }
    return true;
}

bool
AggregateWaveModel::isReady(int *completion) const
{
    if (completion) *completion = 100;

    bool ready = true;
    for (auto c: m_components) {
        int completionHere = 100;
        auto model = ModelById::get(c.model);
        if (!model) continue;
        if (!model->isReady(&completionHere)) {
            ready = false;
        }
        if (completion && completionHere < *completion) {
            *completion = completionHere;
        }
    }

#ifdef DEBUG_AGGREGATE_WAVE_FILE_MODEL
    SVDEBUG << "AggregateWaveModel(" << objectName()
            << ")::isReady: returning " << ready << endl;
#endif
    
    return ready;
}

sv_frame_t
AggregateWaveModel::getFrameCount() const
{
    sv_frame_t count = 0;
    for (auto c: m_components) {
        auto model = ModelById::get(c.model);
        if (!model) continue;
        sv_frame_t thisCount = model->getEndFrame() - model->getStartFrame();
        if (thisCount > count) count = thisCount;
    }
    return count;
}

int
AggregateWaveModel::getChannelCount() const
{
    return int(m_components.size());
}

sv_samplerate_t
AggregateWaveModel::getSampleRate() const
{
    if (m_components.empty()) return 0;
    auto model = ModelById::get(m_components.begin()->model);
    if (!model) return 0;
    return model->getSampleRate();
}

floatvec_t
AggregateWaveModel::getData(int channel, sv_frame_t start, sv_frame_t count) const
{
    if (m_components.empty()) return {};

    int ch0 = channel, ch1 = channel;
    if (channel == -1) {
        ch0 = 0;
        ch1 = getChannelCount()-1;
    } else if (!in_range_for(m_components, channel)) {
        return {};
    }

    floatvec_t result(count, 0.f);
    sv_frame_t longest = 0;
    
    for (int c = ch0; c <= ch1; ++c) {

        auto model = ModelById::getAs<RangeSummarisableTimeValueModel>
            (m_components[c].model);
        if (!model) continue;

        auto here = model->getData(m_components[c].channel, start, count);
        if (sv_frame_t(here.size()) > longest) {
            longest = sv_frame_t(here.size());
        }
        for (sv_frame_t i = 0; in_range_for(here, i); ++i) {
            result[i] += here[i];
        }
    }

    result.resize(longest);
    return result;
}

vector<floatvec_t>
AggregateWaveModel::getMultiChannelData(int fromchannel, int tochannel,
                                        sv_frame_t start, sv_frame_t count) const
{
    sv_frame_t min = count;

    vector<floatvec_t> result;

    for (int c = fromchannel; c <= tochannel; ++c) {
        auto here = getData(c, start, count);
        if (sv_frame_t(here.size()) < min) {
            min = sv_frame_t(here.size());
        }
        result.push_back(here);
    }

    if (min < count) {
        for (auto &v : result) v.resize(min);
    }
    
    return result;
}

int
AggregateWaveModel::getSummaryBlockSize(int desired) const
{
    //!!! complete
    return desired;
}
        
void
AggregateWaveModel::getSummaries(int, sv_frame_t, sv_frame_t,
                                 RangeBlock &, int &) const
{
    //!!! complete
}

AggregateWaveModel::Range
AggregateWaveModel::getSummary(int, sv_frame_t, sv_frame_t) const
{
    //!!! complete
    return Range();
}
        
int
AggregateWaveModel::getComponentCount() const
{
    return int(m_components.size());
}

AggregateWaveModel::ModelChannelSpec
AggregateWaveModel::getComponent(int c) const
{
    return m_components[c];
}

void
AggregateWaveModel::componentModelChanged(ModelId)
{
    emit modelChanged(getId());
}

void
AggregateWaveModel::componentModelChangedWithin(ModelId, sv_frame_t start, sv_frame_t end)
{
    emit modelChangedWithin(getId(), start, end);
}

void
AggregateWaveModel::componentModelCompletionChanged(ModelId)
{
    emit completionChanged(getId());
}

void
AggregateWaveModel::toXml(QTextStream &out,
                          QString indent,
                          QString extraAttributes) const
{
    QStringList componentStrings;
    for (const auto &c: m_components) {
        auto model = ModelById::get(c.model);
        if (!model) continue;
        componentStrings.push_back(QString("%1").arg(model->getExportId()));
    }
    Model::toXml(out, indent,
                 QString("type=\"aggregatewave\" components=\"%1\" %2")
                 .arg(componentStrings.join(","))
                 .arg(extraAttributes));
}