Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 107:bf196d6e8998
* Separate out window and FFT size variables. Not necessarily correct
for frequency estimation code.
author | Chris Cannam |
---|---|
date | Mon, 19 Jun 2006 16:14:16 +0000 |
parents | 1348818e7be7 |
children | 12340cb6e6cb |
comparison
equal
deleted
inserted
replaced
106:551d7ae05526 | 107:bf196d6e8998 |
---|---|
66 m_model(0), | 66 m_model(0), |
67 m_channel(0), | 67 m_channel(0), |
68 m_windowSize(1024), | 68 m_windowSize(1024), |
69 m_windowType(HanningWindow), | 69 m_windowType(HanningWindow), |
70 m_windowHopLevel(2), | 70 m_windowHopLevel(2), |
71 m_fftSize(1024), | |
71 m_gain(1.0), | 72 m_gain(1.0), |
72 m_threshold(0.0), | 73 m_threshold(0.0), |
73 m_colourRotation(0), | 74 m_colourRotation(0), |
74 m_minFrequency(0), | 75 m_minFrequency(0), |
75 m_maxFrequency(8000), | 76 m_maxFrequency(8000), |
582 m_mutex.lock(); | 583 m_mutex.lock(); |
583 m_cacheInvalid = true; | 584 m_cacheInvalid = true; |
584 invalidatePixmapCaches(); | 585 invalidatePixmapCaches(); |
585 | 586 |
586 m_windowSize = ws; | 587 m_windowSize = ws; |
588 m_fftSize = ws; | |
587 | 589 |
588 m_mutex.unlock(); | 590 m_mutex.unlock(); |
589 | 591 |
590 emit layerParametersChanged(); | 592 emit layerParametersChanged(); |
591 | 593 |
1111 steadyState = false; | 1113 steadyState = false; |
1112 return frequency; | 1114 return frequency; |
1113 } | 1115 } |
1114 | 1116 |
1115 void | 1117 void |
1116 SpectrogramLayer::fillCacheColumn(int column, fftsample *input, | 1118 SpectrogramLayer::fillCacheColumn(int column, |
1119 fftsample *input, | |
1117 fftwf_complex *output, | 1120 fftwf_complex *output, |
1118 fftwf_plan plan, | 1121 fftwf_plan plan, |
1119 size_t windowSize, | 1122 size_t windowSize, |
1123 size_t fftSize, | |
1120 size_t increment, | 1124 size_t increment, |
1121 float *workbuffer, | 1125 float *workbuffer, |
1122 const Window<fftsample> &windower) const | 1126 const Window<fftsample> &windower) const |
1123 { | 1127 { |
1124 //!!! we _do_ need a lock for these references to the model | 1128 //!!! we _do_ need a lock for these references to the model |
1129 | 1133 |
1130 startFrame -= int(windowSize - increment) / 2; | 1134 startFrame -= int(windowSize - increment) / 2; |
1131 endFrame -= int(windowSize - increment) / 2; | 1135 endFrame -= int(windowSize - increment) / 2; |
1132 size_t pfx = 0; | 1136 size_t pfx = 0; |
1133 | 1137 |
1138 size_t off = (m_fftSize - m_windowSize) / 2; | |
1139 | |
1140 for (size_t i = 0; i < off; ++i) { | |
1141 input[i] = 0.0; | |
1142 input[m_fftSize - i - 1] = 0.0; | |
1143 } | |
1144 | |
1134 if (startFrame < 0) { | 1145 if (startFrame < 0) { |
1135 pfx = size_t(-startFrame); | 1146 pfx = size_t(-startFrame); |
1136 for (size_t i = 0; i < pfx; ++i) { | 1147 for (size_t i = 0; i < pfx; ++i) { |
1137 input[i] = 0.0; | 1148 input[off + i] = 0.0; |
1138 } | 1149 } |
1139 } | 1150 } |
1140 | 1151 |
1141 size_t got = m_model->getValues(m_channel, startFrame + pfx, | 1152 size_t got = m_model->getValues(m_channel, startFrame + pfx, |
1142 endFrame, input + pfx); | 1153 endFrame, input + pfx); |
1143 while (got + pfx < windowSize) { | 1154 while (got + pfx < windowSize) { |
1144 input[got + pfx] = 0.0; | 1155 input[off + got + pfx] = 0.0; |
1145 ++got; | 1156 ++got; |
1146 } | 1157 } |
1147 | 1158 |
1148 if (m_channel == -1) { | 1159 if (m_channel == -1) { |
1149 int channels = m_model->getChannelCount(); | 1160 int channels = m_model->getChannelCount(); |
1150 if (channels > 1) { | 1161 if (channels > 1) { |
1151 for (size_t i = 0; i < windowSize; ++i) { | 1162 for (size_t i = 0; i < windowSize; ++i) { |
1152 input[i] /= channels; | 1163 input[off + i] /= channels; |
1153 } | 1164 } |
1154 } | 1165 } |
1155 } | 1166 } |
1156 | 1167 |
1157 windower.cut(input); | 1168 windower.cut(input); |
1158 | 1169 |
1159 for (size_t i = 0; i < windowSize/2; ++i) { | 1170 for (size_t i = 0; i < windowSize/2; ++i) { |
1160 fftsample temp = input[i]; | 1171 fftsample temp = input[off + i]; |
1161 input[i] = input[i + windowSize/2]; | 1172 input[off + i] = input[off + i + windowSize/2]; |
1162 input[i + windowSize/2] = temp; | 1173 input[off + i + windowSize/2] = temp; |
1163 } | 1174 } |
1164 | 1175 |
1165 fftwf_execute(plan); | 1176 fftwf_execute(plan); |
1166 | 1177 |
1167 fftsample factor = 0.0; | 1178 fftsample factor = 0.0; |
1168 | 1179 |
1169 for (size_t i = 0; i < windowSize/2; ++i) { | 1180 for (size_t i = 0; i < fftSize/2; ++i) { |
1170 | 1181 |
1171 fftsample mag = sqrtf(output[i][0] * output[i][0] + | 1182 fftsample mag = sqrtf(output[i][0] * output[i][0] + |
1172 output[i][1] * output[i][1]); | 1183 output[i][1] * output[i][1]); |
1173 mag /= windowSize / 2; | 1184 mag /= fftSize / 2; |
1174 | 1185 |
1175 if (mag > factor) factor = mag; | 1186 if (mag > factor) factor = mag; |
1176 | 1187 |
1177 fftsample phase = atan2f(output[i][1], output[i][0]); | 1188 fftsample phase = atan2f(output[i][1], output[i][0]); |
1178 phase = princargf(phase); | 1189 phase = princargf(phase); |
1179 | 1190 |
1180 workbuffer[i] = mag; | 1191 workbuffer[i] = mag; |
1181 workbuffer[i + windowSize/2] = phase; | 1192 workbuffer[i + fftSize/2] = phase; |
1182 } | 1193 } |
1183 | 1194 |
1184 m_writeCache->setColumnAt(column, workbuffer, | 1195 m_writeCache->setColumnAt(column, workbuffer, |
1185 workbuffer + windowSize/2, factor); | 1196 workbuffer + fftSize/2, factor); |
1186 } | 1197 } |
1187 | 1198 |
1188 unsigned char | 1199 unsigned char |
1189 SpectrogramLayer::getDisplayValue(float input) const | 1200 SpectrogramLayer::getDisplayValue(float input) const |
1190 { | 1201 { |
1312 // std::cerr << "start = " << start << ", end = " << end << std::endl; | 1323 // std::cerr << "start = " << start << ", end = " << end << std::endl; |
1313 | 1324 |
1314 WindowType windowType = m_layer.m_windowType; | 1325 WindowType windowType = m_layer.m_windowType; |
1315 size_t windowSize = m_layer.m_windowSize; | 1326 size_t windowSize = m_layer.m_windowSize; |
1316 size_t windowIncrement = m_layer.getWindowIncrement(); | 1327 size_t windowIncrement = m_layer.getWindowIncrement(); |
1328 size_t fftSize = m_layer.m_fftSize; | |
1317 | 1329 |
1318 // std::cerr << "\nWINDOW INCREMENT: " << windowIncrement << " (for hop level " << m_layer.m_windowHopLevel << ")\n" << std::endl; | 1330 // std::cerr << "\nWINDOW INCREMENT: " << windowIncrement << " (for hop level " << m_layer.m_windowHopLevel << ")\n" << std::endl; |
1319 | 1331 |
1320 size_t visibleStart = m_layer.m_candidateFillStartFrame; | 1332 size_t visibleStart = m_layer.m_candidateFillStartFrame; |
1321 visibleStart = (visibleStart / windowIncrement) * windowIncrement; | 1333 visibleStart = (visibleStart / windowIncrement) * windowIncrement; |
1322 | 1334 |
1323 size_t width = (end - start) / windowIncrement + 1; | 1335 size_t width = (end - start) / windowIncrement + 1; |
1324 size_t height = windowSize / 2; | 1336 size_t height = fftSize / 2; |
1325 | 1337 |
1326 //!!! if (!m_layer.m_cache) { | 1338 //!!! if (!m_layer.m_cache) { |
1327 // m_layer.m_cache = new FFTMemoryCache; | 1339 // m_layer.m_cache = new FFTMemoryCache; |
1328 // } | 1340 // } |
1329 if (!m_layer.m_writeCache) { | 1341 if (!m_layer.m_writeCache) { |
1339 | 1351 |
1340 m_layer.setColourmap(); | 1352 m_layer.setColourmap(); |
1341 //!!! m_layer.m_writeCache->reset(); | 1353 //!!! m_layer.m_writeCache->reset(); |
1342 | 1354 |
1343 fftsample *input = (fftsample *) | 1355 fftsample *input = (fftsample *) |
1344 fftwf_malloc(windowSize * sizeof(fftsample)); | 1356 fftwf_malloc(fftSize * sizeof(fftsample)); |
1345 | 1357 |
1346 fftwf_complex *output = (fftwf_complex *) | 1358 fftwf_complex *output = (fftwf_complex *) |
1347 fftwf_malloc(windowSize * sizeof(fftwf_complex)); | 1359 fftwf_malloc(fftSize * sizeof(fftwf_complex)); |
1348 | 1360 |
1349 float *workbuffer = (float *) | 1361 float *workbuffer = (float *) |
1350 fftwf_malloc(windowSize * sizeof(float)); | 1362 fftwf_malloc(fftSize * sizeof(float)); |
1351 | 1363 |
1352 fftwf_plan plan = fftwf_plan_dft_r2c_1d(windowSize, input, | 1364 fftwf_plan plan = fftwf_plan_dft_r2c_1d(fftSize, input, |
1353 output, FFTW_ESTIMATE); | 1365 output, FFTW_ESTIMATE); |
1354 | 1366 |
1355 if (!plan) { | 1367 if (!plan) { |
1356 std::cerr << "WARNING: fftwf_plan_dft_r2c_1d(" << windowSize << ") failed!" << std::endl; | 1368 std::cerr << "WARNING: fftwf_plan_dft_r2c_1d(" << windowSize << ") failed!" << std::endl; |
1357 fftwf_free(input); | 1369 fftwf_free(input); |
1383 | 1395 |
1384 for (size_t f = visibleStart; f < end; f += windowIncrement) { | 1396 for (size_t f = visibleStart; f < end; f += windowIncrement) { |
1385 | 1397 |
1386 m_layer.fillCacheColumn(int((f - start) / windowIncrement), | 1398 m_layer.fillCacheColumn(int((f - start) / windowIncrement), |
1387 input, output, plan, | 1399 input, output, plan, |
1388 windowSize, windowIncrement, | 1400 windowSize, fftSize, |
1401 windowIncrement, | |
1389 workbuffer, windower); | 1402 workbuffer, windower); |
1390 | 1403 |
1391 if (m_layer.m_cacheInvalid || m_layer.m_exiting) { | 1404 if (m_layer.m_cacheInvalid || m_layer.m_exiting) { |
1392 interrupted = true; | 1405 interrupted = true; |
1393 m_fillExtent = 0; | 1406 m_fillExtent = 0; |
1415 | 1428 |
1416 for (size_t f = start; f < remainingEnd; f += windowIncrement) { | 1429 for (size_t f = start; f < remainingEnd; f += windowIncrement) { |
1417 | 1430 |
1418 m_layer.fillCacheColumn(int((f - start) / windowIncrement), | 1431 m_layer.fillCacheColumn(int((f - start) / windowIncrement), |
1419 input, output, plan, | 1432 input, output, plan, |
1420 windowSize, windowIncrement, | 1433 windowSize, fftSize, |
1434 windowIncrement, | |
1421 workbuffer, windower); | 1435 workbuffer, windower); |
1422 | 1436 |
1423 if (m_layer.m_cacheInvalid || m_layer.m_exiting) { | 1437 if (m_layer.m_cacheInvalid || m_layer.m_exiting) { |
1424 interrupted = true; | 1438 interrupted = true; |
1425 m_fillExtent = 0; | 1439 m_fillExtent = 0; |
1455 | 1469 |
1456 float | 1470 float |
1457 SpectrogramLayer::getEffectiveMinFrequency() const | 1471 SpectrogramLayer::getEffectiveMinFrequency() const |
1458 { | 1472 { |
1459 int sr = m_model->getSampleRate(); | 1473 int sr = m_model->getSampleRate(); |
1460 float minf = float(sr) / m_windowSize; | 1474 float minf = float(sr) / m_fftSize; |
1461 | 1475 |
1462 if (m_minFrequency > 0.0) { | 1476 if (m_minFrequency > 0.0) { |
1463 size_t minbin = size_t((double(m_minFrequency) * m_windowSize) / sr + 0.01); | 1477 size_t minbin = size_t((double(m_minFrequency) * m_fftSize) / sr + 0.01); |
1464 if (minbin < 1) minbin = 1; | 1478 if (minbin < 1) minbin = 1; |
1465 minf = minbin * sr / m_windowSize; | 1479 minf = minbin * sr / m_fftSize; |
1466 } | 1480 } |
1467 | 1481 |
1468 return minf; | 1482 return minf; |
1469 } | 1483 } |
1470 | 1484 |
1473 { | 1487 { |
1474 int sr = m_model->getSampleRate(); | 1488 int sr = m_model->getSampleRate(); |
1475 float maxf = float(sr) / 2; | 1489 float maxf = float(sr) / 2; |
1476 | 1490 |
1477 if (m_maxFrequency > 0.0) { | 1491 if (m_maxFrequency > 0.0) { |
1478 size_t maxbin = size_t((double(m_maxFrequency) * m_windowSize) / sr + 0.1); | 1492 size_t maxbin = size_t((double(m_maxFrequency) * m_fftSize) / sr + 0.1); |
1479 if (maxbin > m_windowSize / 2) maxbin = m_windowSize / 2; | 1493 if (maxbin > m_fftSize / 2) maxbin = m_fftSize / 2; |
1480 maxf = maxbin * sr / m_windowSize; | 1494 maxf = maxbin * sr / m_fftSize; |
1481 } | 1495 } |
1482 | 1496 |
1483 return maxf; | 1497 return maxf; |
1484 } | 1498 } |
1485 | 1499 |
1498 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); | 1512 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); |
1499 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); | 1513 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); |
1500 | 1514 |
1501 // Now map these on to actual bins | 1515 // Now map these on to actual bins |
1502 | 1516 |
1503 int b0 = int((q0 * m_windowSize) / sr); | 1517 int b0 = int((q0 * m_fftSize) / sr); |
1504 int b1 = int((q1 * m_windowSize) / sr); | 1518 int b1 = int((q1 * m_fftSize) / sr); |
1505 | 1519 |
1506 //!!! this is supposed to return fractions-of-bins, as it were, hence the floats | 1520 //!!! this is supposed to return fractions-of-bins, as it were, hence the floats |
1507 q0 = b0; | 1521 q0 = b0; |
1508 q1 = b1; | 1522 q1 = b1; |
1509 | 1523 |
1510 // q0 = (b0 * sr) / m_windowSize; | 1524 // q0 = (b0 * sr) / m_fftSize; |
1511 // q1 = (b1 * sr) / m_windowSize; | 1525 // q1 = (b1 * sr) / m_fftSize; |
1512 | 1526 |
1513 return true; | 1527 return true; |
1514 } | 1528 } |
1515 | 1529 |
1516 bool | 1530 bool |
1567 int q1i = int(q1); | 1581 int q1i = int(q1); |
1568 | 1582 |
1569 int sr = m_model->getSampleRate(); | 1583 int sr = m_model->getSampleRate(); |
1570 | 1584 |
1571 for (int q = q0i; q <= q1i; ++q) { | 1585 for (int q = q0i; q <= q1i; ++q) { |
1572 int binfreq = (sr * q) / m_windowSize; | 1586 int binfreq = (sr * q) / m_fftSize; |
1573 if (q == q0i) freqMin = binfreq; | 1587 if (q == q0i) freqMin = binfreq; |
1574 if (q == q1i) freqMax = binfreq; | 1588 if (q == q1i) freqMax = binfreq; |
1575 } | 1589 } |
1576 return true; | 1590 return true; |
1577 } | 1591 } |
1965 | 1979 |
1966 m_drawBuffer.fill(m_colourMap.getColour(0).rgb()); | 1980 m_drawBuffer.fill(m_colourMap.getColour(0).rgb()); |
1967 | 1981 |
1968 int sr = m_model->getSampleRate(); | 1982 int sr = m_model->getSampleRate(); |
1969 | 1983 |
1970 size_t bins = m_windowSize / 2; | 1984 size_t bins = m_fftSize / 2; |
1971 if (m_maxFrequency > 0) { | 1985 if (m_maxFrequency > 0) { |
1972 bins = int((double(m_maxFrequency) * m_windowSize) / sr + 0.1); | 1986 bins = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); |
1973 if (bins > m_windowSize / 2) bins = m_windowSize / 2; | 1987 if (bins > m_fftSize / 2) bins = m_fftSize / 2; |
1974 } | 1988 } |
1975 | 1989 |
1976 size_t minbin = 1; | 1990 size_t minbin = 1; |
1977 if (m_minFrequency > 0) { | 1991 if (m_minFrequency > 0) { |
1978 minbin = int((double(m_minFrequency) * m_windowSize) / sr + 0.1); | 1992 minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.1); |
1979 if (minbin < 1) minbin = 1; | 1993 if (minbin < 1) minbin = 1; |
1980 if (minbin >= bins) minbin = bins - 1; | 1994 if (minbin >= bins) minbin = bins - 1; |
1981 } | 1995 } |
1982 | 1996 |
1983 float minFreq = (float(minbin) * sr) / m_windowSize; | 1997 float minFreq = (float(minbin) * sr) / m_fftSize; |
1984 float maxFreq = (float(bins) * sr) / m_windowSize; | 1998 float maxFreq = (float(bins) * sr) / m_fftSize; |
1985 | 1999 |
1986 float ymag[h]; | 2000 float ymag[h]; |
1987 float ydiv[h]; | 2001 float ydiv[h]; |
1988 float yval[bins + 1]; | 2002 float yval[bins + 1]; |
1989 | 2003 |
1992 bool logarithmic = (m_frequencyScale == LogFrequencyScale); | 2006 bool logarithmic = (m_frequencyScale == LogFrequencyScale); |
1993 | 2007 |
1994 m_mutex.unlock(); | 2008 m_mutex.unlock(); |
1995 | 2009 |
1996 for (size_t q = minbin; q <= bins; ++q) { | 2010 for (size_t q = minbin; q <= bins; ++q) { |
1997 float f0 = (float(q) * sr) / m_windowSize; | 2011 float f0 = (float(q) * sr) / m_fftSize; |
1998 yval[q] = v->getYForFrequency(f0, minFreq, maxFreq, logarithmic); | 2012 yval[q] = v->getYForFrequency(f0, minFreq, maxFreq, logarithmic); |
1999 } | 2013 } |
2000 | 2014 |
2001 m_mutex.lock(); | 2015 m_mutex.lock(); |
2002 | 2016 |
2446 int h = rect.height(), w = rect.width(); | 2460 int h = rect.height(), w = rect.width(); |
2447 | 2461 |
2448 int tickw = (m_frequencyScale == LogFrequencyScale ? 10 : 4); | 2462 int tickw = (m_frequencyScale == LogFrequencyScale ? 10 : 4); |
2449 int pkw = (m_frequencyScale == LogFrequencyScale ? 10 : 0); | 2463 int pkw = (m_frequencyScale == LogFrequencyScale ? 10 : 0); |
2450 | 2464 |
2451 size_t bins = m_windowSize / 2; | 2465 size_t bins = m_fftSize / 2; |
2452 int sr = m_model->getSampleRate(); | 2466 int sr = m_model->getSampleRate(); |
2453 | 2467 |
2454 if (m_maxFrequency > 0) { | 2468 if (m_maxFrequency > 0) { |
2455 bins = int((double(m_maxFrequency) * m_windowSize) / sr + 0.1); | 2469 bins = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); |
2456 if (bins > m_windowSize / 2) bins = m_windowSize / 2; | 2470 if (bins > m_fftSize / 2) bins = m_fftSize / 2; |
2457 } | 2471 } |
2458 | 2472 |
2459 int cw = getColourScaleWidth(paint); | 2473 int cw = getColourScaleWidth(paint); |
2460 | 2474 |
2461 int py = -1; | 2475 int py = -1; |
2528 bin = int(q0); | 2542 bin = int(q0); |
2529 } else { | 2543 } else { |
2530 continue; | 2544 continue; |
2531 } | 2545 } |
2532 | 2546 |
2533 int freq = (sr * bin) / m_windowSize; | 2547 int freq = (sr * bin) / m_fftSize; |
2534 | 2548 |
2535 if (py >= 0 && (vy - py) < textHeight - 1) { | 2549 if (py >= 0 && (vy - py) < textHeight - 1) { |
2536 if (m_frequencyScale == LinearFrequencyScale) { | 2550 if (m_frequencyScale == LinearFrequencyScale) { |
2537 paint.drawLine(w - tickw, h - vy, w, h - vy); | 2551 paint.drawLine(w - tickw, h - vy, w, h - vy); |
2538 } | 2552 } |