/[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 1155 by schoenebeck, Wed Apr 11 18:11:09 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 45  Line 45 
45  #define CONN_TRANSFORM_INVERT_SRC_ENCODE(x)             ((x) ? 0x8000 : 0)  #define CONN_TRANSFORM_INVERT_SRC_ENCODE(x)             ((x) ? 0x8000 : 0)
46  #define CONN_TRANSFORM_INVERT_CTL_ENCODE(x)             ((x) ? 0x0200 : 0)  #define CONN_TRANSFORM_INVERT_CTL_ENCODE(x)             ((x) ? 0x0200 : 0)
47    
48  #define DRUM_TYPE_MASK                  0x00000001  #define DRUM_TYPE_MASK                  0x80000000
49    
50  #define F_RGN_OPTION_SELFNONEXCLUSIVE   0x0001  #define F_RGN_OPTION_SELFNONEXCLUSIVE   0x0001
51    
# Line 142  namespace DLS { Line 142  namespace DLS {
142          const int iEntrySize = 12; // 12 bytes per connection block          const int iEntrySize = 12; // 12 bytes per connection block
143          pArticulationCk->Resize(HeaderSize + Connections * iEntrySize);          pArticulationCk->Resize(HeaderSize + Connections * iEntrySize);
144          uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData();          uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData();
145          memccpy(&pData[0], &HeaderSize, 1, 2);          memcpy(&pData[0], &HeaderSize, 2);
146          memccpy(&pData[2], &Connections, 1, 2);          memcpy(&pData[2], &Connections, 2);
147          for (uint32_t i = 0; i < Connections; i++) {          for (uint32_t i = 0; i < Connections; i++) {
148              Connection::conn_block_t c = pConnections[i].ToConnBlock();              Connection::conn_block_t c = pConnections[i].ToConnBlock();
149              memccpy(&pData[HeaderSize + i * iEntrySize],     &c.source, 1, 2);              memcpy(&pData[HeaderSize + i * iEntrySize],     &c.source, 2);
150              memccpy(&pData[HeaderSize + i * iEntrySize + 2], &c.control, 1, 2);              memcpy(&pData[HeaderSize + i * iEntrySize + 2], &c.control, 2);
151              memccpy(&pData[HeaderSize + i * iEntrySize + 4], &c.destination, 1, 2);              memcpy(&pData[HeaderSize + i * iEntrySize + 4], &c.destination, 2);
152              memccpy(&pData[HeaderSize + i * iEntrySize + 6], &c.transform, 1, 2);              memcpy(&pData[HeaderSize + i * iEntrySize + 6], &c.transform, 2);
153              memccpy(&pData[HeaderSize + i * iEntrySize + 8], &c.scale, 1, 4);              memcpy(&pData[HeaderSize + i * iEntrySize + 8], &c.scale, 4);
154          }          }
155      }      }
156    
# Line 212  namespace DLS { Line 212  namespace DLS {
212       * call File::Save() to make changes persistent.       * call File::Save() to make changes persistent.
213       */       */
214      void Articulator::UpdateChunks() {      void Articulator::UpdateChunks() {
215          ArticulationList::iterator iter = pArticulations->begin();          if (pArticulations) {
216          ArticulationList::iterator end  = pArticulations->end();              ArticulationList::iterator iter = pArticulations->begin();
217          for (; iter != end; ++iter) {              ArticulationList::iterator end  = pArticulations->end();
218              (*iter)->UpdateChunks();              for (; iter != end; ++iter) {
219                    (*iter)->UpdateChunks();
220                }
221          }          }
222      }      }
223    
# Line 226  namespace DLS { Line 228  namespace DLS {
228    
229      /** @brief Constructor.      /** @brief Constructor.
230       *       *
231       * Initializes the info strings with values provided by a INFO list chunk.       * Initializes the info strings with values provided by an INFO list chunk.
232       *       *
233       * @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
234       */       */
235      Info::Info(RIFF::List* list) {      Info::Info(RIFF::List* list) {
236            UseFixedLengthStrings = false;
237          pResourceListChunk = list;          pResourceListChunk = list;
238          if (list) {          if (list) {
239              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);
# Line 251  namespace DLS { Line 254  namespace DLS {
254                  LoadString(CHUNK_ID_ISRC, lstINFO, Source);                  LoadString(CHUNK_ID_ISRC, lstINFO, Source);
255                  LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);                  LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);
256                  LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);                  LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);
257                    LoadString(CHUNK_ID_ISBJ, lstINFO, Subject);
258              }              }
259          }          }
260      }      }
261    
262        Info::~Info() {
263        }
264    
265      /** @brief Load given INFO field.      /** @brief Load given INFO field.
266       *       *
267       * 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 269  namespace DLS {
269       */       */
270      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {
271          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
272          if (ck) {          ::LoadString(ck, s); // function from helper.h
             // TODO: no check for ZSTR terminated strings yet  
             s = (char*) ck->LoadChunkData();  
             ck->ReleaseChunkData();  
         }  
273      }      }
274    
275      /** @brief Apply given INFO field to the respective chunk.      /** @brief Apply given INFO field to the respective chunk.
276       *       *
277       * 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
278       * subchunk of INFO list chunk \a lstINFO. If the given chunk already       * subchunk of INFO list chunk \a lstINFO. If the given chunk already
279       * 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
280       * 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
281       * and \a sDefault will be applied.       * will be created and either \a s or \a sDefault will be applied
282         * (depending on which one is not an empty string, if both are not an
283         * empty string \a s will be preferred).
284       *       *
285       * @param ChunkID  - 32 bit RIFF chunk ID of INFO subchunk       * @param ChunkID  - 32 bit RIFF chunk ID of INFO subchunk
286       * @param lstINFO  - parent (INFO) RIFF list chunk       * @param lstINFO  - parent (INFO) RIFF list chunk
287       * @param s        - current value of info field       * @param s        - current value of info field
288       * @param sDefault - default value       * @param sDefault - default value
289         * @param bUseFixedLengthStrings - should a specific string size be forced in the chunk?
290         * @param size     - wanted size of the INFO chunk. This is ignored if bUseFixedLengthStrings is false.
291       */       */
292      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, bool bUseFixedLengthStrings, int size) {
293          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
294          if (ck) { // if chunk exists already, use 's' as value          ::SaveString(ChunkID, ck, lstINFO, s, sDefault, bUseFixedLengthStrings, size); // function from helper.h
             ck->Resize(s.size() + 1);  
             char* pData = (char*) ck->LoadChunkData();  
             memcpy(pData, s.c_str(), s.size() + 1);  
         } else if (sDefault != "") { // create chunk and use default value  
             ck = lstINFO->AddSubChunk(ChunkID, sDefault.size() + 1);  
             char* pData = (char*) ck->LoadChunkData();  
             memcpy(pData, sDefault.c_str(), sDefault.size() + 1);  
         }  
295      }      }
296    
297      /** @brief Update chunks with current info values.      /** @brief Update chunks with current info values.
# Line 305  namespace DLS { Line 304  namespace DLS {
304    
305          // make sure INFO list chunk exists          // make sure INFO list chunk exists
306          RIFF::List* lstINFO   = pResourceListChunk->GetSubList(LIST_TYPE_INFO);          RIFF::List* lstINFO   = pResourceListChunk->GetSubList(LIST_TYPE_INFO);
         if (!lstINFO) lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO);  
307    
308          // assemble default values in case the respective chunk is missing yet          String defaultName = "";
309          String defaultName = "NONAME";          String defaultCreationDate = "";
310          // get current date          String defaultSoftware = "";
311          time_t now = time(NULL);          String defaultComments = "";
312          tm* pNowBroken = localtime(&now);  
313          String defaultCreationDate = ToString(pNowBroken->tm_year) + "-" +          uint32_t resourceType = pResourceListChunk->GetListType();
314                                       ToString(pNowBroken->tm_mon)  + "-" +  
315                                       ToString(pNowBroken->tm_mday);          if (!lstINFO) {
316          String defaultSoftware = libraryName() + " " + libraryVersion();              lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO);
317          String defaultComments = "Created with " + libraryName() + " " + libraryVersion();  
318                // assemble default values
319                defaultName = "NONAME";
320    
321                if (resourceType == RIFF_TYPE_DLS) {
322                    // get current date
323                    time_t now = time(NULL);
324                    tm* pNowBroken = localtime(&now);
325                    char buf[11];
326                    strftime(buf, 11, "%F", pNowBroken);
327                    defaultCreationDate = buf;
328    
329                    defaultComments = "Created with " + libraryName() + " " + libraryVersion();
330                }
331                if (resourceType == RIFF_TYPE_DLS || resourceType == LIST_TYPE_INS)
332                {
333                    defaultSoftware = libraryName() + " " + libraryVersion();
334                }
335            }
336    
337          // save values          // save values
338          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName);  
339          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""));          // (the string size values are for gig files; they are only
340          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate);          // used if UseFixedLengthStrings is set to true)
341          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments);          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName, UseFixedLengthStrings,
342          SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""));                     resourceType == RIFF_TYPE_DLS ? 128 : 64);
343          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""));          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""), UseFixedLengthStrings, 256);
344          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""));          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate, UseFixedLengthStrings, 128);
345          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""));          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments, UseFixedLengthStrings, 1024);
346          SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String(""));          SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""), UseFixedLengthStrings, 128);
347          SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""));          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""), UseFixedLengthStrings, 128);
348          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""));          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""), UseFixedLengthStrings, 128);
349          SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware);          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""), UseFixedLengthStrings, 128);
350          SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""));          SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String(""), UseFixedLengthStrings, 128);
351          SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""));          SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""), UseFixedLengthStrings, 128);
352          SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""));          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""), UseFixedLengthStrings, 128);
353          SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""));          SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware, UseFixedLengthStrings,
354                       resourceType == LIST_TYPE_INS ?
355                       (Software == "" ? defaultSoftware.length()+1 : Software.length()+1) : 128);
356            SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""), UseFixedLengthStrings, 128);
357            SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""), UseFixedLengthStrings, 128);
358            SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""), UseFixedLengthStrings, 128);
359            SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""), UseFixedLengthStrings, 128);
360            SaveString(CHUNK_ID_ISBJ, lstINFO, Subject, String(""), UseFixedLengthStrings, 128);
361      }      }
362    
363    
# Line 440  namespace DLS { Line 463  namespace DLS {
463          }          }
464          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();
465          // update headers size          // update headers size
466          memccpy(&pData[0], &uiHeaderSize, 1, 4);          memcpy(&pData[0], &uiHeaderSize, 4);
467          // update respective sampler options bits          // update respective sampler options bits
468          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION
469                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);
470          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION
471                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);
472            memcpy(&pData[4], &UnityNote, 2);
473            memcpy(&pData[6], &FineTune, 2);
474            memcpy(&pData[8], &Gain, 4);
475            memcpy(&pData[12], &SamplerOptions, 4);
476            memcpy(&pData[16], &SampleLoops, 4);
477          // update loop definitions          // update loop definitions
478          for (uint32_t i = 0; i < SampleLoops; i++) {          for (uint32_t i = 0; i < SampleLoops; i++) {
479              //FIXME: this does not handle extended loop structs correctly              //FIXME: this does not handle extended loop structs correctly
480              memccpy(&pData[uiHeaderSize + i * 16], pSampleLoops + i, 4, 4);              memcpy(&pData[uiHeaderSize + i * 16], pSampleLoops + i, 4 * 4);
481          }          }
482      }      }
483    
484        /**
485         * Adds a new sample loop with the provided loop definition.
486         *
487         * @param - points to a loop definition that is to be copied
488         */
489        void Sampler::AddSampleLoop(sample_loop_t* pLoopDef) {
490            sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops + 1];
491            // copy old loops array
492            for (int i = 0; i < SampleLoops; i++) {
493                pNewLoops[i] = pSampleLoops[i];
494            }
495            // add the new loop
496            pNewLoops[SampleLoops] = *pLoopDef;
497            // auto correct size field
498            pNewLoops[SampleLoops].Size = sizeof(DLS::sample_loop_t);
499            // free the old array and update the member variables
500            if (SampleLoops) delete[] pSampleLoops;
501            pSampleLoops = pNewLoops;
502            SampleLoops++;
503        }
504    
505        /**
506         * Deletes an existing sample loop.
507         *
508         * @param pLoopDef - pointer to existing loop definition
509         * @throws Exception - if given loop definition does not exist
510         */
511        void Sampler::DeleteSampleLoop(sample_loop_t* pLoopDef) {
512            sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops - 1];
513            // copy old loops array (skipping given loop)
514            for (int i = 0, o = 0; i < SampleLoops; i++) {
515                if (&pSampleLoops[i] == pLoopDef) continue;
516                if (o == SampleLoops - 1)
517                    throw Exception("Could not delete Sample Loop, because it does not exist");
518                pNewLoops[o] = pSampleLoops[i];
519                o++;
520            }
521            // free the old array and update the member variables
522            if (SampleLoops) delete[] pSampleLoops;
523            pSampleLoops = pNewLoops;
524            SampleLoops--;
525        }
526    
527    
528    
529  // *************** Sample ***************  // *************** Sample ***************
# Line 486  namespace DLS { Line 557  namespace DLS {
557              AverageBytesPerSecond  = pCkFormat->ReadUint32();              AverageBytesPerSecond  = pCkFormat->ReadUint32();
558              BlockAlign             = pCkFormat->ReadUint16();              BlockAlign             = pCkFormat->ReadUint16();
559              // PCM format specific              // PCM format specific
560              if (FormatTag == WAVE_FORMAT_PCM) {              if (FormatTag == DLS_WAVE_FORMAT_PCM) {
561                  BitDepth     = pCkFormat->ReadUint16();                  BitDepth     = pCkFormat->ReadUint16();
562                  FrameSize    = (FormatTag == WAVE_FORMAT_PCM) ? (BitDepth / 8) * Channels                  FrameSize    = (BitDepth / 8) * Channels;
                                                             : 0;  
563              } else { // unsupported sample data format              } else { // unsupported sample data format
564                  BitDepth     = 0;                  BitDepth     = 0;
565                  FrameSize    = 0;                  FrameSize    = 0;
566              }              }
567          } else { // 'fmt' chunk missing          } else { // 'fmt' chunk missing
568              FormatTag              = WAVE_FORMAT_PCM;              FormatTag              = DLS_WAVE_FORMAT_PCM;
569              BitDepth               = 16;              BitDepth               = 16;
570              Channels               = 1;              Channels               = 1;
571              SamplesPerSecond       = 44100;              SamplesPerSecond       = 44100;
# Line 503  namespace DLS { Line 573  namespace DLS {
573              FrameSize              = (BitDepth / 8) * Channels;              FrameSize              = (BitDepth / 8) * Channels;
574              BlockAlign             = FrameSize;              BlockAlign             = FrameSize;
575          }          }
576          SamplesTotal = (pCkData) ? (FormatTag == WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize          SamplesTotal = (pCkData) ? (FormatTag == DLS_WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize
577                                                                    : 0                                                                        : 0
578                                   : 0;                                   : 0;
579      }      }
580    
# Line 564  namespace DLS { Line 634  namespace DLS {
634       * the RIFF chunk which encapsulates the sample's wave data. The       * the RIFF chunk which encapsulates the sample's wave data. The
635       * returned value is dependant to the current FrameSize value.       * returned value is dependant to the current FrameSize value.
636       *       *
637       * @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
638       * @see FrameSize, FormatTag       * @see FrameSize, FormatTag
639       */       */
640      unsigned long Sample::GetSize() {      unsigned long Sample::GetSize() {
641          if (FormatTag != WAVE_FORMAT_PCM) return 0;          if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0;
642          return (pCkData) ? pCkData->GetSize() / FrameSize : 0;          return (pCkData) ? pCkData->GetSize() / FrameSize : 0;
643      }      }
644    
# Line 590  namespace DLS { Line 660  namespace DLS {
660       * calling File::Save() as this might exceed the current sample's       * calling File::Save() as this might exceed the current sample's
661       * boundary!       * boundary!
662       *       *
663       * Also note: only WAVE_FORMAT_PCM is currently supported, that is       * Also note: only DLS_WAVE_FORMAT_PCM is currently supported, that is
664       * FormatTag must be WAVE_FORMAT_PCM. Trying to resize samples with       * FormatTag must be DLS_WAVE_FORMAT_PCM. Trying to resize samples with
665       * other formats will fail!       * other formats will fail!
666       *       *
667       * @param iNewSize - new sample wave data size in sample points (must be       * @param iNewSize - new sample wave data size in sample points (must be
668       *                   greater than zero)       *                   greater than zero)
669       * @throws Excecption if FormatTag != WAVE_FORMAT_PCM       * @throws Excecption if FormatTag != DLS_WAVE_FORMAT_PCM
670       * @throws Exception if \a iNewSize is less than 1       * @throws Exception if \a iNewSize is less than 1
671       * @see File::Save(), FrameSize, FormatTag       * @see File::Save(), FrameSize, FormatTag
672       */       */
673      void Sample::Resize(int iNewSize) {      void Sample::Resize(int iNewSize) {
674          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");
675          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");
676          const int iSizeInBytes = iNewSize * FrameSize;          const int iSizeInBytes = iNewSize * FrameSize;
677          pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA);          pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA);
# Line 614  namespace DLS { Line 684  namespace DLS {
684       * 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
685       * the sample into RAM, thus for disk streaming.       * the sample into RAM, thus for disk streaming.
686       *       *
687       * Also note: only WAVE_FORMAT_PCM is currently supported, that is       * Also note: only DLS_WAVE_FORMAT_PCM is currently supported, that is
688       * FormatTag must be WAVE_FORMAT_PCM. Trying to reposition the sample       * FormatTag must be DLS_WAVE_FORMAT_PCM. Trying to reposition the sample
689       * with other formats will fail!       * with other formats will fail!
690       *       *
691       * @param SampleCount  number of sample points       * @param SampleCount  number of sample points
692       * @param Whence       to which relation \a SampleCount refers to       * @param Whence       to which relation \a SampleCount refers to
693       * @returns new position within the sample, 0 if       * @returns new position within the sample, 0 if
694       *          FormatTag != WAVE_FORMAT_PCM       *          FormatTag != DLS_WAVE_FORMAT_PCM
695       * @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
696       * @see FrameSize, FormatTag       * @see FrameSize, FormatTag
697       */       */
698      unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {      unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {
699          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
700          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");
701          unsigned long orderedBytes = SampleCount * FrameSize;          unsigned long orderedBytes = SampleCount * FrameSize;
702          unsigned long result = pCkData->SetPos(orderedBytes, Whence);          unsigned long result = pCkData->SetPos(orderedBytes, Whence);
# Line 644  namespace DLS { Line 714  namespace DLS {
714       * @param SampleCount  number of sample points to read       * @param SampleCount  number of sample points to read
715       */       */
716      unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {      unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {
717          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
718          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?
719      }      }
720    
# Line 664  namespace DLS { Line 734  namespace DLS {
734       * @see LoadSampleData()       * @see LoadSampleData()
735       */       */
736      unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) {      unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) {
737          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
738          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");
739          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?
740      }      }
# Line 673  namespace DLS { Line 743  namespace DLS {
743       * Apply sample and its settings to the respective RIFF chunks. You have       * Apply sample and its settings to the respective RIFF chunks. You have
744       * to call File::Save() to make changes persistent.       * to call File::Save() to make changes persistent.
745       *       *
746       * @throws Exception if FormatTag != WAVE_FORMAT_PCM or no sample data       * @throws Exception if FormatTag != DLS_WAVE_FORMAT_PCM or no sample data
747       *                   was provided yet       *                   was provided yet
748       */       */
749      void Sample::UpdateChunks() {      void Sample::UpdateChunks() {
750          if (FormatTag != WAVE_FORMAT_PCM)          if (FormatTag != DLS_WAVE_FORMAT_PCM)
751              throw Exception("Could not save sample, only PCM format is supported");              throw Exception("Could not save sample, only PCM format is supported");
752          // 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
753          if (!pCkData)          if (!pCkData)
# Line 689  namespace DLS { Line 759  namespace DLS {
759          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format
760          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();
761          // update 'fmt' chunk          // update 'fmt' chunk
762          memccpy(&pData[0], &FormatTag, 1, 2);          memcpy(&pData[0], &FormatTag, 2);
763          memccpy(&pData[2], &Channels,  1, 2);          memcpy(&pData[2], &Channels,  2);
764          memccpy(&pData[4], &SamplesPerSecond, 1, 4);          memcpy(&pData[4], &SamplesPerSecond, 4);
765          memccpy(&pData[8], &AverageBytesPerSecond, 1, 4);          memcpy(&pData[8], &AverageBytesPerSecond, 4);
766          memccpy(&pData[12], &BlockAlign, 1, 2);          memcpy(&pData[12], &BlockAlign, 2);
767          memccpy(&pData[14], &BitDepth, 1, 2); // assuming PCM format          memcpy(&pData[14], &BitDepth, 2); // assuming PCM format
768      }      }
769    
770    
# Line 786  namespace DLS { Line 856  namespace DLS {
856      void Region::UpdateChunks() {      void Region::UpdateChunks() {
857          // make sure 'rgnh' chunk exists          // make sure 'rgnh' chunk exists
858          RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH);          RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH);
859          if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, 14);          if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, Layer ? 14 : 12);
860          uint8_t* pData = (uint8_t*) rgnh->LoadChunkData();          uint8_t* pData = (uint8_t*) rgnh->LoadChunkData();
861          FormatOptionFlags = (SelfNonExclusive)          FormatOptionFlags = (SelfNonExclusive)
862                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE
863                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);
864          // update 'rgnh' chunk          // update 'rgnh' chunk
865          memccpy(&pData[0], &KeyRange, 2, 2);          memcpy(&pData[0], &KeyRange, 2 * 2);
866          memccpy(&pData[4], &VelocityRange, 2, 2);          memcpy(&pData[4], &VelocityRange, 2 * 2);
867          memccpy(&pData[8], &FormatOptionFlags, 1, 2);          memcpy(&pData[8], &FormatOptionFlags, 2);
868          memccpy(&pData[10], &KeyGroup, 1, 2);          memcpy(&pData[10], &KeyGroup, 2);
869          memccpy(&pData[12], &Layer, 1, 2);          if (rgnh->GetSize() >= 14) memcpy(&pData[12], &Layer, 2);
870    
871          // update chunks of base classes as well          // update chunks of base classes as well (but skip Resource,
872          Resource::UpdateChunks();          // as a rgn doesn't seem to have dlid and INFO chunks)
873          Articulator::UpdateChunks();          Articulator::UpdateChunks();
874          Sampler::UpdateChunks();          Sampler::UpdateChunks();
875    
# Line 816  namespace DLS { Line 886  namespace DLS {
886          // get sample's wave pool table index          // get sample's wave pool table index
887          int index = -1;          int index = -1;
888          File* pFile = (File*) GetParent()->GetParent();          File* pFile = (File*) GetParent()->GetParent();
889          File::SampleList::iterator iter = pFile->pSamples->begin();          if (pFile->pSamples) {
890          File::SampleList::iterator end  = pFile->pSamples->end();              File::SampleList::iterator iter = pFile->pSamples->begin();
891          for (int i = 0; iter != end; ++iter, i++) {              File::SampleList::iterator end  = pFile->pSamples->end();
892              if (*iter == pSample) {              for (int i = 0; iter != end; ++iter, i++) {
893                  index = i;                  if (*iter == pSample) {
894                  break;                      index = i;
895                        break;
896                    }
897              }              }
898          }          }
899          if (index < 0) throw Exception("Could not save Region, could not find Region's sample");          if (index < 0) throw Exception("Could not save Region, could not find Region's sample");
900          WavePoolTableIndex = index;          WavePoolTableIndex = index;
901          // update 'wlnk' chunk          // update 'wlnk' chunk
902          memccpy(&pData[0], &WaveLinkOptionFlags, 1, 2);          memcpy(&pData[0], &WaveLinkOptionFlags, 2);
903          memccpy(&pData[2], &PhaseGroup, 1, 2);          memcpy(&pData[2], &PhaseGroup, 2);
904          memccpy(&pData[4], &Channel, 1, 4);          memcpy(&pData[4], &Channel, 4);
905          memccpy(&pData[8], &WavePoolTableIndex, 1, 4);          memcpy(&pData[8], &WavePoolTableIndex, 4);
906      }      }
907    
908    
# Line 888  namespace DLS { Line 960  namespace DLS {
960      }      }
961    
962      void Instrument::LoadRegions() {      void Instrument::LoadRegions() {
963            if (!pRegions) pRegions = new RegionList;
964          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
965          if (!lrgn) throw DLS::Exception("Mandatory chunks in <ins > chunk not found.");          if (lrgn) {
966          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
967          RIFF::List* rgn = lrgn->GetFirstSubList();              RIFF::List* rgn = lrgn->GetFirstSubList();
968          while (rgn) {              while (rgn) {
969              if (rgn->GetListType() == regionCkType) {                  if (rgn->GetListType() == regionCkType) {
970                  if (!pRegions) pRegions = new RegionList;                      pRegions->push_back(new Region(this, rgn));
971                  pRegions->push_back(new Region(this, rgn));                  }
972                    rgn = lrgn->GetNextSubList();
973              }              }
             rgn = lrgn->GetNextSubList();  
974          }          }
975      }      }
976    
977      Region* Instrument::AddRegion() {      Region* Instrument::AddRegion() {
978          if (!pRegions) pRegions = new RegionList;          if (!pRegions) LoadRegions();
979          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
980          if (!lrgn)  lrgn = pCkInstrument->AddSubList(LIST_TYPE_LRGN);          if (!lrgn)  lrgn = pCkInstrument->AddSubList(LIST_TYPE_LRGN);
981          RIFF::List* rgn = lrgn->AddSubList(LIST_TYPE_RGN);          RIFF::List* rgn = lrgn->AddSubList(LIST_TYPE_RGN);
982          Region* pNewRegion = new Region(this, rgn);          Region* pNewRegion = new Region(this, rgn);
983          pRegions->push_back(pNewRegion);          pRegions->push_back(pNewRegion);
984            Regions = pRegions->size();
985          return pNewRegion;          return pNewRegion;
986      }      }
987    
988        void Instrument::MoveRegion(Region* pSrc, Region* pDst) {
989            RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
990            lrgn->MoveSubChunk(pSrc->pCkRegion, pDst ? pDst->pCkRegion : 0);
991    
992            pRegions->remove(pSrc);
993            RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pDst);
994            pRegions->insert(iter, pSrc);
995        }
996    
997      void Instrument::DeleteRegion(Region* pRegion) {      void Instrument::DeleteRegion(Region* pRegion) {
998            if (!pRegions) return;
999          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);
1000          if (iter == pRegions->end()) return;          if (iter == pRegions->end()) return;
1001          pRegions->erase(iter);          pRegions->erase(iter);
1002            Regions = pRegions->size();
1003          delete pRegion;          delete pRegion;
1004      }      }
1005    
# Line 933  namespace DLS { Line 1018  namespace DLS {
1018          if (!insh) insh = pCkInstrument->AddSubChunk(CHUNK_ID_INSH, 12);          if (!insh) insh = pCkInstrument->AddSubChunk(CHUNK_ID_INSH, 12);
1019          uint8_t* pData = (uint8_t*) insh->LoadChunkData();          uint8_t* pData = (uint8_t*) insh->LoadChunkData();
1020          // update 'insh' chunk          // update 'insh' chunk
1021          Regions = pRegions->size();          Regions = (pRegions) ? pRegions->size() : 0;
1022          midi_locale_t locale;          midi_locale_t locale;
1023          locale.instrument = MIDIProgram;          locale.instrument = MIDIProgram;
1024          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);
1025          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);
1026          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
1027          memccpy(&pData[0], &Regions, 1, 4);          memcpy(&pData[0], &Regions, 4);
1028          memccpy(&pData[4], &locale, 2, 4);          memcpy(&pData[4], &locale, 2 * 4);
1029          // update Region's chunks          // update Region's chunks
1030            if (!pRegions) return;
1031          RegionList::iterator iter = pRegions->begin();          RegionList::iterator iter = pRegions->begin();
1032          RegionList::iterator end  = pRegions->end();          RegionList::iterator end  = pRegions->end();
1033          for (; iter != end; ++iter) {          for (; iter != end; ++iter) {
# Line 980  namespace DLS { Line 1066  namespace DLS {
1066       * to add samples, instruments and finally call Save() to actually write       * to add samples, instruments and finally call Save() to actually write
1067       * a DLS file.       * a DLS file.
1068       */       */
1069      File::File() : pRIFF(new RIFF::File(RIFF_TYPE_DLS)), Resource(NULL, pRIFF) {      File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) {
1070          pVersion = new version_t;          pVersion = new version_t;
1071          pVersion->major   = 0;          pVersion->major   = 0;
1072          pVersion->minor   = 0;          pVersion->minor   = 0;
# Line 1024  namespace DLS { Line 1110  namespace DLS {
1110          Instruments = colh->ReadUint32();          Instruments = colh->ReadUint32();
1111    
1112          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);
1113          if (!ptbl) throw DLS::Exception("Mandatory <ptbl> chunk not found.");          if (!ptbl) { // pool table is missing - this is probably an ".art" file
1114          WavePoolHeaderSize = ptbl->ReadUint32();              WavePoolCount    = 0;
1115          WavePoolCount  = ptbl->ReadUint32();              pWavePoolTable   = NULL;
1116          pWavePoolTable = new uint32_t[WavePoolCount];              pWavePoolTableHi = NULL;
1117          pWavePoolTableHi = new uint32_t[WavePoolCount];              WavePoolHeaderSize = 8;
1118          ptbl->SetPos(WavePoolHeaderSize);              b64BitWavePoolOffsets = false;
1119            } else {
1120          // Check for 64 bit offsets (used in gig v3 files)              WavePoolHeaderSize = ptbl->ReadUint32();
1121          b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8);              WavePoolCount  = ptbl->ReadUint32();
1122          if (b64BitWavePoolOffsets) {              pWavePoolTable = new uint32_t[WavePoolCount];
1123              for (int i = 0 ; i < WavePoolCount ; i++) {              pWavePoolTableHi = new uint32_t[WavePoolCount];
1124                  pWavePoolTableHi[i] = ptbl->ReadUint32();              ptbl->SetPos(WavePoolHeaderSize);
1125                  pWavePoolTable[i] = ptbl->ReadUint32();  
1126                  if (pWavePoolTable[i] & 0x80000000)              // Check for 64 bit offsets (used in gig v3 files)
1127                      throw DLS::Exception("Files larger than 2 GB not yet supported");              b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8);
1128                if (b64BitWavePoolOffsets) {
1129                    for (int i = 0 ; i < WavePoolCount ; i++) {
1130                        pWavePoolTableHi[i] = ptbl->ReadUint32();
1131                        pWavePoolTable[i] = ptbl->ReadUint32();
1132                        if (pWavePoolTable[i] & 0x80000000)
1133                            throw DLS::Exception("Files larger than 2 GB not yet supported");
1134                    }
1135                } else { // conventional 32 bit offsets
1136                    ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));
1137                    for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;
1138              }              }
         } else { // conventional 32 bit offsets  
             ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));  
             for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;  
1139          }          }
1140    
1141          pSamples     = NULL;          pSamples     = NULL;
# Line 1073  namespace DLS { Line 1166  namespace DLS {
1166          if (pWavePoolTable) delete[] pWavePoolTable;          if (pWavePoolTable) delete[] pWavePoolTable;
1167          if (pWavePoolTableHi) delete[] pWavePoolTableHi;          if (pWavePoolTableHi) delete[] pWavePoolTableHi;
1168          if (pVersion) delete pVersion;          if (pVersion) delete pVersion;
1169            for (std::list<RIFF::File*>::iterator i = ExtensionFiles.begin() ; i != ExtensionFiles.end() ; i++)
1170                delete *i;
1171      }      }
1172    
1173      Sample* File::GetFirstSample() {      Sample* File::GetFirstSample() {
# Line 1089  namespace DLS { Line 1184  namespace DLS {
1184      }      }
1185    
1186      void File::LoadSamples() {      void File::LoadSamples() {
1187            if (!pSamples) pSamples = new SampleList;
1188          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
1189          if (wvpl) {          if (wvpl) {
1190              unsigned long wvplFileOffset = wvpl->GetFilePos();              unsigned long wvplFileOffset = wvpl->GetFilePos();
1191              RIFF::List* wave = wvpl->GetFirstSubList();              RIFF::List* wave = wvpl->GetFirstSubList();
1192              while (wave) {              while (wave) {
1193                  if (wave->GetListType() == LIST_TYPE_WAVE) {                  if (wave->GetListType() == LIST_TYPE_WAVE) {
                     if (!pSamples) pSamples = new SampleList;  
1194                      unsigned long waveFileOffset = wave->GetFilePos();                      unsigned long waveFileOffset = wave->GetFilePos();
1195                      pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));                      pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));
1196                  }                  }
# Line 1109  namespace DLS { Line 1204  namespace DLS {
1204                  RIFF::List* wave = dwpl->GetFirstSubList();                  RIFF::List* wave = dwpl->GetFirstSubList();
1205                  while (wave) {                  while (wave) {
1206                      if (wave->GetListType() == LIST_TYPE_WAVE) {                      if (wave->GetListType() == LIST_TYPE_WAVE) {
                         if (!pSamples) pSamples = new SampleList;  
1207                          unsigned long waveFileOffset = wave->GetFilePos();                          unsigned long waveFileOffset = wave->GetFilePos();
1208                          pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset));                          pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset));
1209                      }                      }
# Line 1127  namespace DLS { Line 1221  namespace DLS {
1221       * @returns pointer to new Sample object       * @returns pointer to new Sample object
1222       */       */
1223      Sample* File::AddSample() {      Sample* File::AddSample() {
1224           if (!pSamples) LoadSamples();
1225         __ensureMandatoryChunksExist();         __ensureMandatoryChunksExist();
1226         RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);         RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
1227         // 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;  
1228         RIFF::List* wave = wvpl->AddSubList(LIST_TYPE_WAVE);         RIFF::List* wave = wvpl->AddSubList(LIST_TYPE_WAVE);
1229         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*/);
1230         pSamples->push_back(pSample);         pSamples->push_back(pSample);
# Line 1145  namespace DLS { Line 1239  namespace DLS {
1239       * @param pSample - sample to delete       * @param pSample - sample to delete
1240       */       */
1241      void File::DeleteSample(Sample* pSample) {      void File::DeleteSample(Sample* pSample) {
1242            if (!pSamples) return;
1243          SampleList::iterator iter = find(pSamples->begin(), pSamples->end(), pSample);          SampleList::iterator iter = find(pSamples->begin(), pSamples->end(), pSample);
1244          if (iter == pSamples->end()) return;          if (iter == pSamples->end()) return;
1245          pSamples->erase(iter);          pSamples->erase(iter);
# Line 1165  namespace DLS { Line 1260  namespace DLS {
1260      }      }
1261    
1262      void File::LoadInstruments() {      void File::LoadInstruments() {
1263            if (!pInstruments) pInstruments = new InstrumentList;
1264          RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);          RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
1265          if (lstInstruments) {          if (lstInstruments) {
1266              RIFF::List* lstInstr = lstInstruments->GetFirstSubList();              RIFF::List* lstInstr = lstInstruments->GetFirstSubList();
1267              while (lstInstr) {              while (lstInstr) {
1268                  if (lstInstr->GetListType() == LIST_TYPE_INS) {                  if (lstInstr->GetListType() == LIST_TYPE_INS) {
                     if (!pInstruments) pInstruments = new InstrumentList;  
1269                      pInstruments->push_back(new Instrument(this, lstInstr));                      pInstruments->push_back(new Instrument(this, lstInstr));
1270                  }                  }
1271                  lstInstr = lstInstruments->GetNextSubList();                  lstInstr = lstInstruments->GetNextSubList();
# Line 1186  namespace DLS { Line 1281  namespace DLS {
1281       * @returns pointer to new Instrument object       * @returns pointer to new Instrument object
1282       */       */
1283      Instrument* File::AddInstrument() {      Instrument* File::AddInstrument() {
1284           if (!pInstruments) LoadInstruments();
1285         __ensureMandatoryChunksExist();         __ensureMandatoryChunksExist();
        if (!pInstruments) pInstruments = new InstrumentList;  
1286         RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);         RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
1287         RIFF::List* lstInstr = lstInstruments->AddSubList(LIST_TYPE_INS);         RIFF::List* lstInstr = lstInstruments->AddSubList(LIST_TYPE_INS);
1288         Instrument* pInstrument = new Instrument(this, lstInstr);         Instrument* pInstrument = new Instrument(this, lstInstr);
# Line 1195  namespace DLS { Line 1290  namespace DLS {
1290         return pInstrument;         return pInstrument;
1291      }      }
1292    
1293      /** @brief Delete a instrument.      /** @brief Delete an instrument.
1294       *       *
1295       * This will delete the given Instrument object from the DLS file. You       * This will delete the given Instrument object from the DLS file. You
1296       * 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 1298  namespace DLS {
1298       * @param pInstrument - instrument to delete       * @param pInstrument - instrument to delete
1299       */       */
1300      void File::DeleteInstrument(Instrument* pInstrument) {      void File::DeleteInstrument(Instrument* pInstrument) {
1301            if (!pInstruments) return;
1302          InstrumentList::iterator iter = find(pInstruments->begin(), pInstruments->end(), pInstrument);          InstrumentList::iterator iter = find(pInstruments->begin(), pInstruments->end(), pInstrument);
1303          if (iter == pInstruments->end()) return;          if (iter == pInstruments->end()) return;
1304          pInstruments->erase(iter);          pInstruments->erase(iter);
# Line 1225  namespace DLS { Line 1321  namespace DLS {
1321              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);
1322              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);
1323              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();
1324              memccpy(pData, pVersion, 2, 4);              memcpy(pData, pVersion, 2 * 4);
1325          }          }
1326    
1327          // update 'colh' chunk          // update 'colh' chunk
# Line 1233  namespace DLS { Line 1329  namespace DLS {
1329          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);
1330          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);
1331          uint8_t* pData = (uint8_t*) colh->LoadChunkData();          uint8_t* pData = (uint8_t*) colh->LoadChunkData();
1332          memccpy(pData, &Instruments, 1, 4);          memcpy(pData, &Instruments, 4);
1333    
1334          // update instrument's chunks          // update instrument's chunks
1335          if (pInstruments) {          if (pInstruments) {
# Line 1253  namespace DLS { Line 1349  namespace DLS {
1349          ptbl->Resize(iPtblSize);          ptbl->Resize(iPtblSize);
1350          pData = (uint8_t*) ptbl->LoadChunkData();          pData = (uint8_t*) ptbl->LoadChunkData();
1351          WavePoolCount = iSamples;          WavePoolCount = iSamples;
1352          memccpy(&pData[4], &WavePoolCount, 1, 4);          memcpy(&pData[4], &WavePoolCount, 4);
1353          // 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()
1354          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);
1355    
# Line 1324  namespace DLS { Line 1420  namespace DLS {
1420      /**      /**
1421       * Updates (persistently) the wave pool table with offsets to all       * Updates (persistently) the wave pool table with offsets to all
1422       * currently available samples. <b>Caution:</b> this method assumes the       * currently available samples. <b>Caution:</b> this method assumes the
1423       * '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
1424       * method is only called after a Save() call.       * writable, so usually this method is only called after a Save() call.
1425       *       *
1426       * @throws Exception - if 'ptbl' chunk is too small (should only occur       * @throws Exception - if 'ptbl' chunk is too small (should only occur
1427       *                     if there's a bug)       *                     if there's a bug)
# Line 1335  namespace DLS { Line 1431  namespace DLS {
1431          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);
1432          const int iOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4;          const int iOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4;
1433          // check if 'ptbl' chunk is large enough          // check if 'ptbl' chunk is large enough
1434          WavePoolCount = pSamples->size();          WavePoolCount = (pSamples) ? pSamples->size() : 0;
1435          const unsigned long ulRequiredSize = WavePoolHeaderSize + iOffsetSize * WavePoolCount;          const unsigned long ulRequiredSize = WavePoolHeaderSize + iOffsetSize * WavePoolCount;
1436          if (ptbl->GetSize() < ulRequiredSize) throw Exception("Fatal error, 'ptbl' chunk too small");          if (ptbl->GetSize() < ulRequiredSize) throw Exception("Fatal error, 'ptbl' chunk too small");
1437          uint8_t* pData = (uint8_t*) ptbl->LoadChunkData();          // save the 'ptbl' chunk's current read/write position
1438            unsigned long ulOriginalPos = ptbl->GetPos();
1439          // update headers          // update headers
1440          memccpy(&pData[0], &WavePoolHeaderSize, 1, 4);          ptbl->SetPos(0);
1441          memccpy(&pData[4], &WavePoolCount, 1, 4);          ptbl->WriteUint32(&WavePoolHeaderSize);
1442            ptbl->WriteUint32(&WavePoolCount);
1443          // update offsets          // update offsets
1444            ptbl->SetPos(WavePoolHeaderSize);
1445          if (b64BitWavePoolOffsets) {          if (b64BitWavePoolOffsets) {
1446              for (int i = 0 ; i < WavePoolCount ; i++) {              for (int i = 0 ; i < WavePoolCount ; i++) {
1447                  memccpy(&pData[WavePoolHeaderSize + i*iOffsetSize], &pWavePoolTableHi[i], 1, 4);                  ptbl->WriteUint32(&pWavePoolTableHi[i]);
1448                  memccpy(&pData[WavePoolHeaderSize + i*iOffsetSize], &pWavePoolTable[i],   1, 4);                  ptbl->WriteUint32(&pWavePoolTable[i]);
1449              }              }
1450          } else { // conventional 32 bit offsets          } else { // conventional 32 bit offsets
1451              for (int i = 0 ; i < WavePoolCount ; i++)              for (int i = 0 ; i < WavePoolCount ; i++)
1452                  memccpy(&pData[WavePoolHeaderSize + i*iOffsetSize], &pWavePoolTable[i], 1, 4);                  ptbl->WriteUint32(&pWavePoolTable[i]);
1453          }          }
1454            // restore 'ptbl' chunk's original read/write position
1455            ptbl->SetPos(ulOriginalPos);
1456      }      }
1457    
1458      /**      /**
# Line 1360  namespace DLS { Line 1461  namespace DLS {
1461       * exists already.       * exists already.
1462       */       */
1463      void File::__UpdateWavePoolTable() {      void File::__UpdateWavePoolTable() {
1464          WavePoolCount = pSamples->size();          WavePoolCount = (pSamples) ? pSamples->size() : 0;
1465          // resize wave pool table arrays          // resize wave pool table arrays
1466          if (pWavePoolTable)   delete[] pWavePoolTable;          if (pWavePoolTable)   delete[] pWavePoolTable;
1467          if (pWavePoolTableHi) delete[] pWavePoolTableHi;          if (pWavePoolTableHi) delete[] pWavePoolTableHi;
1468          pWavePoolTable   = new uint32_t[WavePoolCount];          pWavePoolTable   = new uint32_t[WavePoolCount];
1469          pWavePoolTableHi = new uint32_t[WavePoolCount];          pWavePoolTableHi = new uint32_t[WavePoolCount];
1470            if (!pSamples) return;
1471          // update offsets int wave pool table          // update offsets int wave pool table
1472          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
1473          uint64_t wvplFileOffset = wvpl->GetFilePos();          uint64_t wvplFileOffset = wvpl->GetFilePos();
# Line 1373  namespace DLS { Line 1475  namespace DLS {
1475              SampleList::iterator iter = pSamples->begin();              SampleList::iterator iter = pSamples->begin();
1476              SampleList::iterator end  = pSamples->end();              SampleList::iterator end  = pSamples->end();
1477              for (int i = 0 ; iter != end ; ++iter, i++) {              for (int i = 0 ; iter != end ; ++iter, i++) {
1478                  uint64_t _64BitOffset = wvplFileOffset - (*iter)->pWaveList->GetFilePos() - LIST_HEADER_SIZE;                  uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - wvplFileOffset - LIST_HEADER_SIZE;
1479                  (*iter)->ulWavePoolOffset = _64BitOffset;                  (*iter)->ulWavePoolOffset = _64BitOffset;
1480                  pWavePoolTableHi[i] = (uint32_t) (_64BitOffset >> 32);                  pWavePoolTableHi[i] = (uint32_t) (_64BitOffset >> 32);
1481                  pWavePoolTable[i]   = (uint32_t) _64BitOffset;                  pWavePoolTable[i]   = (uint32_t) _64BitOffset;
# Line 1382  namespace DLS { Line 1484  namespace DLS {
1484              SampleList::iterator iter = pSamples->begin();              SampleList::iterator iter = pSamples->begin();
1485              SampleList::iterator end  = pSamples->end();              SampleList::iterator end  = pSamples->end();
1486              for (int i = 0 ; iter != end ; ++iter, i++) {              for (int i = 0 ; iter != end ; ++iter, i++) {
1487                  uint64_t _64BitOffset = wvplFileOffset - (*iter)->pWaveList->GetFilePos() - LIST_HEADER_SIZE;                  uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - wvplFileOffset - LIST_HEADER_SIZE;
1488                  (*iter)->ulWavePoolOffset = _64BitOffset;                  (*iter)->ulWavePoolOffset = _64BitOffset;
1489                  pWavePoolTable[i] = (uint32_t) _64BitOffset;                  pWavePoolTable[i] = (uint32_t) _64BitOffset;
1490              }              }

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

  ViewVC Help
Powered by ViewVC