Mercurial > hg > svcore
comparison data/model/WaveFileModel.cpp @ 384:6f6ab834449d spectrogram-cache-rejig
* Merge from trunk
author | Chris Cannam |
---|---|
date | Wed, 27 Feb 2008 11:59:42 +0000 |
parents | 1afaf98dbf11 |
children |
comparison
equal
deleted
inserted
replaced
337:a6fab10ff9e6 | 384:6f6ab834449d |
---|---|
171 WaveFileModel::getMaker() const | 171 WaveFileModel::getMaker() const |
172 { | 172 { |
173 if (m_reader) return m_reader->getMaker(); | 173 if (m_reader) return m_reader->getMaker(); |
174 return ""; | 174 return ""; |
175 } | 175 } |
176 | |
177 QString | |
178 WaveFileModel::getLocation() const | |
179 { | |
180 if (m_reader) return m_reader->getLocation(); | |
181 return ""; | |
182 } | |
176 | 183 |
177 size_t | 184 size_t |
178 WaveFileModel::getData(int channel, size_t start, size_t count, | 185 WaveFileModel::getData(int channel, size_t start, size_t count, |
179 float *buffer) const | 186 float *buffer) const |
180 { | 187 { |
181 // Always read these directly from the file. | 188 // Always read these directly from the file. |
182 // This is used for e.g. audio playback. | 189 // This is used for e.g. audio playback. |
183 // Could be much more efficient (although compiler optimisation will help) | 190 // Could be much more efficient (although compiler optimisation will help) |
184 | 191 |
185 if (start > m_startFrame) { | 192 if (start >= m_startFrame) { |
186 start -= m_startFrame; | 193 start -= m_startFrame; |
187 } else { | 194 } else { |
188 for (size_t i = 0; i < count; ++i) buffer[i] = 0.f; | 195 for (size_t i = 0; i < count; ++i) buffer[i] = 0.f; |
189 if (count <= m_startFrame - start) { | 196 if (count <= m_startFrame - start) { |
190 return 0; | 197 return 0; |
202 #ifdef DEBUG_WAVE_FILE_MODEL | 209 #ifdef DEBUG_WAVE_FILE_MODEL |
203 // std::cerr << "WaveFileModel::getValues(" << channel << ", " | 210 // std::cerr << "WaveFileModel::getValues(" << channel << ", " |
204 // << start << ", " << end << "): calling reader" << std::endl; | 211 // << start << ", " << end << "): calling reader" << std::endl; |
205 #endif | 212 #endif |
206 | 213 |
207 SampleBlock frames; | 214 int channels = getChannelCount(); |
215 | |
216 SampleBlock frames(count * channels); | |
208 m_reader->getInterleavedFrames(start, count, frames); | 217 m_reader->getInterleavedFrames(start, count, frames); |
209 | 218 |
210 size_t i = 0; | 219 size_t i = 0; |
211 | 220 |
212 int ch0 = channel, ch1 = channel, channels = getChannelCount(); | 221 int ch0 = channel, ch1 = channel; |
213 if (channel == -1) { | 222 if (channel == -1) { |
214 ch0 = 0; | 223 ch0 = 0; |
215 ch1 = channels - 1; | 224 ch1 = channels - 1; |
216 } | 225 } |
217 | 226 |
253 if (!m_reader || !m_reader->isOK() || count == 0) { | 262 if (!m_reader || !m_reader->isOK() || count == 0) { |
254 for (size_t i = 0; i < count; ++i) buffer[i] = 0.0; | 263 for (size_t i = 0; i < count; ++i) buffer[i] = 0.0; |
255 return 0; | 264 return 0; |
256 } | 265 } |
257 | 266 |
258 SampleBlock frames; | 267 int channels = getChannelCount(); |
268 | |
269 SampleBlock frames(count * channels); | |
259 m_reader->getInterleavedFrames(start, count, frames); | 270 m_reader->getInterleavedFrames(start, count, frames); |
260 | 271 |
261 size_t i = 0; | 272 size_t i = 0; |
262 | 273 |
263 int ch0 = channel, ch1 = channel, channels = getChannelCount(); | 274 int ch0 = channel, ch1 = channel; |
264 if (channel == -1) { | 275 if (channel == -1) { |
265 ch0 = 0; | 276 ch0 = 0; |
266 ch1 = channels - 1; | 277 ch1 = channels - 1; |
267 } | 278 } |
268 | 279 |
283 } | 294 } |
284 | 295 |
285 return i; | 296 return i; |
286 } | 297 } |
287 | 298 |
299 size_t | |
300 WaveFileModel::getData(size_t fromchannel, size_t tochannel, | |
301 size_t start, size_t count, | |
302 float **buffer) const | |
303 { | |
304 size_t channels = getChannelCount(); | |
305 | |
306 if (fromchannel > tochannel) { | |
307 std::cerr << "ERROR: WaveFileModel::getData: fromchannel (" | |
308 << fromchannel << ") > tochannel (" << tochannel << ")" | |
309 << std::endl; | |
310 return 0; | |
311 } | |
312 | |
313 if (tochannel >= channels) { | |
314 std::cerr << "ERROR: WaveFileModel::getData: tochannel (" | |
315 << tochannel << ") >= channel count (" << channels << ")" | |
316 << std::endl; | |
317 return 0; | |
318 } | |
319 | |
320 if (fromchannel == tochannel) { | |
321 return getData(fromchannel, start, count, buffer[0]); | |
322 } | |
323 | |
324 size_t reqchannels = (tochannel - fromchannel) + 1; | |
325 | |
326 // Always read these directly from the file. | |
327 // This is used for e.g. audio playback. | |
328 // Could be much more efficient (although compiler optimisation will help) | |
329 | |
330 if (start >= m_startFrame) { | |
331 start -= m_startFrame; | |
332 } else { | |
333 for (size_t c = 0; c < reqchannels; ++c) { | |
334 for (size_t i = 0; i < count; ++i) buffer[c][i] = 0.f; | |
335 } | |
336 if (count <= m_startFrame - start) { | |
337 return 0; | |
338 } else { | |
339 count -= (m_startFrame - start); | |
340 start = 0; | |
341 } | |
342 } | |
343 | |
344 if (!m_reader || !m_reader->isOK() || count == 0) { | |
345 for (size_t c = 0; c < reqchannels; ++c) { | |
346 for (size_t i = 0; i < count; ++i) buffer[c][i] = 0.f; | |
347 } | |
348 return 0; | |
349 } | |
350 | |
351 SampleBlock frames(count * channels); | |
352 m_reader->getInterleavedFrames(start, count, frames); | |
353 | |
354 size_t i = 0; | |
355 | |
356 int ch0 = fromchannel, ch1 = tochannel; | |
357 | |
358 size_t index = 0, available = frames.size(); | |
359 | |
360 while (i < count) { | |
361 | |
362 if (index >= available) break; | |
363 | |
364 size_t destc = 0; | |
365 | |
366 for (size_t c = 0; c < channels; ++c) { | |
367 | |
368 if (c >= fromchannel && c <= tochannel) { | |
369 buffer[destc][i] = frames[index]; | |
370 ++destc; | |
371 } | |
372 | |
373 ++index; | |
374 } | |
375 | |
376 ++i; | |
377 } | |
378 | |
379 return i; | |
380 } | |
381 | |
382 size_t | |
383 WaveFileModel::getSummaryBlockSize(size_t desired) const | |
384 { | |
385 int cacheType = 0; | |
386 int power = m_zoomConstraint.getMinCachePower(); | |
387 size_t roundedBlockSize = m_zoomConstraint.getNearestBlockSize | |
388 (desired, cacheType, power, ZoomConstraint::RoundDown); | |
389 if (cacheType != 0 && cacheType != 1) { | |
390 // We will be reading directly from file, so can satisfy any | |
391 // blocksize requirement | |
392 return desired; | |
393 } else { | |
394 return roundedBlockSize; | |
395 } | |
396 } | |
397 | |
288 void | 398 void |
289 WaveFileModel::getSummaries(size_t channel, size_t start, size_t count, | 399 WaveFileModel::getSummaries(size_t channel, size_t start, size_t count, |
290 RangeBlock &ranges, size_t &blockSize) const | 400 RangeBlock &ranges, size_t &blockSize) const |
291 { | 401 { |
292 ranges.clear(); | 402 ranges.clear(); |
293 if (!isOK()) return; | 403 if (!isOK()) return; |
404 ranges.reserve((count / blockSize) + 1); | |
294 | 405 |
295 if (start > m_startFrame) start -= m_startFrame; | 406 if (start > m_startFrame) start -= m_startFrame; |
296 else if (count <= m_startFrame - start) return; | 407 else if (count <= m_startFrame - start) return; |
297 else { | 408 else { |
298 count -= (m_startFrame - start); | 409 count -= (m_startFrame - start); |
299 start = 0; | 410 start = 0; |
300 } | 411 } |
301 | 412 |
302 int cacheType = 0; | 413 int cacheType = 0; |
303 int power = m_zoomConstraint.getMinCachePower(); | 414 int power = m_zoomConstraint.getMinCachePower(); |
304 blockSize = m_zoomConstraint.getNearestBlockSize | 415 size_t roundedBlockSize = m_zoomConstraint.getNearestBlockSize |
305 (blockSize, cacheType, power, ZoomConstraint::RoundUp); | 416 (blockSize, cacheType, power, ZoomConstraint::RoundDown); |
306 | 417 |
307 size_t channels = getChannelCount(); | 418 size_t channels = getChannelCount(); |
308 | 419 |
309 if (cacheType != 0 && cacheType != 1) { | 420 if (cacheType != 0 && cacheType != 1) { |
310 | 421 |
314 // for stereo files, in two separate calls to this method. | 425 // for stereo files, in two separate calls to this method. |
315 // We could fairly trivially handle this for most cases that | 426 // We could fairly trivially handle this for most cases that |
316 // matter by putting a single cache in getInterleavedFrames | 427 // matter by putting a single cache in getInterleavedFrames |
317 // for short queries. | 428 // for short queries. |
318 | 429 |
319 SampleBlock frames; | 430 m_directReadMutex.lock(); |
320 m_reader->getInterleavedFrames(start, count, frames); | 431 |
432 if (m_lastDirectReadStart != start || | |
433 m_lastDirectReadCount != count || | |
434 m_directRead.empty()) { | |
435 | |
436 m_reader->getInterleavedFrames(start, count, m_directRead); | |
437 m_lastDirectReadStart = start; | |
438 m_lastDirectReadCount = count; | |
439 } | |
440 | |
321 float max = 0.0, min = 0.0, total = 0.0; | 441 float max = 0.0, min = 0.0, total = 0.0; |
322 size_t i = 0, got = 0; | 442 size_t i = 0, got = 0; |
323 | 443 |
324 while (i < count) { | 444 while (i < count) { |
325 | 445 |
326 size_t index = i * channels + channel; | 446 size_t index = i * channels + channel; |
327 if (index >= frames.size()) break; | 447 if (index >= m_directRead.size()) break; |
328 | 448 |
329 float sample = frames[index]; | 449 float sample = m_directRead[index]; |
330 if (sample > max || got == 0) max = sample; | 450 if (sample > max || got == 0) max = sample; |
331 if (sample < min || got == 0) min = sample; | 451 if (sample < min || got == 0) min = sample; |
332 total += fabsf(sample); | 452 total += fabsf(sample); |
333 | 453 |
334 ++i; | 454 ++i; |
339 min = max = total = 0.0f; | 459 min = max = total = 0.0f; |
340 got = 0; | 460 got = 0; |
341 } | 461 } |
342 } | 462 } |
343 | 463 |
464 m_directReadMutex.unlock(); | |
465 | |
344 if (got > 0) { | 466 if (got > 0) { |
345 ranges.push_back(Range(min, max, total / got)); | 467 ranges.push_back(Range(min, max, total / got)); |
346 } | 468 } |
347 | 469 |
348 return; | 470 return; |
350 } else { | 472 } else { |
351 | 473 |
352 QMutexLocker locker(&m_mutex); | 474 QMutexLocker locker(&m_mutex); |
353 | 475 |
354 const RangeBlock &cache = m_cache[cacheType]; | 476 const RangeBlock &cache = m_cache[cacheType]; |
477 | |
478 blockSize = roundedBlockSize; | |
355 | 479 |
356 size_t cacheBlock, div; | 480 size_t cacheBlock, div; |
357 | 481 |
358 if (cacheType == 0) { | 482 if (cacheType == 0) { |
359 cacheBlock = (1 << m_zoomConstraint.getMinCachePower()); | 483 cacheBlock = (1 << m_zoomConstraint.getMinCachePower()); |