Mercurial > hg > classical
changeset 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 |
files | common/FeatureFileIndex.cpp common/FeatureFileIndex.h common/Objects.cpp common/Objects.h common/TypeRegistrar.cpp utilities/the-application/the-application.cpp utilities/track/track.cpp |
diffstat | 7 files changed, 174 insertions(+), 69 deletions(-) [+] |
line wrap: on
line diff
--- a/common/FeatureFileIndex.cpp Mon May 10 17:33:00 2010 +0100 +++ b/common/FeatureFileIndex.cpp Fri May 14 17:58:04 2010 +0100 @@ -22,6 +22,7 @@ } FeatureFileIndex::FeatureFileIndex() : + m_bs(0), m_index(0) { try { @@ -31,19 +32,22 @@ return; } - m_index = new BasicStore; + m_bs = new BasicStore; + m_index = new TransactionalStore(m_bs); - TypeRegistrar::addMappings(m_index, 0); + TypeRegistrar::addMappings(m_bs, 0); if (QFile(m_indexFileName).exists()) { - m_index->import(QUrl::fromLocalFile(m_indexFileName), - BasicStore::ImportIgnoreDuplicates); + m_bs->import(QUrl::fromLocalFile(m_indexFileName), + BasicStore::ImportIgnoreDuplicates); //!!! catch } } FeatureFileIndex::~FeatureFileIndex() { + delete m_index; + delete m_bs; } QString @@ -77,7 +81,7 @@ } void -FeatureFileIndex::loadFor(TrackFile *tf, BasicStore *store) +FeatureFileIndex::loadFor(AudioFile *tf, Store *store) { if (!m_index) { std::cerr << "FeatureFileIndex::loadFor: No index!" << std::endl; @@ -85,10 +89,37 @@ } 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); @@ -106,27 +137,40 @@ featureDir.setFilter(QDir::Files); for (unsigned int i = 0; i < featureDir.count(); ++i) { - QFileInfo fi(featureDir.filePath(featureDir[i])); - if (fi.isFile() && fi.isReadable()) { - QUrl fileUrl(QUrl::fromLocalFile(fi.filePath())); - try { - BasicStore *b = BasicStore::load(fileUrl); - Triples ts = b->match - (Triple(Node(), "a", m_index->expand("mo:AudioFile"))); - foreach (Triple t, ts) { - m_index->add(Triple(Uri(fileUrl), "a", m_index->expand("foaf:Document"))); - m_index->add(Triple(Uri(fileUrl), "foaf:primaryTopic", t.a));; - } - } catch (...) { } + 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_index->save(m_indexFileName); + 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; }
--- a/common/FeatureFileIndex.h Mon May 10 17:33:00 2010 +0100 +++ b/common/FeatureFileIndex.h Fri May 14 17:58:04 2010 +0100 @@ -6,28 +6,36 @@ #include "Objects.h" #include <dataquay/BasicStore.h> +#include <dataquay/TransactionalStore.h> #include <QMutex> namespace ClassicalData { -class FeatureFileIndex +class FeatureFileIndex : public QObject { + Q_OBJECT + public: static FeatureFileIndex *getInstance(); FeatureFileIndex(); ~FeatureFileIndex(); - void loadFor(TrackFile *, Dataquay::BasicStore *); + void loadFor(AudioFile *, Dataquay::Store *); + +public slots: + void featureFileAdded(QString filepath); private: QMutex m_mutex; QString m_indexFileName; - Dataquay::BasicStore *m_index; + Dataquay::BasicStore *m_bs; + Dataquay::TransactionalStore *m_index; QString getIndexFileName(); QString getFeatureDirectoryName(); void updateIndex(); + void index(QUrl); }; }
--- a/common/Objects.cpp Mon May 10 17:33:00 2010 +0100 +++ b/common/Objects.cpp Fri May 14 17:58:04 2010 +0100 @@ -825,24 +825,18 @@ } } -TrackFile::TrackFile(QObject *parent) : - QObject(parent), - m_composer(0), - m_work(0), - m_movement(0) +AudioFile::AudioFile(QObject *parent) : + QObject(parent) { } -TrackFile::TrackFile(FileSource source, QObject *parent) : - QObject(parent), - m_composer(0), - m_work(0), - m_movement(0) +AudioFile::AudioFile(FileSource source, QObject *parent) : + QObject(parent) { if (source.isAvailable()) { QFile f(source.getLocalFilename()); f.open(QIODevice::ReadOnly); - //!!! data may be too large! + //!!! stream this! QByteArray ba = f.readAll(); m_hash = QString::fromAscii (QCryptographicHash::hash(ba, QCryptographicHash::Sha1).toHex()); @@ -859,7 +853,8 @@ m_uri = Dataquay::Uri("file://" + QFileInfo(location).canonicalFilePath()); } } - std::cerr << "TrackFile::TrackFile: hash = " << m_hash.toStdString() + + std::cerr << "AudioFile::AudioFile: hash = " << m_hash.toStdString() << ", uri = " << m_uri.toString().toStdString() << std::endl; }
--- a/common/Objects.h Mon May 10 17:33:00 2010 +0100 +++ b/common/Objects.h Fri May 14 17:58:04 2010 +0100 @@ -580,30 +580,49 @@ static QMutex m_mutex; }; -class TrackFile : public QObject +// Separate AudioFile and Signal, to correspond with + +class AudioFile : public QObject { Q_OBJECT Q_PROPERTY(QString hash READ hash WRITE setHash NOTIFY hashChanged STORED true) Q_PROPERTY(Dataquay::Uri uri READ uri WRITE setUri NOTIFY uriChanged STORED true) - Q_PROPERTY(QString ofaFingerprint READ ofaFingerprint WRITE setOfaFingerprint NOTIFY ofaFingerprintChanged STORED true) - Q_PROPERTY(QString puid READ puid WRITE setPuid NOTIFY puidChanged STORED true) - Q_PROPERTY(ClassicalData::Composer *composer READ composer WRITE setComposer NOTIFY composerChanged STORED true) - Q_PROPERTY(ClassicalData::Work *work READ work WRITE setWork NOTIFY workChanged STORED true) - Q_PROPERTY(ClassicalData::Movement *movement READ movement WRITE setMovement NOTIFY movementChanged STORED true) - Q_PROPERTY(QSet<Dataquay::Uri> otherURIs READ otherURIs WRITE setOtherURIs NOTIFY otherURIsChanged STORED true) public: - TrackFile(QObject *parent = 0); - TrackFile(FileSource file, QObject *parent = 0); - + AudioFile(QObject *parent = 0); + AudioFile(FileSource file, QObject *parent = 0); + + /// The URI is set automatically from the FileSource at construction + Dataquay::Uri uri() const { return m_uri; } + void setUri(Dataquay::Uri u) { m_uri = u; emit uriChanged(u); } + /// The hash is set automatically from the FileSource at construction QString hash() const { return m_hash; } void setHash(QString hash) { m_hash = hash; emit hashChanged(hash); } - /// The URI is set automatically from the FileSource at construction - Dataquay::Uri uri() const { return m_uri; } - void setUri(Dataquay::Uri u) { m_uri = u; emit uriChanged(u); } +signals: + void uriChanged(Dataquay::Uri); + void hashChanged(QString); + +private: + Dataquay::Uri m_uri; + QString m_hash; +}; + +class Signal : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString ofaFingerprint READ ofaFingerprint WRITE setOfaFingerprint NOTIFY ofaFingerprintChanged STORED true) + Q_PROPERTY(QString puid READ puid WRITE setPuid NOTIFY puidChanged STORED true) + Q_PROPERTY(QSet<ClassicalData::AudioFile *> availableAs READ availableAs WRITE setAvailableAs NOTIFY availableAsChanged STORED true) + Q_PROPERTY(ClassicalData::Composer *composer READ composer WRITE setComposer NOTIFY composerChanged STORED true) + Q_PROPERTY(ClassicalData::Work *work READ work WRITE setWork NOTIFY workChanged STORED true) + Q_PROPERTY(ClassicalData::Movement *movement READ movement WRITE setMovement NOTIFY movementChanged STORED true) + +public: + Signal() : m_composer(0), m_work(0), m_movement(0) { } QString ofaFingerprint() const { return m_ofaFingerprint; } void setOfaFingerprint(QString fprint) { m_ofaFingerprint = fprint; emit ofaFingerprintChanged(fprint); } @@ -611,6 +630,10 @@ QString puid() const { return m_puid; } void setPuid(QString puid) { m_puid = puid; emit puidChanged(puid); } + QSet<AudioFile *> availableAs() const { return m_availableAs; } + void setAvailableAs(QSet<AudioFile *> aa) { m_availableAs = aa; emit availableAsChanged(m_availableAs); } + void addAvailableAs(AudioFile *aa) { m_availableAs.insert(aa); emit availableAsChanged(m_availableAs); } + Composer *composer() const { return m_composer; } void setComposer(Composer *c) { m_composer = c; emit composerChanged(c); } @@ -620,29 +643,21 @@ Movement *movement() const { return m_movement; } void setMovement(Movement *m) { m_movement = m; emit movementChanged(m); } - QSet<Dataquay::Uri> otherURIs() const { return m_otherURIs; } - void addOtherURI(Dataquay::Uri u) { m_otherURIs.insert(u); emit otherURIsChanged(m_otherURIs); } - void setOtherURIs(QSet<Dataquay::Uri> u) { m_otherURIs = u; emit otherURIsChanged(u); } - signals: - void uriChanged(Dataquay::Uri); - void hashChanged(QString); void ofaFingerprintChanged(QString); void puidChanged(QString); void composerChanged(Composer *); void workChanged(Work *); void movementChanged(Movement *); - void otherURIsChanged(QSet<Dataquay::Uri>); + void availableAsChanged(QSet<AudioFile *>); private: - Dataquay::Uri m_uri; - QString m_hash; QString m_ofaFingerprint; QString m_puid; Composer *m_composer; Work *m_work; Movement *m_movement; - QSet<Dataquay::Uri> m_otherURIs; + QSet<AudioFile *> m_availableAs; }; } @@ -655,11 +670,15 @@ Q_DECLARE_METATYPE(ClassicalData::Work*); Q_DECLARE_METATYPE(ClassicalData::Movement*); Q_DECLARE_METATYPE(ClassicalData::Document*); +Q_DECLARE_METATYPE(ClassicalData::AudioFile*); +Q_DECLARE_METATYPE(ClassicalData::Signal*); Q_DECLARE_METATYPE(QSet<QString>); Q_DECLARE_METATYPE(QSet<Dataquay::Uri>); Q_DECLARE_METATYPE(QSet<ClassicalData::Work*>); Q_DECLARE_METATYPE(QSet<ClassicalData::Movement*>); Q_DECLARE_METATYPE(QSet<ClassicalData::Document*>); +Q_DECLARE_METATYPE(QSet<ClassicalData::AudioFile*>); +Q_DECLARE_METATYPE(QSet<ClassicalData::Signal*>); Q_DECLARE_METATYPE(ClassicalData::Composer*); Q_DECLARE_METATYPE(ClassicalData::Form*); Q_DECLARE_METATYPE(QSet<ClassicalData::Form*>);
--- a/common/TypeRegistrar.cpp Mon May 10 17:33:00 2010 +0100 +++ b/common/TypeRegistrar.cpp Fri May 14 17:58:04 2010 +0100 @@ -47,6 +47,12 @@ ("QSet<QString>"); qRegisterMetaType<QSet<Dataquay::Uri> > ("QSet<Dataquay::Uri>"); + qRegisterMetaType<AudioFile *> + ("ClassicalData::AudioFile*"); + qRegisterMetaType<QSet<AudioFile *> > + ("QSet<ClassicalData::AudioFile*>"); + qRegisterMetaType<Signal *> + ("ClassicalData::Signal*"); Node::registerDatatype(Uri("http://www.w3.org/2001/XMLSchema#gYear"), "ClassicalData::Year", new Year::Encoder()); @@ -69,6 +75,8 @@ <Document, QObject>("ClassicalData::Document*"); ObjectBuilder::getInstance()->registerClass <Form, QObject>("ClassicalData::Form*"); + ObjectBuilder::getInstance()->registerClass + <AudioFile>("ClassicalData::AudioFile*"); ContainerBuilder::getInstance()->registerContainer <QString, QSet<QString> > @@ -97,6 +105,11 @@ <Form*, QSet<Form*> > ("ClassicalData::Form*", "QSet<ClassicalData::Form*>", ContainerBuilder::SetKind); + + ContainerBuilder::getInstance()->registerContainer + <AudioFile*, QSet<AudioFile*> > + ("ClassicalData::AudioFile*", "QSet<ClassicalData::AudioFile*>", + ContainerBuilder::SetKind); } void @@ -180,7 +193,15 @@ mapping->addPropertyMapping("ClassicalData::Composition", "composer", store->expand("mo:composer")); mapping->addPropertyMapping("ClassicalData::Composition", "works", store->expand("mo:produced_work")); - mapping->addTypeMapping("ClassicalData::TrackFile", store->expand("mo:AudioFile")); + mapping->addTypeMapping("ClassicalData::AudioFile", store->expand("mo:AudioFile")); + mapping->addPropertyMapping("ClassicalData::AudioFile", "hash", store->expand("foaf:sha1")); + + mapping->addTypeMapping("ClassicalData::Signal", store->expand("mo:Signal")); + mapping->addPropertyMapping("ClassicalData::Signal", "availableAs", store->expand("mo:available_as")); + mapping->addPropertyMapping("ClassicalData::Signal", "puid", store->expand("mo:puid")); + mapping->addPropertyMapping("ClassicalData::Signal", "composer", store->expand("mo:composer")); + mapping->addPropertyMapping("ClassicalData::Signal", "work", store->expand("mo:")); + mapping->addPropertyMapping("ClassicalData::Signal", "availableAs", store->expand("mo:available_as")); } }
--- a/utilities/the-application/the-application.cpp Mon May 10 17:33:00 2010 +0100 +++ b/utilities/the-application/the-application.cpp Fri May 14 17:58:04 2010 +0100 @@ -457,15 +457,16 @@ guessWorkFromTitle(filepart, scale, composer, guesses); } -TrackFile * +Signal * guess(QString track) { cout << endl; cout << "Guessing composer for: " << track << endl; -// cerr << "Creating TrackFile object..."; +// cerr << "Creating Signal object..."; FileSource fs(track); - TrackFile *tf = new TrackFile(fs); + Signal *tf = new Signal; + tf->addAvailableAs(new AudioFile(fs)); // cerr << "done" << endl; // cerr << "hash = " << tf->hash() << endl; @@ -633,7 +634,20 @@ FeatureFileIndex *ffi = FeatureFileIndex::getInstance(); - ffi->loadFor(0, 0); + QStringList args; + for (int i = 1; i < argc; ++i) { + args.push_back(argv[i]); + } + + BasicStore bs; + if (!args.empty()) { + foreach (QString track, args) { + FileSource fs(track); + AudioFile af(fs); + ffi->loadFor(&af, &bs); + } + } + /* BasicStore *index = new BasicStore; @@ -759,7 +773,7 @@ if (command == "guess") { if (args.empty()) usage(argv[0]); foreach (QString track, args) { - TrackFile *tf = guess(track); + Signal *tf = guess(track); localStorer->store(tf); } }
--- a/utilities/track/track.cpp Mon May 10 17:33:00 2010 +0100 +++ b/utilities/track/track.cpp Fri May 14 17:58:04 2010 +0100 @@ -454,15 +454,16 @@ guessWorkFromTitle(filepart, scale, composer, guesses); } -TrackFile * +Signal * guess(QString track) { cout << endl; cout << "Guessing composer for: " << track << endl; -// cerr << "Creating TrackFile object..."; +// cerr << "Creating Signal..."; FileSource fs(track); - TrackFile *tf = new TrackFile(fs); + Signal *tf = new Signal; + tf->addAvailableAs(new AudioFile(fs)); // cerr << "done" << endl; // cerr << "hash = " << tf->hash() << endl; @@ -701,15 +702,18 @@ ObjectStorer *localStorer = new ObjectStorer(&localStore); localStorer->setTypeMapping(tm); -// localStorer->setFollowPolicy(ObjectStorer::FollowObjectProperties); + localStorer->setFollowPolicy(ObjectStorer::FollowObjectProperties); + localStorer->setPropertyStorePolicy(ObjectStorer::StoreIfChanged); if (command == "guess") { if (args.empty()) usage(argv[0]); foreach (QString track, args) { - TrackFile *tf = guess(track); + Signal *tf = guess(track); localStorer->store(tf); } - } + } else { + usage(argv[0]); + } delete localStorer; localStore.save("local.ttl");