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"