3850 |
if ((int32_t)WavePoolTableIndex == -1) return NULL; |
if ((int32_t)WavePoolTableIndex == -1) return NULL; |
3851 |
File* file = (File*) GetParent()->GetParent(); |
File* file = (File*) GetParent()->GetParent(); |
3852 |
if (!file->pWavePoolTable) return NULL; |
if (!file->pWavePoolTable) return NULL; |
3853 |
if (file->HasMonolithicLargeFilePolicy()) { |
// for new files or files >= 2 GB use 64 bit wave pool offsets |
3854 |
|
if (file->pRIFF->IsNew() || (file->pRIFF->GetCurrentFileSize() >> 31)) { |
3855 |
|
// use 64 bit wave pool offsets (treating this as large file) |
3856 |
uint64_t soughtoffset = |
uint64_t soughtoffset = |
3857 |
uint64_t(file->pWavePoolTable[WavePoolTableIndex]) | |
uint64_t(file->pWavePoolTable[WavePoolTableIndex]) | |
3858 |
uint64_t(file->pWavePoolTableHi[WavePoolTableIndex]) << 32; |
uint64_t(file->pWavePoolTableHi[WavePoolTableIndex]) << 32; |
3863 |
sample = file->GetNextSample(); |
sample = file->GetNextSample(); |
3864 |
} |
} |
3865 |
} else { |
} else { |
3866 |
|
// use extension files and 32 bit wave pool offsets |
3867 |
file_offset_t soughtoffset = file->pWavePoolTable[WavePoolTableIndex]; |
file_offset_t soughtoffset = file->pWavePoolTable[WavePoolTableIndex]; |
3868 |
file_offset_t soughtfileno = file->pWavePoolTableHi[WavePoolTableIndex]; |
file_offset_t soughtfileno = file->pWavePoolTableHi[WavePoolTableIndex]; |
3869 |
Sample* sample = file->GetFirstSample(pProgress); |
Sample* sample = file->GetFirstSample(pProgress); |
5351 |
int iTotalSamples = WavePoolCount; |
int iTotalSamples = WavePoolCount; |
5352 |
|
|
5353 |
// check if samples should be loaded from extension files |
// check if samples should be loaded from extension files |
5354 |
|
// (only for old gig files < 2 GB) |
5355 |
int lastFileNo = 0; |
int lastFileNo = 0; |
5356 |
if (!HasMonolithicLargeFilePolicy()) { |
if (!file->IsNew() && !(file->GetCurrentFileSize() >> 31)) { |
5357 |
for (int i = 0 ; i < WavePoolCount ; i++) { |
for (int i = 0 ; i < WavePoolCount ; i++) { |
5358 |
if (pWavePoolTableHi[i] > lastFileNo) lastFileNo = pWavePoolTableHi[i]; |
if (pWavePoolTableHi[i] > lastFileNo) lastFileNo = pWavePoolTableHi[i]; |
5359 |
} |
} |
5845 |
} |
} |
5846 |
} |
} |
5847 |
|
|
|
/** @brief Returns the version number of libgig's Giga file format extension. |
|
|
* |
|
|
* libgig added several new features which were not available with the |
|
|
* original GigaStudio software. For those purposes libgig's own custom RIFF |
|
|
* chunks were added to the Giga file format. |
|
|
* |
|
|
* This method returns the version number of the Giga file format extension |
|
|
* used in this Giga file. Currently there are 3 possible values that might |
|
|
* be returned by this method: |
|
|
* |
|
|
* - @c 0: This gig file is not using any libgig specific file format |
|
|
* extension at all. |
|
|
* - @c 1: This gig file uses the RT instrument script format extension. |
|
|
* - @c 2: This gig file additionally provides support for monolithic |
|
|
* large gig files (larger than 2 GB). |
|
|
* |
|
|
* @note This method is currently protected and shall not be used as public |
|
|
* API method, since its method signature might change in future. |
|
|
*/ |
|
|
uint File::GetFormatExtensionVersion() const { |
|
|
RIFF::List* lst3LS = pRIFF->GetSubList(LIST_TYPE_3LS); |
|
|
if (!lst3LS) return 0; // is not using custom Giga format extensions at all |
|
|
RIFF::Chunk* ckFFmt = lst3LS->GetSubChunk(CHUNK_ID_FFMT); |
|
|
if (!ckFFmt) return 1; // uses custom Giga format extension(s) but had no format version saved |
|
|
uint8_t* pData = (uint8_t*) ckFFmt->LoadChunkData(); |
|
|
return load32(pData); |
|
|
} |
|
|
|
|
|
/** @brief Returns true in case this file is stored as one, single monolithic gig file. |
|
|
* |
|
|
* To avoid issues with operating systems which did not support large files |
|
|
* (larger than 2 GB) the original Giga file format avoided to ever save gig |
|
|
* files larger than 2 GB, instead such large Giga files were splitted into |
|
|
* several files, each one not being larger than 2 GB. It used a predefined |
|
|
* file name scheme for them like this: |
|
|
* @code |
|
|
* foo.gig |
|
|
* foo.gx01 |
|
|
* foo.gx02 |
|
|
* foo.gx03 |
|
|
* ... |
|
|
* @endcode |
|
|
* So when like in this example foo.gig was loaded, all other files |
|
|
* (foo.gx01, ...) were automatically loaded as well to make up the overall |
|
|
* large gig file (provided they were located at the same directory). Such |
|
|
* additional .gxYY files were called "extension files". |
|
|
* |
|
|
* Since nowadays all modern systems support large files, libgig always |
|
|
* saves large gig files as one single monolithic gig file instead, that |
|
|
* is libgig won't split such a large gig file into separate files like the |
|
|
* original GigaStudio software did. It uses a custom Giga file format |
|
|
* extension for this feature. |
|
|
* |
|
|
* For still being able though to load old splitted gig files and the new |
|
|
* large monolithic ones, this method is used to determine which loading |
|
|
* policy must be used for this gig file. |
|
|
* |
|
|
* @note This method is currently protected and shall not be used as public |
|
|
* API method, since its method signature might change in future and since |
|
|
* this method should not be directly relevant for applications based on |
|
|
* libgig. |
|
|
*/ |
|
|
bool File::HasMonolithicLargeFilePolicy() const { |
|
|
RIFF::List* lst3LS = pRIFF->GetSubList(LIST_TYPE_3LS); |
|
|
if (!lst3LS) return false; |
|
|
RIFF::Chunk* ckFFmt = lst3LS->GetSubChunk(CHUNK_ID_FFMT); |
|
|
if (!ckFFmt) return false; |
|
|
uint8_t* pData = (uint8_t*) ckFFmt->LoadChunkData(); |
|
|
uint32_t formatBitField = load32(&pData[4]); |
|
|
return formatBitField & 1; |
|
|
} |
|
|
|
|
5848 |
/** |
/** |
5849 |
* Apply all the gig file's current instruments, samples, groups and settings |
* Apply all the gig file's current instruments, samples, groups and settings |
5850 |
* to the respective RIFF chunks. You have to call Save() to make changes |
* to the respective RIFF chunks. You have to call Save() to make changes |
5859 |
void File::UpdateChunks(progress_t* pProgress) { |
void File::UpdateChunks(progress_t* pProgress) { |
5860 |
bool newFile = pRIFF->GetSubList(LIST_TYPE_INFO) == NULL; |
bool newFile = pRIFF->GetSubList(LIST_TYPE_INFO) == NULL; |
5861 |
|
|
|
b64BitWavePoolOffsets = pVersion && pVersion->major == 3; |
|
|
|
|
5862 |
// update own gig format extension chunks |
// update own gig format extension chunks |
5863 |
// (not part of the GigaStudio 4 format) |
// (not part of the GigaStudio 4 format) |
5864 |
RIFF::List* lst3LS = pRIFF->GetSubList(LIST_TYPE_3LS); |
RIFF::List* lst3LS = pRIFF->GetSubList(LIST_TYPE_3LS); |
5866 |
lst3LS = pRIFF->AddSubList(LIST_TYPE_3LS); |
lst3LS = pRIFF->AddSubList(LIST_TYPE_3LS); |
5867 |
} |
} |
5868 |
// Make sure <3LS > chunk is placed before <ptbl> chunk. The precise |
// Make sure <3LS > chunk is placed before <ptbl> chunk. The precise |
5869 |
// location of <3LS > is irrelevant, however it MUST BE located BEFORE |
// location of <3LS > is irrelevant, however it should be located |
5870 |
// the actual wave data, otherwise the <3LS > chunk becomes |
// before the actual wave data |
|
// inaccessible on gig files larger than 4GB ! |
|
5871 |
RIFF::Chunk* ckPTBL = pRIFF->GetSubChunk(CHUNK_ID_PTBL); |
RIFF::Chunk* ckPTBL = pRIFF->GetSubChunk(CHUNK_ID_PTBL); |
5872 |
pRIFF->MoveSubChunk(lst3LS, ckPTBL); |
pRIFF->MoveSubChunk(lst3LS, ckPTBL); |
5873 |
|
|
|
// Update <FFmt> chunk with informations about our file format |
|
|
// extensions. Currently this <FFmt> chunk has the following |
|
|
// layout: |
|
|
// |
|
|
// <uint32> -> (libgig's) File Format Extension version |
|
|
// <uint32> -> Format bit field: |
|
|
// bit 0: If flag is not set use separate .gx01 |
|
|
// extension files if file is larger than 2 GB |
|
|
// like with the original Giga format, if flag |
|
|
// is set use 64 bit sample references and keep |
|
|
// everything as one single monolithic gig file. |
|
|
RIFF::Chunk* ckFFmt = lst3LS->GetSubChunk(CHUNK_ID_FFMT); |
|
|
if (!ckFFmt) { |
|
|
const int iChunkSize = 2 * sizeof(uint32_t); |
|
|
ckFFmt = lst3LS->AddSubChunk(CHUNK_ID_FFMT, iChunkSize); |
|
|
} |
|
|
{ |
|
|
uint8_t* pData = (uint8_t*) ckFFmt->LoadChunkData(); |
|
|
store32(&pData[0], GIG_FILE_EXT_VERSION); |
|
|
// for now we always save gig files larger than 2 GB as one |
|
|
// single monolithic file (saving those with extension files is |
|
|
// currently not supported and probably also not desired anymore |
|
|
// nowadays). |
|
|
uint32_t formatBitfield = 1; |
|
|
store32(&pData[4], formatBitfield); |
|
|
} |
|
5874 |
// This must be performed before writing the chunks for instruments, |
// This must be performed before writing the chunks for instruments, |
5875 |
// because the instruments' script slots will write the file offsets |
// because the instruments' script slots will write the file offsets |
5876 |
// of the respective instrument script chunk as reference. |
// of the respective instrument script chunk as reference. |
5883 |
} |
} |
5884 |
} |
} |
5885 |
|
|
5886 |
|
// in case no libgig custom format data was added, then remove the |
5887 |
|
// custom "3LS " chunk again |
5888 |
|
if (!lst3LS->CountSubChunks()) { |
5889 |
|
pRIFF->DeleteSubChunk(lst3LS); |
5890 |
|
lst3LS = NULL; |
5891 |
|
} |
5892 |
|
|
5893 |
// first update base class's chunks |
// first update base class's chunks |
5894 |
DLS::File::UpdateChunks(pProgress); |
DLS::File::UpdateChunks(pProgress); |
5895 |
|
|