comparison data/model/WaveFileModel.cpp @ 300:5877d68815c7

* Change WaveFileModel API from getValues(start,end) to getData(start,count). It's much less error-prone to pass in frame counts instead of start/end locations. Should have done this ages ago. This closes #1794563. * Add option to apply a transform to only the selection region, instead of the whole audio. * (to make the above work properly) Add start frame offset to wave models
author Chris Cannam
date Mon, 01 Oct 2007 13:48:38 +0000
parents c022976d18e8
children 70a232b1f12a
comparison
equal deleted inserted replaced
299:576be0d0d218 300:5877d68815c7
39 WaveFileModel::m_zoomConstraint; 39 WaveFileModel::m_zoomConstraint;
40 40
41 WaveFileModel::WaveFileModel(QString path, size_t targetRate) : 41 WaveFileModel::WaveFileModel(QString path, size_t targetRate) :
42 m_path(path), 42 m_path(path),
43 m_myReader(true), 43 m_myReader(true),
44 m_startFrame(0),
44 m_fillThread(0), 45 m_fillThread(0),
45 m_updateTimer(0), 46 m_updateTimer(0),
46 m_lastFillExtent(0), 47 m_lastFillExtent(0),
47 m_exiting(false) 48 m_exiting(false)
48 { 49 {
54 } 55 }
55 56
56 WaveFileModel::WaveFileModel(QString path, QString originalLocation, size_t targetRate) : 57 WaveFileModel::WaveFileModel(QString path, QString originalLocation, size_t targetRate) :
57 m_path(originalLocation), 58 m_path(originalLocation),
58 m_myReader(true), 59 m_myReader(true),
60 m_startFrame(0),
59 m_fillThread(0), 61 m_fillThread(0),
60 m_updateTimer(0), 62 m_updateTimer(0),
61 m_lastFillExtent(0), 63 m_lastFillExtent(0),
62 m_exiting(false) 64 m_exiting(false)
63 { 65 {
69 } 71 }
70 72
71 WaveFileModel::WaveFileModel(QString path, AudioFileReader *reader) : 73 WaveFileModel::WaveFileModel(QString path, AudioFileReader *reader) :
72 m_path(path), 74 m_path(path),
73 m_myReader(false), 75 m_myReader(false),
76 m_startFrame(0),
74 m_fillThread(0), 77 m_fillThread(0),
75 m_updateTimer(0), 78 m_updateTimer(0),
76 m_lastFillExtent(0), 79 m_lastFillExtent(0),
77 m_exiting(false) 80 m_exiting(false)
78 { 81 {
160 if (rate == 0) rate = getSampleRate(); 163 if (rate == 0) rate = getSampleRate();
161 return rate; 164 return rate;
162 } 165 }
163 166
164 size_t 167 size_t
165 WaveFileModel::getValues(int channel, size_t start, size_t end, 168 WaveFileModel::getData(int channel, size_t start, size_t count,
166 float *buffer) const 169 float *buffer) const
167 { 170 {
168 // Always read these directly from the file. 171 // Always read these directly from the file.
169 // This is used for e.g. audio playback. 172 // This is used for e.g. audio playback.
170 // Could be much more efficient (although compiler optimisation will help) 173 // Could be much more efficient (although compiler optimisation will help)
171 174
172 if (end < start) { 175 if (start > m_startFrame) {
173 std::cerr << "ERROR: WaveFileModel::getValues[float]: end < start (" 176 start -= m_startFrame;
174 << end << " < " << start << ")" << std::endl; 177 } else {
175 assert(end >= start); 178 for (size_t i = 0; i < count; ++i) buffer[i] = 0.f;
176 } 179 if (count <= m_startFrame - start) {
177 180 return 0;
178 if (!m_reader || !m_reader->isOK()) return 0; 181 } else {
182 count -= (m_startFrame - start);
183 start = 0;
184 }
185 }
186
187 if (!m_reader || !m_reader->isOK() || count == 0) {
188 for (size_t i = 0; i < count; ++i) buffer[i] = 0.f;
189 return 0;
190 }
179 191
180 #ifdef DEBUG_WAVE_FILE_MODEL 192 #ifdef DEBUG_WAVE_FILE_MODEL
181 // std::cerr << "WaveFileModel::getValues(" << channel << ", " 193 // std::cerr << "WaveFileModel::getValues(" << channel << ", "
182 // << start << ", " << end << "): calling reader" << std::endl; 194 // << start << ", " << end << "): calling reader" << std::endl;
183 #endif 195 #endif
184 196
185 SampleBlock frames; 197 SampleBlock frames;
186 m_reader->getInterleavedFrames(start, end - start, frames); 198 m_reader->getInterleavedFrames(start, count, frames);
187 199
188 size_t i = 0; 200 size_t i = 0;
189 201
190 int ch0 = channel, ch1 = channel, channels = getChannelCount(); 202 int ch0 = channel, ch1 = channel, channels = getChannelCount();
191 if (channel == -1) { 203 if (channel == -1) {
192 ch0 = 0; 204 ch0 = 0;
193 ch1 = channels - 1; 205 ch1 = channels - 1;
194 } 206 }
195 207
196 while (i < end - start) { 208 while (i < count) {
197 209
198 buffer[i] = 0.0; 210 buffer[i] = 0.0;
199 211
200 for (int ch = ch0; ch <= ch1; ++ch) { 212 for (int ch = ch0; ch <= ch1; ++ch) {
201 213
211 223
212 return i; 224 return i;
213 } 225 }
214 226
215 size_t 227 size_t
216 WaveFileModel::getValues(int channel, size_t start, size_t end, 228 WaveFileModel::getData(int channel, size_t start, size_t count,
217 double *buffer) const 229 double *buffer) const
218 { 230 {
219 if (end < start) { 231 if (start > m_startFrame) {
220 std::cerr << "ERROR: WaveFileModel::getValues[double]: end < start (" 232 start -= m_startFrame;
221 << end << " < " << start << ")" << std::endl; 233 } else {
222 assert(end >= start); 234 for (size_t i = 0; i < count; ++i) buffer[i] = 0.0;
223 } 235 if (count <= m_startFrame - start) {
224 236 return 0;
225 if (!m_reader || !m_reader->isOK()) return 0; 237 } else {
238 count -= (m_startFrame - start);
239 start = 0;
240 }
241 }
242
243 if (!m_reader || !m_reader->isOK() || count == 0) {
244 for (size_t i = 0; i < count; ++i) buffer[i] = 0.0;
245 return 0;
246 }
226 247
227 SampleBlock frames; 248 SampleBlock frames;
228 m_reader->getInterleavedFrames(start, end - start, frames); 249 m_reader->getInterleavedFrames(start, count, frames);
229 250
230 size_t i = 0; 251 size_t i = 0;
231 252
232 int ch0 = channel, ch1 = channel, channels = getChannelCount(); 253 int ch0 = channel, ch1 = channel, channels = getChannelCount();
233 if (channel == -1) { 254 if (channel == -1) {
234 ch0 = 0; 255 ch0 = 0;
235 ch1 = channels - 1; 256 ch1 = channels - 1;
236 } 257 }
237 258
238 while (i < end - start) { 259 while (i < count) {
239 260
240 buffer[i] = 0.0; 261 buffer[i] = 0.0;
241 262
242 for (int ch = ch0; ch <= ch1; ++ch) { 263 for (int ch = ch0; ch <= ch1; ++ch) {
243 264
253 274
254 return i; 275 return i;
255 } 276 }
256 277
257 void 278 void
258 WaveFileModel::getRanges(size_t channel, size_t start, size_t end, 279 WaveFileModel::getSummaries(size_t channel, size_t start, size_t count,
259 RangeBlock &ranges, size_t &blockSize) const 280 RangeBlock &ranges, size_t &blockSize) const
260 { 281 {
261 ranges.clear(); 282 ranges.clear();
262 if (!isOK()) return; 283 if (!isOK()) return;
263 284
264 if (end <= start) { 285 if (start > m_startFrame) start -= m_startFrame;
265 std::cerr << "WARNING: Internal error: end <= start in WaveFileModel::getRanges (end = " << end << ", start = " << start << ", blocksize = " << blockSize << ")" << std::endl; 286 else if (count <= m_startFrame - start) return;
266 return; 287 else {
288 count -= (m_startFrame - start);
289 start = 0;
267 } 290 }
268 291
269 int cacheType = 0; 292 int cacheType = 0;
270 int power = m_zoomConstraint.getMinCachePower(); 293 int power = m_zoomConstraint.getMinCachePower();
271 blockSize = m_zoomConstraint.getNearestBlockSize 294 blockSize = m_zoomConstraint.getNearestBlockSize
282 // We could fairly trivially handle this for most cases that 305 // We could fairly trivially handle this for most cases that
283 // matter by putting a single cache in getInterleavedFrames 306 // matter by putting a single cache in getInterleavedFrames
284 // for short queries. 307 // for short queries.
285 308
286 SampleBlock frames; 309 SampleBlock frames;
287 m_reader->getInterleavedFrames(start, end - start, frames); 310 m_reader->getInterleavedFrames(start, count, frames);
288 float max = 0.0, min = 0.0, total = 0.0; 311 float max = 0.0, min = 0.0, total = 0.0;
289 size_t i = 0, count = 0; 312 size_t i = 0, got = 0;
290 313
291 while (i < end - start) { 314 while (i < count) {
292 315
293 size_t index = i * channels + channel; 316 size_t index = i * channels + channel;
294 if (index >= frames.size()) break; 317 if (index >= frames.size()) break;
295 318
296 float sample = frames[index]; 319 float sample = frames[index];
297 if (sample > max || count == 0) max = sample; 320 if (sample > max || got == 0) max = sample;
298 if (sample < min || count == 0) min = sample; 321 if (sample < min || got == 0) min = sample;
299 total += fabsf(sample); 322 total += fabsf(sample);
300 323
301 ++i; 324 ++i;
302 ++count; 325 ++got;
303 326
304 if (count == blockSize) { 327 if (got == blockSize) {
305 ranges.push_back(Range(min, max, total / count)); 328 ranges.push_back(Range(min, max, total / got));
306 min = max = total = 0.0f; 329 min = max = total = 0.0f;
307 count = 0; 330 got = 0;
308 } 331 }
309 } 332 }
310 333
311 if (count > 0) { 334 if (got > 0) {
312 ranges.push_back(Range(min, max, total / count)); 335 ranges.push_back(Range(min, max, total / got));
313 } 336 }
314 337
315 return; 338 return;
316 339
317 } else { 340 } else {
329 cacheBlock = ((unsigned int)((1 << m_zoomConstraint.getMinCachePower()) * sqrt(2) + 0.01)); 352 cacheBlock = ((unsigned int)((1 << m_zoomConstraint.getMinCachePower()) * sqrt(2) + 0.01));
330 div = ((unsigned int)((1 << power) * sqrt(2) + 0.01)) / cacheBlock; 353 div = ((unsigned int)((1 << power) * sqrt(2) + 0.01)) / cacheBlock;
331 } 354 }
332 355
333 size_t startIndex = start / cacheBlock; 356 size_t startIndex = start / cacheBlock;
334 size_t endIndex = end / cacheBlock; 357 size_t endIndex = (start + count) / cacheBlock;
335 358
336 float max = 0.0, min = 0.0, total = 0.0; 359 float max = 0.0, min = 0.0, total = 0.0;
337 size_t i = 0, count = 0; 360 size_t i = 0, got = 0;
338 361
339 #ifdef DEBUG_WAVE_FILE_MODEL 362 #ifdef DEBUG_WAVE_FILE_MODEL
340 cerr << "blockSize is " << blockSize << ", cacheBlock " << cacheBlock << ", start " << start << ", end " << end << " (frame count " << getFrameCount() << "), power is " << power << ", div is " << div << ", startIndex " << startIndex << ", endIndex " << endIndex << endl; 363 cerr << "blockSize is " << blockSize << ", cacheBlock " << cacheBlock << ", start " << start << ", count " << count << " (frame count " << getFrameCount() << "), power is " << power << ", div is " << div << ", startIndex " << startIndex << ", endIndex " << endIndex << endl;
341 #endif 364 #endif
342 365
343 for (i = 0; i < endIndex - startIndex; ) { 366 for (i = 0; i <= endIndex - startIndex; ) {
344 367
345 size_t index = (i + startIndex) * channels + channel; 368 size_t index = (i + startIndex) * channels + channel;
346 if (index >= cache.size()) break; 369 if (index >= cache.size()) break;
347 370
348 const Range &range = cache[index]; 371 const Range &range = cache[index];
349 if (range.max > max || count == 0) max = range.max; 372 if (range.max > max || got == 0) max = range.max;
350 if (range.min < min || count == 0) min = range.min; 373 if (range.min < min || got == 0) min = range.min;
351 total += range.absmean; 374 total += range.absmean;
352 375
353 ++i; 376 ++i;
354 ++count; 377 ++got;
355 378
356 if (count == div) { 379 if (got == div) {
357 ranges.push_back(Range(min, max, total / count)); 380 ranges.push_back(Range(min, max, total / got));
358 min = max = total = 0.0f; 381 min = max = total = 0.0f;
359 count = 0; 382 got = 0;
360 } 383 }
361 } 384 }
362 385
363 if (count > 0) { 386 if (got > 0) {
364 ranges.push_back(Range(min, max, total / count)); 387 ranges.push_back(Range(min, max, total / got));
365 } 388 }
366 } 389 }
367 390
368 #ifdef DEBUG_WAVE_FILE_MODEL 391 #ifdef DEBUG_WAVE_FILE_MODEL
369 cerr << "returning " << ranges.size() << " ranges" << endl; 392 cerr << "returning " << ranges.size() << " ranges" << endl;
370 #endif 393 #endif
371 return; 394 return;
372 } 395 }
373 396
374 WaveFileModel::Range 397 WaveFileModel::Range
375 WaveFileModel::getRange(size_t channel, size_t start, size_t end) const 398 WaveFileModel::getSummary(size_t channel, size_t start, size_t count) const
376 { 399 {
377 Range range; 400 Range range;
378 if (!isOK()) return range; 401 if (!isOK()) return range;
379 402
380 if (end <= start) { 403 if (start > m_startFrame) start -= m_startFrame;
381 std::cerr << "WARNING: Internal error: end <= start in WaveFileModel::getRange (end = " << end << ", start = " << start << ")" << std::endl; 404 else if (count <= m_startFrame - start) return range;
382 return range; 405 else {
406 count -= (m_startFrame - start);
407 start = 0;
383 } 408 }
384 409
385 size_t blockSize; 410 size_t blockSize;
386 for (blockSize = 1; blockSize <= end - start; blockSize *= 2); 411 for (blockSize = 1; blockSize <= count; blockSize *= 2);
387 blockSize /= 2; 412 if (blockSize > 1) blockSize /= 2;
388 413
389 bool first = false; 414 bool first = false;
390 415
391 size_t blockStart = (start / blockSize) * blockSize; 416 size_t blockStart = (start / blockSize) * blockSize;
392 size_t blockEnd = (end / blockSize) * blockSize; 417 size_t blockEnd = ((start + count) / blockSize) * blockSize;
393 418
394 if (blockStart < start) blockStart += blockSize; 419 if (blockStart < start) blockStart += blockSize;
395 420
396 if (blockEnd > blockStart) { 421 if (blockEnd > blockStart) {
397 RangeBlock ranges; 422 RangeBlock ranges;
398 getRanges(channel, blockStart, blockEnd, ranges, blockSize); 423 getSummaries(channel, blockStart, blockEnd - blockStart, ranges, blockSize);
399 for (size_t i = 0; i < ranges.size(); ++i) { 424 for (size_t i = 0; i < ranges.size(); ++i) {
400 if (first || ranges[i].min < range.min) range.min = ranges[i].min; 425 if (first || ranges[i].min < range.min) range.min = ranges[i].min;
401 if (first || ranges[i].max > range.max) range.max = ranges[i].max; 426 if (first || ranges[i].max > range.max) range.max = ranges[i].max;
402 if (first || ranges[i].absmean < range.absmean) range.absmean = ranges[i].absmean; 427 if (first || ranges[i].absmean < range.absmean) range.absmean = ranges[i].absmean;
403 first = false; 428 first = false;
404 } 429 }
405 } 430 }
406 431
407 if (blockStart > start) { 432 if (blockStart > start) {
408 Range startRange = getRange(channel, start, blockStart); 433 Range startRange = getSummary(channel, start, blockStart - start);
409 range.min = std::min(range.min, startRange.min); 434 range.min = std::min(range.min, startRange.min);
410 range.max = std::max(range.max, startRange.max); 435 range.max = std::max(range.max, startRange.max);
411 range.absmean = std::min(range.absmean, startRange.absmean); 436 range.absmean = std::min(range.absmean, startRange.absmean);
412 } 437 }
413 438
414 if (blockEnd < end) { 439 if (blockEnd < start + count) {
415 Range endRange = getRange(channel, blockEnd, end); 440 Range endRange = getSummary(channel, blockEnd, start + count - blockEnd);
416 range.min = std::min(range.min, endRange.min); 441 range.min = std::min(range.min, endRange.min);
417 range.max = std::max(range.max, endRange.max); 442 range.max = std::max(range.max, endRange.max);
418 range.absmean = std::min(range.absmean, endRange.absmean); 443 range.absmean = std::min(range.absmean, endRange.absmean);
419 } 444 }
420 445