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-2021 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 * |
209 |
if (lart) { |
if (lart) { |
210 |
uint32_t artCkType = (lart->GetListType() == LIST_TYPE_LAR2) ? CHUNK_ID_ART2 |
uint32_t artCkType = (lart->GetListType() == LIST_TYPE_LAR2) ? CHUNK_ID_ART2 |
211 |
: CHUNK_ID_ARTL; |
: CHUNK_ID_ARTL; |
212 |
RIFF::Chunk* art = lart->GetFirstSubChunk(); |
size_t i = 0; |
213 |
while (art) { |
for (RIFF::Chunk* art = lart->GetSubChunkAt(i); art; |
214 |
|
art = lart->GetSubChunkAt(++i)) |
215 |
|
{ |
216 |
if (art->GetChunkID() == artCkType) { |
if (art->GetChunkID() == artCkType) { |
217 |
if (!pArticulations) pArticulations = new ArticulationList; |
if (!pArticulations) pArticulations = new ArticulationList; |
218 |
pArticulations->push_back(new Articulation(art)); |
pArticulations->push_back(new Articulation(art)); |
219 |
} |
} |
|
art = lart->GetNextSubChunk(); |
|
220 |
} |
} |
221 |
} |
} |
222 |
} |
} |
557 |
} |
} |
558 |
|
|
559 |
void Resource::GenerateDLSID(dlsid_t* pDLSID) { |
void Resource::GenerateDLSID(dlsid_t* pDLSID) { |
|
#if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE) |
|
560 |
#ifdef WIN32 |
#ifdef WIN32 |
561 |
UUID uuid; |
UUID uuid; |
562 |
UuidCreate(&uuid); |
UuidCreate(&uuid); |
581 |
pDLSID->abData[5] = uuid.byte13; |
pDLSID->abData[5] = uuid.byte13; |
582 |
pDLSID->abData[6] = uuid.byte14; |
pDLSID->abData[6] = uuid.byte14; |
583 |
pDLSID->abData[7] = uuid.byte15; |
pDLSID->abData[7] = uuid.byte15; |
584 |
#else |
#elif defined(HAVE_UUID_GENERATE) |
585 |
uuid_t uuid; |
uuid_t uuid; |
586 |
uuid_generate(uuid); |
uuid_generate(uuid); |
587 |
pDLSID->ulData1 = uuid[0] | uuid[1] << 8 | uuid[2] << 16 | uuid[3] << 24; |
pDLSID->ulData1 = uuid[0] | uuid[1] << 8 | uuid[2] << 16 | uuid[3] << 24; |
588 |
pDLSID->usData2 = uuid[4] | uuid[5] << 8; |
pDLSID->usData2 = uuid[4] | uuid[5] << 8; |
589 |
pDLSID->usData3 = uuid[6] | uuid[7] << 8; |
pDLSID->usData3 = uuid[6] | uuid[7] << 8; |
590 |
memcpy(pDLSID->abData, &uuid[8], 8); |
memcpy(pDLSID->abData, &uuid[8], 8); |
591 |
#endif |
#else |
592 |
|
# error "Missing support for uuid generation" |
593 |
#endif |
#endif |
594 |
} |
} |
595 |
|
|
1376 |
RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); |
RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); |
1377 |
if (lrgn) { |
if (lrgn) { |
1378 |
uint32_t regionCkType = (lrgn->GetSubList(LIST_TYPE_RGN2)) ? LIST_TYPE_RGN2 : LIST_TYPE_RGN; // prefer regions level 2 |
uint32_t regionCkType = (lrgn->GetSubList(LIST_TYPE_RGN2)) ? LIST_TYPE_RGN2 : LIST_TYPE_RGN; // prefer regions level 2 |
1379 |
RIFF::List* rgn = lrgn->GetFirstSubList(); |
size_t i = 0; |
1380 |
while (rgn) { |
for (RIFF::List* rgn = lrgn->GetSubListAt(i); rgn; |
1381 |
|
rgn = lrgn->GetSubListAt(++i)) |
1382 |
|
{ |
1383 |
if (rgn->GetListType() == regionCkType) { |
if (rgn->GetListType() == regionCkType) { |
1384 |
pRegions->push_back(new Region(this, rgn)); |
pRegions->push_back(new Region(this, rgn)); |
1385 |
} |
} |
|
rgn = lrgn->GetNextSubList(); |
|
1386 |
} |
} |
1387 |
} |
} |
1388 |
} |
} |
1447 |
RegionList::iterator iter = pRegions->begin(); |
RegionList::iterator iter = pRegions->begin(); |
1448 |
RegionList::iterator end = pRegions->end(); |
RegionList::iterator end = pRegions->end(); |
1449 |
for (int i = 0; iter != end; ++iter, ++i) { |
for (int i = 0; iter != end; ++iter, ++i) { |
1450 |
// divide local progress into subprogress |
if (pProgress) { |
1451 |
progress_t subprogress; |
// divide local progress into subprogress |
1452 |
__divide_progress(pProgress, &subprogress, pRegions->size(), i); |
progress_t subprogress; |
1453 |
// do the actual work |
__divide_progress(pProgress, &subprogress, pRegions->size(), i); |
1454 |
(*iter)->UpdateChunks(&subprogress); |
// do the actual work |
1455 |
|
(*iter)->UpdateChunks(&subprogress); |
1456 |
|
} else |
1457 |
|
(*iter)->UpdateChunks(NULL); |
1458 |
} |
} |
1459 |
__notify_progress(pProgress, 1.0); // notify done |
if (pProgress) |
1460 |
|
__notify_progress(pProgress, 1.0); // notify done |
1461 |
} |
} |
1462 |
|
|
1463 |
/** @brief Destructor. |
/** @brief Destructor. |
1681 |
if (wvpl) { |
if (wvpl) { |
1682 |
file_offset_t wvplFileOffset = wvpl->GetFilePos() - |
file_offset_t wvplFileOffset = wvpl->GetFilePos() - |
1683 |
wvpl->GetPos(); // should be zero, but just to be sure |
wvpl->GetPos(); // should be zero, but just to be sure |
1684 |
RIFF::List* wave = wvpl->GetFirstSubList(); |
size_t i = 0; |
1685 |
while (wave) { |
for (RIFF::List* wave = wvpl->GetSubListAt(i); wave; |
1686 |
|
wave = wvpl->GetSubListAt(++i)) |
1687 |
|
{ |
1688 |
if (wave->GetListType() == LIST_TYPE_WAVE) { |
if (wave->GetListType() == LIST_TYPE_WAVE) { |
1689 |
file_offset_t waveFileOffset = wave->GetFilePos() - |
file_offset_t waveFileOffset = wave->GetFilePos() - |
1690 |
wave->GetPos(); // should be zero, but just to be sure |
wave->GetPos(); // should be zero, but just to be sure |
1691 |
pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset)); |
pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset)); |
1692 |
} |
} |
|
wave = wvpl->GetNextSubList(); |
|
1693 |
} |
} |
1694 |
} |
} |
1695 |
else { // Seen a dwpl list chunk instead of a wvpl list chunk in some file (officially not DLS compliant) |
else { // Seen a dwpl list chunk instead of a wvpl list chunk in some file (officially not DLS compliant) |
1697 |
if (dwpl) { |
if (dwpl) { |
1698 |
file_offset_t dwplFileOffset = dwpl->GetFilePos() - |
file_offset_t dwplFileOffset = dwpl->GetFilePos() - |
1699 |
dwpl->GetPos(); // should be zero, but just to be sure |
dwpl->GetPos(); // should be zero, but just to be sure |
1700 |
RIFF::List* wave = dwpl->GetFirstSubList(); |
size_t i = 0; |
1701 |
while (wave) { |
for (RIFF::List* wave = dwpl->GetSubListAt(i); wave; |
1702 |
|
wave = dwpl->GetSubListAt(++i)) |
1703 |
|
{ |
1704 |
if (wave->GetListType() == LIST_TYPE_WAVE) { |
if (wave->GetListType() == LIST_TYPE_WAVE) { |
1705 |
file_offset_t waveFileOffset = wave->GetFilePos() - |
file_offset_t waveFileOffset = wave->GetFilePos() - |
1706 |
wave->GetPos(); // should be zero, but just to be sure |
wave->GetPos(); // should be zero, but just to be sure |
1707 |
pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset)); |
pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset)); |
1708 |
} |
} |
|
wave = dwpl->GetNextSubList(); |
|
1709 |
} |
} |
1710 |
} |
} |
1711 |
} |
} |
1762 |
if (!pInstruments) pInstruments = new InstrumentList; |
if (!pInstruments) pInstruments = new InstrumentList; |
1763 |
RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS); |
RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS); |
1764 |
if (lstInstruments) { |
if (lstInstruments) { |
1765 |
RIFF::List* lstInstr = lstInstruments->GetFirstSubList(); |
size_t i = 0; |
1766 |
while (lstInstr) { |
for (RIFF::List* lstInstr = lstInstruments->GetSubListAt(i); |
1767 |
|
lstInstr; lstInstr = lstInstruments->GetSubListAt(++i)) |
1768 |
|
{ |
1769 |
if (lstInstr->GetListType() == LIST_TYPE_INS) { |
if (lstInstr->GetListType() == LIST_TYPE_INS) { |
1770 |
pInstruments->push_back(new Instrument(this, lstInstr)); |
pInstruments->push_back(new Instrument(this, lstInstr)); |
1771 |
} |
} |
|
lstInstr = lstInstruments->GetNextSubList(); |
|
1772 |
} |
} |
1773 |
} |
} |
1774 |
} |
} |
1887 |
|
|
1888 |
// update instrument's chunks |
// update instrument's chunks |
1889 |
if (pInstruments) { |
if (pInstruments) { |
1890 |
// divide local progress into subprogress |
if (pProgress) { |
1891 |
progress_t subprogress; |
// divide local progress into subprogress |
1892 |
__divide_progress(pProgress, &subprogress, 20.f, 0.f); // arbitrarily subdivided into 5% of total progress |
progress_t subprogress; |
1893 |
|
__divide_progress(pProgress, &subprogress, 20.f, 0.f); // arbitrarily subdivided into 5% of total progress |
1894 |
|
|
|
// do the actual work |
|
|
InstrumentList::iterator iter = pInstruments->begin(); |
|
|
InstrumentList::iterator end = pInstruments->end(); |
|
|
for (int i = 0; iter != end; ++iter, ++i) { |
|
|
// divide subprogress into sub-subprogress |
|
|
progress_t subsubprogress; |
|
|
__divide_progress(&subprogress, &subsubprogress, pInstruments->size(), i); |
|
1895 |
// do the actual work |
// do the actual work |
1896 |
(*iter)->UpdateChunks(&subsubprogress); |
InstrumentList::iterator iter = pInstruments->begin(); |
1897 |
} |
InstrumentList::iterator end = pInstruments->end(); |
1898 |
|
for (int i = 0; iter != end; ++iter, ++i) { |
1899 |
|
// divide subprogress into sub-subprogress |
1900 |
|
progress_t subsubprogress; |
1901 |
|
__divide_progress(&subprogress, &subsubprogress, pInstruments->size(), i); |
1902 |
|
// do the actual work |
1903 |
|
(*iter)->UpdateChunks(&subsubprogress); |
1904 |
|
} |
1905 |
|
|
1906 |
__notify_progress(&subprogress, 1.0); // notify subprogress done |
__notify_progress(&subprogress, 1.0); // notify subprogress done |
1907 |
|
} else { |
1908 |
|
InstrumentList::iterator iter = pInstruments->begin(); |
1909 |
|
InstrumentList::iterator end = pInstruments->end(); |
1910 |
|
for (int i = 0; iter != end; ++iter, ++i) { |
1911 |
|
(*iter)->UpdateChunks(NULL); |
1912 |
|
} |
1913 |
|
} |
1914 |
} |
} |
1915 |
|
|
1916 |
// update 'ptbl' chunk |
// update 'ptbl' chunk |
1928 |
|
|
1929 |
// update sample's chunks |
// update sample's chunks |
1930 |
if (pSamples) { |
if (pSamples) { |
1931 |
// divide local progress into subprogress |
if (pProgress) { |
1932 |
progress_t subprogress; |
// divide local progress into subprogress |
1933 |
__divide_progress(pProgress, &subprogress, 20.f, 1.f); // arbitrarily subdivided into 95% of total progress |
progress_t subprogress; |
1934 |
|
__divide_progress(pProgress, &subprogress, 20.f, 1.f); // arbitrarily subdivided into 95% of total progress |
1935 |
|
|
|
// do the actual work |
|
|
SampleList::iterator iter = pSamples->begin(); |
|
|
SampleList::iterator end = pSamples->end(); |
|
|
for (int i = 0; iter != end; ++iter, ++i) { |
|
|
// divide subprogress into sub-subprogress |
|
|
progress_t subsubprogress; |
|
|
__divide_progress(&subprogress, &subsubprogress, pSamples->size(), i); |
|
1936 |
// do the actual work |
// do the actual work |
1937 |
(*iter)->UpdateChunks(&subsubprogress); |
SampleList::iterator iter = pSamples->begin(); |
1938 |
} |
SampleList::iterator end = pSamples->end(); |
1939 |
|
for (int i = 0; iter != end; ++iter, ++i) { |
1940 |
|
// divide subprogress into sub-subprogress |
1941 |
|
progress_t subsubprogress; |
1942 |
|
__divide_progress(&subprogress, &subsubprogress, pSamples->size(), i); |
1943 |
|
// do the actual work |
1944 |
|
(*iter)->UpdateChunks(&subsubprogress); |
1945 |
|
} |
1946 |
|
|
1947 |
__notify_progress(&subprogress, 1.0); // notify subprogress done |
__notify_progress(&subprogress, 1.0); // notify subprogress done |
1948 |
|
} else { |
1949 |
|
SampleList::iterator iter = pSamples->begin(); |
1950 |
|
SampleList::iterator end = pSamples->end(); |
1951 |
|
for (int i = 0; iter != end; ++iter, ++i) { |
1952 |
|
(*iter)->UpdateChunks(NULL); |
1953 |
|
} |
1954 |
|
} |
1955 |
} |
} |
1956 |
|
|
1957 |
// if there are any extension files, gather which ones are regular |
// if there are any extension files, gather which ones are regular |
2087 |
ptbl->Resize(iPtblSize); |
ptbl->Resize(iPtblSize); |
2088 |
} |
} |
2089 |
|
|
2090 |
__notify_progress(pProgress, 1.0); // notify done |
if (pProgress) |
2091 |
|
__notify_progress(pProgress, 1.0); // notify done |
2092 |
} |
} |
2093 |
|
|
2094 |
/** @brief Save changes to another file. |
/** @brief Save changes to another file. |
2113 |
// save extension files (if required) |
// save extension files (if required) |
2114 |
if (!ExtensionFiles.empty()) { |
if (!ExtensionFiles.empty()) { |
2115 |
// for assembling path of extension files to be saved to |
// for assembling path of extension files to be saved to |
|
const std::string folder = parentPath(Path); |
|
2116 |
const std::string baseName = pathWithoutExtension(Path); |
const std::string baseName = pathWithoutExtension(Path); |
2117 |
// save the individual extension files |
// save the individual extension files |
2118 |
std::list<RIFF::File*>::iterator it = ExtensionFiles.begin(); |
std::list<RIFF::File*>::iterator it = ExtensionFiles.begin(); |
2119 |
for (int i = 0; it != ExtensionFiles.end(); ++i, ++it) { |
for (int i = 0; it != ExtensionFiles.end(); ++i, ++it) { |
|
// divide local progress into subprogress |
|
|
progress_t subprogress; |
|
|
__divide_progress(pProgress, &subprogress, tasks, 0.f + i); // subdivided into amount of extension files |
|
2120 |
//FIXME: the .gx99 file is always used by GSt for convolution |
//FIXME: the .gx99 file is always used by GSt for convolution |
2121 |
// data (GigaPulse); so we should better detect by subchunk |
// data (GigaPulse); so we should better detect by subchunk |
2122 |
// whether the extension file is intended for convolution |
// whether the extension file is intended for convolution |
2124 |
// not work for saving new gigs created from scratch |
// not work for saving new gigs created from scratch |
2125 |
const std::string oldName = (*it)->GetFileName(); |
const std::string oldName = (*it)->GetFileName(); |
2126 |
const bool isGigaPulseFile = (extensionOfPath(oldName) == "gx99"); |
const bool isGigaPulseFile = (extensionOfPath(oldName) == "gx99"); |
2127 |
std::string ext = (isGigaPulseFile) ? ".gx99" : strPrint(".gx02d", i+1); |
std::string ext = (isGigaPulseFile) ? ".gx99" : strPrint(".gx%02d", i+1); |
2128 |
std::string newPath = concatPath(folder, baseName) + ext; |
std::string newPath = baseName + ext; |
2129 |
// save extension file to its new location |
// save extension file to its new location |
2130 |
(*it)->Save(newPath, &subprogress); |
if (pProgress) { |
2131 |
|
// divide local progress into subprogress |
2132 |
|
progress_t subprogress; |
2133 |
|
__divide_progress(pProgress, &subprogress, tasks, 0.f + i); // subdivided into amount of extension files |
2134 |
|
// do the actual work |
2135 |
|
(*it)->Save(newPath, &subprogress); |
2136 |
|
} else |
2137 |
|
(*it)->Save(newPath); |
2138 |
} |
} |
2139 |
} |
} |
2140 |
|
|
2141 |
{ |
if (pProgress) { |
2142 |
// divide local progress into subprogress |
// divide local progress into subprogress |
2143 |
progress_t subprogress; |
progress_t subprogress; |
2144 |
__divide_progress(pProgress, &subprogress, tasks, 1.f + nExtFiles); // arbitrarily subdivided into 50% (minus extension files progress) |
__divide_progress(pProgress, &subprogress, tasks, 1.f + nExtFiles); // arbitrarily subdivided into 50% (minus extension files progress) |
2145 |
// do the actual work |
// do the actual work |
2146 |
UpdateChunks(&subprogress); |
UpdateChunks(&subprogress); |
2147 |
} |
} else |
2148 |
{ |
UpdateChunks(NULL); |
2149 |
|
|
2150 |
|
if (pProgress) { |
2151 |
// divide local progress into subprogress |
// divide local progress into subprogress |
2152 |
progress_t subprogress; |
progress_t subprogress; |
2153 |
__divide_progress(pProgress, &subprogress, tasks, 2.f + nExtFiles); // arbitrarily subdivided into 50% (minus extension files progress) |
__divide_progress(pProgress, &subprogress, tasks, 2.f + nExtFiles); // arbitrarily subdivided into 50% (minus extension files progress) |
2154 |
// do the actual work |
// do the actual work |
2155 |
pRIFF->Save(Path, &subprogress); |
pRIFF->Save(Path, &subprogress); |
2156 |
} |
} else |
2157 |
|
pRIFF->Save(Path); |
2158 |
|
|
2159 |
UpdateFileOffsets(); |
UpdateFileOffsets(); |
2160 |
__notify_progress(pProgress, 1.0); // notify done |
|
2161 |
|
if (pProgress) |
2162 |
|
__notify_progress(pProgress, 1.0); // notify done |
2163 |
} |
} |
2164 |
|
|
2165 |
/** @brief Save changes to same file. |
/** @brief Save changes to same file. |
2181 |
if (!ExtensionFiles.empty()) { |
if (!ExtensionFiles.empty()) { |
2182 |
std::list<RIFF::File*>::iterator it = ExtensionFiles.begin(); |
std::list<RIFF::File*>::iterator it = ExtensionFiles.begin(); |
2183 |
for (int i = 0; it != ExtensionFiles.end(); ++i, ++it) { |
for (int i = 0; it != ExtensionFiles.end(); ++i, ++it) { |
|
// divide local progress into subprogress |
|
|
progress_t subprogress; |
|
|
__divide_progress(pProgress, &subprogress, tasks, 0.f + i); // subdivided into amount of extension files |
|
2184 |
// save extension file |
// save extension file |
2185 |
(*it)->Save(&subprogress); |
if (pProgress) { |
2186 |
|
// divide local progress into subprogress |
2187 |
|
progress_t subprogress; |
2188 |
|
__divide_progress(pProgress, &subprogress, tasks, 0.f + i); // subdivided into amount of extension files |
2189 |
|
// do the actual work |
2190 |
|
(*it)->Save(&subprogress); |
2191 |
|
} else |
2192 |
|
(*it)->Save(); |
2193 |
} |
} |
2194 |
} |
} |
2195 |
|
|
2196 |
{ |
if (pProgress) { |
2197 |
// divide local progress into subprogress |
// divide local progress into subprogress |
2198 |
progress_t subprogress; |
progress_t subprogress; |
2199 |
__divide_progress(pProgress, &subprogress, tasks, 1.f + nExtFiles); // arbitrarily subdivided into 50% (minus extension files progress) |
__divide_progress(pProgress, &subprogress, tasks, 1.f + nExtFiles); // arbitrarily subdivided into 50% (minus extension files progress) |
2200 |
// do the actual work |
// do the actual work |
2201 |
UpdateChunks(&subprogress); |
UpdateChunks(&subprogress); |
2202 |
} |
} else |
2203 |
{ |
UpdateChunks(NULL); |
2204 |
|
|
2205 |
|
if (pProgress) { |
2206 |
// divide local progress into subprogress |
// divide local progress into subprogress |
2207 |
progress_t subprogress; |
progress_t subprogress; |
2208 |
__divide_progress(pProgress, &subprogress, tasks, 2.f + nExtFiles); // arbitrarily subdivided into 50% (minus extension files progress) |
__divide_progress(pProgress, &subprogress, tasks, 2.f + nExtFiles); // arbitrarily subdivided into 50% (minus extension files progress) |
2209 |
// do the actual work |
// do the actual work |
2210 |
pRIFF->Save(&subprogress); |
pRIFF->Save(&subprogress); |
2211 |
} |
} else |
2212 |
|
pRIFF->Save(); |
2213 |
|
|
2214 |
UpdateFileOffsets(); |
UpdateFileOffsets(); |
2215 |
__notify_progress(pProgress, 1.0); // notify done |
|
2216 |
|
if (pProgress) |
2217 |
|
__notify_progress(pProgress, 1.0); // notify done |
2218 |
} |
} |
2219 |
|
|
2220 |
/** @brief Updates all file offsets stored all over the file. |
/** @brief Updates all file offsets stored all over the file. |