Mercurial > hg > svcore
changeset 855:42bbc538d983 tonioni_multi_transform
Merge from tonioni branch
author | Chris Cannam |
---|---|
date | Wed, 04 Dec 2013 18:29:15 +0000 (2013-12-04) |
parents | 418cd2064769 (current diff) 23ecd10c2eb6 (diff) |
children | 8593a3fe50ac |
files | |
diffstat | 11 files changed, 283 insertions(+), 133 deletions(-) [+] |
line wrap: on
line diff
--- a/data/fileio/MIDIFileWriter.cpp Mon Dec 02 11:17:24 2013 +0000 +++ b/data/fileio/MIDIFileWriter.cpp Wed Dec 04 18:29:15 2013 +0000 @@ -23,8 +23,7 @@ #include "MIDIFileWriter.h" #include "data/midi/MIDIEvent.h" - -#include "model/NoteModel.h" +#include "model/NoteData.h" #include "base/Pitch.h" @@ -37,14 +36,13 @@ using namespace MIDIConstants; -MIDIFileWriter::MIDIFileWriter(QString path, NoteModel *model, float tempo) : +MIDIFileWriter::MIDIFileWriter(QString path, const NoteExportable *exportable, + int sampleRate, float tempo) : m_path(path), - m_model(model), - m_modelUsesHz(false), + m_exportable(exportable), + m_sampleRate(sampleRate), m_tempo(tempo) { - if (model->getScaleUnits().toLower() == "hz") m_modelUsesHz = true; - if (!convert()) { m_error = "Conversion from model to internal MIDI format failed"; } @@ -342,42 +340,28 @@ // Omit time signature - const NoteModel::PointList ¬es = - static_cast<SparseModel<Note> *>(m_model)->getPoints(); + NoteList notes = m_exportable->getNotes(); - for (NoteModel::PointList::const_iterator i = notes.begin(); - i != notes.end(); ++i) { + for (NoteList::const_iterator i = notes.begin(); i != notes.end(); ++i) { - long frame = i->frame; - float value = i->value; + size_t frame = i->start; size_t duration = i->duration; - - int pitch; - - if (m_modelUsesHz) { - pitch = Pitch::getPitchForFrequency(value); - } else { - pitch = lrintf(value); - } + int pitch = i->midiPitch; + int velocity = i->velocity; if (pitch < 0) pitch = 0; if (pitch > 127) pitch = 127; // Convert frame to MIDI time - double seconds = double(frame) / double(m_model->getSampleRate()); + double seconds = double(frame) / double(m_sampleRate); double quarters = (seconds * m_tempo) / 60.0; - unsigned long midiTime = lrint(quarters * m_timingDivision); - - int velocity = 100; - if (i->level > 0.f && i->level <= 1.f) { - velocity = lrintf(i->level * 127.f); - } + unsigned long midiTime = int(quarters * m_timingDivision + 0.5); // Get the sounding time for the matching NOTE_OFF - seconds = double(frame + duration) / double(m_model->getSampleRate()); + seconds = double(frame + duration) / double(m_sampleRate); quarters = (seconds * m_tempo) / 60.0; - unsigned long endTime = lrint(quarters * m_timingDivision); + unsigned long endTime = int(quarters * m_timingDivision + 0.5); // At this point all the notes we insert have absolute times // in the delta time fields. We resolve these into delta
--- a/data/fileio/MIDIFileWriter.h Mon Dec 02 11:17:24 2013 +0000 +++ b/data/fileio/MIDIFileWriter.h Wed Dec 04 18:29:15 2013 +0000 @@ -32,7 +32,7 @@ #include <fstream> class MIDIEvent; -class NoteModel; +class NoteExportable; /** * Write a MIDI file. This includes file write code for generic @@ -43,7 +43,10 @@ class MIDIFileWriter { public: - MIDIFileWriter(QString path, NoteModel *model, float tempo = 120.f); + MIDIFileWriter(QString path, + const NoteExportable *exportable, + int sampleRate, // used to convert exportable sample timings + float tempo = 120.f); virtual ~MIDIFileWriter(); virtual bool isOK() const; @@ -74,18 +77,18 @@ bool convert(); - QString m_path; - NoteModel *m_model; - bool m_modelUsesHz; - float m_tempo; - int m_timingDivision; // pulses per quarter note - MIDIFileFormatType m_format; - unsigned int m_numberOfTracks; + QString m_path; + const NoteExportable *m_exportable; + int m_sampleRate; + float m_tempo; + int m_timingDivision; // pulses per quarter note + MIDIFileFormatType m_format; + unsigned int m_numberOfTracks; - MIDIComposition m_midiComposition; + MIDIComposition m_midiComposition; - std::ofstream *m_midiFile; - QString m_error; + std::ofstream *m_midiFile; + QString m_error; }; #endif
--- a/data/model/FlexiNoteModel.h Mon Dec 02 11:17:24 2013 +0000 +++ b/data/model/FlexiNoteModel.h Wed Dec 04 18:29:15 2013 +0000 @@ -16,10 +16,10 @@ #ifndef _FLEXINOTE_MODEL_H_ #define _FLEXINOTE_MODEL_H_ -// #include "NotelikeModel.h" // GF: reomved as this is an uncommitted experiment for now - #include "IntervalModel.h" +#include "NoteData.h" #include "base/RealTime.h" +#include "base/Pitch.h" #include "base/PlayParameterRepository.h" /** @@ -97,7 +97,7 @@ }; -class FlexiNoteModel : public IntervalModel<FlexiNote> +class FlexiNoteModel : public IntervalModel<FlexiNote>, public NoteExportable { Q_OBJECT @@ -227,6 +227,48 @@ return SortNumeric; } + /** + * NoteExportable methods. + */ + + NoteList getNotes() const { + return getNotes(getStartFrame(), getEndFrame()); + } + + NoteList getNotes(size_t startFrame, size_t endFrame) const { + + PointList points = getPoints(startFrame, endFrame); + NoteList notes; + + for (PointList::iterator pli = + points.begin(); pli != points.end(); ++pli) { + + size_t duration = pli->duration; + if (duration == 0 || duration == 1) { + duration = getSampleRate() / 20; + } + + int pitch = lrintf(pli->value); + + int velocity = 100; + if (pli->level > 0.f && pli->level <= 1.f) { + velocity = lrintf(pli->level * 127); + } + + NoteData note(pli->frame, duration, pitch, velocity); + + if (getScaleUnits() == "Hz") { + note.frequency = pli->value; + note.midiPitch = Pitch::getPitchForFrequency(note.frequency); + note.isMidiPitchQuantized = false; + } + + notes.push_back(note); + } + + return notes; + } + protected: float m_valueQuantization; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/model/NoteData.h Wed Dec 04 18:29:15 2013 +0000 @@ -0,0 +1,43 @@ +/* -*- 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 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. +*/ + +#ifndef NOTE_DATA_H +#define NOTE_DATA_H + +#include <vector> + +struct NoteData +{ + NoteData(size_t _start, size_t _dur, int _mp, int _vel) : + start(_start), duration(_dur), midiPitch(_mp), frequency(0), + isMidiPitchQuantized(true), velocity(_vel) { }; + + size_t start; // audio sample frame + size_t duration; // in audio sample frames + int midiPitch; // 0-127 + int frequency; // Hz, to be used if isMidiPitchQuantized false + bool isMidiPitchQuantized; + int velocity; // MIDI-style 0-127 +}; + +typedef std::vector<NoteData> NoteList; + +class NoteExportable +{ +public: + virtual NoteList getNotes() const = 0; + virtual NoteList getNotes(size_t startFrame, size_t endFrame) const = 0; +}; + +#endif
--- a/data/model/NoteModel.h Mon Dec 02 11:17:24 2013 +0000 +++ b/data/model/NoteModel.h Wed Dec 04 18:29:15 2013 +0000 @@ -17,8 +17,10 @@ #define _NOTE_MODEL_H_ #include "IntervalModel.h" +#include "NoteData.h" #include "base/RealTime.h" #include "base/PlayParameterRepository.h" +#include "base/Pitch.h" /** * NoteModel -- a concrete IntervalModel for notes. @@ -91,7 +93,7 @@ }; -class NoteModel : public IntervalModel<Note> +class NoteModel : public IntervalModel<Note>, public NoteExportable { Q_OBJECT @@ -219,6 +221,48 @@ return SortNumeric; } + /** + * NoteExportable methods. + */ + + NoteList getNotes() const { + return getNotes(getStartFrame(), getEndFrame()); + } + + NoteList getNotes(size_t startFrame, size_t endFrame) const { + + PointList points = getPoints(startFrame, endFrame); + NoteList notes; + + for (PointList::iterator pli = + points.begin(); pli != points.end(); ++pli) { + + size_t duration = pli->duration; + if (duration == 0 || duration == 1) { + duration = getSampleRate() / 20; + } + + int pitch = lrintf(pli->value); + + int velocity = 100; + if (pli->level > 0.f && pli->level <= 1.f) { + velocity = lrintf(pli->level * 127); + } + + NoteData note(pli->frame, duration, pitch, velocity); + + if (getScaleUnits() == "Hz") { + note.frequency = pli->value; + note.midiPitch = Pitch::getPitchForFrequency(note.frequency); + note.isMidiPitchQuantized = false; + } + + notes.push_back(note); + } + + return notes; + } + protected: float m_valueQuantization; };
--- a/data/model/SparseOneDimensionalModel.h Mon Dec 02 11:17:24 2013 +0000 +++ b/data/model/SparseOneDimensionalModel.h Wed Dec 04 18:29:15 2013 +0000 @@ -17,6 +17,7 @@ #define _SPARSE_ONE_DIMENSIONAL_MODEL_H_ #include "SparseModel.h" +#include "NoteData.h" #include "base/PlayParameterRepository.h" #include "base/RealTime.h" @@ -69,7 +70,8 @@ }; -class SparseOneDimensionalModel : public SparseModel<OneDimensionalPoint> +class SparseOneDimensionalModel : public SparseModel<OneDimensionalPoint>, + public NoteExportable { Q_OBJECT @@ -181,6 +183,32 @@ if (column == 2) return SortAlphabetical; return SortNumeric; } + + /** + * NoteExportable methods. + */ + + NoteList getNotes() const { + return getNotes(getStartFrame(), getEndFrame()); + } + + NoteList getNotes(size_t startFrame, size_t endFrame) const { + + PointList points = getPoints(startFrame, endFrame); + NoteList notes; + + for (PointList::iterator pli = + points.begin(); pli != points.end(); ++pli) { + + notes.push_back + (NoteData(pli->frame, + getSampleRate() / 6, // arbitrary short duration + 64, // default pitch + 100)); // default velocity + } + + return notes; + } }; #endif
--- a/transform/FeatureExtractionModelTransformer.cpp Mon Dec 02 11:17:24 2013 +0000 +++ b/transform/FeatureExtractionModelTransformer.cpp Wed Dec 04 18:29:15 2013 +0000 @@ -138,6 +138,7 @@ size_t pstep = primaryTransform.getStepSize(); size_t pblock = primaryTransform.getBlockSize(); +///!!! hang on, this isn't right -- we're modifying a copy primaryTransform.setStepSize(0); primaryTransform.setBlockSize(0); TransformFactory::getInstance()->makeContextConsistentWithPlugin @@ -449,7 +450,9 @@ { // SVDEBUG << "FeatureExtractionModelTransformer::~FeatureExtractionModelTransformer()" << endl; delete m_plugin; - delete m_descriptors[n]; + for (int j = 0; j < m_descriptors.size(); ++j) { + delete m_descriptors[j]; + } } DenseTimeValueModel * @@ -473,6 +476,8 @@ if (m_outputs.empty()) return; + Transform primaryTransform = m_transforms[0]; + while (!input->isReady() && !m_abandoned) { SVDEBUG << "FeatureExtractionModelTransformer::run: Waiting for input model to be ready..." << endl; usleep(500000); @@ -488,11 +493,11 @@ float **buffers = new float*[channelCount]; for (size_t ch = 0; ch < channelCount; ++ch) { - buffers[ch] = new float[m_transforms[n].getBlockSize() + 2]; + buffers[ch] = new float[primaryTransform.getBlockSize() + 2]; } - size_t stepSize = m_transforms[n].getStepSize(); - size_t blockSize = m_transforms[n].getBlockSize(); + size_t stepSize = primaryTransform.getStepSize(); + size_t blockSize = primaryTransform.getBlockSize(); bool frequencyDomain = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain); @@ -503,7 +508,7 @@ FFTModel *model = new FFTModel (getConformingInput(), channelCount == 1 ? m_input.getChannel() : ch, - m_transforms[n].getWindowType(), + primaryTransform.getWindowType(), blockSize, stepSize, blockSize, @@ -511,7 +516,9 @@ StorageAdviser::PrecisionCritical); if (!model->isOK()) { delete model; - setCompletion(100); + for (int j = 0; j < (int)m_outputNos.size(); ++j) { + setCompletion(j, 100); + } //!!! need a better way to handle this -- previously we were using a QMessageBox but that isn't an appropriate thing to do here either throw AllocationFailed("Failed to create the FFT model for this feature extraction model transformer"); } @@ -523,8 +530,8 @@ long startFrame = m_input.getModel()->getStartFrame(); long endFrame = m_input.getModel()->getEndFrame(); - RealTime contextStartRT = m_transforms[n].getStartTime(); - RealTime contextDurationRT = m_transforms[n].getDuration(); + RealTime contextStartRT = primaryTransform.getStartTime(); + RealTime contextDurationRT = primaryTransform.getDuration(); long contextStart = RealTime::realTime2Frame(contextStartRT, sampleRate); @@ -547,7 +554,9 @@ long prevCompletion = 0; - setCompletion(0); + for (int j = 0; j < (int)m_outputNos.size(); ++j) { + setCompletion(j, 0); + } float *reals = 0; float *imaginaries = 0; @@ -604,13 +613,17 @@ if (m_abandoned) break; - for (size_t fi = 0; fi < features[m_outputNos[n]].size(); ++fi) { - Vamp::Plugin::Feature feature = features[m_outputNos[n]][fi]; - addFeature(blockFrame, feature); - } + for (int j = 0; j < (int)m_outputNos.size(); ++j) { + for (size_t fi = 0; fi < features[m_outputNos[j]].size(); ++fi) { + Vamp::Plugin::Feature feature = features[m_outputNos[j]][fi]; + addFeature(j, blockFrame, feature); + } + } if (blockFrame == contextStart || completion > prevCompletion) { - setCompletion(completion); + for (int j = 0; j < (int)m_outputNos.size(); ++j) { + setCompletion(j, completion); + } prevCompletion = completion; } @@ -620,13 +633,17 @@ if (!m_abandoned) { Vamp::Plugin::FeatureSet features = m_plugin->getRemainingFeatures(); - for (size_t fi = 0; fi < features[m_outputNos[n]].size(); ++fi) { - Vamp::Plugin::Feature feature = features[m_outputNos[n]][fi]; - addFeature(blockFrame, feature); + for (int j = 0; j < (int)m_outputNos.size(); ++j) { + for (size_t fi = 0; fi < features[m_outputNos[j]].size(); ++fi) { + Vamp::Plugin::Feature feature = features[m_outputNos[j]][fi]; + addFeature(j, blockFrame, feature); + } } } - setCompletion(100); + for (int j = 0; j < (int)m_outputNos.size(); ++j) { + setCompletion(j, 100); + } if (frequencyDomain) { for (size_t ch = 0; ch < channelCount; ++ch) { @@ -698,8 +715,9 @@ } void -FeatureExtractionModelTransformer::addFeature(size_t blockFrame, - const Vamp::Plugin::Feature &feature) +FeatureExtractionModelTransformer::addFeature(int n, + size_t blockFrame, + const Vamp::Plugin::Feature &feature) { size_t inputRate = m_input.getModel()->getSampleRate(); @@ -749,8 +767,6 @@ // to, we instead test what sort of model the constructor decided // to create. - //!!! currently hardcoding model 0 - if (isOutput<SparseOneDimensionalModel>(n)) { SparseOneDimensionalModel *model = @@ -872,7 +888,7 @@ } void -FeatureExtractionModelTransformer::setCompletion(int completion) +FeatureExtractionModelTransformer::setCompletion(int n, int completion) { int binCount = 1; if (m_descriptors[n]->hasFixedBinCount) {
--- a/transform/FeatureExtractionModelTransformer.h Mon Dec 02 11:17:24 2013 +0000 +++ b/transform/FeatureExtractionModelTransformer.h Wed Dec 04 18:29:15 2013 +0000 @@ -63,10 +63,11 @@ void createOutputModel(int n); - void addFeature(size_t blockFrame, + void addFeature(int n, + size_t blockFrame, const Vamp::Plugin::Feature &feature); - void setCompletion(int); + void setCompletion(int, int); void getFrames(int channelCount, long startFrame, long size, float **buffer);
--- a/transform/ModelTransformerFactory.cpp Mon Dec 02 11:17:24 2013 +0000 +++ b/transform/ModelTransformerFactory.cpp Wed Dec 04 18:29:15 2013 +0000 @@ -35,6 +35,8 @@ #include <QRegExp> +using std::vector; + ModelTransformerFactory * ModelTransformerFactory::m_instance = new ModelTransformerFactory; @@ -163,30 +165,30 @@ } ModelTransformer * -ModelTransformerFactory::createTransformer(const Transform &transform, +ModelTransformerFactory::createTransformer(const Transforms &transforms, const ModelTransformer::Input &input) { ModelTransformer *transformer = 0; - QString id = transform.getPluginIdentifier(); + QString id = transforms[0].getPluginIdentifier(); if (FeatureExtractionPluginFactory::instanceFor(id)) { transformer = - new FeatureExtractionModelTransformer(input, transform); + new FeatureExtractionModelTransformer(input, transforms, FeatureExtractionModelTransformer::FlexiNoteOutputModel); //!!! gross } else if (RealTimePluginFactory::instanceFor(id)) { transformer = - new RealTimeEffectModelTransformer(input, transform); + new RealTimeEffectModelTransformer(input, transforms[0]); } else { SVDEBUG << "ModelTransformerFactory::createTransformer: Unknown transform \"" - << transform.getIdentifier() << "\"" << endl; + << transforms[0].getIdentifier() << "\"" << endl; return transformer; } - if (transformer) transformer->setObjectName(transform.getIdentifier()); + if (transformer) transformer->setObjectName(transforms[0].getIdentifier()); return transformer; } @@ -197,37 +199,11 @@ { SVDEBUG << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << endl; - ModelTransformer *t = createTransformer(transform, input); - if (!t) return 0; - - connect(t, SIGNAL(finished()), this, SLOT(transformerFinished())); - - m_runningTransformers.insert(t); - - t->start(); - Model *model = t->detachOutputModel(); - - if (model) { - QString imn = input.getModel()->objectName(); - QString trn = - TransformFactory::getInstance()->getTransformFriendlyName - (transform.getIdentifier()); - if (imn != "") { - if (trn != "") { - model->setObjectName(tr("%1: %2").arg(imn).arg(trn)); - } else { - model->setObjectName(imn); - } - } else if (trn != "") { - model->setObjectName(trn); - } - } else { - t->wait(); - } - - message = t->getMessage(); - - return model; + Transforms transforms; + transforms.push_back(transform); + vector<Model *> mm = transformMultiple(transforms, input, message); + if (mm.empty()) return 0; + else return mm[0]; } vector<Model *> @@ -238,28 +214,30 @@ SVDEBUG << "ModelTransformerFactory::transformMultiple: Constructing transformer with input model " << input.getModel() << endl; ModelTransformer *t = createTransformer(transforms, input); - if (!t) return 0; + if (!t) return vector<Model *>(); connect(t, SIGNAL(finished()), this, SLOT(transformerFinished())); m_runningTransformers.insert(t); t->start(); - Model *model = t->detachOutputModel(); + vector<Model *> models = t->detachOutputModels(); - if (model) { + if (!models.empty()) { QString imn = input.getModel()->objectName(); QString trn = TransformFactory::getInstance()->getTransformFriendlyName - (transform.getIdentifier()); - if (imn != "") { - if (trn != "") { - model->setObjectName(tr("%1: %2").arg(imn).arg(trn)); - } else { - model->setObjectName(imn); + (transforms[0].getIdentifier()); + for (int i = 0; i < models.size(); ++i) { + if (imn != "") { + if (trn != "") { + models[i]->setObjectName(tr("%1: %2").arg(imn).arg(trn)); + } else { + models[i]->setObjectName(imn); + } + } else if (trn != "") { + models[i]->setObjectName(trn); } - } else if (trn != "") { - model->setObjectName(trn); } } else { t->wait(); @@ -267,7 +245,7 @@ message = t->getMessage(); - return model; + return models; } void @@ -306,8 +284,13 @@ ModelTransformer *t = *i; - if (t->getInputModel() == m || t->getOutputModel() == m) { + if (t->getInputModel() == m) { affected.insert(t); + } else { + vector<Model *> mm = t->getOutputModels(); + for (int i = 0; i < (int)mm.size(); ++i) { + if (mm[i] == m) affected.insert(t); + } } }
--- a/transform/ModelTransformerFactory.h Mon Dec 02 11:17:24 2013 +0000 +++ b/transform/ModelTransformerFactory.h Wed Dec 04 18:29:15 2013 +0000 @@ -119,7 +119,7 @@ void modelAboutToBeDeleted(Model *); protected: - ModelTransformer *createTransformer(const Transform &transform, + ModelTransformer *createTransformer(const Transforms &transforms, const ModelTransformer::Input &input); typedef std::map<TransformId, QString> TransformerConfigurationMap;
--- a/transform/RealTimeEffectModelTransformer.cpp Mon Dec 02 11:17:24 2013 +0000 +++ b/transform/RealTimeEffectModelTransformer.cpp Wed Dec 04 18:29:15 2013 +0000 @@ -30,10 +30,16 @@ #include <iostream> RealTimeEffectModelTransformer::RealTimeEffectModelTransformer(Input in, - const Transform &transform) : - ModelTransformer(in, transform), + const Transform &t) : + ModelTransformer(in, t), m_plugin(0) { + Transform transform(t); + if (!transform.getBlockSize()) { + transform.setBlockSize(1024); + m_transforms[0] = transform; + } + m_units = TransformFactory::getInstance()->getTransformUnits (transform.getIdentifier()); m_outputNo = @@ -41,8 +47,6 @@ QString pluginId = transform.getPluginIdentifier(); - if (!m_transform.getBlockSize()) m_transform.setBlockSize(1024); - // SVDEBUG << "RealTimeEffectModelTransformer::RealTimeEffectModelTransformer: plugin " << pluginId << ", output " << output << endl; RealTimePluginFactory *factory = @@ -59,16 +63,16 @@ m_plugin = factory->instantiatePlugin(pluginId, 0, 0, input->getSampleRate(), - m_transform.getBlockSize(), + transform.getBlockSize(), input->getChannelCount()); if (!m_plugin) { cerr << "RealTimeEffectModelTransformer: Failed to instantiate plugin \"" - << pluginId << "\"" << endl; + << pluginId << "\"" << endl; return; } - TransformFactory::getInstance()->setPluginParameters(m_transform, m_plugin); + TransformFactory::getInstance()->setPluginParameters(transform, m_plugin); if (m_outputNo >= 0 && m_outputNo >= int(m_plugin->getControlOutputCount())) { @@ -91,7 +95,7 @@ } else { SparseTimeValueModel *model = new SparseTimeValueModel - (input->getSampleRate(), m_transform.getBlockSize(), 0.0, 0.0, false); + (input->getSampleRate(), transform.getBlockSize(), 0.0, 0.0, false); if (m_units != "") model->setScaleUnits(m_units); @@ -143,9 +147,11 @@ long startFrame = m_input.getModel()->getStartFrame(); long endFrame = m_input.getModel()->getEndFrame(); + + Transform transform = m_transforms[0]; - RealTime contextStartRT = m_transform.getStartTime(); - RealTime contextDurationRT = m_transform.getDuration(); + RealTime contextStartRT = transform.getStartTime(); + RealTime contextDurationRT = transform.getDuration(); long contextStart = RealTime::realTime2Frame(contextStartRT, sampleRate);