--- libgig/trunk/src/gig.cpp 2005/05/07 21:24:04 516 +++ libgig/trunk/src/gig.cpp 2005/09/18 12:41:56 774 @@ -132,35 +132,24 @@ { // Note: The 24 bits are truncated to 16 bits for now. - // Note: The calculation of the initial value of y is strange - // and not 100% correct. What should the first two parameters - // really be used for? Why are they two? The correct value for - // y seems to lie somewhere between the values of the first - // two parameters. - // - // 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 an extra step, and also why y is - // initialized with a sum instead of a mean value. - - int y, dy, ddy; - + int y, dy, ddy, dddy; const int shift = 8 - truncatedBits; - const int shift1 = shift + 1; -#define GET_PARAMS(params) \ - y = (get24(params) + get24((params) + 3)); \ - dy = get24((params) + 6); \ - ddy = get24((params) + 9) +#define GET_PARAMS(params) \ + y = get24(params); \ + dy = y - get24((params) + 3); \ + ddy = get24((params) + 6); \ + dddy = get24((params) + 9) #define SKIP_ONE(x) \ - ddy -= (x); \ - dy -= ddy; \ - y -= dy + dddy -= (x); \ + ddy -= dddy; \ + dy = -dy - ddy; \ + y += dy #define COPY_ONE(x) \ SKIP_ONE(x); \ - *pDst = y >> shift1; \ + *pDst = y >> shift; \ pDst += dstStep switch (compressionmode) { @@ -243,8 +232,9 @@ unsigned int Sample::Instances = 0; buffer_t Sample::InternalDecompressionBuffer; - 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, unsigned long fileNo) : DLS::Sample((DLS::File*) pFile, waveList, WavePoolOffset) { Instances++; + FileNo = fileNo; RIFF::Chunk* _3gix = waveList->GetSubChunk(CHUNK_ID_3GIX); if (!_3gix) throw gig::Exception("Mandatory chunks in list chunk not found."); @@ -1144,7 +1134,9 @@ VCFEnabled = vcfcutoff & 0x80; // bit 7 VCFCutoff = vcfcutoff & 0x7f; // lower 7 bits VCFCutoffController = static_cast(_3ewa->ReadUint8()); - VCFVelocityScale = _3ewa->ReadUint8(); + uint8_t vcfvelscale = _3ewa->ReadUint8(); + VCFCutoffControllerInvert = vcfvelscale & 0x80; // bit 7 + VCFVelocityScale = vcfvelscale & 0x7f; // lower 7 bits _3ewa->ReadInt8(); // unknown uint8_t vcfresonance = _3ewa->ReadUint8(); VCFResonance = vcfresonance & 0x7f; // lower 7 bits @@ -1161,20 +1153,53 @@ VCFType = vcf_type_lowpassturbo; } - // get the corresponding velocity->volume table from the table map or create & calculate that table if it doesn't exist yet - uint32_t tableKey = (VelocityResponseCurve<<16) | (VelocityResponseDepth<<8) | VelocityResponseCurveScaling; + pVelocityAttenuationTable = GetVelocityTable(VelocityResponseCurve, + VelocityResponseDepth, + VelocityResponseCurveScaling); + + curve_type_t curveType = ReleaseVelocityResponseCurve; + uint8_t depth = ReleaseVelocityResponseDepth; + + // this models a strange behaviour or bug in GSt: two of the + // velocity response curves for release time are not used even + // if specified, instead another curve is chosen. + if ((curveType == curve_type_nonlinear && depth == 0) || + (curveType == curve_type_special && depth == 4)) { + curveType = curve_type_nonlinear; + depth = 3; + } + pVelocityReleaseTable = GetVelocityTable(curveType, depth, 0); + + curveType = VCFVelocityCurve; + depth = VCFVelocityDynamicRange; + + // even stranger GSt: two of the velocity response curves for + // filter cutoff are not used, instead another special curve + // is chosen. This curve is not used anywhere else. + if ((curveType == curve_type_nonlinear && depth == 0) || + (curveType == curve_type_special && depth == 4)) { + curveType = curve_type_special; + depth = 5; + } + pVelocityCutoffTable = GetVelocityTable(curveType, depth, + VCFCutoffController <= vcf_cutoff_ctrl_none2 ? VCFVelocityScale : 0); + + SampleAttenuation = pow(10.0, -Gain / (20.0 * 655360)); + } + + // get the corresponding velocity table from the table map or create & calculate that table if it doesn't exist yet + double* DimensionRegion::GetVelocityTable(curve_type_t curveType, uint8_t depth, uint8_t scaling) + { + double* table; + uint32_t tableKey = (curveType<<16) | (depth<<8) | scaling; if (pVelocityTables->count(tableKey)) { // if key exists - pVelocityAttenuationTable = (*pVelocityTables)[tableKey]; + table = (*pVelocityTables)[tableKey]; } else { - pVelocityAttenuationTable = - CreateVelocityTable(VelocityResponseCurve, - VelocityResponseDepth, - VelocityResponseCurveScaling); - (*pVelocityTables)[tableKey] = pVelocityAttenuationTable; // put the new table into the tables map + table = CreateVelocityTable(curveType, depth, scaling); + (*pVelocityTables)[tableKey] = table; // put the new table into the tables map } - - SampleAttenuation = pow(10.0, -Gain / (20.0 * 655360)); + return table; } leverage_ctrl_t DimensionRegion::DecodeLeverageController(_lev_ctrl_t EncodedController) { @@ -1325,6 +1350,14 @@ return pVelocityAttenuationTable[MIDIKeyVelocity]; } + double DimensionRegion::GetVelocityRelease(uint8_t MIDIKeyVelocity) { + return pVelocityReleaseTable[MIDIKeyVelocity]; + } + + double DimensionRegion::GetVelocityCutoff(uint8_t MIDIKeyVelocity) { + return pVelocityCutoffTable[MIDIKeyVelocity]; + } + double* DimensionRegion::CreateVelocityTable(curve_type_t curveType, uint8_t depth, uint8_t scaling) { // line-segment approximations of the 15 velocity curves @@ -1358,9 +1391,13 @@ const int spe4[] = { 1, 4, 23, 5, 49, 13, 57, 17, 92, 57, 122, 127, 127, 127 }; + // this is only used by the VCF velocity curve + const int spe5[] = { 1, 2, 30, 5, 60, 19, 77, 70, 83, 85, 88, 106, + 91, 127, 127, 127 }; + const int* const curves[] = { non0, non1, non2, non3, non4, lin0, lin1, lin2, lin3, lin4, - spe0, spe1, spe2, spe3, spe4 }; + spe0, spe1, spe2, spe3, spe4, spe5 }; double* const table = new double[128]; @@ -1412,6 +1449,9 @@ for (int i = 0; i < dimensionBits; i++) { dimension_t dimension = static_cast(_3lnk->ReadUint8()); uint8_t bits = _3lnk->ReadUint8(); + _3lnk->ReadUint8(); // probably the position of the dimension + _3lnk->ReadUint8(); // unknown + uint8_t zones = _3lnk->ReadUint8(); // new for v3: number of zones doesn't have to be == pow(2,bits) if (dimension == dimension_none) { // inactive dimension pDimensionDefinitions[i].dimension = dimension_none; pDimensionDefinitions[i].bits = 0; @@ -1423,7 +1463,7 @@ else { // active dimension pDimensionDefinitions[i].dimension = dimension; pDimensionDefinitions[i].bits = bits; - pDimensionDefinitions[i].zones = 0x01 << bits; // = pow(2,bits) + pDimensionDefinitions[i].zones = zones ? zones : 0x01 << bits; // = pow(2,bits) pDimensionDefinitions[i].split_type = (dimension == dimension_layer || dimension == dimension_samplechannel || dimension == dimension_releasetrigger || @@ -1432,14 +1472,14 @@ : 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 + (pDimensionDefinitions[i].split_type == split_type_normal) ? 128.0 / pDimensionDefinitions[i].zones : 0; Dimensions++; // if this is a layer dimension, remember the amount of layers if (dimension == dimension_layer) Layers = pDimensionDefinitions[i].zones; } - _3lnk->SetPos(6, RIFF::stream_curpos); // jump forward to next dimension definition + _3lnk->SetPos(3, RIFF::stream_curpos); // jump forward to next dimension definition } // check velocity dimension (if there is one) for custom defined zone ranges @@ -1537,7 +1577,7 @@ bits[i] = DimValues[i]; switch (pDimensionDefinitions[i].split_type) { case split_type_normal: - bits[i] /= pDimensionDefinitions[i].zone_size; + bits[i] = uint8_t(bits[i] / pDimensionDefinitions[i].zone_size); break; case split_type_customvelocity: bits[i] = VelocityTable[bits[i]]; @@ -1589,9 +1629,11 @@ if ((int32_t)WavePoolTableIndex == -1) return NULL; File* file = (File*) GetParent()->GetParent(); unsigned long soughtoffset = file->pWavePoolTable[WavePoolTableIndex]; + unsigned long soughtfileno = file->pWavePoolTableHi[WavePoolTableIndex]; Sample* sample = file->GetFirstSample(pProgress); while (sample) { - if (sample->ulWavePoolOffset == soughtoffset) return static_cast(pSample = sample); + if (sample->ulWavePoolOffset == soughtoffset && + sample->FileNo == soughtfileno) return static_cast(pSample = sample); sample = file->GetNextSample(); } return NULL; @@ -1734,6 +1776,9 @@ pInstruments->clear(); delete pInstruments; } + // free extension files + for (std::list::iterator i = ExtensionFiles.begin() ; i != ExtensionFiles.end() ; i++) + delete *i; } Sample* File::GetFirstSample(progress_t* pProgress) { @@ -1750,31 +1795,55 @@ } 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); + RIFF::File* file = pRIFF; - if (!pSamples) pSamples = new SampleList; - unsigned long waveFileOffset = wave->GetFilePos(); - pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset)); + // just for progress calculation + int iSampleIndex = 0; + int iTotalSamples = WavePoolCount; + + // check if samples should be loaded from extension files + int lastFileNo = 0; + for (int i = 0 ; i < WavePoolCount ; i++) { + if (pWavePoolTableHi[i] > lastFileNo) lastFileNo = pWavePoolTableHi[i]; + } + String name(pRIFF->Filename); + int nameLen = pRIFF->Filename.length(); + char suffix[6]; + if (nameLen > 4 && pRIFF->Filename.substr(nameLen - 4) == ".gig") nameLen -= 4; + + for (int fileNo = 0 ; ; ) { + RIFF::List* wvpl = file->GetSubList(LIST_TYPE_WVPL); + if (wvpl) { + 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, fileNo)); - iSampleIndex++; + iSampleIndex++; + } + wave = wvpl->GetNextSubList(); } - wave = wvpl->GetNextSubList(); + + if (fileNo == lastFileNo) break; + + // open extension file (*.gx01, *.gx02, ...) + fileNo++; + sprintf(suffix, ".gx%02d", fileNo); + name.replace(nameLen, 5, suffix); + file = new RIFF::File(name); + ExtensionFiles.push_back(file); } - __notify_progress(pProgress, 1.0); // notify done + else throw gig::Exception("Mandatory chunk not found."); } - else throw gig::Exception("Mandatory chunk not found."); + + __notify_progress(pProgress, 1.0); // notify done } Instrument* File::GetFirstInstrument() { @@ -1865,4 +1934,25 @@ std::cout << "gig::Exception: " << Message << std::endl; } + +// *************** functions *************** +// * + + /** + * Returns the name of this C++ library. This is usually "libgig" of + * course. This call is equivalent to RIFF::libraryName() and + * DLS::libraryName(). + */ + String libraryName() { + return PACKAGE; + } + + /** + * Returns version of this C++ library. This call is equivalent to + * RIFF::libraryVersion() and DLS::libraryVersion(). + */ + String libraryVersion() { + return VERSION; + } + } // namespace gig