--- libgig/trunk/src/gig.cpp 2019/12/14 17:04:28 3656 +++ libgig/trunk/src/gig.cpp 2020/01/22 15:37:09 3722 @@ -2,7 +2,7 @@ * * * libgig - C++ cross-platform Gigasampler format file access library * * * - * Copyright (C) 2003-2019 by Christian Schoenebeck * + * Copyright (C) 2003-2020 by Christian Schoenebeck * * * * * * This library is free software; you can redistribute it and/or modify * @@ -3412,7 +3412,7 @@ } File* pFile = (File*) GetParent()->GetParent(); - bool versiongt2 = pFile->pVersion && pFile->pVersion->major > 2; + const bool versiongt2 = pFile->pVersion && pFile->pVersion->major > 2; const int iMaxDimensions = versiongt2 ? 8 : 5; const int iMaxDimensionRegions = versiongt2 ? 256 : 32; @@ -3459,6 +3459,39 @@ } store32(&pData[iWavePoolOffset + i * 4], iWaveIndex); } + + // The following chunks are just added for compatibility with the + // GigaStudio software, which would show a warning if these were + // missing. However currently these chunks don't cover any useful + // data. So if this gig file uses any of our own gig format + // extensions which would cause this gig file to be unloadable + // with GSt software anyway, then just skip these GSt compatibility + // chunks here as well. + if (versiongt2 && !UsesAnyGigFormatExtension()) { + // add 3dnm list which always seems to be empty + RIFF::List* _3dnm = pCkRegion->GetSubList(LIST_TYPE_3DNM); + if (!_3dnm) _3dnm = pCkRegion->AddSubList(LIST_TYPE_3DNM); + + // add 3ddp chunk which always seems to have 16 bytes of 0xFF + RIFF::Chunk* _3ddp = pCkRegion->GetSubChunk(CHUNK_ID_3DDP); + if (!_3ddp) _3ddp = pCkRegion->AddSubChunk(CHUNK_ID_3DDP, 16); + uint8_t* pData = (uint8_t*) _3ddp->LoadChunkData(); + for (int i = 0; i < 16; i += 4) { + store32(&pData[i], 0xFFFFFFFF); + } + + // move 3dnm and 3ddp to the end of the region list + pCkRegion->MoveSubChunk(pCkRegion->GetSubList(LIST_TYPE_3DNM), (RIFF::Chunk*)NULL); + pCkRegion->MoveSubChunk(pCkRegion->GetSubChunk(CHUNK_ID_3DDP), (RIFF::Chunk*)NULL); + } else { + // this is intended for the user switching from GSt >= 3 version + // back to an older format version, delete GSt3 chunks ... + RIFF::List* _3dnm = pCkRegion->GetSubList(LIST_TYPE_3DNM); + if (_3dnm) pCkRegion->DeleteSubChunk(_3dnm); + + RIFF::Chunk* _3ddp = pCkRegion->GetSubChunk(CHUNK_ID_3DDP); + if (_3ddp) pCkRegion->DeleteSubChunk(_3ddp); + } } void Region::LoadDimensionRegions(RIFF::List* rgn) { @@ -3857,9 +3890,23 @@ // now tempRegion's dimensions and DimensionRegions basically reflect // what we wanted to get for this actual Region here, so we now just // delete and recreate the dimension in question with the new amount - // zones and then copy back from tempRegion - DeleteDimension(oldDef); - AddDimension(&newDef); + // zones and then copy back from tempRegion. we're actually deleting and + // recreating all dimensions here, to avoid altering the precise order + // of the dimensions (which would not be an error per se, but it would + // cause usability issues with instrument editors) + { + std::vector oldDefs; + for (int i = 0; i < Dimensions; ++i) + oldDefs.push_back(pDimensionDefinitions[i]); // copy, don't reference + for (int i = Dimensions - 1; i >= 0; --i) + DeleteDimension(&pDimensionDefinitions[i]); + for (int i = 0; i < oldDefs.size(); ++i) { + dimension_def_t& def = oldDefs[i]; + AddDimension( + (def.dimension == newDef.dimension) ? &newDef : &def + ); + } + } for (int iSrc = 0; iSrc < 256; ++iSrc) { DimensionRegion* srcDimRgn = tempRgn->pDimensionRegions[iSrc]; if (!srcDimRgn) continue; @@ -3997,9 +4044,23 @@ // now tempRegion's dimensions and DimensionRegions basically reflect // what we wanted to get for this actual Region here, so we now just // delete and recreate the dimension in question with the new amount - // zones and then copy back from tempRegion - DeleteDimension(oldDef); - AddDimension(&newDef); + // zones and then copy back from tempRegion. we're actually deleting and + // recreating all dimensions here, to avoid altering the precise order + // of the dimensions (which would not be an error per se, but it would + // cause usability issues with instrument editors) + { + std::vector oldDefs; + for (int i = 0; i < Dimensions; ++i) + oldDefs.push_back(pDimensionDefinitions[i]); // copy, don't reference + for (int i = Dimensions - 1; i >= 0; --i) + DeleteDimension(&pDimensionDefinitions[i]); + for (int i = 0; i < oldDefs.size(); ++i) { + dimension_def_t& def = oldDefs[i]; + AddDimension( + (def.dimension == newDef.dimension) ? &newDef : &def + ); + } + } for (int iSrc = 0; iSrc < 256; ++iSrc) { DimensionRegion* srcDimRgn = tempRgn->pDimensionRegions[iSrc]; if (!srcDimRgn) continue; @@ -4323,6 +4384,29 @@ Layers = orig->Layers; } + /** + * Returns @c true in case this Region object uses any gig format + * extension, that is e.g. whether any DimensionRegion object currently + * has any setting effective that would require our "LSDE" RIFF chunk to + * be stored to the gig file. + * + * Right now this is a private method. It is considerable though this method + * to become (in slightly modified form) a public API method in future, i.e. + * to allow instrument editors to visualize and/or warn the user of any gig + * format extension being used. See also comments on + * DimensionRegion::UsesAnyGigFormatExtension() for details about such a + * potential public API change in future. + */ + bool Region::UsesAnyGigFormatExtension() const { + for (int i = 0; i < 256; i++) { + if (pDimensionRegions[i]) { + if (pDimensionRegions[i]->UsesAnyGigFormatExtension()) + return true; + } + } + return false; + } + // *************** MidiRule *************** // * @@ -4504,7 +4588,7 @@ Compression = (Compression_t) ckScri->ReadUint32(); Encoding = (Encoding_t) ckScri->ReadUint32(); Language = (Language_t) ckScri->ReadUint32(); - Bypass = (Language_t) ckScri->ReadUint32() & 1; + Bypass = ckScri->ReadUint32() & 1; crc = ckScri->ReadUint32(); uint32_t nameSize = ckScri->ReadUint32(); Name.resize(nameSize, ' '); @@ -5493,6 +5577,31 @@ UpdateRegionKeyTable(); } + /** + * Returns @c true in case this Instrument object uses any gig format + * extension, that is e.g. whether any DimensionRegion object currently + * has any setting effective that would require our "LSDE" RIFF chunk to + * be stored to the gig file. + * + * Right now this is a private method. It is considerable though this method + * to become (in slightly modified form) a public API method in future, i.e. + * to allow instrument editors to visualize and/or warn the user of any gig + * format extension being used. See also comments on + * DimensionRegion::UsesAnyGigFormatExtension() for details about such a + * potential public API change in future. + */ + bool Instrument::UsesAnyGigFormatExtension() const { + if (!pRegions) return false; + RegionList::const_iterator iter = pRegions->begin(); + RegionList::const_iterator end = pRegions->end(); + for (; iter != end; ++iter) { + gig::Region* rgn = static_cast(*iter); + if (rgn->UsesAnyGigFormatExtension()) + return true; + } + return false; + } + // *************** Group *************** // * @@ -6823,6 +6932,30 @@ return bAutoLoad; } + /** + * Returns @c true in case this gig File object uses any gig format + * extension, that is e.g. whether any DimensionRegion object currently + * has any setting effective that would require our "LSDE" RIFF chunk to + * be stored to the gig file. + * + * Right now this is a private method. It is considerable though this method + * to become (in slightly modified form) a public API method in future, i.e. + * to allow instrument editors to visualize and/or warn the user of any gig + * format extension being used. See also comments on + * DimensionRegion::UsesAnyGigFormatExtension() for details about such a + * potential public API change in future. + */ + bool File::UsesAnyGigFormatExtension() const { + if (!pInstruments) return false; + InstrumentList::iterator iter = pInstruments->begin(); + InstrumentList::iterator end = pInstruments->end(); + for (; iter != end; ++iter) { + Instrument* pInstrument = static_cast(*iter); + if (pInstrument->UsesAnyGigFormatExtension()) + return true; + } + return false; + } // *************** Exception ***************