annotate data/fft/FFTMemoryCache.cpp @ 458:f60360209e5c

* Fix race condition in FFTFileCache when reading from the same FFT model from multiple threads (e.g. when applying more than one plugin at once)
author Chris Cannam
date Wed, 15 Oct 2008 12:08:02 +0000
parents 115f60df1e4d
children 3cc4b7cd2aa5
rev   line source
Chris@159 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@159 2
Chris@159 3 /*
Chris@159 4 Sonic Visualiser
Chris@159 5 An audio file viewer and annotation editor.
Chris@159 6 Centre for Digital Music, Queen Mary, University of London.
Chris@159 7 This file copyright 2006 Chris Cannam.
Chris@159 8
Chris@159 9 This program is free software; you can redistribute it and/or
Chris@159 10 modify it under the terms of the GNU General Public License as
Chris@159 11 published by the Free Software Foundation; either version 2 of the
Chris@159 12 License, or (at your option) any later version. See the file
Chris@159 13 COPYING included with this distribution for more information.
Chris@159 14 */
Chris@159 15
Chris@159 16 #include "FFTMemoryCache.h"
Chris@159 17 #include "system/System.h"
Chris@159 18
Chris@159 19 #include <iostream>
Chris@159 20
Chris@374 21 //#define DEBUG_FFT_MEMORY_CACHE 1
Chris@374 22
Chris@264 23 FFTMemoryCache::FFTMemoryCache(StorageType storageType) :
Chris@159 24 m_width(0),
Chris@159 25 m_height(0),
Chris@159 26 m_magnitude(0),
Chris@159 27 m_phase(0),
Chris@264 28 m_fmagnitude(0),
Chris@264 29 m_fphase(0),
Chris@334 30 m_freal(0),
Chris@334 31 m_fimag(0),
Chris@264 32 m_factor(0),
Chris@264 33 m_storageType(storageType)
Chris@159 34 {
Chris@374 35 #ifdef DEBUG_FFT_MEMORY_CACHE
Chris@264 36 std::cerr << "FFTMemoryCache[" << this << "]::FFTMemoryCache (type "
Chris@264 37 << m_storageType << ")" << std::endl;
Chris@374 38 #endif
Chris@159 39 }
Chris@159 40
Chris@159 41 FFTMemoryCache::~FFTMemoryCache()
Chris@159 42 {
Chris@374 43 #ifdef DEBUG_FFT_MEMORY_CACHE
Chris@374 44 std::cerr << "FFTMemoryCache[" << this << "]::~FFTMemoryCache" << std::endl;
Chris@374 45 #endif
Chris@159 46
Chris@159 47 for (size_t i = 0; i < m_width; ++i) {
Chris@159 48 if (m_magnitude && m_magnitude[i]) free(m_magnitude[i]);
Chris@159 49 if (m_phase && m_phase[i]) free(m_phase[i]);
Chris@264 50 if (m_fmagnitude && m_fmagnitude[i]) free(m_fmagnitude[i]);
Chris@264 51 if (m_fphase && m_fphase[i]) free(m_fphase[i]);
Chris@334 52 if (m_freal && m_freal[i]) free(m_freal[i]);
Chris@334 53 if (m_fimag && m_fimag[i]) free(m_fimag[i]);
Chris@159 54 }
Chris@159 55
Chris@159 56 if (m_magnitude) free(m_magnitude);
Chris@159 57 if (m_phase) free(m_phase);
Chris@264 58 if (m_fmagnitude) free(m_fmagnitude);
Chris@264 59 if (m_fphase) free(m_fphase);
Chris@334 60 if (m_freal) free(m_freal);
Chris@334 61 if (m_fimag) free(m_fimag);
Chris@159 62 if (m_factor) free(m_factor);
Chris@159 63 }
Chris@159 64
Chris@159 65 void
Chris@159 66 FFTMemoryCache::resize(size_t width, size_t height)
Chris@159 67 {
Chris@408 68 Profiler profiler("FFTMemoryCache::resize");
Chris@408 69
Chris@374 70 #ifdef DEBUG_FFT_MEMORY_CACHE
Chris@359 71 std::cerr << "FFTMemoryCache[" << this << "]::resize(" << width << "x" << height << " = " << width*height << ")" << std::endl;
Chris@374 72 #endif
Chris@159 73
Chris@159 74 if (m_width == width && m_height == height) return;
Chris@159 75
Chris@264 76 if (m_storageType == Compact) {
Chris@264 77 resize(m_magnitude, width, height);
Chris@264 78 resize(m_phase, width, height);
Chris@334 79 } else if (m_storageType == Polar) {
Chris@264 80 resize(m_fmagnitude, width, height);
Chris@264 81 resize(m_fphase, width, height);
Chris@334 82 } else {
Chris@334 83 resize(m_freal, width, height);
Chris@334 84 resize(m_fimag, width, height);
Chris@264 85 }
Chris@264 86
Chris@159 87 m_colset.resize(width);
Chris@159 88
Chris@159 89 m_factor = (float *)realloc(m_factor, width * sizeof(float));
Chris@159 90
Chris@159 91 m_width = width;
Chris@159 92 m_height = height;
Chris@159 93
Chris@374 94 #ifdef DEBUG_FFT_MEMORY_CACHE
Chris@374 95 std::cerr << "done, width = " << m_width << " height = " << m_height << std::endl;
Chris@374 96 #endif
Chris@159 97 }
Chris@159 98
Chris@159 99 void
Chris@159 100 FFTMemoryCache::resize(uint16_t **&array, size_t width, size_t height)
Chris@159 101 {
Chris@159 102 for (size_t i = width; i < m_width; ++i) {
Chris@159 103 free(array[i]);
Chris@159 104 }
Chris@159 105
Chris@159 106 if (width != m_width) {
Chris@159 107 array = (uint16_t **)realloc(array, width * sizeof(uint16_t *));
Chris@159 108 if (!array) throw std::bad_alloc();
Chris@159 109 MUNLOCK(array, width * sizeof(uint16_t *));
Chris@159 110 }
Chris@159 111
Chris@159 112 for (size_t i = m_width; i < width; ++i) {
Chris@159 113 array[i] = 0;
Chris@159 114 }
Chris@159 115
Chris@159 116 for (size_t i = 0; i < width; ++i) {
Chris@159 117 array[i] = (uint16_t *)realloc(array[i], height * sizeof(uint16_t));
Chris@159 118 if (!array[i]) throw std::bad_alloc();
Chris@159 119 MUNLOCK(array[i], height * sizeof(uint16_t));
Chris@159 120 }
Chris@159 121 }
Chris@159 122
Chris@159 123 void
Chris@264 124 FFTMemoryCache::resize(float **&array, size_t width, size_t height)
Chris@264 125 {
Chris@264 126 for (size_t i = width; i < m_width; ++i) {
Chris@264 127 free(array[i]);
Chris@264 128 }
Chris@264 129
Chris@264 130 if (width != m_width) {
Chris@264 131 array = (float **)realloc(array, width * sizeof(float *));
Chris@264 132 if (!array) throw std::bad_alloc();
Chris@264 133 MUNLOCK(array, width * sizeof(float *));
Chris@264 134 }
Chris@264 135
Chris@264 136 for (size_t i = m_width; i < width; ++i) {
Chris@264 137 array[i] = 0;
Chris@264 138 }
Chris@264 139
Chris@264 140 for (size_t i = 0; i < width; ++i) {
Chris@264 141 array[i] = (float *)realloc(array[i], height * sizeof(float));
Chris@264 142 if (!array[i]) throw std::bad_alloc();
Chris@264 143 MUNLOCK(array[i], height * sizeof(float));
Chris@264 144 }
Chris@264 145 }
Chris@264 146
Chris@264 147 void
Chris@159 148 FFTMemoryCache::reset()
Chris@159 149 {
Chris@264 150 switch (m_storageType) {
Chris@264 151
Chris@264 152 case Compact:
Chris@264 153 for (size_t x = 0; x < m_width; ++x) {
Chris@264 154 for (size_t y = 0; y < m_height; ++y) {
Chris@264 155 m_magnitude[x][y] = 0;
Chris@264 156 m_phase[x][y] = 0;
Chris@264 157 }
Chris@264 158 m_factor[x] = 1.0;
Chris@264 159 }
Chris@264 160 break;
Chris@264 161
Chris@264 162 case Polar:
Chris@264 163 for (size_t x = 0; x < m_width; ++x) {
Chris@264 164 for (size_t y = 0; y < m_height; ++y) {
Chris@264 165 m_fmagnitude[x][y] = 0;
Chris@264 166 m_fphase[x][y] = 0;
Chris@264 167 }
Chris@264 168 m_factor[x] = 1.0;
Chris@264 169 }
Chris@264 170 break;
Chris@334 171
Chris@334 172 case Rectangular:
Chris@334 173 for (size_t x = 0; x < m_width; ++x) {
Chris@334 174 for (size_t y = 0; y < m_height; ++y) {
Chris@334 175 m_freal[x][y] = 0;
Chris@334 176 m_fimag[x][y] = 0;
Chris@334 177 }
Chris@334 178 m_factor[x] = 1.0;
Chris@334 179 }
Chris@334 180 break;
Chris@159 181 }
Chris@159 182 }
Chris@159 183
Chris@159 184 void
Chris@334 185 FFTMemoryCache::setColumnAt(size_t x, float *mags, float *phases, float factor)
Chris@334 186 {
Chris@408 187 Profiler profiler("FFTMemoryCache::setColumnAt: from polar");
Chris@408 188
Chris@334 189 setNormalizationFactor(x, factor);
Chris@334 190
Chris@334 191 if (m_storageType == Rectangular) {
Chris@408 192 Profiler subprof("FFTMemoryCache::setColumnAt: polar to cart");
Chris@334 193 for (size_t y = 0; y < m_height; ++y) {
Chris@334 194 m_freal[x][y] = mags[y] * cosf(phases[y]);
Chris@334 195 m_fimag[x][y] = mags[y] * sinf(phases[y]);
Chris@334 196 }
Chris@334 197 } else {
Chris@334 198 for (size_t y = 0; y < m_height; ++y) {
Chris@334 199 setMagnitudeAt(x, y, mags[y]);
Chris@334 200 setPhaseAt(x, y, phases[y]);
Chris@334 201 }
Chris@334 202 }
Chris@334 203
Chris@334 204 m_colset.set(x);
Chris@334 205 }
Chris@334 206
Chris@334 207 void
Chris@159 208 FFTMemoryCache::setColumnAt(size_t x, float *reals, float *imags)
Chris@159 209 {
Chris@408 210 Profiler profiler("FFTMemoryCache::setColumnAt: from cart");
Chris@408 211
Chris@159 212 float max = 0.0;
Chris@159 213
Chris@264 214 switch (m_storageType) {
Chris@264 215
Chris@334 216 case Rectangular:
Chris@334 217 for (size_t y = 0; y < m_height; ++y) {
Chris@334 218 m_freal[x][y] = reals[y];
Chris@334 219 m_fimag[x][y] = imags[y];
Chris@334 220 float mag = sqrtf(reals[y] * reals[y] + imags[y] * imags[y]);
Chris@334 221 if (mag > max) max = mag;
Chris@334 222 }
Chris@334 223 break;
Chris@334 224
Chris@264 225 case Compact:
Chris@264 226 case Polar:
Chris@408 227 {
Chris@408 228 Profiler subprof("FFTMemoryCache::setColumnAt: cart to polar");
Chris@264 229 for (size_t y = 0; y < m_height; ++y) {
Chris@264 230 float mag = sqrtf(reals[y] * reals[y] + imags[y] * imags[y]);
Chris@264 231 float phase = atan2f(imags[y], reals[y]);
Chris@264 232 reals[y] = mag;
Chris@264 233 imags[y] = phase;
Chris@264 234 if (mag > max) max = mag;
Chris@264 235 }
Chris@264 236 break;
Chris@408 237 }
Chris@264 238 };
Chris@159 239
Chris@334 240 if (m_storageType == Rectangular) {
Chris@334 241 m_factor[x] = max;
Chris@334 242 m_colset.set(x);
Chris@334 243 } else {
Chris@334 244 setColumnAt(x, reals, imags, max);
Chris@334 245 }
Chris@159 246 }
Chris@159 247
Chris@170 248 size_t
Chris@264 249 FFTMemoryCache::getCacheSize(size_t width, size_t height, StorageType type)
Chris@170 250 {
Chris@264 251 size_t sz = 0;
Chris@264 252
Chris@264 253 switch (type) {
Chris@264 254
Chris@264 255 case Compact:
Chris@264 256 sz = (height * 2 + 1) * width * sizeof(uint16_t);
Chris@264 257
Chris@264 258 case Polar:
Chris@334 259 case Rectangular:
Chris@264 260 sz = (height * 2 + 1) * width * sizeof(float);
Chris@264 261 }
Chris@264 262
Chris@264 263 return sz;
Chris@170 264 }
Chris@170 265