Mercurial > hg > svgui
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 |