Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 104:1348818e7be7
* Switch from fftw3 to fftw3f. I think the efficiency improvement is probably
worth the lower precision, although I ought to do a few more tests.
author | Chris Cannam |
---|---|
date | Thu, 15 Jun 2006 12:28:47 +0000 |
parents | 8ce53683d0d7 |
children | bf196d6e8998 |
comparison
equal
deleted
inserted
replaced
103:5064eeb1c76f | 104:1348818e7be7 |
---|---|
41 double a = floor(x / y); | 41 double a = floor(x / y); |
42 double b = x - (y * a); | 42 double b = x - (y * a); |
43 return b; | 43 return b; |
44 } | 44 } |
45 | 45 |
46 static float modf(float x, float y) | |
47 { | |
48 float a = floorf(x / y); | |
49 float b = x - (y * a); | |
50 return b; | |
51 } | |
52 | |
46 static double princarg(double ang) | 53 static double princarg(double ang) |
47 { | 54 { |
48 return mod(ang + M_PI, -2 * M_PI) + M_PI; | 55 return mod(ang + M_PI, -2 * M_PI) + M_PI; |
56 } | |
57 | |
58 static float princargf(float ang) | |
59 { | |
60 return modf(ang + M_PI, -2 * M_PI) + M_PI; | |
49 } | 61 } |
50 | 62 |
51 | 63 |
52 SpectrogramLayer::SpectrogramLayer(Configuration config) : | 64 SpectrogramLayer::SpectrogramLayer(Configuration config) : |
53 Layer(), | 65 Layer(), |
1079 float frequency = (float(bin) * sampleRate) / windowSize; | 1091 float frequency = (float(bin) * sampleRate) / windowSize; |
1080 | 1092 |
1081 float expectedPhase = | 1093 float expectedPhase = |
1082 oldPhase + (2.0 * M_PI * bin * windowIncrement) / windowSize; | 1094 oldPhase + (2.0 * M_PI * bin * windowIncrement) / windowSize; |
1083 | 1095 |
1084 float phaseError = princarg(newPhase - expectedPhase); | 1096 float phaseError = princargf(newPhase - expectedPhase); |
1085 | 1097 |
1086 if (fabs(phaseError) < (1.1 * (windowIncrement * M_PI) / windowSize)) { | 1098 if (fabs(phaseError) < (1.1 * (windowIncrement * M_PI) / windowSize)) { |
1087 | 1099 |
1088 // The new frequency estimate based on the phase error | 1100 // The new frequency estimate based on the phase error |
1089 // resulting from assuming the "native" frequency of this bin | 1101 // resulting from assuming the "native" frequency of this bin |
1099 steadyState = false; | 1111 steadyState = false; |
1100 return frequency; | 1112 return frequency; |
1101 } | 1113 } |
1102 | 1114 |
1103 void | 1115 void |
1104 SpectrogramLayer::fillCacheColumn(int column, double *input, | 1116 SpectrogramLayer::fillCacheColumn(int column, fftsample *input, |
1105 fftw_complex *output, | 1117 fftwf_complex *output, |
1106 fftw_plan plan, | 1118 fftwf_plan plan, |
1107 size_t windowSize, | 1119 size_t windowSize, |
1108 size_t increment, | 1120 size_t increment, |
1109 float *workbuffer, | 1121 float *workbuffer, |
1110 const Window<double> &windower) const | 1122 const Window<fftsample> &windower) const |
1111 { | 1123 { |
1112 //!!! we _do_ need a lock for these references to the model | 1124 //!!! we _do_ need a lock for these references to the model |
1113 // though, don't we? | 1125 // though, don't we? |
1114 | 1126 |
1115 int startFrame = increment * column; | 1127 int startFrame = increment * column; |
1143 } | 1155 } |
1144 | 1156 |
1145 windower.cut(input); | 1157 windower.cut(input); |
1146 | 1158 |
1147 for (size_t i = 0; i < windowSize/2; ++i) { | 1159 for (size_t i = 0; i < windowSize/2; ++i) { |
1148 double temp = input[i]; | 1160 fftsample temp = input[i]; |
1149 input[i] = input[i + windowSize/2]; | 1161 input[i] = input[i + windowSize/2]; |
1150 input[i + windowSize/2] = temp; | 1162 input[i + windowSize/2] = temp; |
1151 } | 1163 } |
1152 | 1164 |
1153 fftw_execute(plan); | 1165 fftwf_execute(plan); |
1154 | 1166 |
1155 double factor = 0.0; | 1167 fftsample factor = 0.0; |
1156 | 1168 |
1157 for (size_t i = 0; i < windowSize/2; ++i) { | 1169 for (size_t i = 0; i < windowSize/2; ++i) { |
1158 | 1170 |
1159 double mag = sqrt(output[i][0] * output[i][0] + | 1171 fftsample mag = sqrtf(output[i][0] * output[i][0] + |
1160 output[i][1] * output[i][1]); | 1172 output[i][1] * output[i][1]); |
1161 mag /= windowSize / 2; | 1173 mag /= windowSize / 2; |
1162 | 1174 |
1163 if (mag > factor) factor = mag; | 1175 if (mag > factor) factor = mag; |
1164 | 1176 |
1165 double phase = atan2(output[i][1], output[i][0]); | 1177 fftsample phase = atan2f(output[i][1], output[i][0]); |
1166 phase = princarg(phase); | 1178 phase = princargf(phase); |
1167 | 1179 |
1168 workbuffer[i] = mag; | 1180 workbuffer[i] = mag; |
1169 workbuffer[i + windowSize/2] = phase; | 1181 workbuffer[i + windowSize/2] = phase; |
1170 } | 1182 } |
1171 | 1183 |
1326 MatrixFile::ReadOnly); | 1338 MatrixFile::ReadOnly); |
1327 | 1339 |
1328 m_layer.setColourmap(); | 1340 m_layer.setColourmap(); |
1329 //!!! m_layer.m_writeCache->reset(); | 1341 //!!! m_layer.m_writeCache->reset(); |
1330 | 1342 |
1331 double *input = (double *) | 1343 fftsample *input = (fftsample *) |
1332 fftw_malloc(windowSize * sizeof(double)); | 1344 fftwf_malloc(windowSize * sizeof(fftsample)); |
1333 | 1345 |
1334 fftw_complex *output = (fftw_complex *) | 1346 fftwf_complex *output = (fftwf_complex *) |
1335 fftw_malloc(windowSize * sizeof(fftw_complex)); | 1347 fftwf_malloc(windowSize * sizeof(fftwf_complex)); |
1336 | 1348 |
1337 float *workbuffer = (float *) | 1349 float *workbuffer = (float *) |
1338 fftw_malloc(windowSize * sizeof(float)); | 1350 fftwf_malloc(windowSize * sizeof(float)); |
1339 | 1351 |
1340 fftw_plan plan = fftw_plan_dft_r2c_1d(windowSize, input, | 1352 fftwf_plan plan = fftwf_plan_dft_r2c_1d(windowSize, input, |
1341 output, FFTW_ESTIMATE); | 1353 output, FFTW_ESTIMATE); |
1342 | 1354 |
1343 if (!plan) { | 1355 if (!plan) { |
1344 std::cerr << "WARNING: fftw_plan_dft_r2c_1d(" << windowSize << ") failed!" << std::endl; | 1356 std::cerr << "WARNING: fftwf_plan_dft_r2c_1d(" << windowSize << ") failed!" << std::endl; |
1345 fftw_free(input); | 1357 fftwf_free(input); |
1346 fftw_free(output); | 1358 fftwf_free(output); |
1347 fftw_free(workbuffer); | 1359 fftwf_free(workbuffer); |
1348 continue; | 1360 continue; |
1349 } | 1361 } |
1350 | 1362 |
1351 // We don't need a lock when writing to or reading from | 1363 // We don't need a lock when writing to or reading from |
1352 // the pixels in the cache. We do need to ensure we have | 1364 // the pixels in the cache. We do need to ensure we have |
1357 // happens, because they will continue to match the | 1369 // happens, because they will continue to match the |
1358 // dimensions of the actual cache (which this thread | 1370 // dimensions of the actual cache (which this thread |
1359 // manages, not the layer's). | 1371 // manages, not the layer's). |
1360 m_layer.m_mutex.unlock(); | 1372 m_layer.m_mutex.unlock(); |
1361 | 1373 |
1362 Window<double> windower(windowType, windowSize); | 1374 Window<fftsample> windower(windowType, windowSize); |
1363 | 1375 |
1364 int counter = 0; | 1376 int counter = 0; |
1365 int updateAt = (end / windowIncrement) / 20; | 1377 int updateAt = (end / windowIncrement) / 20; |
1366 if (updateAt < 100) updateAt = 100; | 1378 if (updateAt < 100) updateAt = 100; |
1367 | 1379 |
1422 counter = 0; | 1434 counter = 0; |
1423 } | 1435 } |
1424 } | 1436 } |
1425 } | 1437 } |
1426 | 1438 |
1427 fftw_destroy_plan(plan); | 1439 fftwf_destroy_plan(plan); |
1428 fftw_free(output); | 1440 fftwf_free(output); |
1429 fftw_free(input); | 1441 fftwf_free(input); |
1430 fftw_free(workbuffer); | 1442 fftwf_free(workbuffer); |
1431 | 1443 |
1432 if (!interrupted) { | 1444 if (!interrupted) { |
1433 m_fillExtent = end; | 1445 m_fillExtent = end; |
1434 m_fillCompletion = 100; | 1446 m_fillCompletion = 100; |
1435 } | 1447 } |