315 |
} |
} |
316 |
|
|
317 |
/** |
/** |
318 |
|
* Reads \a SampleCount number of sample points from the position stored |
319 |
|
* in \a pPlaybackState into the buffer pointed by \a pBuffer and moves |
320 |
|
* the position within the sample respectively, this method honors the |
321 |
|
* looping informations of the sample (if any). The sample wave stream |
322 |
|
* will be decompressed on the fly if using a compressed sample. Use this |
323 |
|
* method if you don't want to load the sample into RAM, thus for disk |
324 |
|
* streaming. All this methods needs to know to proceed with streaming |
325 |
|
* for the next time you call this method is stored in \a pPlaybackState. |
326 |
|
* You have to allocate and initialize the playback_state_t structure by |
327 |
|
* yourself before you use it to stream a sample: |
328 |
|
* |
329 |
|
* <i> |
330 |
|
* gig::playback_state_t playbackstate; <br> |
331 |
|
* playbackstate.position = 0; <br> |
332 |
|
* playbackstate.reverse = false; <br> |
333 |
|
* playbackstate.loop_cycles_left = pSample->LoopPlayCount; <br> |
334 |
|
* </i> |
335 |
|
* |
336 |
|
* You don't have to take care of things like if there is actually a loop |
337 |
|
* defined or if the current read position is located within a loop area. |
338 |
|
* The method already handles such cases by itself. |
339 |
|
* |
340 |
|
* @param pBuffer destination buffer |
341 |
|
* @param SampleCount number of sample points to read |
342 |
|
* @param pPlaybackState will be used to store and reload the playback |
343 |
|
* state for the next ReadAndLoop() call |
344 |
|
* @returns number of successfully read sample points |
345 |
|
*/ |
346 |
|
unsigned long Sample::ReadAndLoop(void* pBuffer, unsigned long SampleCount, playback_state_t* pPlaybackState) { |
347 |
|
unsigned long samplestoread = SampleCount, totalreadsamples = 0, readsamples, samplestoloopend; |
348 |
|
uint8_t* pDst = (uint8_t*) pBuffer; |
349 |
|
|
350 |
|
SetPos(pPlaybackState->position); // recover position from the last time |
351 |
|
|
352 |
|
if (this->Loops && GetPos() <= this->LoopEnd) { // honor looping if there are loop points defined |
353 |
|
|
354 |
|
switch (this->LoopType) { |
355 |
|
|
356 |
|
case loop_type_bidirectional: { //TODO: not tested yet! |
357 |
|
do { |
358 |
|
// if not endless loop check if max. number of loop cycles have been passed |
359 |
|
if (this->LoopPlayCount && !pPlaybackState->loop_cycles_left) break; |
360 |
|
|
361 |
|
if (!pPlaybackState->reverse) { // forward playback |
362 |
|
do { |
363 |
|
samplestoloopend = this->LoopEnd - GetPos(); |
364 |
|
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoread, samplestoloopend)); |
365 |
|
samplestoread -= readsamples; |
366 |
|
totalreadsamples += readsamples; |
367 |
|
if (readsamples == samplestoloopend) { |
368 |
|
pPlaybackState->reverse = true; |
369 |
|
break; |
370 |
|
} |
371 |
|
} while (samplestoread && readsamples); |
372 |
|
} |
373 |
|
else { // backward playback |
374 |
|
|
375 |
|
// as we can only read forward from disk, we have to |
376 |
|
// determine the end position within the loop first, |
377 |
|
// read forward from that 'end' and finally after |
378 |
|
// reading, swap all sample frames so it reflects |
379 |
|
// backward playback |
380 |
|
|
381 |
|
unsigned long swapareastart = totalreadsamples; |
382 |
|
unsigned long loopoffset = GetPos() - this->LoopStart; |
383 |
|
unsigned long samplestoreadinloop = Min(samplestoread, loopoffset); |
384 |
|
unsigned long reverseplaybackend = GetPos() - samplestoreadinloop; |
385 |
|
|
386 |
|
SetPos(reverseplaybackend); |
387 |
|
|
388 |
|
// read samples for backward playback |
389 |
|
do { |
390 |
|
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], samplestoreadinloop); |
391 |
|
samplestoreadinloop -= readsamples; |
392 |
|
samplestoread -= readsamples; |
393 |
|
totalreadsamples += readsamples; |
394 |
|
} while (samplestoreadinloop && readsamples); |
395 |
|
|
396 |
|
SetPos(reverseplaybackend); // pretend we really read backwards |
397 |
|
|
398 |
|
if (reverseplaybackend == this->LoopStart) { |
399 |
|
pPlaybackState->loop_cycles_left--; |
400 |
|
pPlaybackState->reverse = false; |
401 |
|
} |
402 |
|
|
403 |
|
// reverse the sample frames for backward playback |
404 |
|
SwapMemoryArea(&pDst[swapareastart * this->FrameSize], (totalreadsamples - swapareastart) * this->FrameSize, this->FrameSize); |
405 |
|
} |
406 |
|
} while (samplestoread && readsamples); |
407 |
|
break; |
408 |
|
} |
409 |
|
|
410 |
|
case loop_type_backward: { // TODO: not tested yet! |
411 |
|
// forward playback (not entered the loop yet) |
412 |
|
if (!pPlaybackState->reverse) do { |
413 |
|
samplestoloopend = this->LoopEnd - GetPos(); |
414 |
|
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoread, samplestoloopend)); |
415 |
|
samplestoread -= readsamples; |
416 |
|
totalreadsamples += readsamples; |
417 |
|
if (readsamples == samplestoloopend) { |
418 |
|
pPlaybackState->reverse = true; |
419 |
|
break; |
420 |
|
} |
421 |
|
} while (samplestoread && readsamples); |
422 |
|
|
423 |
|
if (!samplestoread) break; |
424 |
|
|
425 |
|
// as we can only read forward from disk, we have to |
426 |
|
// determine the end position within the loop first, |
427 |
|
// read forward from that 'end' and finally after |
428 |
|
// reading, swap all sample frames so it reflects |
429 |
|
// backward playback |
430 |
|
|
431 |
|
unsigned long swapareastart = totalreadsamples; |
432 |
|
unsigned long loopoffset = GetPos() - this->LoopStart; |
433 |
|
unsigned long samplestoreadinloop = (this->LoopPlayCount) ? Min(samplestoread, pPlaybackState->loop_cycles_left * LoopSize - loopoffset) |
434 |
|
: samplestoread; |
435 |
|
unsigned long reverseplaybackend = this->LoopStart + Abs((loopoffset - samplestoreadinloop) % this->LoopSize); |
436 |
|
|
437 |
|
SetPos(reverseplaybackend); |
438 |
|
|
439 |
|
// read samples for backward playback |
440 |
|
do { |
441 |
|
// if not endless loop check if max. number of loop cycles have been passed |
442 |
|
if (this->LoopPlayCount && !pPlaybackState->loop_cycles_left) break; |
443 |
|
samplestoloopend = this->LoopEnd - GetPos(); |
444 |
|
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoreadinloop, samplestoloopend)); |
445 |
|
samplestoreadinloop -= readsamples; |
446 |
|
samplestoread -= readsamples; |
447 |
|
totalreadsamples += readsamples; |
448 |
|
if (readsamples == samplestoloopend) { |
449 |
|
pPlaybackState->loop_cycles_left--; |
450 |
|
SetPos(this->LoopStart); |
451 |
|
} |
452 |
|
} while (samplestoreadinloop && readsamples); |
453 |
|
|
454 |
|
SetPos(reverseplaybackend); // pretend we really read backwards |
455 |
|
|
456 |
|
// reverse the sample frames for backward playback |
457 |
|
SwapMemoryArea(&pDst[swapareastart * this->FrameSize], (totalreadsamples - swapareastart) * this->FrameSize, this->FrameSize); |
458 |
|
break; |
459 |
|
} |
460 |
|
|
461 |
|
default: case loop_type_normal: { |
462 |
|
do { |
463 |
|
// if not endless loop check if max. number of loop cycles have been passed |
464 |
|
if (this->LoopPlayCount && !pPlaybackState->loop_cycles_left) break; |
465 |
|
samplestoloopend = this->LoopEnd - GetPos(); |
466 |
|
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoread, samplestoloopend)); |
467 |
|
samplestoread -= readsamples; |
468 |
|
totalreadsamples += readsamples; |
469 |
|
if (readsamples == samplestoloopend) { |
470 |
|
pPlaybackState->loop_cycles_left--; |
471 |
|
SetPos(this->LoopStart); |
472 |
|
} |
473 |
|
} while (samplestoread && readsamples); |
474 |
|
break; |
475 |
|
} |
476 |
|
} |
477 |
|
} |
478 |
|
|
479 |
|
// read on without looping |
480 |
|
if (samplestoread) do { |
481 |
|
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], samplestoread); |
482 |
|
samplestoread -= readsamples; |
483 |
|
totalreadsamples += readsamples; |
484 |
|
} while (readsamples && samplestoread); |
485 |
|
|
486 |
|
// store current position |
487 |
|
pPlaybackState->position = GetPos(); |
488 |
|
|
489 |
|
return totalreadsamples; |
490 |
|
} |
491 |
|
|
492 |
|
/** |
493 |
* Reads \a SampleCount number of sample points from the current |
* Reads \a SampleCount number of sample points from the current |
494 |
* position into the buffer pointed by \a pBuffer and increments the |
* position into the buffer pointed by \a pBuffer and increments the |
495 |
* position within the sample. The sample wave stream will be |
* position within the sample. The sample wave stream will be |