31 #include <QWriteLocker> 36 #ifdef DEBUG_FFT_SERVER_FILL 37 #ifndef DEBUG_FFT_SERVER 38 #define DEBUG_FFT_SERVER 1 147 ServerMap::iterator best =
m_servers.end();
163 bool poweroftwo =
true;
171 if (!poweroftwo)
continue;
173 if ((server->
getFFTSize() % fftSize) != 0)
continue;
182 if (!poweroftwo)
continue;
186 if (server->
getPolar() != polar) distance += 1;
189 distance += ((server->
getFFTSize() / fftSize) - 1) * 10;
193 #ifdef DEBUG_FFT_SERVER 194 std::cerr <<
"FFTDataServer::getFuzzyInstance: Distance for server " << server <<
" is " << distance <<
", best is " << bestdist << std::endl;
197 if (bestdist == -1 || distance < bestdist) {
206 #ifdef DEBUG_FFT_SERVER 207 std::cerr <<
"FFTDataServer::getFuzzyInstance: We like server " << server <<
" (with distance " << bestdist <<
")" << std::endl;
230 #ifdef DEBUG_FFT_SERVER 231 std::cerr <<
"FFTDataServer::findServer(\"" << n <<
"\")" << std::endl;
238 #ifdef DEBUG_FFT_SERVER 239 std::cerr <<
"FFTDataServer::findServer(\"" << n <<
"\"): found " << server << std::endl;
247 #ifdef DEBUG_FFT_SERVER 248 std::cerr <<
"FFTDataServer::findServer(\"" << n <<
"\"): not found" << std::endl;
264 "FFTDataServer::claimInstance::m_serverMapMutex");
266 #ifdef DEBUG_FFT_SERVER 267 std::cerr <<
"FFTDataServer::claimInstance(" << server <<
")" << std::endl;
271 if (i->second.first == server) {
277 #ifdef DEBUG_FFT_SERVER 278 std::cerr <<
"FFTDataServer::claimInstance: found in released server list, removing from it" << std::endl;
287 #ifdef DEBUG_FFT_SERVER 288 std::cerr <<
"FFTDataServer::claimInstance: new refcount is " << i->second.second << std::endl;
295 cerr <<
"ERROR: FFTDataServer::claimInstance: instance " 296 << server <<
" unknown!" << endl;
309 "FFTDataServer::releaseInstance::m_serverMapMutex");
311 #ifdef DEBUG_FFT_SERVER 312 std::cerr <<
"FFTDataServer::releaseInstance(" << server <<
")" << std::endl;
327 if (i->second.first == server) {
328 if (i->second.second == 0) {
329 cerr <<
"ERROR: FFTDataServer::releaseInstance(" 330 << server <<
"): instance not allocated" << endl;
331 }
else if (--i->second.second == 0) {
343 #ifdef DEBUG_FFT_SERVER 344 std::cerr <<
"FFTDataServer::releaseInstance: instance " 345 << server <<
" no longer in use, marking for possible collection" 352 cerr <<
"ERROR: FFTDataServer::releaseInstance(" 353 << server <<
"): server is already in " 354 <<
"released servers list" << endl;
363 #ifdef DEBUG_FFT_SERVER 364 std::cerr <<
"FFTDataServer::releaseInstance: instance " 365 << server <<
" now has refcount " << i->second.second
373 cerr <<
"ERROR: FFTDataServer::releaseInstance(" << server <<
"): " 374 <<
"instance not found" << endl;
380 #ifdef DEBUG_FFT_SERVER 381 std::cerr <<
"FFTDataServer::purgeLimbo(" << maxSize <<
"): " 391 #ifdef DEBUG_FFT_SERVER 392 std::cerr <<
"FFTDataServer::purgeLimbo: considering candidate " 393 << server << std::endl;
398 if (i->second.first == server) {
400 if (i->second.second > 0) {
401 cerr <<
"ERROR: FFTDataServer::purgeLimbo: Server " 402 << server <<
" is in released queue, but still has non-zero refcount " 403 << i->second.second << endl;
407 #ifdef DEBUG_FFT_SERVER 408 std::cerr <<
"FFTDataServer::purgeLimbo: looks OK, erasing it" 419 cerr <<
"ERROR: FFTDataServer::purgeLimbo: Server " 420 << server <<
" is in released queue, but not in server map!" 428 #ifdef DEBUG_FFT_SERVER 429 std::cerr <<
"FFTDataServer::purgeLimbo(" << maxSize <<
"): " 439 "FFTDataServer::modelAboutToBeDeleted::m_serverMapMutex");
441 #ifdef DEBUG_FFT_SERVER 442 std::cerr <<
"FFTDataServer::modelAboutToBeDeleted(" << model <<
")" 452 #ifdef DEBUG_FFT_SERVER 453 std::cerr <<
"FFTDataServer::modelAboutToBeDeleted: server is " 454 << server << std::endl;
457 if (i->second.second > 0) {
458 cerr <<
"WARNING: FFTDataServer::modelAboutToBeDeleted: Model " << model <<
" (\"" << model->objectName() <<
"\") is about to be deleted, but is still being referred to by FFT server " << server <<
" with non-zero refcount " << i->second.second << endl;
465 #ifdef DEBUG_FFT_SERVER 466 std::cerr <<
"FFTDataServer::modelAboutToBeDeleted: erasing from released servers" << std::endl;
472 #ifdef DEBUG_FFT_SERVER 473 std::cerr <<
"FFTDataServer::modelAboutToBeDeleted: erasing server" << std::endl;
491 int fillFromColumn) :
492 m_fileBaseName(fileBaseName),
495 m_windower(windowType, windowSize),
496 m_windowSize(windowSize),
497 m_windowIncrement(windowIncrement),
503 m_cacheWidthPower(0),
505 m_criteria(criteria),
511 #ifdef DEBUG_FFT_SERVER 512 cerr <<
"FFTDataServer(" <<
this <<
" [" << (
void *)QThread::currentThreadId() <<
"])::FFTDataServer" << endl;
523 #ifdef DEBUG_FFT_SERVER 524 cerr <<
"FFTDataServer(" <<
this <<
"): dimensions are " 528 int maxCacheSize = 20 * 1024 * 1024;
533 #ifdef DEBUG_FFT_SERVER 534 cerr <<
"FFTDataServer(" <<
this <<
"): cache width nominal " 545 #ifdef DEBUG_FFT_SERVER 584 cerr <<
"ERROR: fftf_plan_dft_r2c_1d(" <<
m_windowSize <<
") failed!" << endl;
593 #ifdef DEBUG_FFT_SERVER 594 cerr <<
"FFTDataServer(" <<
this <<
" [" << (
void *)QThread::currentThreadId() <<
"])::~FFTDataServer()" << endl;
611 for (CacheVector::iterator i =
m_caches.begin(); i !=
m_caches.end(); ++i) {
623 #ifdef DEBUG_FFT_SERVER 624 cerr <<
"FFTDataServer(" <<
this <<
" [" << (
void *)QThread::currentThreadId() <<
"]): deleteProcessingData" << endl;
638 #ifdef DEBUG_FFT_SERVER 639 cerr <<
"FFTDataServer(" <<
this <<
" [" << (
void *)QThread::currentThreadId() <<
"]): suspend" << endl;
641 Profiler profiler(
"FFTDataServer::suspend",
false);
650 #ifdef DEBUG_FFT_SERVER 651 cerr <<
"FFTDataServer(" <<
this <<
" [" << (
void *)QThread::currentThreadId() <<
"]): suspendWrites" << endl;
653 Profiler profiler(
"FFTDataServer::suspendWrites",
false);
661 #ifdef DEBUG_FFT_SERVER 662 cerr <<
"FFTDataServer(" <<
this <<
" [" << (
void *)QThread::currentThreadId() <<
"]): resume" << endl;
664 Profiler profiler(
"FFTDataServer::resume",
false);
682 bool &memoryCache,
bool &compactCache)
685 int minimumSize = (cells / 1024) *
sizeof(uint16_t);
686 int maximumSize = (cells / 1024) *
sizeof(
float);
691 bool canCompact =
true;
694 minimumSize = maximumSize;
729 compactCache = canCompact &&
732 #ifdef DEBUG_FFT_SERVER 733 cerr <<
"FFTDataServer: memory cache = " << memoryCache <<
", compact cache = " << compactCache << endl;
735 cerr <<
"Width " << w <<
" of " <<
m_width <<
", height " << h <<
", size " << w * h << endl;
771 bool memoryCache =
false;
772 bool compactCache =
false;
776 bool success =
false;
790 }
catch (std::bad_alloc) {
795 cerr <<
"WARNING: Memory allocation failed when creating" 796 <<
" FFT memory cache no. " << c <<
" of " << width
798 <<
"): falling back to disc cache" << endl;
817 }
catch (std::exception &e) {
822 cerr <<
"ERROR: Failed to construct disc cache for FFT data: " 843 #ifdef DEBUG_FFT_SERVER 844 std::cerr <<
"FFTDataServer::makeCacheReader(" << c <<
")" << std::endl;
847 QThread *me = QThread::currentThread();
850 if (!cb || !cb->fileCacheWriter)
return false;
856 }
catch (std::exception &e) {
858 delete cb->fileCacheReader[me];
859 cb->fileCacheReader.erase(me);
861 cerr <<
"ERROR: Failed to construct disc cache reader for FFT data: " 869 int deleteCandidate = c - 2;
870 if (deleteCandidate < 0) deleteCandidate = c + 2;
871 if (deleteCandidate >= (
int)
m_caches.size()) {
876 if (cb && cb->fileCacheReader.find(me) != cb->fileCacheReader.end()) {
877 #ifdef DEBUG_FFT_SERVER 878 std::cerr <<
"FFTDataServer::makeCacheReader: Deleting probably unpopular reader " << deleteCandidate <<
" for this thread (as I create reader " << c <<
")" << std::endl;
880 delete cb->fileCacheReader[me];
881 cb->fileCacheReader.erase(me);
890 Profiler profiler(
"FFTDataServer::getMagnitudeAt",
false);
899 if (!cache)
return 0;
902 Profiler profiler(
"FFTDataServer::getMagnitudeAt: filling");
903 #ifdef DEBUG_FFT_SERVER 904 std::cerr <<
"FFTDataServer::getMagnitudeAt: calling fillColumn(" 905 << x <<
")" << std::endl;
912 }
catch (std::exception &e) {
922 Profiler profiler(
"FFTDataServer::getMagnitudesAt",
false);
924 if (x >=
m_width)
return false;
927 if (count == 0) count = (
m_height - minbin) / step;
928 else if (minbin + count * step >
m_height) {
935 if (!cache)
return false;
938 Profiler profiler(
"FFTDataServer::getMagnitudesAt: filling");
944 }
catch (std::exception &e) {
955 Profiler profiler(
"FFTDataServer::getNormalizedMagnitudeAt",
false);
965 if (!cache)
return 0;
968 Profiler profiler(
"FFTDataServer::getNormalizedMagnitudeAt: filling");
973 }
catch (std::exception &e) {
983 Profiler profiler(
"FFTDataServer::getNormalizedMagnitudesAt",
false);
985 if (x >=
m_width)
return false;
988 if (count == 0) count = (
m_height - minbin) / step;
989 else if (minbin + count * step >
m_height) {
997 if (!cache)
return false;
1000 Profiler profiler(
"FFTDataServer::getNormalizedMagnitudesAt: filling");
1004 for (
int i = 0; i < count; ++i) {
1008 }
catch (std::exception &e) {
1019 Profiler profiler(
"FFTDataServer::getMaximumMagnitudeAt",
false);
1029 if (!cache)
return 0;
1032 Profiler profiler(
"FFTDataServer::getMaximumMagnitudeAt: filling");
1037 }
catch (std::exception &e) {
1047 Profiler profiler(
"FFTDataServer::getPhaseAt",
false);
1057 if (!cache)
return 0;
1060 Profiler profiler(
"FFTDataServer::getPhaseAt: filling");
1065 }
catch (std::exception &e) {
1075 Profiler profiler(
"FFTDataServer::getPhasesAt",
false);
1077 if (x >=
m_width)
return false;
1080 if (count == 0) count = (
m_height - minbin) / step;
1081 else if (minbin + count * step >
m_height) {
1082 count = (
m_height - minbin) / step;
1089 if (!cache)
return false;
1092 Profiler profiler(
"FFTDataServer::getPhasesAt: filling");
1096 for (
int i = 0; i < count; ++i) {
1097 values[i] = cache->
getPhaseAt(col, i * step + minbin);
1100 }
catch (std::exception &e) {
1111 Profiler profiler(
"FFTDataServer::getValuesAt",
false);
1131 Profiler profiler(
"FFTDataServer::getValuesAt: filling");
1132 #ifdef DEBUG_FFT_SERVER 1133 std::cerr <<
"FFTDataServer::getValuesAt(" << x <<
", " << y <<
"): filling" << std::endl;
1140 }
catch (std::exception &e) {
1148 Profiler profiler(
"FFTDataServer::getValuesAt",
false);
1150 if (x >=
m_width)
return false;
1153 if (count == 0) count = (
m_height - minbin) / step;
1154 else if (minbin + count * step >
m_height) {
1155 count = (
m_height - minbin) / step;
1162 if (!cache)
return false;
1165 Profiler profiler(
"FFTDataServer::getValuesAt: filling");
1169 for (
int i = 0; i < count; ++i) {
1170 cache->
getValuesAt(col, i * step + minbin, reals[i], imaginaries[i]);
1173 }
catch (std::exception &e) {
1184 Profiler profiler(
"FFTDataServer::isColumnReady",
false);
1186 if (x >=
m_width)
return true;
1205 if (!cache)
return true;
1209 }
catch (std::exception &e) {
1218 Profiler profiler(
"FFTDataServer::fillColumn",
false);
1221 cerr <<
"WARNING: FFTDataServer::fillColumn(" 1222 << x <<
"): model not yet ready" << endl;
1234 cerr <<
"WARNING: FFTDataServer::fillColumn(" << x <<
"): " 1235 <<
"x > width (" << x <<
" > " <<
m_width <<
")" 1241 #ifdef DEBUG_FFT_SERVER_FILL 1242 cout <<
"FFTDataServer::fillColumn(" << x <<
")" << endl;
1252 int off = (fftsize - winsize) / 2;
1257 startFrame -= winsize / 2;
1258 endFrame -= winsize / 2;
1260 #ifdef DEBUG_FFT_SERVER_FILL 1261 std::cerr <<
"FFTDataServer::fillColumn: requesting frames " 1262 << startFrame + pfx <<
" -> " << endFrame <<
" ( = " 1263 << endFrame - (startFrame + pfx) <<
") at index " 1264 << off + pfx <<
" in buffer of size " <<
m_fftSize 1266 <<
" from channel " <<
m_channel << std::endl;
1282 cerr <<
"WARNING: FFTDataServer::fillColumn(" << x <<
"): " 1283 <<
"input has already been completed and discarded?" 1288 for (
int i = 0; i < off; ++i) {
1292 for (
int i = 0; i < off; ++i) {
1296 if (startFrame < 0) {
1298 for (
int i = 0; i < pfx; ++i) {
1304 if (endFrame > startFrame + pfx) count = endFrame - (startFrame + pfx);
1309 while (got + pfx < winsize) {
1317 for (
int i = 0; i < winsize; ++i) {
1325 for (
int i = 0; i < hs; ++i) {
1338 for (
int i = 0; i <= hs; ++i) {
1341 float mag = sqrtf(real * real + imag * imag);
1344 if (mag > factor) factor = mag;
1349 for (
int i = 0; i <= hs; ++i) {
1355 Profiler subprof(
"FFTDataServer::fillColumn: set to cache");
1381 for (
int i = 0; i < int(
m_caches.size()); ++i) {
1384 m_caches[i]->memoryCache->allColumnsWritten();
1386 if (
m_caches[i]->fileCacheWriter) {
1387 m_caches[i]->fileCacheWriter->allColumnsWritten();
1427 int windowIncrement,
1433 sprintf(buffer,
"%u-%u-%u-%u-%u-%u%s",
1435 (
unsigned int)(channel + 1),
1436 (
unsigned int)windowType,
1437 (
unsigned int)windowSize,
1438 (
unsigned int)windowIncrement,
1439 (
unsigned int)fftSize,
1440 polar ?
"-p" :
"-r");
1448 #ifdef DEBUG_FFT_SERVER_FILL 1449 std::cerr <<
"FFTDataServer::FillThread::run()" << std::endl;
1456 #ifdef DEBUG_FFT_SERVER_FILL 1457 std::cerr <<
"FFTDataServer::FillThread::run(): waiting for model " <<
m_server.
m_model <<
" to be ready" << std::endl;
1465 int remainingEnd = end;
1470 if (maxUpdateAt < 100) maxUpdateAt = 100;
1478 }
catch (std::exception &e) {
1479 std::cerr <<
"FFTDataServer::FillThread::run: exception: " << e.what() << std::endl;
1490 #ifdef DEBUG_FFT_SERVER 1491 cerr <<
"FFTDataServer(" <<
this <<
" [" << (
void *)QThread::currentThreadId() <<
"]): suspended, waiting..." << endl;
1494 "FFTDataServer::run::m_fftBuffersLock [1]");
1498 #ifdef DEBUG_FFT_SERVER 1499 cerr <<
"FFTDataServer(" <<
this <<
" [" << (
void *)QThread::currentThreadId() <<
"]): waited" << endl;
1504 if (++counter == updateAt) {
1507 float(end -
start)));
1509 if (updateAt < maxUpdateAt) {
1511 if (updateAt > maxUpdateAt) updateAt = maxUpdateAt;
1517 if (remainingEnd >
start) --remainingEnd;
1518 else remainingEnd =
start;
1527 }
catch (std::exception &e) {
1528 std::cerr <<
"FFTDataServer::FillThread::run: exception: " << e.what() << std::endl;
1539 #ifdef DEBUG_FFT_SERVER 1540 cerr <<
"FFTDataServer(" <<
this <<
" [" << (
void *)QThread::currentThreadId() <<
"]): suspended, waiting..." << endl;
1544 "FFTDataServer::run::m_fftBuffersLock [2]");
1552 if (++counter == updateAt) {
1555 int(100 * fabsf(
float(f -
start) /
1556 float(end -
start)));
1558 if (updateAt < maxUpdateAt) {
1560 if (updateAt > maxUpdateAt) updateAt = maxUpdateAt;
1569 #ifdef DEBUG_FFT_SERVER 1570 std::cerr <<
"FFTDataServer::FillThread::run exiting" << std::endl;
virtual int getChannelCount() const =0
Return the number of distinct channels for this model.
void deleteProcessingData()
FillThread * m_fillThread
static QMutex m_serverMapMutex
bool getNormalizedMagnitudesAt(int x, float *values, int minbin=0, int count=0, int step=1)
virtual void getValuesAt(int x, int y, float &real, float &imag) const =0
FFTCacheWriter * getCacheWriter(int x, int &col)
ThreadReaderMap fileCacheReader
QReadWriteLock m_cacheVectorLock
FFTMemoryCache * memoryCache
virtual float getMagnitudeAt(int x, int y) const =0
static ServerMap m_servers
virtual int getStartFrame() const =0
Return the first audio frame spanned by the model.
Window< fftsample > m_windower
FFTDataServer(QString fileBaseName, const DenseTimeValueModel *model, int channel, WindowType windowType, int windowSize, int windowIncrement, int fftSize, bool polar, StorageAdviser::Criteria criteria, int fillFromColumn=0)
float getMaximumMagnitudeAt(int x)
const DenseTimeValueModel * getModel() const
fftf_complex * m_fftOutput
static int getObjectExportId(const void *)
static void purgeLimbo(int maxSize=3)
virtual FFTCache::StorageType getStorageType() const =0
float getMagnitudeAt(int x, int y)
virtual bool haveSetColumnAt(int x) const =0
int getCompletion() const
virtual int getData(int channel, int start, int count, float *buffer) const =0
Get the specified set of samples from the given channel of the model in single-precision floating-poi...
std::pair< FFTDataServer *, int > ServerCountPair
QWaitCondition m_condition
virtual bool isReady(int *completion=0) const
Return true if the model has finished loading or calculating all its data, for a model that is capabl...
int getWindowIncrement() const
#define fftf_destroy_plan
QMutex m_cacheCreationMutex
FFTFileCacheWriter * fileCacheWriter
bool getMagnitudesAt(int x, float *values, int minbin=0, int count=0, int step=1)
static FFTDataServer * findServer(QString)
virtual float getPhaseAt(int x, int y) const =0
WindowType getWindowType() const
virtual float getNormalizedMagnitudeAt(int x, int y) const =0
void getStorageAdvice(int w, int h, bool &memory, bool &compact)
virtual float getMaximumMagnitudeAt(int x) const =0
int getFillExtent() const
float getPhaseAt(int x, int y)
const DenseTimeValueModel * m_model
virtual void setColumnAt(int x, float *mags, float *phases, float factor)=0
virtual bool haveSetColumnAt(int x) const =0
Model is the base class for all data models that represent any sort of data on a time scale based on ...
static void modelAboutToBeDeleted(Model *)
bool isColumnReady(int x)
int getFillCompletion() const
static void claimInstance(FFTDataServer *)
static Recommendation recommend(Criteria criteria, int minimumSize, int maximumSize)
Recommend where to store some data, given certain storage and recall criteria.
StorageAdviser::Criteria m_criteria
FFTCacheReader * getCacheReader(int x, int &col)
static void releaseInstance(FFTDataServer *)
void getValuesAt(int x, int y, float &real, float &imaginary)
Base class for models containing dense two-dimensional data (value against time).
virtual int getEndFrame() const =0
Return the last audio frame spanned by the model.
std::map< QString, ServerCountPair > ServerMap
bool makeCacheReader(int c)
int getWindowSize() const
float getNormalizedMagnitudeAt(int x, int y)
#define fftf_plan_dft_r2c_1d
WindowType getType() const
virtual void getMagnitudesAt(int x, float *values, int minbin, int count, int step) const =0
static FFTDataServer * getInstance(const DenseTimeValueModel *model, int channel, WindowType windowType, int windowSize, int windowIncrement, int fftSize, bool polar, StorageAdviser::Criteria criteria=StorageAdviser::NoCriteria, int fillFromColumn=0)
std::deque< FFTDataServer * > ServerQueue
QString generateFileBasename() const
bool getPhasesAt(int x, float *values, int minbin=0, int count=0, int step=1)
static FFTDataServer * getFuzzyInstance(const DenseTimeValueModel *model, int channel, WindowType windowType, int windowSize, int windowIncrement, int fftSize, bool polar, StorageAdviser::Criteria criteria=StorageAdviser::NoCriteria, int fillFromColumn=0)
Profile point instance class.
static ServerQueue m_releasedServers