/[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 800 by schoenebeck, Wed Nov 9 20:04:11 2005 UTC revision 1388 by persson, Sun Oct 7 11:10:02 2007 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   libgig - C++ cross-platform Gigasampler format file loader library    *   *   libgig - C++ cross-platform Gigasampler format file access library    *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003-2005 by Christian Schoenebeck                      *   *   Copyright (C) 2003-2007 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 25  Line 25 
25    
26  #include <time.h>  #include <time.h>
27    
28    #ifdef __APPLE__
29    #include <CoreFoundation/CFUUID.h>
30    #elif defined(HAVE_UUID_UUID_H)
31    #include <uuid/uuid.h>
32    #endif
33    
34  #include "helper.h"  #include "helper.h"
35    
36  // macros to decode connection transforms  // macros to decode connection transforms
# Line 45  Line 51 
51  #define CONN_TRANSFORM_INVERT_SRC_ENCODE(x)             ((x) ? 0x8000 : 0)  #define CONN_TRANSFORM_INVERT_SRC_ENCODE(x)             ((x) ? 0x8000 : 0)
52  #define CONN_TRANSFORM_INVERT_CTL_ENCODE(x)             ((x) ? 0x0200 : 0)  #define CONN_TRANSFORM_INVERT_CTL_ENCODE(x)             ((x) ? 0x0200 : 0)
53    
54  #define DRUM_TYPE_MASK                  0x00000001  #define DRUM_TYPE_MASK                  0x80000000
55    
56  #define F_RGN_OPTION_SELFNONEXCLUSIVE   0x0001  #define F_RGN_OPTION_SELFNONEXCLUSIVE   0x0001
57    
# Line 142  namespace DLS { Line 148  namespace DLS {
148          const int iEntrySize = 12; // 12 bytes per connection block          const int iEntrySize = 12; // 12 bytes per connection block
149          pArticulationCk->Resize(HeaderSize + Connections * iEntrySize);          pArticulationCk->Resize(HeaderSize + Connections * iEntrySize);
150          uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData();          uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData();
151          memccpy(&pData[0], &HeaderSize, 1, 2);          store16(&pData[0], HeaderSize);
152          memccpy(&pData[2], &Connections, 1, 2);          store16(&pData[2], Connections);
153          for (uint32_t i = 0; i < Connections; i++) {          for (uint32_t i = 0; i < Connections; i++) {
154              Connection::conn_block_t c = pConnections[i].ToConnBlock();              Connection::conn_block_t c = pConnections[i].ToConnBlock();
155              memccpy(&pData[HeaderSize + i * iEntrySize],     &c.source, 1, 2);              store16(&pData[HeaderSize + i * iEntrySize],     c.source);
156              memccpy(&pData[HeaderSize + i * iEntrySize + 2], &c.control, 1, 2);              store16(&pData[HeaderSize + i * iEntrySize + 2], c.control);
157              memccpy(&pData[HeaderSize + i * iEntrySize + 4], &c.destination, 1, 2);              store16(&pData[HeaderSize + i * iEntrySize + 4], c.destination);
158              memccpy(&pData[HeaderSize + i * iEntrySize + 6], &c.transform, 1, 2);              store16(&pData[HeaderSize + i * iEntrySize + 6], c.transform);
159              memccpy(&pData[HeaderSize + i * iEntrySize + 8], &c.scale, 1, 4);              store32(&pData[HeaderSize + i * iEntrySize + 8], c.scale);
160          }          }
161      }      }
162    
# Line 212  namespace DLS { Line 218  namespace DLS {
218       * call File::Save() to make changes persistent.       * call File::Save() to make changes persistent.
219       */       */
220      void Articulator::UpdateChunks() {      void Articulator::UpdateChunks() {
221          ArticulationList::iterator iter = pArticulations->begin();          if (pArticulations) {
222          ArticulationList::iterator end  = pArticulations->end();              ArticulationList::iterator iter = pArticulations->begin();
223          for (; iter != end; ++iter) {              ArticulationList::iterator end  = pArticulations->end();
224              (*iter)->UpdateChunks();              for (; iter != end; ++iter) {
225                    (*iter)->UpdateChunks();
226                }
227          }          }
228      }      }
229    
# Line 226  namespace DLS { Line 234  namespace DLS {
234    
235      /** @brief Constructor.      /** @brief Constructor.
236       *       *
237       * Initializes the info strings with values provided by a INFO list chunk.       * Initializes the info strings with values provided by an INFO list chunk.
238       *       *
239       * @param list - pointer to a list chunk which contains a INFO list chunk       * @param list - pointer to a list chunk which contains an INFO list chunk
240       */       */
241      Info::Info(RIFF::List* list) {      Info::Info(RIFF::List* list) {
242            FixedStringLengths = NULL;
243          pResourceListChunk = list;          pResourceListChunk = list;
244          if (list) {          if (list) {
245              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);
# Line 251  namespace DLS { Line 260  namespace DLS {
260                  LoadString(CHUNK_ID_ISRC, lstINFO, Source);                  LoadString(CHUNK_ID_ISRC, lstINFO, Source);
261                  LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);                  LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);
262                  LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);                  LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);
263                    LoadString(CHUNK_ID_ISBJ, lstINFO, Subject);
264              }              }
265          }          }
266      }      }
267    
268        Info::~Info() {
269        }
270    
271      /** @brief Load given INFO field.      /** @brief Load given INFO field.
272       *       *
273       * 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 262  namespace DLS { Line 275  namespace DLS {
275       */       */
276      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {
277          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
278          if (ck) {          ::LoadString(ck, s); // function from helper.h
             // TODO: no check for ZSTR terminated strings yet  
             s = (char*) ck->LoadChunkData();  
             ck->ReleaseChunkData();  
         }  
279      }      }
280    
281      /** @brief Apply given INFO field to the respective chunk.      /** @brief Apply given INFO field to the respective chunk.
282       *       *
283       * Apply given info value to info chunk with ID \a ChunkID, which is a       * Apply given info value to info chunk with ID \a ChunkID, which is a
284       * subchunk of INFO list chunk \a lstINFO. If the given chunk already       * subchunk of INFO list chunk \a lstINFO. If the given chunk already
285       * exists, value \a s will be applied, otherwise if it doesn't exist yet       * exists, value \a s will be applied. Otherwise if it doesn't exist yet
286       * and \a sDefault is not an empty string, such a chunk will be created       * and either \a s or \a sDefault is not an empty string, such a chunk
287       * and \a sDefault will be applied.       * will be created and either \a s or \a sDefault will be applied
288         * (depending on which one is not an empty string, if both are not an
289         * empty string \a s will be preferred).
290       *       *
291       * @param ChunkID  - 32 bit RIFF chunk ID of INFO subchunk       * @param ChunkID  - 32 bit RIFF chunk ID of INFO subchunk
292       * @param lstINFO  - parent (INFO) RIFF list chunk       * @param lstINFO  - parent (INFO) RIFF list chunk
# Line 283  namespace DLS { Line 294  namespace DLS {
294       * @param sDefault - default value       * @param sDefault - default value
295       */       */
296      void Info::SaveString(uint32_t ChunkID, RIFF::List* lstINFO, const String& s, const String& sDefault) {      void Info::SaveString(uint32_t ChunkID, RIFF::List* lstINFO, const String& s, const String& sDefault) {
297          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          int size = 0;
298          if (ck) { // if chunk exists already, use 's' as value          if (FixedStringLengths) {
299              ck->Resize(s.size() + 1);              for (int i = 0 ; FixedStringLengths[i].length ; i++) {
300              char* pData = (char*) ck->LoadChunkData();                  if (FixedStringLengths[i].chunkId == ChunkID) {
301              memcpy(pData, s.c_str(), s.size() + 1);                      size = FixedStringLengths[i].length;
302          } else if (sDefault != "") { // create chunk and use default value                      break;
303              ck = lstINFO->AddSubChunk(ChunkID, sDefault.size() + 1);                  }
304              char* pData = (char*) ck->LoadChunkData();              }
             memcpy(pData, sDefault.c_str(), sDefault.size() + 1);  
305          }          }
306            RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
307            ::SaveString(ChunkID, ck, lstINFO, s, sDefault, size != 0, size); // function from helper.h
308      }      }
309    
310      /** @brief Update chunks with current info values.      /** @brief Update chunks with current info values.
# Line 305  namespace DLS { Line 317  namespace DLS {
317    
318          // make sure INFO list chunk exists          // make sure INFO list chunk exists
319          RIFF::List* lstINFO   = pResourceListChunk->GetSubList(LIST_TYPE_INFO);          RIFF::List* lstINFO   = pResourceListChunk->GetSubList(LIST_TYPE_INFO);
         if (!lstINFO) lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO);  
320    
321          // assemble default values in case the respective chunk is missing yet          String defaultName = "";
322          String defaultName = "NONAME";          String defaultCreationDate = "";
323          // get current date          String defaultSoftware = "";
324          time_t now = time(NULL);          String defaultComments = "";
325          tm* pNowBroken = localtime(&now);  
326          String defaultCreationDate = ToString(pNowBroken->tm_year) + "-" +          uint32_t resourceType = pResourceListChunk->GetListType();
327                                       ToString(pNowBroken->tm_mon)  + "-" +  
328                                       ToString(pNowBroken->tm_mday);          if (!lstINFO) {
329          String defaultSoftware = libraryName() + " " + libraryVersion();              lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO);
330          String defaultComments = "Created with " + libraryName() + " " + libraryVersion();  
331                // assemble default values
332                defaultName = "NONAME";
333    
334                if (resourceType == RIFF_TYPE_DLS) {
335                    // get current date
336                    time_t now = time(NULL);
337                    tm* pNowBroken = localtime(&now);
338                    char buf[11];
339                    strftime(buf, 11, "%F", pNowBroken);
340                    defaultCreationDate = buf;
341    
342                    defaultComments = "Created with " + libraryName() + " " + libraryVersion();
343                }
344                if (resourceType == RIFF_TYPE_DLS || resourceType == LIST_TYPE_INS)
345                {
346                    defaultSoftware = libraryName() + " " + libraryVersion();
347                }
348            }
349    
350          // save values          // save values
351          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName);  
352          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""));          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""));
353          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate);          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""));
354            SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""));
355          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments);          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments);
         SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""));  
356          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""));          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""));
357          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""));          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate);
358            SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""));
359          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""));          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""));
360          SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String(""));          SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String(""));
         SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""));  
         SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""));  
         SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware);  
361          SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""));          SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""));
362            SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName);
363            SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""));
364            SaveString(CHUNK_ID_ISBJ, lstINFO, Subject, String(""));
365            SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware);
366          SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""));          SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""));
367          SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""));          SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""));
368          SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""));          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""));
369      }      }
370    
371    
# Line 383  namespace DLS { Line 414  namespace DLS {
414       */       */
415      void Resource::UpdateChunks() {      void Resource::UpdateChunks() {
416          pInfo->UpdateChunks();          pInfo->UpdateChunks();
417          //TODO: save DLSID  
418            if (pDLSID) {
419                // make sure 'dlid' chunk exists
420                RIFF::Chunk* ckDLSID = pResourceList->GetSubChunk(CHUNK_ID_DLID);
421                if (!ckDLSID) ckDLSID = pResourceList->AddSubChunk(CHUNK_ID_DLID, 16);
422                uint8_t* pData = (uint8_t*)ckDLSID->LoadChunkData();
423                // update 'dlid' chunk
424                store32(&pData[0], pDLSID->ulData1);
425                store16(&pData[4], pDLSID->usData2);
426                store16(&pData[6], pDLSID->usData3);
427                memcpy(&pData[8], pDLSID->abData, 8);
428            }
429      }      }
430    
431        /**
432         * Generates a new DLSID for the resource.
433         */
434        void Resource::GenerateDLSID() {
435    #if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE)
436    
437            if (!pDLSID) pDLSID = new dlsid_t;
438    
439    #ifdef WIN32
440    
441            UUID uuid;
442            UuidCreate(&uuid);
443            pDLSID->ulData1 = uuid.Data1;
444            pDLSID->usData2 = uuid.Data2;
445            pDLSID->usData3 = uuid.Data3;
446            memcpy(pDLSID->abData, uuid.Data4, 8);
447    
448    #elif defined(__APPLE__)
449    
450            CFUUIDRef uuidRef = CFUUIDCreate(NULL);
451            CFUUIDBytes uuid = CFUUIDGetUUIDBytes(uuidRef);
452            CFRelease(uuidRef);
453            pDLSID->ulData1 = uuid.byte0 | uuid.byte1 << 8 | uuid.byte2 << 16 | uuid.byte3 << 24;
454            pDLSID->usData2 = uuid.byte4 | uuid.byte5 << 8;
455            pDLSID->usData3 = uuid.byte6 | uuid.byte7 << 8;
456            pDLSID->abData[0] = uuid.byte8;
457            pDLSID->abData[1] = uuid.byte9;
458            pDLSID->abData[2] = uuid.byte10;
459            pDLSID->abData[3] = uuid.byte11;
460            pDLSID->abData[4] = uuid.byte12;
461            pDLSID->abData[5] = uuid.byte13;
462            pDLSID->abData[6] = uuid.byte14;
463            pDLSID->abData[7] = uuid.byte15;
464    #else
465            uuid_t uuid;
466            uuid_generate(uuid);
467            pDLSID->ulData1 = uuid[0] | uuid[1] << 8 | uuid[2] << 16 | uuid[3] << 24;
468            pDLSID->usData2 = uuid[4] | uuid[5] << 8;
469            pDLSID->usData3 = uuid[6] | uuid[7] << 8;
470            memcpy(pDLSID->abData, &uuid[8], 8);
471    #endif
472    #endif
473        }
474    
475    
476  // *************** Sampler ***************  // *************** Sampler ***************
# Line 402  namespace DLS { Line 487  namespace DLS {
487              SamplerOptions = wsmp->ReadUint32();              SamplerOptions = wsmp->ReadUint32();
488              SampleLoops    = wsmp->ReadUint32();              SampleLoops    = wsmp->ReadUint32();
489          } else { // 'wsmp' chunk missing          } else { // 'wsmp' chunk missing
490              uiHeaderSize   = 0;              uiHeaderSize   = 20;
491              UnityNote      = 64;              UnityNote      = 60;
492              FineTune       = 0; // +- 0 cents              FineTune       = 0; // +- 0 cents
493              Gain           = 0; // 0 dB              Gain           = 0; // 0 dB
494              SamplerOptions = F_WSMP_NO_COMPRESSION;              SamplerOptions = F_WSMP_NO_COMPRESSION;
# Line 427  namespace DLS { Line 512  namespace DLS {
512          if (pSampleLoops) delete[] pSampleLoops;          if (pSampleLoops) delete[] pSampleLoops;
513      }      }
514    
515        void Sampler::SetGain(int32_t gain) {
516            Gain = gain;
517        }
518    
519      /**      /**
520       * Apply all sample player options to the respective RIFF chunk. You       * Apply all sample player options to the respective RIFF chunk. You
521       * have to call File::Save() to make changes persistent.       * have to call File::Save() to make changes persistent.
# Line 434  namespace DLS { Line 523  namespace DLS {
523      void Sampler::UpdateChunks() {      void Sampler::UpdateChunks() {
524          // make sure 'wsmp' chunk exists          // make sure 'wsmp' chunk exists
525          RIFF::Chunk* wsmp = pParentList->GetSubChunk(CHUNK_ID_WSMP);          RIFF::Chunk* wsmp = pParentList->GetSubChunk(CHUNK_ID_WSMP);
526            int wsmpSize = uiHeaderSize + SampleLoops * 16;
527          if (!wsmp) {          if (!wsmp) {
528              uiHeaderSize = 20;              wsmp = pParentList->AddSubChunk(CHUNK_ID_WSMP, wsmpSize);
529              wsmp = pParentList->AddSubChunk(CHUNK_ID_WSMP, uiHeaderSize + SampleLoops * 16);          } else if (wsmp->GetSize() != wsmpSize) {
530                wsmp->Resize(wsmpSize);
531          }          }
532          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();
533          // update headers size          // update headers size
534          memccpy(&pData[0], &uiHeaderSize, 1, 4);          store32(&pData[0], uiHeaderSize);
535          // update respective sampler options bits          // update respective sampler options bits
536          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION
537                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);
538          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION
539                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);
540            store16(&pData[4], UnityNote);
541            store16(&pData[6], FineTune);
542            store32(&pData[8], Gain);
543            store32(&pData[12], SamplerOptions);
544            store32(&pData[16], SampleLoops);
545          // update loop definitions          // update loop definitions
546          for (uint32_t i = 0; i < SampleLoops; i++) {          for (uint32_t i = 0; i < SampleLoops; i++) {
547              //FIXME: this does not handle extended loop structs correctly              //FIXME: this does not handle extended loop structs correctly
548              memccpy(&pData[uiHeaderSize + i * 16], pSampleLoops + i, 4, 4);              store32(&pData[uiHeaderSize + i * 16], pSampleLoops[i].Size);
549                store32(&pData[uiHeaderSize + i * 16 + 4], pSampleLoops[i].LoopType);
550                store32(&pData[uiHeaderSize + i * 16 + 8], pSampleLoops[i].LoopStart);
551                store32(&pData[uiHeaderSize + i * 16 + 12], pSampleLoops[i].LoopLength);
552          }          }
553      }      }
554    
555        /**
556         * Adds a new sample loop with the provided loop definition.
557         *
558         * @param pLoopDef - points to a loop definition that is to be copied
559         */
560        void Sampler::AddSampleLoop(sample_loop_t* pLoopDef) {
561            sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops + 1];
562            // copy old loops array
563            for (int i = 0; i < SampleLoops; i++) {
564                pNewLoops[i] = pSampleLoops[i];
565            }
566            // add the new loop
567            pNewLoops[SampleLoops] = *pLoopDef;
568            // auto correct size field
569            pNewLoops[SampleLoops].Size = sizeof(DLS::sample_loop_t);
570            // free the old array and update the member variables
571            if (SampleLoops) delete[] pSampleLoops;
572            pSampleLoops = pNewLoops;
573            SampleLoops++;
574        }
575    
576        /**
577         * Deletes an existing sample loop.
578         *
579         * @param pLoopDef - pointer to existing loop definition
580         * @throws Exception - if given loop definition does not exist
581         */
582        void Sampler::DeleteSampleLoop(sample_loop_t* pLoopDef) {
583            sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops - 1];
584            // copy old loops array (skipping given loop)
585            for (int i = 0, o = 0; i < SampleLoops; i++) {
586                if (&pSampleLoops[i] == pLoopDef) continue;
587                if (o == SampleLoops - 1)
588                    throw Exception("Could not delete Sample Loop, because it does not exist");
589                pNewLoops[o] = pSampleLoops[i];
590                o++;
591            }
592            // free the old array and update the member variables
593            if (SampleLoops) delete[] pSampleLoops;
594            pSampleLoops = pNewLoops;
595            SampleLoops--;
596        }
597    
598    
599    
600  // *************** Sample ***************  // *************** Sample ***************
# Line 486  namespace DLS { Line 628  namespace DLS {
628              AverageBytesPerSecond  = pCkFormat->ReadUint32();              AverageBytesPerSecond  = pCkFormat->ReadUint32();
629              BlockAlign             = pCkFormat->ReadUint16();              BlockAlign             = pCkFormat->ReadUint16();
630              // PCM format specific              // PCM format specific
631              if (FormatTag == WAVE_FORMAT_PCM) {              if (FormatTag == DLS_WAVE_FORMAT_PCM) {
632                  BitDepth     = pCkFormat->ReadUint16();                  BitDepth     = pCkFormat->ReadUint16();
633                  FrameSize    = (FormatTag == WAVE_FORMAT_PCM) ? (BitDepth / 8) * Channels                  FrameSize    = (BitDepth / 8) * Channels;
                                                             : 0;  
634              } else { // unsupported sample data format              } else { // unsupported sample data format
635                  BitDepth     = 0;                  BitDepth     = 0;
636                  FrameSize    = 0;                  FrameSize    = 0;
637              }              }
638          } else { // 'fmt' chunk missing          } else { // 'fmt' chunk missing
639              FormatTag              = WAVE_FORMAT_PCM;              FormatTag              = DLS_WAVE_FORMAT_PCM;
640              BitDepth               = 16;              BitDepth               = 16;
641              Channels               = 1;              Channels               = 1;
642              SamplesPerSecond       = 44100;              SamplesPerSecond       = 44100;
# Line 503  namespace DLS { Line 644  namespace DLS {
644              FrameSize              = (BitDepth / 8) * Channels;              FrameSize              = (BitDepth / 8) * Channels;
645              BlockAlign             = FrameSize;              BlockAlign             = FrameSize;
646          }          }
647          SamplesTotal = (pCkData) ? (FormatTag == WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize          SamplesTotal = (pCkData) ? (FormatTag == DLS_WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize
648                                                                    : 0                                                                        : 0
649                                   : 0;                                   : 0;
650      }      }
651    
# Line 564  namespace DLS { Line 705  namespace DLS {
705       * the RIFF chunk which encapsulates the sample's wave data. The       * the RIFF chunk which encapsulates the sample's wave data. The
706       * returned value is dependant to the current FrameSize value.       * returned value is dependant to the current FrameSize value.
707       *       *
708       * @returns number of sample points or 0 if FormatTag != WAVE_FORMAT_PCM       * @returns number of sample points or 0 if FormatTag != DLS_WAVE_FORMAT_PCM
709       * @see FrameSize, FormatTag       * @see FrameSize, FormatTag
710       */       */
711      unsigned long Sample::GetSize() {      unsigned long Sample::GetSize() {
712          if (FormatTag != WAVE_FORMAT_PCM) return 0;          if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0;
713          return (pCkData) ? pCkData->GetSize() / FrameSize : 0;          return (pCkData) ? pCkData->GetSize() / FrameSize : 0;
714      }      }
715    
# Line 590  namespace DLS { Line 731  namespace DLS {
731       * calling File::Save() as this might exceed the current sample's       * calling File::Save() as this might exceed the current sample's
732       * boundary!       * boundary!
733       *       *
734       * Also note: only WAVE_FORMAT_PCM is currently supported, that is       * Also note: only DLS_WAVE_FORMAT_PCM is currently supported, that is
735       * FormatTag must be WAVE_FORMAT_PCM. Trying to resize samples with       * FormatTag must be DLS_WAVE_FORMAT_PCM. Trying to resize samples with
736       * other formats will fail!       * other formats will fail!
737       *       *
738       * @param iNewSize - new sample wave data size in sample points (must be       * @param iNewSize - new sample wave data size in sample points (must be
739       *                   greater than zero)       *                   greater than zero)
740       * @throws Excecption if FormatTag != WAVE_FORMAT_PCM       * @throws Excecption if FormatTag != DLS_WAVE_FORMAT_PCM
741       * @throws Exception if \a iNewSize is less than 1       * @throws Exception if \a iNewSize is less than 1
742       * @see File::Save(), FrameSize, FormatTag       * @see File::Save(), FrameSize, FormatTag
743       */       */
744      void Sample::Resize(int iNewSize) {      void Sample::Resize(int iNewSize) {
745          if (FormatTag != WAVE_FORMAT_PCM) throw Exception("Sample's format is not WAVE_FORMAT_PCM");          if (FormatTag != DLS_WAVE_FORMAT_PCM) throw Exception("Sample's format is not DLS_WAVE_FORMAT_PCM");
746          if (iNewSize < 1) throw Exception("Sample size must be at least one sample point");          if (iNewSize < 1) throw Exception("Sample size must be at least one sample point");
747          const int iSizeInBytes = iNewSize * FrameSize;          const int iSizeInBytes = iNewSize * FrameSize;
748          pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA);          pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA);
# Line 614  namespace DLS { Line 755  namespace DLS {
755       * bytes). Use this method and <i>Read()</i> if you don't want to load       * bytes). Use this method and <i>Read()</i> if you don't want to load
756       * the sample into RAM, thus for disk streaming.       * the sample into RAM, thus for disk streaming.
757       *       *
758       * Also note: only WAVE_FORMAT_PCM is currently supported, that is       * Also note: only DLS_WAVE_FORMAT_PCM is currently supported, that is
759       * FormatTag must be WAVE_FORMAT_PCM. Trying to reposition the sample       * FormatTag must be DLS_WAVE_FORMAT_PCM. Trying to reposition the sample
760       * with other formats will fail!       * with other formats will fail!
761       *       *
762       * @param SampleCount  number of sample points       * @param SampleCount  number of sample points
763       * @param Whence       to which relation \a SampleCount refers to       * @param Whence       to which relation \a SampleCount refers to
764       * @returns new position within the sample, 0 if       * @returns new position within the sample, 0 if
765       *          FormatTag != WAVE_FORMAT_PCM       *          FormatTag != DLS_WAVE_FORMAT_PCM
766       * @throws Exception if no data RIFF chunk was created for the sample yet       * @throws Exception if no data RIFF chunk was created for the sample yet
767       * @see FrameSize, FormatTag       * @see FrameSize, FormatTag
768       */       */
769      unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {      unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {
770          if (FormatTag != WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format          if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format
771          if (!pCkData) throw Exception("No data chunk created for sample yet, call Sample::Resize() to create one");          if (!pCkData) throw Exception("No data chunk created for sample yet, call Sample::Resize() to create one");
772          unsigned long orderedBytes = SampleCount * FrameSize;          unsigned long orderedBytes = SampleCount * FrameSize;
773          unsigned long result = pCkData->SetPos(orderedBytes, Whence);          unsigned long result = pCkData->SetPos(orderedBytes, Whence);
# Line 644  namespace DLS { Line 785  namespace DLS {
785       * @param SampleCount  number of sample points to read       * @param SampleCount  number of sample points to read
786       */       */
787      unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {      unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {
788          if (FormatTag != WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format          if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format
789          return pCkData->Read(pBuffer, SampleCount, FrameSize); // FIXME: channel inversion due to endian correction?          return pCkData->Read(pBuffer, SampleCount, FrameSize); // FIXME: channel inversion due to endian correction?
790      }      }
791    
# Line 664  namespace DLS { Line 805  namespace DLS {
805       * @see LoadSampleData()       * @see LoadSampleData()
806       */       */
807      unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) {      unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) {
808          if (FormatTag != WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format          if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format
809          if (GetSize() < SampleCount) throw Exception("Could not write sample data, current sample size to small");          if (GetSize() < SampleCount) throw Exception("Could not write sample data, current sample size to small");
810          return pCkData->Write(pBuffer, SampleCount, FrameSize); // FIXME: channel inversion due to endian correction?          return pCkData->Write(pBuffer, SampleCount, FrameSize); // FIXME: channel inversion due to endian correction?
811      }      }
# Line 673  namespace DLS { Line 814  namespace DLS {
814       * Apply sample and its settings to the respective RIFF chunks. You have       * Apply sample and its settings to the respective RIFF chunks. You have
815       * to call File::Save() to make changes persistent.       * to call File::Save() to make changes persistent.
816       *       *
817       * @throws Exception if FormatTag != WAVE_FORMAT_PCM or no sample data       * @throws Exception if FormatTag != DLS_WAVE_FORMAT_PCM or no sample data
818       *                   was provided yet       *                   was provided yet
819       */       */
820      void Sample::UpdateChunks() {      void Sample::UpdateChunks() {
821          if (FormatTag != WAVE_FORMAT_PCM)          if (FormatTag != DLS_WAVE_FORMAT_PCM)
822              throw Exception("Could not save sample, only PCM format is supported");              throw Exception("Could not save sample, only PCM format is supported");
823          // we refuse to do anything if not sample wave form was provided yet          // we refuse to do anything if not sample wave form was provided yet
824          if (!pCkData)          if (!pCkData)
# Line 689  namespace DLS { Line 830  namespace DLS {
830          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format
831          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();
832          // update 'fmt' chunk          // update 'fmt' chunk
833          memccpy(&pData[0], &FormatTag, 1, 2);          store16(&pData[0], FormatTag);
834          memccpy(&pData[2], &Channels,  1, 2);          store16(&pData[2], Channels);
835          memccpy(&pData[4], &SamplesPerSecond, 1, 4);          store32(&pData[4], SamplesPerSecond);
836          memccpy(&pData[8], &AverageBytesPerSecond, 1, 4);          store32(&pData[8], AverageBytesPerSecond);
837          memccpy(&pData[12], &BlockAlign, 1, 2);          store16(&pData[12], BlockAlign);
838          memccpy(&pData[14], &BitDepth, 1, 2); // assuming PCM format          store16(&pData[14], BitDepth); // assuming PCM format
839      }      }
840    
841    
# Line 778  namespace DLS { Line 919  namespace DLS {
919      }      }
920    
921      /**      /**
922         * Modifies the key range of this Region and makes sure the respective
923         * chunks are in correct order.
924         *
925         * @param Low  - lower end of key range
926         * @param High - upper end of key range
927         */
928        void Region::SetKeyRange(uint16_t Low, uint16_t High) {
929            KeyRange.low  = Low;
930            KeyRange.high = High;
931    
932            // make sure regions are already loaded
933            Instrument* pInstrument = (Instrument*) GetParent();
934            if (!pInstrument->pRegions) pInstrument->LoadRegions();
935            if (!pInstrument->pRegions) return;
936    
937            // find the r which is the first one to the right of this region
938            // at its new position
939            Region* r = NULL;
940            Region* prev_region = NULL;
941            for (
942                Instrument::RegionList::iterator iter = pInstrument->pRegions->begin();
943                iter != pInstrument->pRegions->end(); iter++
944            ) {
945                if ((*iter)->KeyRange.low > this->KeyRange.low) {
946                    r = *iter;
947                    break;
948                }
949                prev_region = *iter;
950            }
951    
952            // place this region before r if it's not already there
953            if (prev_region != this) pInstrument->MoveRegion(this, r);
954        }
955    
956        /**
957       * Apply Region settings to the respective RIFF chunks. You have to       * Apply Region settings to the respective RIFF chunks. You have to
958       * call File::Save() to make changes persistent.       * call File::Save() to make changes persistent.
959       *       *
# Line 786  namespace DLS { Line 962  namespace DLS {
962      void Region::UpdateChunks() {      void Region::UpdateChunks() {
963          // make sure 'rgnh' chunk exists          // make sure 'rgnh' chunk exists
964          RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH);          RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH);
965          if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, 14);          if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, Layer ? 14 : 12);
966          uint8_t* pData = (uint8_t*) rgnh->LoadChunkData();          uint8_t* pData = (uint8_t*) rgnh->LoadChunkData();
967          FormatOptionFlags = (SelfNonExclusive)          FormatOptionFlags = (SelfNonExclusive)
968                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE
969                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);
970          // update 'rgnh' chunk          // update 'rgnh' chunk
971          memccpy(&pData[0], &KeyRange, 2, 2);          store16(&pData[0], KeyRange.low);
972          memccpy(&pData[4], &VelocityRange, 2, 2);          store16(&pData[2], KeyRange.high);
973          memccpy(&pData[8], &FormatOptionFlags, 1, 2);          store16(&pData[4], VelocityRange.low);
974          memccpy(&pData[10], &KeyGroup, 1, 2);          store16(&pData[6], VelocityRange.high);
975          memccpy(&pData[12], &Layer, 1, 2);          store16(&pData[8], FormatOptionFlags);
976            store16(&pData[10], KeyGroup);
977            if (rgnh->GetSize() >= 14) store16(&pData[12], Layer);
978    
979          // update chunks of base classes as well          // update chunks of base classes as well (but skip Resource,
980          Resource::UpdateChunks();          // as a rgn doesn't seem to have dlid and INFO chunks)
981          Articulator::UpdateChunks();          Articulator::UpdateChunks();
982          Sampler::UpdateChunks();          Sampler::UpdateChunks();
983    
# Line 816  namespace DLS { Line 994  namespace DLS {
994          // get sample's wave pool table index          // get sample's wave pool table index
995          int index = -1;          int index = -1;
996          File* pFile = (File*) GetParent()->GetParent();          File* pFile = (File*) GetParent()->GetParent();
997          File::SampleList::iterator iter = pFile->pSamples->begin();          if (pFile->pSamples) {
998          File::SampleList::iterator end  = pFile->pSamples->end();              File::SampleList::iterator iter = pFile->pSamples->begin();
999          for (int i = 0; iter != end; ++iter, i++) {              File::SampleList::iterator end  = pFile->pSamples->end();
1000              if (*iter == pSample) {              for (int i = 0; iter != end; ++iter, i++) {
1001                  index = i;                  if (*iter == pSample) {
1002                  break;                      index = i;
1003                        break;
1004                    }
1005              }              }
1006          }          }
         if (index < 0) throw Exception("Could not save Region, could not find Region's sample");  
1007          WavePoolTableIndex = index;          WavePoolTableIndex = index;
1008          // update 'wlnk' chunk          // update 'wlnk' chunk
1009          memccpy(&pData[0], &WaveLinkOptionFlags, 1, 2);          store16(&pData[0], WaveLinkOptionFlags);
1010          memccpy(&pData[2], &PhaseGroup, 1, 2);          store16(&pData[2], PhaseGroup);
1011          memccpy(&pData[4], &Channel, 1, 4);          store32(&pData[4], Channel);
1012          memccpy(&pData[8], &WavePoolTableIndex, 1, 4);          store32(&pData[8], WavePoolTableIndex);
1013      }      }
1014    
1015    
# Line 888  namespace DLS { Line 1067  namespace DLS {
1067      }      }
1068    
1069      void Instrument::LoadRegions() {      void Instrument::LoadRegions() {
1070            if (!pRegions) pRegions = new RegionList;
1071          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
1072          if (!lrgn) throw DLS::Exception("Mandatory chunks in <ins > chunk not found.");          if (lrgn) {
1073          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
1074          RIFF::List* rgn = lrgn->GetFirstSubList();              RIFF::List* rgn = lrgn->GetFirstSubList();
1075          while (rgn) {              while (rgn) {
1076              if (rgn->GetListType() == regionCkType) {                  if (rgn->GetListType() == regionCkType) {
1077                  if (!pRegions) pRegions = new RegionList;                      pRegions->push_back(new Region(this, rgn));
1078                  pRegions->push_back(new Region(this, rgn));                  }
1079                    rgn = lrgn->GetNextSubList();
1080              }              }
             rgn = lrgn->GetNextSubList();  
1081          }          }
1082      }      }
1083    
1084      Region* Instrument::AddRegion() {      Region* Instrument::AddRegion() {
1085          if (!pRegions) pRegions = new RegionList;          if (!pRegions) LoadRegions();
1086          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
1087          if (!lrgn)  lrgn = pCkInstrument->AddSubList(LIST_TYPE_LRGN);          if (!lrgn)  lrgn = pCkInstrument->AddSubList(LIST_TYPE_LRGN);
1088          RIFF::List* rgn = lrgn->AddSubList(LIST_TYPE_RGN);          RIFF::List* rgn = lrgn->AddSubList(LIST_TYPE_RGN);
1089          Region* pNewRegion = new Region(this, rgn);          Region* pNewRegion = new Region(this, rgn);
1090          pRegions->push_back(pNewRegion);          pRegions->push_back(pNewRegion);
1091            Regions = pRegions->size();
1092          return pNewRegion;          return pNewRegion;
1093      }      }
1094    
1095        void Instrument::MoveRegion(Region* pSrc, Region* pDst) {
1096            RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
1097            lrgn->MoveSubChunk(pSrc->pCkRegion, pDst ? pDst->pCkRegion : 0);
1098    
1099            pRegions->remove(pSrc);
1100            RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pDst);
1101            pRegions->insert(iter, pSrc);
1102        }
1103    
1104      void Instrument::DeleteRegion(Region* pRegion) {      void Instrument::DeleteRegion(Region* pRegion) {
1105            if (!pRegions) return;
1106          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);
1107          if (iter == pRegions->end()) return;          if (iter == pRegions->end()) return;
1108          pRegions->erase(iter);          pRegions->erase(iter);
1109            Regions = pRegions->size();
1110          delete pRegion;          delete pRegion;
1111      }      }
1112    
# Line 933  namespace DLS { Line 1125  namespace DLS {
1125          if (!insh) insh = pCkInstrument->AddSubChunk(CHUNK_ID_INSH, 12);          if (!insh) insh = pCkInstrument->AddSubChunk(CHUNK_ID_INSH, 12);
1126          uint8_t* pData = (uint8_t*) insh->LoadChunkData();          uint8_t* pData = (uint8_t*) insh->LoadChunkData();
1127          // update 'insh' chunk          // update 'insh' chunk
1128          Regions = pRegions->size();          Regions = (pRegions) ? pRegions->size() : 0;
1129          midi_locale_t locale;          midi_locale_t locale;
1130          locale.instrument = MIDIProgram;          locale.instrument = MIDIProgram;
1131          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);
1132          locale.bank       = (IsDrum) ? locale.bank | DRUM_TYPE_MASK : locale.bank & (~DRUM_TYPE_MASK);          locale.bank       = (IsDrum) ? locale.bank | DRUM_TYPE_MASK : locale.bank & (~DRUM_TYPE_MASK);
1133          MIDIBank          = MIDI_BANK_MERGE(MIDIBankCoarse, MIDIBankFine); // just a sync, when we're at it          MIDIBank          = MIDI_BANK_MERGE(MIDIBankCoarse, MIDIBankFine); // just a sync, when we're at it
1134          memccpy(&pData[0], &Regions, 1, 4);          store32(&pData[0], Regions);
1135          memccpy(&pData[4], &locale, 2, 4);          store32(&pData[4], locale.bank);
1136            store32(&pData[8], locale.instrument);
1137          // update Region's chunks          // update Region's chunks
1138            if (!pRegions) return;
1139          RegionList::iterator iter = pRegions->begin();          RegionList::iterator iter = pRegions->begin();
1140          RegionList::iterator end  = pRegions->end();          RegionList::iterator end  = pRegions->end();
1141          for (; iter != end; ++iter) {          for (; iter != end; ++iter) {
# Line 980  namespace DLS { Line 1174  namespace DLS {
1174       * to add samples, instruments and finally call Save() to actually write       * to add samples, instruments and finally call Save() to actually write
1175       * a DLS file.       * a DLS file.
1176       */       */
1177      File::File() : pRIFF(new RIFF::File(RIFF_TYPE_DLS)), Resource(NULL, pRIFF) {      File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) {
1178            pRIFF->SetByteOrder(RIFF::endian_little);
1179          pVersion = new version_t;          pVersion = new version_t;
1180          pVersion->major   = 0;          pVersion->major   = 0;
1181          pVersion->minor   = 0;          pVersion->minor   = 0;
# Line 1024  namespace DLS { Line 1219  namespace DLS {
1219          Instruments = colh->ReadUint32();          Instruments = colh->ReadUint32();
1220    
1221          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);
1222          if (!ptbl) throw DLS::Exception("Mandatory <ptbl> chunk not found.");          if (!ptbl) { // pool table is missing - this is probably an ".art" file
1223          WavePoolHeaderSize = ptbl->ReadUint32();              WavePoolCount    = 0;
1224          WavePoolCount  = ptbl->ReadUint32();              pWavePoolTable   = NULL;
1225          pWavePoolTable = new uint32_t[WavePoolCount];              pWavePoolTableHi = NULL;
1226          pWavePoolTableHi = new uint32_t[WavePoolCount];              WavePoolHeaderSize = 8;
1227          ptbl->SetPos(WavePoolHeaderSize);              b64BitWavePoolOffsets = false;
1228            } else {
1229          // Check for 64 bit offsets (used in gig v3 files)              WavePoolHeaderSize = ptbl->ReadUint32();
1230          b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8);              WavePoolCount  = ptbl->ReadUint32();
1231          if (b64BitWavePoolOffsets) {              pWavePoolTable = new uint32_t[WavePoolCount];
1232              for (int i = 0 ; i < WavePoolCount ; i++) {              pWavePoolTableHi = new uint32_t[WavePoolCount];
1233                  pWavePoolTableHi[i] = ptbl->ReadUint32();              ptbl->SetPos(WavePoolHeaderSize);
1234                  pWavePoolTable[i] = ptbl->ReadUint32();  
1235                  if (pWavePoolTable[i] & 0x80000000)              // Check for 64 bit offsets (used in gig v3 files)
1236                      throw DLS::Exception("Files larger than 2 GB not yet supported");              b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8);
1237                if (b64BitWavePoolOffsets) {
1238                    for (int i = 0 ; i < WavePoolCount ; i++) {
1239                        pWavePoolTableHi[i] = ptbl->ReadUint32();
1240                        pWavePoolTable[i] = ptbl->ReadUint32();
1241                        if (pWavePoolTable[i] & 0x80000000)
1242                            throw DLS::Exception("Files larger than 2 GB not yet supported");
1243                    }
1244                } else { // conventional 32 bit offsets
1245                    ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));
1246                    for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;
1247              }              }
         } else { // conventional 32 bit offsets  
             ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));  
             for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;  
1248          }          }
1249    
1250          pSamples     = NULL;          pSamples     = NULL;
# Line 1073  namespace DLS { Line 1275  namespace DLS {
1275          if (pWavePoolTable) delete[] pWavePoolTable;          if (pWavePoolTable) delete[] pWavePoolTable;
1276          if (pWavePoolTableHi) delete[] pWavePoolTableHi;          if (pWavePoolTableHi) delete[] pWavePoolTableHi;
1277          if (pVersion) delete pVersion;          if (pVersion) delete pVersion;
1278            for (std::list<RIFF::File*>::iterator i = ExtensionFiles.begin() ; i != ExtensionFiles.end() ; i++)
1279                delete *i;
1280      }      }
1281    
1282      Sample* File::GetFirstSample() {      Sample* File::GetFirstSample() {
# Line 1089  namespace DLS { Line 1293  namespace DLS {
1293      }      }
1294    
1295      void File::LoadSamples() {      void File::LoadSamples() {
1296            if (!pSamples) pSamples = new SampleList;
1297          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
1298          if (wvpl) {          if (wvpl) {
1299              unsigned long wvplFileOffset = wvpl->GetFilePos();              unsigned long wvplFileOffset = wvpl->GetFilePos();
1300              RIFF::List* wave = wvpl->GetFirstSubList();              RIFF::List* wave = wvpl->GetFirstSubList();
1301              while (wave) {              while (wave) {
1302                  if (wave->GetListType() == LIST_TYPE_WAVE) {                  if (wave->GetListType() == LIST_TYPE_WAVE) {
                     if (!pSamples) pSamples = new SampleList;  
1303                      unsigned long waveFileOffset = wave->GetFilePos();                      unsigned long waveFileOffset = wave->GetFilePos();
1304                      pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));                      pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));
1305                  }                  }
# Line 1109  namespace DLS { Line 1313  namespace DLS {
1313                  RIFF::List* wave = dwpl->GetFirstSubList();                  RIFF::List* wave = dwpl->GetFirstSubList();
1314                  while (wave) {                  while (wave) {
1315                      if (wave->GetListType() == LIST_TYPE_WAVE) {                      if (wave->GetListType() == LIST_TYPE_WAVE) {
                         if (!pSamples) pSamples = new SampleList;  
1316                          unsigned long waveFileOffset = wave->GetFilePos();                          unsigned long waveFileOffset = wave->GetFilePos();
1317                          pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset));                          pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset));
1318                      }                      }
# Line 1127  namespace DLS { Line 1330  namespace DLS {
1330       * @returns pointer to new Sample object       * @returns pointer to new Sample object
1331       */       */
1332      Sample* File::AddSample() {      Sample* File::AddSample() {
1333           if (!pSamples) LoadSamples();
1334         __ensureMandatoryChunksExist();         __ensureMandatoryChunksExist();
1335         RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);         RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
1336         // create new Sample object and its respective 'wave' list chunk         // create new Sample object and its respective 'wave' list chunk
        if (!pSamples) pSamples = new SampleList;  
1337         RIFF::List* wave = wvpl->AddSubList(LIST_TYPE_WAVE);         RIFF::List* wave = wvpl->AddSubList(LIST_TYPE_WAVE);
1338         Sample* pSample = new Sample(this, wave, 0 /*arbitrary value, we update offsets when we save*/);         Sample* pSample = new Sample(this, wave, 0 /*arbitrary value, we update offsets when we save*/);
1339         pSamples->push_back(pSample);         pSamples->push_back(pSample);
# Line 1145  namespace DLS { Line 1348  namespace DLS {
1348       * @param pSample - sample to delete       * @param pSample - sample to delete
1349       */       */
1350      void File::DeleteSample(Sample* pSample) {      void File::DeleteSample(Sample* pSample) {
1351            if (!pSamples) return;
1352          SampleList::iterator iter = find(pSamples->begin(), pSamples->end(), pSample);          SampleList::iterator iter = find(pSamples->begin(), pSamples->end(), pSample);
1353          if (iter == pSamples->end()) return;          if (iter == pSamples->end()) return;
1354          pSamples->erase(iter);          pSamples->erase(iter);
# Line 1165  namespace DLS { Line 1369  namespace DLS {
1369      }      }
1370    
1371      void File::LoadInstruments() {      void File::LoadInstruments() {
1372            if (!pInstruments) pInstruments = new InstrumentList;
1373          RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);          RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
1374          if (lstInstruments) {          if (lstInstruments) {
1375              RIFF::List* lstInstr = lstInstruments->GetFirstSubList();              RIFF::List* lstInstr = lstInstruments->GetFirstSubList();
1376              while (lstInstr) {              while (lstInstr) {
1377                  if (lstInstr->GetListType() == LIST_TYPE_INS) {                  if (lstInstr->GetListType() == LIST_TYPE_INS) {
                     if (!pInstruments) pInstruments = new InstrumentList;  
1378                      pInstruments->push_back(new Instrument(this, lstInstr));                      pInstruments->push_back(new Instrument(this, lstInstr));
1379                  }                  }
1380                  lstInstr = lstInstruments->GetNextSubList();                  lstInstr = lstInstruments->GetNextSubList();
# Line 1186  namespace DLS { Line 1390  namespace DLS {
1390       * @returns pointer to new Instrument object       * @returns pointer to new Instrument object
1391       */       */
1392      Instrument* File::AddInstrument() {      Instrument* File::AddInstrument() {
1393           if (!pInstruments) LoadInstruments();
1394         __ensureMandatoryChunksExist();         __ensureMandatoryChunksExist();
        if (!pInstruments) pInstruments = new InstrumentList;  
1395         RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);         RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
1396         RIFF::List* lstInstr = lstInstruments->AddSubList(LIST_TYPE_INS);         RIFF::List* lstInstr = lstInstruments->AddSubList(LIST_TYPE_INS);
1397         Instrument* pInstrument = new Instrument(this, lstInstr);         Instrument* pInstrument = new Instrument(this, lstInstr);
# Line 1195  namespace DLS { Line 1399  namespace DLS {
1399         return pInstrument;         return pInstrument;
1400      }      }
1401    
1402      /** @brief Delete a instrument.      /** @brief Delete an instrument.
1403       *       *
1404       * This will delete the given Instrument object from the DLS file. You       * This will delete the given Instrument object from the DLS file. You
1405       * have to call Save() to make this persistent to the file.       * have to call Save() to make this persistent to the file.
# Line 1203  namespace DLS { Line 1407  namespace DLS {
1407       * @param pInstrument - instrument to delete       * @param pInstrument - instrument to delete
1408       */       */
1409      void File::DeleteInstrument(Instrument* pInstrument) {      void File::DeleteInstrument(Instrument* pInstrument) {
1410            if (!pInstruments) return;
1411          InstrumentList::iterator iter = find(pInstruments->begin(), pInstruments->end(), pInstrument);          InstrumentList::iterator iter = find(pInstruments->begin(), pInstruments->end(), pInstrument);
1412          if (iter == pInstruments->end()) return;          if (iter == pInstruments->end()) return;
1413          pInstruments->erase(iter);          pInstruments->erase(iter);
# Line 1225  namespace DLS { Line 1430  namespace DLS {
1430              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);
1431              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);
1432              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();
1433              memccpy(pData, pVersion, 2, 4);              store16(&pData[0], pVersion->minor);
1434                store16(&pData[2], pVersion->major);
1435                store16(&pData[4], pVersion->build);
1436                store16(&pData[6], pVersion->release);
1437          }          }
1438    
1439          // update 'colh' chunk          // update 'colh' chunk
# Line 1233  namespace DLS { Line 1441  namespace DLS {
1441          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);
1442          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);
1443          uint8_t* pData = (uint8_t*) colh->LoadChunkData();          uint8_t* pData = (uint8_t*) colh->LoadChunkData();
1444          memccpy(pData, &Instruments, 1, 4);          store32(pData, Instruments);
1445    
1446          // update instrument's chunks          // update instrument's chunks
1447          if (pInstruments) {          if (pInstruments) {
# Line 1253  namespace DLS { Line 1461  namespace DLS {
1461          ptbl->Resize(iPtblSize);          ptbl->Resize(iPtblSize);
1462          pData = (uint8_t*) ptbl->LoadChunkData();          pData = (uint8_t*) ptbl->LoadChunkData();
1463          WavePoolCount = iSamples;          WavePoolCount = iSamples;
1464          memccpy(&pData[4], &WavePoolCount, 1, 4);          store32(&pData[4], WavePoolCount);
1465          // we actually update the sample offsets in the pool table when we Save()          // we actually update the sample offsets in the pool table when we Save()
1466          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);
1467    
# Line 1324  namespace DLS { Line 1532  namespace DLS {
1532      /**      /**
1533       * Updates (persistently) the wave pool table with offsets to all       * Updates (persistently) the wave pool table with offsets to all
1534       * currently available samples. <b>Caution:</b> this method assumes the       * currently available samples. <b>Caution:</b> this method assumes the
1535       * 'ptbl' chunk to be already of the correct size, so usually this       * 'ptbl' chunk to be already of the correct size and the file to be
1536       * method is only called after a Save() call.       * writable, so usually this method is only called after a Save() call.
1537       *       *
1538       * @throws Exception - if 'ptbl' chunk is too small (should only occur       * @throws Exception - if 'ptbl' chunk is too small (should only occur
1539       *                     if there's a bug)       *                     if there's a bug)
# Line 1335  namespace DLS { Line 1543  namespace DLS {
1543          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);
1544          const int iOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4;          const int iOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4;
1545          // check if 'ptbl' chunk is large enough          // check if 'ptbl' chunk is large enough
1546          WavePoolCount = pSamples->size();          WavePoolCount = (pSamples) ? pSamples->size() : 0;
1547          const unsigned long ulRequiredSize = WavePoolHeaderSize + iOffsetSize * WavePoolCount;          const unsigned long ulRequiredSize = WavePoolHeaderSize + iOffsetSize * WavePoolCount;
1548          if (ptbl->GetSize() < ulRequiredSize) throw Exception("Fatal error, 'ptbl' chunk too small");          if (ptbl->GetSize() < ulRequiredSize) throw Exception("Fatal error, 'ptbl' chunk too small");
1549          uint8_t* pData = (uint8_t*) ptbl->LoadChunkData();          // save the 'ptbl' chunk's current read/write position
1550            unsigned long ulOriginalPos = ptbl->GetPos();
1551          // update headers          // update headers
1552          memccpy(&pData[0], &WavePoolHeaderSize, 1, 4);          ptbl->SetPos(0);
1553          memccpy(&pData[4], &WavePoolCount, 1, 4);          uint32_t tmp = WavePoolHeaderSize;
1554            ptbl->WriteUint32(&tmp);
1555            tmp = WavePoolCount;
1556            ptbl->WriteUint32(&tmp);
1557          // update offsets          // update offsets
1558            ptbl->SetPos(WavePoolHeaderSize);
1559          if (b64BitWavePoolOffsets) {          if (b64BitWavePoolOffsets) {
1560              for (int i = 0 ; i < WavePoolCount ; i++) {              for (int i = 0 ; i < WavePoolCount ; i++) {
1561                  memccpy(&pData[WavePoolHeaderSize + i*iOffsetSize], &pWavePoolTableHi[i], 1, 4);                  tmp = pWavePoolTableHi[i];
1562                  memccpy(&pData[WavePoolHeaderSize + i*iOffsetSize], &pWavePoolTable[i],   1, 4);                  ptbl->WriteUint32(&tmp);
1563                    tmp = pWavePoolTable[i];
1564                    ptbl->WriteUint32(&tmp);
1565              }              }
1566          } else { // conventional 32 bit offsets          } else { // conventional 32 bit offsets
1567              for (int i = 0 ; i < WavePoolCount ; i++)              for (int i = 0 ; i < WavePoolCount ; i++) {
1568                  memccpy(&pData[WavePoolHeaderSize + i*iOffsetSize], &pWavePoolTable[i], 1, 4);                  tmp = pWavePoolTable[i];
1569                    ptbl->WriteUint32(&tmp);
1570                }
1571          }          }
1572            // restore 'ptbl' chunk's original read/write position
1573            ptbl->SetPos(ulOriginalPos);
1574      }      }
1575    
1576      /**      /**
# Line 1360  namespace DLS { Line 1579  namespace DLS {
1579       * exists already.       * exists already.
1580       */       */
1581      void File::__UpdateWavePoolTable() {      void File::__UpdateWavePoolTable() {
1582          WavePoolCount = pSamples->size();          WavePoolCount = (pSamples) ? pSamples->size() : 0;
1583          // resize wave pool table arrays          // resize wave pool table arrays
1584          if (pWavePoolTable)   delete[] pWavePoolTable;          if (pWavePoolTable)   delete[] pWavePoolTable;
1585          if (pWavePoolTableHi) delete[] pWavePoolTableHi;          if (pWavePoolTableHi) delete[] pWavePoolTableHi;
1586          pWavePoolTable   = new uint32_t[WavePoolCount];          pWavePoolTable   = new uint32_t[WavePoolCount];
1587          pWavePoolTableHi = new uint32_t[WavePoolCount];          pWavePoolTableHi = new uint32_t[WavePoolCount];
1588            if (!pSamples) return;
1589          // update offsets int wave pool table          // update offsets int wave pool table
1590          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
1591          uint64_t wvplFileOffset = wvpl->GetFilePos();          uint64_t wvplFileOffset = wvpl->GetFilePos();
# Line 1373  namespace DLS { Line 1593  namespace DLS {
1593              SampleList::iterator iter = pSamples->begin();              SampleList::iterator iter = pSamples->begin();
1594              SampleList::iterator end  = pSamples->end();              SampleList::iterator end  = pSamples->end();
1595              for (int i = 0 ; iter != end ; ++iter, i++) {              for (int i = 0 ; iter != end ; ++iter, i++) {
1596                  uint64_t _64BitOffset = wvplFileOffset - (*iter)->pWaveList->GetFilePos() - LIST_HEADER_SIZE;                  uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - wvplFileOffset - LIST_HEADER_SIZE;
1597                  (*iter)->ulWavePoolOffset = _64BitOffset;                  (*iter)->ulWavePoolOffset = _64BitOffset;
1598                  pWavePoolTableHi[i] = (uint32_t) (_64BitOffset >> 32);                  pWavePoolTableHi[i] = (uint32_t) (_64BitOffset >> 32);
1599                  pWavePoolTable[i]   = (uint32_t) _64BitOffset;                  pWavePoolTable[i]   = (uint32_t) _64BitOffset;
# Line 1382  namespace DLS { Line 1602  namespace DLS {
1602              SampleList::iterator iter = pSamples->begin();              SampleList::iterator iter = pSamples->begin();
1603              SampleList::iterator end  = pSamples->end();              SampleList::iterator end  = pSamples->end();
1604              for (int i = 0 ; iter != end ; ++iter, i++) {              for (int i = 0 ; iter != end ; ++iter, i++) {
1605                  uint64_t _64BitOffset = wvplFileOffset - (*iter)->pWaveList->GetFilePos() - LIST_HEADER_SIZE;                  uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - wvplFileOffset - LIST_HEADER_SIZE;
1606                  (*iter)->ulWavePoolOffset = _64BitOffset;                  (*iter)->ulWavePoolOffset = _64BitOffset;
1607                  pWavePoolTable[i] = (uint32_t) _64BitOffset;                  pWavePoolTable[i] = (uint32_t) _64BitOffset;
1608              }              }

Legend:
Removed from v.800  
changed lines
  Added in v.1388

  ViewVC Help
Powered by ViewVC