Mercurial > hg > svcore
comparison data/model/WaveFileModel.cpp @ 383:94fc0591ea43 1.2-stable
* merge from trunk (1.2 ended up being tracked from trunk, but we may want
this branch for fixes later)
author | Chris Cannam |
---|---|
date | Wed, 27 Feb 2008 10:32:45 +0000 |
parents | 700cd3350391 |
children |
comparison
equal
deleted
inserted
replaced
349:f39d33b0b265 | 383:94fc0591ea43 |
---|---|
187 { | 187 { |
188 // Always read these directly from the file. | 188 // Always read these directly from the file. |
189 // This is used for e.g. audio playback. | 189 // This is used for e.g. audio playback. |
190 // Could be much more efficient (although compiler optimisation will help) | 190 // Could be much more efficient (although compiler optimisation will help) |
191 | 191 |
192 if (start > m_startFrame) { | 192 if (start >= m_startFrame) { |
193 start -= m_startFrame; | 193 start -= m_startFrame; |
194 } else { | 194 } else { |
195 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; |
196 if (count <= m_startFrame - start) { | 196 if (count <= m_startFrame - start) { |
197 return 0; | 197 return 0; |
209 #ifdef DEBUG_WAVE_FILE_MODEL | 209 #ifdef DEBUG_WAVE_FILE_MODEL |
210 // std::cerr << "WaveFileModel::getValues(" << channel << ", " | 210 // std::cerr << "WaveFileModel::getValues(" << channel << ", " |
211 // << start << ", " << end << "): calling reader" << std::endl; | 211 // << start << ", " << end << "): calling reader" << std::endl; |
212 #endif | 212 #endif |
213 | 213 |
214 SampleBlock frames; | 214 int channels = getChannelCount(); |
215 | |
216 SampleBlock frames(count * channels); | |
215 m_reader->getInterleavedFrames(start, count, frames); | 217 m_reader->getInterleavedFrames(start, count, frames); |
216 | 218 |
217 size_t i = 0; | 219 size_t i = 0; |
218 | 220 |
219 int ch0 = channel, ch1 = channel, channels = getChannelCount(); | 221 int ch0 = channel, ch1 = channel; |
220 if (channel == -1) { | 222 if (channel == -1) { |
221 ch0 = 0; | 223 ch0 = 0; |
222 ch1 = channels - 1; | 224 ch1 = channels - 1; |
223 } | 225 } |
224 | 226 |
260 if (!m_reader || !m_reader->isOK() || count == 0) { | 262 if (!m_reader || !m_reader->isOK() || count == 0) { |
261 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; |
262 return 0; | 264 return 0; |
263 } | 265 } |
264 | 266 |
265 SampleBlock frames; | 267 int channels = getChannelCount(); |
268 | |
269 SampleBlock frames(count * channels); | |
266 m_reader->getInterleavedFrames(start, count, frames); | 270 m_reader->getInterleavedFrames(start, count, frames); |
267 | 271 |
268 size_t i = 0; | 272 size_t i = 0; |
269 | 273 |
270 int ch0 = channel, ch1 = channel, channels = getChannelCount(); | 274 int ch0 = channel, ch1 = channel; |
271 if (channel == -1) { | 275 if (channel == -1) { |
272 ch0 = 0; | 276 ch0 = 0; |
273 ch1 = channels - 1; | 277 ch1 = channels - 1; |
274 } | 278 } |
275 | 279 |
290 } | 294 } |
291 | 295 |
292 return i; | 296 return i; |
293 } | 297 } |
294 | 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 | |
295 void | 398 void |
296 WaveFileModel::getSummaries(size_t channel, size_t start, size_t count, | 399 WaveFileModel::getSummaries(size_t channel, size_t start, size_t count, |
297 RangeBlock &ranges, size_t &blockSize) const | 400 RangeBlock &ranges, size_t &blockSize) const |
298 { | 401 { |
299 ranges.clear(); | 402 ranges.clear(); |
300 if (!isOK()) return; | 403 if (!isOK()) return; |
404 ranges.reserve((count / blockSize) + 1); | |
301 | 405 |
302 if (start > m_startFrame) start -= m_startFrame; | 406 if (start > m_startFrame) start -= m_startFrame; |
303 else if (count <= m_startFrame - start) return; | 407 else if (count <= m_startFrame - start) return; |
304 else { | 408 else { |
305 count -= (m_startFrame - start); | 409 count -= (m_startFrame - start); |
306 start = 0; | 410 start = 0; |
307 } | 411 } |
308 | 412 |
309 int cacheType = 0; | 413 int cacheType = 0; |
310 int power = m_zoomConstraint.getMinCachePower(); | 414 int power = m_zoomConstraint.getMinCachePower(); |
311 blockSize = m_zoomConstraint.getNearestBlockSize | 415 size_t roundedBlockSize = m_zoomConstraint.getNearestBlockSize |
312 (blockSize, cacheType, power, ZoomConstraint::RoundUp); | 416 (blockSize, cacheType, power, ZoomConstraint::RoundDown); |
313 | 417 |
314 size_t channels = getChannelCount(); | 418 size_t channels = getChannelCount(); |
315 | 419 |
316 if (cacheType != 0 && cacheType != 1) { | 420 if (cacheType != 0 && cacheType != 1) { |
317 | 421 |
321 // for stereo files, in two separate calls to this method. | 425 // for stereo files, in two separate calls to this method. |
322 // We could fairly trivially handle this for most cases that | 426 // We could fairly trivially handle this for most cases that |
323 // matter by putting a single cache in getInterleavedFrames | 427 // matter by putting a single cache in getInterleavedFrames |
324 // for short queries. | 428 // for short queries. |
325 | 429 |
326 SampleBlock frames; | 430 m_directReadMutex.lock(); |
327 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 | |
328 float max = 0.0, min = 0.0, total = 0.0; | 441 float max = 0.0, min = 0.0, total = 0.0; |
329 size_t i = 0, got = 0; | 442 size_t i = 0, got = 0; |
330 | 443 |
331 while (i < count) { | 444 while (i < count) { |
332 | 445 |
333 size_t index = i * channels + channel; | 446 size_t index = i * channels + channel; |
334 if (index >= frames.size()) break; | 447 if (index >= m_directRead.size()) break; |
335 | 448 |
336 float sample = frames[index]; | 449 float sample = m_directRead[index]; |
337 if (sample > max || got == 0) max = sample; | 450 if (sample > max || got == 0) max = sample; |
338 if (sample < min || got == 0) min = sample; | 451 if (sample < min || got == 0) min = sample; |
339 total += fabsf(sample); | 452 total += fabsf(sample); |
340 | 453 |
341 ++i; | 454 ++i; |
346 min = max = total = 0.0f; | 459 min = max = total = 0.0f; |
347 got = 0; | 460 got = 0; |
348 } | 461 } |
349 } | 462 } |
350 | 463 |
464 m_directReadMutex.unlock(); | |
465 | |
351 if (got > 0) { | 466 if (got > 0) { |
352 ranges.push_back(Range(min, max, total / got)); | 467 ranges.push_back(Range(min, max, total / got)); |
353 } | 468 } |
354 | 469 |
355 return; | 470 return; |
357 } else { | 472 } else { |
358 | 473 |
359 QMutexLocker locker(&m_mutex); | 474 QMutexLocker locker(&m_mutex); |
360 | 475 |
361 const RangeBlock &cache = m_cache[cacheType]; | 476 const RangeBlock &cache = m_cache[cacheType]; |
477 | |
478 blockSize = roundedBlockSize; | |
362 | 479 |
363 size_t cacheBlock, div; | 480 size_t cacheBlock, div; |
364 | 481 |
365 if (cacheType == 0) { | 482 if (cacheType == 0) { |
366 cacheBlock = (1 << m_zoomConstraint.getMinCachePower()); | 483 cacheBlock = (1 << m_zoomConstraint.getMinCachePower()); |