comparison layer/SpectrogramLayer.cpp @ 38:beb801473743

* Rearrange spectrogram cacheing so that gain, normalization, instantaneous frequency calculations etc can be done from the cached data (increasing the size of the cache, but also the usability).
author Chris Cannam
date Thu, 23 Feb 2006 18:01:31 +0000
parents 21d061e66177
children 3be4438b186d
comparison
equal deleted inserted replaced
37:21d061e66177 38:beb801473743
47 m_colourScheme(DefaultColours), 47 m_colourScheme(DefaultColours),
48 m_frequencyScale(LinearFrequencyScale), 48 m_frequencyScale(LinearFrequencyScale),
49 m_binDisplay(AllBins), 49 m_binDisplay(AllBins),
50 m_normalizeColumns(false), 50 m_normalizeColumns(false),
51 m_cache(0), 51 m_cache(0),
52 m_phaseAdjustCache(0),
53 m_cacheInvalid(true), 52 m_cacheInvalid(true),
54 m_pixmapCache(0), 53 m_pixmapCache(0),
55 m_pixmapCacheInvalid(true), 54 m_pixmapCacheInvalid(true),
56 m_fillThread(0), 55 m_fillThread(0),
57 m_updateTimer(0), 56 m_updateTimer(0),
89 m_condition.wakeAll(); 88 m_condition.wakeAll();
90 if (m_fillThread) m_fillThread->wait(); 89 if (m_fillThread) m_fillThread->wait();
91 delete m_fillThread; 90 delete m_fillThread;
92 91
93 delete m_cache; 92 delete m_cache;
94 delete m_phaseAdjustCache;
95 } 93 }
96 94
97 void 95 void
98 SpectrogramLayer::setModel(const DenseTimeValueModel *model) 96 SpectrogramLayer::setModel(const DenseTimeValueModel *model)
99 { 97 {
105 delete m_cache; //!!! hang on, this isn't safe to do here is it? 103 delete m_cache; //!!! hang on, this isn't safe to do here is it?
106 // we need some sort of guard against the fill 104 // we need some sort of guard against the fill
107 // thread trying to read the defunct model too. 105 // thread trying to read the defunct model too.
108 // should we use a scavenger? 106 // should we use a scavenger?
109 m_cache = 0; 107 m_cache = 0;
110 delete m_phaseAdjustCache; //!!! likewise
111 m_phaseAdjustCache = 0;
112 m_mutex.unlock(); 108 m_mutex.unlock();
113 109
114 if (!m_model || !m_model->isOK()) return; 110 if (!m_model || !m_model->isOK()) return;
115 111
116 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); 112 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
163 { 159 {
164 if (name == tr("Window Size") || 160 if (name == tr("Window Size") ||
165 name == tr("Window Type") || 161 name == tr("Window Type") ||
166 name == tr("Window Overlap")) return tr("Window"); 162 name == tr("Window Overlap")) return tr("Window");
167 if (name == tr("Colour") || 163 if (name == tr("Colour") ||
164 name == tr("Gain") ||
165 name == tr("Threshold") ||
168 name == tr("Colour Rotation")) return tr("Colour"); 166 name == tr("Colour Rotation")) return tr("Colour");
169 if (name == tr("Gain") || 167 if (name == tr("Normalize") ||
170 name == tr("Threshold") ||
171 name == tr("Normalize") ||
172 name == tr("Bin Display") || 168 name == tr("Bin Display") ||
173 name == tr("Colour Scale")) return tr("Scale"); 169 name == tr("Colour Scale")) return tr("Scale");
174 if (name == tr("Max Frequency") || 170 if (name == tr("Max Frequency") ||
175 name == tr("Min Frequency") || 171 name == tr("Min Frequency") ||
176 name == tr("Frequency Scale") || 172 name == tr("Frequency Scale") ||
360 } 356 }
361 } 357 }
362 if (name == tr("Min Frequency")) { 358 if (name == tr("Min Frequency")) {
363 switch (value) { 359 switch (value) {
364 default: 360 default:
365 case 0: return tr("None"); 361 case 0: return tr("No min");
366 case 1: return tr("10 Hz"); 362 case 1: return tr("10 Hz");
367 case 2: return tr("20 Hz"); 363 case 2: return tr("20 Hz");
368 case 3: return tr("40 Hz"); 364 case 3: return tr("40 Hz");
369 case 4: return tr("100 Hz"); 365 case 4: return tr("100 Hz");
370 case 5: return tr("250 Hz"); 366 case 5: return tr("250 Hz");
384 case 4: return tr("4 KHz"); 380 case 4: return tr("4 KHz");
385 case 5: return tr("6 KHz"); 381 case 5: return tr("6 KHz");
386 case 6: return tr("8 KHz"); 382 case 6: return tr("8 KHz");
387 case 7: return tr("12 KHz"); 383 case 7: return tr("12 KHz");
388 case 8: return tr("16 KHz"); 384 case 8: return tr("16 KHz");
389 case 9: return tr("All"); 385 case 9: return tr("No max");
390 } 386 }
391 } 387 }
392 if (name == tr("Frequency Scale")) { 388 if (name == tr("Frequency Scale")) {
393 switch (value) { 389 switch (value) {
394 default: 390 default:
589 SpectrogramLayer::setGain(float gain) 585 SpectrogramLayer::setGain(float gain)
590 { 586 {
591 if (m_gain == gain) return; //!!! inadequate for floats! 587 if (m_gain == gain) return; //!!! inadequate for floats!
592 588
593 m_mutex.lock(); 589 m_mutex.lock();
594 m_cacheInvalid = true;
595 m_pixmapCacheInvalid = true; 590 m_pixmapCacheInvalid = true;
596 591
597 m_gain = gain; 592 m_gain = gain;
598 593
599 m_mutex.unlock(); 594 m_mutex.unlock();
613 SpectrogramLayer::setThreshold(float threshold) 608 SpectrogramLayer::setThreshold(float threshold)
614 { 609 {
615 if (m_threshold == threshold) return; //!!! inadequate for floats! 610 if (m_threshold == threshold) return; //!!! inadequate for floats!
616 611
617 m_mutex.lock(); 612 m_mutex.lock();
618 m_cacheInvalid = true;
619 m_pixmapCacheInvalid = true; 613 m_pixmapCacheInvalid = true;
620 614
621 m_threshold = threshold; 615 m_threshold = threshold;
622 616
623 m_mutex.unlock(); 617 m_mutex.unlock();
637 SpectrogramLayer::setMinFrequency(size_t mf) 631 SpectrogramLayer::setMinFrequency(size_t mf)
638 { 632 {
639 if (m_minFrequency == mf) return; 633 if (m_minFrequency == mf) return;
640 634
641 m_mutex.lock(); 635 m_mutex.lock();
642 // don't need to invalidate main cache here
643 m_pixmapCacheInvalid = true; 636 m_pixmapCacheInvalid = true;
644 637
645 m_minFrequency = mf; 638 m_minFrequency = mf;
646 639
647 m_mutex.unlock(); 640 m_mutex.unlock();
659 SpectrogramLayer::setMaxFrequency(size_t mf) 652 SpectrogramLayer::setMaxFrequency(size_t mf)
660 { 653 {
661 if (m_maxFrequency == mf) return; 654 if (m_maxFrequency == mf) return;
662 655
663 m_mutex.lock(); 656 m_mutex.lock();
664 // don't need to invalidate main cache here
665 m_pixmapCacheInvalid = true; 657 m_pixmapCacheInvalid = true;
666 658
667 m_maxFrequency = mf; 659 m_maxFrequency = mf;
668 660
669 m_mutex.unlock(); 661 m_mutex.unlock();
679 671
680 void 672 void
681 SpectrogramLayer::setColourRotation(int r) 673 SpectrogramLayer::setColourRotation(int r)
682 { 674 {
683 m_mutex.lock(); 675 m_mutex.lock();
684 // don't need to invalidate main cache here
685 m_pixmapCacheInvalid = true; 676 m_pixmapCacheInvalid = true;
686 677
687 if (r < 0) r = 0; 678 if (r < 0) r = 0;
688 if (r > 256) r = 256; 679 if (r > 256) r = 256;
689 int distance = r - m_colourRotation; 680 int distance = r - m_colourRotation;
702 SpectrogramLayer::setColourScale(ColourScale colourScale) 693 SpectrogramLayer::setColourScale(ColourScale colourScale)
703 { 694 {
704 if (m_colourScale == colourScale) return; 695 if (m_colourScale == colourScale) return;
705 696
706 m_mutex.lock(); 697 m_mutex.lock();
707 m_cacheInvalid = true;
708 m_pixmapCacheInvalid = true; 698 m_pixmapCacheInvalid = true;
709 699
710 m_colourScale = colourScale; 700 m_colourScale = colourScale;
711 701
712 m_mutex.unlock(); 702 m_mutex.unlock();
725 SpectrogramLayer::setColourScheme(ColourScheme scheme) 715 SpectrogramLayer::setColourScheme(ColourScheme scheme)
726 { 716 {
727 if (m_colourScheme == scheme) return; 717 if (m_colourScheme == scheme) return;
728 718
729 m_mutex.lock(); 719 m_mutex.lock();
730 // don't need to invalidate main cache here
731 m_pixmapCacheInvalid = true; 720 m_pixmapCacheInvalid = true;
732 721
733 m_colourScheme = scheme; 722 m_colourScheme = scheme;
734 setCacheColourmap(); 723 setCacheColourmap();
735 724
749 { 738 {
750 if (m_frequencyScale == frequencyScale) return; 739 if (m_frequencyScale == frequencyScale) return;
751 740
752 m_mutex.lock(); 741 m_mutex.lock();
753 742
754 // don't need to invalidate main cache here
755 m_pixmapCacheInvalid = true; 743 m_pixmapCacheInvalid = true;
756 744
757 m_frequencyScale = frequencyScale; 745 m_frequencyScale = frequencyScale;
758 746
759 m_mutex.unlock(); 747 m_mutex.unlock();
772 { 760 {
773 if (m_binDisplay == binDisplay) return; 761 if (m_binDisplay == binDisplay) return;
774 762
775 m_mutex.lock(); 763 m_mutex.lock();
776 764
777 m_cacheInvalid = true;
778 m_pixmapCacheInvalid = true; 765 m_pixmapCacheInvalid = true;
779 766
780 m_binDisplay = binDisplay; 767 m_binDisplay = binDisplay;
781 768
782 m_mutex.unlock(); 769 m_mutex.unlock();
796 SpectrogramLayer::setNormalizeColumns(bool n) 783 SpectrogramLayer::setNormalizeColumns(bool n)
797 { 784 {
798 if (m_normalizeColumns == n) return; 785 if (m_normalizeColumns == n) return;
799 m_mutex.lock(); 786 m_mutex.lock();
800 787
801 m_cacheInvalid = true;
802 m_pixmapCacheInvalid = true; 788 m_pixmapCacheInvalid = true;
803 m_normalizeColumns = n; 789 m_normalizeColumns = n;
804 m_mutex.unlock(); 790 m_mutex.unlock();
805 791
806 fillCache(); 792 fillCache();
826 // delete m_cache; 812 // delete m_cache;
827 // m_cache = 0; 813 // m_cache = 0;
828 814
829 m_cacheInvalid = true; 815 m_cacheInvalid = true;
830 m_pixmapCacheInvalid = true; 816 m_pixmapCacheInvalid = true;
831 m_cachedInitialVisibleArea = false;
832 delete m_pixmapCache; 817 delete m_pixmapCache;
833 m_pixmapCache = 0; 818 m_pixmapCache = 0;
834 819
835 m_mutex.unlock(); 820 m_mutex.unlock();
836 821
844 void 829 void
845 SpectrogramLayer::cacheInvalid() 830 SpectrogramLayer::cacheInvalid()
846 { 831 {
847 m_cacheInvalid = true; 832 m_cacheInvalid = true;
848 m_pixmapCacheInvalid = true; 833 m_pixmapCacheInvalid = true;
849 m_cachedInitialVisibleArea = false;
850 fillCache(); 834 fillCache();
851 } 835 }
852 836
853 void 837 void
854 SpectrogramLayer::cacheInvalid(size_t, size_t) 838 SpectrogramLayer::cacheInvalid(size_t, size_t)
929 { 913 {
930 if (m_cacheInvalid || !m_cache) return; 914 if (m_cacheInvalid || !m_cache) return;
931 915
932 int formerRotation = m_colourRotation; 916 int formerRotation = m_colourRotation;
933 917
934 m_cache->setColour(NO_VALUE, Qt::white); 918 if (m_colourScheme == BlackOnWhite) {
919 m_cache->setColour(NO_VALUE, Qt::white);
920 } else {
921 m_cache->setColour(NO_VALUE, Qt::black);
922 }
935 923
936 for (int pixel = 1; pixel < 256; ++pixel) { 924 for (int pixel = 1; pixel < 256; ++pixel) {
937 925
938 QColor colour; 926 QColor colour;
939 int hue, px; 927 int hue, px;
1001 for (int pixel = 0; pixel < 256; ++pixel) { 989 for (int pixel = 0; pixel < 256; ++pixel) {
1002 m_cache->setColour(pixel, newPixels[pixel]); 990 m_cache->setColour(pixel, newPixels[pixel]);
1003 } 991 }
1004 } 992 }
1005 993
1006 bool 994 float
995 SpectrogramLayer::calculateFrequency(size_t bin,
996 size_t windowSize,
997 size_t windowIncrement,
998 size_t sampleRate,
999 float oldPhase,
1000 float newPhase,
1001 bool &steadyState)
1002 {
1003 // At frequency f, phase shift of 2pi (one cycle) happens in 1/f sec.
1004 // At hopsize h and sample rate sr, one hop happens in h/sr sec.
1005 // At window size w, for bin b, f is b*sr/w.
1006 // thus 2pi phase shift happens in w/(b*sr) sec.
1007 // We need to know what phase shift we expect from h/sr sec.
1008 // -> 2pi * ((h/sr) / (w/(b*sr)))
1009 // = 2pi * ((h * b * sr) / (w * sr))
1010 // = 2pi * (h * b) / w.
1011
1012 float frequency = (float(bin) * sampleRate) / windowSize;
1013
1014 float expectedPhase =
1015 oldPhase + (2.0 * M_PI * bin * windowIncrement) / windowSize;
1016
1017 float phaseError = MathUtilities::princarg(newPhase - expectedPhase);
1018
1019 if (fabs(phaseError) < (1.1 * (windowIncrement * M_PI) / windowSize)) {
1020
1021 // The new frequency estimate based on the phase error
1022 // resulting from assuming the "native" frequency of this bin
1023
1024 float newFrequency =
1025 (sampleRate * (expectedPhase + phaseError - oldPhase)) /
1026 (2 * M_PI * windowIncrement);
1027
1028 steadyState = true;
1029 return newFrequency;
1030 }
1031
1032 steadyState = false;
1033 return frequency;
1034 }
1035
1036 void
1007 SpectrogramLayer::fillCacheColumn(int column, double *input, 1037 SpectrogramLayer::fillCacheColumn(int column, double *input,
1008 fftw_complex *output, 1038 fftw_complex *output,
1009 fftw_plan plan, 1039 fftw_plan plan,
1010 size_t windowSize, 1040 size_t windowSize,
1011 size_t increment, 1041 size_t increment,
1012 const Window<double> &windower, 1042 const Window<double> &windower) const
1013 bool resetStoredPhase) const 1043 {
1014 { 1044 //!!! we _do_ need a lock for these references to the model
1015 static std::vector<double> storedPhase; 1045 // though, don't we?
1016
1017 bool phaseAdjust = (m_binDisplay == PeakFrequencies);
1018 bool haveStoredPhase = true;
1019 size_t sampleRate = 0;
1020
1021 if (phaseAdjust) {
1022 if (resetStoredPhase || (storedPhase.size() != windowSize / 2)) {
1023 haveStoredPhase = false;
1024 storedPhase.clear();
1025 for (size_t i = 0; i < windowSize / 2; ++i) {
1026 storedPhase.push_back(0.0);
1027 }
1028 }
1029 sampleRate = m_model->getSampleRate();
1030 }
1031 1046
1032 int startFrame = increment * column; 1047 int startFrame = increment * column;
1033 int endFrame = startFrame + windowSize; 1048 int endFrame = startFrame + windowSize;
1034 1049
1035 startFrame -= int(windowSize - increment) / 2; 1050 startFrame -= int(windowSize - increment) / 2;
1046 size_t got = m_model->getValues(m_channel, startFrame + pfx, 1061 size_t got = m_model->getValues(m_channel, startFrame + pfx,
1047 endFrame, input + pfx); 1062 endFrame, input + pfx);
1048 while (got + pfx < windowSize) { 1063 while (got + pfx < windowSize) {
1049 input[got + pfx] = 0.0; 1064 input[got + pfx] = 0.0;
1050 ++got; 1065 ++got;
1051 }
1052
1053 if (m_gain != 1.0) {
1054 for (size_t i = 0; i < windowSize; ++i) {
1055 input[i] *= m_gain;
1056 }
1057 } 1066 }
1058 1067
1059 if (m_channel == -1) { 1068 if (m_channel == -1) {
1060 int channels = m_model->getChannelCount(); 1069 int channels = m_model->getChannelCount();
1061 if (channels > 1) { 1070 if (channels > 1) {
1073 input[i + windowSize/2] = temp; 1082 input[i + windowSize/2] = temp;
1074 } 1083 }
1075 1084
1076 fftw_execute(plan); 1085 fftw_execute(plan);
1077 1086
1078 bool interrupted = false; 1087 double factor = 0.0;
1079 1088
1080 double prevMag = 0.0; 1089 // Calculate magnitude and phase from real and imaginary in
1081 double maxMag = 0.0; 1090 // output[i][0] and output[i][1] respectively, and store the phase
1082 1091 // straight into cache and the magnitude back into output[i][0]
1083 if (m_normalizeColumns) { 1092 // (because we'll need to know the normalization factor,
1084 for (size_t i = 0; i < windowSize/2; ++i) { 1093 // i.e. maximum magnitude in this column, before we can store it)
1085 double mag = sqrt(output[i][0] * output[i][0] + 1094
1086 output[i][1] * output[i][1]); 1095 for (size_t i = 0; i < windowSize/2; ++i) {
1087 mag /= windowSize / 2;
1088 if (mag > maxMag) maxMag = mag;
1089 }
1090 }
1091
1092 if (maxMag == 0.0) maxMag = 1.0;
1093
1094 bool peaksOnly = (m_binDisplay == PeakBins ||
1095 m_binDisplay == PeakFrequencies);
1096
1097 for (size_t i = 0; i < windowSize / 2; ++i) {
1098
1099 int value = 0;
1100 double phase = 0.0;
1101 1096
1102 double mag = sqrt(output[i][0] * output[i][0] + 1097 double mag = sqrt(output[i][0] * output[i][0] +
1103 output[i][1] * output[i][1]); 1098 output[i][1] * output[i][1]);
1104 1099 mag /= windowSize / 2;
1105 mag /= (windowSize / 2); 1100
1106 if (m_normalizeColumns) mag /= maxMag; 1101 if (mag > factor) factor = mag;
1107 1102
1108 bool showThis = true; 1103 double phase = atan2(output[i][1], output[i][0]);
1109 1104 phase = MathUtilities::princarg(phase);
1110 if (peaksOnly) { 1105
1111 if (mag < prevMag) showThis = false; 1106 output[i][0] = mag;
1112 else { 1107 m_cache->setPhaseAt(column, i, phase);
1113 double nextMag = 0.0; 1108 }
1114 if (i < windowSize / 2 - 1) { 1109
1115 nextMag = sqrt(output[i+1][0] * output[i+1][0] + 1110 m_cache->setNormalizationFactor(column, factor);
1116 output[i+1][1] * output[i+1][1]); 1111
1117 nextMag /= windowSize / 2; 1112 for (size_t i = 0; i < windowSize/2; ++i) {
1118 if (m_normalizeColumns) nextMag /= maxMag; 1113 m_cache->setMagnitudeAt(column, i, output[i][0]);
1119 } 1114 }
1120 if (mag < nextMag) showThis = false; 1115 }
1121 } 1116
1122 prevMag = mag; 1117 unsigned char
1123 } 1118 SpectrogramLayer::getDisplayValue(float input) const
1124 1119 {
1125 if (mag < m_threshold) showThis = false; 1120 int value;
1126 1121
1127 if (phaseAdjust || (m_colourScale == PhaseColourScale)) { 1122 if (m_colourScale == PhaseColourScale) {
1128 phase = atan2(output[i][1], output[i][0]); 1123
1129 phase = MathUtilities::princarg(phase); 1124 value = int((input * 127 / M_PI) + 128);
1130 } 1125
1131 1126 } else {
1132 if (phaseAdjust && m_phaseAdjustCache) { 1127
1133 m_phaseAdjustCache->setValueAt(column, i, 0); 1128 switch (m_colourScale) {
1134 }
1135
1136 if (phaseAdjust && m_phaseAdjustCache && haveStoredPhase && showThis) {
1137
1138 double freq = (double(i) * sampleRate) / m_windowSize;
1139 double prevPhase = storedPhase[i];
1140
1141 // At frequency f, phase shift of 2pi (one cycle) happens in 1/f sec.
1142 // At hopsize h and sample rate sr, one hop happens in h/sr sec.
1143 // At window size w, for bin i, f is i*sr/w.
1144 // thus 2pi phase shift happens in w/(b*sr) sec.
1145 // We need to know what phase shift we expect from h/sr sec.
1146 // -> 2pi * ((h/sr) / (w/(i*sr)))
1147 // = 2pi * ((h * i * sr) / (w * sr))
1148 // = 2pi * (h * i) / w.
1149
1150 double expectedPhase =
1151 prevPhase + (2.0 * M_PI * i * increment) / m_windowSize;
1152
1153 double phaseError = MathUtilities::princarg(phase - expectedPhase);
1154 1129
1155 if (fabs(phaseError) < (1.1 * (increment * M_PI) / m_windowSize)) { 1130 default:
1156 1131 case LinearColourScale:
1157 // The new frequency estimate based on the phase error 1132 value = int(input * 50 * 255) + 1;
1158 // resulting from assuming the "native" frequency of this bin 1133 break;
1159
1160 double newFreq =
1161 (sampleRate *
1162 (expectedPhase + phaseError - prevPhase)) /
1163 (2 * M_PI * increment);
1164
1165 // Convert the frequency difference to an unsigned char
1166 // for storage in the phase adjust cache
1167
1168 double binRange = (double(i + 1) * sampleRate) / windowSize - freq;
1169 1134
1170 int offset = lrint(((newFreq - freq) / binRange) * 100); 1135 case MeterColourScale:
1171 1136 value = AudioLevel::multiplier_to_preview(input * 50, 255) + 1;
1172 if (m_cacheInvalid || m_exiting) {
1173 interrupted = true;
1174 break;
1175 }
1176
1177 if (offset >= SCHAR_MIN && offset <= SCHAR_MAX) {
1178 signed char coff = offset;
1179 m_phaseAdjustCache->setValueAt(column, i, (unsigned char)coff);
1180 } else {
1181
1182 if (fabs(phaseError) < ((increment * M_PI) / m_windowSize)) {
1183 std::cerr << "WARNING: Phase error " << phaseError << " ( < " << ((increment * M_PI) / m_windowSize) << ") but offset " << offset << " out of range" << std::endl;
1184 }
1185 }
1186 }
1187 }
1188
1189 if (phaseAdjust) storedPhase[i] = phase;
1190
1191 if (m_colourScale == PhaseColourScale) {
1192
1193 value = int((phase * 127 / M_PI) + 128);
1194
1195 } else {
1196
1197 switch (m_colourScale) {
1198
1199 default:
1200 case LinearColourScale:
1201 value = int(mag * 50 * 255) + 1;
1202 break;
1203
1204 case MeterColourScale:
1205 value = AudioLevel::multiplier_to_preview(mag * 50, 255) + 1;
1206 break; 1137 break;
1207 1138
1208 case dBColourScale: 1139 case dBColourScale:
1209 mag = 20.0 * log10(mag); 1140 input = 20.0 * log10(input);
1210 mag = (mag + 80.0) / 80.0; 1141 input = (input + 80.0) / 80.0;
1211 if (mag < 0.0) mag = 0.0; 1142 if (input < 0.0) input = 0.0;
1212 if (mag > 1.0) mag = 1.0; 1143 if (input > 1.0) input = 1.0;
1213 value = int(mag * 255) + 1; 1144 value = int(input * 255) + 1;
1214 } 1145 }
1215 } 1146 }
1216 1147
1217 if (value > UCHAR_MAX) value = UCHAR_MAX; 1148 if (value > UCHAR_MAX) value = UCHAR_MAX;
1218 if (value < 0) value = 0; 1149 if (value < 0) value = 0;
1219 1150 return value;
1220 if (m_cacheInvalid || m_exiting) { 1151 }
1221 interrupted = true; 1152
1222 break; 1153
1223 } 1154 SpectrogramLayer::Cache::Cache() :
1224 1155 m_width(0),
1225 if (showThis) { 1156 m_height(0),
1226 m_cache->setValueAt(column, i, value); 1157 m_magnitude(0),
1227 } else { 1158 m_phase(0),
1228 m_cache->setValueAt(column, i, NO_VALUE); 1159 m_factor(0)
1229 } 1160 {
1230 }
1231
1232 return !interrupted;
1233 }
1234
1235 SpectrogramLayer::Cache::Cache(size_t width, size_t height) :
1236 m_width(width),
1237 m_height(height)
1238 {
1239 // use malloc rather than new[], because we want to be able to use realloc
1240 m_values = (unsigned char *)
1241 malloc(m_width * m_height * sizeof(unsigned char));
1242 if (!m_values) throw std::bad_alloc();
1243 MUNLOCK(m_values, m_width * m_height * sizeof(unsigned char));
1244 } 1161 }
1245 1162
1246 SpectrogramLayer::Cache::~Cache() 1163 SpectrogramLayer::Cache::~Cache()
1247 { 1164 {
1248 if (m_values) free(m_values); 1165 for (size_t i = 0; i < m_height; ++i) {
1166 if (m_magnitude && m_magnitude[i]) free(m_magnitude[i]);
1167 if (m_phase && m_phase[i]) free(m_phase[i]);
1168 }
1169
1170 if (m_magnitude) free(m_magnitude);
1171 if (m_phase) free(m_phase);
1172 if (m_factor) free(m_factor);
1249 } 1173 }
1250 1174
1251 void 1175 void
1252 SpectrogramLayer::Cache::resize(size_t width, size_t height) 1176 SpectrogramLayer::Cache::resize(size_t width, size_t height)
1253 { 1177 {
1254 std::cerr << "SpectrogramLayer::Cache[" << this << "]::resize(" << width << "x" << height << ")" << std::endl; 1178 std::cerr << "SpectrogramLayer::Cache[" << this << "]::resize(" << width << "x" << height << ")" << std::endl;
1255 m_values = (unsigned char *) 1179
1256 realloc(m_values, m_width * m_height * sizeof(unsigned char)); 1180 if (m_width == width && m_height == height) return;
1257 if (!m_values) throw std::bad_alloc(); 1181
1258 MUNLOCK(m_values, m_width * m_height * sizeof(unsigned char)); 1182 resize(m_magnitude, width, height);
1259 } 1183 resize(m_phase, width, height);
1260 1184
1261 size_t 1185 m_factor = (float *)realloc(m_factor, width * sizeof(float));
1262 SpectrogramLayer::Cache::getWidth() const 1186
1263 { 1187 m_width = width;
1264 return m_width; 1188 m_height = height;
1265 } 1189 }
1266 1190
1267 size_t 1191 void
1268 SpectrogramLayer::Cache::getHeight() const 1192 SpectrogramLayer::Cache::resize(uint16_t **&array, size_t width, size_t height)
1269 { 1193 {
1270 return m_height; 1194 for (size_t i = height; i < m_height; ++i) {
1271 } 1195 free(array[i]);
1272 1196 }
1273 unsigned char 1197
1274 SpectrogramLayer::Cache::getValueAt(size_t x, size_t y) const 1198 if (height != m_height) {
1275 { 1199 array = (uint16_t **)realloc(array, height * sizeof(uint16_t *));
1276 if (x >= m_width || y >= m_height) return 0; 1200 if (!array) throw std::bad_alloc();
1277 return m_values[y * m_width + x]; 1201 MUNLOCK(array, height * sizeof(uint16_t *));
1278 } 1202 }
1279 1203
1280 void 1204 for (size_t i = m_height; i < height; ++i) {
1281 SpectrogramLayer::Cache::setValueAt(size_t x, size_t y, unsigned char value) 1205 array[i] = 0;
1282 { 1206 }
1283 if (x >= m_width || y >= m_height) return; 1207
1284 m_values[y * m_width + x] = value; 1208 for (size_t i = 0; i < height; ++i) {
1285 } 1209 array[i] = (uint16_t *)realloc(array[i], width * sizeof(uint16_t));
1286 1210 if (!array[i]) throw std::bad_alloc();
1287 QColor 1211 MUNLOCK(array[i], width * sizeof(uint16_t));
1288 SpectrogramLayer::Cache::getColour(unsigned char index) const 1212 }
1289 { 1213 }
1290 return m_colours[index]; 1214
1291 } 1215 void
1292 1216 SpectrogramLayer::Cache::reset()
1293 void 1217 {
1294 SpectrogramLayer::Cache::setColour(unsigned char index, QColor colour) 1218 for (size_t x = 0; x < m_width; ++x) {
1295 { 1219 for (size_t y = 0; y < m_height; ++y) {
1296 m_colours[index] = colour; 1220 m_magnitude[y][x] = 0;
1297 } 1221 m_phase[y][x] = 0;
1298 1222 }
1299 void 1223 m_factor[x] = 1.0f;
1300 SpectrogramLayer::Cache::fill(unsigned char value) 1224 }
1301 { 1225 }
1302 std::cerr << "SpectrogramLayer::Cache[" << this << "]::fill(" << value << ")" << std::endl;
1303 for (size_t i = 0; i < m_width * m_height; ++i) {
1304 m_values[i] = value;
1305 }
1306 }
1307 1226
1308 void 1227 void
1309 SpectrogramLayer::CacheFillThread::run() 1228 SpectrogramLayer::CacheFillThread::run()
1310 { 1229 {
1311 // std::cerr << "SpectrogramLayer::CacheFillThread::run" << std::endl; 1230 // std::cerr << "SpectrogramLayer::CacheFillThread::run" << std::endl;
1320 1239
1321 if (m_layer.m_dormant) { 1240 if (m_layer.m_dormant) {
1322 1241
1323 if (m_layer.m_cacheInvalid) { 1242 if (m_layer.m_cacheInvalid) {
1324 delete m_layer.m_cache; 1243 delete m_layer.m_cache;
1325 delete m_layer.m_phaseAdjustCache;
1326 m_layer.m_cache = 0; 1244 m_layer.m_cache = 0;
1327 m_layer.m_phaseAdjustCache = 0;
1328 } 1245 }
1329 1246
1330 } else if (m_layer.m_model && m_layer.m_cacheInvalid) { 1247 } else if (m_layer.m_model && m_layer.m_cacheInvalid) {
1331 1248
1332 // std::cerr << "SpectrogramLayer::CacheFillThread::run: something to do" << std::endl; 1249 // std::cerr << "SpectrogramLayer::CacheFillThread::run: something to do" << std::endl;
1333 1250
1334 while (!m_layer.m_model->isReady()) { 1251 while (!m_layer.m_model->isReady()) {
1335 m_layer.m_condition.wait(&m_layer.m_mutex, 100); 1252 m_layer.m_condition.wait(&m_layer.m_mutex, 100);
1336 } 1253 }
1337 1254
1338 m_layer.m_cachedInitialVisibleArea = false;
1339 m_layer.m_cacheInvalid = false; 1255 m_layer.m_cacheInvalid = false;
1340 m_fillExtent = 0; 1256 m_fillExtent = 0;
1341 m_fillCompletion = 0; 1257 m_fillCompletion = 0;
1342 1258
1343 std::cerr << "SpectrogramLayer::CacheFillThread::run: model is ready" << std::endl; 1259 std::cerr << "SpectrogramLayer::CacheFillThread::run: model is ready" << std::endl;
1365 1281
1366 size_t width = (end - start) / windowIncrement + 1; 1282 size_t width = (end - start) / windowIncrement + 1;
1367 size_t height = windowSize / 2; 1283 size_t height = windowSize / 2;
1368 1284
1369 if (!m_layer.m_cache) { 1285 if (!m_layer.m_cache) {
1370 m_layer.m_cache = new Cache(width, height); 1286 m_layer.m_cache = new Cache;
1371 } else if (width != m_layer.m_cache->getWidth() ||
1372 height != m_layer.m_cache->getHeight()) {
1373 m_layer.m_cache->resize(width, height);
1374 } 1287 }
1375 1288
1289 m_layer.m_cache->resize(width, height);
1376 m_layer.setCacheColourmap(); 1290 m_layer.setCacheColourmap();
1377 m_layer.m_cache->fill(NO_VALUE); 1291 m_layer.m_cache->reset();
1378
1379 if (m_layer.m_binDisplay == PeakFrequencies) {
1380
1381 if (!m_layer.m_phaseAdjustCache) {
1382 m_layer.m_phaseAdjustCache = new Cache(width, height);
1383 } else if (width != m_layer.m_phaseAdjustCache->getWidth() ||
1384 height != m_layer.m_phaseAdjustCache->getHeight()) {
1385 m_layer.m_phaseAdjustCache->resize(width, height);
1386 }
1387
1388 m_layer.m_phaseAdjustCache->fill(0);
1389
1390 } else {
1391 delete m_layer.m_phaseAdjustCache;
1392 m_layer.m_phaseAdjustCache = 0;
1393 }
1394 1292
1395 // We don't need a lock when writing to or reading from 1293 // We don't need a lock when writing to or reading from
1396 // the pixels in the cache, because it's a fixed size 1294 // the pixels in the cache. We do need to ensure we have
1397 // array. We do need to ensure we have the width and 1295 // the width and height of the cache and the FFT
1398 // height of the cache and the FFT parameters known before 1296 // parameters known before we unlock, in case they change
1399 // we unlock, in case they change in the model while we 1297 // in the model while we aren't holding a lock. It's safe
1400 // aren't holding a lock. It's safe for us to continue to 1298 // for us to continue to use the "old" values if that
1401 // use the "old" values if that happens, because they will 1299 // happens, because they will continue to match the
1402 // continue to match the dimensions of the actual cache 1300 // dimensions of the actual cache (which we manage, not
1403 // (which we manage, not the model). 1301 // the model).
1404 m_layer.m_mutex.unlock(); 1302 m_layer.m_mutex.unlock();
1405 1303
1406 double *input = (double *) 1304 double *input = (double *)
1407 fftw_malloc(windowSize * sizeof(double)); 1305 fftw_malloc(windowSize * sizeof(double));
1408 1306
1433 for (size_t f = visibleStart; f < visibleEnd; f += windowIncrement) { 1331 for (size_t f = visibleStart; f < visibleEnd; f += windowIncrement) {
1434 1332
1435 m_layer.fillCacheColumn(int((f - start) / windowIncrement), 1333 m_layer.fillCacheColumn(int((f - start) / windowIncrement),
1436 input, output, plan, 1334 input, output, plan,
1437 windowSize, windowIncrement, 1335 windowSize, windowIncrement,
1438 //!!! actually if we're doing phase adjustment we also want to fill the column preceding the visible area so that we have the right values for the first visible one (also applies below) 1336 windower);
1439 windower, f == visibleStart);
1440 1337
1441 if (m_layer.m_cacheInvalid || m_layer.m_exiting) { 1338 if (m_layer.m_cacheInvalid || m_layer.m_exiting) {
1442 interrupted = true; 1339 interrupted = true;
1443 m_fillExtent = 0; 1340 m_fillExtent = 0;
1444 break; 1341 break;
1445 } 1342 }
1446 1343
1447 if (++counter == updateAt || f == visibleEnd - 1) { 1344 if (++counter == updateAt ||
1345 (f >= visibleEnd - 1 && f < visibleEnd + windowIncrement)) {
1448 if (f < end) m_fillExtent = f; 1346 if (f < end) m_fillExtent = f;
1449 m_fillCompletion = size_t(100 * fabsf(float(f - visibleStart) / 1347 m_fillCompletion = size_t(100 * fabsf(float(f - visibleStart) /
1450 float(end - start))); 1348 float(end - start)));
1451 counter = 0; 1349 counter = 0;
1452 } 1350 }
1453 } 1351 }
1454 1352
1455 m_layer.m_cachedInitialVisibleArea = true;
1456 std::cerr << "SpectrogramLayer::CacheFillThread::run: visible bit done" << std::endl; 1353 std::cerr << "SpectrogramLayer::CacheFillThread::run: visible bit done" << std::endl;
1354 m_layer.m_view->update();
1457 } 1355 }
1458 1356
1459 if (!interrupted && doVisibleFirst) { 1357 if (!interrupted && doVisibleFirst) {
1460 1358
1461 for (size_t f = visibleEnd; f < end; f += windowIncrement) { 1359 for (size_t f = visibleEnd; f < end; f += windowIncrement) {
1462 1360
1463 if (!m_layer.fillCacheColumn(int((f - start) / windowIncrement), 1361 m_layer.fillCacheColumn(int((f - start) / windowIncrement),
1464 input, output, plan, 1362 input, output, plan,
1465 windowSize, windowIncrement, 1363 windowSize, windowIncrement,
1466 windower, f == visibleEnd)) { 1364 windower);
1365
1366 if (m_layer.m_cacheInvalid || m_layer.m_exiting) {
1467 interrupted = true; 1367 interrupted = true;
1468 m_fillExtent = 0; 1368 m_fillExtent = 0;
1469 break; 1369 break;
1470 } 1370 }
1471 1371
1472 1372 if (++counter == updateAt) {
1473 if (++counter == updateAt || f == end - 1) {
1474 m_fillExtent = f; 1373 m_fillExtent = f;
1475 m_fillCompletion = size_t(100 * fabsf(float(f - visibleStart) / 1374 m_fillCompletion = size_t(100 * fabsf(float(f - visibleStart) /
1476 float(end - start))); 1375 float(end - start)));
1477 counter = 0; 1376 counter = 0;
1478 } 1377 }
1489 } 1388 }
1490 size_t baseCompletion = m_fillCompletion; 1389 size_t baseCompletion = m_fillCompletion;
1491 1390
1492 for (size_t f = start; f < remainingEnd; f += windowIncrement) { 1391 for (size_t f = start; f < remainingEnd; f += windowIncrement) {
1493 1392
1494 if (!m_layer.fillCacheColumn(int((f - start) / windowIncrement), 1393 m_layer.fillCacheColumn(int((f - start) / windowIncrement),
1495 input, output, plan, 1394 input, output, plan,
1496 windowSize, windowIncrement, 1395 windowSize, windowIncrement,
1497 windower, f == start)) { 1396 windower);
1397
1398 if (m_layer.m_cacheInvalid || m_layer.m_exiting) {
1498 interrupted = true; 1399 interrupted = true;
1499 m_fillExtent = 0; 1400 m_fillExtent = 0;
1500 break; 1401 break;
1501 } 1402 }
1502 1403
1503 if (++counter == updateAt || 1404 if (++counter == updateAt ||
1504 f == visibleEnd - 1 || 1405 (f >= visibleEnd - 1 && f < visibleEnd + windowIncrement)) {
1505 f == remainingEnd - 1) {
1506 m_fillExtent = f; 1406 m_fillExtent = f;
1507 m_fillCompletion = baseCompletion + 1407 m_fillCompletion = baseCompletion +
1508 size_t(100 * fabsf(float(f - start) / 1408 size_t(100 * fabsf(float(f - start) /
1509 float(end - start))); 1409 float(end - start)));
1510 counter = 0; 1410 counter = 0;
1532 SpectrogramLayer::getYBinRange(int y, float &q0, float &q1) const 1432 SpectrogramLayer::getYBinRange(int y, float &q0, float &q1) const
1533 { 1433 {
1534 int h = m_view->height(); 1434 int h = m_view->height();
1535 if (y < 0 || y >= h) return false; 1435 if (y < 0 || y >= h) return false;
1536 1436
1537 // Each pixel in a column is drawn from a possibly non- 1437 int sr = m_model->getSampleRate();
1538 // integral set of frequency bins. 1438 float minf = float(sr) / m_windowSize;
1539 1439 float maxf = float(sr) / 2;
1540 if (m_frequencyScale == LinearFrequencyScale) { 1440
1541 1441 if (m_minFrequency > 0.0) minf = m_minFrequency;
1542 size_t bins = m_windowSize / 2; 1442 if (m_maxFrequency > 0.0) maxf = m_maxFrequency;
1543 1443
1544 if (m_maxFrequency > 0) { 1444 bool logarithmic = (m_frequencyScale == LogFrequencyScale);
1545 int sr = m_model->getSampleRate(); 1445
1546 bins = int((double(m_maxFrequency) * m_windowSize) / sr + 0.1); 1446 q0 = m_view->getFrequencyForY(y, minf, maxf, logarithmic);
1547 if (bins > m_windowSize / 2) bins = m_windowSize / 2; 1447 q1 = m_view->getFrequencyForY(y - 1, minf, maxf, logarithmic);
1548 } 1448
1549 1449 // Now map these on to actual bins
1550 q0 = float(h - y - 1) * bins / h; 1450
1551 q1 = float(h - y) * bins / h; 1451 int b0 = (q0 * m_windowSize) / sr;
1552 1452 int b1 = (q1 * m_windowSize) / sr;
1553 } else { 1453
1554 1454 q0 = b0;
1555 // This is all most ad-hoc. I'm not at my brightest. 1455 q1 = b1;
1556 1456
1557 int sr = m_model->getSampleRate(); 1457 // q0 = (b0 * sr) / m_windowSize;
1558 1458 // q1 = (b1 * sr) / m_windowSize;
1559 float maxf = m_maxFrequency;
1560 if (maxf == 0.0) maxf = float(sr) / 2;
1561
1562 float minf = float(sr) / m_windowSize;
1563
1564 float maxlogf = log10f(maxf);
1565 float minlogf = log10f(minf);
1566
1567 float logf0 = minlogf + ((maxlogf - minlogf) * (h - y - 1)) / h;
1568 float logf1 = minlogf + ((maxlogf - minlogf) * (h - y)) / h;
1569
1570 float f0 = pow(10.f, logf0);
1571 float f1 = pow(10.f, logf1);
1572
1573 q0 = ((f0 * m_windowSize) / sr) - 1;
1574 q1 = ((f1 * m_windowSize) / sr) - 1;
1575
1576 // std::cout << "y=" << y << " h=" << h << " maxf=" << maxf << " maxlogf="
1577 // << maxlogf << " logf0=" << logf0 << " f0=" << f0 << " q0="
1578 // << q0 << std::endl;
1579 }
1580 1459
1581 return true; 1460 return true;
1582 } 1461 }
1583 1462
1584 bool 1463 bool
1585 SpectrogramLayer::getXBinRange(int x, float &s0, float &s1) const 1464 SpectrogramLayer::getXBinRange(int x, float &s0, float &s1) const
1586 { 1465 {
1587 size_t modelStart = m_model->getStartFrame(); 1466 size_t modelStart = m_model->getStartFrame();
1588 size_t modelEnd = m_model->getEndFrame(); 1467 size_t modelEnd = m_model->getEndFrame();
1660 int q0i = int(q0 + 0.001); 1539 int q0i = int(q0 + 0.001);
1661 int q1i = int(q1); 1540 int q1i = int(q1);
1662 1541
1663 int sr = m_model->getSampleRate(); 1542 int sr = m_model->getSampleRate();
1664 1543
1544 size_t windowSize = m_windowSize;
1545 size_t windowIncrement = getWindowIncrement();
1546
1665 bool haveAdj = false; 1547 bool haveAdj = false;
1666 1548
1667 bool peaksOnly = (m_binDisplay == PeakBins || 1549 bool peaksOnly = (m_binDisplay == PeakBins ||
1668 m_binDisplay == PeakFrequencies); 1550 m_binDisplay == PeakFrequencies);
1669 1551
1673 1555
1674 float binfreq = (sr * q) / m_windowSize; 1556 float binfreq = (sr * q) / m_windowSize;
1675 if (q == q0i) freqMin = binfreq; 1557 if (q == q0i) freqMin = binfreq;
1676 if (q == q1i) freqMax = binfreq; 1558 if (q == q1i) freqMax = binfreq;
1677 1559
1678 if (m_cache->getValueAt(s, q) == NO_VALUE) { 1560 if (!m_cache || m_cacheInvalid) break; //!!! lock?
1679 continue; 1561
1680 } 1562 if (peaksOnly && !m_cache->isLocalPeak(s, q)) continue;
1563
1564 if (!m_cache->isOverThreshold(s, q, m_threshold)) continue;
1565
1566 float freq = binfreq;
1567 bool steady = false;
1568
1569 if (s < m_cache->getWidth() - 1) {
1570
1571 freq = calculateFrequency(q,
1572 windowSize,
1573 windowIncrement,
1574 sr,
1575 m_cache->getPhaseAt(s, q),
1576 m_cache->getPhaseAt(s+1, q),
1577 steady);
1681 1578
1682 if (m_binDisplay == PeakFrequencies && 1579 if (!haveAdj || freq < adjFreqMin) adjFreqMin = freq;
1683 m_phaseAdjustCache) { 1580 if (!haveAdj || freq > adjFreqMax) adjFreqMax = freq;
1684 1581
1685 unsigned char cadj = m_phaseAdjustCache->getValueAt(s, q);
1686 int adjust = int((signed char)cadj);
1687
1688 float nextBinFreq = (sr * (q + 1)) / m_windowSize;
1689 float fadjust = (adjust * (nextBinFreq - binfreq)) / 100.0;//!!!
1690 float f = binfreq + fadjust;
1691 if (!haveAdj || f < adjFreqMin) adjFreqMin = f;
1692 if (!haveAdj || f > adjFreqMax) adjFreqMax = f;
1693 haveAdj = true; 1582 haveAdj = true;
1694 } 1583 }
1695 } 1584 }
1696 } 1585 }
1697 1586
1701 1590
1702 return haveAdj; 1591 return haveAdj;
1703 } 1592 }
1704 1593
1705 bool 1594 bool
1706 SpectrogramLayer::getXYBinSourceRange(int x, int y, float &dbMin, float &dbMax) const 1595 SpectrogramLayer::getXYBinSourceRange(int x, int y,
1596 float &min, float &max,
1597 float &phaseMin, float &phaseMax) const
1707 { 1598 {
1708 float q0 = 0, q1 = 0; 1599 float q0 = 0, q1 = 0;
1709 if (!getYBinRange(y, q0, q1)) return false; 1600 if (!getYBinRange(y, q0, q1)) return false;
1710 1601
1711 float s0 = 0, s1 = 0; 1602 float s0 = 0, s1 = 0;
1723 if (m_cache && !m_cacheInvalid) { 1614 if (m_cache && !m_cacheInvalid) {
1724 1615
1725 int cw = m_cache->getWidth(); 1616 int cw = m_cache->getWidth();
1726 int ch = m_cache->getHeight(); 1617 int ch = m_cache->getHeight();
1727 1618
1728 int min = -1, max = -1; 1619 min = 0.0;
1620 max = 0.0;
1621 phaseMin = 0.0;
1622 phaseMax = 0.0;
1623 bool have = false;
1729 1624
1730 for (int q = q0i; q <= q1i; ++q) { 1625 for (int q = q0i; q <= q1i; ++q) {
1731 for (int s = s0i; s <= s1i; ++s) { 1626 for (int s = s0i; s <= s1i; ++s) {
1732 if (s >= 0 && q >= 0 && s < cw && q < ch) { 1627 if (s >= 0 && q >= 0 && s < cw && q < ch) {
1733 int value = int(m_cache->getValueAt(s, q)); 1628
1734 if (value == NO_VALUE) continue; 1629 float value;
1735 if (min == -1 || value < min) min = value; 1630
1736 if (max == -1 || value > max) max = value; 1631 value = m_cache->getPhaseAt(s, q);
1632 if (!have || value < phaseMin) { phaseMin = value; }
1633 if (!have || value > phaseMax) { phaseMax = value; }
1634
1635 value = m_cache->getMagnitudeAt(s, q);
1636 if (!have || value < min) { min = value; }
1637 if (!have || value > max) { max = value; }
1638
1639 have = true;
1737 } 1640 }
1738 } 1641 }
1739 } 1642 }
1740 1643
1741 if (min >= 0) { 1644 if (have) {
1742 dbMin = (float(min) / 256.0) * 80.0 - 80.0;
1743 dbMax = (float(max + 1) / 256.0) * 80.0 - 80.1;
1744 rv = true; 1645 rv = true;
1745 } 1646 }
1746 } 1647 }
1747 1648
1748 m_mutex.unlock(); 1649 m_mutex.unlock();
1920 } 1821 }
1921 1822
1922 float minFreq = (float(minbin) * sr) / m_windowSize; 1823 float minFreq = (float(minbin) * sr) / m_windowSize;
1923 float maxFreq = (float(bins) * sr) / m_windowSize; 1824 float maxFreq = (float(bins) * sr) / m_windowSize;
1924 1825
1826 size_t increment = getWindowIncrement();
1827
1925 m_mutex.unlock(); 1828 m_mutex.unlock();
1926 1829
1927 for (int x = 0; x < w; ++x) { 1830 for (int x = 0; x < w; ++x) {
1928 1831
1929 m_mutex.lock(); 1832 m_mutex.lock();
1949 } 1852 }
1950 1853
1951 int s0i = int(s0 + 0.001); 1854 int s0i = int(s0 + 0.001);
1952 int s1i = int(s1); 1855 int s1i = int(s1);
1953 1856
1954 for (int q = minbin; q < bins; ++q) { 1857 for (size_t q = minbin; q < bins; ++q) {
1955 1858
1956 for (int s = s0i; s <= s1i; ++s) { 1859 for (int s = s0i; s <= s1i; ++s) {
1957 1860
1958 float sprop = 1.0; 1861 float sprop = 1.0;
1959 if (s == s0i) sprop *= (s + 1) - s0; 1862 if (s == s0i) sprop *= (s + 1) - s0;
1960 if (s == s1i) sprop *= s1 - s; 1863 if (s == s1i) sprop *= s1 - s;
1961 1864
1962 float f0 = (float(q) * sr) / m_windowSize; 1865 float f0 = (float(q) * sr) / m_windowSize;
1963 float f1 = (float(q + 1) * sr) / m_windowSize; 1866 float f1 = (float(q + 1) * sr) / m_windowSize;
1964 1867
1965 if ((m_binDisplay == PeakFrequencies) && 1868 if (m_binDisplay == PeakFrequencies &&
1966 m_phaseAdjustCache) { 1869 s < m_cache->getWidth() - 1) {
1967 1870
1968 unsigned char cadj = m_phaseAdjustCache->getValueAt(s, q); 1871 bool steady = false;
1969 int adjust = int((signed char)cadj); 1872 f0 = f1 = calculateFrequency(q,
1970 float fadjust = (adjust * (f1 - f0)) / 100.0; 1873 m_windowSize,
1971 f0 = f1 = f0 + fadjust; 1874 increment,
1875 sr,
1876 m_cache->getPhaseAt(s, q),
1877 m_cache->getPhaseAt(s+1, q),
1878 steady);
1972 } 1879 }
1973 1880
1974 float y0 = h - (h * (f1 - minFreq)) / maxFreq; 1881 float y0 = m_view->getYForFrequency
1975 float y1 = h - (h * (f0 - minFreq)) / maxFreq; 1882 (f1, minFreq, maxFreq,
1976 1883 m_frequencyScale == LogFrequencyScale);
1977 //!!! We want a general View::getYForFrequency and inverse 1884
1978 // that can be passed min freq, max freq and log/linear. We 1885 float y1 = m_view->getYForFrequency
1979 // can then introduce a central correspondence between, say, 1886 (f0, minFreq, maxFreq,
1980 // spectrogram layer and a frequency-scaled MIDI layer on the 1887 m_frequencyScale == LogFrequencyScale);
1981 // same view. 1888
1982
1983 if (m_frequencyScale == LogFrequencyScale) {
1984
1985 //!!! also, shouldn't be recalculating this every time!
1986
1987 // float maxf = m_maxFrequency;
1988 // if (maxf == 0.0) maxf = float(sr) / 2;
1989
1990 // float minf = float(sr) / m_windowSize;
1991
1992 float maxlogf = log10f(maxFreq);
1993 float minlogf;
1994
1995 if (minFreq > 0) minlogf = log10f(minFreq);
1996 else minlogf = log10f(float(sr) / m_windowSize);
1997
1998 y0 = h - (h * (log10f(f1) - minlogf)) / (maxlogf - minlogf);
1999 y1 = h - (h * (log10f(f0) - minlogf)) / (maxlogf - minlogf);
2000 }
2001
2002 int y0i = int(y0 + 0.001); 1889 int y0i = int(y0 + 0.001);
2003 int y1i = int(y1); 1890 int y1i = int(y1);
2004 1891
2005 for (int y = y0i; y <= y1i; ++y) { 1892 for (int y = y0i; y <= y1i; ++y) {
2006 1893
2008 1895
2009 float yprop = sprop; 1896 float yprop = sprop;
2010 if (y == y0i) yprop *= (y + 1) - y0; 1897 if (y == y0i) yprop *= (y + 1) - y0;
2011 if (y == y1i) yprop *= y1 - y; 1898 if (y == y1i) yprop *= y1 - y;
2012 1899
2013 int value = m_cache->getValueAt(s, q); 1900 if (m_binDisplay == PeakBins ||
2014 if (value == NO_VALUE) continue; 1901 m_binDisplay == PeakFrequencies) {
1902 if (!m_cache->isLocalPeak(s, q)) continue;
1903 }
1904
1905 if (!m_cache->isOverThreshold(s, q, m_threshold)) continue;
1906
1907 float value;
1908
1909 if (m_colourScale == PhaseColourScale) {
1910 value = m_cache->getPhaseAt(s, q);
1911 } else if (m_normalizeColumns) {
1912 value = m_cache->getNormalizedMagnitudeAt(s, q) * m_gain;
1913 } else {
1914 value = m_cache->getMagnitudeAt(s, q) * m_gain;
1915 }
2015 1916
2016 ymag[y] += yprop * value; 1917 ymag[y] += yprop * value;
2017 ydiv[y] += yprop; 1918 ydiv[y] += yprop;
2018 } 1919 }
2019 } 1920 }
2020 } 1921 }
2021 1922
2022 for (int y = 0; y < h; ++y) { 1923 for (int y = 0; y < h; ++y) {
2023 1924
2024 int pixel = 1; 1925 unsigned char pixel = 0;
2025 1926
2026 if (ydiv[y] > 0.0) { 1927 if (ydiv[y] > 0.0) {
2027 pixel = int(ymag[y] / ydiv[y]); 1928 float avg = ymag[y] / ydiv[y];
2028 if (pixel > 255) pixel = 255; 1929 pixel = getDisplayValue(avg);
2029 if (pixel < 1) pixel = 1;
2030 } 1930 }
2031 1931
2032 assert(x <= scaled.width()); 1932 assert(x <= scaled.width());
2033 QColor c = m_cache->getColour(pixel); 1933 QColor c = m_cache->getColour(pixel);
2034 scaled.setPixel(x, y, 1934 scaled.setPixel(x, y,
2035 qRgb(c.red(), c.green(), c.blue())); 1935 qRgb(c.red(), c.green(), c.blue()));
2036 } 1936 }
2037
2038 1937
2039 m_mutex.unlock(); 1938 m_mutex.unlock();
2040 } 1939 }
2041 1940
2042 paint.drawImage(x0, y0, scaled); 1941 paint.drawImage(x0, y0, scaled);
2096 int x = pos.x(); 1995 int x = pos.x();
2097 int y = pos.y(); 1996 int y = pos.y();
2098 1997
2099 if (!m_model || !m_model->isOK()) return ""; 1998 if (!m_model || !m_model->isOK()) return "";
2100 1999
2101 float dbMin = 0, dbMax = 0; 2000 float magMin = 0, magMax = 0;
2001 float phaseMin = 0, phaseMax = 0;
2102 float freqMin = 0, freqMax = 0; 2002 float freqMin = 0, freqMax = 0;
2103 float adjFreqMin = 0, adjFreqMax = 0; 2003 float adjFreqMin = 0, adjFreqMax = 0;
2104 QString pitchMin, pitchMax; 2004 QString pitchMin, pitchMax;
2105 RealTime rtMin, rtMax; 2005 RealTime rtMin, rtMax;
2106 2006
2107 bool haveDb = false; 2007 bool haveValues = false;
2108 2008
2109 if (!getXBinSourceRange(x, rtMin, rtMax)) return ""; 2009 if (!getXBinSourceRange(x, rtMin, rtMax)) {
2110 if (getXYBinSourceRange(x, y, dbMin, dbMax)) haveDb = true; 2010 return "";
2011 }
2012 if (getXYBinSourceRange(x, y, magMin, magMax, phaseMin, phaseMax)) {
2013 haveValues = true;
2014 }
2111 2015
2112 QString adjFreqText = "", adjPitchText = ""; 2016 QString adjFreqText = "", adjPitchText = "";
2113 2017
2114 if ((m_binDisplay == PeakFrequencies) && 2018 if (m_binDisplay == PeakFrequencies) {
2115 m_phaseAdjustCache) {
2116 2019
2117 if (!getAdjustedYBinSourceRange(x, y, freqMin, freqMax, 2020 if (!getAdjustedYBinSourceRange(x, y, freqMin, freqMax,
2118 adjFreqMin, adjFreqMax)) return ""; 2021 adjFreqMin, adjFreqMax)) {
2022 return "";
2023 }
2119 2024
2120 if (adjFreqMin != adjFreqMax) { 2025 if (adjFreqMin != adjFreqMax) {
2121 adjFreqText = tr("Adjusted Frequency:\t%1 - %2 Hz\n") 2026 adjFreqText = tr("Adjusted Frequency:\t%1 - %2 Hz\n")
2122 .arg(adjFreqMin).arg(adjFreqMax); 2027 .arg(adjFreqMin).arg(adjFreqMax);
2123 adjPitchText = tr("Adjusted Pitch:\t%3 - %4\n")
2124 .arg(Pitch::getPitchLabelForFrequency(adjFreqMin))
2125 .arg(Pitch::getPitchLabelForFrequency(adjFreqMax));
2126 } else { 2028 } else {
2127 adjFreqText = tr("Adjusted Frequency:\t%1 Hz\n") 2029 adjFreqText = tr("Adjusted Frequency:\t%1 Hz\n")
2128 .arg(adjFreqMin); 2030 .arg(adjFreqMin);
2129 adjPitchText = tr("Adjusted Pitch:\t%2\n") 2031 }
2130 .arg(Pitch::getPitchLabelForFrequency(adjFreqMin)); 2032
2033 QString pmin = Pitch::getPitchLabelForFrequency(adjFreqMin);
2034 QString pmax = Pitch::getPitchLabelForFrequency(adjFreqMax);
2035
2036 if (pmin != pmax) {
2037 adjPitchText = tr("Adjusted Pitch:\t%3 - %4\n").arg(pmin).arg(pmax);
2038 } else {
2039 adjPitchText = tr("Adjusted Pitch:\t%2\n").arg(pmin);
2131 } 2040 }
2132 2041
2133 } else { 2042 } else {
2134 2043
2135 if (!getYBinSourceRange(y, freqMin, freqMax)) return ""; 2044 if (!getYBinSourceRange(y, freqMin, freqMax)) return "";
2136 } 2045 }
2137
2138 //!!! want to actually do a one-off FFT to recalculate the dB value!
2139 2046
2140 QString text; 2047 QString text;
2141 2048
2142 if (rtMin != rtMax) { 2049 if (rtMin != rtMax) {
2143 text += tr("Time:\t%1 - %2\n") 2050 text += tr("Time:\t%1 - %2\n")
2162 .arg(adjFreqText) 2069 .arg(adjFreqText)
2163 .arg(Pitch::getPitchLabelForFrequency(freqMin)) 2070 .arg(Pitch::getPitchLabelForFrequency(freqMin))
2164 .arg(adjPitchText); 2071 .arg(adjPitchText);
2165 } 2072 }
2166 2073
2167 if (haveDb) { 2074 if (haveValues) {
2075 float dbMin = AudioLevel::multiplier_to_dB(magMin);
2076 float dbMax = AudioLevel::multiplier_to_dB(magMax);
2168 if (lrintf(dbMin) != lrintf(dbMax)) { 2077 if (lrintf(dbMin) != lrintf(dbMax)) {
2169 text += tr("dB:\t%1 - %2").arg(lrintf(dbMin)).arg(lrintf(dbMax)); 2078 text += tr("dB:\t%1 - %2").arg(lrintf(dbMin)).arg(lrintf(dbMax));
2170 } else { 2079 } else {
2171 text += tr("dB:\t%1").arg(lrintf(dbMin)); 2080 text += tr("dB:\t%1").arg(lrintf(dbMin));
2081 }
2082 if (phaseMin != phaseMax) {
2083 text += tr("\nPhase:\t%1 - %2").arg(phaseMin).arg(phaseMax);
2084 } else {
2085 text += tr("\nPhase:\t%1").arg(phaseMin);
2172 } 2086 }
2173 } 2087 }
2174 2088
2175 return text; 2089 return text;
2176 } 2090 }