/[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 809 by schoenebeck, Tue Nov 22 11:26:55 2005 UTC revision 2329 by schoenebeck, Mon Mar 12 14:59:10 2012 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-2009 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 45  Line 52 
52  #define CONN_TRANSFORM_INVERT_SRC_ENCODE(x)             ((x) ? 0x8000 : 0)  #define CONN_TRANSFORM_INVERT_SRC_ENCODE(x)             ((x) ? 0x8000 : 0)
53  #define CONN_TRANSFORM_INVERT_CTL_ENCODE(x)             ((x) ? 0x0200 : 0)  #define CONN_TRANSFORM_INVERT_CTL_ENCODE(x)             ((x) ? 0x0200 : 0)
54    
55  #define DRUM_TYPE_MASK                  0x00000001  #define DRUM_TYPE_MASK                  0x80000000
56    
57  #define F_RGN_OPTION_SELFNONEXCLUSIVE   0x0001  #define F_RGN_OPTION_SELFNONEXCLUSIVE   0x0001
58    
# Line 142  namespace DLS { Line 149  namespace DLS {
149          const int iEntrySize = 12; // 12 bytes per connection block          const int iEntrySize = 12; // 12 bytes per connection block
150          pArticulationCk->Resize(HeaderSize + Connections * iEntrySize);          pArticulationCk->Resize(HeaderSize + Connections * iEntrySize);
151          uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData();          uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData();
152          memccpy(&pData[0], &HeaderSize, 1, 2);          store16(&pData[0], HeaderSize);
153          memccpy(&pData[2], &Connections, 1, 2);          store16(&pData[2], Connections);
154          for (uint32_t i = 0; i < Connections; i++) {          for (uint32_t i = 0; i < Connections; i++) {
155              Connection::conn_block_t c = pConnections[i].ToConnBlock();              Connection::conn_block_t c = pConnections[i].ToConnBlock();
156              memccpy(&pData[HeaderSize + i * iEntrySize],     &c.source, 1, 2);              store16(&pData[HeaderSize + i * iEntrySize],     c.source);
157              memccpy(&pData[HeaderSize + i * iEntrySize + 2], &c.control, 1, 2);              store16(&pData[HeaderSize + i * iEntrySize + 2], c.control);
158              memccpy(&pData[HeaderSize + i * iEntrySize + 4], &c.destination, 1, 2);              store16(&pData[HeaderSize + i * iEntrySize + 4], c.destination);
159              memccpy(&pData[HeaderSize + i * iEntrySize + 6], &c.transform, 1, 2);              store16(&pData[HeaderSize + i * iEntrySize + 6], c.transform);
160              memccpy(&pData[HeaderSize + i * iEntrySize + 8], &c.scale, 1, 4);              store32(&pData[HeaderSize + i * iEntrySize + 8], c.scale);
161          }          }
162      }      }
163    
# Line 228  namespace DLS { Line 235  namespace DLS {
235    
236      /** @brief Constructor.      /** @brief Constructor.
237       *       *
238       * Initializes the info strings with values provided by a INFO list chunk.       * Initializes the info strings with values provided by an INFO list chunk.
239       *       *
240       * @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
241       */       */
242      Info::Info(RIFF::List* list) {      Info::Info(RIFF::List* list) {
243            pFixedStringLengths = NULL;
244          pResourceListChunk = list;          pResourceListChunk = list;
245          if (list) {          if (list) {
246              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);
# Line 253  namespace DLS { Line 261  namespace DLS {
261                  LoadString(CHUNK_ID_ISRC, lstINFO, Source);                  LoadString(CHUNK_ID_ISRC, lstINFO, Source);
262                  LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);                  LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);
263                  LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);                  LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);
264                    LoadString(CHUNK_ID_ISBJ, lstINFO, Subject);
265              }              }
266          }          }
267      }      }
268    
269        Info::~Info() {
270        }
271    
272        /**
273         * Forces specific Info fields to be of a fixed length when being saved
274         * to a file. By default the respective RIFF chunk of an Info field
275         * will have a size analogue to its actual string length. With this
276         * method however this behavior can be overridden, allowing to force an
277         * arbitrary fixed size individually for each Info field.
278         *
279         * This method is used as a workaround for the gig format, not for DLS.
280         *
281         * @param lengths - NULL terminated array of string_length_t elements
282         */
283        void Info::SetFixedStringLengths(const string_length_t* lengths) {
284            pFixedStringLengths = lengths;
285        }
286    
287      /** @brief Load given INFO field.      /** @brief Load given INFO field.
288       *       *
289       * 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 264  namespace DLS { Line 291  namespace DLS {
291       */       */
292      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {
293          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
294          if (ck) {          ::LoadString(ck, s); // function from helper.h
             // TODO: no check for ZSTR terminated strings yet  
             s = (char*) ck->LoadChunkData();  
             ck->ReleaseChunkData();  
         }  
295      }      }
296    
297      /** @brief Apply given INFO field to the respective chunk.      /** @brief Apply given INFO field to the respective chunk.
# Line 287  namespace DLS { Line 310  namespace DLS {
310       * @param sDefault - default value       * @param sDefault - default value
311       */       */
312      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) {
313          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          int size = 0;
314          if (ck) { // if chunk exists already, use 's' as value          if (pFixedStringLengths) {
315              ck->Resize(s.size() + 1);              for (int i = 0 ; pFixedStringLengths[i].length ; i++) {
316              char* pData = (char*) ck->LoadChunkData();                  if (pFixedStringLengths[i].chunkId == ChunkID) {
317              memcpy(pData, s.c_str(), s.size() + 1);                      size = pFixedStringLengths[i].length;
318          } else if (s != "" || sDefault != "") { // create chunk                      break;
319              const String& sToSave = (s != "") ? s : sDefault;                  }
320              ck = lstINFO->AddSubChunk(ChunkID, sToSave.size() + 1);              }
             char* pData = (char*) ck->LoadChunkData();  
             memcpy(pData, sToSave.c_str(), sToSave.size() + 1);  
321          }          }
322            RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
323            ::SaveString(ChunkID, ck, lstINFO, s, sDefault, size != 0, size); // function from helper.h
324      }      }
325    
326      /** @brief Update chunks with current info values.      /** @brief Update chunks with current info values.
# Line 310  namespace DLS { Line 333  namespace DLS {
333    
334          // make sure INFO list chunk exists          // make sure INFO list chunk exists
335          RIFF::List* lstINFO   = pResourceListChunk->GetSubList(LIST_TYPE_INFO);          RIFF::List* lstINFO   = pResourceListChunk->GetSubList(LIST_TYPE_INFO);
         if (!lstINFO) lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO);  
336    
337          // assemble default values in case the respective chunk is missing yet          String defaultName = "";
338          String defaultName = "NONAME";          String defaultCreationDate = "";
339          // get current date          String defaultSoftware = "";
340          time_t now = time(NULL);          String defaultComments = "";
341          tm* pNowBroken = localtime(&now);  
342          String defaultCreationDate = ToString(1900 + pNowBroken->tm_year) + "-" +          uint32_t resourceType = pResourceListChunk->GetListType();
343                                       ToString(pNowBroken->tm_mon + 1)  + "-" +  
344                                       ToString(pNowBroken->tm_mday);          if (!lstINFO) {
345          String defaultSoftware = libraryName() + " " + libraryVersion();              lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO);
346          String defaultComments = "Created with " + libraryName() + " " + libraryVersion();  
347                // assemble default values
348                defaultName = "NONAME";
349    
350                if (resourceType == RIFF_TYPE_DLS) {
351                    // get current date
352                    time_t now = time(NULL);
353                    tm* pNowBroken = localtime(&now);
354                    char buf[11];
355                    strftime(buf, 11, "%F", pNowBroken);
356                    defaultCreationDate = buf;
357    
358                    defaultComments = "Created with " + libraryName() + " " + libraryVersion();
359                }
360                if (resourceType == RIFF_TYPE_DLS || resourceType == LIST_TYPE_INS)
361                {
362                    defaultSoftware = libraryName() + " " + libraryVersion();
363                }
364            }
365    
366          // save values          // save values
367          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName);  
368          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""));          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""));
369          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate);          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""));
370            SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""));
371          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments);          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments);
         SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""));  
372          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""));          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""));
373          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""));          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate);
374            SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""));
375          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""));          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""));
376          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);  
377          SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""));          SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""));
378            SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName);
379            SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""));
380            SaveString(CHUNK_ID_ISBJ, lstINFO, Subject, String(""));
381            SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware);
382          SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""));          SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""));
383          SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""));          SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""));
384          SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""));          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""));
385      }      }
386    
387    
# Line 388  namespace DLS { Line 430  namespace DLS {
430       */       */
431      void Resource::UpdateChunks() {      void Resource::UpdateChunks() {
432          pInfo->UpdateChunks();          pInfo->UpdateChunks();
433          //TODO: save DLSID  
434            if (pDLSID) {
435                // make sure 'dlid' chunk exists
436                RIFF::Chunk* ckDLSID = pResourceList->GetSubChunk(CHUNK_ID_DLID);
437                if (!ckDLSID) ckDLSID = pResourceList->AddSubChunk(CHUNK_ID_DLID, 16);
438                uint8_t* pData = (uint8_t*)ckDLSID->LoadChunkData();
439                // update 'dlid' chunk
440                store32(&pData[0], pDLSID->ulData1);
441                store16(&pData[4], pDLSID->usData2);
442                store16(&pData[6], pDLSID->usData3);
443                memcpy(&pData[8], pDLSID->abData, 8);
444            }
445      }      }
446    
447        /**
448         * Generates a new DLSID for the resource.
449         */
450        void Resource::GenerateDLSID() {
451    #if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE)
452    
453            if (!pDLSID) pDLSID = new dlsid_t;
454    
455    #ifdef WIN32
456    
457            UUID uuid;
458            UuidCreate(&uuid);
459            pDLSID->ulData1 = uuid.Data1;
460            pDLSID->usData2 = uuid.Data2;
461            pDLSID->usData3 = uuid.Data3;
462            memcpy(pDLSID->abData, uuid.Data4, 8);
463    
464    #elif defined(__APPLE__)
465    
466            CFUUIDRef uuidRef = CFUUIDCreate(NULL);
467            CFUUIDBytes uuid = CFUUIDGetUUIDBytes(uuidRef);
468            CFRelease(uuidRef);
469            pDLSID->ulData1 = uuid.byte0 | uuid.byte1 << 8 | uuid.byte2 << 16 | uuid.byte3 << 24;
470            pDLSID->usData2 = uuid.byte4 | uuid.byte5 << 8;
471            pDLSID->usData3 = uuid.byte6 | uuid.byte7 << 8;
472            pDLSID->abData[0] = uuid.byte8;
473            pDLSID->abData[1] = uuid.byte9;
474            pDLSID->abData[2] = uuid.byte10;
475            pDLSID->abData[3] = uuid.byte11;
476            pDLSID->abData[4] = uuid.byte12;
477            pDLSID->abData[5] = uuid.byte13;
478            pDLSID->abData[6] = uuid.byte14;
479            pDLSID->abData[7] = uuid.byte15;
480    #else
481            uuid_t uuid;
482            uuid_generate(uuid);
483            pDLSID->ulData1 = uuid[0] | uuid[1] << 8 | uuid[2] << 16 | uuid[3] << 24;
484            pDLSID->usData2 = uuid[4] | uuid[5] << 8;
485            pDLSID->usData3 = uuid[6] | uuid[7] << 8;
486            memcpy(pDLSID->abData, &uuid[8], 8);
487    #endif
488    #endif
489        }
490    
491    
492  // *************** Sampler ***************  // *************** Sampler ***************
# Line 407  namespace DLS { Line 503  namespace DLS {
503              SamplerOptions = wsmp->ReadUint32();              SamplerOptions = wsmp->ReadUint32();
504              SampleLoops    = wsmp->ReadUint32();              SampleLoops    = wsmp->ReadUint32();
505          } else { // 'wsmp' chunk missing          } else { // 'wsmp' chunk missing
506              uiHeaderSize   = 0;              uiHeaderSize   = 20;
507              UnityNote      = 64;              UnityNote      = 60;
508              FineTune       = 0; // +- 0 cents              FineTune       = 0; // +- 0 cents
509              Gain           = 0; // 0 dB              Gain           = 0; // 0 dB
510              SamplerOptions = F_WSMP_NO_COMPRESSION;              SamplerOptions = F_WSMP_NO_COMPRESSION;
# Line 432  namespace DLS { Line 528  namespace DLS {
528          if (pSampleLoops) delete[] pSampleLoops;          if (pSampleLoops) delete[] pSampleLoops;
529      }      }
530    
531        void Sampler::SetGain(int32_t gain) {
532            Gain = gain;
533        }
534    
535      /**      /**
536       * Apply all sample player options to the respective RIFF chunk. You       * Apply all sample player options to the respective RIFF chunk. You
537       * have to call File::Save() to make changes persistent.       * have to call File::Save() to make changes persistent.
# Line 439  namespace DLS { Line 539  namespace DLS {
539      void Sampler::UpdateChunks() {      void Sampler::UpdateChunks() {
540          // make sure 'wsmp' chunk exists          // make sure 'wsmp' chunk exists
541          RIFF::Chunk* wsmp = pParentList->GetSubChunk(CHUNK_ID_WSMP);          RIFF::Chunk* wsmp = pParentList->GetSubChunk(CHUNK_ID_WSMP);
542            int wsmpSize = uiHeaderSize + SampleLoops * 16;
543          if (!wsmp) {          if (!wsmp) {
544              uiHeaderSize = 20;              wsmp = pParentList->AddSubChunk(CHUNK_ID_WSMP, wsmpSize);
545              wsmp = pParentList->AddSubChunk(CHUNK_ID_WSMP, uiHeaderSize + SampleLoops * 16);          } else if (wsmp->GetSize() != wsmpSize) {
546                wsmp->Resize(wsmpSize);
547          }          }
548          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();
549          // update headers size          // update headers size
550          memccpy(&pData[0], &uiHeaderSize, 1, 4);          store32(&pData[0], uiHeaderSize);
551          // update respective sampler options bits          // update respective sampler options bits
552          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION
553                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);
554          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION
555                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);
556            store16(&pData[4], UnityNote);
557            store16(&pData[6], FineTune);
558            store32(&pData[8], Gain);
559            store32(&pData[12], SamplerOptions);
560            store32(&pData[16], SampleLoops);
561          // update loop definitions          // update loop definitions
562          for (uint32_t i = 0; i < SampleLoops; i++) {          for (uint32_t i = 0; i < SampleLoops; i++) {
563              //FIXME: this does not handle extended loop structs correctly              //FIXME: this does not handle extended loop structs correctly
564              memccpy(&pData[uiHeaderSize + i * 16], pSampleLoops + i, 4, 4);              store32(&pData[uiHeaderSize + i * 16], pSampleLoops[i].Size);
565                store32(&pData[uiHeaderSize + i * 16 + 4], pSampleLoops[i].LoopType);
566                store32(&pData[uiHeaderSize + i * 16 + 8], pSampleLoops[i].LoopStart);
567                store32(&pData[uiHeaderSize + i * 16 + 12], pSampleLoops[i].LoopLength);
568          }          }
569      }      }
570    
571        /**
572         * Adds a new sample loop with the provided loop definition.
573         *
574         * @param pLoopDef - points to a loop definition that is to be copied
575         */
576        void Sampler::AddSampleLoop(sample_loop_t* pLoopDef) {
577            sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops + 1];
578            // copy old loops array
579            for (int i = 0; i < SampleLoops; i++) {
580                pNewLoops[i] = pSampleLoops[i];
581            }
582            // add the new loop
583            pNewLoops[SampleLoops] = *pLoopDef;
584            // auto correct size field
585            pNewLoops[SampleLoops].Size = sizeof(DLS::sample_loop_t);
586            // free the old array and update the member variables
587            if (SampleLoops) delete[] pSampleLoops;
588            pSampleLoops = pNewLoops;
589            SampleLoops++;
590        }
591    
592        /**
593         * Deletes an existing sample loop.
594         *
595         * @param pLoopDef - pointer to existing loop definition
596         * @throws Exception - if given loop definition does not exist
597         */
598        void Sampler::DeleteSampleLoop(sample_loop_t* pLoopDef) {
599            sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops - 1];
600            // copy old loops array (skipping given loop)
601            for (int i = 0, o = 0; i < SampleLoops; i++) {
602                if (&pSampleLoops[i] == pLoopDef) continue;
603                if (o == SampleLoops - 1) {
604                    delete[] pNewLoops;
605                    throw Exception("Could not delete Sample Loop, because it does not exist");
606                }
607                pNewLoops[o] = pSampleLoops[i];
608                o++;
609            }
610            // free the old array and update the member variables
611            if (SampleLoops) delete[] pSampleLoops;
612            pSampleLoops = pNewLoops;
613            SampleLoops--;
614        }
615    
616    
617    
618  // *************** Sample ***************  // *************** Sample ***************
# Line 491  namespace DLS { Line 646  namespace DLS {
646              AverageBytesPerSecond  = pCkFormat->ReadUint32();              AverageBytesPerSecond  = pCkFormat->ReadUint32();
647              BlockAlign             = pCkFormat->ReadUint16();              BlockAlign             = pCkFormat->ReadUint16();
648              // PCM format specific              // PCM format specific
649              if (FormatTag == WAVE_FORMAT_PCM) {              if (FormatTag == DLS_WAVE_FORMAT_PCM) {
650                  BitDepth     = pCkFormat->ReadUint16();                  BitDepth     = pCkFormat->ReadUint16();
651                  FrameSize    = (FormatTag == WAVE_FORMAT_PCM) ? (BitDepth / 8) * Channels                  FrameSize    = (BitDepth / 8) * Channels;
                                                             : 0;  
652              } else { // unsupported sample data format              } else { // unsupported sample data format
653                  BitDepth     = 0;                  BitDepth     = 0;
654                  FrameSize    = 0;                  FrameSize    = 0;
655              }              }
656          } else { // 'fmt' chunk missing          } else { // 'fmt' chunk missing
657              FormatTag              = WAVE_FORMAT_PCM;              FormatTag              = DLS_WAVE_FORMAT_PCM;
658              BitDepth               = 16;              BitDepth               = 16;
659              Channels               = 1;              Channels               = 1;
660              SamplesPerSecond       = 44100;              SamplesPerSecond       = 44100;
# Line 508  namespace DLS { Line 662  namespace DLS {
662              FrameSize              = (BitDepth / 8) * Channels;              FrameSize              = (BitDepth / 8) * Channels;
663              BlockAlign             = FrameSize;              BlockAlign             = FrameSize;
664          }          }
665          SamplesTotal = (pCkData) ? (FormatTag == WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize          SamplesTotal = (pCkData) ? (FormatTag == DLS_WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize
666                                                                    : 0                                                                        : 0
667                                   : 0;                                   : 0;
668      }      }
669    
# Line 569  namespace DLS { Line 723  namespace DLS {
723       * the RIFF chunk which encapsulates the sample's wave data. The       * the RIFF chunk which encapsulates the sample's wave data. The
724       * returned value is dependant to the current FrameSize value.       * returned value is dependant to the current FrameSize value.
725       *       *
726       * @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
727       * @see FrameSize, FormatTag       * @see FrameSize, FormatTag
728       */       */
729      unsigned long Sample::GetSize() {      unsigned long Sample::GetSize() {
730          if (FormatTag != WAVE_FORMAT_PCM) return 0;          if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0;
731          return (pCkData) ? pCkData->GetSize() / FrameSize : 0;          return (pCkData) ? pCkData->GetSize() / FrameSize : 0;
732      }      }
733    
# Line 595  namespace DLS { Line 749  namespace DLS {
749       * calling File::Save() as this might exceed the current sample's       * calling File::Save() as this might exceed the current sample's
750       * boundary!       * boundary!
751       *       *
752       * Also note: only WAVE_FORMAT_PCM is currently supported, that is       * Also note: only DLS_WAVE_FORMAT_PCM is currently supported, that is
753       * FormatTag must be WAVE_FORMAT_PCM. Trying to resize samples with       * FormatTag must be DLS_WAVE_FORMAT_PCM. Trying to resize samples with
754       * other formats will fail!       * other formats will fail!
755       *       *
756       * @param iNewSize - new sample wave data size in sample points (must be       * @param iNewSize - new sample wave data size in sample points (must be
757       *                   greater than zero)       *                   greater than zero)
758       * @throws Excecption if FormatTag != WAVE_FORMAT_PCM       * @throws Excecption if FormatTag != DLS_WAVE_FORMAT_PCM
759       * @throws Exception if \a iNewSize is less than 1       * @throws Exception if \a iNewSize is less than 1
760       * @see File::Save(), FrameSize, FormatTag       * @see File::Save(), FrameSize, FormatTag
761       */       */
762      void Sample::Resize(int iNewSize) {      void Sample::Resize(int iNewSize) {
763          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");
764          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");
765          const int iSizeInBytes = iNewSize * FrameSize;          const int iSizeInBytes = iNewSize * FrameSize;
766          pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA);          pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA);
# Line 619  namespace DLS { Line 773  namespace DLS {
773       * 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
774       * the sample into RAM, thus for disk streaming.       * the sample into RAM, thus for disk streaming.
775       *       *
776       * Also note: only WAVE_FORMAT_PCM is currently supported, that is       * Also note: only DLS_WAVE_FORMAT_PCM is currently supported, that is
777       * FormatTag must be WAVE_FORMAT_PCM. Trying to reposition the sample       * FormatTag must be DLS_WAVE_FORMAT_PCM. Trying to reposition the sample
778       * with other formats will fail!       * with other formats will fail!
779       *       *
780       * @param SampleCount  number of sample points       * @param SampleCount  number of sample points
781       * @param Whence       to which relation \a SampleCount refers to       * @param Whence       to which relation \a SampleCount refers to
782       * @returns new position within the sample, 0 if       * @returns new position within the sample, 0 if
783       *          FormatTag != WAVE_FORMAT_PCM       *          FormatTag != DLS_WAVE_FORMAT_PCM
784       * @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
785       * @see FrameSize, FormatTag       * @see FrameSize, FormatTag
786       */       */
787      unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {      unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {
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          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");
790          unsigned long orderedBytes = SampleCount * FrameSize;          unsigned long orderedBytes = SampleCount * FrameSize;
791          unsigned long result = pCkData->SetPos(orderedBytes, Whence);          unsigned long result = pCkData->SetPos(orderedBytes, Whence);
# Line 649  namespace DLS { Line 803  namespace DLS {
803       * @param SampleCount  number of sample points to read       * @param SampleCount  number of sample points to read
804       */       */
805      unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {      unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {
806          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
807          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?
808      }      }
809    
# Line 669  namespace DLS { Line 823  namespace DLS {
823       * @see LoadSampleData()       * @see LoadSampleData()
824       */       */
825      unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) {      unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) {
826          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
827          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");
828          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?
829      }      }
# Line 678  namespace DLS { Line 832  namespace DLS {
832       * Apply sample and its settings to the respective RIFF chunks. You have       * Apply sample and its settings to the respective RIFF chunks. You have
833       * to call File::Save() to make changes persistent.       * to call File::Save() to make changes persistent.
834       *       *
835       * @throws Exception if FormatTag != WAVE_FORMAT_PCM or no sample data       * @throws Exception if FormatTag != DLS_WAVE_FORMAT_PCM or no sample data
836       *                   was provided yet       *                   was provided yet
837       */       */
838      void Sample::UpdateChunks() {      void Sample::UpdateChunks() {
839          if (FormatTag != WAVE_FORMAT_PCM)          if (FormatTag != DLS_WAVE_FORMAT_PCM)
840              throw Exception("Could not save sample, only PCM format is supported");              throw Exception("Could not save sample, only PCM format is supported");
841          // 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
842          if (!pCkData)          if (!pCkData)
# Line 694  namespace DLS { Line 848  namespace DLS {
848          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format
849          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();
850          // update 'fmt' chunk          // update 'fmt' chunk
851          memccpy(&pData[0], &FormatTag, 1, 2);          store16(&pData[0], FormatTag);
852          memccpy(&pData[2], &Channels,  1, 2);          store16(&pData[2], Channels);
853          memccpy(&pData[4], &SamplesPerSecond, 1, 4);          store32(&pData[4], SamplesPerSecond);
854          memccpy(&pData[8], &AverageBytesPerSecond, 1, 4);          store32(&pData[8], AverageBytesPerSecond);
855          memccpy(&pData[12], &BlockAlign, 1, 2);          store16(&pData[12], BlockAlign);
856          memccpy(&pData[14], &BitDepth, 1, 2); // assuming PCM format          store16(&pData[14], BitDepth); // assuming PCM format
857      }      }
858    
859    
# Line 783  namespace DLS { Line 937  namespace DLS {
937      }      }
938    
939      /**      /**
940         * Modifies the key range of this Region and makes sure the respective
941         * chunks are in correct order.
942         *
943         * @param Low  - lower end of key range
944         * @param High - upper end of key range
945         */
946        void Region::SetKeyRange(uint16_t Low, uint16_t High) {
947            KeyRange.low  = Low;
948            KeyRange.high = High;
949    
950            // make sure regions are already loaded
951            Instrument* pInstrument = (Instrument*) GetParent();
952            if (!pInstrument->pRegions) pInstrument->LoadRegions();
953            if (!pInstrument->pRegions) return;
954    
955            // find the r which is the first one to the right of this region
956            // at its new position
957            Region* r = NULL;
958            Region* prev_region = NULL;
959            for (
960                Instrument::RegionList::iterator iter = pInstrument->pRegions->begin();
961                iter != pInstrument->pRegions->end(); iter++
962            ) {
963                if ((*iter)->KeyRange.low > this->KeyRange.low) {
964                    r = *iter;
965                    break;
966                }
967                prev_region = *iter;
968            }
969    
970            // place this region before r if it's not already there
971            if (prev_region != this) pInstrument->MoveRegion(this, r);
972        }
973    
974        /**
975       * Apply Region settings to the respective RIFF chunks. You have to       * Apply Region settings to the respective RIFF chunks. You have to
976       * call File::Save() to make changes persistent.       * call File::Save() to make changes persistent.
977       *       *
# Line 791  namespace DLS { Line 980  namespace DLS {
980      void Region::UpdateChunks() {      void Region::UpdateChunks() {
981          // make sure 'rgnh' chunk exists          // make sure 'rgnh' chunk exists
982          RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH);          RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH);
983          if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, 14);          if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, Layer ? 14 : 12);
984          uint8_t* pData = (uint8_t*) rgnh->LoadChunkData();          uint8_t* pData = (uint8_t*) rgnh->LoadChunkData();
985          FormatOptionFlags = (SelfNonExclusive)          FormatOptionFlags = (SelfNonExclusive)
986                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE
987                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);
988          // update 'rgnh' chunk          // update 'rgnh' chunk
989          memccpy(&pData[0], &KeyRange, 2, 2);          store16(&pData[0], KeyRange.low);
990          memccpy(&pData[4], &VelocityRange, 2, 2);          store16(&pData[2], KeyRange.high);
991          memccpy(&pData[8], &FormatOptionFlags, 1, 2);          store16(&pData[4], VelocityRange.low);
992          memccpy(&pData[10], &KeyGroup, 1, 2);          store16(&pData[6], VelocityRange.high);
993          memccpy(&pData[12], &Layer, 1, 2);          store16(&pData[8], FormatOptionFlags);
994            store16(&pData[10], KeyGroup);
995            if (rgnh->GetSize() >= 14) store16(&pData[12], Layer);
996    
997          // update chunks of base classes as well          // update chunks of base classes as well (but skip Resource,
998          Resource::UpdateChunks();          // as a rgn doesn't seem to have dlid and INFO chunks)
999          Articulator::UpdateChunks();          Articulator::UpdateChunks();
1000          Sampler::UpdateChunks();          Sampler::UpdateChunks();
1001    
# Line 831  namespace DLS { Line 1022  namespace DLS {
1022                  }                  }
1023              }              }
1024          }          }
         if (index < 0) throw Exception("Could not save Region, could not find Region's sample");  
1025          WavePoolTableIndex = index;          WavePoolTableIndex = index;
1026          // update 'wlnk' chunk          // update 'wlnk' chunk
1027          memccpy(&pData[0], &WaveLinkOptionFlags, 1, 2);          store16(&pData[0], WaveLinkOptionFlags);
1028          memccpy(&pData[2], &PhaseGroup, 1, 2);          store16(&pData[2], PhaseGroup);
1029          memccpy(&pData[4], &Channel, 1, 4);          store32(&pData[4], Channel);
1030          memccpy(&pData[8], &WavePoolTableIndex, 1, 4);          store32(&pData[8], WavePoolTableIndex);
1031      }      }
1032    
1033    
# Line 895  namespace DLS { Line 1085  namespace DLS {
1085      }      }
1086    
1087      void Instrument::LoadRegions() {      void Instrument::LoadRegions() {
1088            if (!pRegions) pRegions = new RegionList;
1089          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
1090          if (!lrgn) throw DLS::Exception("DLS::Instrument doesn't seem to have any Region (mandatory chunks in <ins > chunk not found)");          if (lrgn) {
1091          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
1092          RIFF::List* rgn = lrgn->GetFirstSubList();              RIFF::List* rgn = lrgn->GetFirstSubList();
1093          while (rgn) {              while (rgn) {
1094              if (rgn->GetListType() == regionCkType) {                  if (rgn->GetListType() == regionCkType) {
1095                  if (!pRegions) pRegions = new RegionList;                      pRegions->push_back(new Region(this, rgn));
1096                  pRegions->push_back(new Region(this, rgn));                  }
1097                    rgn = lrgn->GetNextSubList();
1098              }              }
             rgn = lrgn->GetNextSubList();  
1099          }          }
1100      }      }
1101    
1102      Region* Instrument::AddRegion() {      Region* Instrument::AddRegion() {
1103          if (!pRegions) pRegions = new RegionList;          if (!pRegions) LoadRegions();
1104          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
1105          if (!lrgn)  lrgn = pCkInstrument->AddSubList(LIST_TYPE_LRGN);          if (!lrgn)  lrgn = pCkInstrument->AddSubList(LIST_TYPE_LRGN);
1106          RIFF::List* rgn = lrgn->AddSubList(LIST_TYPE_RGN);          RIFF::List* rgn = lrgn->AddSubList(LIST_TYPE_RGN);
1107          Region* pNewRegion = new Region(this, rgn);          Region* pNewRegion = new Region(this, rgn);
1108          pRegions->push_back(pNewRegion);          pRegions->push_back(pNewRegion);
1109            Regions = pRegions->size();
1110          return pNewRegion;          return pNewRegion;
1111      }      }
1112    
1113        void Instrument::MoveRegion(Region* pSrc, Region* pDst) {
1114            RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
1115            lrgn->MoveSubChunk(pSrc->pCkRegion, pDst ? pDst->pCkRegion : 0);
1116    
1117            pRegions->remove(pSrc);
1118            RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pDst);
1119            pRegions->insert(iter, pSrc);
1120        }
1121    
1122      void Instrument::DeleteRegion(Region* pRegion) {      void Instrument::DeleteRegion(Region* pRegion) {
1123          if (!pRegions) return;          if (!pRegions) return;
1124          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);
1125          if (iter == pRegions->end()) return;          if (iter == pRegions->end()) return;
1126          pRegions->erase(iter);          pRegions->erase(iter);
1127            Regions = pRegions->size();
1128          delete pRegion;          delete pRegion;
1129      }      }
1130    
# Line 947  namespace DLS { Line 1149  namespace DLS {
1149          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);
1150          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);
1151          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
1152          memccpy(&pData[0], &Regions, 1, 4);          store32(&pData[0], Regions);
1153          memccpy(&pData[4], &locale, 2, 4);          store32(&pData[4], locale.bank);
1154            store32(&pData[8], locale.instrument);
1155          // update Region's chunks          // update Region's chunks
1156          if (!pRegions) return;          if (!pRegions) return;
1157          RegionList::iterator iter = pRegions->begin();          RegionList::iterator iter = pRegions->begin();
# Line 990  namespace DLS { Line 1193  namespace DLS {
1193       * a DLS file.       * a DLS file.
1194       */       */
1195      File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) {      File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) {
1196            pRIFF->SetByteOrder(RIFF::endian_little);
1197          pVersion = new version_t;          pVersion = new version_t;
1198          pVersion->major   = 0;          pVersion->major   = 0;
1199          pVersion->minor   = 0;          pVersion->minor   = 0;
# Line 1033  namespace DLS { Line 1237  namespace DLS {
1237          Instruments = colh->ReadUint32();          Instruments = colh->ReadUint32();
1238    
1239          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);
1240          if (!ptbl) throw DLS::Exception("Mandatory <ptbl> chunk not found.");          if (!ptbl) { // pool table is missing - this is probably an ".art" file
1241          WavePoolHeaderSize = ptbl->ReadUint32();              WavePoolCount    = 0;
1242          WavePoolCount  = ptbl->ReadUint32();              pWavePoolTable   = NULL;
1243          pWavePoolTable = new uint32_t[WavePoolCount];              pWavePoolTableHi = NULL;
1244          pWavePoolTableHi = new uint32_t[WavePoolCount];              WavePoolHeaderSize = 8;
1245          ptbl->SetPos(WavePoolHeaderSize);              b64BitWavePoolOffsets = false;
1246            } else {
1247          // Check for 64 bit offsets (used in gig v3 files)              WavePoolHeaderSize = ptbl->ReadUint32();
1248          b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8);              WavePoolCount  = ptbl->ReadUint32();
1249          if (b64BitWavePoolOffsets) {              pWavePoolTable = new uint32_t[WavePoolCount];
1250              for (int i = 0 ; i < WavePoolCount ; i++) {              pWavePoolTableHi = new uint32_t[WavePoolCount];
1251                  pWavePoolTableHi[i] = ptbl->ReadUint32();              ptbl->SetPos(WavePoolHeaderSize);
1252                  pWavePoolTable[i] = ptbl->ReadUint32();  
1253                  if (pWavePoolTable[i] & 0x80000000)              // Check for 64 bit offsets (used in gig v3 files)
1254                      throw DLS::Exception("Files larger than 2 GB not yet supported");              b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8);
1255                if (b64BitWavePoolOffsets) {
1256                    for (int i = 0 ; i < WavePoolCount ; i++) {
1257                        pWavePoolTableHi[i] = ptbl->ReadUint32();
1258                        pWavePoolTable[i] = ptbl->ReadUint32();
1259                        if (pWavePoolTable[i] & 0x80000000)
1260                            throw DLS::Exception("Files larger than 2 GB not yet supported");
1261                    }
1262                } else { // conventional 32 bit offsets
1263                    ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));
1264                    for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;
1265              }              }
         } else { // conventional 32 bit offsets  
             ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));  
             for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;  
1266          }          }
1267    
1268          pSamples     = NULL;          pSamples     = NULL;
# Line 1082  namespace DLS { Line 1293  namespace DLS {
1293          if (pWavePoolTable) delete[] pWavePoolTable;          if (pWavePoolTable) delete[] pWavePoolTable;
1294          if (pWavePoolTableHi) delete[] pWavePoolTableHi;          if (pWavePoolTableHi) delete[] pWavePoolTableHi;
1295          if (pVersion) delete pVersion;          if (pVersion) delete pVersion;
1296            for (std::list<RIFF::File*>::iterator i = ExtensionFiles.begin() ; i != ExtensionFiles.end() ; i++)
1297                delete *i;
1298      }      }
1299    
1300      Sample* File::GetFirstSample() {      Sample* File::GetFirstSample() {
# Line 1098  namespace DLS { Line 1311  namespace DLS {
1311      }      }
1312    
1313      void File::LoadSamples() {      void File::LoadSamples() {
1314            if (!pSamples) pSamples = new SampleList;
1315          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
1316          if (wvpl) {          if (wvpl) {
1317              unsigned long wvplFileOffset = wvpl->GetFilePos();              unsigned long wvplFileOffset = wvpl->GetFilePos();
1318              RIFF::List* wave = wvpl->GetFirstSubList();              RIFF::List* wave = wvpl->GetFirstSubList();
1319              while (wave) {              while (wave) {
1320                  if (wave->GetListType() == LIST_TYPE_WAVE) {                  if (wave->GetListType() == LIST_TYPE_WAVE) {
                     if (!pSamples) pSamples = new SampleList;  
1321                      unsigned long waveFileOffset = wave->GetFilePos();                      unsigned long waveFileOffset = wave->GetFilePos();
1322                      pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));                      pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));
1323                  }                  }
# Line 1118  namespace DLS { Line 1331  namespace DLS {
1331                  RIFF::List* wave = dwpl->GetFirstSubList();                  RIFF::List* wave = dwpl->GetFirstSubList();
1332                  while (wave) {                  while (wave) {
1333                      if (wave->GetListType() == LIST_TYPE_WAVE) {                      if (wave->GetListType() == LIST_TYPE_WAVE) {
                         if (!pSamples) pSamples = new SampleList;  
1334                          unsigned long waveFileOffset = wave->GetFilePos();                          unsigned long waveFileOffset = wave->GetFilePos();
1335                          pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset));                          pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset));
1336                      }                      }
# Line 1140  namespace DLS { Line 1352  namespace DLS {
1352         __ensureMandatoryChunksExist();         __ensureMandatoryChunksExist();
1353         RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);         RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
1354         // 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;  
1355         RIFF::List* wave = wvpl->AddSubList(LIST_TYPE_WAVE);         RIFF::List* wave = wvpl->AddSubList(LIST_TYPE_WAVE);
1356         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*/);
1357         pSamples->push_back(pSample);         pSamples->push_back(pSample);
# Line 1176  namespace DLS { Line 1387  namespace DLS {
1387      }      }
1388    
1389      void File::LoadInstruments() {      void File::LoadInstruments() {
1390            if (!pInstruments) pInstruments = new InstrumentList;
1391          RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);          RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
1392          if (lstInstruments) {          if (lstInstruments) {
1393              RIFF::List* lstInstr = lstInstruments->GetFirstSubList();              RIFF::List* lstInstr = lstInstruments->GetFirstSubList();
1394              while (lstInstr) {              while (lstInstr) {
1395                  if (lstInstr->GetListType() == LIST_TYPE_INS) {                  if (lstInstr->GetListType() == LIST_TYPE_INS) {
                     if (!pInstruments) pInstruments = new InstrumentList;  
1396                      pInstruments->push_back(new Instrument(this, lstInstr));                      pInstruments->push_back(new Instrument(this, lstInstr));
1397                  }                  }
1398                  lstInstr = lstInstruments->GetNextSubList();                  lstInstr = lstInstruments->GetNextSubList();
# Line 1199  namespace DLS { Line 1410  namespace DLS {
1410      Instrument* File::AddInstrument() {      Instrument* File::AddInstrument() {
1411         if (!pInstruments) LoadInstruments();         if (!pInstruments) LoadInstruments();
1412         __ensureMandatoryChunksExist();         __ensureMandatoryChunksExist();
        if (!pInstruments) pInstruments = new InstrumentList;  
1413         RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);         RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
1414         RIFF::List* lstInstr = lstInstruments->AddSubList(LIST_TYPE_INS);         RIFF::List* lstInstr = lstInstruments->AddSubList(LIST_TYPE_INS);
1415         Instrument* pInstrument = new Instrument(this, lstInstr);         Instrument* pInstrument = new Instrument(this, lstInstr);
# Line 1223  namespace DLS { Line 1433  namespace DLS {
1433      }      }
1434    
1435      /**      /**
1436         * Returns extension file of given index. Extension files are used
1437         * sometimes to circumvent the 2 GB file size limit of the RIFF format and
1438         * of certain operating systems in general. In this case, instead of just
1439         * using one file, the content is spread among several files with similar
1440         * file name scheme. This is especially used by some GigaStudio sound
1441         * libraries.
1442         *
1443         * @param index - index of extension file
1444         * @returns sought extension file, NULL if index out of bounds
1445         * @see GetFileName()
1446         */
1447        RIFF::File* File::GetExtensionFile(int index) {
1448            if (index < 0 || index >= ExtensionFiles.size()) return NULL;
1449            std::list<RIFF::File*>::iterator iter = ExtensionFiles.begin();
1450            for (int i = 0; iter != ExtensionFiles.end(); ++iter, ++i)
1451                if (i == index) return *iter;
1452            return NULL;
1453        }
1454    
1455        /** @brief File name of this DLS file.
1456         *
1457         * This method returns the file name as it was provided when loading
1458         * the respective DLS file. However in case the File object associates
1459         * an empty, that is new DLS file, which was not yet saved to disk,
1460         * this method will return an empty string.
1461         *
1462         * @see GetExtensionFile()
1463         */
1464        String File::GetFileName() {
1465            return pRIFF->GetFileName();
1466        }
1467    
1468        /**
1469       * Apply all the DLS file's current instruments, samples and settings to       * Apply all the DLS file's current instruments, samples and settings to
1470       * the respective RIFF chunks. You have to call Save() to make changes       * the respective RIFF chunks. You have to call Save() to make changes
1471       * persistent.       * persistent.
# Line 1238  namespace DLS { Line 1481  namespace DLS {
1481              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);
1482              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);
1483              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();
1484              memccpy(pData, pVersion, 2, 4);              store16(&pData[0], pVersion->minor);
1485                store16(&pData[2], pVersion->major);
1486                store16(&pData[4], pVersion->build);
1487                store16(&pData[6], pVersion->release);
1488          }          }
1489    
1490          // update 'colh' chunk          // update 'colh' chunk
# Line 1246  namespace DLS { Line 1492  namespace DLS {
1492          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);
1493          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);
1494          uint8_t* pData = (uint8_t*) colh->LoadChunkData();          uint8_t* pData = (uint8_t*) colh->LoadChunkData();
1495          memccpy(pData, &Instruments, 1, 4);          store32(pData, Instruments);
1496    
1497          // update instrument's chunks          // update instrument's chunks
1498          if (pInstruments) {          if (pInstruments) {
# Line 1266  namespace DLS { Line 1512  namespace DLS {
1512          ptbl->Resize(iPtblSize);          ptbl->Resize(iPtblSize);
1513          pData = (uint8_t*) ptbl->LoadChunkData();          pData = (uint8_t*) ptbl->LoadChunkData();
1514          WavePoolCount = iSamples;          WavePoolCount = iSamples;
1515          memccpy(&pData[4], &WavePoolCount, 1, 4);          store32(&pData[4], WavePoolCount);
1516          // 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()
1517          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);
1518    
# Line 1355  namespace DLS { Line 1601  namespace DLS {
1601          unsigned long ulOriginalPos = ptbl->GetPos();          unsigned long ulOriginalPos = ptbl->GetPos();
1602          // update headers          // update headers
1603          ptbl->SetPos(0);          ptbl->SetPos(0);
1604          ptbl->WriteUint32(&WavePoolHeaderSize);          uint32_t tmp = WavePoolHeaderSize;
1605          ptbl->WriteUint32(&WavePoolCount);          ptbl->WriteUint32(&tmp);
1606            tmp = WavePoolCount;
1607            ptbl->WriteUint32(&tmp);
1608          // update offsets          // update offsets
1609          ptbl->SetPos(WavePoolHeaderSize);          ptbl->SetPos(WavePoolHeaderSize);
1610          if (b64BitWavePoolOffsets) {          if (b64BitWavePoolOffsets) {
1611              for (int i = 0 ; i < WavePoolCount ; i++) {              for (int i = 0 ; i < WavePoolCount ; i++) {
1612                  ptbl->WriteUint32(&pWavePoolTableHi[i]);                  tmp = pWavePoolTableHi[i];
1613                  ptbl->WriteUint32(&pWavePoolTable[i]);                  ptbl->WriteUint32(&tmp);
1614                    tmp = pWavePoolTable[i];
1615                    ptbl->WriteUint32(&tmp);
1616              }              }
1617          } else { // conventional 32 bit offsets          } else { // conventional 32 bit offsets
1618              for (int i = 0 ; i < WavePoolCount ; i++)              for (int i = 0 ; i < WavePoolCount ; i++) {
1619                  ptbl->WriteUint32(&pWavePoolTable[i]);                  tmp = pWavePoolTable[i];
1620                    ptbl->WriteUint32(&tmp);
1621                }
1622          }          }
1623          // restore 'ptbl' chunk's original read/write position          // restore 'ptbl' chunk's original read/write position
1624          ptbl->SetPos(ulOriginalPos);          ptbl->SetPos(ulOriginalPos);

Legend:
Removed from v.809  
changed lines
  Added in v.2329

  ViewVC Help
Powered by ViewVC