Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 946:36cddc3de023 alignment_view
Merge from default branch
author | Chris Cannam |
---|---|
date | Mon, 20 Apr 2015 09:19:52 +0100 |
parents | 28d05ae8741c |
children | 94e4952a6774 b8187c83b93a |
comparison
equal
deleted
inserted
replaced
897:499b637f2a26 | 946:36cddc3de023 |
---|---|
39 #include <QMouseEvent> | 39 #include <QMouseEvent> |
40 #include <QTextStream> | 40 #include <QTextStream> |
41 | 41 |
42 #include <iostream> | 42 #include <iostream> |
43 | 43 |
44 | |
45 | |
46 #include <cassert> | 44 #include <cassert> |
47 #include <cmath> | 45 #include <cmath> |
48 | 46 |
49 #ifndef __GNUC__ | 47 #ifndef __GNUC__ |
50 #include <alloca.h> | 48 #include <alloca.h> |
51 #endif | 49 #endif |
52 | 50 |
53 //#define DEBUG_SPECTROGRAM_REPAINT 1 | 51 //#define DEBUG_SPECTROGRAM_REPAINT 1 |
52 | |
53 using std::vector; | |
54 | 54 |
55 SpectrogramLayer::SpectrogramLayer(Configuration config) : | 55 SpectrogramLayer::SpectrogramLayer(Configuration config) : |
56 m_model(0), | 56 m_model(0), |
57 m_channel(0), | 57 m_channel(0), |
58 m_windowSize(1024), | 58 m_windowSize(1024), |
139 if (!m_model || !m_model->isOK()) return; | 139 if (!m_model || !m_model->isOK()) return; |
140 | 140 |
141 connectSignals(m_model); | 141 connectSignals(m_model); |
142 | 142 |
143 connect(m_model, SIGNAL(modelChanged()), this, SLOT(cacheInvalid())); | 143 connect(m_model, SIGNAL(modelChanged()), this, SLOT(cacheInvalid())); |
144 connect(m_model, SIGNAL(modelChangedWithin(int, int)), | 144 connect(m_model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)), |
145 this, SLOT(cacheInvalid(int, int))); | 145 this, SLOT(cacheInvalid(sv_frame_t, sv_frame_t))); |
146 | 146 |
147 emit modelReplaced(); | 147 emit modelReplaced(); |
148 } | 148 } |
149 | 149 |
150 Layer::PropertyList | 150 Layer::PropertyList |
240 if (name == "Gain") { | 240 if (name == "Gain") { |
241 | 241 |
242 *min = -50; | 242 *min = -50; |
243 *max = 50; | 243 *max = 50; |
244 | 244 |
245 *deflt = lrintf(log10(m_initialGain) * 20.0);; | 245 *deflt = int(lrint(log10(m_initialGain) * 20.0)); |
246 if (*deflt < *min) *deflt = *min; | 246 if (*deflt < *min) *deflt = *min; |
247 if (*deflt > *max) *deflt = *max; | 247 if (*deflt > *max) *deflt = *max; |
248 | 248 |
249 val = lrintf(log10(m_gain) * 20.0); | 249 val = int(lrint(log10(m_gain) * 20.0)); |
250 if (val < *min) val = *min; | 250 if (val < *min) val = *min; |
251 if (val > *max) val = *max; | 251 if (val > *max) val = *max; |
252 | 252 |
253 } else if (name == "Threshold") { | 253 } else if (name == "Threshold") { |
254 | 254 |
255 *min = -50; | 255 *min = -50; |
256 *max = 0; | 256 *max = 0; |
257 | 257 |
258 *deflt = lrintf(AudioLevel::multiplier_to_dB(m_initialThreshold)); | 258 *deflt = int(lrint(AudioLevel::multiplier_to_dB(m_initialThreshold))); |
259 if (*deflt < *min) *deflt = *min; | 259 if (*deflt < *min) *deflt = *min; |
260 if (*deflt > *max) *deflt = *max; | 260 if (*deflt > *max) *deflt = *max; |
261 | 261 |
262 val = lrintf(AudioLevel::multiplier_to_dB(m_threshold)); | 262 val = int(lrint(AudioLevel::multiplier_to_dB(m_threshold))); |
263 if (val < *min) val = *min; | 263 if (val < *min) val = *min; |
264 if (val > *max) val = *max; | 264 if (val > *max) val = *max; |
265 | 265 |
266 } else if (name == "Colour Rotation") { | 266 } else if (name == "Colour Rotation") { |
267 | 267 |
479 | 479 |
480 void | 480 void |
481 SpectrogramLayer::setProperty(const PropertyName &name, int value) | 481 SpectrogramLayer::setProperty(const PropertyName &name, int value) |
482 { | 482 { |
483 if (name == "Gain") { | 483 if (name == "Gain") { |
484 setGain(pow(10, float(value)/20.0)); | 484 setGain(float(pow(10, float(value)/20.0))); |
485 } else if (name == "Threshold") { | 485 } else if (name == "Threshold") { |
486 if (value == -50) setThreshold(0.0); | 486 if (value == -50) setThreshold(0.0); |
487 else setThreshold(AudioLevel::dB_to_multiplier(value)); | 487 else setThreshold(float(AudioLevel::dB_to_multiplier(value))); |
488 } else if (name == "Colour Rotation") { | 488 } else if (name == "Colour Rotation") { |
489 setColourRotation(value); | 489 setColourRotation(value); |
490 } else if (name == "Colour") { | 490 } else if (name == "Colour") { |
491 setColourMap(value); | 491 setColourMap(value); |
492 } else if (name == "Window Size") { | 492 } else if (name == "Window Size") { |
570 i->second.validArea = QRect(); | 570 i->second.validArea = QRect(); |
571 } | 571 } |
572 } | 572 } |
573 | 573 |
574 void | 574 void |
575 SpectrogramLayer::invalidateImageCaches(int startFrame, int endFrame) | 575 SpectrogramLayer::invalidateImageCaches(sv_frame_t startFrame, sv_frame_t endFrame) |
576 { | 576 { |
577 for (ViewImageCache::iterator i = m_imageCaches.begin(); | 577 for (ViewImageCache::iterator i = m_imageCaches.begin(); |
578 i != m_imageCaches.end(); ++i) { | 578 i != m_imageCaches.end(); ++i) { |
579 | 579 |
580 //!!! when are views removed from the map? on setLayerDormant? | 580 //!!! when are views removed from the map? on setLayerDormant? |
1047 invalidateImageCaches(); | 1047 invalidateImageCaches(); |
1048 invalidateMagnitudes(); | 1048 invalidateMagnitudes(); |
1049 } | 1049 } |
1050 | 1050 |
1051 void | 1051 void |
1052 SpectrogramLayer::cacheInvalid(int from, int to) | 1052 SpectrogramLayer::cacheInvalid(sv_frame_t from, sv_frame_t to) |
1053 { | 1053 { |
1054 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1054 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1055 SVDEBUG << "SpectrogramLayer::cacheInvalid(" << from << ", " << to << ")" << endl; | 1055 SVDEBUG << "SpectrogramLayer::cacheInvalid(" << from << ", " << to << ")" << endl; |
1056 #endif | 1056 #endif |
1057 | 1057 |
1072 | 1072 |
1073 for (ViewFFTMap::iterator i = m_fftModels.begin(); | 1073 for (ViewFFTMap::iterator i = m_fftModels.begin(); |
1074 i != m_fftModels.end(); ++i) { | 1074 i != m_fftModels.end(); ++i) { |
1075 | 1075 |
1076 const FFTModel *model = i->second.first; | 1076 const FFTModel *model = i->second.first; |
1077 int lastFill = i->second.second; | 1077 sv_frame_t lastFill = i->second.second; |
1078 | 1078 |
1079 if (model) { | 1079 if (model) { |
1080 | 1080 |
1081 int fill = model->getFillExtent(); | 1081 sv_frame_t fill = model->getFillExtent(); |
1082 | 1082 |
1083 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1083 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1084 SVDEBUG << "SpectrogramLayer::fillTimerTimedOut: extent for " << model << ": " << fill << ", last " << lastFill << ", total " << m_model->getEndFrame() << endl; | 1084 SVDEBUG << "SpectrogramLayer::fillTimerTimedOut: extent for " << model << ": " << fill << ", last " << lastFill << ", total " << m_model->getEndFrame() << endl; |
1085 #endif | 1085 #endif |
1086 | 1086 |
1145 } | 1145 } |
1146 | 1146 |
1147 ColourMapper mapper(m_colourMap, 1.f, 255.f); | 1147 ColourMapper mapper(m_colourMap, 1.f, 255.f); |
1148 | 1148 |
1149 for (int pixel = 1; pixel < 256; ++pixel) { | 1149 for (int pixel = 1; pixel < 256; ++pixel) { |
1150 m_palette.setColour(pixel, mapper.map(pixel)); | 1150 m_palette.setColour((unsigned char)pixel, mapper.map(pixel)); |
1151 } | 1151 } |
1152 | 1152 |
1153 m_crosshairColour = mapper.getContrastingColour(); | 1153 m_crosshairColour = mapper.getContrastingColour(); |
1154 | 1154 |
1155 m_colourRotation = 0; | 1155 m_colourRotation = 0; |
1168 | 1168 |
1169 for (int pixel = 1; pixel < 256; ++pixel) { | 1169 for (int pixel = 1; pixel < 256; ++pixel) { |
1170 int target = pixel + distance; | 1170 int target = pixel + distance; |
1171 while (target < 1) target += 255; | 1171 while (target < 1) target += 255; |
1172 while (target > 255) target -= 255; | 1172 while (target > 255) target -= 255; |
1173 newPixels[target] = m_palette.getColour(pixel); | 1173 newPixels[target] = m_palette.getColour((unsigned char)pixel); |
1174 } | 1174 } |
1175 | 1175 |
1176 for (int pixel = 0; pixel < 256; ++pixel) { | 1176 for (int pixel = 0; pixel < 256; ++pixel) { |
1177 m_palette.setColour(pixel, newPixels[pixel]); | 1177 m_palette.setColour((unsigned char)pixel, newPixels[pixel]); |
1178 } | 1178 } |
1179 | 1179 |
1180 m_drawBuffer = QImage(); | 1180 m_drawBuffer = QImage(); |
1181 } | 1181 } |
1182 | 1182 |
1183 unsigned char | 1183 unsigned char |
1184 SpectrogramLayer::getDisplayValue(View *v, float input) const | 1184 SpectrogramLayer::getDisplayValue(View *v, double input) const |
1185 { | 1185 { |
1186 int value; | 1186 int value; |
1187 | 1187 |
1188 float min = 0.f; | 1188 double min = 0.0; |
1189 float max = 1.f; | 1189 double max = 1.0; |
1190 | 1190 |
1191 if (m_normalizeVisibleArea) { | 1191 if (m_normalizeVisibleArea) { |
1192 min = m_viewMags[v].getMin(); | 1192 min = m_viewMags[v].getMin(); |
1193 max = m_viewMags[v].getMax(); | 1193 max = m_viewMags[v].getMax(); |
1194 } else if (!m_normalizeColumns) { | 1194 } else if (!m_normalizeColumns) { |
1195 if (m_colourScale == LinearColourScale //|| | 1195 if (m_colourScale == LinearColourScale //|| |
1196 // m_colourScale == MeterColourScale) { | 1196 // m_colourScale == MeterColourScale) { |
1197 ) { | 1197 ) { |
1198 max = 0.1f; | 1198 max = 0.1; |
1199 } | 1199 } |
1200 } | 1200 } |
1201 | 1201 |
1202 float thresh = -80.f; | 1202 double thresh = -80.0; |
1203 | 1203 |
1204 if (max == 0.f) max = 1.f; | 1204 if (max == 0.0) max = 1.0; |
1205 if (max == min) min = max - 0.0001f; | 1205 if (max == min) min = max - 0.0001; |
1206 | 1206 |
1207 switch (m_colourScale) { | 1207 switch (m_colourScale) { |
1208 | 1208 |
1209 default: | 1209 default: |
1210 case LinearColourScale: | 1210 case LinearColourScale: |
1211 value = int(((input - min) / (max - min)) * 255.f) + 1; | 1211 value = int(((input - min) / (max - min)) * 255.0) + 1; |
1212 break; | 1212 break; |
1213 | 1213 |
1214 case MeterColourScale: | 1214 case MeterColourScale: |
1215 value = AudioLevel::multiplier_to_preview | 1215 value = AudioLevel::multiplier_to_preview |
1216 ((input - min) / (max - min), 254) + 1; | 1216 ((input - min) / (max - min), 254) + 1; |
1217 break; | 1217 break; |
1218 | 1218 |
1219 case dBSquaredColourScale: | 1219 case dBSquaredColourScale: |
1220 input = ((input - min) * (input - min)) / ((max - min) * (max - min)); | 1220 input = ((input - min) * (input - min)) / ((max - min) * (max - min)); |
1221 if (input > 0.f) { | 1221 if (input > 0.0) { |
1222 input = 10.f * log10f(input); | 1222 input = 10.0 * log10(input); |
1223 } else { | 1223 } else { |
1224 input = thresh; | 1224 input = thresh; |
1225 } | 1225 } |
1226 if (min > 0.f) { | 1226 if (min > 0.0) { |
1227 thresh = 10.f * log10f(min * min); | 1227 thresh = 10.0 * log10(min * min); |
1228 if (thresh < -80.f) thresh = -80.f; | 1228 if (thresh < -80.0) thresh = -80.0; |
1229 } | 1229 } |
1230 input = (input - thresh) / (-thresh); | 1230 input = (input - thresh) / (-thresh); |
1231 if (input < 0.f) input = 0.f; | 1231 if (input < 0.0) input = 0.0; |
1232 if (input > 1.f) input = 1.f; | 1232 if (input > 1.0) input = 1.0; |
1233 value = int(input * 255.f) + 1; | 1233 value = int(input * 255.0) + 1; |
1234 break; | 1234 break; |
1235 | 1235 |
1236 case dBColourScale: | 1236 case dBColourScale: |
1237 //!!! experiment with normalizing the visible area this way. | 1237 //!!! experiment with normalizing the visible area this way. |
1238 //In any case, we need to have some indication of what the dB | 1238 //In any case, we need to have some indication of what the dB |
1239 //scale is relative to. | 1239 //scale is relative to. |
1240 input = (input - min) / (max - min); | 1240 input = (input - min) / (max - min); |
1241 if (input > 0.f) { | 1241 if (input > 0.0) { |
1242 input = 10.f * log10f(input); | 1242 input = 10.0 * log10(input); |
1243 } else { | 1243 } else { |
1244 input = thresh; | 1244 input = thresh; |
1245 } | 1245 } |
1246 if (min > 0.f) { | 1246 if (min > 0.0) { |
1247 thresh = 10.f * log10f(min); | 1247 thresh = 10.0 * log10(min); |
1248 if (thresh < -80.f) thresh = -80.f; | 1248 if (thresh < -80.0) thresh = -80.0; |
1249 } | 1249 } |
1250 input = (input - thresh) / (-thresh); | 1250 input = (input - thresh) / (-thresh); |
1251 if (input < 0.f) input = 0.f; | 1251 if (input < 0.0) input = 0.0; |
1252 if (input > 1.f) input = 1.f; | 1252 if (input > 1.0) input = 1.0; |
1253 value = int(input * 255.f) + 1; | 1253 value = int(input * 255.0) + 1; |
1254 break; | 1254 break; |
1255 | 1255 |
1256 case PhaseColourScale: | 1256 case PhaseColourScale: |
1257 value = int((input * 127.0 / M_PI) + 128); | 1257 value = int((input * 127.0 / M_PI) + 128); |
1258 break; | 1258 break; |
1259 } | 1259 } |
1260 | 1260 |
1261 if (value > UCHAR_MAX) value = UCHAR_MAX; | 1261 if (value > UCHAR_MAX) value = UCHAR_MAX; |
1262 if (value < 0) value = 0; | 1262 if (value < 0) value = 0; |
1263 return value; | 1263 return (unsigned char)value; |
1264 } | 1264 } |
1265 | 1265 |
1266 float | 1266 double |
1267 SpectrogramLayer::getEffectiveMinFrequency() const | 1267 SpectrogramLayer::getEffectiveMinFrequency() const |
1268 { | 1268 { |
1269 int sr = m_model->getSampleRate(); | 1269 sv_samplerate_t sr = m_model->getSampleRate(); |
1270 float minf = float(sr) / m_fftSize; | 1270 double minf = double(sr) / m_fftSize; |
1271 | 1271 |
1272 if (m_minFrequency > 0.0) { | 1272 if (m_minFrequency > 0.0) { |
1273 int minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.01); | 1273 int minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.01); |
1274 if (minbin < 1) minbin = 1; | 1274 if (minbin < 1) minbin = 1; |
1275 minf = minbin * sr / m_fftSize; | 1275 minf = minbin * sr / m_fftSize; |
1276 } | 1276 } |
1277 | 1277 |
1278 return minf; | 1278 return minf; |
1279 } | 1279 } |
1280 | 1280 |
1281 float | 1281 double |
1282 SpectrogramLayer::getEffectiveMaxFrequency() const | 1282 SpectrogramLayer::getEffectiveMaxFrequency() const |
1283 { | 1283 { |
1284 int sr = m_model->getSampleRate(); | 1284 sv_samplerate_t sr = m_model->getSampleRate(); |
1285 float maxf = float(sr) / 2; | 1285 double maxf = double(sr) / 2; |
1286 | 1286 |
1287 if (m_maxFrequency > 0.0) { | 1287 if (m_maxFrequency > 0.0) { |
1288 int maxbin = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); | 1288 int maxbin = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); |
1289 if (maxbin > m_fftSize / 2) maxbin = m_fftSize / 2; | 1289 if (maxbin > m_fftSize / 2) maxbin = m_fftSize / 2; |
1290 maxf = maxbin * sr / m_fftSize; | 1290 maxf = maxbin * sr / m_fftSize; |
1292 | 1292 |
1293 return maxf; | 1293 return maxf; |
1294 } | 1294 } |
1295 | 1295 |
1296 bool | 1296 bool |
1297 SpectrogramLayer::getYBinRange(View *v, int y, float &q0, float &q1) const | 1297 SpectrogramLayer::getYBinRange(View *v, int y, double &q0, double &q1) const |
1298 { | 1298 { |
1299 Profiler profiler("SpectrogramLayer::getYBinRange"); | 1299 Profiler profiler("SpectrogramLayer::getYBinRange"); |
1300 | 1300 |
1301 int h = v->height(); | 1301 int h = v->height(); |
1302 if (y < 0 || y >= h) return false; | 1302 if (y < 0 || y >= h) return false; |
1303 | 1303 |
1304 int sr = m_model->getSampleRate(); | 1304 sv_samplerate_t sr = m_model->getSampleRate(); |
1305 float minf = getEffectiveMinFrequency(); | 1305 double minf = getEffectiveMinFrequency(); |
1306 float maxf = getEffectiveMaxFrequency(); | 1306 double maxf = getEffectiveMaxFrequency(); |
1307 | 1307 |
1308 bool logarithmic = (m_frequencyScale == LogFrequencyScale); | 1308 bool logarithmic = (m_frequencyScale == LogFrequencyScale); |
1309 | 1309 |
1310 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); | 1310 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); |
1311 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); | 1311 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); |
1318 | 1318 |
1319 return true; | 1319 return true; |
1320 } | 1320 } |
1321 | 1321 |
1322 bool | 1322 bool |
1323 SpectrogramLayer::getSmoothedYBinRange(View *v, int y, float &q0, float &q1) const | 1323 SpectrogramLayer::getSmoothedYBinRange(View *v, int y, double &q0, double &q1) const |
1324 { | 1324 { |
1325 Profiler profiler("SpectrogramLayer::getSmoothedYBinRange"); | 1325 Profiler profiler("SpectrogramLayer::getSmoothedYBinRange"); |
1326 | 1326 |
1327 int h = v->height(); | 1327 int h = v->height(); |
1328 if (y < 0 || y >= h) return false; | 1328 if (y < 0 || y >= h) return false; |
1329 | 1329 |
1330 int sr = m_model->getSampleRate(); | 1330 sv_samplerate_t sr = m_model->getSampleRate(); |
1331 float minf = getEffectiveMinFrequency(); | 1331 double minf = getEffectiveMinFrequency(); |
1332 float maxf = getEffectiveMaxFrequency(); | 1332 double maxf = getEffectiveMaxFrequency(); |
1333 | 1333 |
1334 bool logarithmic = (m_frequencyScale == LogFrequencyScale); | 1334 bool logarithmic = (m_frequencyScale == LogFrequencyScale); |
1335 | 1335 |
1336 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); | 1336 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); |
1337 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); | 1337 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); |
1344 | 1344 |
1345 return true; | 1345 return true; |
1346 } | 1346 } |
1347 | 1347 |
1348 bool | 1348 bool |
1349 SpectrogramLayer::getXBinRange(View *v, int x, float &s0, float &s1) const | 1349 SpectrogramLayer::getXBinRange(View *v, int x, double &s0, double &s1) const |
1350 { | 1350 { |
1351 int modelStart = m_model->getStartFrame(); | 1351 sv_frame_t modelStart = m_model->getStartFrame(); |
1352 int modelEnd = m_model->getEndFrame(); | 1352 sv_frame_t modelEnd = m_model->getEndFrame(); |
1353 | 1353 |
1354 // Each pixel column covers an exact range of sample frames: | 1354 // Each pixel column covers an exact range of sample frames: |
1355 int f0 = v->getFrameForX(x) - modelStart; | 1355 sv_frame_t f0 = v->getFrameForX(x) - modelStart; |
1356 int f1 = v->getFrameForX(x + 1) - modelStart - 1; | 1356 sv_frame_t f1 = v->getFrameForX(x + 1) - modelStart - 1; |
1357 | 1357 |
1358 if (f1 < int(modelStart) || f0 > int(modelEnd)) { | 1358 if (f1 < int(modelStart) || f0 > int(modelEnd)) { |
1359 return false; | 1359 return false; |
1360 } | 1360 } |
1361 | 1361 |
1362 // And that range may be drawn from a possibly non-integral | 1362 // And that range may be drawn from a possibly non-integral |
1363 // range of spectrogram windows: | 1363 // range of spectrogram windows: |
1364 | 1364 |
1365 int windowIncrement = getWindowIncrement(); | 1365 int windowIncrement = getWindowIncrement(); |
1366 s0 = float(f0) / windowIncrement; | 1366 s0 = double(f0) / windowIncrement; |
1367 s1 = float(f1) / windowIncrement; | 1367 s1 = double(f1) / windowIncrement; |
1368 | 1368 |
1369 return true; | 1369 return true; |
1370 } | 1370 } |
1371 | 1371 |
1372 bool | 1372 bool |
1373 SpectrogramLayer::getXBinSourceRange(View *v, int x, RealTime &min, RealTime &max) const | 1373 SpectrogramLayer::getXBinSourceRange(View *v, int x, RealTime &min, RealTime &max) const |
1374 { | 1374 { |
1375 float s0 = 0, s1 = 0; | 1375 double s0 = 0, s1 = 0; |
1376 if (!getXBinRange(v, x, s0, s1)) return false; | 1376 if (!getXBinRange(v, x, s0, s1)) return false; |
1377 | 1377 |
1378 int s0i = int(s0 + 0.001); | 1378 int s0i = int(s0 + 0.001); |
1379 int s1i = int(s1); | 1379 int s1i = int(s1); |
1380 | 1380 |
1387 max = RealTime::frame2RealTime(w1, m_model->getSampleRate()); | 1387 max = RealTime::frame2RealTime(w1, m_model->getSampleRate()); |
1388 return true; | 1388 return true; |
1389 } | 1389 } |
1390 | 1390 |
1391 bool | 1391 bool |
1392 SpectrogramLayer::getYBinSourceRange(View *v, int y, float &freqMin, float &freqMax) | 1392 SpectrogramLayer::getYBinSourceRange(View *v, int y, double &freqMin, double &freqMax) |
1393 const | 1393 const |
1394 { | 1394 { |
1395 float q0 = 0, q1 = 0; | 1395 double q0 = 0, q1 = 0; |
1396 if (!getYBinRange(v, y, q0, q1)) return false; | 1396 if (!getYBinRange(v, y, q0, q1)) return false; |
1397 | 1397 |
1398 int q0i = int(q0 + 0.001); | 1398 int q0i = int(q0 + 0.001); |
1399 int q1i = int(q1); | 1399 int q1i = int(q1); |
1400 | 1400 |
1401 int sr = m_model->getSampleRate(); | 1401 sv_samplerate_t sr = m_model->getSampleRate(); |
1402 | 1402 |
1403 for (int q = q0i; q <= q1i; ++q) { | 1403 for (int q = q0i; q <= q1i; ++q) { |
1404 if (q == q0i) freqMin = (sr * q) / m_fftSize; | 1404 if (q == q0i) freqMin = (sr * q) / m_fftSize; |
1405 if (q == q1i) freqMax = (sr * (q+1)) / m_fftSize; | 1405 if (q == q1i) freqMax = (sr * (q+1)) / m_fftSize; |
1406 } | 1406 } |
1407 return true; | 1407 return true; |
1408 } | 1408 } |
1409 | 1409 |
1410 bool | 1410 bool |
1411 SpectrogramLayer::getAdjustedYBinSourceRange(View *v, int x, int y, | 1411 SpectrogramLayer::getAdjustedYBinSourceRange(View *v, int x, int y, |
1412 float &freqMin, float &freqMax, | 1412 double &freqMin, double &freqMax, |
1413 float &adjFreqMin, float &adjFreqMax) | 1413 double &adjFreqMin, double &adjFreqMax) |
1414 const | 1414 const |
1415 { | 1415 { |
1416 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | 1416 if (!m_model || !m_model->isOK() || !m_model->isReady()) { |
1417 return false; | 1417 return false; |
1418 } | 1418 } |
1419 | 1419 |
1420 FFTModel *fft = getFFTModel(v); | 1420 FFTModel *fft = getFFTModel(v); |
1421 if (!fft) return false; | 1421 if (!fft) return false; |
1422 | 1422 |
1423 float s0 = 0, s1 = 0; | 1423 double s0 = 0, s1 = 0; |
1424 if (!getXBinRange(v, x, s0, s1)) return false; | 1424 if (!getXBinRange(v, x, s0, s1)) return false; |
1425 | 1425 |
1426 float q0 = 0, q1 = 0; | 1426 double q0 = 0, q1 = 0; |
1427 if (!getYBinRange(v, y, q0, q1)) return false; | 1427 if (!getYBinRange(v, y, q0, q1)) return false; |
1428 | 1428 |
1429 int s0i = int(s0 + 0.001); | 1429 int s0i = int(s0 + 0.001); |
1430 int s1i = int(s1); | 1430 int s1i = int(s1); |
1431 | 1431 |
1432 int q0i = int(q0 + 0.001); | 1432 int q0i = int(q0 + 0.001); |
1433 int q1i = int(q1); | 1433 int q1i = int(q1); |
1434 | 1434 |
1435 int sr = m_model->getSampleRate(); | 1435 sv_samplerate_t sr = m_model->getSampleRate(); |
1436 | 1436 |
1437 bool haveAdj = false; | 1437 bool haveAdj = false; |
1438 | 1438 |
1439 bool peaksOnly = (m_binDisplay == PeakBins || | 1439 bool peaksOnly = (m_binDisplay == PeakBins || |
1440 m_binDisplay == PeakFrequencies); | 1440 m_binDisplay == PeakFrequencies); |
1443 | 1443 |
1444 for (int s = s0i; s <= s1i; ++s) { | 1444 for (int s = s0i; s <= s1i; ++s) { |
1445 | 1445 |
1446 if (!fft->isColumnAvailable(s)) continue; | 1446 if (!fft->isColumnAvailable(s)) continue; |
1447 | 1447 |
1448 float binfreq = (float(sr) * q) / m_windowSize; | 1448 double binfreq = (double(sr) * q) / m_windowSize; |
1449 if (q == q0i) freqMin = binfreq; | 1449 if (q == q0i) freqMin = binfreq; |
1450 if (q == q1i) freqMax = binfreq; | 1450 if (q == q1i) freqMax = binfreq; |
1451 | 1451 |
1452 if (peaksOnly && !fft->isLocalPeak(s, q)) continue; | 1452 if (peaksOnly && !fft->isLocalPeak(s, q)) continue; |
1453 | 1453 |
1454 if (!fft->isOverThreshold(s, q, m_threshold * (m_fftSize/2))) continue; | 1454 if (!fft->isOverThreshold(s, q, float(m_threshold * double(m_fftSize)/2.0))) continue; |
1455 | 1455 |
1456 float freq = binfreq; | 1456 double freq = binfreq; |
1457 | 1457 |
1458 if (s < int(fft->getWidth()) - 1) { | 1458 if (s < int(fft->getWidth()) - 1) { |
1459 | 1459 |
1460 fft->estimateStableFrequency(s, q, freq); | 1460 fft->estimateStableFrequency(s, q, freq); |
1461 | 1461 |
1474 return haveAdj; | 1474 return haveAdj; |
1475 } | 1475 } |
1476 | 1476 |
1477 bool | 1477 bool |
1478 SpectrogramLayer::getXYBinSourceRange(View *v, int x, int y, | 1478 SpectrogramLayer::getXYBinSourceRange(View *v, int x, int y, |
1479 float &min, float &max, | 1479 double &min, double &max, |
1480 float &phaseMin, float &phaseMax) const | 1480 double &phaseMin, double &phaseMax) const |
1481 { | 1481 { |
1482 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | 1482 if (!m_model || !m_model->isOK() || !m_model->isReady()) { |
1483 return false; | 1483 return false; |
1484 } | 1484 } |
1485 | 1485 |
1486 float q0 = 0, q1 = 0; | 1486 double q0 = 0, q1 = 0; |
1487 if (!getYBinRange(v, y, q0, q1)) return false; | 1487 if (!getYBinRange(v, y, q0, q1)) return false; |
1488 | 1488 |
1489 float s0 = 0, s1 = 0; | 1489 double s0 = 0, s1 = 0; |
1490 if (!getXBinRange(v, x, s0, s1)) return false; | 1490 if (!getXBinRange(v, x, s0, s1)) return false; |
1491 | 1491 |
1492 int q0i = int(q0 + 0.001); | 1492 int q0i = int(q0 + 0.001); |
1493 int q1i = int(q1); | 1493 int q1i = int(q1); |
1494 | 1494 |
1518 for (int s = s0i; s <= s1i; ++s) { | 1518 for (int s = s0i; s <= s1i; ++s) { |
1519 if (s >= 0 && q >= 0 && s < cw && q < ch) { | 1519 if (s >= 0 && q >= 0 && s < cw && q < ch) { |
1520 | 1520 |
1521 if (!fft->isColumnAvailable(s)) continue; | 1521 if (!fft->isColumnAvailable(s)) continue; |
1522 | 1522 |
1523 float value; | 1523 double value; |
1524 | 1524 |
1525 value = fft->getPhaseAt(s, q); | 1525 value = fft->getPhaseAt(s, q); |
1526 if (!have || value < phaseMin) { phaseMin = value; } | 1526 if (!have || value < phaseMin) { phaseMin = value; } |
1527 if (!have || value > phaseMax) { phaseMax = value; } | 1527 if (!have || value > phaseMax) { phaseMax = value; } |
1528 | 1528 |
1529 value = fft->getMagnitudeAt(s, q) / (m_fftSize/2); | 1529 value = fft->getMagnitudeAt(s, q) / (m_fftSize/2.0); |
1530 if (!have || value < min) { min = value; } | 1530 if (!have || value < min) { min = value; } |
1531 if (!have || value > max) { max = value; } | 1531 if (!have || value > max) { max = value; } |
1532 | 1532 |
1533 have = true; | 1533 have = true; |
1534 } | 1534 } |
1556 if (smoothing == Preferences::NoSpectrogramSmoothing || | 1556 if (smoothing == Preferences::NoSpectrogramSmoothing || |
1557 smoothing == Preferences::SpectrogramInterpolated) return 0; | 1557 smoothing == Preferences::SpectrogramInterpolated) return 0; |
1558 | 1558 |
1559 if (m_frequencyScale == LogFrequencyScale) return 3; | 1559 if (m_frequencyScale == LogFrequencyScale) return 3; |
1560 | 1560 |
1561 int sr = m_model->getSampleRate(); | 1561 sv_samplerate_t sr = m_model->getSampleRate(); |
1562 | 1562 |
1563 int maxbin = m_fftSize / 2; | 1563 int maxbin = m_fftSize / 2; |
1564 if (m_maxFrequency > 0) { | 1564 if (m_maxFrequency > 0) { |
1565 maxbin = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); | 1565 maxbin = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); |
1566 if (maxbin > m_fftSize / 2) maxbin = m_fftSize / 2; | 1566 if (maxbin > m_fftSize / 2) maxbin = m_fftSize / 2; |
1571 minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.1); | 1571 minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.1); |
1572 if (minbin < 1) minbin = 1; | 1572 if (minbin < 1) minbin = 1; |
1573 if (minbin >= maxbin) minbin = maxbin - 1; | 1573 if (minbin >= maxbin) minbin = maxbin - 1; |
1574 } | 1574 } |
1575 | 1575 |
1576 float perPixel = | 1576 double perPixel = |
1577 float(v->height()) / | 1577 double(v->height()) / |
1578 float((maxbin - minbin) / (m_zeroPadLevel + 1)); | 1578 double((maxbin - minbin) / (m_zeroPadLevel + 1)); |
1579 | 1579 |
1580 if (perPixel > 2.8) { | 1580 if (perPixel > 2.8) { |
1581 return 3; // 4x oversampling | 1581 return 3; // 4x oversampling |
1582 } else if (perPixel > 1.5) { | 1582 } else if (perPixel > 1.5) { |
1583 return 1; // 2x | 1583 return 1; // 2x |
1722 SpectrogramLayer::updateViewMagnitudes(View *v) const | 1722 SpectrogramLayer::updateViewMagnitudes(View *v) const |
1723 { | 1723 { |
1724 MagnitudeRange mag; | 1724 MagnitudeRange mag; |
1725 | 1725 |
1726 int x0 = 0, x1 = v->width(); | 1726 int x0 = 0, x1 = v->width(); |
1727 float s00 = 0, s01 = 0, s10 = 0, s11 = 0; | 1727 double s00 = 0, s01 = 0, s10 = 0, s11 = 0; |
1728 | 1728 |
1729 if (!getXBinRange(v, x0, s00, s01)) { | 1729 if (!getXBinRange(v, x0, s00, s01)) { |
1730 s00 = s01 = m_model->getStartFrame() / getWindowIncrement(); | 1730 s00 = s01 = double(m_model->getStartFrame()) / getWindowIncrement(); |
1731 } | 1731 } |
1732 | 1732 |
1733 if (!getXBinRange(v, x1, s10, s11)) { | 1733 if (!getXBinRange(v, x1, s10, s11)) { |
1734 s10 = s11 = m_model->getEndFrame() / getWindowIncrement(); | 1734 s10 = s11 = double(m_model->getEndFrame()) / getWindowIncrement(); |
1735 } | 1735 } |
1736 | 1736 |
1737 int s0 = int(std::min(s00, s10) + 0.0001); | 1737 int s0 = int(std::min(s00, s10) + 0.0001); |
1738 int s1 = int(std::max(s01, s11) + 0.0001); | 1738 int s1 = int(std::max(s01, s11) + 0.0001); |
1739 | 1739 |
1778 SVDEBUG << "SpectrogramLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << ", m_updateTimer " << m_updateTimer << endl; | 1778 SVDEBUG << "SpectrogramLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << ", m_updateTimer " << m_updateTimer << endl; |
1779 | 1779 |
1780 cerr << "rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl; | 1780 cerr << "rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl; |
1781 #endif | 1781 #endif |
1782 | 1782 |
1783 int startFrame = v->getStartFrame(); | 1783 sv_frame_t startFrame = v->getStartFrame(); |
1784 if (startFrame < 0) m_candidateFillStartFrame = 0; | 1784 if (startFrame < 0) m_candidateFillStartFrame = 0; |
1785 else m_candidateFillStartFrame = startFrame; | 1785 else m_candidateFillStartFrame = startFrame; |
1786 | 1786 |
1787 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | 1787 if (!m_model || !m_model->isOK() || !m_model->isReady()) { |
1788 return; | 1788 return; |
1828 bool recreateWholeImageCache = true; | 1828 bool recreateWholeImageCache = true; |
1829 | 1829 |
1830 x0 = rect.left(); | 1830 x0 = rect.left(); |
1831 x1 = rect.right() + 1; | 1831 x1 = rect.right() + 1; |
1832 /* | 1832 /* |
1833 float xPixelRatio = float(fft->getResolution()) / float(zoomLevel); | 1833 double xPixelRatio = double(fft->getResolution()) / double(zoomLevel); |
1834 cerr << "xPixelRatio = " << xPixelRatio << endl; | 1834 cerr << "xPixelRatio = " << xPixelRatio << endl; |
1835 if (xPixelRatio < 1.f) xPixelRatio = 1.f; | 1835 if (xPixelRatio < 1.f) xPixelRatio = 1.f; |
1836 */ | 1836 */ |
1837 if (cache.validArea.width() > 0) { | 1837 if (cache.validArea.width() > 0) { |
1838 | 1838 |
1879 dx > -cw && | 1879 dx > -cw && |
1880 dx < cw) { | 1880 dx < cw) { |
1881 | 1881 |
1882 int dxp = dx; | 1882 int dxp = dx; |
1883 if (dxp < 0) dxp = -dxp; | 1883 if (dxp < 0) dxp = -dxp; |
1884 int copy = (cw - dxp) * sizeof(QRgb); | 1884 size_t copy = (cw - dxp) * sizeof(QRgb); |
1885 for (int y = 0; y < ch; ++y) { | 1885 for (int y = 0; y < ch; ++y) { |
1886 QRgb *line = (QRgb *)cache.image.scanLine(y); | 1886 QRgb *line = (QRgb *)cache.image.scanLine(y); |
1887 if (dx < 0) { | 1887 if (dx < 0) { |
1888 memmove(line, line + dxp, copy); | 1888 memmove(line, line + dxp, copy); |
1889 } else { | 1889 } else { |
2104 | 2104 |
2105 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2105 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2106 cerr << "x0 " << x0 << ", x1 " << x1 << ", w " << w << ", h " << h << endl; | 2106 cerr << "x0 " << x0 << ", x1 " << x1 << ", w " << w << ", h " << h << endl; |
2107 #endif | 2107 #endif |
2108 | 2108 |
2109 int sr = m_model->getSampleRate(); | 2109 sv_samplerate_t sr = m_model->getSampleRate(); |
2110 | 2110 |
2111 // Set minFreq and maxFreq to the frequency extents of the possibly | 2111 // Set minFreq and maxFreq to the frequency extents of the possibly |
2112 // zero-padded visible bin range, and displayMinFreq and displayMaxFreq | 2112 // zero-padded visible bin range, and displayMinFreq and displayMaxFreq |
2113 // to the actual scale frequency extents (presumably not zero padded). | 2113 // to the actual scale frequency extents (presumably not zero padded). |
2114 | 2114 |
2135 | 2135 |
2136 int zpl = getZeroPadLevel(v) + 1; | 2136 int zpl = getZeroPadLevel(v) + 1; |
2137 minbin = minbin * zpl; | 2137 minbin = minbin * zpl; |
2138 maxbin = (maxbin + 1) * zpl - 1; | 2138 maxbin = (maxbin + 1) * zpl - 1; |
2139 | 2139 |
2140 float minFreq = (float(minbin) * sr) / fftSize; | 2140 double minFreq = (double(minbin) * sr) / fftSize; |
2141 float maxFreq = (float(maxbin) * sr) / fftSize; | 2141 double maxFreq = (double(maxbin) * sr) / fftSize; |
2142 | 2142 |
2143 float displayMinFreq = minFreq; | 2143 double displayMinFreq = minFreq; |
2144 float displayMaxFreq = maxFreq; | 2144 double displayMaxFreq = maxFreq; |
2145 | 2145 |
2146 if (fftSize != m_fftSize) { | 2146 if (fftSize != m_fftSize) { |
2147 displayMinFreq = getEffectiveMinFrequency(); | 2147 displayMinFreq = getEffectiveMinFrequency(); |
2148 displayMaxFreq = getEffectiveMaxFrequency(); | 2148 displayMaxFreq = getEffectiveMaxFrequency(); |
2149 } | 2149 } |
2152 | 2152 |
2153 int increment = getWindowIncrement(); | 2153 int increment = getWindowIncrement(); |
2154 | 2154 |
2155 bool logarithmic = (m_frequencyScale == LogFrequencyScale); | 2155 bool logarithmic = (m_frequencyScale == LogFrequencyScale); |
2156 /* | 2156 /* |
2157 float yforbin[maxbin - minbin + 1]; | 2157 double yforbin[maxbin - minbin + 1]; |
2158 | 2158 |
2159 for (int q = minbin; q <= maxbin; ++q) { | 2159 for (int q = minbin; q <= maxbin; ++q) { |
2160 float f0 = (float(q) * sr) / fftSize; | 2160 double f0 = (double(q) * sr) / fftSize; |
2161 yforbin[q - minbin] = | 2161 yforbin[q - minbin] = |
2162 v->getYForFrequency(f0, displayMinFreq, displayMaxFreq, | 2162 v->getYForFrequency(f0, displayMinFreq, displayMaxFreq, |
2163 logarithmic); | 2163 logarithmic); |
2164 } | 2164 } |
2165 */ | 2165 */ |
2166 MagnitudeRange overallMag = m_viewMags[v]; | 2166 MagnitudeRange overallMag = m_viewMags[v]; |
2167 bool overallMagChanged = false; | 2167 bool overallMagChanged = false; |
2168 | 2168 |
2169 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2169 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2170 cerr << ((float(v->getFrameForX(1) - v->getFrameForX(0))) / increment) << " bin(s) per pixel" << endl; | 2170 cerr << ((double(v->getFrameForX(1) - v->getFrameForX(0))) / increment) << " bin(s) per pixel" << endl; |
2171 #endif | 2171 #endif |
2172 | 2172 |
2173 if (w == 0) { | 2173 if (w == 0) { |
2174 SVDEBUG << "*** NOTE: w == 0" << endl; | 2174 SVDEBUG << "*** NOTE: w == 0" << endl; |
2175 } | 2175 } |
2194 // we draw up to, and one which we subsequently crop at. | 2194 // we draw up to, and one which we subsequently crop at. |
2195 | 2195 |
2196 bool bufferBinResolution = false; | 2196 bool bufferBinResolution = false; |
2197 if (increment > zoomLevel) bufferBinResolution = true; | 2197 if (increment > zoomLevel) bufferBinResolution = true; |
2198 | 2198 |
2199 int leftBoundaryFrame = -1, leftCropFrame = -1; | 2199 sv_frame_t leftBoundaryFrame = -1, leftCropFrame = -1; |
2200 int rightBoundaryFrame = -1, rightCropFrame = -1; | 2200 sv_frame_t rightBoundaryFrame = -1, rightCropFrame = -1; |
2201 | 2201 |
2202 int bufwid; | 2202 int bufwid; |
2203 | 2203 |
2204 if (bufferBinResolution) { | 2204 if (bufferBinResolution) { |
2205 | 2205 |
2206 for (int x = x0; ; --x) { | 2206 for (int x = x0; ; --x) { |
2207 int f = v->getFrameForX(x); | 2207 sv_frame_t f = v->getFrameForX(x); |
2208 if ((f / increment) * increment == f) { | 2208 if ((f / increment) * increment == f) { |
2209 if (leftCropFrame == -1) leftCropFrame = f; | 2209 if (leftCropFrame == -1) leftCropFrame = f; |
2210 else if (x < x0 - 2) { leftBoundaryFrame = f; break; } | 2210 else if (x < x0 - 2) { leftBoundaryFrame = f; break; } |
2211 } | 2211 } |
2212 } | 2212 } |
2213 for (int x = x0 + w; ; ++x) { | 2213 for (int x = x0 + w; ; ++x) { |
2214 int f = v->getFrameForX(x); | 2214 sv_frame_t f = v->getFrameForX(x); |
2215 if ((f / increment) * increment == f) { | 2215 if ((f / increment) * increment == f) { |
2216 if (rightCropFrame == -1) rightCropFrame = f; | 2216 if (rightCropFrame == -1) rightCropFrame = f; |
2217 else if (x > x0 + w + 2) { rightBoundaryFrame = f; break; } | 2217 else if (x > x0 + w + 2) { rightBoundaryFrame = f; break; } |
2218 } | 2218 } |
2219 } | 2219 } |
2220 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2220 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2221 cerr << "Left: crop: " << leftCropFrame << " (bin " << leftCropFrame/increment << "); boundary: " << leftBoundaryFrame << " (bin " << leftBoundaryFrame/increment << ")" << endl; | 2221 cerr << "Left: crop: " << leftCropFrame << " (bin " << leftCropFrame/increment << "); boundary: " << leftBoundaryFrame << " (bin " << leftBoundaryFrame/increment << ")" << endl; |
2222 cerr << "Right: crop: " << rightCropFrame << " (bin " << rightCropFrame/increment << "); boundary: " << rightBoundaryFrame << " (bin " << rightBoundaryFrame/increment << ")" << endl; | 2222 cerr << "Right: crop: " << rightCropFrame << " (bin " << rightCropFrame/increment << "); boundary: " << rightBoundaryFrame << " (bin " << rightBoundaryFrame/increment << ")" << endl; |
2223 #endif | 2223 #endif |
2224 | 2224 |
2225 bufwid = (rightBoundaryFrame - leftBoundaryFrame) / increment; | 2225 bufwid = int((rightBoundaryFrame - leftBoundaryFrame) / increment); |
2226 | 2226 |
2227 } else { | 2227 } else { |
2228 | 2228 |
2229 bufwid = w; | 2229 bufwid = w; |
2230 } | 2230 } |
2231 | 2231 |
2232 #ifdef __GNUC__ | 2232 vector<int> binforx(bufwid); |
2233 int binforx[bufwid]; | 2233 vector<double> binfory(h); |
2234 float binfory[h]; | 2234 |
2235 #else | |
2236 int *binforx = (int *)alloca(bufwid * sizeof(int)); | |
2237 float *binfory = (float *)alloca(h * sizeof(float)); | |
2238 #endif | |
2239 | |
2240 bool usePeaksCache = false; | 2235 bool usePeaksCache = false; |
2241 | 2236 |
2242 if (bufferBinResolution) { | 2237 if (bufferBinResolution) { |
2243 for (int x = 0; x < bufwid; ++x) { | 2238 for (int x = 0; x < bufwid; ++x) { |
2244 binforx[x] = (leftBoundaryFrame / increment) + x; | 2239 binforx[x] = int(leftBoundaryFrame / increment) + x; |
2245 // cerr << "binforx[" << x << "] = " << binforx[x] << endl; | 2240 // cerr << "binforx[" << x << "] = " << binforx[x] << endl; |
2246 } | 2241 } |
2247 m_drawBuffer = QImage(bufwid, h, QImage::Format_Indexed8); | 2242 m_drawBuffer = QImage(bufwid, h, QImage::Format_Indexed8); |
2248 } else { | 2243 } else { |
2249 for (int x = 0; x < bufwid; ++x) { | 2244 for (int x = 0; x < bufwid; ++x) { |
2250 float s0 = 0, s1 = 0; | 2245 double s0 = 0, s1 = 0; |
2251 if (getXBinRange(v, x + x0, s0, s1)) { | 2246 if (getXBinRange(v, x + x0, s0, s1)) { |
2252 binforx[x] = int(s0 + 0.0001); | 2247 binforx[x] = int(s0 + 0.0001); |
2253 } else { | 2248 } else { |
2254 binforx[x] = -1; //??? | 2249 binforx[x] = -1; //??? |
2255 } | 2250 } |
2261 if (m_colourScale == PhaseColourScale) usePeaksCache = false; | 2256 if (m_colourScale == PhaseColourScale) usePeaksCache = false; |
2262 } | 2257 } |
2263 | 2258 |
2264 // No longer exists in Qt5: m_drawBuffer.setNumColors(256); | 2259 // No longer exists in Qt5: m_drawBuffer.setNumColors(256); |
2265 for (int pixel = 0; pixel < 256; ++pixel) { | 2260 for (int pixel = 0; pixel < 256; ++pixel) { |
2266 m_drawBuffer.setColor(pixel, m_palette.getColour(pixel).rgb()); | 2261 m_drawBuffer.setColor((unsigned char)pixel, |
2262 m_palette.getColour((unsigned char)pixel).rgb()); | |
2267 } | 2263 } |
2268 | 2264 |
2269 m_drawBuffer.fill(0); | 2265 m_drawBuffer.fill(0); |
2270 | 2266 |
2271 if (m_binDisplay != PeakFrequencies) { | 2267 if (m_binDisplay != PeakFrequencies) { |
2272 | 2268 |
2273 for (int y = 0; y < h; ++y) { | 2269 for (int y = 0; y < h; ++y) { |
2274 float q0 = 0, q1 = 0; | 2270 double q0 = 0, q1 = 0; |
2275 if (!getSmoothedYBinRange(v, h-y-1, q0, q1)) { | 2271 if (!getSmoothedYBinRange(v, h-y-1, q0, q1)) { |
2276 binfory[y] = -1; | 2272 binfory[y] = -1; |
2277 } else { | 2273 } else { |
2278 binfory[y] = q0; | 2274 binfory[y] = q0; |
2279 // cerr << "binfory[" << y << "] = " << binfory[y] << endl; | 2275 // cerr << "binfory[" << y << "] = " << binfory[y] << endl; |
2455 | 2451 |
2456 bool | 2452 bool |
2457 SpectrogramLayer::paintDrawBufferPeakFrequencies(View *v, | 2453 SpectrogramLayer::paintDrawBufferPeakFrequencies(View *v, |
2458 int w, | 2454 int w, |
2459 int h, | 2455 int h, |
2460 int *binforx, | 2456 const vector<int> &binforx, |
2461 int minbin, | 2457 int minbin, |
2462 int maxbin, | 2458 int maxbin, |
2463 float displayMinFreq, | 2459 double displayMinFreq, |
2464 float displayMaxFreq, | 2460 double displayMaxFreq, |
2465 bool logarithmic, | 2461 bool logarithmic, |
2466 MagnitudeRange &overallMag, | 2462 MagnitudeRange &overallMag, |
2467 bool &overallMagChanged) const | 2463 bool &overallMagChanged) const |
2468 { | 2464 { |
2469 Profiler profiler("SpectrogramLayer::paintDrawBufferPeakFrequencies"); | 2465 Profiler profiler("SpectrogramLayer::paintDrawBufferPeakFrequencies"); |
2520 fft->getPhasesAt(sx, values, minbin, maxbin - minbin + 1); | 2516 fft->getPhasesAt(sx, values, minbin, maxbin - minbin + 1); |
2521 } else if (m_normalizeColumns) { | 2517 } else if (m_normalizeColumns) { |
2522 fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); | 2518 fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); |
2523 } else if (m_normalizeHybrid) { | 2519 } else if (m_normalizeHybrid) { |
2524 fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); | 2520 fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); |
2525 float max = fft->getMaximumMagnitudeAt(sx); | 2521 double max = fft->getMaximumMagnitudeAt(sx); |
2526 if (max > 0.f) { | 2522 if (max > 0.f) { |
2527 for (int i = minbin; i <= maxbin; ++i) { | 2523 for (int i = minbin; i <= maxbin; ++i) { |
2528 values[i - minbin] *= log10(max); | 2524 values[i - minbin] = float(values[i - minbin] * log10(max)); |
2529 } | 2525 } |
2530 } | 2526 } |
2531 } else { | 2527 } else { |
2532 fft->getMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); | 2528 fft->getMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); |
2533 } | 2529 } |
2536 | 2532 |
2537 for (FFTModel::PeakSet::const_iterator pi = peakfreqs.begin(); | 2533 for (FFTModel::PeakSet::const_iterator pi = peakfreqs.begin(); |
2538 pi != peakfreqs.end(); ++pi) { | 2534 pi != peakfreqs.end(); ++pi) { |
2539 | 2535 |
2540 int bin = pi->first; | 2536 int bin = pi->first; |
2541 int freq = pi->second; | 2537 double freq = pi->second; |
2542 | 2538 |
2543 if (bin < minbin) continue; | 2539 if (bin < minbin) continue; |
2544 if (bin > maxbin) break; | 2540 if (bin > maxbin) break; |
2545 | 2541 |
2546 float value = values[bin - minbin]; | 2542 double value = values[bin - minbin]; |
2547 | 2543 |
2548 if (m_colourScale != PhaseColourScale) { | 2544 if (m_colourScale != PhaseColourScale) { |
2549 if (!m_normalizeColumns && !m_normalizeHybrid) { | 2545 if (!m_normalizeColumns && !m_normalizeHybrid) { |
2550 value /= (m_fftSize/2.f); | 2546 value /= (m_fftSize/2.0); |
2551 } | 2547 } |
2552 mag.sample(value); | 2548 mag.sample(float(value)); |
2553 value *= m_gain; | 2549 value *= m_gain; |
2554 } | 2550 } |
2555 | 2551 |
2556 float y = v->getYForFrequency | 2552 double y = v->getYForFrequency |
2557 (freq, displayMinFreq, displayMaxFreq, logarithmic); | 2553 (freq, displayMinFreq, displayMaxFreq, logarithmic); |
2558 | 2554 |
2559 int iy = int(y + 0.5); | 2555 int iy = int(y + 0.5); |
2560 if (iy < 0 || iy >= h) continue; | 2556 if (iy < 0 || iy >= h) continue; |
2561 | 2557 |
2583 | 2579 |
2584 bool | 2580 bool |
2585 SpectrogramLayer::paintDrawBuffer(View *v, | 2581 SpectrogramLayer::paintDrawBuffer(View *v, |
2586 int w, | 2582 int w, |
2587 int h, | 2583 int h, |
2588 int *binforx, | 2584 const vector<int> &binforx, |
2589 float *binfory, | 2585 const vector<double> &binfory, |
2590 bool usePeaksCache, | 2586 bool usePeaksCache, |
2591 MagnitudeRange &overallMag, | 2587 MagnitudeRange &overallMag, |
2592 bool &overallMagChanged) const | 2588 bool &overallMagChanged) const |
2593 { | 2589 { |
2594 Profiler profiler("SpectrogramLayer::paintDrawBuffer"); | 2590 Profiler profiler("SpectrogramLayer::paintDrawBuffer"); |
2595 | 2591 |
2596 int minbin = int(binfory[0] + 0.0001); | 2592 int minbin = int(binfory[0] + 0.0001); |
2597 int maxbin = binfory[h-1]; | 2593 int maxbin = int(binfory[h-1]); |
2598 | 2594 |
2599 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2595 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2600 cerr << "minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; | 2596 cerr << "minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; |
2601 #endif | 2597 #endif |
2602 if (minbin < 0) minbin = 0; | 2598 if (minbin < 0) minbin = 0; |
2687 fft->getPhasesAt(sx, autoarray, minbin, maxbin - minbin + 1); | 2683 fft->getPhasesAt(sx, autoarray, minbin, maxbin - minbin + 1); |
2688 } else if (m_normalizeColumns) { | 2684 } else if (m_normalizeColumns) { |
2689 fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); | 2685 fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); |
2690 } else if (m_normalizeHybrid) { | 2686 } else if (m_normalizeHybrid) { |
2691 fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); | 2687 fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); |
2692 float max = fft->getMaximumMagnitudeAt(sx); | 2688 double max = fft->getMaximumMagnitudeAt(sx); |
2693 for (int i = minbin; i <= maxbin; ++i) { | 2689 for (int i = minbin; i <= maxbin; ++i) { |
2694 if (max > 0.f) { | 2690 if (max > 0.0) { |
2695 autoarray[i - minbin] *= log10(max); | 2691 autoarray[i - minbin] = float(autoarray[i - minbin] * log10(max)); |
2696 } | 2692 } |
2697 } | 2693 } |
2698 } else { | 2694 } else { |
2699 fft->getMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); | 2695 fft->getMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); |
2700 } | 2696 } |
2713 psx = sx; | 2709 psx = sx; |
2714 } | 2710 } |
2715 | 2711 |
2716 for (int y = 0; y < h; ++y) { | 2712 for (int y = 0; y < h; ++y) { |
2717 | 2713 |
2718 float sy0 = binfory[y]; | 2714 double sy0 = binfory[y]; |
2719 float sy1 = sy0 + 1; | 2715 double sy1 = sy0 + 1; |
2720 if (y+1 < h) sy1 = binfory[y+1]; | 2716 if (y+1 < h) sy1 = binfory[y+1]; |
2721 | 2717 |
2722 float value = 0.f; | 2718 double value = 0.0; |
2723 | 2719 |
2724 if (interpolate && fabsf(sy1 - sy0) < 1.f) { | 2720 if (interpolate && fabs(sy1 - sy0) < 1.0) { |
2725 | 2721 |
2726 float centre = (sy0 + sy1) / 2; | 2722 double centre = (sy0 + sy1) / 2; |
2727 float dist = (centre - 0.5) - lrintf(centre - 0.5); | 2723 double dist = (centre - 0.5) - rint(centre - 0.5); |
2728 int bin = int(centre); | 2724 int bin = int(centre); |
2729 int other = (dist < 0 ? (bin-1) : (bin+1)); | 2725 int other = (dist < 0 ? (bin-1) : (bin+1)); |
2730 if (bin < minbin) bin = minbin; | 2726 if (bin < minbin) bin = minbin; |
2731 if (bin > maxbin) bin = maxbin; | 2727 if (bin > maxbin) bin = maxbin; |
2732 if (other < minbin || other > maxbin) other = bin; | 2728 if (other < minbin || other > maxbin) other = bin; |
2733 float prop = 1.f - fabsf(dist); | 2729 double prop = 1.0 - fabs(dist); |
2734 | 2730 |
2735 float v0 = values[bin - minbin]; | 2731 double v0 = values[bin - minbin]; |
2736 float v1 = values[other - minbin]; | 2732 double v1 = values[other - minbin]; |
2737 if (m_binDisplay == PeakBins) { | 2733 if (m_binDisplay == PeakBins) { |
2738 if (bin == minbin || bin == maxbin || | 2734 if (bin == minbin || bin == maxbin || |
2739 v0 < values[bin-minbin-1] || | 2735 v0 < values[bin-minbin-1] || |
2740 v0 < values[bin-minbin+1]) v0 = 0.f; | 2736 v0 < values[bin-minbin+1]) v0 = 0.0; |
2741 if (other == minbin || other == maxbin || | 2737 if (other == minbin || other == maxbin || |
2742 v1 < values[other-minbin-1] || | 2738 v1 < values[other-minbin-1] || |
2743 v1 < values[other-minbin+1]) v1 = 0.f; | 2739 v1 < values[other-minbin+1]) v1 = 0.0; |
2744 } | 2740 } |
2745 if (v0 == 0.f && v1 == 0.f) continue; | 2741 if (v0 == 0.0 && v1 == 0.0) continue; |
2746 value = prop * v0 + (1.f - prop) * v1; | 2742 value = prop * v0 + (1.0 - prop) * v1; |
2747 | 2743 |
2748 if (m_colourScale != PhaseColourScale) { | 2744 if (m_colourScale != PhaseColourScale) { |
2749 if (!m_normalizeColumns) { | 2745 if (!m_normalizeColumns) { |
2750 value /= (m_fftSize/2.f); | 2746 value /= (m_fftSize/2.0); |
2751 } | 2747 } |
2752 mag.sample(value); | 2748 mag.sample(float(value)); |
2753 value *= m_gain; | 2749 value *= m_gain; |
2754 } | 2750 } |
2755 | 2751 |
2756 peaks[y] = value; | 2752 peaks[y] = float(value); |
2757 | 2753 |
2758 } else { | 2754 } else { |
2759 | 2755 |
2760 int by0 = int(sy0 + 0.0001); | 2756 int by0 = int(sy0 + 0.0001); |
2761 int by1 = int(sy1 + 0.0001); | 2757 int by1 = int(sy1 + 0.0001); |
2770 value < values[bin-minbin+1]) continue; | 2766 value < values[bin-minbin+1]) continue; |
2771 } | 2767 } |
2772 | 2768 |
2773 if (m_colourScale != PhaseColourScale) { | 2769 if (m_colourScale != PhaseColourScale) { |
2774 if (!m_normalizeColumns) { | 2770 if (!m_normalizeColumns) { |
2775 value /= (m_fftSize/2.f); | 2771 value /= (m_fftSize/2.0); |
2776 } | 2772 } |
2777 mag.sample(value); | 2773 mag.sample(float(value)); |
2778 value *= m_gain; | 2774 value *= m_gain; |
2779 } | 2775 } |
2780 | 2776 |
2781 if (value > peaks[y]) peaks[y] = value; //!!! not right for phase! | 2777 if (value > peaks[y]) { |
2778 peaks[y] = float(value); //!!! not right for phase! | |
2779 } | |
2782 } | 2780 } |
2783 } | 2781 } |
2784 } | 2782 } |
2785 | 2783 |
2786 if (mag.isSet()) { | 2784 if (mag.isSet()) { |
2798 } | 2796 } |
2799 } | 2797 } |
2800 | 2798 |
2801 for (int y = 0; y < h; ++y) { | 2799 for (int y = 0; y < h; ++y) { |
2802 | 2800 |
2803 float peak = peaks[y]; | 2801 double peak = peaks[y]; |
2804 | 2802 |
2805 if (m_colourScale != PhaseColourScale && | 2803 if (m_colourScale != PhaseColourScale && |
2806 (m_normalizeColumns || m_normalizeHybrid) && | 2804 (m_normalizeColumns || m_normalizeHybrid) && |
2807 columnMax > 0.f) { | 2805 columnMax > 0.f) { |
2808 peak /= columnMax; | 2806 peak /= columnMax; |
2831 } | 2829 } |
2832 | 2830 |
2833 // cerr << "SpectrogramLayer: illuminateLocalFeatures(" | 2831 // cerr << "SpectrogramLayer: illuminateLocalFeatures(" |
2834 // << localPos.x() << "," << localPos.y() << ")" << endl; | 2832 // << localPos.x() << "," << localPos.y() << ")" << endl; |
2835 | 2833 |
2836 float s0, s1; | 2834 double s0, s1; |
2837 float f0, f1; | 2835 double f0, f1; |
2838 | 2836 |
2839 if (getXBinRange(v, localPos.x(), s0, s1) && | 2837 if (getXBinRange(v, localPos.x(), s0, s1) && |
2840 getYBinSourceRange(v, localPos.y(), f0, f1)) { | 2838 getYBinSourceRange(v, localPos.y(), f0, f1)) { |
2841 | 2839 |
2842 int s0i = int(s0 + 0.001); | 2840 int s0i = int(s0 + 0.001); |
2857 | 2855 |
2858 paint.drawRect(x0, y1, x1 - x0 + 1, y0 - y1 + 1); | 2856 paint.drawRect(x0, y1, x1 - x0 + 1, y0 - y1 + 1); |
2859 } | 2857 } |
2860 } | 2858 } |
2861 | 2859 |
2862 float | 2860 double |
2863 SpectrogramLayer::getYForFrequency(const View *v, float frequency) const | 2861 SpectrogramLayer::getYForFrequency(const View *v, double frequency) const |
2864 { | 2862 { |
2865 return v->getYForFrequency(frequency, | 2863 return v->getYForFrequency(frequency, |
2866 getEffectiveMinFrequency(), | 2864 getEffectiveMinFrequency(), |
2867 getEffectiveMaxFrequency(), | 2865 getEffectiveMaxFrequency(), |
2868 m_frequencyScale == LogFrequencyScale); | 2866 m_frequencyScale == LogFrequencyScale); |
2869 } | 2867 } |
2870 | 2868 |
2871 float | 2869 double |
2872 SpectrogramLayer::getFrequencyForY(const View *v, int y) const | 2870 SpectrogramLayer::getFrequencyForY(const View *v, int y) const |
2873 { | 2871 { |
2874 return v->getFrequencyForY(y, | 2872 return v->getFrequencyForY(y, |
2875 getEffectiveMinFrequency(), | 2873 getEffectiveMinFrequency(), |
2876 getEffectiveMaxFrequency(), | 2874 getEffectiveMaxFrequency(), |
2896 if (m_fftModels.find(v) == m_fftModels.end()) return ""; | 2894 if (m_fftModels.find(v) == m_fftModels.end()) return ""; |
2897 return m_fftModels[v].first->getError(); | 2895 return m_fftModels[v].first->getError(); |
2898 } | 2896 } |
2899 | 2897 |
2900 bool | 2898 bool |
2901 SpectrogramLayer::getValueExtents(float &min, float &max, | 2899 SpectrogramLayer::getValueExtents(double &min, double &max, |
2902 bool &logarithmic, QString &unit) const | 2900 bool &logarithmic, QString &unit) const |
2903 { | 2901 { |
2904 if (!m_model) return false; | 2902 if (!m_model) return false; |
2905 | 2903 |
2906 int sr = m_model->getSampleRate(); | 2904 sv_samplerate_t sr = m_model->getSampleRate(); |
2907 min = float(sr) / m_fftSize; | 2905 min = double(sr) / m_fftSize; |
2908 max = float(sr) / 2; | 2906 max = double(sr) / 2; |
2909 | 2907 |
2910 logarithmic = (m_frequencyScale == LogFrequencyScale); | 2908 logarithmic = (m_frequencyScale == LogFrequencyScale); |
2911 unit = "Hz"; | 2909 unit = "Hz"; |
2912 return true; | 2910 return true; |
2913 } | 2911 } |
2914 | 2912 |
2915 bool | 2913 bool |
2916 SpectrogramLayer::getDisplayExtents(float &min, float &max) const | 2914 SpectrogramLayer::getDisplayExtents(double &min, double &max) const |
2917 { | 2915 { |
2918 min = getEffectiveMinFrequency(); | 2916 min = getEffectiveMinFrequency(); |
2919 max = getEffectiveMaxFrequency(); | 2917 max = getEffectiveMaxFrequency(); |
2920 | 2918 |
2921 // SVDEBUG << "SpectrogramLayer::getDisplayExtents: " << min << "->" << max << endl; | 2919 // SVDEBUG << "SpectrogramLayer::getDisplayExtents: " << min << "->" << max << endl; |
2922 return true; | 2920 return true; |
2923 } | 2921 } |
2924 | 2922 |
2925 bool | 2923 bool |
2926 SpectrogramLayer::setDisplayExtents(float min, float max) | 2924 SpectrogramLayer::setDisplayExtents(double min, double max) |
2927 { | 2925 { |
2928 if (!m_model) return false; | 2926 if (!m_model) return false; |
2929 | 2927 |
2930 // SVDEBUG << "SpectrogramLayer::setDisplayExtents: " << min << "->" << max << endl; | 2928 // SVDEBUG << "SpectrogramLayer::setDisplayExtents: " << min << "->" << max << endl; |
2931 | 2929 |
2932 if (min < 0) min = 0; | 2930 if (min < 0) min = 0; |
2933 if (max > m_model->getSampleRate()/2.f) max = m_model->getSampleRate()/2.f; | 2931 if (max > m_model->getSampleRate()/2.0) max = m_model->getSampleRate()/2.0; |
2934 | 2932 |
2935 int minf = lrintf(min); | 2933 int minf = int(lrint(min)); |
2936 int maxf = lrintf(max); | 2934 int maxf = int(lrint(max)); |
2937 | 2935 |
2938 if (m_minFrequency == minf && m_maxFrequency == maxf) return true; | 2936 if (m_minFrequency == minf && m_maxFrequency == maxf) return true; |
2939 | 2937 |
2940 invalidateImageCaches(); | 2938 invalidateImageCaches(); |
2941 invalidateMagnitudes(); | 2939 invalidateMagnitudes(); |
2954 return true; | 2952 return true; |
2955 } | 2953 } |
2956 | 2954 |
2957 bool | 2955 bool |
2958 SpectrogramLayer::getYScaleValue(const View *v, int y, | 2956 SpectrogramLayer::getYScaleValue(const View *v, int y, |
2959 float &value, QString &unit) const | 2957 double &value, QString &unit) const |
2960 { | 2958 { |
2961 value = getFrequencyForY(v, y); | 2959 value = getFrequencyForY(v, y); |
2962 unit = "Hz"; | 2960 unit = "Hz"; |
2963 return true; | 2961 return true; |
2964 } | 2962 } |
2965 | 2963 |
2966 bool | 2964 bool |
2967 SpectrogramLayer::snapToFeatureFrame(View *, int &frame, | 2965 SpectrogramLayer::snapToFeatureFrame(View *, |
2966 sv_frame_t &frame, | |
2968 int &resolution, | 2967 int &resolution, |
2969 SnapType snap) const | 2968 SnapType snap) const |
2970 { | 2969 { |
2971 resolution = getWindowIncrement(); | 2970 resolution = getWindowIncrement(); |
2972 int left = (frame / resolution) * resolution; | 2971 sv_frame_t left = (frame / resolution) * resolution; |
2973 int right = left + resolution; | 2972 sv_frame_t right = left + resolution; |
2974 | 2973 |
2975 switch (snap) { | 2974 switch (snap) { |
2976 case SnapLeft: frame = left; break; | 2975 case SnapLeft: frame = left; break; |
2977 case SnapRight: frame = right; break; | 2976 case SnapRight: frame = right; break; |
2978 case SnapNearest: | 2977 case SnapNearest: |
3060 paint.setPen(m_crosshairColour); | 3059 paint.setPen(m_crosshairColour); |
3061 | 3060 |
3062 paint.drawLine(0, cursorPos.y(), cursorPos.x() - 1, cursorPos.y()); | 3061 paint.drawLine(0, cursorPos.y(), cursorPos.x() - 1, cursorPos.y()); |
3063 paint.drawLine(cursorPos.x(), 0, cursorPos.x(), v->height()); | 3062 paint.drawLine(cursorPos.x(), 0, cursorPos.x(), v->height()); |
3064 | 3063 |
3065 float fundamental = getFrequencyForY(v, cursorPos.y()); | 3064 double fundamental = getFrequencyForY(v, cursorPos.y()); |
3066 | 3065 |
3067 v->drawVisibleText(paint, | 3066 v->drawVisibleText(paint, |
3068 sw + 2, | 3067 sw + 2, |
3069 cursorPos.y() - 2, | 3068 cursorPos.y() - 2, |
3070 QString("%1 Hz").arg(fundamental), | 3069 QString("%1 Hz").arg(fundamental), |
3077 cursorPos.y() + paint.fontMetrics().ascent() + 2, | 3076 cursorPos.y() + paint.fontMetrics().ascent() + 2, |
3078 pitchLabel, | 3077 pitchLabel, |
3079 View::OutlinedText); | 3078 View::OutlinedText); |
3080 } | 3079 } |
3081 | 3080 |
3082 int frame = v->getFrameForX(cursorPos.x()); | 3081 sv_frame_t frame = v->getFrameForX(cursorPos.x()); |
3083 RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate()); | 3082 RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate()); |
3084 QString rtLabel = QString("%1 s").arg(rt.toText(true).c_str()); | 3083 QString rtLabel = QString("%1 s").arg(rt.toText(true).c_str()); |
3085 QString frameLabel = QString("%1").arg(frame); | 3084 QString frameLabel = QString("%1").arg(frame); |
3086 v->drawVisibleText(paint, | 3085 v->drawVisibleText(paint, |
3087 cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2, | 3086 cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2, |
3096 | 3095 |
3097 int harmonic = 2; | 3096 int harmonic = 2; |
3098 | 3097 |
3099 while (harmonic < 100) { | 3098 while (harmonic < 100) { |
3100 | 3099 |
3101 float hy = lrintf(getYForFrequency(v, fundamental * harmonic)); | 3100 int hy = int(lrint(getYForFrequency(v, fundamental * harmonic))); |
3102 if (hy < 0 || hy > v->height()) break; | 3101 if (hy < 0 || hy > v->height()) break; |
3103 | 3102 |
3104 int len = 7; | 3103 int len = 7; |
3105 | 3104 |
3106 if (harmonic % 2 == 0) { | 3105 if (harmonic % 2 == 0) { |
3110 len = 10; | 3109 len = 10; |
3111 } | 3110 } |
3112 } | 3111 } |
3113 | 3112 |
3114 paint.drawLine(cursorPos.x() - len, | 3113 paint.drawLine(cursorPos.x() - len, |
3115 int(hy), | 3114 hy, |
3116 cursorPos.x(), | 3115 cursorPos.x(), |
3117 int(hy)); | 3116 hy); |
3118 | 3117 |
3119 ++harmonic; | 3118 ++harmonic; |
3120 } | 3119 } |
3121 | 3120 |
3122 paint.restore(); | 3121 paint.restore(); |
3128 int x = pos.x(); | 3127 int x = pos.x(); |
3129 int y = pos.y(); | 3128 int y = pos.y(); |
3130 | 3129 |
3131 if (!m_model || !m_model->isOK()) return ""; | 3130 if (!m_model || !m_model->isOK()) return ""; |
3132 | 3131 |
3133 float magMin = 0, magMax = 0; | 3132 double magMin = 0, magMax = 0; |
3134 float phaseMin = 0, phaseMax = 0; | 3133 double phaseMin = 0, phaseMax = 0; |
3135 float freqMin = 0, freqMax = 0; | 3134 double freqMin = 0, freqMax = 0; |
3136 float adjFreqMin = 0, adjFreqMax = 0; | 3135 double adjFreqMin = 0, adjFreqMax = 0; |
3137 QString pitchMin, pitchMax; | 3136 QString pitchMin, pitchMax; |
3138 RealTime rtMin, rtMax; | 3137 RealTime rtMin, rtMax; |
3139 | 3138 |
3140 bool haveValues = false; | 3139 bool haveValues = false; |
3141 | 3140 |
3203 .arg(adjPitchText) | 3202 .arg(adjPitchText) |
3204 .arg(Pitch::getPitchLabelForFrequency(freqMin)); | 3203 .arg(Pitch::getPitchLabelForFrequency(freqMin)); |
3205 } | 3204 } |
3206 | 3205 |
3207 if (haveValues) { | 3206 if (haveValues) { |
3208 float dbMin = AudioLevel::multiplier_to_dB(magMin); | 3207 double dbMin = AudioLevel::multiplier_to_dB(magMin); |
3209 float dbMax = AudioLevel::multiplier_to_dB(magMax); | 3208 double dbMax = AudioLevel::multiplier_to_dB(magMax); |
3210 QString dbMinString; | 3209 QString dbMinString; |
3211 QString dbMaxString; | 3210 QString dbMaxString; |
3212 if (dbMin == AudioLevel::DB_FLOOR) { | 3211 if (dbMin == AudioLevel::DB_FLOOR) { |
3213 dbMinString = tr("-Inf"); | 3212 dbMinString = tr("-Inf"); |
3214 } else { | 3213 } else { |
3215 dbMinString = QString("%1").arg(lrintf(dbMin)); | 3214 dbMinString = QString("%1").arg(lrint(dbMin)); |
3216 } | 3215 } |
3217 if (dbMax == AudioLevel::DB_FLOOR) { | 3216 if (dbMax == AudioLevel::DB_FLOOR) { |
3218 dbMaxString = tr("-Inf"); | 3217 dbMaxString = tr("-Inf"); |
3219 } else { | 3218 } else { |
3220 dbMaxString = QString("%1").arg(lrintf(dbMax)); | 3219 dbMaxString = QString("%1").arg(lrint(dbMax)); |
3221 } | 3220 } |
3222 if (lrintf(dbMin) != lrintf(dbMax)) { | 3221 if (lrint(dbMin) != lrint(dbMax)) { |
3223 text += tr("dB:\t%1 - %2").arg(dbMinString).arg(dbMaxString); | 3222 text += tr("dB:\t%1 - %2").arg(dbMinString).arg(dbMaxString); |
3224 } else { | 3223 } else { |
3225 text += tr("dB:\t%1").arg(dbMinString); | 3224 text += tr("dB:\t%1").arg(dbMinString); |
3226 } | 3225 } |
3227 if (phaseMin != phaseMax) { | 3226 if (phaseMin != phaseMax) { |
3280 | 3279 |
3281 int tickw = (m_frequencyScale == LogFrequencyScale ? 10 : 4); | 3280 int tickw = (m_frequencyScale == LogFrequencyScale ? 10 : 4); |
3282 int pkw = (m_frequencyScale == LogFrequencyScale ? 10 : 0); | 3281 int pkw = (m_frequencyScale == LogFrequencyScale ? 10 : 0); |
3283 | 3282 |
3284 int bins = m_fftSize / 2; | 3283 int bins = m_fftSize / 2; |
3285 int sr = m_model->getSampleRate(); | 3284 sv_samplerate_t sr = m_model->getSampleRate(); |
3286 | 3285 |
3287 if (m_maxFrequency > 0) { | 3286 if (m_maxFrequency > 0) { |
3288 bins = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); | 3287 bins = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); |
3289 if (bins > m_fftSize / 2) bins = m_fftSize / 2; | 3288 if (bins > m_fftSize / 2) bins = m_fftSize / 2; |
3290 } | 3289 } |
3306 int ch = h - textHeight * (topLines + 1) - 8; | 3305 int ch = h - textHeight * (topLines + 1) - 8; |
3307 // paint.drawRect(4, textHeight + 4, cw - 1, ch + 1); | 3306 // paint.drawRect(4, textHeight + 4, cw - 1, ch + 1); |
3308 paint.drawRect(4 + cw - cbw, textHeight * topLines + 4, cbw - 1, ch + 1); | 3307 paint.drawRect(4 + cw - cbw, textHeight * topLines + 4, cbw - 1, ch + 1); |
3309 | 3308 |
3310 QString top, bottom; | 3309 QString top, bottom; |
3311 float min = m_viewMags[v].getMin(); | 3310 double min = m_viewMags[v].getMin(); |
3312 float max = m_viewMags[v].getMax(); | 3311 double max = m_viewMags[v].getMax(); |
3313 | 3312 |
3314 float dBmin = AudioLevel::multiplier_to_dB(min); | 3313 double dBmin = AudioLevel::multiplier_to_dB(min); |
3315 float dBmax = AudioLevel::multiplier_to_dB(max); | 3314 double dBmax = AudioLevel::multiplier_to_dB(max); |
3316 | 3315 |
3317 if (dBmax < -60.f) dBmax = -60.f; | 3316 if (dBmax < -60.f) dBmax = -60.f; |
3318 else top = QString("%1").arg(lrintf(dBmax)); | 3317 else top = QString("%1").arg(lrint(dBmax)); |
3319 | 3318 |
3320 if (dBmin < dBmax - 60.f) dBmin = dBmax - 60.f; | 3319 if (dBmin < dBmax - 60.f) dBmin = dBmax - 60.f; |
3321 bottom = QString("%1").arg(lrintf(dBmin)); | 3320 bottom = QString("%1").arg(lrint(dBmin)); |
3322 | 3321 |
3323 //!!! & phase etc | 3322 //!!! & phase etc |
3324 | 3323 |
3325 if (m_colourScale != PhaseColourScale) { | 3324 if (m_colourScale != PhaseColourScale) { |
3326 paint.drawText((cw + 6 - paint.fontMetrics().width("dBFS")) / 2, | 3325 paint.drawText((cw + 6 - paint.fontMetrics().width("dBFS")) / 2, |
3340 int lasty = 0; | 3339 int lasty = 0; |
3341 int lastdb = 0; | 3340 int lastdb = 0; |
3342 | 3341 |
3343 for (int i = 0; i < ch; ++i) { | 3342 for (int i = 0; i < ch; ++i) { |
3344 | 3343 |
3345 float dBval = dBmin + (((dBmax - dBmin) * i) / (ch - 1)); | 3344 double dBval = dBmin + (((dBmax - dBmin) * i) / (ch - 1)); |
3346 int idb = int(dBval); | 3345 int idb = int(dBval); |
3347 | 3346 |
3348 float value = AudioLevel::dB_to_multiplier(dBval); | 3347 double value = AudioLevel::dB_to_multiplier(dBval); |
3349 int colour = getDisplayValue(v, value * m_gain); | 3348 int colour = getDisplayValue(v, value * m_gain); |
3350 | 3349 |
3351 paint.setPen(m_palette.getColour(colour)); | 3350 paint.setPen(m_palette.getColour((unsigned char)colour)); |
3352 | 3351 |
3353 int y = textHeight * topLines + 4 + ch - i; | 3352 int y = textHeight * topLines + 4 + ch - i; |
3354 | 3353 |
3355 paint.drawLine(5 + cw - cbw, y, cw + 2, y); | 3354 paint.drawLine(5 + cw - cbw, y, cw + 2, y); |
3356 | 3355 |
3380 | 3379 |
3381 int bin = -1; | 3380 int bin = -1; |
3382 | 3381 |
3383 for (int y = 0; y < v->height(); ++y) { | 3382 for (int y = 0; y < v->height(); ++y) { |
3384 | 3383 |
3385 float q0, q1; | 3384 double q0, q1; |
3386 if (!getYBinRange(v, v->height() - y, q0, q1)) continue; | 3385 if (!getYBinRange(v, v->height() - y, q0, q1)) continue; |
3387 | 3386 |
3388 int vy; | 3387 int vy; |
3389 | 3388 |
3390 if (int(q0) > bin) { | 3389 if (int(q0) > bin) { |
3392 bin = int(q0); | 3391 bin = int(q0); |
3393 } else { | 3392 } else { |
3394 continue; | 3393 continue; |
3395 } | 3394 } |
3396 | 3395 |
3397 int freq = (sr * bin) / m_fftSize; | 3396 int freq = int((sr * bin) / m_fftSize); |
3398 | 3397 |
3399 if (py >= 0 && (vy - py) < textHeight - 1) { | 3398 if (py >= 0 && (vy - py) < textHeight - 1) { |
3400 if (m_frequencyScale == LinearFrequencyScale) { | 3399 if (m_frequencyScale == LinearFrequencyScale) { |
3401 paint.drawLine(w - tickw, h - vy, w, h - vy); | 3400 paint.drawLine(w - tickw, h - vy, w, h - vy); |
3402 } | 3401 } |
3428 } | 3427 } |
3429 | 3428 |
3430 class SpectrogramRangeMapper : public RangeMapper | 3429 class SpectrogramRangeMapper : public RangeMapper |
3431 { | 3430 { |
3432 public: | 3431 public: |
3433 SpectrogramRangeMapper(int sr, int /* fftsize */) : | 3432 SpectrogramRangeMapper(sv_samplerate_t sr, int /* fftsize */) : |
3434 m_dist(float(sr) / 2), | 3433 m_dist(sr / 2), |
3435 m_s2(sqrtf(sqrtf(2))) { } | 3434 m_s2(sqrt(sqrt(2))) { } |
3436 ~SpectrogramRangeMapper() { } | 3435 ~SpectrogramRangeMapper() { } |
3437 | 3436 |
3438 virtual int getPositionForValue(float value) const { | 3437 virtual int getPositionForValue(double value) const { |
3439 | 3438 |
3440 float dist = m_dist; | 3439 double dist = m_dist; |
3441 | 3440 |
3442 int n = 0; | 3441 int n = 0; |
3443 | 3442 |
3444 while (dist > (value + 0.00001) && dist > 0.1f) { | 3443 while (dist > (value + 0.00001) && dist > 0.1) { |
3445 dist /= m_s2; | 3444 dist /= m_s2; |
3446 ++n; | 3445 ++n; |
3447 } | 3446 } |
3448 | 3447 |
3449 return n; | 3448 return n; |
3450 } | 3449 } |
3451 | 3450 |
3452 virtual int getPositionForValueUnclamped(float value) const { | 3451 virtual int getPositionForValueUnclamped(double value) const { |
3453 // We don't really support this | 3452 // We don't really support this |
3454 return getPositionForValue(value); | 3453 return getPositionForValue(value); |
3455 } | 3454 } |
3456 | 3455 |
3457 virtual float getValueForPosition(int position) const { | 3456 virtual double getValueForPosition(int position) const { |
3458 | 3457 |
3459 // Vertical zoom step 0 shows the entire range from DC -> | 3458 // Vertical zoom step 0 shows the entire range from DC -> |
3460 // Nyquist frequency. Step 1 shows 2^(1/4) of the range of | 3459 // Nyquist frequency. Step 1 shows 2^(1/4) of the range of |
3461 // step 0, and so on until the visible range is smaller than | 3460 // step 0, and so on until the visible range is smaller than |
3462 // the frequency step between bins at the current fft size. | 3461 // the frequency step between bins at the current fft size. |
3463 | 3462 |
3464 float dist = m_dist; | 3463 double dist = m_dist; |
3465 | 3464 |
3466 int n = 0; | 3465 int n = 0; |
3467 while (n < position) { | 3466 while (n < position) { |
3468 dist /= m_s2; | 3467 dist /= m_s2; |
3469 ++n; | 3468 ++n; |
3470 } | 3469 } |
3471 | 3470 |
3472 return dist; | 3471 return dist; |
3473 } | 3472 } |
3474 | 3473 |
3475 virtual float getValueForPositionUnclamped(int position) const { | 3474 virtual double getValueForPositionUnclamped(int position) const { |
3476 // We don't really support this | 3475 // We don't really support this |
3477 return getValueForPosition(position); | 3476 return getValueForPosition(position); |
3478 } | 3477 } |
3479 | 3478 |
3480 virtual QString getUnit() const { return "Hz"; } | 3479 virtual QString getUnit() const { return "Hz"; } |
3481 | 3480 |
3482 protected: | 3481 protected: |
3483 float m_dist; | 3482 double m_dist; |
3484 float m_s2; | 3483 double m_s2; |
3485 }; | 3484 }; |
3486 | 3485 |
3487 int | 3486 int |
3488 SpectrogramLayer::getVerticalZoomSteps(int &defaultStep) const | 3487 SpectrogramLayer::getVerticalZoomSteps(int &defaultStep) const |
3489 { | 3488 { |
3490 if (!m_model) return 0; | 3489 if (!m_model) return 0; |
3491 | 3490 |
3492 int sr = m_model->getSampleRate(); | 3491 sv_samplerate_t sr = m_model->getSampleRate(); |
3493 | 3492 |
3494 SpectrogramRangeMapper mapper(sr, m_fftSize); | 3493 SpectrogramRangeMapper mapper(sr, m_fftSize); |
3495 | 3494 |
3496 // int maxStep = mapper.getPositionForValue((float(sr) / m_fftSize) + 0.001); | 3495 // int maxStep = mapper.getPositionForValue((double(sr) / m_fftSize) + 0.001); |
3497 int maxStep = mapper.getPositionForValue(0); | 3496 int maxStep = mapper.getPositionForValue(0); |
3498 int minStep = mapper.getPositionForValue(float(sr) / 2); | 3497 int minStep = mapper.getPositionForValue(double(sr) / 2); |
3499 | 3498 |
3500 int initialMax = m_initialMaxFrequency; | 3499 int initialMax = m_initialMaxFrequency; |
3501 if (initialMax == 0) initialMax = sr / 2; | 3500 if (initialMax == 0) initialMax = int(sr / 2); |
3502 | 3501 |
3503 defaultStep = mapper.getPositionForValue(initialMax) - minStep; | 3502 defaultStep = mapper.getPositionForValue(initialMax) - minStep; |
3504 | 3503 |
3505 // SVDEBUG << "SpectrogramLayer::getVerticalZoomSteps: " << maxStep - minStep << " (" << maxStep <<"-" << minStep << "), default is " << defaultStep << " (from initial max freq " << initialMax << ")" << endl; | 3504 // SVDEBUG << "SpectrogramLayer::getVerticalZoomSteps: " << maxStep - minStep << " (" << maxStep <<"-" << minStep << "), default is " << defaultStep << " (from initial max freq " << initialMax << ")" << endl; |
3506 | 3505 |
3510 int | 3509 int |
3511 SpectrogramLayer::getCurrentVerticalZoomStep() const | 3510 SpectrogramLayer::getCurrentVerticalZoomStep() const |
3512 { | 3511 { |
3513 if (!m_model) return 0; | 3512 if (!m_model) return 0; |
3514 | 3513 |
3515 float dmin, dmax; | 3514 double dmin, dmax; |
3516 getDisplayExtents(dmin, dmax); | 3515 getDisplayExtents(dmin, dmax); |
3517 | 3516 |
3518 SpectrogramRangeMapper mapper(m_model->getSampleRate(), m_fftSize); | 3517 SpectrogramRangeMapper mapper(m_model->getSampleRate(), m_fftSize); |
3519 int n = mapper.getPositionForValue(dmax - dmin); | 3518 int n = mapper.getPositionForValue(dmax - dmin); |
3520 // SVDEBUG << "SpectrogramLayer::getCurrentVerticalZoomStep: " << n << endl; | 3519 // SVDEBUG << "SpectrogramLayer::getCurrentVerticalZoomStep: " << n << endl; |
3524 void | 3523 void |
3525 SpectrogramLayer::setVerticalZoomStep(int step) | 3524 SpectrogramLayer::setVerticalZoomStep(int step) |
3526 { | 3525 { |
3527 if (!m_model) return; | 3526 if (!m_model) return; |
3528 | 3527 |
3529 float dmin = m_minFrequency, dmax = m_maxFrequency; | 3528 double dmin = m_minFrequency, dmax = m_maxFrequency; |
3530 // getDisplayExtents(dmin, dmax); | 3529 // getDisplayExtents(dmin, dmax); |
3531 | 3530 |
3532 // cerr << "current range " << dmin << " -> " << dmax << ", range " << dmax-dmin << ", mid " << (dmax + dmin)/2 << endl; | 3531 // cerr << "current range " << dmin << " -> " << dmax << ", range " << dmax-dmin << ", mid " << (dmax + dmin)/2 << endl; |
3533 | 3532 |
3534 int sr = m_model->getSampleRate(); | 3533 sv_samplerate_t sr = m_model->getSampleRate(); |
3535 SpectrogramRangeMapper mapper(sr, m_fftSize); | 3534 SpectrogramRangeMapper mapper(sr, m_fftSize); |
3536 float newdist = mapper.getValueForPosition(step); | 3535 double newdist = mapper.getValueForPosition(step); |
3537 | 3536 |
3538 float newmin, newmax; | 3537 double newmin, newmax; |
3539 | 3538 |
3540 if (m_frequencyScale == LogFrequencyScale) { | 3539 if (m_frequencyScale == LogFrequencyScale) { |
3541 | 3540 |
3542 // need to pick newmin and newmax such that | 3541 // need to pick newmin and newmax such that |
3543 // | 3542 // |
3558 // so exp(2logmid) = exp(log(dmin) + log(dmax)) | 3557 // so exp(2logmid) = exp(log(dmin) + log(dmax)) |
3559 // = exp(log(dmin.dmax)) | 3558 // = exp(log(dmin.dmax)) |
3560 // = dmin.dmax | 3559 // = dmin.dmax |
3561 // so newmax = (newdist + sqrtf(newdist^2 + 4dmin.dmax)) / 2 | 3560 // so newmax = (newdist + sqrtf(newdist^2 + 4dmin.dmax)) / 2 |
3562 | 3561 |
3563 newmax = (newdist + sqrtf(newdist*newdist + 4*dmin*dmax)) / 2; | 3562 newmax = (newdist + sqrt(newdist*newdist + 4*dmin*dmax)) / 2; |
3564 newmin = newmax - newdist; | 3563 newmin = newmax - newdist; |
3565 | 3564 |
3566 // cerr << "newmin = " << newmin << ", newmax = " << newmax << endl; | 3565 // cerr << "newmin = " << newmin << ", newmax = " << newmax << endl; |
3567 | 3566 |
3568 } else { | 3567 } else { |
3569 float dmid = (dmax + dmin) / 2; | 3568 double dmid = (dmax + dmin) / 2; |
3570 newmin = dmid - newdist / 2; | 3569 newmin = dmid - newdist / 2; |
3571 newmax = dmid + newdist / 2; | 3570 newmax = dmid + newdist / 2; |
3572 } | 3571 } |
3573 | 3572 |
3574 float mmin, mmax; | 3573 double mmin, mmax; |
3575 mmin = 0; | 3574 mmin = 0; |
3576 mmax = float(sr) / 2; | 3575 mmax = double(sr) / 2; |
3577 | 3576 |
3578 if (newmin < mmin) { | 3577 if (newmin < mmin) { |
3579 newmax += (mmin - newmin); | 3578 newmax += (mmin - newmin); |
3580 newmin = mmin; | 3579 newmin = mmin; |
3581 } | 3580 } |
3583 newmax = mmax; | 3582 newmax = mmax; |
3584 } | 3583 } |
3585 | 3584 |
3586 // SVDEBUG << "SpectrogramLayer::setVerticalZoomStep: " << step << ": " << newmin << " -> " << newmax << " (range " << newdist << ")" << endl; | 3585 // SVDEBUG << "SpectrogramLayer::setVerticalZoomStep: " << step << ": " << newmin << " -> " << newmax << " (range " << newdist << ")" << endl; |
3587 | 3586 |
3588 setMinFrequency(lrintf(newmin)); | 3587 setMinFrequency(int(lrint(newmin))); |
3589 setMaxFrequency(lrintf(newmax)); | 3588 setMaxFrequency(int(lrint(newmax))); |
3590 } | 3589 } |
3591 | 3590 |
3592 RangeMapper * | 3591 RangeMapper * |
3593 SpectrogramLayer::getNewVerticalZoomRangeMapper() const | 3592 SpectrogramLayer::getNewVerticalZoomRangeMapper() const |
3594 { | 3593 { |
3598 | 3597 |
3599 void | 3598 void |
3600 SpectrogramLayer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const | 3599 SpectrogramLayer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const |
3601 { | 3600 { |
3602 int y0 = 0; | 3601 int y0 = 0; |
3603 if (r.startY > 0.0) y0 = getYForFrequency(v, r.startY); | 3602 if (r.startY > 0.0) y0 = int(getYForFrequency(v, r.startY)); |
3604 | 3603 |
3605 int y1 = y0; | 3604 int y1 = y0; |
3606 if (r.endY > 0.0) y1 = getYForFrequency(v, r.endY); | 3605 if (r.endY > 0.0) y1 = int(getYForFrequency(v, r.endY)); |
3607 | 3606 |
3608 // SVDEBUG << "SpectrogramLayer::updateMeasureRectYCoords: start " << r.startY << " -> " << y0 << ", end " << r.endY << " -> " << y1 << endl; | 3607 // SVDEBUG << "SpectrogramLayer::updateMeasureRectYCoords: start " << r.startY << " -> " << y0 << ", end " << r.endY << " -> " << y1 << endl; |
3609 | 3608 |
3610 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0); | 3609 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0); |
3611 } | 3610 } |