--- libgig/trunk/src/gig.cpp 2005/02/23 19:11:07 406 +++ libgig/trunk/src/gig.cpp 2005/05/07 20:19:10 515 @@ -25,11 +25,42 @@ #include -namespace gig { namespace { +namespace gig { + +// *************** progress_t *************** +// * + + progress_t::progress_t() { + callback = NULL; + __range_min = 0.0f; + __range_max = 1.0f; + } + + // private helper function to convert progress of a subprocess into the global progress + static void __notify_progress(progress_t* pProgress, float subprogress) { + if (pProgress && pProgress->callback) { + const float totalrange = pProgress->__range_max - pProgress->__range_min; + const float totalprogress = pProgress->__range_min + subprogress * totalrange; + pProgress->callback(totalprogress); // now actually notify about the progress + } + } + + // private helper function to divide a progress into subprogresses + static void __divide_progress(progress_t* pParentProgress, progress_t* pSubProgress, float totalTasks, float currentTask) { + if (pParentProgress && pParentProgress->callback) { + const float totalrange = pParentProgress->__range_max - pParentProgress->__range_min; + pSubProgress->callback = pParentProgress->callback; + pSubProgress->__range_min = pParentProgress->__range_min + totalrange * currentTask / totalTasks; + pSubProgress->__range_max = pSubProgress->__range_min + totalrange / totalTasks; + } + } + // *************** Internal functions for sample decopmression *************** // * +namespace { + inline int get12lo(const unsigned char* pSrc) { const int x = pSrc[0] | (pSrc[1] & 0x0f) << 8; @@ -94,7 +125,7 @@ void Decompress24(int compressionmode, const unsigned char* params, int dstStep, const unsigned char* pSrc, int16_t* pDst, unsigned long currentframeoffset, - unsigned long copysamples) + unsigned long copysamples, int truncatedBits) { // Note: The 24 bits are truncated to 16 bits for now. @@ -106,11 +137,14 @@ // // Strange thing #2: The formula in SKIP_ONE gives values for // y that are twice as high as they should be. That's why - // COPY_ONE shifts 9 steps instead of 8, and also why y is + // COPY_ONE shifts an extra step, and also why y is // initialized with a sum instead of a mean value. int y, dy, ddy; + const int shift = 8 - truncatedBits; + const int shift1 = shift + 1; + #define GET_PARAMS(params) \ y = (get24(params) + get24((params) + 3)); \ dy = get24((params) + 6); \ @@ -123,14 +157,14 @@ #define COPY_ONE(x) \ SKIP_ONE(x); \ - *pDst = y >> 9; \ + *pDst = y >> shift1; \ pDst += dstStep switch (compressionmode) { case 2: // 24 bit uncompressed pSrc += currentframeoffset * 3; while (copysamples) { - *pDst = get24(pSrc) >> 8; + *pDst = get24(pSrc) >> shift; pDst += dstStep; pSrc += 3; copysamples--; @@ -239,8 +273,17 @@ if (BitDepth > 24) throw gig::Exception("Only samples up to 24 bit supported"); - Compressed = (waveList->GetSubChunk(CHUNK_ID_EWAV)); + RIFF::Chunk* ewav = waveList->GetSubChunk(CHUNK_ID_EWAV); + Compressed = ewav; + Dithered = false; + TruncatedBits = 0; if (Compressed) { + uint32_t version = ewav->ReadInt32(); + if (version == 3 && BitDepth == 24) { + Dithered = ewav->ReadInt32(); + ewav->SetPos(Channels == 2 ? 84 : 64); + TruncatedBits = ewav->ReadInt32(); + } ScanCompressedSample(); } @@ -249,7 +292,7 @@ InternalDecompressionBuffer.pStart = new unsigned char[INITIAL_SAMPLE_BUFFER_SIZE]; InternalDecompressionBuffer.Size = INITIAL_SAMPLE_BUFFER_SIZE; } - FrameOffset = 0; // just for streaming compressed samples + FrameOffset = 0; // just for streaming compressed samples LoopSize = LoopEnd - LoopStart; } @@ -846,13 +889,15 @@ const unsigned char* const param_r = pSrc; if (mode_r != 2) pSrc += 12; - Decompress24(mode_l, param_l, 2, pSrc, pDst, skipsamples, copysamples); + Decompress24(mode_l, param_l, 2, pSrc, pDst, + skipsamples, copysamples, TruncatedBits); Decompress24(mode_r, param_r, 2, pSrc + rightChannelOffset, pDst + 1, - skipsamples, copysamples); + skipsamples, copysamples, TruncatedBits); pDst += copysamples << 1; } else { // Mono - Decompress24(mode_l, param_l, 1, pSrc, pDst, skipsamples, copysamples); + Decompress24(mode_l, param_l, 1, pSrc, pDst, + skipsamples, copysamples, TruncatedBits); pDst += copysamples; } } @@ -1378,8 +1423,10 @@ pDimensionDefinitions[i].zones = 0x01 << bits; // = pow(2,bits) pDimensionDefinitions[i].split_type = (dimension == dimension_layer || dimension == dimension_samplechannel || - dimension == dimension_releasetrigger) ? split_type_bit - : split_type_normal; + dimension == dimension_releasetrigger || + dimension == dimension_roundrobin || + dimension == dimension_random) ? split_type_bit + : split_type_normal; pDimensionDefinitions[i].ranges = NULL; // it's not possible to check velocity dimensions for custom defined ranges at this point pDimensionDefinitions[i].zone_size = (pDimensionDefinitions[i].split_type == split_type_normal) ? 128 / pDimensionDefinitions[i].zones @@ -1535,11 +1582,11 @@ else return static_cast(pSample = GetSampleFromWavePool(WavePoolTableIndex)); } - Sample* Region::GetSampleFromWavePool(unsigned int WavePoolTableIndex) { + Sample* Region::GetSampleFromWavePool(unsigned int WavePoolTableIndex, progress_t* pProgress) { if ((int32_t)WavePoolTableIndex == -1) return NULL; File* file = (File*) GetParent()->GetParent(); unsigned long soughtoffset = file->pWavePoolTable[WavePoolTableIndex]; - Sample* sample = file->GetFirstSample(); + Sample* sample = file->GetFirstSample(pProgress); while (sample) { if (sample->ulWavePoolOffset == soughtoffset) return static_cast(pSample = sample); sample = file->GetNextSample(); @@ -1552,7 +1599,7 @@ // *************** Instrument *************** // * - Instrument::Instrument(File* pFile, RIFF::List* insList) : DLS::Instrument((DLS::File*)pFile, insList) { + Instrument::Instrument(File* pFile, RIFF::List* insList, progress_t* pProgress) : DLS::Instrument((DLS::File*)pFile, insList) { // Initialization for (int i = 0; i < 128; i++) RegionKeyTable[i] = NULL; RegionIndex = -1; @@ -1583,6 +1630,7 @@ unsigned int iRegion = 0; while (rgn) { if (rgn->GetListType() == LIST_TYPE_RGN) { + __notify_progress(pProgress, (float) iRegion / (float) Regions); pRegions[iRegion] = new Region(this, rgn); iRegion++; } @@ -1595,6 +1643,8 @@ RegionKeyTable[iKey] = pRegions[iReg]; } } + + __notify_progress(pProgress, 1.0f); // notify done } Instrument::~Instrument() { @@ -1683,8 +1733,8 @@ } } - Sample* File::GetFirstSample() { - if (!pSamples) LoadSamples(); + Sample* File::GetFirstSample(progress_t* pProgress) { + if (!pSamples) LoadSamples(pProgress); if (!pSamples) return NULL; SamplesIterator = pSamples->begin(); return static_cast( (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL ); @@ -1696,19 +1746,30 @@ return static_cast( (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL ); } - void File::LoadSamples() { + void File::LoadSamples(progress_t* pProgress) { RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL); if (wvpl) { + // just for progress calculation + int iSampleIndex = 0; + int iTotalSamples = wvpl->CountSubLists(LIST_TYPE_WAVE); + unsigned long wvplFileOffset = wvpl->GetFilePos(); RIFF::List* wave = wvpl->GetFirstSubList(); while (wave) { if (wave->GetListType() == LIST_TYPE_WAVE) { + // notify current progress + const float subprogress = (float) iSampleIndex / (float) iTotalSamples; + __notify_progress(pProgress, subprogress); + if (!pSamples) pSamples = new SampleList; unsigned long waveFileOffset = wave->GetFilePos(); pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset)); + + iSampleIndex++; } wave = wvpl->GetNextSubList(); } + __notify_progress(pProgress, 1.0); // notify done } else throw gig::Exception("Mandatory chunk not found."); } @@ -1729,10 +1790,30 @@ /** * Returns the instrument with the given index. * + * @param index - number of the sought instrument (0..n) + * @param pProgress - optional: callback function for progress notification * @returns sought instrument or NULL if there's no such instrument */ - Instrument* File::GetInstrument(uint index) { - if (!pInstruments) LoadInstruments(); + Instrument* File::GetInstrument(uint index, progress_t* pProgress) { + if (!pInstruments) { + // TODO: hack - we simply load ALL samples here, it would have been done in the Region constructor anyway (ATM) + + // sample loading subtask + progress_t subprogress; + __divide_progress(pProgress, &subprogress, 3.0f, 0.0f); // randomly schedule 33% for this subtask + __notify_progress(&subprogress, 0.0f); + GetFirstSample(&subprogress); // now force all samples to be loaded + __notify_progress(&subprogress, 1.0f); + + // instrument loading subtask + if (pProgress && pProgress->callback) { + subprogress.__range_min = subprogress.__range_max; + subprogress.__range_max = pProgress->__range_max; // schedule remaining percentage for this subtask + } + __notify_progress(&subprogress, 0.0f); + LoadInstruments(&subprogress); + __notify_progress(&subprogress, 1.0f); + } if (!pInstruments) return NULL; InstrumentsIterator = pInstruments->begin(); for (uint i = 0; InstrumentsIterator != pInstruments->end(); i++) { @@ -1742,17 +1823,29 @@ return NULL; } - void File::LoadInstruments() { + void File::LoadInstruments(progress_t* pProgress) { RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS); if (lstInstruments) { + int iInstrumentIndex = 0; RIFF::List* lstInstr = lstInstruments->GetFirstSubList(); while (lstInstr) { if (lstInstr->GetListType() == LIST_TYPE_INS) { + // notify current progress + const float localProgress = (float) iInstrumentIndex / (float) Instruments; + __notify_progress(pProgress, localProgress); + + // divide local progress into subprogress for loading current Instrument + progress_t subprogress; + __divide_progress(pProgress, &subprogress, Instruments, iInstrumentIndex); + if (!pInstruments) pInstruments = new InstrumentList; - pInstruments->push_back(new Instrument(this, lstInstr)); + pInstruments->push_back(new Instrument(this, lstInstr, &subprogress)); + + iInstrumentIndex++; } lstInstr = lstInstruments->GetNextSubList(); } + __notify_progress(pProgress, 1.0); // notify done } else throw gig::Exception("Mandatory list chunk not found."); }