comparison layer/SpectrogramLayer.cpp @ 1087:6d990a24ac1b spectrogram-minor-refactor

One FFT size method, no member for it
author Chris Cannam
date Sat, 02 Jul 2016 12:56:07 +0100
parents 163cb9b98104
children c520f90bbf2e
comparison
equal deleted inserted replaced
1086:163cb9b98104 1087:6d990a24ac1b
59 m_model(0), 59 m_model(0),
60 m_channel(0), 60 m_channel(0),
61 m_windowSize(1024), 61 m_windowSize(1024),
62 m_windowType(HanningWindow), 62 m_windowType(HanningWindow),
63 m_windowHopLevel(2), 63 m_windowHopLevel(2),
64 m_fftSize(1024),
65 m_gain(1.0), 64 m_gain(1.0),
66 m_initialGain(1.0), 65 m_initialGain(1.0),
67 m_threshold(0.0), 66 m_threshold(0.0),
68 m_initialThreshold(0.0), 67 m_initialThreshold(0.0),
69 m_colourRotation(0), 68 m_colourRotation(0),
635 } 634 }
636 635
637 return 4; 636 return 4;
638 } 637 }
639 638
639 int
640 SpectrogramLayer::getFFTSize() const
641 {
642 return m_windowSize * getFFTOversampling();
643 }
644
640 void 645 void
641 SpectrogramLayer::setWindowSize(int ws) 646 SpectrogramLayer::setWindowSize(int ws)
642 { 647 {
643 int fftSize = ws * getFFTOversampling(); 648 if (m_windowSize == ws) return;
644
645 if (m_windowSize == ws && m_fftSize == fftSize) return;
646 649
647 invalidateImageCaches(); 650 invalidateImageCaches();
648 651
649 m_windowSize = ws; 652 m_windowSize = ws;
650 m_fftSize = fftSize;
651 653
652 invalidateFFTModels(); 654 invalidateFFTModels();
653 655
654 emit layerParametersChanged(); 656 emit layerParametersChanged();
655 } 657 }
1111 1113
1112 double 1114 double
1113 SpectrogramLayer::getEffectiveMinFrequency() const 1115 SpectrogramLayer::getEffectiveMinFrequency() const
1114 { 1116 {
1115 sv_samplerate_t sr = m_model->getSampleRate(); 1117 sv_samplerate_t sr = m_model->getSampleRate();
1116 double minf = double(sr) / m_fftSize; 1118 double minf = double(sr) / getFFTSize();
1117 1119
1118 if (m_minFrequency > 0.0) { 1120 if (m_minFrequency > 0.0) {
1119 int minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.01); 1121 int minbin = int((double(m_minFrequency) * getFFTSize()) / sr + 0.01);
1120 if (minbin < 1) minbin = 1; 1122 if (minbin < 1) minbin = 1;
1121 minf = minbin * sr / m_fftSize; 1123 minf = minbin * sr / getFFTSize();
1122 } 1124 }
1123 1125
1124 return minf; 1126 return minf;
1125 } 1127 }
1126 1128
1129 { 1131 {
1130 sv_samplerate_t sr = m_model->getSampleRate(); 1132 sv_samplerate_t sr = m_model->getSampleRate();
1131 double maxf = double(sr) / 2; 1133 double maxf = double(sr) / 2;
1132 1134
1133 if (m_maxFrequency > 0.0) { 1135 if (m_maxFrequency > 0.0) {
1134 int maxbin = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); 1136 int maxbin = int((double(m_maxFrequency) * getFFTSize()) / sr + 0.1);
1135 if (maxbin > m_fftSize / 2) maxbin = m_fftSize / 2; 1137 if (maxbin > getFFTSize() / 2) maxbin = getFFTSize() / 2;
1136 maxf = maxbin * sr / m_fftSize; 1138 maxf = maxbin * sr / getFFTSize();
1137 } 1139 }
1138 1140
1139 return maxf; 1141 return maxf;
1140 } 1142 }
1141 1143
1156 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); 1158 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic);
1157 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); 1159 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic);
1158 1160
1159 // Now map these on to ("proportions of") actual bins 1161 // Now map these on to ("proportions of") actual bins
1160 1162
1161 q0 = (q0 * m_fftSize) / sr; 1163 q0 = (q0 * getFFTSize()) / sr;
1162 q1 = (q1 * m_fftSize) / sr; 1164 q1 = (q1 * getFFTSize()) / sr;
1163 1165
1164 return true; 1166 return true;
1165 } 1167 }
1166 1168
1167 double 1169 double
1187 1189
1188 double q = v->getFrequencyForY(y, minf, maxf, logarithmic); 1190 double q = v->getFrequencyForY(y, minf, maxf, logarithmic);
1189 1191
1190 // Now map on to ("proportions of") actual bins 1192 // Now map on to ("proportions of") actual bins
1191 1193
1192 q = (q * getFFTSize(v)) / sr; 1194 q = (q * getFFTSize()) / sr;
1193 1195
1194 return q; 1196 return q;
1195 } 1197 }
1196 1198
1197 bool 1199 bool
1248 int q1i = int(q1); 1250 int q1i = int(q1);
1249 1251
1250 sv_samplerate_t sr = m_model->getSampleRate(); 1252 sv_samplerate_t sr = m_model->getSampleRate();
1251 1253
1252 for (int q = q0i; q <= q1i; ++q) { 1254 for (int q = q0i; q <= q1i; ++q) {
1253 if (q == q0i) freqMin = (sr * q) / m_fftSize; 1255 if (q == q0i) freqMin = (sr * q) / getFFTSize();
1254 if (q == q1i) freqMax = (sr * (q+1)) / m_fftSize; 1256 if (q == q1i) freqMax = (sr * (q+1)) / getFFTSize();
1255 } 1257 }
1256 return true; 1258 return true;
1257 } 1259 }
1258 1260
1259 bool 1261 bool
1297 if (q == q1i) freqMax = binfreq; 1299 if (q == q1i) freqMax = binfreq;
1298 1300
1299 if (peaksOnly && !fft->isLocalPeak(s, q)) continue; 1301 if (peaksOnly && !fft->isLocalPeak(s, q)) continue;
1300 1302
1301 if (!fft->isOverThreshold 1303 if (!fft->isOverThreshold
1302 (s, q, float(m_threshold * double(m_fftSize)/2.0))) { 1304 (s, q, float(m_threshold * double(getFFTSize())/2.0))) {
1303 continue; 1305 continue;
1304 } 1306 }
1305 1307
1306 double freq = binfreq; 1308 double freq = binfreq;
1307 1309
1368 1370
1369 value = fft->getPhaseAt(s, q); 1371 value = fft->getPhaseAt(s, q);
1370 if (!have || value < phaseMin) { phaseMin = value; } 1372 if (!have || value < phaseMin) { phaseMin = value; }
1371 if (!have || value > phaseMax) { phaseMax = value; } 1373 if (!have || value > phaseMax) { phaseMax = value; }
1372 1374
1373 value = fft->getMagnitudeAt(s, q) / (m_fftSize/2.0); 1375 value = fft->getMagnitudeAt(s, q) / (getFFTSize()/2.0);
1374 if (!have || value < min) { min = value; } 1376 if (!have || value < min) { min = value; }
1375 if (!have || value > max) { max = value; } 1377 if (!have || value > max) { max = value; }
1376 1378
1377 have = true; 1379 have = true;
1378 } 1380 }
1384 } 1386 }
1385 } 1387 }
1386 1388
1387 return rv; 1389 return rv;
1388 } 1390 }
1389
1390 int
1391 SpectrogramLayer::getFFTSize(const LayerGeometryProvider *) const
1392 {
1393 //!!!
1394 return m_fftSize;
1395 }
1396 1391
1397 FFTModel * 1392 FFTModel *
1398 SpectrogramLayer::getFFTModel(const LayerGeometryProvider *v) const 1393 SpectrogramLayer::getFFTModel(const LayerGeometryProvider *v) const
1399 { 1394 {
1400 if (!m_model) return 0; 1395 if (!m_model) return 0;
1401 1396
1402 int fftSize = getFFTSize(v); 1397 int fftSize = getFFTSize();
1403 1398
1404 const View *view = v->getView(); 1399 const View *view = v->getView();
1405 1400
1406 if (m_fftModels.find(view->getId()) != m_fftModels.end()) { 1401 if (m_fftModels.find(view->getId()) != m_fftModels.end()) {
1407 if (m_fftModels[view->getId()] == 0) { 1402 if (m_fftModels[view->getId()] == 0) {
1604 // and accountable for when determining whether we need the cache 1599 // and accountable for when determining whether we need the cache
1605 // in the cache-fill thread above. 1600 // in the cache-fill thread above.
1606 //!!! no inter use cache-fill thread 1601 //!!! no inter use cache-fill thread
1607 const_cast<SpectrogramLayer *>(this)->Layer::setLayerDormant(v, false); 1602 const_cast<SpectrogramLayer *>(this)->Layer::setLayerDormant(v, false);
1608 1603
1609 int fftSize = getFFTSize(v); 1604 int fftSize = getFFTSize();
1610 1605
1611 const View *view = v->getView(); 1606 const View *view = v->getView();
1612 ScrollableImageCache &cache = getImageCacheReference(view); 1607 ScrollableImageCache &cache = getImageCacheReference(view);
1613 1608
1614 #ifdef DEBUG_SPECTROGRAM_REPAINT 1609 #ifdef DEBUG_SPECTROGRAM_REPAINT
1747 // If we are zero padding (i.e. oversampling) we want to use the 1742 // If we are zero padding (i.e. oversampling) we want to use the
1748 // zero-padded equivalents of the bins that we would be using if 1743 // zero-padded equivalents of the bins that we would be using if
1749 // not zero padded, to avoid spaces at the top and bottom of the 1744 // not zero padded, to avoid spaces at the top and bottom of the
1750 // display. 1745 // display.
1751 1746
1752 int maxbin = m_fftSize / 2; 1747 int maxbin = fftSize / 2;
1753 if (m_maxFrequency > 0) { 1748 if (m_maxFrequency > 0) {
1754 maxbin = int((double(m_maxFrequency) * m_fftSize) / sr + 0.001); 1749 maxbin = int((double(m_maxFrequency) * fftSize) / sr + 0.001);
1755 if (maxbin > m_fftSize / 2) maxbin = m_fftSize / 2; 1750 if (maxbin > fftSize / 2) maxbin = fftSize / 2;
1756 } 1751 }
1757 1752
1758 int minbin = 1; 1753 int minbin = 1;
1759 if (m_minFrequency > 0) { 1754 if (m_minFrequency > 0) {
1760 minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.001); 1755 minbin = int((double(m_minFrequency) * fftSize) / sr + 0.001);
1761 // cerr << "m_minFrequency = " << m_minFrequency << " -> minbin = " << minbin << endl; 1756 // cerr << "m_minFrequency = " << m_minFrequency << " -> minbin = " << minbin << endl;
1762 if (minbin < 1) minbin = 1; 1757 if (minbin < 1) minbin = 1;
1763 if (minbin >= maxbin) minbin = maxbin - 1; 1758 if (minbin >= maxbin) minbin = maxbin - 1;
1764 } 1759 }
1765 1760
1771 double maxFreq = (double(maxbin) * sr) / fftSize; 1766 double maxFreq = (double(maxbin) * sr) / fftSize;
1772 1767
1773 double displayMinFreq = minFreq; 1768 double displayMinFreq = minFreq;
1774 double displayMaxFreq = maxFreq; 1769 double displayMaxFreq = maxFreq;
1775 1770
1776 if (fftSize != m_fftSize) { 1771 //!!! if (fftSize != getFFTSize()) {
1777 displayMinFreq = getEffectiveMinFrequency(); 1772 // displayMinFreq = getEffectiveMinFrequency();
1778 displayMaxFreq = getEffectiveMaxFrequency(); 1773 // displayMaxFreq = getEffectiveMaxFrequency();
1779 } 1774 // }
1780 1775
1781 // cerr << "(giving actual minFreq " << minFreq << " and display minFreq " << displayMinFreq << ")" << endl; 1776 // cerr << "(giving actual minFreq " << minFreq << " and display minFreq " << displayMinFreq << ")" << endl;
1782 1777
1783 int increment = getWindowIncrement(); 1778 int increment = getWindowIncrement();
1784 1779
2204 sx, 2199 sx,
2205 minbin, 2200 minbin,
2206 maxbin - minbin + 1); 2201 maxbin - minbin + 1);
2207 2202
2208 if (m_colourScale != PhaseColourScale) { 2203 if (m_colourScale != PhaseColourScale) {
2209 column = ColumnOp::fftScale(column, m_fftSize); 2204 column = ColumnOp::fftScale(column, getFFTSize());
2210 } 2205 }
2211 2206
2212 recordColumnExtents(column, 2207 recordColumnExtents(column,
2213 sx, 2208 sx,
2214 overallMag, 2209 overallMag,
2465 minbin, 2460 minbin,
2466 maxbin - minbin + 1); 2461 maxbin - minbin + 1);
2467 } 2462 }
2468 2463
2469 if (m_colourScale != PhaseColourScale) { 2464 if (m_colourScale != PhaseColourScale) {
2470 column = ColumnOp::fftScale(column, m_fftSize); 2465 column = ColumnOp::fftScale(column, getFFTSize());
2471 } 2466 }
2472 2467
2473 recordColumnExtents(column, 2468 recordColumnExtents(column,
2474 sx, 2469 sx,
2475 overallMag, 2470 overallMag,
2627 bool &logarithmic, QString &unit) const 2622 bool &logarithmic, QString &unit) const
2628 { 2623 {
2629 if (!m_model) return false; 2624 if (!m_model) return false;
2630 2625
2631 sv_samplerate_t sr = m_model->getSampleRate(); 2626 sv_samplerate_t sr = m_model->getSampleRate();
2632 min = double(sr) / m_fftSize; 2627 min = double(sr) / getFFTSize();
2633 max = double(sr) / 2; 2628 max = double(sr) / 2;
2634 2629
2635 logarithmic = (m_frequencyScale == LogFrequencyScale); 2630 logarithmic = (m_frequencyScale == LogFrequencyScale);
2636 unit = "Hz"; 2631 unit = "Hz";
2637 return true; 2632 return true;
3006 int h = rect.height(), w = rect.width(); 3001 int h = rect.height(), w = rect.width();
3007 3002
3008 int tickw = (m_frequencyScale == LogFrequencyScale ? 10 : 4); 3003 int tickw = (m_frequencyScale == LogFrequencyScale ? 10 : 4);
3009 int pkw = (m_frequencyScale == LogFrequencyScale ? 10 : 0); 3004 int pkw = (m_frequencyScale == LogFrequencyScale ? 10 : 0);
3010 3005
3011 int bins = m_fftSize / 2; 3006 int bins = getFFTSize() / 2;
3012 sv_samplerate_t sr = m_model->getSampleRate(); 3007 sv_samplerate_t sr = m_model->getSampleRate();
3013 3008
3014 if (m_maxFrequency > 0) { 3009 if (m_maxFrequency > 0) {
3015 bins = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); 3010 bins = int((double(m_maxFrequency) * getFFTSize()) / sr + 0.1);
3016 if (bins > m_fftSize / 2) bins = m_fftSize / 2; 3011 if (bins > getFFTSize() / 2) bins = getFFTSize() / 2;
3017 } 3012 }
3018 3013
3019 int cw = 0; 3014 int cw = 0;
3020 3015
3021 if (detailed) cw = getColourScaleWidth(paint); 3016 if (detailed) cw = getColourScaleWidth(paint);
3125 bin = int(q0); 3120 bin = int(q0);
3126 } else { 3121 } else {
3127 continue; 3122 continue;
3128 } 3123 }
3129 3124
3130 int freq = int((sr * bin) / m_fftSize); 3125 int freq = int((sr * bin) / getFFTSize());
3131 3126
3132 if (py >= 0 && (vy - py) < textHeight - 1) { 3127 if (py >= 0 && (vy - py) < textHeight - 1) {
3133 if (m_frequencyScale == LinearFrequencyScale) { 3128 if (m_frequencyScale == LinearFrequencyScale) {
3134 paint.drawLine(w - tickw, h - vy, w, h - vy); 3129 paint.drawLine(w - tickw, h - vy, w, h - vy);
3135 } 3130 }
3222 { 3217 {
3223 if (!m_model) return 0; 3218 if (!m_model) return 0;
3224 3219
3225 sv_samplerate_t sr = m_model->getSampleRate(); 3220 sv_samplerate_t sr = m_model->getSampleRate();
3226 3221
3227 SpectrogramRangeMapper mapper(sr, m_fftSize); 3222 SpectrogramRangeMapper mapper(sr, getFFTSize());
3228 3223
3229 // int maxStep = mapper.getPositionForValue((double(sr) / m_fftSize) + 0.001); 3224 // int maxStep = mapper.getPositionForValue((double(sr) / getFFTSize()) + 0.001);
3230 int maxStep = mapper.getPositionForValue(0); 3225 int maxStep = mapper.getPositionForValue(0);
3231 int minStep = mapper.getPositionForValue(double(sr) / 2); 3226 int minStep = mapper.getPositionForValue(double(sr) / 2);
3232 3227
3233 int initialMax = m_initialMaxFrequency; 3228 int initialMax = m_initialMaxFrequency;
3234 if (initialMax == 0) initialMax = int(sr / 2); 3229 if (initialMax == 0) initialMax = int(sr / 2);
3246 if (!m_model) return 0; 3241 if (!m_model) return 0;
3247 3242
3248 double dmin, dmax; 3243 double dmin, dmax;
3249 getDisplayExtents(dmin, dmax); 3244 getDisplayExtents(dmin, dmax);
3250 3245
3251 SpectrogramRangeMapper mapper(m_model->getSampleRate(), m_fftSize); 3246 SpectrogramRangeMapper mapper(m_model->getSampleRate(), getFFTSize());
3252 int n = mapper.getPositionForValue(dmax - dmin); 3247 int n = mapper.getPositionForValue(dmax - dmin);
3253 // SVDEBUG << "SpectrogramLayer::getCurrentVerticalZoomStep: " << n << endl; 3248 // SVDEBUG << "SpectrogramLayer::getCurrentVerticalZoomStep: " << n << endl;
3254 return n; 3249 return n;
3255 } 3250 }
3256 3251
3263 // getDisplayExtents(dmin, dmax); 3258 // getDisplayExtents(dmin, dmax);
3264 3259
3265 // cerr << "current range " << dmin << " -> " << dmax << ", range " << dmax-dmin << ", mid " << (dmax + dmin)/2 << endl; 3260 // cerr << "current range " << dmin << " -> " << dmax << ", range " << dmax-dmin << ", mid " << (dmax + dmin)/2 << endl;
3266 3261
3267 sv_samplerate_t sr = m_model->getSampleRate(); 3262 sv_samplerate_t sr = m_model->getSampleRate();
3268 SpectrogramRangeMapper mapper(sr, m_fftSize); 3263 SpectrogramRangeMapper mapper(sr, getFFTSize());
3269 double newdist = mapper.getValueForPosition(step); 3264 double newdist = mapper.getValueForPosition(step);
3270 3265
3271 double newmin, newmax; 3266 double newmin, newmax;
3272 3267
3273 if (m_frequencyScale == LogFrequencyScale) { 3268 if (m_frequencyScale == LogFrequencyScale) {
3324 3319
3325 RangeMapper * 3320 RangeMapper *
3326 SpectrogramLayer::getNewVerticalZoomRangeMapper() const 3321 SpectrogramLayer::getNewVerticalZoomRangeMapper() const
3327 { 3322 {
3328 if (!m_model) return 0; 3323 if (!m_model) return 0;
3329 return new SpectrogramRangeMapper(m_model->getSampleRate(), m_fftSize); 3324 return new SpectrogramRangeMapper(m_model->getSampleRate(), getFFTSize());
3330 } 3325 }
3331 3326
3332 void 3327 void
3333 SpectrogramLayer::updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const 3328 SpectrogramLayer::updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const
3334 { 3329 {
3520 // Tony v1.0 is (and hopefully will remain!) the only released 3515 // Tony v1.0 is (and hopefully will remain!) the only released
3521 // SV-a-like to use old-style attributes when saving sessions 3516 // SV-a-like to use old-style attributes when saving sessions
3522 // that ask for hybrid normalization. It saves them with the 3517 // that ask for hybrid normalization. It saves them with the
3523 // wrong gain factor, so hack in a fix for that here -- this 3518 // wrong gain factor, so hack in a fix for that here -- this
3524 // gives us backward but not forward compatibility. 3519 // gives us backward but not forward compatibility.
3525 setGain(m_gain / float(m_fftSize / 2)); 3520 setGain(m_gain / float(getFFTSize() / 2));
3526 } 3521 }
3527 } 3522 }
3528 3523