view common/FeatureFileIndex.cpp @ 45:0033259c6772

* More Music Ontology-like structure for audio files & signals
author Chris Cannam
date Fri, 14 May 2010 17:58:04 +0100
parents ed2befdf1e98
children c8b777862198
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

#include "FeatureFileIndex.h"
#include "TypeRegistrar.h"

#include <QMutexLocker>
#include <QDir>

#include "base/TempDirectory.h"
#include "base/Exceptions.h"

using namespace Dataquay;


namespace ClassicalData {

FeatureFileIndex *
FeatureFileIndex::getInstance()
{
    static FeatureFileIndex instance;
    return &instance;
}

FeatureFileIndex::FeatureFileIndex() :
    m_bs(0),
    m_index(0)
{
    try {
	m_indexFileName = getIndexFileName();
    } catch (DirectoryCreationFailed f) {
        std::cerr << "FeatureFileIndex: ERROR: Failed to find or create index directory: " << f.what() << std::endl;
        return;
    }

    m_bs = new BasicStore;
    m_index = new TransactionalStore(m_bs);

    TypeRegistrar::addMappings(m_bs, 0);

    if (QFile(m_indexFileName).exists()) {
	m_bs->import(QUrl::fromLocalFile(m_indexFileName),
                     BasicStore::ImportIgnoreDuplicates);
	//!!! catch
    }
}

FeatureFileIndex::~FeatureFileIndex()
{
    delete m_index;
    delete m_bs;
}

QString
FeatureFileIndex::getIndexFileName()
{
    QDir d = TempDirectory::getInstance()->getContainingPath();
    QString n("index");
    QFileInfo fi(d.filePath(n));

    if ((fi.exists() && !fi.isDir()) ||
        (!fi.exists() && !d.mkdir(n))) {
        throw DirectoryCreationFailed(fi.filePath());
    }

    return QDir(fi.filePath()).filePath("features.ttl");
}

QString
FeatureFileIndex::getFeatureDirectoryName()
{
    QDir d = TempDirectory::getInstance()->getContainingPath();
    QString n("features");
    QFileInfo fi(d.filePath(n));

    if ((fi.exists() && !fi.isDir()) ||
        (!fi.exists() && !d.mkdir(n))) {
        throw DirectoryCreationFailed(fi.filePath());
    }

    return fi.filePath();
}

void
FeatureFileIndex::loadFor(AudioFile *tf, Store *store)
{
    if (!m_index) {
	std::cerr << "FeatureFileIndex::loadFor: No index!" << std::endl;
	return;
    }
    updateIndex();

    // The AudioFile object has a URI and a hash.  Feature files
    // generated for this AudioFile should ideally have a matching
    // hash; if they have no hash, then the URI should match.  If the
    // hash is present in the feature file but does not match, then it
    // cannot be the right track even if the URI matches.

    Triple t(Node(), "foaf:primaryTopic", tf->uri());
    Triples results = m_index->match(t);
    std::cerr << "FeatureFileIndex::loadFor: " << results.size() << " feature file(s) for audio file " << tf->uri() << std::endl;

    t = Triple(Node(), "foaf:primaryTopic",
               Uri(QString::fromUtf8(QUrl(tf->uri().toString()).toEncoded())));
    Triples moreResults = m_index->match(t);
    std::cerr << "FeatureFileIndex::loadFor: " << moreResults.size() << " feature file(s) for audio file " << t.c << std::endl;

    //!!! what's the right approach here?

    if (results.empty() && moreResults.empty()) {
        return;
    }

    
}

void
FeatureFileIndex::featureFileAdded(QString filepath)
{
    index(QUrl::fromLocalFile(filepath));
}    

void
FeatureFileIndex::updateIndex()
{
    QMutexLocker locker(&m_mutex);
    if (!m_index) return;

    QDir featureDir;
    try {
	QString s = getFeatureDirectoryName();
        featureDir = QDir(s);
    } catch (DirectoryCreationFailed f) {
        std::cerr << "FeatureFileIndex::updateIndex: ERROR: Failed to find or create feature directory: " << f.what() << std::endl;
        return;
    }

    featureDir.setFilter(QDir::Files);

    for (unsigned int i = 0; i < featureDir.count(); ++i) {
        QFileInfo fi(featureDir.filePath(featureDir[i]));
        if (fi.isFile() && fi.isReadable()) {
            index(QUrl::fromLocalFile(fi.filePath()));
        }
    }

    //!!! remove triples from index that refer to nonexistent files?

    std::cerr << "Saving index to " << m_indexFileName.toStdString() << std::endl;
    m_bs->save(m_indexFileName);
}

void
FeatureFileIndex::index(QUrl fileUrl)
{
    Triple typeTriple(Uri(fileUrl), "a", m_index->expand("foaf:Document"));

    if (m_index->contains(typeTriple)) {
        return;
    }

    Transaction *tx = m_index->startTransaction();
    tx->add(typeTriple);

    try {
        BasicStore *b = BasicStore::load(fileUrl);
        Triples ts = b->match
            (Triple(Node(), "a", m_index->expand("mo:AudioFile")));
        foreach (Triple t, ts) {
            tx->add(Triple(Uri(fileUrl), "foaf:primaryTopic", t.a));;
        }
    } catch (...) { }

    delete tx;
}


}