/[svn]/libgig/trunk/src/DLS.cpp
ViewVC logotype

Diff of /libgig/trunk/src/DLS.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3473 by schoenebeck, Sun Feb 10 19:58:24 2019 UTC revision 3474 by schoenebeck, Wed Feb 20 16:04:19 2019 UTC
# Line 24  Line 24 
24  #include "DLS.h"  #include "DLS.h"
25    
26  #include <algorithm>  #include <algorithm>
27    #include <vector>
28  #include <time.h>  #include <time.h>
29    
30  #ifdef __APPLE__  #ifdef __APPLE__
# Line 493  namespace DLS { Line 494  namespace DLS {
494       * Generates a new DLSID for the resource.       * Generates a new DLSID for the resource.
495       */       */
496      void Resource::GenerateDLSID() {      void Resource::GenerateDLSID() {
497  #if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE)          #if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE)
   
498          if (!pDLSID) pDLSID = new dlsid_t;          if (!pDLSID) pDLSID = new dlsid_t;
499            GenerateDLSID(pDLSID);
500            #endif
501        }
502    
503        void Resource::GenerateDLSID(dlsid_t* pDLSID) {
504    #if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE)
505  #ifdef WIN32  #ifdef WIN32
   
506          UUID uuid;          UUID uuid;
507          UuidCreate(&uuid);          UuidCreate(&uuid);
508          pDLSID->ulData1 = uuid.Data1;          pDLSID->ulData1 = uuid.Data1;
# Line 1773  namespace DLS { Line 1777  namespace DLS {
1777              __notify_progress(&subprogress, 1.0); // notify subprogress done              __notify_progress(&subprogress, 1.0); // notify subprogress done
1778          }          }
1779    
1780            // if there are any extension files, gather which ones are regular
1781            // extension files used as wave pool files (.gx00, .gx01, ... , .gx98)
1782            // and which one is probably a convolution (GigaPulse) file (always to
1783            // be saved as .gx99)
1784            std::list<RIFF::File*> poolFiles;  // < for (.gx00, .gx01, ... , .gx98) files
1785            RIFF::File* pGigaPulseFile = NULL; // < for .gx99 file
1786            if (!ExtensionFiles.empty()) {
1787                std::list<RIFF::File*>::iterator it = ExtensionFiles.begin();
1788                for (; it != ExtensionFiles.end(); ++it) {
1789                    //FIXME: the .gx99 file is always used by GSt for convolution
1790                    // data (GigaPulse); so we should better detect by subchunk
1791                    // whether the extension file is intended for convolution
1792                    // instead of checkking for a file name, because the latter does
1793                    // not work for saving new gigs created from scratch
1794                    const std::string oldName = (*it)->GetFileName();
1795                    const bool isGigaPulseFile = (extensionOfPath(oldName) == "gx99");
1796                    if (isGigaPulseFile)
1797                        pGigaPulseFile = *it;
1798                    else
1799                        poolFiles.push_back(*it);
1800                }
1801            }
1802    
1803            // update the 'xfil' chunk which describes all extension files (wave
1804            // pool files) except the .gx99 file
1805            if (!poolFiles.empty()) {
1806                const int n = poolFiles.size();
1807                const int iHeaderSize = 4;
1808                const int iEntrySize = 144;
1809    
1810                // make sure chunk exists, and with correct size
1811                RIFF::Chunk* ckXfil = pRIFF->GetSubChunk(CHUNK_ID_XFIL);
1812                if (ckXfil)
1813                    ckXfil->Resize(iHeaderSize + n * iEntrySize);
1814                else
1815                    ckXfil = pRIFF->AddSubChunk(CHUNK_ID_XFIL, iHeaderSize + n * iEntrySize);
1816    
1817                uint8_t* pData = (uint8_t*) ckXfil->LoadChunkData();
1818    
1819                // re-assemble the chunk's content
1820                store32(pData, n);
1821                std::list<RIFF::File*>::iterator itExtFile = poolFiles.begin();
1822                for (int i = 0, iOffset = 4; i < n;
1823                     ++itExtFile, ++i, iOffset += iEntrySize)
1824                {
1825                    // update the filename string and 5 byte extension of each extension file
1826                    std::string file = lastPathComponent(
1827                        (*itExtFile)->GetFileName()
1828                    );
1829                    if (file.length() + 6 > 128)
1830                        throw Exception("Fatal error, extension filename length exceeds 122 byte maximum");
1831                    uint8_t* pStrings = &pData[iOffset];
1832                    memset(pStrings, 0, 128);
1833                    memcpy(pStrings, file.c_str(), file.length());
1834                    pStrings += file.length() + 1;
1835                    std::string ext = file.substr(file.length()-5);
1836                    memcpy(pStrings, ext.c_str(), 5);
1837                    // update the dlsid of the extension file
1838                    uint8_t* pId = &pData[iOffset + 128];
1839                    dlsid_t id;
1840                    RIFF::Chunk* ckDLSID = (*itExtFile)->GetSubChunk(CHUNK_ID_DLID);
1841                    if (ckDLSID) {
1842                        ckDLSID->Read(&id.ulData1, 1, 4);
1843                        ckDLSID->Read(&id.usData2, 1, 2);
1844                        ckDLSID->Read(&id.usData3, 1, 2);
1845                        ckDLSID->Read(id.abData, 8, 1);
1846                    } else {
1847                        ckDLSID = (*itExtFile)->AddSubChunk(CHUNK_ID_DLID, 16);
1848                        Resource::GenerateDLSID(&id);
1849                        uint8_t* pData = (uint8_t*)ckDLSID->LoadChunkData();
1850                        store32(&pData[0], id.ulData1);
1851                        store16(&pData[4], id.usData2);
1852                        store16(&pData[6], id.usData3);
1853                        memcpy(&pData[8], id.abData, 8);
1854                    }
1855                    store32(&pId[0], id.ulData1);
1856                    store16(&pId[4], id.usData2);
1857                    store16(&pId[6], id.usData3);
1858                    memcpy(&pId[8], id.abData, 8);
1859                }
1860            } else {
1861                // in case there was a 'xfil' chunk, remove it
1862                RIFF::Chunk* ckXfil = pRIFF->GetSubChunk(CHUNK_ID_XFIL);
1863                if (ckXfil) pRIFF->DeleteSubChunk(ckXfil);
1864            }
1865    
1866            // update the 'doxf' chunk which describes a .gx99 extension file
1867            // which contains convolution data (GigaPulse)
1868            if (pGigaPulseFile) {
1869                RIFF::Chunk* ckDoxf = pRIFF->GetSubChunk(CHUNK_ID_DOXF);
1870                if (!ckDoxf) ckDoxf = pRIFF->AddSubChunk(CHUNK_ID_DOXF, 148);
1871    
1872                uint8_t* pData = (uint8_t*) ckDoxf->LoadChunkData();
1873    
1874                // update the dlsid from the extension file
1875                uint8_t* pId = &pData[132];
1876                RIFF::Chunk* ckDLSID = pGigaPulseFile->GetSubChunk(CHUNK_ID_DLID);
1877                if (!ckDLSID) { //TODO: auto generate DLS ID if missing
1878                    throw Exception("Fatal error, GigaPulse file does not contain a DLS ID chunk");
1879                } else {
1880                    dlsid_t id;
1881                    // read DLS ID from extension files's DLS ID chunk
1882                    uint8_t* pData = (uint8_t*) ckDLSID->LoadChunkData();
1883                    id.ulData1 = load32(&pData[0]);
1884                    id.usData2 = load16(&pData[4]);
1885                    id.usData3 = load16(&pData[6]);
1886                    memcpy(id.abData, &pData[8], 8);
1887                    // store DLS ID to 'doxf' chunk
1888                    store32(&pId[0], id.ulData1);
1889                    store16(&pId[4], id.usData2);
1890                    store16(&pId[6], id.usData3);
1891                    memcpy(&pId[8], id.abData, 8);
1892                }
1893            } else {
1894                // in case there was a 'doxf' chunk, remove it
1895                RIFF::Chunk* ckDoxf = pRIFF->GetSubChunk(CHUNK_ID_DOXF);
1896                if (ckDoxf) pRIFF->DeleteSubChunk(ckDoxf);
1897            }
1898    
1899          // the RIFF file to be written might now been grown >= 4GB or might          // the RIFF file to be written might now been grown >= 4GB or might
1900          // been shrunk < 4GB, so we might need to update the wave pool offset          // been shrunk < 4GB, so we might need to update the wave pool offset
1901          // size and thus accordingly we would need to resize the wave pool          // size and thus accordingly we would need to resize the wave pool
1902          // chunk          // chunk
1903          const file_offset_t finalFileSize = pRIFF->GetRequiredFileSize();          const file_offset_t finalFileSize = pRIFF->GetRequiredFileSize();
1904          const bool bRequires64Bit = (finalFileSize >> 32) != 0;          const bool bRequires64Bit = (finalFileSize >> 32) != 0 || // < native 64 bit gig file
1905                                         poolFiles.size() > 0;        // < 32 bit gig file where the hi 32 bits are used as extension file nr
1906          if (b64BitWavePoolOffsets != bRequires64Bit) {          if (b64BitWavePoolOffsets != bRequires64Bit) {
1907              b64BitWavePoolOffsets = bRequires64Bit;              b64BitWavePoolOffsets = bRequires64Bit;
1908              iPtblOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4;              iPtblOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4;
# Line 1804  namespace DLS { Line 1928  namespace DLS {
1928       * @param pProgress - optional: callback function for progress notification       * @param pProgress - optional: callback function for progress notification
1929       */       */
1930      void File::Save(const String& Path, progress_t* pProgress) {      void File::Save(const String& Path, progress_t* pProgress) {
1931            // calculate number of tasks to notify progress appropriately
1932            const size_t nExtFiles = ExtensionFiles.size();
1933            const float tasks = 2.f + nExtFiles;
1934    
1935            // save extension files (if required)
1936            if (!ExtensionFiles.empty()) {
1937                // for assembling path of extension files to be saved to
1938                const std::string folder = parentPath(Path);
1939                const std::string baseName = pathWithoutExtension(Path);
1940                // save the individual extension files
1941                std::list<RIFF::File*>::iterator it = ExtensionFiles.begin();
1942                for (int i = 0; it != ExtensionFiles.end(); ++i, ++it) {
1943                    // divide local progress into subprogress
1944                    progress_t subprogress;
1945                    __divide_progress(pProgress, &subprogress, tasks, 0.f + i); // subdivided into amount of extension files
1946                    //FIXME: the .gx99 file is always used by GSt for convolution
1947                    // data (GigaPulse); so we should better detect by subchunk
1948                    // whether the extension file is intended for convolution
1949                    // instead of checkking for a file name, because the latter does
1950                    // not work for saving new gigs created from scratch
1951                    const std::string oldName = (*it)->GetFileName();
1952                    const bool isGigaPulseFile = (extensionOfPath(oldName) == "gx99");
1953                    std::string ext = (isGigaPulseFile) ? ".gx99" : strPrint(".gx02d", i+1);
1954                    std::string newPath = concatPath(folder, baseName) + ext;
1955                    // save extension file to its new location
1956                    (*it)->Save(newPath, &subprogress);
1957                }
1958            }
1959    
1960          {          {
1961              // divide local progress into subprogress              // divide local progress into subprogress
1962              progress_t subprogress;              progress_t subprogress;
1963              __divide_progress(pProgress, &subprogress, 2.f, 0.f); // arbitrarily subdivided into 50% of total progress              __divide_progress(pProgress, &subprogress, tasks, 1.f + nExtFiles); // arbitrarily subdivided into 50% (minus extension files progress)
1964              // do the actual work              // do the actual work
1965              UpdateChunks(&subprogress);              UpdateChunks(&subprogress);
               
1966          }          }
1967          {          {
1968              // divide local progress into subprogress              // divide local progress into subprogress
1969              progress_t subprogress;              progress_t subprogress;
1970              __divide_progress(pProgress, &subprogress, 2.f, 1.f); // arbitrarily subdivided into 50% of total progress              __divide_progress(pProgress, &subprogress, tasks, 2.f + nExtFiles); // arbitrarily subdivided into 50% (minus extension files progress)
1971              // do the actual work              // do the actual work
1972              pRIFF->Save(Path, &subprogress);              pRIFF->Save(Path, &subprogress);
1973          }          }
# Line 1834  namespace DLS { Line 1986  namespace DLS {
1986       * @throws DLS::Exception  if any kind of DLS specific error occurred       * @throws DLS::Exception  if any kind of DLS specific error occurred
1987       */       */
1988      void File::Save(progress_t* pProgress) {      void File::Save(progress_t* pProgress) {
1989            // calculate number of tasks to notify progress appropriately
1990            const size_t nExtFiles = ExtensionFiles.size();
1991            const float tasks = 2.f + nExtFiles;
1992    
1993            // save extension files (if required)
1994            if (!ExtensionFiles.empty()) {
1995                std::list<RIFF::File*>::iterator it = ExtensionFiles.begin();
1996                for (int i = 0; it != ExtensionFiles.end(); ++i, ++it) {
1997                    // divide local progress into subprogress
1998                    progress_t subprogress;
1999                    __divide_progress(pProgress, &subprogress, tasks, 0.f + i); // subdivided into amount of extension files
2000                    // save extension file
2001                    (*it)->Save(&subprogress);
2002                }
2003            }
2004    
2005          {          {
2006              // divide local progress into subprogress              // divide local progress into subprogress
2007              progress_t subprogress;              progress_t subprogress;
2008              __divide_progress(pProgress, &subprogress, 2.f, 0.f); // arbitrarily subdivided into 50% of total progress              __divide_progress(pProgress, &subprogress, tasks, 1.f + nExtFiles); // arbitrarily subdivided into 50% (minus extension files progress)
2009              // do the actual work              // do the actual work
2010              UpdateChunks(&subprogress);              UpdateChunks(&subprogress);
2011          }          }
2012          {          {
2013              // divide local progress into subprogress              // divide local progress into subprogress
2014              progress_t subprogress;              progress_t subprogress;
2015              __divide_progress(pProgress, &subprogress, 2.f, 1.f); // arbitrarily subdivided into 50% of total progress              __divide_progress(pProgress, &subprogress, tasks, 2.f + nExtFiles); // arbitrarily subdivided into 50% (minus extension files progress)
2016              // do the actual work              // do the actual work
2017              pRIFF->Save(&subprogress);              pRIFF->Save(&subprogress);
2018          }          }
# Line 1943  namespace DLS { Line 2111  namespace DLS {
2111          pWavePoolTable   = new uint32_t[WavePoolCount];          pWavePoolTable   = new uint32_t[WavePoolCount];
2112          pWavePoolTableHi = new uint32_t[WavePoolCount];          pWavePoolTableHi = new uint32_t[WavePoolCount];
2113          if (!pSamples) return;          if (!pSamples) return;
2114          // update offsets int wave pool table          // update offsets in wave pool table
2115          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
2116          uint64_t wvplFileOffset = wvpl->GetFilePos();          uint64_t wvplFileOffset = wvpl->GetFilePos();
2117          if (b64BitWavePoolOffsets) {          if (!b64BitWavePoolOffsets) { // conventional 32 bit offsets (and no extension files) ...
             SampleList::iterator iter = pSamples->begin();  
             SampleList::iterator end  = pSamples->end();  
             for (int i = 0 ; iter != end ; ++iter, i++) {  
                 uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - wvplFileOffset - LIST_HEADER_SIZE(pRIFF->GetFileOffsetSize());  
                 (*iter)->ullWavePoolOffset = _64BitOffset;  
                 pWavePoolTableHi[i] = (uint32_t) (_64BitOffset >> 32);  
                 pWavePoolTable[i]   = (uint32_t) _64BitOffset;  
             }  
         } else { // conventional 32 bit offsets  
2118              SampleList::iterator iter = pSamples->begin();              SampleList::iterator iter = pSamples->begin();
2119              SampleList::iterator end  = pSamples->end();              SampleList::iterator end  = pSamples->end();
2120              for (int i = 0 ; iter != end ; ++iter, i++) {              for (int i = 0 ; iter != end ; ++iter, i++) {
# Line 1963  namespace DLS { Line 2122  namespace DLS {
2122                  (*iter)->ullWavePoolOffset = _64BitOffset;                  (*iter)->ullWavePoolOffset = _64BitOffset;
2123                  pWavePoolTable[i] = (uint32_t) _64BitOffset;                  pWavePoolTable[i] = (uint32_t) _64BitOffset;
2124              }              }
2125            } else { // a) native 64 bit offsets without extension files or b) 32 bit offsets with extension files ...
2126                if (ExtensionFiles.empty()) { // native 64 bit offsets (and no extension files) [not compatible with GigaStudio] ...
2127                    SampleList::iterator iter = pSamples->begin();
2128                    SampleList::iterator end  = pSamples->end();
2129                    for (int i = 0 ; iter != end ; ++iter, i++) {
2130                        uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - wvplFileOffset - LIST_HEADER_SIZE(pRIFF->GetFileOffsetSize());
2131                        (*iter)->ullWavePoolOffset = _64BitOffset;
2132                        pWavePoolTableHi[i] = (uint32_t) (_64BitOffset >> 32);
2133                        pWavePoolTable[i]   = (uint32_t) _64BitOffset;
2134                    }
2135                } else { // 32 bit offsets with extension files (GigaStudio legacy support) ...
2136                    // the main gig and the extension files may contain wave data
2137                    std::vector<RIFF::File*> poolFiles;
2138                    poolFiles.push_back(pRIFF);
2139                    poolFiles.insert(poolFiles.end(), ExtensionFiles.begin(), ExtensionFiles.end());
2140    
2141                    RIFF::File* pCurPoolFile = NULL;
2142                    int fileNo = 0;
2143                    int waveOffset = 0;
2144                    SampleList::iterator iter = pSamples->begin();
2145                    SampleList::iterator end  = pSamples->end();
2146                    for (int i = 0 ; iter != end ; ++iter, i++) {
2147                        RIFF::File* pPoolFile = (*iter)->pWaveList->GetFile();
2148                        // if this sample is located in the same pool file as the
2149                        // last we reuse the previously computed fileNo and waveOffset
2150                        if (pPoolFile != pCurPoolFile) { // it is a different pool file than the last sample ...
2151                            pCurPoolFile = pPoolFile;
2152    
2153                            std::vector<RIFF::File*>::iterator sIter;
2154                            sIter = std::find(poolFiles.begin(), poolFiles.end(), pPoolFile);
2155                            if (sIter != poolFiles.end())
2156                                fileNo = std::distance(poolFiles.begin(), sIter);
2157                            else
2158                                throw DLS::Exception("Fatal error, unknown pool file");
2159    
2160                            RIFF::List* extWvpl = pCurPoolFile->GetSubList(LIST_TYPE_WVPL);
2161                            if (!extWvpl)
2162                                throw DLS::Exception("Fatal error, pool file has no 'wvpl' list chunk");
2163                            waveOffset = extWvpl->GetFilePos() + LIST_HEADER_SIZE(pCurPoolFile->GetFileOffsetSize());
2164                        }
2165                        uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - waveOffset;
2166                        // pWavePoolTableHi stores file number when extension files are in use
2167                        pWavePoolTableHi[i] = (uint32_t) fileNo;
2168                        pWavePoolTable[i]   = (uint32_t) _64BitOffset;
2169                        (*iter)->ullWavePoolOffset = _64BitOffset;
2170                    }
2171                }
2172          }          }
2173      }      }
2174    
2175    
   
2176  // *************** Exception ***************  // *************** Exception ***************
2177  // *  // *
2178    

Legend:
Removed from v.3473  
changed lines
  Added in v.3474

  ViewVC Help
Powered by ViewVC