2 |
* * |
* * |
3 |
* libgig - C++ cross-platform Gigasampler format file loader library * |
* libgig - C++ cross-platform Gigasampler format file loader library * |
4 |
* * |
* * |
5 |
* Copyright (C) 2003, 2004 by Christian Schoenebeck * |
* Copyright (C) 2003-2005 by Christian Schoenebeck * |
6 |
* <cuse@users.sourceforge.net> * |
* <cuse@users.sourceforge.net> * |
7 |
* * |
* * |
8 |
* This library is free software; you can redistribute it and/or modify * |
* This library is free software; you can redistribute it and/or modify * |
9 |
* it under the terms of the GNU General Public License as published by * |
* it under the terms of the GNU General Public License as published by * |
23 |
|
|
24 |
#include "gig.h" |
#include "gig.h" |
25 |
|
|
26 |
|
#include <iostream> |
27 |
|
|
28 |
namespace gig { namespace { |
namespace gig { namespace { |
29 |
|
|
30 |
// *************** Internal functions for sample decopmression *************** |
// *************** Internal functions for sample decopmression *************** |
203 |
// *************** Sample *************** |
// *************** Sample *************** |
204 |
// * |
// * |
205 |
|
|
206 |
unsigned int Sample::Instances = 0; |
unsigned int Sample::Instances = 0; |
207 |
unsigned char* Sample::pDecompressionBuffer = NULL; |
buffer_t Sample::InternalDecompressionBuffer; |
|
unsigned long Sample::DecompressionBufferSize = 0; |
|
208 |
|
|
209 |
Sample::Sample(File* pFile, RIFF::List* waveList, unsigned long WavePoolOffset) : DLS::Sample((DLS::File*) pFile, waveList, WavePoolOffset) { |
Sample::Sample(File* pFile, RIFF::List* waveList, unsigned long WavePoolOffset) : DLS::Sample((DLS::File*) pFile, waveList, WavePoolOffset) { |
210 |
Instances++; |
Instances++; |
245 |
} |
} |
246 |
|
|
247 |
// we use a buffer for decompression and for truncating 24 bit samples to 16 bit |
// we use a buffer for decompression and for truncating 24 bit samples to 16 bit |
248 |
if ((Compressed || BitDepth == 24) && !pDecompressionBuffer) { |
if ((Compressed || BitDepth == 24) && !InternalDecompressionBuffer.Size) { |
249 |
pDecompressionBuffer = new unsigned char[INITIAL_SAMPLE_BUFFER_SIZE]; |
InternalDecompressionBuffer.pStart = new unsigned char[INITIAL_SAMPLE_BUFFER_SIZE]; |
250 |
DecompressionBufferSize = INITIAL_SAMPLE_BUFFER_SIZE; |
InternalDecompressionBuffer.Size = INITIAL_SAMPLE_BUFFER_SIZE; |
251 |
} |
} |
252 |
FrameOffset = 0; // just for streaming compressed samples |
FrameOffset = 0; // just for streaming compressed samples |
253 |
|
|
261 |
std::list<unsigned long> frameOffsets; |
std::list<unsigned long> frameOffsets; |
262 |
|
|
263 |
SamplesPerFrame = BitDepth == 24 ? 256 : 2048; |
SamplesPerFrame = BitDepth == 24 ? 256 : 2048; |
264 |
WorstCaseFrameSize = SamplesPerFrame * FrameSize + Channels; |
WorstCaseFrameSize = SamplesPerFrame * FrameSize + Channels; // +Channels for compression flag |
265 |
|
|
266 |
// Scanning |
// Scanning |
267 |
pCkData->SetPos(0); |
pCkData->SetPos(0); |
342 |
* that will be returned to determine the actual cached samples, but note |
* that will be returned to determine the actual cached samples, but note |
343 |
* that the size is given in bytes! You get the number of actually cached |
* that the size is given in bytes! You get the number of actually cached |
344 |
* samples by dividing it by the frame size of the sample: |
* samples by dividing it by the frame size of the sample: |
345 |
* |
* @code |
346 |
* buffer_t buf = pSample->LoadSampleData(acquired_samples); |
* buffer_t buf = pSample->LoadSampleData(acquired_samples); |
347 |
* long cachedsamples = buf.Size / pSample->FrameSize; |
* long cachedsamples = buf.Size / pSample->FrameSize; |
348 |
|
* @endcode |
349 |
* |
* |
350 |
* @param SampleCount - number of sample points to load into RAM |
* @param SampleCount - number of sample points to load into RAM |
351 |
* @returns buffer_t structure with start address and size of |
* @returns buffer_t structure with start address and size of |
391 |
* that will be returned to determine the actual cached samples, but note |
* that will be returned to determine the actual cached samples, but note |
392 |
* that the size is given in bytes! You get the number of actually cached |
* that the size is given in bytes! You get the number of actually cached |
393 |
* samples by dividing it by the frame size of the sample: |
* samples by dividing it by the frame size of the sample: |
394 |
* |
* @code |
395 |
* buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(acquired_samples, null_samples); |
* buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(acquired_samples, null_samples); |
396 |
* long cachedsamples = buf.Size / pSample->FrameSize; |
* long cachedsamples = buf.Size / pSample->FrameSize; |
397 |
* |
* @endcode |
398 |
* The method will add \a NullSamplesCount silence samples past the |
* The method will add \a NullSamplesCount silence samples past the |
399 |
* official buffer end (this won't affect the 'Size' member of the |
* official buffer end (this won't affect the 'Size' member of the |
400 |
* buffer_t structure, that means 'Size' always reflects the size of the |
* buffer_t structure, that means 'Size' always reflects the size of the |
525 |
* for the next time you call this method is stored in \a pPlaybackState. |
* for the next time you call this method is stored in \a pPlaybackState. |
526 |
* You have to allocate and initialize the playback_state_t structure by |
* You have to allocate and initialize the playback_state_t structure by |
527 |
* yourself before you use it to stream a sample: |
* yourself before you use it to stream a sample: |
528 |
* |
* @code |
529 |
* <i> |
* gig::playback_state_t playbackstate; |
530 |
* gig::playback_state_t playbackstate; <br> |
* playbackstate.position = 0; |
531 |
* playbackstate.position = 0; <br> |
* playbackstate.reverse = false; |
532 |
* playbackstate.reverse = false; <br> |
* playbackstate.loop_cycles_left = pSample->LoopPlayCount; |
533 |
* playbackstate.loop_cycles_left = pSample->LoopPlayCount; <br> |
* @endcode |
|
* </i> |
|
|
* |
|
534 |
* You don't have to take care of things like if there is actually a loop |
* You don't have to take care of things like if there is actually a loop |
535 |
* defined or if the current read position is located within a loop area. |
* defined or if the current read position is located within a loop area. |
536 |
* The method already handles such cases by itself. |
* The method already handles such cases by itself. |
537 |
* |
* |
538 |
|
* <b>Caution:</b> If you are using more than one streaming thread, you |
539 |
|
* have to use an external decompression buffer for <b>EACH</b> |
540 |
|
* streaming thread to avoid race conditions and crashes! |
541 |
|
* |
542 |
* @param pBuffer destination buffer |
* @param pBuffer destination buffer |
543 |
* @param SampleCount number of sample points to read |
* @param SampleCount number of sample points to read |
544 |
* @param pPlaybackState will be used to store and reload the playback |
* @param pPlaybackState will be used to store and reload the playback |
545 |
* state for the next ReadAndLoop() call |
* state for the next ReadAndLoop() call |
546 |
|
* @param pExternalDecompressionBuffer (optional) external buffer to use for decompression |
547 |
* @returns number of successfully read sample points |
* @returns number of successfully read sample points |
548 |
|
* @see CreateDecompressionBuffer() |
549 |
*/ |
*/ |
550 |
unsigned long Sample::ReadAndLoop(void* pBuffer, unsigned long SampleCount, playback_state_t* pPlaybackState) { |
unsigned long Sample::ReadAndLoop(void* pBuffer, unsigned long SampleCount, playback_state_t* pPlaybackState, buffer_t* pExternalDecompressionBuffer) { |
551 |
unsigned long samplestoread = SampleCount, totalreadsamples = 0, readsamples, samplestoloopend; |
unsigned long samplestoread = SampleCount, totalreadsamples = 0, readsamples, samplestoloopend; |
552 |
uint8_t* pDst = (uint8_t*) pBuffer; |
uint8_t* pDst = (uint8_t*) pBuffer; |
553 |
|
|
565 |
if (!pPlaybackState->reverse) { // forward playback |
if (!pPlaybackState->reverse) { // forward playback |
566 |
do { |
do { |
567 |
samplestoloopend = this->LoopEnd - GetPos(); |
samplestoloopend = this->LoopEnd - GetPos(); |
568 |
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoread, samplestoloopend)); |
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoread, samplestoloopend), pExternalDecompressionBuffer); |
569 |
samplestoread -= readsamples; |
samplestoread -= readsamples; |
570 |
totalreadsamples += readsamples; |
totalreadsamples += readsamples; |
571 |
if (readsamples == samplestoloopend) { |
if (readsamples == samplestoloopend) { |
591 |
|
|
592 |
// read samples for backward playback |
// read samples for backward playback |
593 |
do { |
do { |
594 |
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], samplestoreadinloop); |
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], samplestoreadinloop, pExternalDecompressionBuffer); |
595 |
samplestoreadinloop -= readsamples; |
samplestoreadinloop -= readsamples; |
596 |
samplestoread -= readsamples; |
samplestoread -= readsamples; |
597 |
totalreadsamples += readsamples; |
totalreadsamples += readsamples; |
615 |
// forward playback (not entered the loop yet) |
// forward playback (not entered the loop yet) |
616 |
if (!pPlaybackState->reverse) do { |
if (!pPlaybackState->reverse) do { |
617 |
samplestoloopend = this->LoopEnd - GetPos(); |
samplestoloopend = this->LoopEnd - GetPos(); |
618 |
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoread, samplestoloopend)); |
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoread, samplestoloopend), pExternalDecompressionBuffer); |
619 |
samplestoread -= readsamples; |
samplestoread -= readsamples; |
620 |
totalreadsamples += readsamples; |
totalreadsamples += readsamples; |
621 |
if (readsamples == samplestoloopend) { |
if (readsamples == samplestoloopend) { |
645 |
// if not endless loop check if max. number of loop cycles have been passed |
// if not endless loop check if max. number of loop cycles have been passed |
646 |
if (this->LoopPlayCount && !pPlaybackState->loop_cycles_left) break; |
if (this->LoopPlayCount && !pPlaybackState->loop_cycles_left) break; |
647 |
samplestoloopend = this->LoopEnd - GetPos(); |
samplestoloopend = this->LoopEnd - GetPos(); |
648 |
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoreadinloop, samplestoloopend)); |
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoreadinloop, samplestoloopend), pExternalDecompressionBuffer); |
649 |
samplestoreadinloop -= readsamples; |
samplestoreadinloop -= readsamples; |
650 |
samplestoread -= readsamples; |
samplestoread -= readsamples; |
651 |
totalreadsamples += readsamples; |
totalreadsamples += readsamples; |
667 |
// if not endless loop check if max. number of loop cycles have been passed |
// if not endless loop check if max. number of loop cycles have been passed |
668 |
if (this->LoopPlayCount && !pPlaybackState->loop_cycles_left) break; |
if (this->LoopPlayCount && !pPlaybackState->loop_cycles_left) break; |
669 |
samplestoloopend = this->LoopEnd - GetPos(); |
samplestoloopend = this->LoopEnd - GetPos(); |
670 |
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoread, samplestoloopend)); |
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoread, samplestoloopend), pExternalDecompressionBuffer); |
671 |
samplestoread -= readsamples; |
samplestoread -= readsamples; |
672 |
totalreadsamples += readsamples; |
totalreadsamples += readsamples; |
673 |
if (readsamples == samplestoloopend) { |
if (readsamples == samplestoloopend) { |
682 |
|
|
683 |
// read on without looping |
// read on without looping |
684 |
if (samplestoread) do { |
if (samplestoread) do { |
685 |
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], samplestoread); |
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], samplestoread, pExternalDecompressionBuffer); |
686 |
samplestoread -= readsamples; |
samplestoread -= readsamples; |
687 |
totalreadsamples += readsamples; |
totalreadsamples += readsamples; |
688 |
} while (readsamples && samplestoread); |
} while (readsamples && samplestoread); |
701 |
* and <i>SetPos()</i> if you don't want to load the sample into RAM, |
* and <i>SetPos()</i> if you don't want to load the sample into RAM, |
702 |
* thus for disk streaming. |
* thus for disk streaming. |
703 |
* |
* |
704 |
|
* <b>Caution:</b> If you are using more than one streaming thread, you |
705 |
|
* have to use an external decompression buffer for <b>EACH</b> |
706 |
|
* streaming thread to avoid race conditions and crashes! |
707 |
|
* |
708 |
* @param pBuffer destination buffer |
* @param pBuffer destination buffer |
709 |
* @param SampleCount number of sample points to read |
* @param SampleCount number of sample points to read |
710 |
|
* @param pExternalDecompressionBuffer (optional) external buffer to use for decompression |
711 |
* @returns number of successfully read sample points |
* @returns number of successfully read sample points |
712 |
* @see SetPos() |
* @see SetPos(), CreateDecompressionBuffer() |
713 |
*/ |
*/ |
714 |
unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) { |
unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount, buffer_t* pExternalDecompressionBuffer) { |
715 |
if (SampleCount == 0) return 0; |
if (SampleCount == 0) return 0; |
716 |
if (!Compressed) { |
if (!Compressed) { |
717 |
if (BitDepth == 24) { |
if (BitDepth == 24) { |
718 |
// 24 bit sample. For now just truncate to 16 bit. |
// 24 bit sample. For now just truncate to 16 bit. |
719 |
unsigned char* pSrc = this->pDecompressionBuffer; |
unsigned char* pSrc = (unsigned char*) ((pExternalDecompressionBuffer) ? pExternalDecompressionBuffer->pStart : this->InternalDecompressionBuffer.pStart); |
720 |
int16_t* pDst = static_cast<int16_t*>(pBuffer); |
int16_t* pDst = static_cast<int16_t*>(pBuffer); |
721 |
if (Channels == 2) { // Stereo |
if (Channels == 2) { // Stereo |
722 |
unsigned long readBytes = pCkData->Read(pSrc, SampleCount * 6, 1); |
unsigned long readBytes = pCkData->Read(pSrc, SampleCount * 6, 1); |
753 |
currentframeoffset = this->FrameOffset; // offset in current sample frame since last Read() |
currentframeoffset = this->FrameOffset; // offset in current sample frame since last Read() |
754 |
this->FrameOffset = 0; |
this->FrameOffset = 0; |
755 |
|
|
756 |
if (assumedsize > this->DecompressionBufferSize) { |
buffer_t* pDecompressionBuffer = (pExternalDecompressionBuffer) ? pExternalDecompressionBuffer : &InternalDecompressionBuffer; |
757 |
// local buffer reallocation - hope this won't happen |
|
758 |
if (this->pDecompressionBuffer) delete[] this->pDecompressionBuffer; |
// if decompression buffer too small, then reduce amount of samples to read |
759 |
this->pDecompressionBuffer = new unsigned char[assumedsize << 1]; // double of current needed size |
if (pDecompressionBuffer->Size < assumedsize) { |
760 |
this->DecompressionBufferSize = assumedsize << 1; |
std::cerr << "gig::Read(): WARNING - decompression buffer size too small!" << std::endl; |
761 |
|
SampleCount = WorstCaseMaxSamples(pDecompressionBuffer); |
762 |
|
remainingsamples = SampleCount; |
763 |
|
assumedsize = GuessSize(SampleCount); |
764 |
} |
} |
765 |
|
|
766 |
unsigned char* pSrc = this->pDecompressionBuffer; |
unsigned char* pSrc = (unsigned char*) pDecompressionBuffer->pStart; |
767 |
int16_t* pDst = static_cast<int16_t*>(pBuffer); |
int16_t* pDst = static_cast<int16_t*>(pBuffer); |
768 |
remainingbytes = pCkData->Read(pSrc, assumedsize, 1); |
remainingbytes = pCkData->Read(pSrc, assumedsize, 1); |
769 |
|
|
884 |
assumedsize = GuessSize(remainingsamples); |
assumedsize = GuessSize(remainingsamples); |
885 |
pCkData->SetPos(remainingbytes, RIFF::stream_backward); |
pCkData->SetPos(remainingbytes, RIFF::stream_backward); |
886 |
if (pCkData->RemainingBytes() < assumedsize) assumedsize = pCkData->RemainingBytes(); |
if (pCkData->RemainingBytes() < assumedsize) assumedsize = pCkData->RemainingBytes(); |
887 |
remainingbytes = pCkData->Read(this->pDecompressionBuffer, assumedsize, 1); |
remainingbytes = pCkData->Read(pDecompressionBuffer->pStart, assumedsize, 1); |
888 |
pSrc = this->pDecompressionBuffer; |
pSrc = (unsigned char*) pDecompressionBuffer->pStart; |
889 |
} |
} |
890 |
} // while |
} // while |
891 |
|
|
895 |
} |
} |
896 |
} |
} |
897 |
|
|
898 |
|
/** |
899 |
|
* Allocates a decompression buffer for streaming (compressed) samples |
900 |
|
* with Sample::Read(). If you are using more than one streaming thread |
901 |
|
* in your application you <b>HAVE</b> to create a decompression buffer |
902 |
|
* for <b>EACH</b> of your streaming threads and provide it with the |
903 |
|
* Sample::Read() call in order to avoid race conditions and crashes. |
904 |
|
* |
905 |
|
* You should free the memory occupied by the allocated buffer(s) once |
906 |
|
* you don't need one of your streaming threads anymore by calling |
907 |
|
* DestroyDecompressionBuffer(). |
908 |
|
* |
909 |
|
* @param MaxReadSize - the maximum size (in sample points) you ever |
910 |
|
* expect to read with one Read() call |
911 |
|
* @returns allocated decompression buffer |
912 |
|
* @see DestroyDecompressionBuffer() |
913 |
|
*/ |
914 |
|
buffer_t Sample::CreateDecompressionBuffer(unsigned long MaxReadSize) { |
915 |
|
buffer_t result; |
916 |
|
const double worstCaseHeaderOverhead = |
917 |
|
(256.0 /*frame size*/ + 12.0 /*header*/ + 2.0 /*compression type flag (stereo)*/) / 256.0; |
918 |
|
result.Size = (unsigned long) (double(MaxReadSize) * 3.0 /*(24 Bit)*/ * 2.0 /*stereo*/ * worstCaseHeaderOverhead); |
919 |
|
result.pStart = new int8_t[result.Size]; |
920 |
|
result.NullExtensionSize = 0; |
921 |
|
return result; |
922 |
|
} |
923 |
|
|
924 |
|
/** |
925 |
|
* Free decompression buffer, previously created with |
926 |
|
* CreateDecompressionBuffer(). |
927 |
|
* |
928 |
|
* @param DecompressionBuffer - previously allocated decompression |
929 |
|
* buffer to free |
930 |
|
*/ |
931 |
|
void Sample::DestroyDecompressionBuffer(buffer_t& DecompressionBuffer) { |
932 |
|
if (DecompressionBuffer.Size && DecompressionBuffer.pStart) { |
933 |
|
delete[] (int8_t*) DecompressionBuffer.pStart; |
934 |
|
DecompressionBuffer.pStart = NULL; |
935 |
|
DecompressionBuffer.Size = 0; |
936 |
|
DecompressionBuffer.NullExtensionSize = 0; |
937 |
|
} |
938 |
|
} |
939 |
|
|
940 |
Sample::~Sample() { |
Sample::~Sample() { |
941 |
Instances--; |
Instances--; |
942 |
if (!Instances && pDecompressionBuffer) { |
if (!Instances && InternalDecompressionBuffer.Size) { |
943 |
delete[] pDecompressionBuffer; |
delete[] (unsigned char*) InternalDecompressionBuffer.pStart; |
944 |
pDecompressionBuffer = NULL; |
InternalDecompressionBuffer.pStart = NULL; |
945 |
|
InternalDecompressionBuffer.Size = 0; |
946 |
} |
} |
947 |
if (FrameTable) delete[] FrameTable; |
if (FrameTable) delete[] FrameTable; |
948 |
if (RAMCache.pStart) delete[] (int8_t*) RAMCache.pStart; |
if (RAMCache.pStart) delete[] (int8_t*) RAMCache.pStart; |