/[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 1179 by persson, Sat May 12 11:25:04 2007 UTC revision 2394 by schoenebeck, Mon Jan 7 23:23:58 2013 UTC
# Line 2  Line 2 
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-2007 by Christian Schoenebeck                      *   *   Copyright (C) 2003-2013 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  *
# Line 23  Line 23 
23    
24  #include "DLS.h"  #include "DLS.h"
25    
26    #include <algorithm>
27  #include <time.h>  #include <time.h>
28    
29    #ifdef __APPLE__
30    #include <CoreFoundation/CFUUID.h>
31    #elif defined(HAVE_UUID_UUID_H)
32    #include <uuid/uuid.h>
33    #endif
34    
35  #include "helper.h"  #include "helper.h"
36    
37  // macros to decode connection transforms  // macros to decode connection transforms
# Line 220  namespace DLS { Line 227  namespace DLS {
227              }              }
228          }          }
229      }      }
230        
231        /**
232         * Not yet implemented in this version, since the .gig format does
233         * not need to copy DLS articulators and so far nobody used pure
234         * DLS instrument AFAIK.
235         */
236        void Articulator::CopyAssign(const Articulator* orig) {
237            //TODO: implement deep copy assignment for this class
238        }
239    
240    
241    
# Line 233  namespace DLS { Line 249  namespace DLS {
249       * @param list - pointer to a list chunk which contains an INFO list chunk       * @param list - pointer to a list chunk which contains an INFO list chunk
250       */       */
251      Info::Info(RIFF::List* list) {      Info::Info(RIFF::List* list) {
252          UseFixedLengthStrings = false;          pFixedStringLengths = NULL;
253          pResourceListChunk = list;          pResourceListChunk = list;
254          if (list) {          if (list) {
255              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);
# Line 262  namespace DLS { Line 278  namespace DLS {
278      Info::~Info() {      Info::~Info() {
279      }      }
280    
281        /**
282         * Forces specific Info fields to be of a fixed length when being saved
283         * to a file. By default the respective RIFF chunk of an Info field
284         * will have a size analogue to its actual string length. With this
285         * method however this behavior can be overridden, allowing to force an
286         * arbitrary fixed size individually for each Info field.
287         *
288         * This method is used as a workaround for the gig format, not for DLS.
289         *
290         * @param lengths - NULL terminated array of string_length_t elements
291         */
292        void Info::SetFixedStringLengths(const string_length_t* lengths) {
293            pFixedStringLengths = lengths;
294        }
295    
296      /** @brief Load given INFO field.      /** @brief Load given INFO field.
297       *       *
298       * Load INFO field from INFO chunk with chunk ID \a ChunkID from INFO       * Load INFO field from INFO chunk with chunk ID \a ChunkID from INFO
# Line 286  namespace DLS { Line 317  namespace DLS {
317       * @param lstINFO  - parent (INFO) RIFF list chunk       * @param lstINFO  - parent (INFO) RIFF list chunk
318       * @param s        - current value of info field       * @param s        - current value of info field
319       * @param sDefault - default value       * @param sDefault - default value
      * @param bUseFixedLengthStrings - should a specific string size be forced in the chunk?  
      * @param size     - wanted size of the INFO chunk. This is ignored if bUseFixedLengthStrings is false.  
320       */       */
321      void Info::SaveString(uint32_t ChunkID, RIFF::List* lstINFO, const String& s, const String& sDefault, bool bUseFixedLengthStrings, int size) {      void Info::SaveString(uint32_t ChunkID, RIFF::List* lstINFO, const String& s, const String& sDefault) {
322            int size = 0;
323            if (pFixedStringLengths) {
324                for (int i = 0 ; pFixedStringLengths[i].length ; i++) {
325                    if (pFixedStringLengths[i].chunkId == ChunkID) {
326                        size = pFixedStringLengths[i].length;
327                        break;
328                    }
329                }
330            }
331          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
332          ::SaveString(ChunkID, ck, lstINFO, s, sDefault, bUseFixedLengthStrings, size); // function from helper.h          ::SaveString(ChunkID, ck, lstINFO, s, sDefault, size != 0, size); // function from helper.h
333      }      }
334    
335      /** @brief Update chunks with current info values.      /** @brief Update chunks with current info values.
# Line 336  namespace DLS { Line 374  namespace DLS {
374    
375          // save values          // save values
376    
377          // (the string size values are for gig files; they are only          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""));
378          // used if UseFixedLengthStrings is set to true)          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""));
379          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName, UseFixedLengthStrings,          SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""));
380                     resourceType == RIFF_TYPE_DLS ? 128 : 64);          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments);
381          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""), UseFixedLengthStrings, 256);          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""));
382          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate, UseFixedLengthStrings, 128);          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate);
383          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments, UseFixedLengthStrings, 1024);          SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""));
384          SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""), UseFixedLengthStrings, 128);          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""));
385          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""), UseFixedLengthStrings, 128);          SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String(""));
386          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""), UseFixedLengthStrings, 128);          SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""));
387          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""), UseFixedLengthStrings, 128);          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName);
388          SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String(""), UseFixedLengthStrings, 128);          SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""));
389          SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""), UseFixedLengthStrings, 128);          SaveString(CHUNK_ID_ISBJ, lstINFO, Subject, String(""));
390          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""), UseFixedLengthStrings, 128);          SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware);
391          SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware, UseFixedLengthStrings,          SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""));
392                     resourceType == LIST_TYPE_INS ?          SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""));
393                     (Software == "" ? defaultSoftware.length()+1 : Software.length()+1) : 128);          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""));
394          SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""), UseFixedLengthStrings, 128);      }
395          SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""), UseFixedLengthStrings, 128);      
396          SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""), UseFixedLengthStrings, 128);      /**
397          SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""), UseFixedLengthStrings, 128);       * Make a deep copy of the Info object given by @a orig and assign it to
398          SaveString(CHUNK_ID_ISBJ, lstINFO, Subject, String(""), UseFixedLengthStrings, 128);       * this object.
399         *
400         * @param orig - original Info object to be copied from
401         */
402        void Info::CopyAssign(const Info* orig) {
403            Name = orig->Name;
404            ArchivalLocation = orig->ArchivalLocation;
405            CreationDate = orig->CreationDate;
406            Comments = orig->Comments;
407            Product = orig->Product;
408            Copyright = orig->Copyright;
409            Artists = orig->Artists;
410            Genre = orig->Genre;
411            Keywords = orig->Keywords;
412            Engineer = orig->Engineer;
413            Technician = orig->Technician;
414            Software = orig->Software;
415            Medium = orig->Medium;
416            Source = orig->Source;
417            SourceForm = orig->SourceForm;
418            Commissioned = orig->Commissioned;
419            Subject = orig->Subject;
420            //FIXME: hmm, is copying this pointer a good idea?
421            pFixedStringLengths = orig->pFixedStringLengths;
422      }      }
423    
424    
# Line 406  namespace DLS { Line 467  namespace DLS {
467       */       */
468      void Resource::UpdateChunks() {      void Resource::UpdateChunks() {
469          pInfo->UpdateChunks();          pInfo->UpdateChunks();
470          //TODO: save DLSID  
471            if (pDLSID) {
472                // make sure 'dlid' chunk exists
473                RIFF::Chunk* ckDLSID = pResourceList->GetSubChunk(CHUNK_ID_DLID);
474                if (!ckDLSID) ckDLSID = pResourceList->AddSubChunk(CHUNK_ID_DLID, 16);
475                uint8_t* pData = (uint8_t*)ckDLSID->LoadChunkData();
476                // update 'dlid' chunk
477                store32(&pData[0], pDLSID->ulData1);
478                store16(&pData[4], pDLSID->usData2);
479                store16(&pData[6], pDLSID->usData3);
480                memcpy(&pData[8], pDLSID->abData, 8);
481            }
482      }      }
483    
484        /**
485         * Generates a new DLSID for the resource.
486         */
487        void Resource::GenerateDLSID() {
488    #if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE)
489    
490            if (!pDLSID) pDLSID = new dlsid_t;
491    
492    #ifdef WIN32
493    
494            UUID uuid;
495            UuidCreate(&uuid);
496            pDLSID->ulData1 = uuid.Data1;
497            pDLSID->usData2 = uuid.Data2;
498            pDLSID->usData3 = uuid.Data3;
499            memcpy(pDLSID->abData, uuid.Data4, 8);
500    
501    #elif defined(__APPLE__)
502    
503            CFUUIDRef uuidRef = CFUUIDCreate(NULL);
504            CFUUIDBytes uuid = CFUUIDGetUUIDBytes(uuidRef);
505            CFRelease(uuidRef);
506            pDLSID->ulData1 = uuid.byte0 | uuid.byte1 << 8 | uuid.byte2 << 16 | uuid.byte3 << 24;
507            pDLSID->usData2 = uuid.byte4 | uuid.byte5 << 8;
508            pDLSID->usData3 = uuid.byte6 | uuid.byte7 << 8;
509            pDLSID->abData[0] = uuid.byte8;
510            pDLSID->abData[1] = uuid.byte9;
511            pDLSID->abData[2] = uuid.byte10;
512            pDLSID->abData[3] = uuid.byte11;
513            pDLSID->abData[4] = uuid.byte12;
514            pDLSID->abData[5] = uuid.byte13;
515            pDLSID->abData[6] = uuid.byte14;
516            pDLSID->abData[7] = uuid.byte15;
517    #else
518            uuid_t uuid;
519            uuid_generate(uuid);
520            pDLSID->ulData1 = uuid[0] | uuid[1] << 8 | uuid[2] << 16 | uuid[3] << 24;
521            pDLSID->usData2 = uuid[4] | uuid[5] << 8;
522            pDLSID->usData3 = uuid[6] | uuid[7] << 8;
523            memcpy(pDLSID->abData, &uuid[8], 8);
524    #endif
525    #endif
526        }
527        
528        /**
529         * Make a deep copy of the Resource object given by @a orig and assign it
530         * to this object.
531         *
532         * @param orig - original Resource object to be copied from
533         */
534        void Resource::CopyAssign(const Resource* orig) {
535            pInfo->CopyAssign(orig->pInfo);
536        }
537    
538    
539  // *************** Sampler ***************  // *************** Sampler ***************
# Line 425  namespace DLS { Line 550  namespace DLS {
550              SamplerOptions = wsmp->ReadUint32();              SamplerOptions = wsmp->ReadUint32();
551              SampleLoops    = wsmp->ReadUint32();              SampleLoops    = wsmp->ReadUint32();
552          } else { // 'wsmp' chunk missing          } else { // 'wsmp' chunk missing
553              uiHeaderSize   = 0;              uiHeaderSize   = 20;
554              UnityNote      = 64;              UnityNote      = 60;
555              FineTune       = 0; // +- 0 cents              FineTune       = 0; // +- 0 cents
556              Gain           = 0; // 0 dB              Gain           = 0; // 0 dB
557              SamplerOptions = F_WSMP_NO_COMPRESSION;              SamplerOptions = F_WSMP_NO_COMPRESSION;
# Line 450  namespace DLS { Line 575  namespace DLS {
575          if (pSampleLoops) delete[] pSampleLoops;          if (pSampleLoops) delete[] pSampleLoops;
576      }      }
577    
578        void Sampler::SetGain(int32_t gain) {
579            Gain = gain;
580        }
581    
582      /**      /**
583       * Apply all sample player options to the respective RIFF chunk. You       * Apply all sample player options to the respective RIFF chunk. You
584       * have to call File::Save() to make changes persistent.       * have to call File::Save() to make changes persistent.
# Line 457  namespace DLS { Line 586  namespace DLS {
586      void Sampler::UpdateChunks() {      void Sampler::UpdateChunks() {
587          // make sure 'wsmp' chunk exists          // make sure 'wsmp' chunk exists
588          RIFF::Chunk* wsmp = pParentList->GetSubChunk(CHUNK_ID_WSMP);          RIFF::Chunk* wsmp = pParentList->GetSubChunk(CHUNK_ID_WSMP);
589            int wsmpSize = uiHeaderSize + SampleLoops * 16;
590          if (!wsmp) {          if (!wsmp) {
591              uiHeaderSize = 20;              wsmp = pParentList->AddSubChunk(CHUNK_ID_WSMP, wsmpSize);
592              wsmp = pParentList->AddSubChunk(CHUNK_ID_WSMP, uiHeaderSize + SampleLoops * 16);          } else if (wsmp->GetSize() != wsmpSize) {
593                wsmp->Resize(wsmpSize);
594          }          }
595          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();
596          // update headers size          // update headers size
# Line 487  namespace DLS { Line 618  namespace DLS {
618      /**      /**
619       * Adds a new sample loop with the provided loop definition.       * Adds a new sample loop with the provided loop definition.
620       *       *
621       * @param - points to a loop definition that is to be copied       * @param pLoopDef - points to a loop definition that is to be copied
622       */       */
623      void Sampler::AddSampleLoop(sample_loop_t* pLoopDef) {      void Sampler::AddSampleLoop(sample_loop_t* pLoopDef) {
624          sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops + 1];          sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops + 1];
# Line 516  namespace DLS { Line 647  namespace DLS {
647          // copy old loops array (skipping given loop)          // copy old loops array (skipping given loop)
648          for (int i = 0, o = 0; i < SampleLoops; i++) {          for (int i = 0, o = 0; i < SampleLoops; i++) {
649              if (&pSampleLoops[i] == pLoopDef) continue;              if (&pSampleLoops[i] == pLoopDef) continue;
650              if (o == SampleLoops - 1)              if (o == SampleLoops - 1) {
651                    delete[] pNewLoops;
652                  throw Exception("Could not delete Sample Loop, because it does not exist");                  throw Exception("Could not delete Sample Loop, because it does not exist");
653                }
654              pNewLoops[o] = pSampleLoops[i];              pNewLoops[o] = pSampleLoops[i];
655              o++;              o++;
656          }          }
# Line 526  namespace DLS { Line 659  namespace DLS {
659          pSampleLoops = pNewLoops;          pSampleLoops = pNewLoops;
660          SampleLoops--;          SampleLoops--;
661      }      }
662        
663        /**
664         * Make a deep copy of the Sampler object given by @a orig and assign it
665         * to this object.
666         *
667         * @param orig - original Sampler object to be copied from
668         */
669        void Sampler::CopyAssign(const Sampler* orig) {
670            // copy trivial scalars
671            UnityNote = orig->UnityNote;
672            FineTune = orig->FineTune;
673            Gain = orig->Gain;
674            NoSampleDepthTruncation = orig->NoSampleDepthTruncation;
675            NoSampleCompression = orig->NoSampleCompression;
676            SamplerOptions = orig->SamplerOptions;
677            
678            // copy sample loops
679            if (SampleLoops) delete[] pSampleLoops;
680            pSampleLoops = new sample_loop_t[orig->SampleLoops];
681            memcpy(pSampleLoops, orig->pSampleLoops, orig->SampleLoops * sizeof(sample_loop_t));
682            SampleLoops = orig->SampleLoops;
683        }
684    
685    
686  // *************** Sample ***************  // *************** Sample ***************
# Line 851  namespace DLS { Line 1005  namespace DLS {
1005      }      }
1006    
1007      /**      /**
1008         * Modifies the key range of this Region and makes sure the respective
1009         * chunks are in correct order.
1010         *
1011         * @param Low  - lower end of key range
1012         * @param High - upper end of key range
1013         */
1014        void Region::SetKeyRange(uint16_t Low, uint16_t High) {
1015            KeyRange.low  = Low;
1016            KeyRange.high = High;
1017    
1018            // make sure regions are already loaded
1019            Instrument* pInstrument = (Instrument*) GetParent();
1020            if (!pInstrument->pRegions) pInstrument->LoadRegions();
1021            if (!pInstrument->pRegions) return;
1022    
1023            // find the r which is the first one to the right of this region
1024            // at its new position
1025            Region* r = NULL;
1026            Region* prev_region = NULL;
1027            for (
1028                Instrument::RegionList::iterator iter = pInstrument->pRegions->begin();
1029                iter != pInstrument->pRegions->end(); iter++
1030            ) {
1031                if ((*iter)->KeyRange.low > this->KeyRange.low) {
1032                    r = *iter;
1033                    break;
1034                }
1035                prev_region = *iter;
1036            }
1037    
1038            // place this region before r if it's not already there
1039            if (prev_region != this) pInstrument->MoveRegion(this, r);
1040        }
1041    
1042        /**
1043       * Apply Region settings to the respective RIFF chunks. You have to       * Apply Region settings to the respective RIFF chunks. You have to
1044       * call File::Save() to make changes persistent.       * call File::Save() to make changes persistent.
1045       *       *
# Line 901  namespace DLS { Line 1090  namespace DLS {
1090                  }                  }
1091              }              }
1092          }          }
         if (index < 0) throw Exception("Could not save Region, could not find Region's sample");  
1093          WavePoolTableIndex = index;          WavePoolTableIndex = index;
1094          // update 'wlnk' chunk          // update 'wlnk' chunk
1095          store16(&pData[0], WaveLinkOptionFlags);          store16(&pData[0], WaveLinkOptionFlags);
# Line 909  namespace DLS { Line 1097  namespace DLS {
1097          store32(&pData[4], Channel);          store32(&pData[4], Channel);
1098          store32(&pData[8], WavePoolTableIndex);          store32(&pData[8], WavePoolTableIndex);
1099      }      }
1100        
1101        /**
1102         * Make a (semi) deep copy of the Region object given by @a orig and assign
1103         * it to this object.
1104         *
1105         * Note that the sample pointer referenced by @a orig is simply copied as
1106         * memory address. Thus the respective sample is shared, not duplicated!
1107         *
1108         * @param orig - original Region object to be copied from
1109         */
1110        void Region::CopyAssign(const Region* orig) {
1111            // handle base classes
1112            Resource::CopyAssign(orig);
1113            Articulator::CopyAssign(orig);
1114            Sampler::CopyAssign(orig);
1115            // handle actual own attributes of this class
1116            // (the trivial ones)
1117            VelocityRange = orig->VelocityRange;
1118            KeyGroup = orig->KeyGroup;
1119            Layer = orig->Layer;
1120            SelfNonExclusive = orig->SelfNonExclusive;
1121            PhaseMaster = orig->PhaseMaster;
1122            PhaseGroup = orig->PhaseGroup;
1123            MultiChannel = orig->MultiChannel;
1124            Channel = orig->Channel;
1125            WavePoolTableIndex = orig->WavePoolTableIndex;
1126            pSample = orig->pSample;
1127            FormatOptionFlags = orig->FormatOptionFlags;
1128            WaveLinkOptionFlags = orig->WaveLinkOptionFlags;
1129            // handle the last, a bit sensible attribute
1130            SetKeyRange(orig->KeyRange.low, orig->KeyRange.high);
1131        }
1132    
1133    
1134  // *************** Instrument ***************  // *************** Instrument ***************
# Line 1060  namespace DLS { Line 1279  namespace DLS {
1279          RIFF::List* pParent = pCkInstrument->GetParent();          RIFF::List* pParent = pCkInstrument->GetParent();
1280          pParent->DeleteSubChunk(pCkInstrument);          pParent->DeleteSubChunk(pCkInstrument);
1281      }      }
1282        
1283        void Instrument::CopyAssignCore(const Instrument* orig) {
1284            // handle base classes
1285            Resource::CopyAssign(orig);
1286            Articulator::CopyAssign(orig);
1287            // handle actual own attributes of this class
1288            // (the trivial ones)
1289            IsDrum = orig->IsDrum;
1290            MIDIBank = orig->MIDIBank;
1291            MIDIBankCoarse = orig->MIDIBankCoarse;
1292            MIDIBankFine = orig->MIDIBankFine;
1293            MIDIProgram = orig->MIDIProgram;
1294        }
1295        
1296        /**
1297         * Make a (semi) deep copy of the Instrument object given by @a orig and assign
1298         * it to this object.
1299         *
1300         * Note that all sample pointers referenced by @a orig are simply copied as
1301         * memory address. Thus the respective samples are shared, not duplicated!
1302         *
1303         * @param orig - original Instrument object to be copied from
1304         */
1305        void Instrument::CopyAssign(const Instrument* orig) {
1306            CopyAssignCore(orig);
1307            // delete all regions first
1308            while (Regions) DeleteRegion(GetFirstRegion());
1309            // now recreate and copy regions
1310            {
1311                RegionList::const_iterator it = orig->pRegions->begin();
1312                for (int i = 0; i < orig->Regions; ++i, ++it) {
1313                    Region* dstRgn = AddRegion();
1314                    //NOTE: Region does semi-deep copy !
1315                    dstRgn->CopyAssign(*it);
1316                }
1317            }
1318        }
1319    
1320    
1321  // *************** File ***************  // *************** File ***************
# Line 1073  namespace DLS { Line 1328  namespace DLS {
1328       * a DLS file.       * a DLS file.
1329       */       */
1330      File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) {      File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) {
1331            pRIFF->SetByteOrder(RIFF::endian_little);
1332          pVersion = new version_t;          pVersion = new version_t;
1333          pVersion->major   = 0;          pVersion->major   = 0;
1334          pVersion->minor   = 0;          pVersion->minor   = 0;
# Line 1312  namespace DLS { Line 1568  namespace DLS {
1568      }      }
1569    
1570      /**      /**
1571         * Returns extension file of given index. Extension files are used
1572         * sometimes to circumvent the 2 GB file size limit of the RIFF format and
1573         * of certain operating systems in general. In this case, instead of just
1574         * using one file, the content is spread among several files with similar
1575         * file name scheme. This is especially used by some GigaStudio sound
1576         * libraries.
1577         *
1578         * @param index - index of extension file
1579         * @returns sought extension file, NULL if index out of bounds
1580         * @see GetFileName()
1581         */
1582        RIFF::File* File::GetExtensionFile(int index) {
1583            if (index < 0 || index >= ExtensionFiles.size()) return NULL;
1584            std::list<RIFF::File*>::iterator iter = ExtensionFiles.begin();
1585            for (int i = 0; iter != ExtensionFiles.end(); ++iter, ++i)
1586                if (i == index) return *iter;
1587            return NULL;
1588        }
1589    
1590        /** @brief File name of this DLS file.
1591         *
1592         * This method returns the file name as it was provided when loading
1593         * the respective DLS file. However in case the File object associates
1594         * an empty, that is new DLS file, which was not yet saved to disk,
1595         * this method will return an empty string.
1596         *
1597         * @see GetExtensionFile()
1598         */
1599        String File::GetFileName() {
1600            return pRIFF->GetFileName();
1601        }
1602    
1603        /**
1604       * Apply all the DLS file's current instruments, samples and settings to       * Apply all the DLS file's current instruments, samples and settings to
1605       * the respective RIFF chunks. You have to call Save() to make changes       * the respective RIFF chunks. You have to call Save() to make changes
1606       * persistent.       * persistent.

Legend:
Removed from v.1179  
changed lines
  Added in v.2394

  ViewVC Help
Powered by ViewVC