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) { |