# HG changeset patch # User Chris Cannam # Date 1477664458 -3600 # Node ID 5261a7791f1c4c37bf88e116d9eab3360c641cb2 # Parent a1b97df9962e0c39486748309bee4ad63a226157# Parent dd49630e0d7070276e33465db43269363df06c18 Merge from branch piper diff -r a1b97df9962e -r 5261a7791f1c base/Preferences.cpp --- a/base/Preferences.cpp Thu Oct 20 11:16:22 2016 +0100 +++ b/base/Preferences.cpp Fri Oct 28 15:20:58 2016 +0100 @@ -41,6 +41,7 @@ m_propertyBoxLayout(VerticallyStacked), m_windowType(HanningWindow), m_resampleQuality(1), + m_runPluginsInProcess(true), m_omitRecentTemps(true), m_tempDirRoot(""), m_fixedSampleRate(0), @@ -65,6 +66,7 @@ m_windowType = WindowType (settings.value("window-type", int(HanningWindow)).toInt()); m_resampleQuality = settings.value("resample-quality", 1).toInt(); + m_runPluginsInProcess = settings.value("run-vamp-plugins-in-process", true).toBool(); m_fixedSampleRate = settings.value("fixed-sample-rate", 0).toDouble(); m_resampleOnLoad = settings.value("resample-on-load", false).toBool(); m_normaliseAudio = settings.value("normalise-audio", false).toBool(); @@ -266,6 +268,10 @@ return m_resampleQuality; } + if (name == "Run Vamp Plugins In Process") { + return m_runPluginsInProcess; + } + if (name == "Omit Temporaries from Recent Files") { if (deflt) *deflt = 1; return m_omitRecentTemps ? 1 : 0; @@ -414,6 +420,8 @@ setWindowType(WindowType(value)); } else if (name == "Resample Quality") { setResampleQuality(value); + } else if (name == "Run Vamp Plugins In Process") { + setRunPluginsInProcess(value ? true : false); } else if (name == "Omit Temporaries from Recent Files") { setOmitTempsFromRecentFiles(value ? true : false); } else if (name == "Background Mode") { @@ -519,6 +527,19 @@ } void +Preferences::setRunPluginsInProcess(bool run) +{ + if (m_runPluginsInProcess != run) { + m_runPluginsInProcess = run; + QSettings settings; + settings.beginGroup("Preferences"); + settings.setValue("run-vamp-plugins-in-process", run); + settings.endGroup(); + emit propertyChanged("Run Vamp Plugins In Process"); + } +} + +void Preferences::setOmitTempsFromRecentFiles(bool omit) { if (m_omitRecentTemps != omit) { diff -r a1b97df9962e -r 5261a7791f1c base/Preferences.h --- a/base/Preferences.h Thu Oct 20 11:16:22 2016 +0100 +++ b/base/Preferences.h Fri Oct 28 15:20:58 2016 +0100 @@ -53,6 +53,8 @@ WindowType getWindowType() const { return m_windowType; } int getResampleQuality() const { return m_resampleQuality; } + bool getRunPluginsInProcess() const { return m_runPluginsInProcess; } + //!!! harmonise with PaneStack enum PropertyBoxLayout { VerticallyStacked, @@ -114,6 +116,7 @@ void setPropertyBoxLayout(PropertyBoxLayout layout); void setWindowType(WindowType type); void setResampleQuality(int quality); + void setRunPluginsInProcess(bool r); void setOmitTempsFromRecentFiles(bool omit); void setTemporaryDirectoryRoot(QString tempDirRoot); void setFixedSampleRate(sv_samplerate_t); @@ -151,6 +154,7 @@ PropertyBoxLayout m_propertyBoxLayout; WindowType m_windowType; int m_resampleQuality; + bool m_runPluginsInProcess; bool m_omitRecentTemps; QString m_tempDirRoot; sv_samplerate_t m_fixedSampleRate; diff -r a1b97df9962e -r 5261a7791f1c base/RealTime.cpp --- a/base/RealTime.cpp Thu Oct 20 11:16:22 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,480 +0,0 @@ -/* -*- 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. -*/ - -/* - This is a modified version of a source file from the - Rosegarden MIDI and audio sequencer and notation editor. - This file copyright 2000-2006 Chris Cannam. -*/ - -#include - -#include -#include - -#include "RealTime.h" - -#include "Debug.h" - -#include "Preferences.h" - -// A RealTime consists of two ints that must be at least 32 bits each. -// A signed 32-bit int can store values exceeding +/- 2 billion. This -// means we can safely use our lower int for nanoseconds, as there are -// 1 billion nanoseconds in a second and we need to handle double that -// because of the implementations of addition etc that we use. -// -// The maximum valid RealTime on a 32-bit system is somewhere around -// 68 years: 999999999 nanoseconds longer than the classic Unix epoch. - -#define ONE_BILLION 1000000000 - -RealTime::RealTime(int s, int n) : - sec(s), nsec(n) -{ - if (sec == 0) { - while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } - while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } - } else if (sec < 0) { - while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } - while (nsec > 0) { nsec -= ONE_BILLION; ++sec; } - } else { - while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } - while (nsec < 0) { nsec += ONE_BILLION; --sec; } - } -} - -RealTime -RealTime::fromSeconds(double sec) -{ - if (sec >= 0) { - return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5)); - } else { - return -fromSeconds(-sec); - } -} - -RealTime -RealTime::fromMilliseconds(int msec) -{ - return RealTime(msec / 1000, (msec % 1000) * 1000000); -} - -RealTime -RealTime::fromTimeval(const struct timeval &tv) -{ - return RealTime(int(tv.tv_sec), int(tv.tv_usec * 1000)); -} - -RealTime -RealTime::fromXsdDuration(std::string xsdd) -{ - RealTime t; - - int year = 0, month = 0, day = 0, hour = 0, minute = 0; - double second = 0.0; - - int i = 0; - - const char *s = xsdd.c_str(); - int len = int(xsdd.length()); - - bool negative = false, afterT = false; - - while (i < len) { - - if (s[i] == '-') { - if (i == 0) negative = true; - ++i; - continue; - } - - double value = 0.0; - char *eptr = 0; - - if (isdigit(s[i]) || s[i] == '.') { - value = strtod(&s[i], &eptr); - i = int(eptr - s); - } - - if (i == len) break; - - switch (s[i]) { - case 'Y': year = int(value + 0.1); break; - case 'D': day = int(value + 0.1); break; - case 'H': hour = int(value + 0.1); break; - case 'M': - if (afterT) minute = int(value + 0.1); - else month = int(value + 0.1); - break; - case 'S': - second = value; - break; - case 'T': afterT = true; break; - }; - - ++i; - } - - if (year > 0) { - cerr << "WARNING: This xsd:duration (\"" << xsdd << "\") contains a non-zero year.\nWith no origin and a limited data size, I will treat a year as exactly 31556952\nseconds and you should expect overflow and/or poor results." << endl; - t = t + RealTime(year * 31556952, 0); - } - - if (month > 0) { - cerr << "WARNING: This xsd:duration (\"" << xsdd << "\") contains a non-zero month.\nWith no origin and a limited data size, I will treat a month as exactly 2629746\nseconds and you should expect overflow and/or poor results." << endl; - t = t + RealTime(month * 2629746, 0); - } - - if (day > 0) { - t = t + RealTime(day * 86400, 0); - } - - if (hour > 0) { - t = t + RealTime(hour * 3600, 0); - } - - if (minute > 0) { - t = t + RealTime(minute * 60, 0); - } - - t = t + fromSeconds(second); - - if (negative) { - return -t; - } else { - return t; - } -} - -double -RealTime::toDouble() const -{ - double d = sec; - d += double(nsec) / double(ONE_BILLION); - return d; -} - -std::ostream &operator<<(std::ostream &out, const RealTime &rt) -{ - if (rt < RealTime::zeroTime) { - out << "-"; - } else { - out << " "; - } - - int s = (rt.sec < 0 ? -rt.sec : rt.sec); - int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec); - - out << s << "."; - - int nn(n); - if (nn == 0) out << "00000000"; - else while (nn < (ONE_BILLION / 10)) { - out << "0"; - nn *= 10; - } - - out << n << "R"; - return out; -} - -std::string -RealTime::toString(bool align) const -{ - std::stringstream out; - out << *this; - - std::string s = out.str(); - - if (!align && *this >= RealTime::zeroTime) { - // remove leading " " - s = s.substr(1, s.length() - 1); - } - - // remove trailing R - return s.substr(0, s.length() - 1); -} - -RealTime -RealTime::fromString(std::string s) -{ - bool negative = false; - int section = 0; - std::string ssec, snsec; - - for (size_t i = 0; i < s.length(); ++i) { - - char c = s[i]; - if (isspace(c)) continue; - - if (section == 0) { - - if (c == '-') negative = true; - else if (isdigit(c)) { section = 1; ssec += c; } - else if (c == '.') section = 2; - else break; - - } else if (section == 1) { - - if (c == '.') section = 2; - else if (isdigit(c)) ssec += c; - else break; - - } else if (section == 2) { - - if (isdigit(c)) snsec += c; - else break; - } - } - - while (snsec.length() < 8) snsec += '0'; - - int sec = atoi(ssec.c_str()); - int nsec = atoi(snsec.c_str()); - if (negative) sec = -sec; - -// SVDEBUG << "RealTime::fromString: string " << s << " -> " -// << sec << " sec, " << nsec << " nsec" << endl; - - return RealTime(sec, nsec); -} - -std::string -RealTime::toText(bool fixedDp) const -{ - if (*this < RealTime::zeroTime) return "-" + (-*this).toText(fixedDp); - - Preferences *p = Preferences::getInstance(); - bool hms = true; - - if (p) { - hms = p->getShowHMS(); - int fps = 0; - switch (p->getTimeToTextMode()) { - case Preferences::TimeToTextMs: break; - case Preferences::TimeToTextUs: fps = 1000000; break; - case Preferences::TimeToText24Frame: fps = 24; break; - case Preferences::TimeToText25Frame: fps = 25; break; - case Preferences::TimeToText30Frame: fps = 30; break; - case Preferences::TimeToText50Frame: fps = 50; break; - case Preferences::TimeToText60Frame: fps = 60; break; - } - if (fps != 0) return toFrameText(fps, hms); - } - - return toMSText(fixedDp, hms); -} - -static void -writeSecPart(std::stringstream &out, bool hms, int sec) -{ - if (hms) { - if (sec >= 3600) { - out << (sec / 3600) << ":"; - } - - if (sec >= 60) { - int minutes = (sec % 3600) / 60; - if (sec >= 3600 && minutes < 10) out << "0"; - out << minutes << ":"; - } - - if (sec >= 10) { - out << ((sec % 60) / 10); - } - - out << (sec % 10); - - } else { - out << sec; - } -} - -std::string -RealTime::toMSText(bool fixedDp, bool hms) const -{ - if (*this < RealTime::zeroTime) return "-" + (-*this).toMSText(fixedDp, hms); - - std::stringstream out; - - writeSecPart(out, hms, sec); - - int ms = msec(); - - if (ms != 0) { - out << "."; - out << (ms / 100); - ms = ms % 100; - if (ms != 0) { - out << (ms / 10); - ms = ms % 10; - } else if (fixedDp) { - out << "0"; - } - if (ms != 0) { - out << ms; - } else if (fixedDp) { - out << "0"; - } - } else if (fixedDp) { - out << ".000"; - } - - std::string s = out.str(); - - return s; -} - -std::string -RealTime::toFrameText(int fps, bool hms) const -{ - if (*this < RealTime::zeroTime) return "-" + (-*this).toFrameText(fps, hms); - - std::stringstream out; - - writeSecPart(out, hms, sec); - - // avoid rounding error if fps does not divide into ONE_BILLION - int64_t fbig = nsec; - fbig *= fps; - int f = int(fbig / ONE_BILLION); - - int div = 1; - int n = fps - 1; - while ((n = n / 10)) { - div *= 10; - } - - out << ":"; - -// cerr << "div = " << div << ", f = "<< f << endl; - - while (div) { - int d = (f / div) % 10; - out << d; - div /= 10; - } - - std::string s = out.str(); - -// cerr << "converted " << toString() << " to " << s << endl; - - return s; -} - -std::string -RealTime::toSecText() const -{ - if (*this < RealTime::zeroTime) return "-" + (-*this).toSecText(); - - std::stringstream out; - - writeSecPart(out, true, sec); - - if (sec < 60) { - out << "s"; - } - - std::string s = out.str(); - - return s; -} - -std::string -RealTime::toXsdDuration() const -{ - std::string s = "PT" + toString(false) + "S"; - return s; -} - -RealTime -RealTime::operator*(int m) const -{ - double t = (double(nsec) / ONE_BILLION) * m; - t += sec * m; - return fromSeconds(t); -} - -RealTime -RealTime::operator/(int d) const -{ - int secdiv = sec / d; - int secrem = sec % d; - - double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d; - - return RealTime(secdiv, int(nsecdiv + 0.5)); -} - -RealTime -RealTime::operator*(double m) const -{ - double t = (double(nsec) / ONE_BILLION) * m; - t += sec * m; - return fromSeconds(t); -} - -RealTime -RealTime::operator/(double d) const -{ - double t = (double(nsec) / ONE_BILLION) / d; - t += sec / d; - return fromSeconds(t); -} - -double -RealTime::operator/(const RealTime &r) const -{ - double lTotal = double(sec) * ONE_BILLION + double(nsec); - double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec); - - if (rTotal == 0) return 0.0; - else return lTotal/rTotal; -} - -static RealTime -frame2RealTime_i(sv_frame_t frame, sv_frame_t iSampleRate) -{ - if (frame < 0) return -frame2RealTime_i(-frame, iSampleRate); - - RealTime rt; - sv_frame_t sec = frame / iSampleRate; - rt.sec = int(sec); - frame -= sec * iSampleRate; - rt.nsec = (int)(((double(frame) * 1000000.0) / double(iSampleRate)) * 1000.0); - return rt; -} - -sv_frame_t -RealTime::realTime2Frame(const RealTime &time, sv_samplerate_t sampleRate) -{ - if (time < zeroTime) return -realTime2Frame(-time, sampleRate); - double s = time.sec + double(time.nsec + 1) / 1000000000.0; - return sv_frame_t(s * sampleRate); -} - -RealTime -RealTime::frame2RealTime(sv_frame_t frame, sv_samplerate_t sampleRate) -{ - if (sampleRate == double(int(sampleRate))) { - return frame2RealTime_i(frame, int(sampleRate)); - } - - double sec = double(frame) / sampleRate; - return fromSeconds(sec); -} - -const RealTime RealTime::zeroTime(0,0); - diff -r a1b97df9962e -r 5261a7791f1c base/RealTimeSV.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/RealTimeSV.cpp Fri Oct 28 15:20:58 2016 +0100 @@ -0,0 +1,480 @@ +/* -*- 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. +*/ + +/* + This is a modified version of a source file from the + Rosegarden MIDI and audio sequencer and notation editor. + This file copyright 2000-2006 Chris Cannam. +*/ + +#include + +#include +#include + +#include "RealTime.h" + +#include "Debug.h" + +#include "Preferences.h" + +// A RealTime consists of two ints that must be at least 32 bits each. +// A signed 32-bit int can store values exceeding +/- 2 billion. This +// means we can safely use our lower int for nanoseconds, as there are +// 1 billion nanoseconds in a second and we need to handle double that +// because of the implementations of addition etc that we use. +// +// The maximum valid RealTime on a 32-bit system is somewhere around +// 68 years: 999999999 nanoseconds longer than the classic Unix epoch. + +#define ONE_BILLION 1000000000 + +RealTime::RealTime(int s, int n) : + sec(s), nsec(n) +{ + if (sec == 0) { + while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } + while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } + } else if (sec < 0) { + while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } + while (nsec > 0) { nsec -= ONE_BILLION; ++sec; } + } else { + while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } + while (nsec < 0) { nsec += ONE_BILLION; --sec; } + } +} + +RealTime +RealTime::fromSeconds(double sec) +{ + if (sec >= 0) { + return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5)); + } else { + return -fromSeconds(-sec); + } +} + +RealTime +RealTime::fromMilliseconds(int msec) +{ + return RealTime(msec / 1000, (msec % 1000) * 1000000); +} + +RealTime +RealTime::fromTimeval(const struct timeval &tv) +{ + return RealTime(int(tv.tv_sec), int(tv.tv_usec * 1000)); +} + +RealTime +RealTime::fromXsdDuration(std::string xsdd) +{ + RealTime t; + + int year = 0, month = 0, day = 0, hour = 0, minute = 0; + double second = 0.0; + + int i = 0; + + const char *s = xsdd.c_str(); + int len = int(xsdd.length()); + + bool negative = false, afterT = false; + + while (i < len) { + + if (s[i] == '-') { + if (i == 0) negative = true; + ++i; + continue; + } + + double value = 0.0; + char *eptr = 0; + + if (isdigit(s[i]) || s[i] == '.') { + value = strtod(&s[i], &eptr); + i = int(eptr - s); + } + + if (i == len) break; + + switch (s[i]) { + case 'Y': year = int(value + 0.1); break; + case 'D': day = int(value + 0.1); break; + case 'H': hour = int(value + 0.1); break; + case 'M': + if (afterT) minute = int(value + 0.1); + else month = int(value + 0.1); + break; + case 'S': + second = value; + break; + case 'T': afterT = true; break; + }; + + ++i; + } + + if (year > 0) { + cerr << "WARNING: This xsd:duration (\"" << xsdd << "\") contains a non-zero year.\nWith no origin and a limited data size, I will treat a year as exactly 31556952\nseconds and you should expect overflow and/or poor results." << endl; + t = t + RealTime(year * 31556952, 0); + } + + if (month > 0) { + cerr << "WARNING: This xsd:duration (\"" << xsdd << "\") contains a non-zero month.\nWith no origin and a limited data size, I will treat a month as exactly 2629746\nseconds and you should expect overflow and/or poor results." << endl; + t = t + RealTime(month * 2629746, 0); + } + + if (day > 0) { + t = t + RealTime(day * 86400, 0); + } + + if (hour > 0) { + t = t + RealTime(hour * 3600, 0); + } + + if (minute > 0) { + t = t + RealTime(minute * 60, 0); + } + + t = t + fromSeconds(second); + + if (negative) { + return -t; + } else { + return t; + } +} + +double +RealTime::toDouble() const +{ + double d = sec; + d += double(nsec) / double(ONE_BILLION); + return d; +} + +std::ostream &operator<<(std::ostream &out, const RealTime &rt) +{ + if (rt < RealTime::zeroTime) { + out << "-"; + } else { + out << " "; + } + + int s = (rt.sec < 0 ? -rt.sec : rt.sec); + int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec); + + out << s << "."; + + int nn(n); + if (nn == 0) out << "00000000"; + else while (nn < (ONE_BILLION / 10)) { + out << "0"; + nn *= 10; + } + + out << n << "R"; + return out; +} + +std::string +RealTime::toString(bool align) const +{ + std::stringstream out; + out << *this; + + std::string s = out.str(); + + if (!align && *this >= RealTime::zeroTime) { + // remove leading " " + s = s.substr(1, s.length() - 1); + } + + // remove trailing R + return s.substr(0, s.length() - 1); +} + +RealTime +RealTime::fromString(std::string s) +{ + bool negative = false; + int section = 0; + std::string ssec, snsec; + + for (size_t i = 0; i < s.length(); ++i) { + + char c = s[i]; + if (isspace(c)) continue; + + if (section == 0) { + + if (c == '-') negative = true; + else if (isdigit(c)) { section = 1; ssec += c; } + else if (c == '.') section = 2; + else break; + + } else if (section == 1) { + + if (c == '.') section = 2; + else if (isdigit(c)) ssec += c; + else break; + + } else if (section == 2) { + + if (isdigit(c)) snsec += c; + else break; + } + } + + while (snsec.length() < 8) snsec += '0'; + + int sec = atoi(ssec.c_str()); + int nsec = atoi(snsec.c_str()); + if (negative) sec = -sec; + +// SVDEBUG << "RealTime::fromString: string " << s << " -> " +// << sec << " sec, " << nsec << " nsec" << endl; + + return RealTime(sec, nsec); +} + +std::string +RealTime::toText(bool fixedDp) const +{ + if (*this < RealTime::zeroTime) return "-" + (-*this).toText(fixedDp); + + Preferences *p = Preferences::getInstance(); + bool hms = true; + + if (p) { + hms = p->getShowHMS(); + int fps = 0; + switch (p->getTimeToTextMode()) { + case Preferences::TimeToTextMs: break; + case Preferences::TimeToTextUs: fps = 1000000; break; + case Preferences::TimeToText24Frame: fps = 24; break; + case Preferences::TimeToText25Frame: fps = 25; break; + case Preferences::TimeToText30Frame: fps = 30; break; + case Preferences::TimeToText50Frame: fps = 50; break; + case Preferences::TimeToText60Frame: fps = 60; break; + } + if (fps != 0) return toFrameText(fps, hms); + } + + return toMSText(fixedDp, hms); +} + +static void +writeSecPart(std::stringstream &out, bool hms, int sec) +{ + if (hms) { + if (sec >= 3600) { + out << (sec / 3600) << ":"; + } + + if (sec >= 60) { + int minutes = (sec % 3600) / 60; + if (sec >= 3600 && minutes < 10) out << "0"; + out << minutes << ":"; + } + + if (sec >= 10) { + out << ((sec % 60) / 10); + } + + out << (sec % 10); + + } else { + out << sec; + } +} + +std::string +RealTime::toMSText(bool fixedDp, bool hms) const +{ + if (*this < RealTime::zeroTime) return "-" + (-*this).toMSText(fixedDp, hms); + + std::stringstream out; + + writeSecPart(out, hms, sec); + + int ms = msec(); + + if (ms != 0) { + out << "."; + out << (ms / 100); + ms = ms % 100; + if (ms != 0) { + out << (ms / 10); + ms = ms % 10; + } else if (fixedDp) { + out << "0"; + } + if (ms != 0) { + out << ms; + } else if (fixedDp) { + out << "0"; + } + } else if (fixedDp) { + out << ".000"; + } + + std::string s = out.str(); + + return s; +} + +std::string +RealTime::toFrameText(int fps, bool hms) const +{ + if (*this < RealTime::zeroTime) return "-" + (-*this).toFrameText(fps, hms); + + std::stringstream out; + + writeSecPart(out, hms, sec); + + // avoid rounding error if fps does not divide into ONE_BILLION + int64_t fbig = nsec; + fbig *= fps; + int f = int(fbig / ONE_BILLION); + + int div = 1; + int n = fps - 1; + while ((n = n / 10)) { + div *= 10; + } + + out << ":"; + +// cerr << "div = " << div << ", f = "<< f << endl; + + while (div) { + int d = (f / div) % 10; + out << d; + div /= 10; + } + + std::string s = out.str(); + +// cerr << "converted " << toString() << " to " << s << endl; + + return s; +} + +std::string +RealTime::toSecText() const +{ + if (*this < RealTime::zeroTime) return "-" + (-*this).toSecText(); + + std::stringstream out; + + writeSecPart(out, true, sec); + + if (sec < 60) { + out << "s"; + } + + std::string s = out.str(); + + return s; +} + +std::string +RealTime::toXsdDuration() const +{ + std::string s = "PT" + toString(false) + "S"; + return s; +} + +RealTime +RealTime::operator*(int m) const +{ + double t = (double(nsec) / ONE_BILLION) * m; + t += sec * m; + return fromSeconds(t); +} + +RealTime +RealTime::operator/(int d) const +{ + int secdiv = sec / d; + int secrem = sec % d; + + double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d; + + return RealTime(secdiv, int(nsecdiv + 0.5)); +} + +RealTime +RealTime::operator*(double m) const +{ + double t = (double(nsec) / ONE_BILLION) * m; + t += sec * m; + return fromSeconds(t); +} + +RealTime +RealTime::operator/(double d) const +{ + double t = (double(nsec) / ONE_BILLION) / d; + t += sec / d; + return fromSeconds(t); +} + +double +RealTime::operator/(const RealTime &r) const +{ + double lTotal = double(sec) * ONE_BILLION + double(nsec); + double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec); + + if (rTotal == 0) return 0.0; + else return lTotal/rTotal; +} + +static RealTime +frame2RealTime_i(sv_frame_t frame, sv_frame_t iSampleRate) +{ + if (frame < 0) return -frame2RealTime_i(-frame, iSampleRate); + + RealTime rt; + sv_frame_t sec = frame / iSampleRate; + rt.sec = int(sec); + frame -= sec * iSampleRate; + rt.nsec = (int)(((double(frame) * 1000000.0) / double(iSampleRate)) * 1000.0); + return rt; +} + +sv_frame_t +RealTime::realTime2Frame(const RealTime &time, sv_samplerate_t sampleRate) +{ + if (time < zeroTime) return -realTime2Frame(-time, sampleRate); + double s = time.sec + double(time.nsec + 1) / 1000000000.0; + return sv_frame_t(s * sampleRate); +} + +RealTime +RealTime::frame2RealTime(sv_frame_t frame, sv_samplerate_t sampleRate) +{ + if (sampleRate == double(int(sampleRate))) { + return frame2RealTime_i(frame, int(sampleRate)); + } + + double sec = double(frame) / sampleRate; + return fromSeconds(sec); +} + +const RealTime RealTime::zeroTime(0,0); + diff -r a1b97df9962e -r 5261a7791f1c base/Resampler.cpp --- a/base/Resampler.cpp Thu Oct 20 11:16:22 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -/* -*- 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. -*/ - -/* - This is a modified version of a source file from the - Rubber Band audio timestretcher library. - This file copyright 2007 Chris Cannam. -*/ - -#include "Resampler.h" - -#include -#include - -#include - -#include - -#include "Debug.h" - -class Resampler::D -{ -public: - D(Quality quality, int channels, sv_frame_t chunkSize); - ~D(); - - sv_frame_t resample(float **in, float **out, - sv_frame_t incount, double ratio, - bool final); - - sv_frame_t resampleInterleaved(float *in, float *out, - sv_frame_t incount, double ratio, - bool final); - - void reset(); - -protected: - SRC_STATE *m_src; - float *m_iin; - float *m_iout; - int m_channels; - sv_frame_t m_iinsize; - sv_frame_t m_ioutsize; -}; - -Resampler::D::D(Quality quality, int channels, sv_frame_t chunkSize) : - m_src(0), - m_iin(0), - m_iout(0), - m_channels(channels), - m_iinsize(0), - m_ioutsize(0) -{ - int err = 0; - m_src = src_new(quality == Best ? SRC_SINC_BEST_QUALITY : - quality == Fastest ? SRC_LINEAR : - SRC_SINC_FASTEST, - channels, &err); - - //!!! check err, throw - - if (chunkSize > 0 && m_channels > 1) { - //!!! alignment? - m_iinsize = chunkSize * m_channels; - m_ioutsize = chunkSize * m_channels * 2; - m_iin = (float *)malloc(m_iinsize * sizeof(float)); - m_iout = (float *)malloc(m_ioutsize * sizeof(float)); - } -} - -Resampler::D::~D() -{ - src_delete(m_src); - if (m_iinsize > 0) { - free(m_iin); - } - if (m_ioutsize > 0) { - free(m_iout); - } -} - -sv_frame_t -Resampler::D::resample(float **in, float **out, - sv_frame_t incount, double ratio, - bool final) -{ - if (m_channels == 1) { - return resampleInterleaved(*in, *out, incount, ratio, final); - } - - sv_frame_t outcount = lrint(ceil(double(incount) * ratio)); - - if (incount * m_channels > m_iinsize) { - m_iinsize = incount * m_channels; - m_iin = (float *)realloc(m_iin, m_iinsize * sizeof(float)); - } - if (outcount * m_channels > m_ioutsize) { - m_ioutsize = outcount * m_channels; - m_iout = (float *)realloc(m_iout, m_ioutsize * sizeof(float)); - } - for (sv_frame_t i = 0; i < incount; ++i) { - for (int c = 0; c < m_channels; ++c) { - m_iin[i * m_channels + c] = in[c][i]; - } - } - - sv_frame_t gen = resampleInterleaved(m_iin, m_iout, incount, ratio, final); - - for (sv_frame_t i = 0; i < gen; ++i) { - for (int c = 0; c < m_channels; ++c) { - out[c][i] = m_iout[i * m_channels + c]; - } - } - - return gen; -} - -sv_frame_t -Resampler::D::resampleInterleaved(float *in, float *out, - sv_frame_t incount, double ratio, - bool final) -{ - SRC_DATA data; - - sv_frame_t outcount = lrint(ceil(double(incount) * ratio)); - - data.data_in = in; - data.data_out = out; - data.input_frames = incount; - data.output_frames = outcount; - data.src_ratio = ratio; - data.end_of_input = (final ? 1 : 0); - - int err = src_process(m_src, &data); - - if (err) { - cerr << "Resampler: ERROR: src_process returned error: " << - src_strerror(err) << endl; - return 0; - } - - if (data.input_frames_used != incount) { - cerr << "Resampler: NOTE: input_frames_used == " << data.input_frames_used << " (while incount = " << incount << ")" << endl; - } - - return data.output_frames_gen; -} - -void -Resampler::D::reset() -{ - src_reset(m_src); -} - -Resampler::Resampler(Quality quality, int channels, sv_frame_t chunkSize) -{ - m_d = new D(quality, channels, chunkSize); -} - -Resampler::~Resampler() -{ - delete m_d; -} - -sv_frame_t -Resampler::resample(float **in, float **out, - sv_frame_t incount, double ratio, - bool final) -{ - return m_d->resample(in, out, incount, ratio, final); -} - -sv_frame_t -Resampler::resampleInterleaved(float *in, float *out, - sv_frame_t incount, double ratio, - bool final) -{ - return m_d->resampleInterleaved(in, out, incount, ratio, final); -} - -void -Resampler::reset() -{ - m_d->reset(); -} - diff -r a1b97df9962e -r 5261a7791f1c base/ResamplerSV.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/ResamplerSV.cpp Fri Oct 28 15:20:58 2016 +0100 @@ -0,0 +1,196 @@ +/* -*- 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. +*/ + +/* + This is a modified version of a source file from the + Rubber Band audio timestretcher library. + This file copyright 2007 Chris Cannam. +*/ + +#include "Resampler.h" + +#include +#include + +#include + +#include + +#include "Debug.h" + +class Resampler::D +{ +public: + D(Quality quality, int channels, sv_frame_t chunkSize); + ~D(); + + sv_frame_t resample(float **in, float **out, + sv_frame_t incount, double ratio, + bool final); + + sv_frame_t resampleInterleaved(float *in, float *out, + sv_frame_t incount, double ratio, + bool final); + + void reset(); + +protected: + SRC_STATE *m_src; + float *m_iin; + float *m_iout; + int m_channels; + sv_frame_t m_iinsize; + sv_frame_t m_ioutsize; +}; + +Resampler::D::D(Quality quality, int channels, sv_frame_t chunkSize) : + m_src(0), + m_iin(0), + m_iout(0), + m_channels(channels), + m_iinsize(0), + m_ioutsize(0) +{ + int err = 0; + m_src = src_new(quality == Best ? SRC_SINC_BEST_QUALITY : + quality == Fastest ? SRC_LINEAR : + SRC_SINC_FASTEST, + channels, &err); + + //!!! check err, throw + + if (chunkSize > 0 && m_channels > 1) { + //!!! alignment? + m_iinsize = chunkSize * m_channels; + m_ioutsize = chunkSize * m_channels * 2; + m_iin = (float *)malloc(m_iinsize * sizeof(float)); + m_iout = (float *)malloc(m_ioutsize * sizeof(float)); + } +} + +Resampler::D::~D() +{ + src_delete(m_src); + if (m_iinsize > 0) { + free(m_iin); + } + if (m_ioutsize > 0) { + free(m_iout); + } +} + +sv_frame_t +Resampler::D::resample(float **in, float **out, + sv_frame_t incount, double ratio, + bool final) +{ + if (m_channels == 1) { + return resampleInterleaved(*in, *out, incount, ratio, final); + } + + sv_frame_t outcount = lrint(ceil(double(incount) * ratio)); + + if (incount * m_channels > m_iinsize) { + m_iinsize = incount * m_channels; + m_iin = (float *)realloc(m_iin, m_iinsize * sizeof(float)); + } + if (outcount * m_channels > m_ioutsize) { + m_ioutsize = outcount * m_channels; + m_iout = (float *)realloc(m_iout, m_ioutsize * sizeof(float)); + } + for (sv_frame_t i = 0; i < incount; ++i) { + for (int c = 0; c < m_channels; ++c) { + m_iin[i * m_channels + c] = in[c][i]; + } + } + + sv_frame_t gen = resampleInterleaved(m_iin, m_iout, incount, ratio, final); + + for (sv_frame_t i = 0; i < gen; ++i) { + for (int c = 0; c < m_channels; ++c) { + out[c][i] = m_iout[i * m_channels + c]; + } + } + + return gen; +} + +sv_frame_t +Resampler::D::resampleInterleaved(float *in, float *out, + sv_frame_t incount, double ratio, + bool final) +{ + SRC_DATA data; + + sv_frame_t outcount = lrint(ceil(double(incount) * ratio)); + + data.data_in = in; + data.data_out = out; + data.input_frames = incount; + data.output_frames = outcount; + data.src_ratio = ratio; + data.end_of_input = (final ? 1 : 0); + + int err = src_process(m_src, &data); + + if (err) { + cerr << "Resampler: ERROR: src_process returned error: " << + src_strerror(err) << endl; + return 0; + } + + if (data.input_frames_used != incount) { + cerr << "Resampler: NOTE: input_frames_used == " << data.input_frames_used << " (while incount = " << incount << ")" << endl; + } + + return data.output_frames_gen; +} + +void +Resampler::D::reset() +{ + src_reset(m_src); +} + +Resampler::Resampler(Quality quality, int channels, sv_frame_t chunkSize) +{ + m_d = new D(quality, channels, chunkSize); +} + +Resampler::~Resampler() +{ + delete m_d; +} + +sv_frame_t +Resampler::resample(float **in, float **out, + sv_frame_t incount, double ratio, + bool final) +{ + return m_d->resample(in, out, incount, ratio, final); +} + +sv_frame_t +Resampler::resampleInterleaved(float *in, float *out, + sv_frame_t incount, double ratio, + bool final) +{ + return m_d->resampleInterleaved(in, out, incount, ratio, final); +} + +void +Resampler::reset() +{ + m_d->reset(); +} + diff -r a1b97df9962e -r 5261a7791f1c data/model/SparseModel.h --- a/data/model/SparseModel.h Thu Oct 20 11:16:22 2016 +0100 +++ b/data/model/SparseModel.h Fri Oct 28 15:20:58 2016 +0100 @@ -730,8 +730,8 @@ { QMutexLocker locker(&m_mutex); m_resolution = resolution; + m_rows.clear(); } - m_rows.clear(); emit modelChanged(); } @@ -743,8 +743,8 @@ QMutexLocker locker(&m_mutex); m_points.clear(); m_pointCount = 0; + m_rows.clear(); } - m_rows.clear(); emit modelChanged(); } @@ -752,12 +752,11 @@ void SparseModel::addPoint(const PointType &point) { - { - QMutexLocker locker(&m_mutex); - m_points.insert(point); - m_pointCount++; - if (point.getLabel() != "") m_hasTextLabels = true; - } + QMutexLocker locker(&m_mutex); + + m_points.insert(point); + m_pointCount++; + if (point.getLabel() != "") m_hasTextLabels = true; // Even though this model is nominally sparse, there may still be // too many signals going on here (especially as they'll probably @@ -784,18 +783,16 @@ bool SparseModel::containsPoint(const PointType &point) { - { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_mutex); - PointListIterator i = m_points.lower_bound(point); - typename PointType::Comparator comparator; - while (i != m_points.end()) { - if (i->frame > point.frame) break; - if (!comparator(*i, point) && !comparator(point, *i)) { - return true; - } - ++i; - } + PointListIterator i = m_points.lower_bound(point); + typename PointType::Comparator comparator; + while (i != m_points.end()) { + if (i->frame > point.frame) break; + if (!comparator(*i, point) && !comparator(point, *i)) { + return true; + } + ++i; } return false; @@ -805,21 +802,20 @@ void SparseModel::deletePoint(const PointType &point) { - { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_mutex); - PointListIterator i = m_points.lower_bound(point); - typename PointType::Comparator comparator; - while (i != m_points.end()) { - if (i->frame > point.frame) break; - if (!comparator(*i, point) && !comparator(point, *i)) { - m_points.erase(i); - m_pointCount--; - break; + PointListIterator i = m_points.lower_bound(point); + typename PointType::Comparator comparator; + while (i != m_points.end()) { + if (i->frame > point.frame) break; + if (!comparator(*i, point) && !comparator(point, *i)) { + m_points.erase(i); + m_pointCount--; + break; } - ++i; - } + ++i; } + // std::cout << "SparseOneDimensionalModel: emit modelChanged(" // << point.frame << ")" << std::endl; m_rows.clear(); //!!! inefficient @@ -832,6 +828,8 @@ { // std::cerr << "SparseModel::setCompletion(" << completion << ")" << std::endl; + QMutexLocker locker(&m_mutex); + if (m_completion != completion) { m_completion = completion; diff -r a1b97df9962e -r 5261a7791f1c files.pri --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/files.pri Fri Oct 28 15:20:58 2016 +0100 @@ -0,0 +1,247 @@ +SVCORE_HEADERS = \ + base/AudioLevel.h \ + base/AudioPlaySource.h \ + base/BaseTypes.h \ + base/Clipboard.h \ + base/ColumnOp.h \ + base/Command.h \ + base/Debug.h \ + base/Exceptions.h \ + base/LogRange.h \ + base/MagnitudeRange.h \ + base/Pitch.h \ + base/Playable.h \ + base/PlayParameterRepository.h \ + base/PlayParameters.h \ + base/Preferences.h \ + base/Profiler.h \ + base/ProgressPrinter.h \ + base/ProgressReporter.h \ + base/PropertyContainer.h \ + base/RangeMapper.h \ + base/RealTime.h \ + base/RecentFiles.h \ + base/Resampler.h \ + base/ResourceFinder.h \ + base/RingBuffer.h \ + base/Scavenger.h \ + base/Selection.h \ + base/Serialiser.h \ + base/StorageAdviser.h \ + base/StringBits.h \ + base/Strings.h \ + base/TempDirectory.h \ + base/TempWriteFile.h \ + base/TextMatcher.h \ + base/Thread.h \ + base/UnitDatabase.h \ + base/ViewManagerBase.h \ + base/Window.h \ + base/XmlExportable.h \ + base/ZoomConstraint.h \ + data/fft/FFTapi.h \ + data/fileio/AudioFileReader.h \ + data/fileio/AudioFileReaderFactory.h \ + data/fileio/AudioFileSizeEstimator.h \ + data/fileio/BZipFileDevice.h \ + data/fileio/CachedFile.h \ + data/fileio/CodedAudioFileReader.h \ + data/fileio/CSVFileReader.h \ + data/fileio/CSVFileWriter.h \ + data/fileio/CSVFormat.h \ + data/fileio/DataFileReader.h \ + data/fileio/DataFileReaderFactory.h \ + data/fileio/FileFinder.h \ + data/fileio/FileReadThread.h \ + data/fileio/FileSource.h \ + data/fileio/MIDIFileReader.h \ + data/fileio/MIDIFileWriter.h \ + data/fileio/MP3FileReader.h \ + data/fileio/OggVorbisFileReader.h \ + data/fileio/PlaylistFileReader.h \ + data/fileio/QuickTimeFileReader.h \ + data/fileio/CoreAudioFileReader.h \ + data/fileio/DecodingWavFileReader.h \ + data/fileio/WavFileReader.h \ + data/fileio/WavFileWriter.h \ + data/midi/MIDIEvent.h \ + data/midi/MIDIInput.h \ + data/midi/rtmidi/RtError.h \ + data/midi/rtmidi/RtMidi.h \ + data/model/AggregateWaveModel.h \ + data/model/AlignmentModel.h \ + data/model/Dense3DModelPeakCache.h \ + data/model/DenseThreeDimensionalModel.h \ + data/model/DenseTimeValueModel.h \ + data/model/EditableDenseThreeDimensionalModel.h \ + data/model/FFTModel.h \ + data/model/ImageModel.h \ + data/model/IntervalModel.h \ + data/model/Labeller.h \ + data/model/Model.h \ + data/model/ModelDataTableModel.h \ + data/model/NoteModel.h \ + data/model/FlexiNoteModel.h \ + data/model/PathModel.h \ + data/model/PowerOfSqrtTwoZoomConstraint.h \ + data/model/PowerOfTwoZoomConstraint.h \ + data/model/RangeSummarisableTimeValueModel.h \ + data/model/RegionModel.h \ + data/model/SparseModel.h \ + data/model/SparseOneDimensionalModel.h \ + data/model/SparseTimeValueModel.h \ + data/model/SparseValueModel.h \ + data/model/TabularModel.h \ + data/model/TextModel.h \ + data/model/WaveFileModel.h \ + data/model/ReadOnlyWaveFileModel.h \ + data/model/WritableWaveFileModel.h \ + data/osc/OSCMessage.h \ + data/osc/OSCQueue.h \ + plugin/PluginScan.h \ + plugin/DSSIPluginFactory.h \ + plugin/DSSIPluginInstance.h \ + plugin/FeatureExtractionPluginFactory.h \ + plugin/LADSPAPluginFactory.h \ + plugin/LADSPAPluginInstance.h \ + plugin/NativeVampPluginFactory.h \ + plugin/PiperVampPluginFactory.h \ + plugin/PluginIdentifier.h \ + plugin/PluginXml.h \ + plugin/RealTimePluginFactory.h \ + plugin/RealTimePluginInstance.h \ + plugin/api/dssi.h \ + plugin/api/ladspa.h \ + plugin/plugins/SamplePlayer.h \ + plugin/api/alsa/asoundef.h \ + plugin/api/alsa/asoundlib.h \ + plugin/api/alsa/seq.h \ + plugin/api/alsa/seq_event.h \ + plugin/api/alsa/seq_midi_event.h \ + plugin/api/alsa/sound/asequencer.h \ + rdf/PluginRDFIndexer.h \ + rdf/PluginRDFDescription.h \ + rdf/RDFExporter.h \ + rdf/RDFFeatureWriter.h \ + rdf/RDFImporter.h \ + rdf/RDFTransformFactory.h \ + system/Init.h \ + system/System.h \ + transform/CSVFeatureWriter.h \ + transform/FeatureExtractionModelTransformer.h \ + transform/FeatureWriter.h \ + transform/FileFeatureWriter.h \ + transform/RealTimeEffectModelTransformer.h \ + transform/Transform.h \ + transform/TransformDescription.h \ + transform/TransformFactory.h \ + transform/ModelTransformer.h \ + transform/ModelTransformerFactory.h + +SVCORE_SOURCES = \ + base/AudioLevel.cpp \ + base/Clipboard.cpp \ + base/Command.cpp \ + base/Debug.cpp \ + base/Exceptions.cpp \ + base/LogRange.cpp \ + base/Pitch.cpp \ + base/PlayParameterRepository.cpp \ + base/PlayParameters.cpp \ + base/Preferences.cpp \ + base/Profiler.cpp \ + base/ProgressPrinter.cpp \ + base/ProgressReporter.cpp \ + base/PropertyContainer.cpp \ + base/RangeMapper.cpp \ + base/RealTimeSV.cpp \ + base/RecentFiles.cpp \ + base/ResamplerSV.cpp \ + base/ResourceFinder.cpp \ + base/Selection.cpp \ + base/Serialiser.cpp \ + base/StorageAdviser.cpp \ + base/StringBits.cpp \ + base/Strings.cpp \ + base/TempDirectory.cpp \ + base/TempWriteFile.cpp \ + base/TextMatcher.cpp \ + base/Thread.cpp \ + base/UnitDatabase.cpp \ + base/ViewManagerBase.cpp \ + base/XmlExportable.cpp \ + data/fft/FFTapi.cpp \ + data/fileio/AudioFileReader.cpp \ + data/fileio/AudioFileReaderFactory.cpp \ + data/fileio/AudioFileSizeEstimator.cpp \ + data/fileio/BZipFileDevice.cpp \ + data/fileio/CachedFile.cpp \ + data/fileio/CodedAudioFileReader.cpp \ + data/fileio/CSVFileReader.cpp \ + data/fileio/CSVFileWriter.cpp \ + data/fileio/CSVFormat.cpp \ + data/fileio/DataFileReaderFactory.cpp \ + data/fileio/FileReadThread.cpp \ + data/fileio/FileSource.cpp \ + data/fileio/MIDIFileReader.cpp \ + data/fileio/MIDIFileWriter.cpp \ + data/fileio/MP3FileReader.cpp \ + data/fileio/OggVorbisFileReader.cpp \ + data/fileio/PlaylistFileReader.cpp \ + data/fileio/QuickTimeFileReader.cpp \ + data/fileio/CoreAudioFileReader.cpp \ + data/fileio/DecodingWavFileReader.cpp \ + data/fileio/WavFileReader.cpp \ + data/fileio/WavFileWriter.cpp \ + data/midi/MIDIInput.cpp \ + data/midi/rtmidi/RtMidi.cpp \ + data/model/AggregateWaveModel.cpp \ + data/model/AlignmentModel.cpp \ + data/model/Dense3DModelPeakCache.cpp \ + data/model/DenseTimeValueModel.cpp \ + data/model/EditableDenseThreeDimensionalModel.cpp \ + data/model/FFTModel.cpp \ + data/model/Model.cpp \ + data/model/ModelDataTableModel.cpp \ + data/model/PowerOfSqrtTwoZoomConstraint.cpp \ + data/model/PowerOfTwoZoomConstraint.cpp \ + data/model/RangeSummarisableTimeValueModel.cpp \ + data/model/WaveFileModel.cpp \ + data/model/ReadOnlyWaveFileModel.cpp \ + data/model/WritableWaveFileModel.cpp \ + data/osc/OSCMessage.cpp \ + data/osc/OSCQueue.cpp \ + plugin/PluginScan.cpp \ + plugin/DSSIPluginFactory.cpp \ + plugin/DSSIPluginInstance.cpp \ + plugin/FeatureExtractionPluginFactory.cpp \ + plugin/LADSPAPluginFactory.cpp \ + plugin/LADSPAPluginInstance.cpp \ + plugin/NativeVampPluginFactory.cpp \ + plugin/PiperVampPluginFactory.cpp \ + plugin/PluginIdentifier.cpp \ + plugin/PluginXml.cpp \ + plugin/RealTimePluginFactory.cpp \ + plugin/RealTimePluginInstance.cpp \ + plugin/plugins/SamplePlayer.cpp \ + rdf/PluginRDFIndexer.cpp \ + rdf/PluginRDFDescription.cpp \ + rdf/RDFExporter.cpp \ + rdf/RDFFeatureWriter.cpp \ + rdf/RDFImporter.cpp \ + rdf/RDFTransformFactory.cpp \ + system/Init.cpp \ + system/System.cpp \ + transform/CSVFeatureWriter.cpp \ + transform/FeatureExtractionModelTransformer.cpp \ + transform/FileFeatureWriter.cpp \ + transform/RealTimeEffectModelTransformer.cpp \ + transform/Transform.cpp \ + transform/TransformFactory.cpp \ + transform/ModelTransformer.cpp \ + transform/ModelTransformerFactory.cpp + +!linux* { + SVCORE_SOURCES += plugin/api/dssi_alsa_compat.c +} + diff -r a1b97df9962e -r 5261a7791f1c plugin/FeatureExtractionPluginFactory.cpp --- a/plugin/FeatureExtractionPluginFactory.cpp Thu Oct 20 11:16:22 2016 +0100 +++ b/plugin/FeatureExtractionPluginFactory.cpp Fri Oct 28 15:20:58 2016 +0100 @@ -4,7 +4,7 @@ Sonic Visualiser An audio file viewer and annotation editor. Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam and QMUL. + This file copyright 2006-2016 Chris Cannam and QMUL. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -13,423 +13,32 @@ COPYING included with this distribution for more information. */ -#include "FeatureExtractionPluginFactory.h" -#include "PluginIdentifier.h" +#include "PiperVampPluginFactory.h" +#include "NativeVampPluginFactory.h" -#include -#include +#include +#include -#include "system/System.h" - -#include "PluginScan.h" - -#include -#include -#include -#include - -#include - -#include "base/Profiler.h" - -using namespace std; - -//#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 - -class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper { -public: - PluginDeletionNotifyAdapter(Vamp::Plugin *plugin, - FeatureExtractionPluginFactory *factory) : - PluginWrapper(plugin), m_factory(factory) { } - virtual ~PluginDeletionNotifyAdapter(); -protected: - FeatureExtractionPluginFactory *m_factory; -}; - -PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter() -{ - // see notes in vamp-sdk/hostext/PluginLoader.cpp from which this is drawn - Vamp::Plugin *p = m_plugin; - delete m_plugin; - m_plugin = 0; - // acceptable use after free here, as pluginDeleted uses p only as - // pointer key and does not deref it - if (m_factory) m_factory->pluginDeleted(p); -} - -static FeatureExtractionPluginFactory *_nativeInstance = 0; +#include "base/Preferences.h" FeatureExtractionPluginFactory * -FeatureExtractionPluginFactory::instance(QString pluginType) +FeatureExtractionPluginFactory::instance() { - if (pluginType == "vamp") { - if (!_nativeInstance) { -// SVDEBUG << "FeatureExtractionPluginFactory::instance(" << pluginType// << "): creating new FeatureExtractionPluginFactory" << endl; - _nativeInstance = new FeatureExtractionPluginFactory(); - } - return _nativeInstance; - } + static QMutex mutex; + static FeatureExtractionPluginFactory *instance = 0; - else return 0; -} + QMutexLocker locker(&mutex); + + if (!instance) { -FeatureExtractionPluginFactory * -FeatureExtractionPluginFactory::instanceFor(QString identifier) -{ - QString type, soName, label; - PluginIdentifier::parseIdentifier(identifier, type, soName, label); - return instance(type); -} - -vector -FeatureExtractionPluginFactory::getPluginPath() -{ - if (!m_pluginPath.empty()) return m_pluginPath; - - vector p = Vamp::PluginHostAdapter::getPluginPath(); - for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str()); - return m_pluginPath; -} - -vector -FeatureExtractionPluginFactory::getAllPluginIdentifiers() -{ - FeatureExtractionPluginFactory *factory; - vector rv; - - factory = instance("vamp"); - if (factory) { - vector tmp = factory->getPluginIdentifiers(); - for (size_t i = 0; i < tmp.size(); ++i) { -// cerr << "identifier: " << tmp[i] << endl; - rv.push_back(tmp[i]); - } - } - - // Plugins can change the locale, revert it to default. - RestoreStartupLocale(); - - return rv; -} - -vector -FeatureExtractionPluginFactory::getPluginIdentifiers() -{ - Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers"); - - vector rv; - - QStringList candidates = PluginScan::getInstance()->getCandidateLibrariesFor - (PluginScan::VampPlugin); - - for (QString soname : candidates) { - - void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL); - - if (!libraryHandle) { - cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname << ": " << DLERROR() << endl; - continue; - } - - VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) - DLSYM(libraryHandle, "vampGetPluginDescriptor"); - - if (!fn) { - cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname << endl; - if (DLCLOSE(libraryHandle) != 0) { - cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl; - } - continue; - } - -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Vamp descriptor found" << endl; -#endif - - const VampPluginDescriptor *descriptor = 0; - int index = 0; - - map known; - bool ok = true; - - while ((descriptor = fn(VAMP_API_VERSION, index))) { - - if (known.find(descriptor->identifier) != known.end()) { - cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Plugin library " - << soname - << " returns the same plugin identifier \"" - << descriptor->identifier << "\" at indices " - << known[descriptor->identifier] << " and " - << index << endl; - cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << endl; - ok = false; - break; - } else { - known[descriptor->identifier] = index; - } - - ++index; - } - - if (ok) { - - index = 0; - - while ((descriptor = fn(VAMP_API_VERSION, index))) { - - QString id = PluginIdentifier::createIdentifier - ("vamp", soname, descriptor->identifier); - rv.push_back(id); -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Found plugin id " << id << " at index " << index << endl; -#endif - ++index; - } - } - - if (DLCLOSE(libraryHandle) != 0) { - cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl; + if (Preferences::getInstance()->getRunPluginsInProcess()) { + cerr << "creating native instance" << endl; + instance = new NativeVampPluginFactory(); + } else { + cerr << "creating piper instance" << endl; + instance = new PiperVampPluginFactory(); } } - generateTaxonomy(); - - return rv; + return instance; } - -QString -FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir) -{ - QString file = ""; - -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "FeatureExtractionPluginFactory::findPluginFile(\"" - << soname << "\", \"" << inDir << "\")" - << endl; -#endif - - if (inDir != "") { - - QDir dir(inDir, PLUGIN_GLOB, - QDir::Name | QDir::IgnoreCase, - QDir::Files | QDir::Readable); - if (!dir.exists()) return ""; - - file = dir.filePath(QFileInfo(soname).fileName()); - - if (QFileInfo(file).exists() && QFileInfo(file).isFile()) { - -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "FeatureExtractionPluginFactory::findPluginFile: " - << "found trivially at " << file << endl; -#endif - - return file; - } - - for (unsigned int j = 0; j < dir.count(); ++j) { - file = dir.filePath(dir[j]); - if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) { - -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "FeatureExtractionPluginFactory::findPluginFile: " - << "found \"" << soname << "\" at " << file << endl; -#endif - - return file; - } - } - -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "FeatureExtractionPluginFactory::findPluginFile (with dir): " - << "not found" << endl; -#endif - - return ""; - - } else { - - QFileInfo fi(soname); - - if (fi.isAbsolute() && fi.exists() && fi.isFile()) { -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "FeatureExtractionPluginFactory::findPluginFile: " - << "found trivially at " << soname << endl; -#endif - return soname; - } - - if (fi.isAbsolute() && fi.absolutePath() != "") { - file = findPluginFile(soname, fi.absolutePath()); - if (file != "") return file; - } - - vector path = getPluginPath(); - for (vector::iterator i = path.begin(); - i != path.end(); ++i) { - if (*i != "") { - file = findPluginFile(soname, *i); - if (file != "") return file; - } - } - -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "FeatureExtractionPluginFactory::findPluginFile: " - << "not found" << endl; -#endif - - return ""; - } -} - -Vamp::Plugin * -FeatureExtractionPluginFactory::instantiatePlugin(QString identifier, - sv_samplerate_t inputSampleRate) -{ - Profiler profiler("FeatureExtractionPluginFactory::instantiatePlugin"); - - Vamp::Plugin *rv = 0; - Vamp::PluginHostAdapter *plugin = 0; - - const VampPluginDescriptor *descriptor = 0; - int index = 0; - - QString type, soname, label; - PluginIdentifier::parseIdentifier(identifier, type, soname, label); - if (type != "vamp") { -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type << endl; -#endif - return 0; - } - - QString found = findPluginFile(soname); - - if (found == "") { - cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname << endl; - return 0; - } else if (found != soname) { - -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Given library name was " << soname << ", found at " << found << endl; - cerr << soname << " -> " << found << endl; -#endif - - } - - soname = found; - - void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL); - - if (!libraryHandle) { - cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname << ": " << DLERROR() << endl; - return 0; - } - - VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) - DLSYM(libraryHandle, "vampGetPluginDescriptor"); - - if (!fn) { - cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname << endl; - goto done; - } - - while ((descriptor = fn(VAMP_API_VERSION, index))) { - if (label == descriptor->identifier) break; - ++index; - } - - if (!descriptor) { - cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label << "\" in library " << soname << endl; - goto done; - } - - plugin = new Vamp::PluginHostAdapter(descriptor, float(inputSampleRate)); - - if (plugin) { - m_handleMap[plugin] = libraryHandle; - rv = new PluginDeletionNotifyAdapter(plugin, this); - } - -// SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << endl; - - //!!! need to dlclose() when plugins from a given library are unloaded - -done: - if (!rv) { - if (DLCLOSE(libraryHandle) != 0) { - cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname << endl; - } - } - -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Instantiated plugin " << label << " from library " << soname << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << endl; -#endif - - return rv; -} - -void -FeatureExtractionPluginFactory::pluginDeleted(Vamp::Plugin *plugin) -{ - void *handle = m_handleMap[plugin]; - if (handle) { -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "unloading library " << handle << " for plugin " << plugin << endl; -#endif - DLCLOSE(handle); - } - m_handleMap.erase(plugin); -} - -QString -FeatureExtractionPluginFactory::getPluginCategory(QString identifier) -{ - return m_taxonomy[identifier]; -} - -void -FeatureExtractionPluginFactory::generateTaxonomy() -{ - vector pluginPath = getPluginPath(); - vector path; - - for (size_t i = 0; i < pluginPath.size(); ++i) { - if (pluginPath[i].contains("/lib/")) { - QString p(pluginPath[i]); - path.push_back(p); - p.replace("/lib/", "/share/"); - path.push_back(p); - } - path.push_back(pluginPath[i]); - } - - for (size_t i = 0; i < path.size(); ++i) { - - QDir dir(path[i], "*.cat"); - -// SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << endl; - for (unsigned int j = 0; j < dir.count(); ++j) { - - QFile file(path[i] + "/" + dir[j]); - -// SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i]+ "/" + dir[j]) << endl; - - if (file.open(QIODevice::ReadOnly)) { -// cerr << "...opened" << endl; - QTextStream stream(&file); - QString line; - - while (!stream.atEnd()) { - line = stream.readLine(); -// cerr << "line is: \"" << line << "\"" << endl; - QString id = PluginIdentifier::canonicalise - (line.section("::", 0, 0)); - QString cat = line.section("::", 1, 1); - m_taxonomy[id] = cat; -// cerr << "FeatureExtractionPluginFactory: set id \"" << id << "\" to cat \"" << cat << "\"" << endl; - } - } - } - } -} diff -r a1b97df9962e -r 5261a7791f1c plugin/FeatureExtractionPluginFactory.h --- a/plugin/FeatureExtractionPluginFactory.h Thu Oct 20 11:16:22 2016 +0100 +++ b/plugin/FeatureExtractionPluginFactory.h Fri Oct 28 15:20:58 2016 +0100 @@ -4,7 +4,7 @@ Sonic Visualiser An audio file viewer and annotation editor. Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. + This file copyright 2006-2016 Chris Cannam and QMUL. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -13,52 +13,55 @@ COPYING included with this distribution for more information. */ -#ifndef _FEATURE_EXTRACTION_PLUGIN_FACTORY_H_ -#define _FEATURE_EXTRACTION_PLUGIN_FACTORY_H_ - -#include -#include -#include +#ifndef SV_FEATURE_EXTRACTION_PLUGIN_FACTORY_H +#define SV_FEATURE_EXTRACTION_PLUGIN_FACTORY_H #include -#include "base/Debug.h" +#include "vamp-support/PluginStaticData.h" + #include "base/BaseTypes.h" +#include + class FeatureExtractionPluginFactory { public: + static FeatureExtractionPluginFactory *instance(); + virtual ~FeatureExtractionPluginFactory() { } - static FeatureExtractionPluginFactory *instance(QString pluginType); - static FeatureExtractionPluginFactory *instanceFor(QString identifier); - static std::vector getAllPluginIdentifiers(); + /** + * Return all installed plugin identifiers. + */ + virtual std::vector getPluginIdentifiers(QString &errorMessage) { + return instance()->getPluginIdentifiers(errorMessage); + } - virtual std::vector getPluginPath(); + /** + * Return static data for the given plugin. + */ + virtual piper_vamp::PluginStaticData getPluginStaticData(QString identifier) { + return instance()->getPluginStaticData(identifier); + } - virtual std::vector getPluginIdentifiers(); - - virtual QString findPluginFile(QString soname, QString inDir = ""); - - // We don't set blockSize or channels on this -- they're - // negotiated and handled via initialize() on the plugin + /** + * Instantiate (load) and return pointer to the plugin with the + * given identifier, at the given sample rate. We don't set + * blockSize or channels on this -- they're negotiated and handled + * via initialize() on the plugin itself after loading. + */ virtual Vamp::Plugin *instantiatePlugin(QString identifier, - sv_samplerate_t inputSampleRate); + sv_samplerate_t inputSampleRate) { + return instance()->instantiatePlugin(identifier, inputSampleRate); + } /** * Get category metadata about a plugin (without instantiating it). */ - virtual QString getPluginCategory(QString identifier); - -protected: - std::vector m_pluginPath; - std::map m_taxonomy; - - friend class PluginDeletionNotifyAdapter; - void pluginDeleted(Vamp::Plugin *); - std::map m_handleMap; - - void generateTaxonomy(); + virtual QString getPluginCategory(QString identifier) { + return instance()->getPluginCategory(identifier); + } }; #endif diff -r a1b97df9962e -r 5261a7791f1c plugin/NativeVampPluginFactory.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/NativeVampPluginFactory.cpp Fri Oct 28 15:20:58 2016 +0100 @@ -0,0 +1,432 @@ +/* -*- 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 2006-2016 Chris Cannam and 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 "NativeVampPluginFactory.h" +#include "PluginIdentifier.h" + +#include +#include + +#include "system/System.h" + +#include "PluginScan.h" + +#include +#include +#include +#include + +#include + +#include "base/Profiler.h" + +#include +#include + +using namespace std; + +//#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 + +class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper { +public: + PluginDeletionNotifyAdapter(Vamp::Plugin *plugin, + NativeVampPluginFactory *factory) : + PluginWrapper(plugin), m_factory(factory) { } + virtual ~PluginDeletionNotifyAdapter(); +protected: + NativeVampPluginFactory *m_factory; +}; + +PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter() +{ + // see notes in vamp-sdk/hostext/PluginLoader.cpp from which this is drawn + Vamp::Plugin *p = m_plugin; + delete m_plugin; + m_plugin = 0; + // acceptable use after free here, as pluginDeleted uses p only as + // pointer key and does not deref it + if (m_factory) m_factory->pluginDeleted(p); +} + +vector +NativeVampPluginFactory::getPluginPath() +{ + if (!m_pluginPath.empty()) return m_pluginPath; + + vector p = Vamp::PluginHostAdapter::getPluginPath(); + for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str()); + return m_pluginPath; +} + +vector +NativeVampPluginFactory::getPluginIdentifiers(QString &) +{ + Profiler profiler("NativeVampPluginFactory::getPluginIdentifiers"); + + QMutexLocker locker(&m_mutex); + + if (!m_identifiers.empty()) { + return m_identifiers; + } + + QStringList candidates = PluginScan::getInstance()->getCandidateLibrariesFor + (PluginScan::VampPlugin); + + for (QString soname : candidates) { + + void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL); + + if (!libraryHandle) { + cerr << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: Failed to load library " << soname << ": " << DLERROR() << endl; + continue; + } + + VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) + DLSYM(libraryHandle, "vampGetPluginDescriptor"); + + if (!fn) { + cerr << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: No descriptor function in " << soname << endl; + if (DLCLOSE(libraryHandle) != 0) { + cerr << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl; + } + continue; + } + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::getPluginIdentifiers: Vamp descriptor found" << endl; +#endif + + const VampPluginDescriptor *descriptor = 0; + int index = 0; + + map known; + bool ok = true; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + + if (known.find(descriptor->identifier) != known.end()) { + cerr << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: Plugin library " + << soname + << " returns the same plugin identifier \"" + << descriptor->identifier << "\" at indices " + << known[descriptor->identifier] << " and " + << index << endl; + cerr << "NativeVampPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << endl; + ok = false; + break; + } else { + known[descriptor->identifier] = index; + } + + ++index; + } + + if (ok) { + + index = 0; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + + QString id = PluginIdentifier::createIdentifier + ("vamp", soname, descriptor->identifier); + m_identifiers.push_back(id); +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::getPluginIdentifiers: Found plugin id " << id << " at index " << index << endl; +#endif + ++index; + } + } + + if (DLCLOSE(libraryHandle) != 0) { + cerr << "WARNING: NativeVampPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl; + } + } + + generateTaxonomy(); + + // Plugins can change the locale, revert it to default. + RestoreStartupLocale(); + + return m_identifiers; +} + +QString +NativeVampPluginFactory::findPluginFile(QString soname, QString inDir) +{ + QString file = ""; + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::findPluginFile(\"" + << soname << "\", \"" << inDir << "\")" + << endl; +#endif + + if (inDir != "") { + + QDir dir(inDir, PLUGIN_GLOB, + QDir::Name | QDir::IgnoreCase, + QDir::Files | QDir::Readable); + if (!dir.exists()) return ""; + + file = dir.filePath(QFileInfo(soname).fileName()); + + if (QFileInfo(file).exists() && QFileInfo(file).isFile()) { + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::findPluginFile: " + << "found trivially at " << file << endl; +#endif + + return file; + } + + for (unsigned int j = 0; j < dir.count(); ++j) { + file = dir.filePath(dir[j]); + if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) { + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::findPluginFile: " + << "found \"" << soname << "\" at " << file << endl; +#endif + + return file; + } + } + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::findPluginFile (with dir): " + << "not found" << endl; +#endif + + return ""; + + } else { + + QFileInfo fi(soname); + + if (fi.isAbsolute() && fi.exists() && fi.isFile()) { +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::findPluginFile: " + << "found trivially at " << soname << endl; +#endif + return soname; + } + + if (fi.isAbsolute() && fi.absolutePath() != "") { + file = findPluginFile(soname, fi.absolutePath()); + if (file != "") return file; + } + + vector path = getPluginPath(); + for (vector::iterator i = path.begin(); + i != path.end(); ++i) { + if (*i != "") { + file = findPluginFile(soname, *i); + if (file != "") return file; + } + } + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::findPluginFile: " + << "not found" << endl; +#endif + + return ""; + } +} + +Vamp::Plugin * +NativeVampPluginFactory::instantiatePlugin(QString identifier, + sv_samplerate_t inputSampleRate) +{ + Profiler profiler("NativeVampPluginFactory::instantiatePlugin"); + + Vamp::Plugin *rv = 0; + Vamp::PluginHostAdapter *plugin = 0; + + const VampPluginDescriptor *descriptor = 0; + int index = 0; + + QString type, soname, label; + PluginIdentifier::parseIdentifier(identifier, type, soname, label); + if (type != "vamp") { +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type << endl; +#endif + return 0; + } + + QString found = findPluginFile(soname); + + if (found == "") { + cerr << "NativeVampPluginFactory::instantiatePlugin: Failed to find library file " << soname << endl; + return 0; + } else if (found != soname) { + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::instantiatePlugin: Given library name was " << soname << ", found at " << found << endl; + cerr << soname << " -> " << found << endl; +#endif + + } + + soname = found; + + void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL); + + if (!libraryHandle) { + cerr << "NativeVampPluginFactory::instantiatePlugin: Failed to load library " << soname << ": " << DLERROR() << endl; + return 0; + } + + VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) + DLSYM(libraryHandle, "vampGetPluginDescriptor"); + + if (!fn) { + cerr << "NativeVampPluginFactory::instantiatePlugin: No descriptor function in " << soname << endl; + goto done; + } + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + if (label == descriptor->identifier) break; + ++index; + } + + if (!descriptor) { + cerr << "NativeVampPluginFactory::instantiatePlugin: Failed to find plugin \"" << label << "\" in library " << soname << endl; + goto done; + } + + plugin = new Vamp::PluginHostAdapter(descriptor, float(inputSampleRate)); + + if (plugin) { + m_handleMap[plugin] = libraryHandle; + rv = new PluginDeletionNotifyAdapter(plugin, this); + } + +// SVDEBUG << "NativeVampPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << endl; + + //!!! need to dlclose() when plugins from a given library are unloaded + +done: + if (!rv) { + if (DLCLOSE(libraryHandle) != 0) { + cerr << "WARNING: NativeVampPluginFactory::instantiatePlugin: Failed to unload library " << soname << endl; + } + } + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "NativeVampPluginFactory::instantiatePlugin: Instantiated plugin " << label << " from library " << soname << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << endl; +#endif + + return rv; +} + +void +NativeVampPluginFactory::pluginDeleted(Vamp::Plugin *plugin) +{ + void *handle = m_handleMap[plugin]; + if (handle) { +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + cerr << "unloading library " << handle << " for plugin " << plugin << endl; +#endif + DLCLOSE(handle); + } + m_handleMap.erase(plugin); +} + +QString +NativeVampPluginFactory::getPluginCategory(QString identifier) +{ + return m_taxonomy[identifier]; +} + +void +NativeVampPluginFactory::generateTaxonomy() +{ + vector pluginPath = getPluginPath(); + vector path; + + for (size_t i = 0; i < pluginPath.size(); ++i) { + if (pluginPath[i].contains("/lib/")) { + QString p(pluginPath[i]); + path.push_back(p); + p.replace("/lib/", "/share/"); + path.push_back(p); + } + path.push_back(pluginPath[i]); + } + + for (size_t i = 0; i < path.size(); ++i) { + + QDir dir(path[i], "*.cat"); + +// SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << endl; + for (unsigned int j = 0; j < dir.count(); ++j) { + + QFile file(path[i] + "/" + dir[j]); + +// SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i]+ "/" + dir[j]) << endl; + + if (file.open(QIODevice::ReadOnly)) { +// cerr << "...opened" << endl; + QTextStream stream(&file); + QString line; + + while (!stream.atEnd()) { + line = stream.readLine(); +// cerr << "line is: \"" << line << "\"" << endl; + QString id = PluginIdentifier::canonicalise + (line.section("::", 0, 0)); + QString cat = line.section("::", 1, 1); + m_taxonomy[id] = cat; +// cerr << "NativeVampPluginFactory: set id \"" << id << "\" to cat \"" << cat << "\"" << endl; + } + } + } + } +} + +piper_vamp::PluginStaticData +NativeVampPluginFactory::getPluginStaticData(QString identifier) +{ + QMutexLocker locker(&m_mutex); + + if (m_pluginData.find(identifier) != m_pluginData.end()) { + return m_pluginData[identifier]; + } + + QString type, soname, label; + PluginIdentifier::parseIdentifier(identifier, type, soname, label); + std::string pluginKey = (soname + ":" + label).toStdString(); + + std::vector catlist; + for (auto s: getPluginCategory(identifier).split(" > ")) { + catlist.push_back(s.toStdString()); + } + + Vamp::Plugin *p = instantiatePlugin(identifier, 44100); + if (!p) return {}; + + auto psd = piper_vamp::PluginStaticData::fromPlugin(pluginKey, + catlist, + p); + + delete p; + + m_pluginData[identifier] = psd; + return psd; +} + diff -r a1b97df9962e -r 5261a7791f1c plugin/NativeVampPluginFactory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/NativeVampPluginFactory.h Fri Oct 28 15:20:58 2016 +0100 @@ -0,0 +1,68 @@ +/* -*- 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 2006-2016 Chris Cannam and 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. +*/ + +#ifndef SV_NATIVE_VAMP_PLUGIN_FACTORY_H +#define SV_NATIVE_VAMP_PLUGIN_FACTORY_H + +#include "FeatureExtractionPluginFactory.h" + +#include +#include + +#include "base/Debug.h" + +#include + +/** + * FeatureExtractionPluginFactory type for Vamp plugins hosted + * in-process. + */ +class NativeVampPluginFactory : public FeatureExtractionPluginFactory +{ +public: + virtual ~NativeVampPluginFactory() { } + + virtual std::vector getPluginIdentifiers(QString &errorMessage) + override; + + virtual piper_vamp::PluginStaticData getPluginStaticData(QString identifier) + override; + + virtual Vamp::Plugin *instantiatePlugin(QString identifier, + sv_samplerate_t inputSampleRate) + override; + + /** + * Get category metadata about a plugin (without instantiating it). + */ + virtual QString getPluginCategory(QString identifier) override; + +protected: + QMutex m_mutex; + std::vector m_pluginPath; + std::vector m_identifiers; + std::map m_taxonomy; // identifier -> category string + std::map m_pluginData; // identifier -> data (created opportunistically) + + friend class PluginDeletionNotifyAdapter; + void pluginDeleted(Vamp::Plugin *); + std::map m_handleMap; + + QString findPluginFile(QString soname, QString inDir = ""); + std::vector getPluginPath(); + void generateTaxonomy(); +}; + +#endif diff -r a1b97df9962e -r 5261a7791f1c plugin/PiperVampPluginFactory.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/PiperVampPluginFactory.cpp Fri Oct 28 15:20:58 2016 +0100 @@ -0,0 +1,182 @@ +/* -*- 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 2006 Chris Cannam and 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 "PiperVampPluginFactory.h" +#include "PluginIdentifier.h" + +#include "system/System.h" + +#include "PluginScan.h" + +#ifdef _WIN32 +#undef VOID +#undef ERROR +#define CAPNP_LITE 1 +#endif + +#include "vamp-client/AutoPlugin.h" + +#include +#include +#include +#include +#include + +#include + +#include "base/Profiler.h" + +#include "vamp-client/ProcessQtTransport.h" +#include "vamp-client/CapnpRRClient.h" + +using namespace std; + +//#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 + +PiperVampPluginFactory::PiperVampPluginFactory() : + // No server unless we find one - don't run arbitrary stuff from the path: + m_serverName() +{ + // Server must exist either in the same directory as this one or + // (preferably) a subdirectory called "piper-bin". + //!!! todo: merge this with plugin scan checker thingy used in main.cpp? + QString myDir = QCoreApplication::applicationDirPath(); + QString name = "piper-vamp-simple-server"; + QString path = myDir + "/piper-bin/" + name; + QString suffix = ""; +#ifdef _WIN32 + suffix = ".exe"; +#endif + if (!QFile(path + suffix).exists()) { + cerr << "NOTE: Piper Vamp server not found at " << (path + suffix) + << ", trying in my own directory" << endl; + path = myDir + "/" + name; + } + if (!QFile(path + suffix).exists()) { + cerr << "NOTE: Piper Vamp server not found at " << (path + suffix) + << endl; + } else { + m_serverName = (path + suffix).toStdString(); + } +} + +vector +PiperVampPluginFactory::getPluginIdentifiers(QString &errorMessage) +{ + Profiler profiler("PiperVampPluginFactory::getPluginIdentifiers"); + + QMutexLocker locker(&m_mutex); + + if (m_serverName == "") { + errorMessage = QObject::tr("External plugin host executable does not appear to be installed"); + return {}; + } + + if (m_pluginData.empty()) { + populate(errorMessage); + } + + vector rv; + + for (const auto &d: m_pluginData) { + rv.push_back(QString("vamp:") + QString::fromStdString(d.second.pluginKey)); + } + + return rv; +} + +Vamp::Plugin * +PiperVampPluginFactory::instantiatePlugin(QString identifier, + sv_samplerate_t inputSampleRate) +{ + Profiler profiler("PiperVampPluginFactory::instantiatePlugin"); + + auto psd = getPluginStaticData(identifier); + if (psd.pluginKey == "") { + return 0; + } + + auto ap = new piper_vamp::client::AutoPlugin + (m_serverName, psd.pluginKey, float(inputSampleRate), 0); + if (!ap->isOK()) { + delete ap; + return 0; + } + + return ap; +} + +piper_vamp::PluginStaticData +PiperVampPluginFactory::getPluginStaticData(QString identifier) +{ + if (m_pluginData.find(identifier) != m_pluginData.end()) { + return m_pluginData[identifier]; + } else { + return {}; + } +} + +QString +PiperVampPluginFactory::getPluginCategory(QString identifier) +{ + if (m_taxonomy.find(identifier) != m_taxonomy.end()) { + return m_taxonomy[identifier]; + } else { + return {}; + } +} + +void +PiperVampPluginFactory::populate(QString &errorMessage) +{ + if (m_serverName == "") return; + + piper_vamp::client::ProcessQtTransport transport(m_serverName, "capnp"); + if (!transport.isOK()) { + errorMessage = QObject::tr("Could not start external plugin host"); + return; + } + + piper_vamp::client::CapnpRRClient client(&transport); + piper_vamp::ListResponse lr; + + try { + lr = client.listPluginData(); + } catch (piper_vamp::client::ServerCrashed) { + errorMessage = QObject::tr + ("External plugin host exited unexpectedly while listing plugins"); + return; + } catch (const std::exception &e) { + errorMessage = QObject::tr("External plugin host invocation failed: %1") + .arg(e.what()); + return; + } + + for (const auto &pd: lr.available) { + + QString identifier = + QString("vamp:") + QString::fromStdString(pd.pluginKey); + + m_pluginData[identifier] = pd; + + QStringList catlist; + for (const auto &cs: pd.category) { + catlist.push_back(QString::fromStdString(cs)); + } + + m_taxonomy[identifier] = catlist.join(" > "); + } +} + diff -r a1b97df9962e -r 5261a7791f1c plugin/PiperVampPluginFactory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/PiperVampPluginFactory.h Fri Oct 28 15:20:58 2016 +0100 @@ -0,0 +1,58 @@ +/* -*- 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 2006-2016 Chris Cannam and 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. +*/ + +#ifndef SV_PIPER_VAMP_PLUGIN_FACTORY_H +#define SV_PIPER_VAMP_PLUGIN_FACTORY_H + +#include "FeatureExtractionPluginFactory.h" + +#include +#include +#include + +#include "base/Debug.h" + +/** + * FeatureExtractionPluginFactory type for Vamp plugins hosted in a + * separate process using Piper protocol. + */ +class PiperVampPluginFactory : public FeatureExtractionPluginFactory +{ +public: + PiperVampPluginFactory(); + + virtual ~PiperVampPluginFactory() { } + + virtual std::vector getPluginIdentifiers(QString &errorMessage) + override; + + virtual piper_vamp::PluginStaticData getPluginStaticData(QString identifier) + override; + + virtual Vamp::Plugin *instantiatePlugin(QString identifier, + sv_samplerate_t inputSampleRate) + override; + + virtual QString getPluginCategory(QString identifier) override; + +protected: + QMutex m_mutex; + std::string m_serverName; + std::map m_pluginData; // identifier -> data + std::map m_taxonomy; // identifier -> category string + void populate(QString &errorMessage); +}; + +#endif diff -r a1b97df9962e -r 5261a7791f1c plugin/PluginScan.cpp --- a/plugin/PluginScan.cpp Thu Oct 20 11:16:22 2016 +0100 +++ b/plugin/PluginScan.cpp Fri Oct 28 15:20:58 2016 +0100 @@ -23,10 +23,15 @@ using std::string; +//#define DEBUG_PLUGIN_SCAN 1 + class PluginScan::Logger : public PluginCandidates::LogCallback { protected: void log(std::string message) { +#ifdef DEBUG_PLUGIN_SCAN + cerr << "PluginScan: " << message; +#endif SVDEBUG << "PluginScan: " << message; } }; diff -r a1b97df9962e -r 5261a7791f1c svcore.pro --- a/svcore.pro Thu Oct 20 11:16:22 2016 +0100 +++ b/svcore.pro Fri Oct 28 15:20:58 2016 +0100 @@ -2,41 +2,10 @@ TEMPLATE = lib INCLUDEPATH += ../vamp-plugin-sdk -DEFINES += HAVE_VAMP HAVE_VAMPHOSTSDK exists(config.pri) { include(config.pri) } -!exists(config.pri) { - - CONFIG += release - DEFINES += NDEBUG BUILD_RELEASE NO_TIMING - - win32-g++ { - INCLUDEPATH += ../sv-dependency-builds/win32-mingw/include - LIBS += -L../sv-dependency-builds/win32-mingw/lib - } - win32-msvc* { - # We actually expect MSVC to be used only for 64-bit builds, - # though the qmake spec is still called win32-msvc* - INCLUDEPATH += ../sv-dependency-builds/win64-msvc/include - LIBS += -L../sv-dependency-builds/win64-msvc/lib - } - macx* { - INCLUDEPATH += ../sv-dependency-builds/osx/include - LIBS += -L../sv-dependency-builds/osx/lib - } - - DEFINES += HAVE_BZ2 HAVE_FFTW3 HAVE_FFTW3F HAVE_SNDFILE HAVE_SAMPLERATE HAVE_LIBLO HAVE_MAD HAVE_ID3TAG - - macx* { - DEFINES += HAVE_COREAUDIO - } - win32-msvc* { - DEFINES += NOMINMAX _USE_MATH_DEFINES - DEFINES -= HAVE_LIBLO - } -} CONFIG += staticlib qt thread warn_on stl rtti exceptions c++11 QT += network xml @@ -44,8 +13,8 @@ TARGET = svcore -DEPENDPATH += . data plugin plugin/api/alsa -INCLUDEPATH += . data plugin plugin/api/alsa ../dataquay ../checker +DEPENDPATH += . data plugin plugin/api/alsa ../dataquay ../checker ../piper-cpp +INCLUDEPATH += . data plugin plugin/api/alsa ../dataquay ../checker ../piper-cpp OBJECTS_DIR = o MOC_DIR = o @@ -58,249 +27,8 @@ win*: DEFINES += __WINDOWS_MM__ solaris*: DEFINES += __RTMIDI_DUMMY_ONLY__ -HEADERS += base/AudioLevel.h \ - base/AudioPlaySource.h \ - base/BaseTypes.h \ - base/Clipboard.h \ - base/ColumnOp.h \ - base/Command.h \ - base/Debug.h \ - base/Exceptions.h \ - base/LogRange.h \ - base/MagnitudeRange.h \ - base/Pitch.h \ - base/Playable.h \ - base/PlayParameterRepository.h \ - base/PlayParameters.h \ - base/Preferences.h \ - base/Profiler.h \ - base/ProgressPrinter.h \ - base/ProgressReporter.h \ - base/PropertyContainer.h \ - base/RangeMapper.h \ - base/RealTime.h \ - base/RecentFiles.h \ - base/Resampler.h \ - base/ResourceFinder.h \ - base/RingBuffer.h \ - base/Scavenger.h \ - base/Selection.h \ - base/Serialiser.h \ - base/StorageAdviser.h \ - base/StringBits.h \ - base/Strings.h \ - base/TempDirectory.h \ - base/TempWriteFile.h \ - base/TextMatcher.h \ - base/Thread.h \ - base/UnitDatabase.h \ - base/ViewManagerBase.h \ - base/Window.h \ - base/XmlExportable.h \ - base/ZoomConstraint.h -SOURCES += base/AudioLevel.cpp \ - base/Clipboard.cpp \ - base/Command.cpp \ - base/Debug.cpp \ - base/Exceptions.cpp \ - base/LogRange.cpp \ - base/Pitch.cpp \ - base/PlayParameterRepository.cpp \ - base/PlayParameters.cpp \ - base/Preferences.cpp \ - base/Profiler.cpp \ - base/ProgressPrinter.cpp \ - base/ProgressReporter.cpp \ - base/PropertyContainer.cpp \ - base/RangeMapper.cpp \ - base/RealTime.cpp \ - base/RecentFiles.cpp \ - base/Resampler.cpp \ - base/ResourceFinder.cpp \ - base/Selection.cpp \ - base/Serialiser.cpp \ - base/StorageAdviser.cpp \ - base/StringBits.cpp \ - base/Strings.cpp \ - base/TempDirectory.cpp \ - base/TempWriteFile.cpp \ - base/TextMatcher.cpp \ - base/Thread.cpp \ - base/UnitDatabase.cpp \ - base/ViewManagerBase.cpp \ - base/XmlExportable.cpp +include(files.pri) -HEADERS += data/fft/FFTapi.h \ - data/fileio/AudioFileReader.h \ - data/fileio/AudioFileReaderFactory.h \ - data/fileio/AudioFileSizeEstimator.h \ - data/fileio/BZipFileDevice.h \ - data/fileio/CachedFile.h \ - data/fileio/CodedAudioFileReader.h \ - data/fileio/CSVFileReader.h \ - data/fileio/CSVFileWriter.h \ - data/fileio/CSVFormat.h \ - data/fileio/DataFileReader.h \ - data/fileio/DataFileReaderFactory.h \ - data/fileio/FileFinder.h \ - data/fileio/FileReadThread.h \ - data/fileio/FileSource.h \ - data/fileio/MIDIFileReader.h \ - data/fileio/MIDIFileWriter.h \ - data/fileio/MP3FileReader.h \ - data/fileio/OggVorbisFileReader.h \ - data/fileio/PlaylistFileReader.h \ - data/fileio/QuickTimeFileReader.h \ - data/fileio/CoreAudioFileReader.h \ - data/fileio/DecodingWavFileReader.h \ - data/fileio/WavFileReader.h \ - data/fileio/WavFileWriter.h \ - data/midi/MIDIEvent.h \ - data/midi/MIDIInput.h \ - data/midi/rtmidi/RtError.h \ - data/midi/rtmidi/RtMidi.h \ - data/model/AggregateWaveModel.h \ - data/model/AlignmentModel.h \ - data/model/Dense3DModelPeakCache.h \ - data/model/DenseThreeDimensionalModel.h \ - data/model/DenseTimeValueModel.h \ - data/model/EditableDenseThreeDimensionalModel.h \ - data/model/FFTModel.h \ - data/model/ImageModel.h \ - data/model/IntervalModel.h \ - data/model/Labeller.h \ - data/model/Model.h \ - data/model/ModelDataTableModel.h \ - data/model/NoteModel.h \ - data/model/FlexiNoteModel.h \ - data/model/PathModel.h \ - data/model/PowerOfSqrtTwoZoomConstraint.h \ - data/model/PowerOfTwoZoomConstraint.h \ - data/model/RangeSummarisableTimeValueModel.h \ - data/model/RegionModel.h \ - data/model/SparseModel.h \ - data/model/SparseOneDimensionalModel.h \ - data/model/SparseTimeValueModel.h \ - data/model/SparseValueModel.h \ - data/model/TabularModel.h \ - data/model/TextModel.h \ - data/model/WaveFileModel.h \ - data/model/ReadOnlyWaveFileModel.h \ - data/model/WritableWaveFileModel.h \ - data/osc/OSCMessage.h \ - data/osc/OSCQueue.h -SOURCES += data/fft/FFTapi.cpp \ - data/fileio/AudioFileReader.cpp \ - data/fileio/AudioFileReaderFactory.cpp \ - data/fileio/AudioFileSizeEstimator.cpp \ - data/fileio/BZipFileDevice.cpp \ - data/fileio/CachedFile.cpp \ - data/fileio/CodedAudioFileReader.cpp \ - data/fileio/CSVFileReader.cpp \ - data/fileio/CSVFileWriter.cpp \ - data/fileio/CSVFormat.cpp \ - data/fileio/DataFileReaderFactory.cpp \ - data/fileio/FileReadThread.cpp \ - data/fileio/FileSource.cpp \ - data/fileio/MIDIFileReader.cpp \ - data/fileio/MIDIFileWriter.cpp \ - data/fileio/MP3FileReader.cpp \ - data/fileio/OggVorbisFileReader.cpp \ - data/fileio/PlaylistFileReader.cpp \ - data/fileio/QuickTimeFileReader.cpp \ - data/fileio/CoreAudioFileReader.cpp \ - data/fileio/DecodingWavFileReader.cpp \ - data/fileio/WavFileReader.cpp \ - data/fileio/WavFileWriter.cpp \ - data/midi/MIDIInput.cpp \ - data/midi/rtmidi/RtMidi.cpp \ - data/model/AggregateWaveModel.cpp \ - data/model/AlignmentModel.cpp \ - data/model/Dense3DModelPeakCache.cpp \ - data/model/DenseTimeValueModel.cpp \ - data/model/EditableDenseThreeDimensionalModel.cpp \ - data/model/FFTModel.cpp \ - data/model/Model.cpp \ - data/model/ModelDataTableModel.cpp \ - data/model/PowerOfSqrtTwoZoomConstraint.cpp \ - data/model/PowerOfTwoZoomConstraint.cpp \ - data/model/RangeSummarisableTimeValueModel.cpp \ - data/model/WaveFileModel.cpp \ - data/model/ReadOnlyWaveFileModel.cpp \ - data/model/WritableWaveFileModel.cpp \ - data/osc/OSCMessage.cpp \ - data/osc/OSCQueue.cpp +HEADERS = $$(SVCORE_HEADERS) +SOURCES = $$(SVCORE_SOURCES) -HEADERS += plugin/PluginScan.h \ - plugin/DSSIPluginFactory.h \ - plugin/DSSIPluginInstance.h \ - plugin/FeatureExtractionPluginFactory.h \ - plugin/LADSPAPluginFactory.h \ - plugin/LADSPAPluginInstance.h \ - plugin/PluginIdentifier.h \ - plugin/PluginXml.h \ - plugin/RealTimePluginFactory.h \ - plugin/RealTimePluginInstance.h \ - plugin/api/dssi.h \ - plugin/api/ladspa.h \ - plugin/plugins/SamplePlayer.h \ - plugin/api/alsa/asoundef.h \ - plugin/api/alsa/asoundlib.h \ - plugin/api/alsa/seq.h \ - plugin/api/alsa/seq_event.h \ - plugin/api/alsa/seq_midi_event.h \ - plugin/api/alsa/sound/asequencer.h - - -SOURCES += plugin/PluginScan.cpp \ - plugin/DSSIPluginFactory.cpp \ - plugin/DSSIPluginInstance.cpp \ - plugin/FeatureExtractionPluginFactory.cpp \ - plugin/LADSPAPluginFactory.cpp \ - plugin/LADSPAPluginInstance.cpp \ - plugin/PluginIdentifier.cpp \ - plugin/PluginXml.cpp \ - plugin/RealTimePluginFactory.cpp \ - plugin/RealTimePluginInstance.cpp \ - plugin/plugins/SamplePlayer.cpp - -!linux* { -SOURCES += plugin/api/dssi_alsa_compat.c -} - -HEADERS += rdf/PluginRDFIndexer.h \ - rdf/PluginRDFDescription.h \ - rdf/RDFExporter.h \ - rdf/RDFFeatureWriter.h \ - rdf/RDFImporter.h \ - rdf/RDFTransformFactory.h -SOURCES += rdf/PluginRDFIndexer.cpp \ - rdf/PluginRDFDescription.cpp \ - rdf/RDFExporter.cpp \ - rdf/RDFFeatureWriter.cpp \ - rdf/RDFImporter.cpp \ - rdf/RDFTransformFactory.cpp - -HEADERS += system/Init.h \ - system/System.h -SOURCES += system/Init.cpp \ - system/System.cpp - -HEADERS += transform/CSVFeatureWriter.h \ - transform/FeatureExtractionModelTransformer.h \ - transform/FeatureWriter.h \ - transform/FileFeatureWriter.h \ - transform/RealTimeEffectModelTransformer.h \ - transform/Transform.h \ - transform/TransformDescription.h \ - transform/TransformFactory.h \ - transform/ModelTransformer.h \ - transform/ModelTransformerFactory.h -SOURCES += transform/CSVFeatureWriter.cpp \ - transform/FeatureExtractionModelTransformer.cpp \ - transform/FileFeatureWriter.cpp \ - transform/RealTimeEffectModelTransformer.cpp \ - transform/Transform.cpp \ - transform/TransformFactory.cpp \ - transform/ModelTransformer.cpp \ - transform/ModelTransformerFactory.cpp diff -r a1b97df9962e -r 5261a7791f1c system/System.h --- a/system/System.h Thu Oct 20 11:16:22 2016 +0100 +++ b/system/System.h Fri Oct 28 15:20:58 2016 +0100 @@ -64,12 +64,15 @@ typedef SSIZE_T ssize_t; #endif +#ifdef _MSC_VER extern "C" { - -#ifdef _MSC_VER void usleep(unsigned long usec); +} +#else +#include #endif +extern "C" { int gettimeofday(struct timeval *p, void *tz); } diff -r a1b97df9962e -r 5261a7791f1c transform/FeatureExtractionModelTransformer.cpp --- a/transform/FeatureExtractionModelTransformer.cpp Thu Oct 20 11:16:22 2016 +0100 +++ b/transform/FeatureExtractionModelTransformer.cpp Fri Oct 28 15:20:58 2016 +0100 @@ -16,6 +16,7 @@ #include "FeatureExtractionModelTransformer.h" #include "plugin/FeatureExtractionPluginFactory.h" + #include "plugin/PluginXml.h" #include @@ -42,25 +43,23 @@ FeatureExtractionModelTransformer::FeatureExtractionModelTransformer(Input in, const Transform &transform) : ModelTransformer(in, transform), - m_plugin(0) + m_plugin(0), + m_haveOutputs(false) { SVDEBUG << "FeatureExtractionModelTransformer::FeatureExtractionModelTransformer: plugin " << m_transforms.begin()->getPluginIdentifier() << ", outputName " << m_transforms.begin()->getOutput() << endl; - - initialise(); } FeatureExtractionModelTransformer::FeatureExtractionModelTransformer(Input in, const Transforms &transforms) : ModelTransformer(in, transforms), - m_plugin(0) + m_plugin(0), + m_haveOutputs(false) { if (m_transforms.empty()) { SVDEBUG << "FeatureExtractionModelTransformer::FeatureExtractionModelTransformer: " << transforms.size() << " transform(s)" << endl; } else { SVDEBUG << "FeatureExtractionModelTransformer::FeatureExtractionModelTransformer: " << transforms.size() << " transform(s), first has plugin " << m_transforms.begin()->getPluginIdentifier() << ", outputName " << m_transforms.begin()->getOutput() << endl; } - - initialise(); } static bool @@ -74,6 +73,10 @@ bool FeatureExtractionModelTransformer::initialise() { + // This is (now) called from the run thread. The plugin is + // constructed, initialised, used, and destroyed all from a single + // thread. + // All transforms must use the same plugin, parameters, and // inputs: they can differ only in choice of plugin output. So we // initialise based purely on the first transform in the list (but @@ -91,7 +94,7 @@ QString pluginId = primaryTransform.getPluginIdentifier(); FeatureExtractionPluginFactory *factory = - FeatureExtractionPluginFactory::instanceFor(pluginId); + FeatureExtractionPluginFactory::instance(); if (!factory) { m_message = tr("No factory available for feature extraction plugin id \"%1\" (unknown plugin type, or internal error?)").arg(pluginId); @@ -104,6 +107,9 @@ return false; } + cerr << "instantiating plugin for transform in thread " + << QThread::currentThreadId() << endl; + m_plugin = factory->instantiatePlugin(pluginId, input->getSampleRate()); if (!m_plugin) { m_message = tr("Failed to instantiate plugin \"%1\"").arg(pluginId); @@ -220,10 +226,27 @@ createOutputModels(j); } + m_outputMutex.lock(); + m_haveOutputs = true; + m_outputsCondition.wakeAll(); + m_outputMutex.unlock(); + return true; } void +FeatureExtractionModelTransformer::deinitialise() +{ + cerr << "deleting plugin for transform in thread " + << QThread::currentThreadId() << endl; + + delete m_plugin; + for (int j = 0; j < (int)m_descriptors.size(); ++j) { + delete m_descriptors[j]; + } +} + +void FeatureExtractionModelTransformer::createOutputModels(int n) { DenseTimeValueModel *input = getConformingInput(); @@ -479,13 +502,21 @@ } } +void +FeatureExtractionModelTransformer::awaitOutputModels() +{ + m_outputMutex.lock(); + while (!m_haveOutputs) { + m_outputsCondition.wait(&m_outputMutex); + } + m_outputMutex.unlock(); +} + FeatureExtractionModelTransformer::~FeatureExtractionModelTransformer() { -// SVDEBUG << "FeatureExtractionModelTransformer::~FeatureExtractionModelTransformer()" << endl; - delete m_plugin; - for (int j = 0; j < (int)m_descriptors.size(); ++j) { - delete m_descriptors[j]; - } + // Parent class dtor set the abandoned flag and waited for the run + // thread to exit; the run thread owns the plugin, and should have + // destroyed it before exiting (via a call to deinitialise) } FeatureExtractionModelTransformer::Models @@ -566,6 +597,8 @@ void FeatureExtractionModelTransformer::run() { + initialise(); + DenseTimeValueModel *input = getConformingInput(); if (!input) return; @@ -758,6 +791,8 @@ delete[] buffers[ch]; } delete[] buffers; + + deinitialise(); } void diff -r a1b97df9962e -r 5261a7791f1c transform/FeatureExtractionModelTransformer.h --- a/transform/FeatureExtractionModelTransformer.h Thu Oct 20 11:16:22 2016 +0100 +++ b/transform/FeatureExtractionModelTransformer.h Fri Oct 28 15:20:58 2016 +0100 @@ -19,6 +19,8 @@ #include "ModelTransformer.h" #include +#include +#include #include @@ -28,7 +30,7 @@ class DenseTimeValueModel; class SparseTimeValueModel; -class FeatureExtractionModelTransformer : public ModelTransformer +class FeatureExtractionModelTransformer : public ModelTransformer // + is a Thread { Q_OBJECT @@ -50,6 +52,7 @@ protected: bool initialise(); + void deinitialise(); virtual void run(); @@ -74,7 +77,12 @@ void getFrames(int channelCount, sv_frame_t startFrame, sv_frame_t size, float **buffer); - // just casts + bool m_haveOutputs; + QMutex m_outputMutex; + QWaitCondition m_outputsCondition; + void awaitOutputModels(); + + // just casts: DenseTimeValueModel *getConformingInput(); diff -r a1b97df9962e -r 5261a7791f1c transform/ModelTransformer.h --- a/transform/ModelTransformer.h Thu Oct 20 11:16:22 2016 +0100 +++ b/transform/ModelTransformer.h Fri Oct 28 15:20:58 2016 +0100 @@ -89,16 +89,20 @@ * be initialised; an error message may be available via * getMessage() in this situation. */ - Models getOutputModels() { return m_outputs; } + Models getOutputModels() { + awaitOutputModels(); + return m_outputs; + } /** * Return the set of output models, also detaching them from the * transformer so that they will not be deleted when the * transformer is. The caller takes ownership of the models. */ - Models detachOutputModels() { + Models detachOutputModels() { + awaitOutputModels(); m_detached = true; - return getOutputModels(); + return m_outputs; } /** @@ -138,6 +142,8 @@ ModelTransformer(Input input, const Transform &transform); ModelTransformer(Input input, const Transforms &transforms); + virtual void awaitOutputModels() = 0; + Transforms m_transforms; Input m_input; // I don't own the model in this Models m_outputs; // I own this, unless... diff -r a1b97df9962e -r 5261a7791f1c transform/ModelTransformerFactory.cpp --- a/transform/ModelTransformerFactory.cpp Thu Oct 20 11:16:22 2016 +0100 +++ b/transform/ModelTransformerFactory.cpp Fri Oct 28 15:20:58 2016 +0100 @@ -93,17 +93,7 @@ Vamp::PluginBase *plugin = 0; - if (FeatureExtractionPluginFactory::instanceFor(id)) { - - cerr << "getConfigurationForTransform: instantiating Vamp plugin" << endl; - - Vamp::Plugin *vp = - FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin - (id, float(inputModel->getSampleRate())); - - plugin = vp; - - } else if (RealTimePluginFactory::instanceFor(id)) { + if (RealTimePluginFactory::instanceFor(id)) { RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id); @@ -120,6 +110,16 @@ (id, 0, 0, sampleRate, blockSize, channels); plugin = rtp; + + } else { + + cerr << "getConfigurationForTransform: instantiating Vamp plugin" << endl; + + Vamp::Plugin *vp = + FeatureExtractionPluginFactory::instance()->instantiatePlugin + (id, float(inputModel->getSampleRate())); + + plugin = vp; } if (plugin) { @@ -171,20 +171,15 @@ QString id = transforms[0].getPluginIdentifier(); - if (FeatureExtractionPluginFactory::instanceFor(id)) { - - transformer = - new FeatureExtractionModelTransformer(input, transforms); - - } else if (RealTimePluginFactory::instanceFor(id)) { + if (RealTimePluginFactory::instanceFor(id)) { transformer = new RealTimeEffectModelTransformer(input, transforms[0]); } else { - SVDEBUG << "ModelTransformerFactory::createTransformer: Unknown transform \"" - << transforms[0].getIdentifier() << "\"" << endl; - return transformer; + + transformer = + new FeatureExtractionModelTransformer(input, transforms); } if (transformer) transformer->setObjectName(transforms[0].getIdentifier()); diff -r a1b97df9962e -r 5261a7791f1c transform/RealTimeEffectModelTransformer.h --- a/transform/RealTimeEffectModelTransformer.h Thu Oct 20 11:16:22 2016 +0100 +++ b/transform/RealTimeEffectModelTransformer.h Fri Oct 28 15:20:58 2016 +0100 @@ -31,6 +31,8 @@ protected: virtual void run(); + virtual void awaitOutputModels() { } // they're created synchronously + QString m_units; RealTimePluginInstance *m_plugin; int m_outputNo; diff -r a1b97df9962e -r 5261a7791f1c transform/Transform.cpp --- a/transform/Transform.cpp Thu Oct 20 11:16:22 2016 +0100 +++ b/transform/Transform.cpp Fri Oct 28 15:20:58 2016 +0100 @@ -202,12 +202,10 @@ Transform::Type Transform::getType() const { - if (FeatureExtractionPluginFactory::instanceFor(getPluginIdentifier())) { - return FeatureExtraction; - } else if (RealTimePluginFactory::instanceFor(getPluginIdentifier())) { + if (RealTimePluginFactory::instanceFor(getPluginIdentifier())) { return RealTimeEffect; } else { - return UnknownType; + return FeatureExtraction; } } diff -r a1b97df9962e -r 5261a7791f1c transform/TransformFactory.cpp --- a/transform/TransformFactory.cpp Thu Oct 20 11:16:22 2016 +0100 +++ b/transform/TransformFactory.cpp Fri Oct 28 15:20:58 2016 +0100 @@ -16,6 +16,7 @@ #include "TransformFactory.h" #include "plugin/FeatureExtractionPluginFactory.h" + #include "plugin/RealTimePluginFactory.h" #include "plugin/RealTimePluginInstance.h" #include "plugin/PluginXml.h" @@ -402,80 +403,77 @@ void TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms) { - std::vector plugs = - FeatureExtractionPluginFactory::getAllPluginIdentifiers(); + FeatureExtractionPluginFactory *factory = + FeatureExtractionPluginFactory::instance(); + + QString errorMessage; + std::vector plugs = factory->getPluginIdentifiers(errorMessage); + if (errorMessage != "") { + m_errorString = tr("Failed to list Vamp plugins: %1").arg(errorMessage); + } + if (m_exiting) return; for (int i = 0; i < (int)plugs.size(); ++i) { QString pluginId = plugs[i]; - FeatureExtractionPluginFactory *factory = - FeatureExtractionPluginFactory::instanceFor(pluginId); + piper_vamp::PluginStaticData psd = factory->getPluginStaticData(pluginId); - if (!factory) { - cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId << endl; - continue; - } + if (psd.pluginKey == "") { + cerr << "WARNING: TransformFactory::populateTransforms: No plugin static data available for instance " << pluginId << endl; + continue; + } - Vamp::Plugin *plugin = - factory->instantiatePlugin(pluginId, 44100); + QString pluginName = QString::fromStdString(psd.basic.name); + QString category = factory->getPluginCategory(pluginId); + + const auto &basicOutputs = psd.basicOutputInfo; - if (!plugin) { - cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId << endl; - continue; - } - - QString pluginName = plugin->getName().c_str(); - QString category = factory->getPluginCategory(pluginId); + for (const auto &o: basicOutputs) { - Vamp::Plugin::OutputList outputs = - plugin->getOutputDescriptors(); - - for (int j = 0; j < (int)outputs.size(); ++j) { + QString outputName = QString::fromStdString(o.name); QString transformId = QString("%1:%2") - .arg(pluginId).arg(outputs[j].identifier.c_str()); + .arg(pluginId).arg(QString::fromStdString(o.identifier)); QString userName; QString friendlyName; - QString units = outputs[j].unit.c_str(); - QString description = plugin->getDescription().c_str(); - QString maker = plugin->getMaker().c_str(); +//!!! return to this QString units = outputs[j].unit.c_str(); + QString description = QString::fromStdString(psd.basic.description); + QString maker = QString::fromStdString(psd.maker); if (maker == "") maker = tr(""); QString longDescription = description; if (longDescription == "") { - if (outputs.size() == 1) { + if (basicOutputs.size() == 1) { longDescription = tr("Extract features using \"%1\" plugin (from %2)") .arg(pluginName).arg(maker); } else { longDescription = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)") - .arg(outputs[j].name.c_str()).arg(pluginName).arg(maker); + .arg(outputName).arg(pluginName).arg(maker); } } else { - if (outputs.size() == 1) { + if (basicOutputs.size() == 1) { longDescription = tr("%1 using \"%2\" plugin (from %3)") .arg(longDescription).arg(pluginName).arg(maker); } else { longDescription = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)") - .arg(longDescription).arg(outputs[j].name.c_str()).arg(pluginName).arg(maker); + .arg(longDescription).arg(outputName).arg(pluginName).arg(maker); } } - if (outputs.size() == 1) { + if (basicOutputs.size() == 1) { userName = pluginName; friendlyName = pluginName; } else { - userName = QString("%1: %2") - .arg(pluginName) - .arg(outputs[j].name.c_str()); - friendlyName = outputs[j].name.c_str(); + userName = QString("%1: %2").arg(pluginName).arg(outputName); + friendlyName = outputName; } - bool configurable = (!plugin->getPrograms().empty() || - !plugin->getParameterDescriptors().empty()); + bool configurable = (!psd.programs.empty() || + !psd.parameters.empty()); #ifdef DEBUG_TRANSFORM_FACTORY cerr << "Feature extraction plugin transform: " << transformId << " friendly name: " << friendlyName << endl; @@ -490,11 +488,10 @@ description, longDescription, maker, - units, +//!!! units, + "", configurable); } - - delete plugin; } } @@ -797,8 +794,8 @@ // cerr << "TransformFactory::instantiateDefaultPluginFor: identifier \"" // << identifier << "\" is a feature extraction transform" << endl; - FeatureExtractionPluginFactory *factory = - FeatureExtractionPluginFactory::instanceFor(pluginId); + FeatureExtractionPluginFactory *factory = + FeatureExtractionPluginFactory::instance(); if (factory) { plugin = factory->instantiatePlugin(pluginId, rate); @@ -917,22 +914,7 @@ { QString id = identifier.section(':', 0, 2); - if (FeatureExtractionPluginFactory::instanceFor(id)) { - - Vamp::Plugin *plugin = - FeatureExtractionPluginFactory::instanceFor(id)-> - instantiatePlugin(id, 44100); - if (!plugin) return false; - - min = (int)plugin->getMinChannelCount(); - max = (int)plugin->getMaxChannelCount(); - delete plugin; - - return true; - - } else if (RealTimePluginFactory::instanceFor(id)) { - - // don't need to instantiate + if (RealTimePluginFactory::instanceFor(id)) { const RealTimePluginDescriptor *descriptor = RealTimePluginFactory::instanceFor(id)-> @@ -943,6 +925,17 @@ max = descriptor->audioInputPortCount; return true; + + } else { + + auto psd = FeatureExtractionPluginFactory::instance()-> + getPluginStaticData(id); + if (psd.pluginKey == "") return false; + + min = (int)psd.minChannelCount; + max = (int)psd.maxChannelCount; + + return true; } return false; diff -r a1b97df9962e -r 5261a7791f1c transform/TransformFactory.h --- a/transform/TransformFactory.h Thu Oct 20 11:16:22 2016 +0100 +++ b/transform/TransformFactory.h Fri Oct 28 15:20:58 2016 +0100 @@ -196,6 +196,10 @@ void setParametersFromPluginConfigurationXml(Transform &transform, QString xml); + QString getStartupFailureReport() const { + return m_errorString; + } + protected: typedef std::map TransformDescriptionMap; @@ -205,6 +209,8 @@ TransformDescriptionMap m_uninstalledTransforms; bool m_uninstalledTransformsPopulated; + QString m_errorString; + void populateTransforms(); void populateUninstalledTransforms(); void populateFeatureExtractionPlugins(TransformDescriptionMap &);