Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 33:651e4e868bcc
* Implement play mute, level and pan controls and a layer visibility control
* Handle swapping the buffers in AudioCallbackPlaySource more gracefully, so
that in many cases it can be done inaudibly. Still gets it wrong when
playing in a noncontiguous selection.
* Fix to SV file save for non-2d sparse models
* Fixes to LED button drawing and AudioDial mouse functionality
* Add progress bar for Ogg file import
* Reshuffle PropertyContainer and its subclasses so it can be a QObject
* Add layer dormancy (invisible layer permitted to free its cache space)
* Optimisations to SpectrogramLayer, removing locks when reading/writing
individual pixels in the cache (should be unnecessary there) -- there's
still an issue here as we need a lock when reading from the model in
case the model is replaced, and we don't currently have one
* Several munlock() calls to make it harder to exhaust real memory if
running in an RT mode with mlockall() active
author | Chris Cannam |
---|---|
date | Fri, 17 Feb 2006 18:04:26 +0000 |
parents | fc802f7b112e |
children | c43f2c4f66f2 |
comparison
equal
deleted
inserted
replaced
32:c53b949ef142 | 33:651e4e868bcc |
---|---|
47 m_pixmapCache(0), | 47 m_pixmapCache(0), |
48 m_pixmapCacheInvalid(true), | 48 m_pixmapCacheInvalid(true), |
49 m_fillThread(0), | 49 m_fillThread(0), |
50 m_updateTimer(0), | 50 m_updateTimer(0), |
51 m_lastFillExtent(0), | 51 m_lastFillExtent(0), |
52 m_dormant(false), | |
53 m_exiting(false) | 52 m_exiting(false) |
54 { | 53 { |
55 if (config == MelodicRange) { | 54 if (config == MelodicRange) { |
56 setWindowSize(8192); | 55 setWindowSize(8192); |
57 setWindowOverlap(90); | 56 setWindowOverlap(90); |
595 { | 594 { |
596 return m_frequencyScale; | 595 return m_frequencyScale; |
597 } | 596 } |
598 | 597 |
599 void | 598 void |
600 SpectrogramLayer::setLayerDormant() | 599 SpectrogramLayer::setLayerDormant(bool dormant) |
601 { | 600 { |
602 m_mutex.lock(); | 601 if (dormant == m_dormant) return; |
603 m_dormant = true; | 602 |
604 delete m_cache; | 603 if (dormant) { |
605 m_cache = 0; | 604 |
606 m_pixmapCacheInvalid = true; | 605 m_mutex.lock(); |
607 delete m_pixmapCache; | 606 m_dormant = true; |
608 m_pixmapCache = 0; | 607 |
609 m_mutex.unlock(); | 608 delete m_cache; |
609 m_cache = 0; | |
610 | |
611 m_pixmapCacheInvalid = true; | |
612 delete m_pixmapCache; | |
613 m_pixmapCache = 0; | |
614 | |
615 m_mutex.unlock(); | |
616 | |
617 } else { | |
618 | |
619 m_dormant = false; | |
620 fillCache(); | |
621 } | |
610 } | 622 } |
611 | 623 |
612 void | 624 void |
613 SpectrogramLayer::cacheInvalid() | 625 SpectrogramLayer::cacheInvalid() |
614 { | 626 { |
981 size_t width = (end - start) / windowIncrement + 1; | 993 size_t width = (end - start) / windowIncrement + 1; |
982 size_t height = windowSize / 2; | 994 size_t height = windowSize / 2; |
983 m_layer.m_cache = new Cache(width, height); | 995 m_layer.m_cache = new Cache(width, height); |
984 | 996 |
985 m_layer.setCacheColourmap(); | 997 m_layer.setCacheColourmap(); |
986 | |
987 m_layer.m_cache->fill(0); | 998 m_layer.m_cache->fill(0); |
999 | |
1000 // We don't need a lock when writing to or reading from | |
1001 // the pixels in the cache, because it's a fixed size | |
1002 // array. We do need to ensure we have the width and | |
1003 // height of the cache and the FFT parameters fixed before | |
1004 // we unlock, in case they change in the model while we | |
1005 // aren't holding a lock. It's safe for us to continue to | |
1006 // use the "old" values if that happens, because they will | |
1007 // continue to match the dimensions of the actual cache | |
1008 // (which we manage, not the model). | |
988 m_layer.m_mutex.unlock(); | 1009 m_layer.m_mutex.unlock(); |
989 | 1010 |
990 double *input = (double *) | 1011 double *input = (double *) |
991 fftw_malloc(windowSize * sizeof(double)); | 1012 fftw_malloc(windowSize * sizeof(double)); |
992 | 1013 |
1000 | 1021 |
1001 if (!plan) { | 1022 if (!plan) { |
1002 std::cerr << "WARNING: fftw_plan_dft_r2c_1d(" << windowSize << ") failed!" << std::endl; | 1023 std::cerr << "WARNING: fftw_plan_dft_r2c_1d(" << windowSize << ") failed!" << std::endl; |
1003 fftw_free(input); | 1024 fftw_free(input); |
1004 fftw_free(output); | 1025 fftw_free(output); |
1005 m_layer.m_mutex.lock(); | |
1006 continue; | 1026 continue; |
1007 } | 1027 } |
1008 | 1028 |
1009 int counter = 0; | 1029 int counter = 0; |
1010 int updateAt = (end / windowIncrement) / 20; | 1030 int updateAt = (end / windowIncrement) / 20; |
1011 if (updateAt < 100) updateAt = 100; | 1031 if (updateAt < 100) updateAt = 100; |
1012 | 1032 |
1013 bool doVisibleFirst = (visibleStart != start && visibleEnd != end); | 1033 bool doVisibleFirst = (visibleStart != start && visibleEnd != end); |
1014 | 1034 |
1015 if (doVisibleFirst) { | 1035 if (doVisibleFirst) { |
1016 | |
1017 m_layer.m_mutex.lock(); | |
1018 | 1036 |
1019 for (size_t f = visibleStart; f < visibleEnd; f += windowIncrement) { | 1037 for (size_t f = visibleStart; f < visibleEnd; f += windowIncrement) { |
1020 | 1038 |
1021 m_layer.fillCacheColumn(int((f - start) / windowIncrement), | 1039 m_layer.fillCacheColumn(int((f - start) / windowIncrement), |
1022 input, output, plan, | 1040 input, output, plan, |
1023 windowSize, windowIncrement, | 1041 windowSize, windowIncrement, |
1024 windower, false); | 1042 windower, false); |
1025 | |
1026 m_layer.m_mutex.unlock(); | |
1027 m_layer.m_mutex.lock(); | |
1028 | 1043 |
1029 if (m_layer.m_cacheInvalid || m_layer.m_exiting) { | 1044 if (m_layer.m_cacheInvalid || m_layer.m_exiting) { |
1030 interrupted = true; | 1045 interrupted = true; |
1031 m_fillExtent = 0; | 1046 m_fillExtent = 0; |
1032 break; | 1047 break; |
1037 m_fillCompletion = size_t(100 * fabsf(float(f - visibleStart) / | 1052 m_fillCompletion = size_t(100 * fabsf(float(f - visibleStart) / |
1038 float(end - start))); | 1053 float(end - start))); |
1039 counter = 0; | 1054 counter = 0; |
1040 } | 1055 } |
1041 } | 1056 } |
1042 | |
1043 m_layer.m_mutex.unlock(); | |
1044 } | 1057 } |
1045 | 1058 |
1046 m_layer.m_cachedInitialVisibleArea = true; | 1059 m_layer.m_cachedInitialVisibleArea = true; |
1047 | 1060 |
1048 if (!interrupted && doVisibleFirst) { | 1061 if (!interrupted && doVisibleFirst) { |
1288 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | 1301 if (!m_model || !m_model->isOK() || !m_model->isReady()) { |
1289 return; | 1302 return; |
1290 } | 1303 } |
1291 | 1304 |
1292 if (m_dormant) { | 1305 if (m_dormant) { |
1293 std::cerr << "SpectrogramLayer::paint(): Layer is dormant, de-hibernating" << std::endl; | 1306 std::cerr << "SpectrogramLayer::paint(): Layer is dormant" << std::endl; |
1294 m_dormant = false; | |
1295 ((SpectrogramLayer *)this)->fillCache(); | |
1296 return; | 1307 return; |
1297 } | 1308 } |
1298 | 1309 |
1299 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1310 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1300 std::cerr << "SpectrogramLayer::paint(): About to lock" << std::endl; | 1311 std::cerr << "SpectrogramLayer::paint(): About to lock" << std::endl; |