Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 277:8acd30ed735c
* Fix up and simplify the LayerTreeModel, removing a horrible memory leak
* Move phase-unwrapped frequency estimation from SpectrogramLayer to
  FFTDataServer
* Make the spectrum show peak phase-unwrapped frequencies as well (still
  needs work)
* Start adding piano keyboard horizontal scale to spectrum
* Debug output for id3 tags
| author | Chris Cannam | 
|---|---|
| date | Tue, 03 Jul 2007 12:46:18 +0000 | 
| parents | e954c00cbe55 | 
| children | a078aa2932cc | 
   comparison
  equal
  deleted
  inserted
  replaced
| 276:21c7152ddba8 | 277:8acd30ed735c | 
|---|---|
| 1062 for (int pixel = 0; pixel < 256; ++pixel) { | 1062 for (int pixel = 0; pixel < 256; ++pixel) { | 
| 1063 m_palette.setColour(pixel, newPixels[pixel]); | 1063 m_palette.setColour(pixel, newPixels[pixel]); | 
| 1064 } | 1064 } | 
| 1065 } | 1065 } | 
| 1066 | 1066 | 
| 1067 float | |
| 1068 SpectrogramLayer::calculateFrequency(size_t bin, | |
| 1069 size_t windowSize, | |
| 1070 size_t windowIncrement, | |
| 1071 size_t sampleRate, | |
| 1072 float oldPhase, | |
| 1073 float newPhase, | |
| 1074 bool &steadyState) | |
| 1075 { | |
| 1076 // At frequency f, phase shift of 2pi (one cycle) happens in 1/f sec. | |
| 1077 // At hopsize h and sample rate sr, one hop happens in h/sr sec. | |
| 1078 // At window size w, for bin b, f is b*sr/w. | |
| 1079 // thus 2pi phase shift happens in w/(b*sr) sec. | |
| 1080 // We need to know what phase shift we expect from h/sr sec. | |
| 1081 // -> 2pi * ((h/sr) / (w/(b*sr))) | |
| 1082 // = 2pi * ((h * b * sr) / (w * sr)) | |
| 1083 // = 2pi * (h * b) / w. | |
| 1084 | |
| 1085 float frequency = (float(bin) * sampleRate) / windowSize; | |
| 1086 | |
| 1087 float expectedPhase = | |
| 1088 oldPhase + (2.0 * M_PI * bin * windowIncrement) / windowSize; | |
| 1089 | |
| 1090 float phaseError = princargf(newPhase - expectedPhase); | |
| 1091 | |
| 1092 if (fabsf(phaseError) < (1.1f * (windowIncrement * M_PI) / windowSize)) { | |
| 1093 | |
| 1094 // The new frequency estimate based on the phase error | |
| 1095 // resulting from assuming the "native" frequency of this bin | |
| 1096 | |
| 1097 float newFrequency = | |
| 1098 (sampleRate * (expectedPhase + phaseError - oldPhase)) / | |
| 1099 (2 * M_PI * windowIncrement); | |
| 1100 | |
| 1101 steadyState = true; | |
| 1102 return newFrequency; | |
| 1103 } | |
| 1104 | |
| 1105 steadyState = false; | |
| 1106 return frequency; | |
| 1107 } | |
| 1108 | |
| 1109 unsigned char | 1067 unsigned char | 
| 1110 SpectrogramLayer::getDisplayValue(View *v, float input) const | 1068 SpectrogramLayer::getDisplayValue(View *v, float input) const | 
| 1111 { | 1069 { | 
| 1112 int value; | 1070 int value; | 
| 1113 | 1071 | 
| 1361 SpectrogramLayer::getAdjustedYBinSourceRange(View *v, int x, int y, | 1319 SpectrogramLayer::getAdjustedYBinSourceRange(View *v, int x, int y, | 
| 1362 float &freqMin, float &freqMax, | 1320 float &freqMin, float &freqMax, | 
| 1363 float &adjFreqMin, float &adjFreqMax) | 1321 float &adjFreqMin, float &adjFreqMax) | 
| 1364 const | 1322 const | 
| 1365 { | 1323 { | 
| 1324 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | |
| 1325 return false; | |
| 1326 } | |
| 1327 | |
| 1366 FFTModel *fft = getFFTModel(v); | 1328 FFTModel *fft = getFFTModel(v); | 
| 1367 if (!fft) return false; | 1329 if (!fft) return false; | 
| 1368 | 1330 | 
| 1369 float s0 = 0, s1 = 0; | 1331 float s0 = 0, s1 = 0; | 
| 1370 if (!getXBinRange(v, x, s0, s1)) return false; | 1332 if (!getXBinRange(v, x, s0, s1)) return false; | 
| 1405 float freq = binfreq; | 1367 float freq = binfreq; | 
| 1406 bool steady = false; | 1368 bool steady = false; | 
| 1407 | 1369 | 
| 1408 if (s < int(fft->getWidth()) - 1) { | 1370 if (s < int(fft->getWidth()) - 1) { | 
| 1409 | 1371 | 
| 1410 freq = calculateFrequency(q, | 1372 fft->estimateStableFrequency(s, q, freq); | 
| 1411 windowSize, | |
| 1412 windowIncrement, | |
| 1413 sr, | |
| 1414 fft->getPhaseAt(s, q), | |
| 1415 fft->getPhaseAt(s+1, q), | |
| 1416 steady); | |
| 1417 | 1373 | 
| 1418 if (!haveAdj || freq < adjFreqMin) adjFreqMin = freq; | 1374 if (!haveAdj || freq < adjFreqMin) adjFreqMin = freq; | 
| 1419 if (!haveAdj || freq > adjFreqMax) adjFreqMax = freq; | 1375 if (!haveAdj || freq > adjFreqMax) adjFreqMax = freq; | 
| 1420 | 1376 | 
| 1421 haveAdj = true; | 1377 haveAdj = true; | 
| 1433 bool | 1389 bool | 
| 1434 SpectrogramLayer::getXYBinSourceRange(View *v, int x, int y, | 1390 SpectrogramLayer::getXYBinSourceRange(View *v, int x, int y, | 
| 1435 float &min, float &max, | 1391 float &min, float &max, | 
| 1436 float &phaseMin, float &phaseMax) const | 1392 float &phaseMin, float &phaseMax) const | 
| 1437 { | 1393 { | 
| 1394 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | |
| 1395 return false; | |
| 1396 } | |
| 1397 | |
| 1438 float q0 = 0, q1 = 0; | 1398 float q0 = 0, q1 = 0; | 
| 1439 if (!getYBinRange(v, y, q0, q1)) return false; | 1399 if (!getYBinRange(v, y, q0, q1)) return false; | 
| 1440 | 1400 | 
| 1441 float s0 = 0, s1 = 0; | 1401 float s0 = 0, s1 = 0; | 
| 1442 if (!getXBinRange(v, x, s0, s1)) return false; | 1402 if (!getXBinRange(v, x, s0, s1)) return false; | 
| 2131 if (s == s1i) sprop *= s1 - s; | 2091 if (s == s1i) sprop *= s1 - s; | 
| 2132 | 2092 | 
| 2133 if (m_binDisplay == PeakFrequencies && | 2093 if (m_binDisplay == PeakFrequencies && | 
| 2134 s < int(fft->getWidth()) - 1) { | 2094 s < int(fft->getWidth()) - 1) { | 
| 2135 | 2095 | 
| 2136 bool steady = false; | 2096 float f = 0; | 
| 2137 float f = calculateFrequency(q, | 2097 fft->estimateStableFrequency(s, q, f); | 
| 2138 m_windowSize, | |
| 2139 increment, | |
| 2140 sr, | |
| 2141 fft->getPhaseAt(s, q), | |
| 2142 fft->getPhaseAt(s+1, q), | |
| 2143 steady); | |
| 2144 | 2098 | 
| 2145 y0 = y1 = v->getYForFrequency | 2099 y0 = y1 = v->getYForFrequency | 
| 2146 (f, displayMinFreq, displayMaxFreq, logarithmic); | 2100 (f, displayMinFreq, displayMaxFreq, logarithmic); | 
| 2147 } | 2101 } | 
| 2148 | 2102 | 
| 2853 py = vy; | 2807 py = vy; | 
| 2854 } | 2808 } | 
| 2855 | 2809 | 
| 2856 if (m_frequencyScale == LogFrequencyScale) { | 2810 if (m_frequencyScale == LogFrequencyScale) { | 
| 2857 | 2811 | 
| 2812 // piano keyboard | |
| 2813 | |
| 2858 paint.drawLine(w - pkw - 1, 0, w - pkw - 1, h); | 2814 paint.drawLine(w - pkw - 1, 0, w - pkw - 1, h); | 
| 2859 | 2815 | 
| 2860 float minf = getEffectiveMinFrequency(); | 2816 float minf = getEffectiveMinFrequency(); | 
| 2861 float maxf = getEffectiveMaxFrequency(); | 2817 float maxf = getEffectiveMaxFrequency(); | 
| 2862 | 2818 | 
| 2877 | 2833 | 
| 2878 if (n == 1) { | 2834 if (n == 1) { | 
| 2879 // C# -- fill the C from here | 2835 // C# -- fill the C from here | 
| 2880 if (ppy - y > 2) { | 2836 if (ppy - y > 2) { | 
| 2881 paint.fillRect(w - pkw, | 2837 paint.fillRect(w - pkw, | 
| 2882 // y - (py - y) / 2 - (py - y) / 4, | |
| 2883 y, | 2838 y, | 
| 2884 pkw, | 2839 pkw, | 
| 2885 (py + ppy) / 2 - y, | 2840 (py + ppy) / 2 - y, | 
| 2886 // py - y + 1, | |
| 2887 Qt::gray); | 2841 Qt::gray); | 
| 2888 } | 2842 } | 
| 2889 } | 2843 } | 
| 2890 | 2844 | 
| 2891 if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) { | 2845 if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) { | 
