Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 36:c28ebb4ba4de
* Improvements to text layer editing, and implement file I/O for it
* Start some fixes to spectrogram frequency computation
author | Chris Cannam |
---|---|
date | Mon, 20 Feb 2006 17:23:40 +0000 |
parents | 10ba9276a315 |
children | 21d061e66177 |
comparison
equal
deleted
inserted
replaced
35:10ba9276a315 | 36:c28ebb4ba4de |
---|---|
43 m_maxFrequency(8000), | 43 m_maxFrequency(8000), |
44 m_colourScale(dBColourScale), | 44 m_colourScale(dBColourScale), |
45 m_colourScheme(DefaultColours), | 45 m_colourScheme(DefaultColours), |
46 m_frequencyScale(LinearFrequencyScale), | 46 m_frequencyScale(LinearFrequencyScale), |
47 m_frequencyAdjustment(RawFrequency), | 47 m_frequencyAdjustment(RawFrequency), |
48 m_normalizeColumns(false), | |
48 m_cache(0), | 49 m_cache(0), |
49 m_phaseAdjustCache(0), | 50 m_phaseAdjustCache(0), |
50 m_cacheInvalid(true), | 51 m_cacheInvalid(true), |
51 m_pixmapCache(0), | 52 m_pixmapCache(0), |
52 m_pixmapCacheInvalid(true), | 53 m_pixmapCacheInvalid(true), |
122 list.push_back(tr("Colour")); | 123 list.push_back(tr("Colour")); |
123 list.push_back(tr("Colour Scale")); | 124 list.push_back(tr("Colour Scale")); |
124 list.push_back(tr("Window Type")); | 125 list.push_back(tr("Window Type")); |
125 list.push_back(tr("Window Size")); | 126 list.push_back(tr("Window Size")); |
126 list.push_back(tr("Window Overlap")); | 127 list.push_back(tr("Window Overlap")); |
128 list.push_back(tr("Normalize")); | |
127 list.push_back(tr("Gain")); | 129 list.push_back(tr("Gain")); |
128 list.push_back(tr("Colour Rotation")); | 130 list.push_back(tr("Colour Rotation")); |
129 list.push_back(tr("Max Frequency")); | 131 list.push_back(tr("Max Frequency")); |
130 list.push_back(tr("Frequency Scale")); | 132 list.push_back(tr("Frequency Scale")); |
131 list.push_back(tr("Frequency Adjustment")); | 133 list.push_back(tr("Frequency Adjustment")); |
135 Layer::PropertyType | 137 Layer::PropertyType |
136 SpectrogramLayer::getPropertyType(const PropertyName &name) const | 138 SpectrogramLayer::getPropertyType(const PropertyName &name) const |
137 { | 139 { |
138 if (name == tr("Gain")) return RangeProperty; | 140 if (name == tr("Gain")) return RangeProperty; |
139 if (name == tr("Colour Rotation")) return RangeProperty; | 141 if (name == tr("Colour Rotation")) return RangeProperty; |
142 if (name == tr("Normalize")) return ToggleProperty; | |
140 return ValueProperty; | 143 return ValueProperty; |
141 } | 144 } |
142 | 145 |
143 QString | 146 QString |
144 SpectrogramLayer::getPropertyGroupName(const PropertyName &name) const | 147 SpectrogramLayer::getPropertyGroupName(const PropertyName &name) const |
147 name == tr("Window Type") || | 150 name == tr("Window Type") || |
148 name == tr("Window Overlap")) return tr("Window"); | 151 name == tr("Window Overlap")) return tr("Window"); |
149 if (name == tr("Colour") || | 152 if (name == tr("Colour") || |
150 name == tr("Colour Rotation")) return tr("Colour"); | 153 name == tr("Colour Rotation")) return tr("Colour"); |
151 if (name == tr("Gain") || | 154 if (name == tr("Gain") || |
155 name == tr("Normalize") || | |
152 name == tr("Colour Scale")) return tr("Scale"); | 156 name == tr("Colour Scale")) return tr("Scale"); |
153 if (name == tr("Max Frequency") || | 157 if (name == tr("Max Frequency") || |
154 name == tr("Frequency Scale") || | 158 name == tr("Frequency Scale") || |
155 name == tr("Frequency Adjustment")) return tr("Frequency"); | 159 name == tr("Frequency Adjustment")) return tr("Frequency"); |
156 return QString(); | 160 return QString(); |
247 } else if (name == tr("Frequency Adjustment")) { | 251 } else if (name == tr("Frequency Adjustment")) { |
248 | 252 |
249 *min = 0; | 253 *min = 0; |
250 *max = 2; | 254 *max = 2; |
251 deft = (int)m_frequencyAdjustment; | 255 deft = (int)m_frequencyAdjustment; |
256 | |
257 } else if (name == tr("Normalize")) { | |
258 | |
259 deft = (m_normalizeColumns ? 1 : 0); | |
252 | 260 |
253 } else { | 261 } else { |
254 deft = Layer::getPropertyRangeAndValue(name, min, max); | 262 deft = Layer::getPropertyRangeAndValue(name, min, max); |
255 } | 263 } |
256 | 264 |
397 default: | 405 default: |
398 case 0: setFrequencyAdjustment(RawFrequency); break; | 406 case 0: setFrequencyAdjustment(RawFrequency); break; |
399 case 1: setFrequencyAdjustment(PhaseAdjustedFrequency); break; | 407 case 1: setFrequencyAdjustment(PhaseAdjustedFrequency); break; |
400 case 2: setFrequencyAdjustment(PhaseAdjustedPeaks); break; | 408 case 2: setFrequencyAdjustment(PhaseAdjustedPeaks); break; |
401 } | 409 } |
410 } else if (name == "Normalize") { | |
411 setNormalizeColumns(value ? true : false); | |
402 } | 412 } |
403 } | 413 } |
404 | 414 |
405 void | 415 void |
406 SpectrogramLayer::setChannel(int ch) | 416 SpectrogramLayer::setChannel(int ch) |
655 | 665 |
656 SpectrogramLayer::FrequencyAdjustment | 666 SpectrogramLayer::FrequencyAdjustment |
657 SpectrogramLayer::getFrequencyAdjustment() const | 667 SpectrogramLayer::getFrequencyAdjustment() const |
658 { | 668 { |
659 return m_frequencyAdjustment; | 669 return m_frequencyAdjustment; |
670 } | |
671 | |
672 void | |
673 SpectrogramLayer::setNormalizeColumns(bool n) | |
674 { | |
675 if (m_normalizeColumns == n) return; | |
676 m_mutex.lock(); | |
677 | |
678 m_cacheInvalid = true; | |
679 m_pixmapCacheInvalid = true; | |
680 m_normalizeColumns = n; | |
681 m_mutex.unlock(); | |
682 | |
683 fillCache(); | |
684 emit layerParametersChanged(); | |
685 } | |
686 | |
687 bool | |
688 SpectrogramLayer::getNormalizeColumns() const | |
689 { | |
690 return m_normalizeColumns; | |
660 } | 691 } |
661 | 692 |
662 void | 693 void |
663 SpectrogramLayer::setLayerDormant(bool dormant) | 694 SpectrogramLayer::setLayerDormant(bool dormant) |
664 { | 695 { |
920 | 951 |
921 bool interrupted = false; | 952 bool interrupted = false; |
922 | 953 |
923 double prevMag = 0.0; | 954 double prevMag = 0.0; |
924 | 955 |
925 for (size_t i = 0; i < windowSize / 2; ++i) { | 956 double maxMag = 0.0; |
926 | 957 if (m_normalizeColumns) { |
927 int value = 0; | 958 for (size_t i = 0; i < windowSize/2; ++i) { |
928 double phase = 0.0; | |
929 | |
930 double mag = sqrt(output[i][0] * output[i][0] + | 959 double mag = sqrt(output[i][0] * output[i][0] + |
931 output[i][1] * output[i][1]); | 960 output[i][1] * output[i][1]); |
932 mag /= windowSize / 2; | 961 mag /= windowSize / 2; |
962 if (mag > maxMag) maxMag = mag; | |
963 } | |
964 } | |
965 | |
966 for (size_t i = 0; i < windowSize / 2; ++i) { | |
967 | |
968 int value = 0; | |
969 double phase = 0.0; | |
970 | |
971 double mag = sqrt(output[i][0] * output[i][0] + | |
972 output[i][1] * output[i][1]); | |
973 mag /= windowSize / 2; | |
974 | |
975 if (m_normalizeColumns && maxMag > 0.0) { | |
976 mag /= maxMag; | |
977 } | |
933 | 978 |
934 if (phaseAdjust || (m_colourScale == PhaseColourScale)) { | 979 if (phaseAdjust || (m_colourScale == PhaseColourScale)) { |
935 | 980 |
936 // phase = atan2(-output[i][1], output[i][0]); | 981 // phase = atan2(-output[i][1], output[i][0]); |
937 // phase = atan2(output[i][1], output[i][0]); | 982 // phase = atan2(output[i][1], output[i][0]); |
940 } | 985 } |
941 | 986 |
942 if (phaseAdjust && m_phaseAdjustCache && haveStoredPhase) { | 987 if (phaseAdjust && m_phaseAdjustCache && haveStoredPhase) { |
943 | 988 |
944 bool peak = true; | 989 bool peak = true; |
945 if (m_frequencyAdjustment == PhaseAdjustedPeaks) { | 990 // if (m_frequencyAdjustment == PhaseAdjustedPeaks) { |
991 if (true) { //!!! | |
946 if (mag < prevMag) peak = false; | 992 if (mag < prevMag) peak = false; |
947 else { | 993 else { |
948 double nextMag = 0.0; | 994 double nextMag = 0.0; |
949 if (i < windowSize / 2 - 1) { | 995 if (i < windowSize / 2 - 1) { |
950 nextMag = sqrt(output[i+1][0] * output[i+1][0] + | 996 nextMag = sqrt(output[i+1][0] * output[i+1][0] + |
951 output[i+1][1] * output[i+1][1]); | 997 output[i+1][1] * output[i+1][1]); |
952 nextMag /= windowSize / 2; | 998 nextMag /= windowSize / 2; |
999 if (m_normalizeColumns && maxMag > 0.0) { | |
1000 nextMag /= maxMag; | |
1001 } | |
953 } | 1002 } |
954 if (mag < nextMag) peak = false; | 1003 if (mag < nextMag) peak = false; |
955 } | 1004 } |
956 prevMag = mag; | 1005 prevMag = mag; |
957 } | 1006 } |
962 break; | 1011 break; |
963 } | 1012 } |
964 m_phaseAdjustCache->setValueAt(column, i, SCHAR_MIN); | 1013 m_phaseAdjustCache->setValueAt(column, i, SCHAR_MIN); |
965 } else { | 1014 } else { |
966 | 1015 |
967 // if (i > 45 && i < 55 && counter == 10) { | 1016 if (i < 100 && counter == 10) { |
968 | 1017 |
1018 // if (counter == 10) { | |
1019 | |
969 double freq = (double(i) * sampleRate) / m_windowSize; | 1020 double freq = (double(i) * sampleRate) / m_windowSize; |
970 // std::cout << "\nbin = " << i << " initial estimate freq = " << freq | 1021 // std::cout << "\nbin = " << i << " initial estimate freq = " << freq |
971 // << " mag = " << mag << std::endl; | 1022 // << " mag = " << mag << std::endl; |
972 | 1023 |
973 double prevPhase = storedPhase[i]; | 1024 double prevPhase = storedPhase[i]; |
974 | 1025 |
1026 // If the frequency is 100Hz and the sample rate is | |
1027 // 10000Hz and we have 1000 samples (1/10sec) per bin, | |
1028 // then we expect phase 0 | |
1029 | |
1030 // 2pi happens in 1/freq sec | |
1031 // one hop happens in hopsize/sr sec | |
1032 // freq is bin*sr / windowsize | |
1033 // thus 2pi happens in windowsize/(bin*sr) sec | |
1034 | |
1035 // need to know what phase increment we expect from | |
1036 // hopsize/sr sec | |
1037 // must be 2pi * ((hopsize/sr) / (windowsize/(bin*sr))) | |
1038 // = 2pi * ((hopsize * bin * sr) / (windowsize * sr)) | |
1039 // = 2pi * (hopsize * bin) / windowsize | |
1040 | |
975 double expectedPhase = | 1041 double expectedPhase = |
976 prevPhase + (2 * M_PI * i * increment) / m_windowSize; | 1042 prevPhase + (2.0 * M_PI * i * increment) / m_windowSize; |
977 | 1043 |
978 double phaseError = MathUtilities::princarg(phase - expectedPhase); | 1044 double phaseError = MathUtilities::princarg(phase - expectedPhase); |
979 | 1045 |
980 // if (fabs(phaseError) > (1.2 * (increment * M_PI) / m_windowSize)) { | 1046 // if (fabs(phaseError) > (1.2 * (increment * M_PI) / m_windowSize)) { |
981 // std::cout << "error > " << (1.2 * (increment * M_PI) / m_windowSize) << std::endl; | 1047 // std::cout << "error > " << (1.2 * (increment * M_PI) / m_windowSize) << std::endl; |
982 // }// else { | 1048 // }// else { |
983 | 1049 |
984 // std::cout << "prevPhase = " << prevPhase << ", phase = " << phase | 1050 std::cout << "prev = " << prevPhase << ", phase = " << phase |
985 // << ", expected = " << MathUtilities::princarg(expectedPhase) << ", error = " | 1051 << ", exp = " << expectedPhase << " prin = " << MathUtilities::princarg(expectedPhase) << ", error = " |
986 // << phaseError << std::endl; | 1052 << phaseError << " inc = " << increment << " i = " << i << ", pi = " << M_PI << std::endl; |
987 | 1053 |
988 double newFreq = | 1054 double newFreq = |
989 (sampleRate * | 1055 (sampleRate * |
990 (expectedPhase + phaseError - prevPhase)) / | 1056 (expectedPhase + phaseError - prevPhase)) / |
991 //(prevPhase - (expectedPhase + phaseError))) / | 1057 //(prevPhase - (expectedPhase + phaseError))) / |
992 (2 * M_PI * increment); | 1058 (2 * M_PI * increment); |
993 | 1059 |
994 // std::cout << freq << " (" << Pitch::getPitchLabelForFrequency(freq).toStdString() << ") -> " << newFreq << " (" << Pitch::getPitchLabelForFrequency(newFreq).toStdString() << ")" << std::endl; | 1060 std::cout << freq << " (" << Pitch::getPitchLabelForFrequency(freq).toStdString() << ") -> " << newFreq << " (" << Pitch::getPitchLabelForFrequency(newFreq).toStdString() << ")" << std::endl; |
995 // } | 1061 // } |
996 //} | |
997 | 1062 |
998 double binRange = (double(i + 1) * sampleRate) / windowSize - freq; | 1063 double binRange = (double(i + 1) * sampleRate) / windowSize - freq; |
999 | 1064 |
1000 int offset = lrint(((newFreq - freq) / binRange) * 10);//!!! | 1065 int offset = lrint(((newFreq - freq) / binRange) * 10);//!!! |
1001 | 1066 |
1008 m_phaseAdjustCache->setValueAt(column, i, (unsigned char)coff); | 1073 m_phaseAdjustCache->setValueAt(column, i, (unsigned char)coff); |
1009 } else { | 1074 } else { |
1010 m_phaseAdjustCache->setValueAt(column, i, 0); | 1075 m_phaseAdjustCache->setValueAt(column, i, 0); |
1011 } | 1076 } |
1012 } | 1077 } |
1078 } | |
1079 | |
1013 storedPhase[i] = phase; | 1080 storedPhase[i] = phase; |
1014 } | 1081 } |
1015 | 1082 |
1016 if (m_colourScale == PhaseColourScale) { | 1083 if (m_colourScale == PhaseColourScale) { |
1017 | 1084 |
1018 phase = MathUtilities::princarg(phase); | 1085 phase = MathUtilities::princarg(phase); |
1019 value = int((phase * 128 / M_PI) + 128); | 1086 value = int((phase * 128 / M_PI) + 128); |
1020 | 1087 |
1021 } else { | 1088 } else { |
1022 | |
1023 double mag = sqrt(output[i][0] * output[i][0] + | |
1024 output[i][1] * output[i][1]); | |
1025 mag /= windowSize / 2; | |
1026 | 1089 |
1027 switch (m_colourScale) { | 1090 switch (m_colourScale) { |
1028 | 1091 |
1029 default: | 1092 default: |
1030 case LinearColourScale: | 1093 case LinearColourScale: |
2171 | 2234 |
2172 s += QString("maxFrequency=\"%1\" " | 2235 s += QString("maxFrequency=\"%1\" " |
2173 "colourScale=\"%2\" " | 2236 "colourScale=\"%2\" " |
2174 "colourScheme=\"%3\" " | 2237 "colourScheme=\"%3\" " |
2175 "frequencyScale=\"%4\" " | 2238 "frequencyScale=\"%4\" " |
2176 "frequencyAdjustment=\"%5\"") | 2239 "frequencyAdjustment=\"%5\" " |
2240 "normalizeColumns=\"%6\"") | |
2177 .arg(m_maxFrequency) | 2241 .arg(m_maxFrequency) |
2178 .arg(m_colourScale) | 2242 .arg(m_colourScale) |
2179 .arg(m_colourScheme) | 2243 .arg(m_colourScheme) |
2180 .arg(m_frequencyScale) | 2244 .arg(m_frequencyScale) |
2181 .arg(m_frequencyAdjustment); | 2245 .arg(m_frequencyAdjustment) |
2246 .arg(m_normalizeColumns ? "true" : "false"); | |
2182 | 2247 |
2183 return Layer::toXmlString(indent, extraAttributes + " " + s); | 2248 return Layer::toXmlString(indent, extraAttributes + " " + s); |
2184 } | 2249 } |
2185 | 2250 |
2186 void | 2251 void |
2220 if (ok) setFrequencyScale(frequencyScale); | 2285 if (ok) setFrequencyScale(frequencyScale); |
2221 | 2286 |
2222 FrequencyAdjustment frequencyAdjustment = (FrequencyAdjustment) | 2287 FrequencyAdjustment frequencyAdjustment = (FrequencyAdjustment) |
2223 attributes.value("frequencyAdjustment").toInt(&ok); | 2288 attributes.value("frequencyAdjustment").toInt(&ok); |
2224 if (ok) setFrequencyAdjustment(frequencyAdjustment); | 2289 if (ok) setFrequencyAdjustment(frequencyAdjustment); |
2290 | |
2291 bool normalizeColumns = | |
2292 (attributes.value("normalizeColumns").trimmed() == "true"); | |
2293 setNormalizeColumns(normalizeColumns); | |
2225 } | 2294 } |
2226 | 2295 |
2227 | 2296 |
2228 #ifdef INCLUDE_MOCFILES | 2297 #ifdef INCLUDE_MOCFILES |
2229 #include "SpectrogramLayer.moc.cpp" | 2298 #include "SpectrogramLayer.moc.cpp" |