2 |
* * |
* * |
3 |
* libgig - C++ cross-platform Gigasampler format file access library * |
* libgig - C++ cross-platform Gigasampler format file access library * |
4 |
* * |
* * |
5 |
* Copyright (C) 2003-2019 by Christian Schoenebeck * |
* Copyright (C) 2003-2020 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 * |
3412 |
} |
} |
3413 |
|
|
3414 |
File* pFile = (File*) GetParent()->GetParent(); |
File* pFile = (File*) GetParent()->GetParent(); |
3415 |
bool versiongt2 = pFile->pVersion && pFile->pVersion->major > 2; |
const bool versiongt2 = pFile->pVersion && pFile->pVersion->major > 2; |
3416 |
const int iMaxDimensions = versiongt2 ? 8 : 5; |
const int iMaxDimensions = versiongt2 ? 8 : 5; |
3417 |
const int iMaxDimensionRegions = versiongt2 ? 256 : 32; |
const int iMaxDimensionRegions = versiongt2 ? 256 : 32; |
3418 |
|
|
3459 |
} |
} |
3460 |
store32(&pData[iWavePoolOffset + i * 4], iWaveIndex); |
store32(&pData[iWavePoolOffset + i * 4], iWaveIndex); |
3461 |
} |
} |
3462 |
|
|
3463 |
|
// The following chunks are just added for compatibility with the |
3464 |
|
// GigaStudio software, which would show a warning if these were |
3465 |
|
// missing. However currently these chunks don't cover any useful |
3466 |
|
// data. So if this gig file uses any of our own gig format |
3467 |
|
// extensions which would cause this gig file to be unloadable |
3468 |
|
// with GSt software anyway, then just skip these GSt compatibility |
3469 |
|
// chunks here as well. |
3470 |
|
if (versiongt2 && !UsesAnyGigFormatExtension()) { |
3471 |
|
// add 3dnm list which always seems to be empty |
3472 |
|
RIFF::List* _3dnm = pCkRegion->GetSubList(LIST_TYPE_3DNM); |
3473 |
|
if (!_3dnm) _3dnm = pCkRegion->AddSubList(LIST_TYPE_3DNM); |
3474 |
|
|
3475 |
|
// add 3ddp chunk which always seems to have 16 bytes of 0xFF |
3476 |
|
RIFF::Chunk* _3ddp = pCkRegion->GetSubChunk(CHUNK_ID_3DDP); |
3477 |
|
if (!_3ddp) _3ddp = pCkRegion->AddSubChunk(CHUNK_ID_3DDP, 16); |
3478 |
|
uint8_t* pData = (uint8_t*) _3ddp->LoadChunkData(); |
3479 |
|
for (int i = 0; i < 16; i += 4) { |
3480 |
|
store32(&pData[i], 0xFFFFFFFF); |
3481 |
|
} |
3482 |
|
|
3483 |
|
// move 3dnm and 3ddp to the end of the region list |
3484 |
|
pCkRegion->MoveSubChunk(pCkRegion->GetSubList(LIST_TYPE_3DNM), (RIFF::Chunk*)NULL); |
3485 |
|
pCkRegion->MoveSubChunk(pCkRegion->GetSubChunk(CHUNK_ID_3DDP), (RIFF::Chunk*)NULL); |
3486 |
|
} else { |
3487 |
|
// this is intended for the user switching from GSt >= 3 version |
3488 |
|
// back to an older format version, delete GSt3 chunks ... |
3489 |
|
RIFF::List* _3dnm = pCkRegion->GetSubList(LIST_TYPE_3DNM); |
3490 |
|
if (_3dnm) pCkRegion->DeleteSubChunk(_3dnm); |
3491 |
|
|
3492 |
|
RIFF::Chunk* _3ddp = pCkRegion->GetSubChunk(CHUNK_ID_3DDP); |
3493 |
|
if (_3ddp) pCkRegion->DeleteSubChunk(_3ddp); |
3494 |
|
} |
3495 |
} |
} |
3496 |
|
|
3497 |
void Region::LoadDimensionRegions(RIFF::List* rgn) { |
void Region::LoadDimensionRegions(RIFF::List* rgn) { |
3890 |
// now tempRegion's dimensions and DimensionRegions basically reflect |
// now tempRegion's dimensions and DimensionRegions basically reflect |
3891 |
// what we wanted to get for this actual Region here, so we now just |
// what we wanted to get for this actual Region here, so we now just |
3892 |
// delete and recreate the dimension in question with the new amount |
// delete and recreate the dimension in question with the new amount |
3893 |
// zones and then copy back from tempRegion |
// zones and then copy back from tempRegion. we're actually deleting and |
3894 |
DeleteDimension(oldDef); |
// recreating all dimensions here, to avoid altering the precise order |
3895 |
AddDimension(&newDef); |
// of the dimensions (which would not be an error per se, but it would |
3896 |
|
// cause usability issues with instrument editors) |
3897 |
|
{ |
3898 |
|
std::vector<dimension_def_t> oldDefs; |
3899 |
|
for (int i = 0; i < Dimensions; ++i) |
3900 |
|
oldDefs.push_back(pDimensionDefinitions[i]); // copy, don't reference |
3901 |
|
for (int i = Dimensions - 1; i >= 0; --i) |
3902 |
|
DeleteDimension(&pDimensionDefinitions[i]); |
3903 |
|
for (int i = 0; i < oldDefs.size(); ++i) { |
3904 |
|
dimension_def_t& def = oldDefs[i]; |
3905 |
|
AddDimension( |
3906 |
|
(def.dimension == newDef.dimension) ? &newDef : &def |
3907 |
|
); |
3908 |
|
} |
3909 |
|
} |
3910 |
for (int iSrc = 0; iSrc < 256; ++iSrc) { |
for (int iSrc = 0; iSrc < 256; ++iSrc) { |
3911 |
DimensionRegion* srcDimRgn = tempRgn->pDimensionRegions[iSrc]; |
DimensionRegion* srcDimRgn = tempRgn->pDimensionRegions[iSrc]; |
3912 |
if (!srcDimRgn) continue; |
if (!srcDimRgn) continue; |
4044 |
// now tempRegion's dimensions and DimensionRegions basically reflect |
// now tempRegion's dimensions and DimensionRegions basically reflect |
4045 |
// what we wanted to get for this actual Region here, so we now just |
// what we wanted to get for this actual Region here, so we now just |
4046 |
// delete and recreate the dimension in question with the new amount |
// delete and recreate the dimension in question with the new amount |
4047 |
// zones and then copy back from tempRegion |
// zones and then copy back from tempRegion. we're actually deleting and |
4048 |
DeleteDimension(oldDef); |
// recreating all dimensions here, to avoid altering the precise order |
4049 |
AddDimension(&newDef); |
// of the dimensions (which would not be an error per se, but it would |
4050 |
|
// cause usability issues with instrument editors) |
4051 |
|
{ |
4052 |
|
std::vector<dimension_def_t> oldDefs; |
4053 |
|
for (int i = 0; i < Dimensions; ++i) |
4054 |
|
oldDefs.push_back(pDimensionDefinitions[i]); // copy, don't reference |
4055 |
|
for (int i = Dimensions - 1; i >= 0; --i) |
4056 |
|
DeleteDimension(&pDimensionDefinitions[i]); |
4057 |
|
for (int i = 0; i < oldDefs.size(); ++i) { |
4058 |
|
dimension_def_t& def = oldDefs[i]; |
4059 |
|
AddDimension( |
4060 |
|
(def.dimension == newDef.dimension) ? &newDef : &def |
4061 |
|
); |
4062 |
|
} |
4063 |
|
} |
4064 |
for (int iSrc = 0; iSrc < 256; ++iSrc) { |
for (int iSrc = 0; iSrc < 256; ++iSrc) { |
4065 |
DimensionRegion* srcDimRgn = tempRgn->pDimensionRegions[iSrc]; |
DimensionRegion* srcDimRgn = tempRgn->pDimensionRegions[iSrc]; |
4066 |
if (!srcDimRgn) continue; |
if (!srcDimRgn) continue; |
4384 |
Layers = orig->Layers; |
Layers = orig->Layers; |
4385 |
} |
} |
4386 |
|
|
4387 |
|
/** |
4388 |
|
* Returns @c true in case this Region object uses any gig format |
4389 |
|
* extension, that is e.g. whether any DimensionRegion object currently |
4390 |
|
* has any setting effective that would require our "LSDE" RIFF chunk to |
4391 |
|
* be stored to the gig file. |
4392 |
|
* |
4393 |
|
* Right now this is a private method. It is considerable though this method |
4394 |
|
* to become (in slightly modified form) a public API method in future, i.e. |
4395 |
|
* to allow instrument editors to visualize and/or warn the user of any gig |
4396 |
|
* format extension being used. See also comments on |
4397 |
|
* DimensionRegion::UsesAnyGigFormatExtension() for details about such a |
4398 |
|
* potential public API change in future. |
4399 |
|
*/ |
4400 |
|
bool Region::UsesAnyGigFormatExtension() const { |
4401 |
|
for (int i = 0; i < 256; i++) { |
4402 |
|
if (pDimensionRegions[i]) { |
4403 |
|
if (pDimensionRegions[i]->UsesAnyGigFormatExtension()) |
4404 |
|
return true; |
4405 |
|
} |
4406 |
|
} |
4407 |
|
return false; |
4408 |
|
} |
4409 |
|
|
4410 |
|
|
4411 |
// *************** MidiRule *************** |
// *************** MidiRule *************** |
4412 |
// * |
// * |
5577 |
UpdateRegionKeyTable(); |
UpdateRegionKeyTable(); |
5578 |
} |
} |
5579 |
|
|
5580 |
|
/** |
5581 |
|
* Returns @c true in case this Instrument object uses any gig format |
5582 |
|
* extension, that is e.g. whether any DimensionRegion object currently |
5583 |
|
* has any setting effective that would require our "LSDE" RIFF chunk to |
5584 |
|
* be stored to the gig file. |
5585 |
|
* |
5586 |
|
* Right now this is a private method. It is considerable though this method |
5587 |
|
* to become (in slightly modified form) a public API method in future, i.e. |
5588 |
|
* to allow instrument editors to visualize and/or warn the user of any gig |
5589 |
|
* format extension being used. See also comments on |
5590 |
|
* DimensionRegion::UsesAnyGigFormatExtension() for details about such a |
5591 |
|
* potential public API change in future. |
5592 |
|
*/ |
5593 |
|
bool Instrument::UsesAnyGigFormatExtension() const { |
5594 |
|
if (!pRegions) return false; |
5595 |
|
RegionList::const_iterator iter = pRegions->begin(); |
5596 |
|
RegionList::const_iterator end = pRegions->end(); |
5597 |
|
for (; iter != end; ++iter) { |
5598 |
|
gig::Region* rgn = static_cast<gig::Region*>(*iter); |
5599 |
|
if (rgn->UsesAnyGigFormatExtension()) |
5600 |
|
return true; |
5601 |
|
} |
5602 |
|
return false; |
5603 |
|
} |
5604 |
|
|
5605 |
|
|
5606 |
// *************** Group *************** |
// *************** Group *************** |
5607 |
// * |
// * |
6734 |
if (pVersion && pVersion->major > 2) { |
if (pVersion && pVersion->major > 2) { |
6735 |
RIFF::Chunk* _3gnm = _3gnl->GetFirstSubChunk(); |
RIFF::Chunk* _3gnm = _3gnl->GetFirstSubChunk(); |
6736 |
for (int i = 0 ; i < 128 ; i++) { |
for (int i = 0 ; i < 128 ; i++) { |
6737 |
if (i >= pGroups->size()) ::SaveString(CHUNK_ID_3GNM, _3gnm, _3gnl, "", "", true, 64); |
// create 128 empty placeholder strings which will either |
6738 |
|
// be filled by Group::UpdateChunks below or left empty. |
6739 |
|
::SaveString(CHUNK_ID_3GNM, _3gnm, _3gnl, "", "", true, 64); |
6740 |
if (_3gnm) _3gnm = _3gnl->GetNextSubChunk(); |
if (_3gnm) _3gnm = _3gnl->GetNextSubChunk(); |
6741 |
} |
} |
6742 |
} |
} |
6932 |
return bAutoLoad; |
return bAutoLoad; |
6933 |
} |
} |
6934 |
|
|
6935 |
|
/** |
6936 |
|
* Returns @c true in case this gig File object uses any gig format |
6937 |
|
* extension, that is e.g. whether any DimensionRegion object currently |
6938 |
|
* has any setting effective that would require our "LSDE" RIFF chunk to |
6939 |
|
* be stored to the gig file. |
6940 |
|
* |
6941 |
|
* Right now this is a private method. It is considerable though this method |
6942 |
|
* to become (in slightly modified form) a public API method in future, i.e. |
6943 |
|
* to allow instrument editors to visualize and/or warn the user of any gig |
6944 |
|
* format extension being used. See also comments on |
6945 |
|
* DimensionRegion::UsesAnyGigFormatExtension() for details about such a |
6946 |
|
* potential public API change in future. |
6947 |
|
*/ |
6948 |
|
bool File::UsesAnyGigFormatExtension() const { |
6949 |
|
if (!pInstruments) return false; |
6950 |
|
InstrumentList::iterator iter = pInstruments->begin(); |
6951 |
|
InstrumentList::iterator end = pInstruments->end(); |
6952 |
|
for (; iter != end; ++iter) { |
6953 |
|
Instrument* pInstrument = static_cast<gig::Instrument*>(*iter); |
6954 |
|
if (pInstrument->UsesAnyGigFormatExtension()) |
6955 |
|
return true; |
6956 |
|
} |
6957 |
|
return false; |
6958 |
|
} |
6959 |
|
|
6960 |
|
|
6961 |
// *************** Exception *************** |
// *************** Exception *************** |