/[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 834 by persson, Mon Feb 6 17:58:21 2006 UTC revision 2482 by schoenebeck, Mon Nov 25 02:22:38 2013 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-2013 by Christian Schoenebeck                      *
6   *                              <cuse@users.sourceforge.net>               *   *                              <cuse@users.sourceforge.net>               *
7   *                                                                         *   *                                                                         *
8   *   This library is free software; you can redistribute it and/or modify  *   *   This library is free software; you can redistribute it and/or modify  *
# Line 23  Line 23 
23    
24  #include "DLS.h"  #include "DLS.h"
25    
26    #include <algorithm>
27  #include <time.h>  #include <time.h>
28    
29    #ifdef __APPLE__
30    #include <CoreFoundation/CFUUID.h>
31    #elif defined(HAVE_UUID_UUID_H)
32    #include <uuid/uuid.h>
33    #endif
34    
35  #include "helper.h"  #include "helper.h"
36    
37  // macros to decode connection transforms  // macros to decode connection transforms
# Line 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 220  namespace DLS { Line 227  namespace DLS {
227              }              }
228          }          }
229      }      }
230        
231        /**
232         * Not yet implemented in this version, since the .gig format does
233         * not need to copy DLS articulators and so far nobody used pure
234         * DLS instrument AFAIK.
235         */
236        void Articulator::CopyAssign(const Articulator* orig) {
237            //TODO: implement deep copy assignment for this class
238        }
239    
240    
241    
# Line 228  namespace DLS { Line 244  namespace DLS {
244    
245      /** @brief Constructor.      /** @brief Constructor.
246       *       *
247       * Initializes the info strings with values provided by a INFO list chunk.       * Initializes the info strings with values provided by an INFO list chunk.
248       *       *
249       * @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
250       */       */
251      Info::Info(RIFF::List* list) {      Info::Info(RIFF::List* list) {
252            pFixedStringLengths = NULL;
253          pResourceListChunk = list;          pResourceListChunk = list;
254          if (list) {          if (list) {
255              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);
# Line 253  namespace DLS { Line 270  namespace DLS {
270                  LoadString(CHUNK_ID_ISRC, lstINFO, Source);                  LoadString(CHUNK_ID_ISRC, lstINFO, Source);
271                  LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);                  LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);
272                  LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);                  LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);
273                    LoadString(CHUNK_ID_ISBJ, lstINFO, Subject);
274              }              }
275          }          }
276      }      }
# Line 260  namespace DLS { Line 278  namespace DLS {
278      Info::~Info() {      Info::~Info() {
279      }      }
280    
281        /**
282         * Forces specific Info fields to be of a fixed length when being saved
283         * to a file. By default the respective RIFF chunk of an Info field
284         * will have a size analogue to its actual string length. With this
285         * method however this behavior can be overridden, allowing to force an
286         * arbitrary fixed size individually for each Info field.
287         *
288         * This method is used as a workaround for the gig format, not for DLS.
289         *
290         * @param lengths - NULL terminated array of string_length_t elements
291         */
292        void Info::SetFixedStringLengths(const string_length_t* lengths) {
293            pFixedStringLengths = lengths;
294        }
295    
296      /** @brief Load given INFO field.      /** @brief Load given INFO field.
297       *       *
298       * Load INFO field from INFO chunk with chunk ID \a ChunkID from INFO       * Load INFO field from INFO chunk with chunk ID \a ChunkID from INFO
# Line 267  namespace DLS { Line 300  namespace DLS {
300       */       */
301      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {
302          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
303          if (ck) {          ::LoadString(ck, s); // function from helper.h
             // TODO: no check for ZSTR terminated strings yet  
             s.assign((char*) ck->LoadChunkData(), ck->GetSize());  
             ck->ReleaseChunkData();  
         }  
304      }      }
305    
306      /** @brief Apply given INFO field to the respective chunk.      /** @brief Apply given INFO field to the respective chunk.
# Line 290  namespace DLS { Line 319  namespace DLS {
319       * @param sDefault - default value       * @param sDefault - default value
320       */       */
321      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) {
322          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          int size = 0;
323          if (ck) { // if chunk exists already, use 's' as value          if (pFixedStringLengths) {
324              ck->Resize(s.size() + 1);              for (int i = 0 ; pFixedStringLengths[i].length ; i++) {
325              char* pData = (char*) ck->LoadChunkData();                  if (pFixedStringLengths[i].chunkId == ChunkID) {
326              memcpy(pData, s.c_str(), s.size() + 1);                      size = pFixedStringLengths[i].length;
327          } else if (s != "" || sDefault != "") { // create chunk                      break;
328              const String& sToSave = (s != "") ? s : sDefault;                  }
329              ck = lstINFO->AddSubChunk(ChunkID, sToSave.size() + 1);              }
             char* pData = (char*) ck->LoadChunkData();  
             memcpy(pData, sToSave.c_str(), sToSave.size() + 1);  
330          }          }
331            RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
332            ::SaveString(ChunkID, ck, lstINFO, s, sDefault, size != 0, size); // function from helper.h
333      }      }
334    
335      /** @brief Update chunks with current info values.      /** @brief Update chunks with current info values.
# Line 313  namespace DLS { Line 342  namespace DLS {
342    
343          // make sure INFO list chunk exists          // make sure INFO list chunk exists
344          RIFF::List* lstINFO   = pResourceListChunk->GetSubList(LIST_TYPE_INFO);          RIFF::List* lstINFO   = pResourceListChunk->GetSubList(LIST_TYPE_INFO);
         if (!lstINFO) lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO);  
345    
346          // assemble default values in case the respective chunk is missing yet          String defaultName = "";
347          String defaultName = "NONAME";          String defaultCreationDate = "";
348          // get current date          String defaultSoftware = "";
349          time_t now = time(NULL);          String defaultComments = "";
350          tm* pNowBroken = localtime(&now);  
351          String defaultCreationDate = ToString(1900 + pNowBroken->tm_year) + "-" +          uint32_t resourceType = pResourceListChunk->GetListType();
352                                       ToString(pNowBroken->tm_mon + 1)  + "-" +  
353                                       ToString(pNowBroken->tm_mday);          if (!lstINFO) {
354          String defaultSoftware = libraryName() + " " + libraryVersion();              lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO);
355          String defaultComments = "Created with " + libraryName() + " " + libraryVersion();  
356                // assemble default values
357                defaultName = "NONAME";
358    
359                if (resourceType == RIFF_TYPE_DLS) {
360                    // get current date
361                    time_t now = time(NULL);
362                    tm* pNowBroken = localtime(&now);
363                    char buf[11];
364                    strftime(buf, 11, "%F", pNowBroken);
365                    defaultCreationDate = buf;
366    
367                    defaultComments = "Created with " + libraryName() + " " + libraryVersion();
368                }
369                if (resourceType == RIFF_TYPE_DLS || resourceType == LIST_TYPE_INS)
370                {
371                    defaultSoftware = libraryName() + " " + libraryVersion();
372                }
373            }
374    
375          // save values          // save values
376          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName);  
377          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""));          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""));
378          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate);          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""));
379            SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""));
380          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments);          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments);
         SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""));  
381          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""));          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""));
382          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""));          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate);
383            SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""));
384          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""));          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""));
385          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);  
386          SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""));          SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""));
387            SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName);
388            SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""));
389            SaveString(CHUNK_ID_ISBJ, lstINFO, Subject, String(""));
390            SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware);
391          SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""));          SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""));
392          SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""));          SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""));
393          SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""));          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""));
394        }
395        
396        /**
397         * Make a deep copy of the Info object given by @a orig and assign it to
398         * this object.
399         *
400         * @param orig - original Info object to be copied from
401         */
402        void Info::CopyAssign(const Info* orig) {
403            Name = orig->Name;
404            ArchivalLocation = orig->ArchivalLocation;
405            CreationDate = orig->CreationDate;
406            Comments = orig->Comments;
407            Product = orig->Product;
408            Copyright = orig->Copyright;
409            Artists = orig->Artists;
410            Genre = orig->Genre;
411            Keywords = orig->Keywords;
412            Engineer = orig->Engineer;
413            Technician = orig->Technician;
414            Software = orig->Software;
415            Medium = orig->Medium;
416            Source = orig->Source;
417            SourceForm = orig->SourceForm;
418            Commissioned = orig->Commissioned;
419            Subject = orig->Subject;
420            //FIXME: hmm, is copying this pointer a good idea?
421            pFixedStringLengths = orig->pFixedStringLengths;
422      }      }
423    
424    
# Line 391  namespace DLS { Line 467  namespace DLS {
467       */       */
468      void Resource::UpdateChunks() {      void Resource::UpdateChunks() {
469          pInfo->UpdateChunks();          pInfo->UpdateChunks();
470          //TODO: save DLSID  
471            if (pDLSID) {
472                // make sure 'dlid' chunk exists
473                RIFF::Chunk* ckDLSID = pResourceList->GetSubChunk(CHUNK_ID_DLID);
474                if (!ckDLSID) ckDLSID = pResourceList->AddSubChunk(CHUNK_ID_DLID, 16);
475                uint8_t* pData = (uint8_t*)ckDLSID->LoadChunkData();
476                // update 'dlid' chunk
477                store32(&pData[0], pDLSID->ulData1);
478                store16(&pData[4], pDLSID->usData2);
479                store16(&pData[6], pDLSID->usData3);
480                memcpy(&pData[8], pDLSID->abData, 8);
481            }
482      }      }
483    
484        /**
485         * Generates a new DLSID for the resource.
486         */
487        void Resource::GenerateDLSID() {
488    #if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE)
489    
490            if (!pDLSID) pDLSID = new dlsid_t;
491    
492    #ifdef WIN32
493    
494            UUID uuid;
495            UuidCreate(&uuid);
496            pDLSID->ulData1 = uuid.Data1;
497            pDLSID->usData2 = uuid.Data2;
498            pDLSID->usData3 = uuid.Data3;
499            memcpy(pDLSID->abData, uuid.Data4, 8);
500    
501    #elif defined(__APPLE__)
502    
503            CFUUIDRef uuidRef = CFUUIDCreate(NULL);
504            CFUUIDBytes uuid = CFUUIDGetUUIDBytes(uuidRef);
505            CFRelease(uuidRef);
506            pDLSID->ulData1 = uuid.byte0 | uuid.byte1 << 8 | uuid.byte2 << 16 | uuid.byte3 << 24;
507            pDLSID->usData2 = uuid.byte4 | uuid.byte5 << 8;
508            pDLSID->usData3 = uuid.byte6 | uuid.byte7 << 8;
509            pDLSID->abData[0] = uuid.byte8;
510            pDLSID->abData[1] = uuid.byte9;
511            pDLSID->abData[2] = uuid.byte10;
512            pDLSID->abData[3] = uuid.byte11;
513            pDLSID->abData[4] = uuid.byte12;
514            pDLSID->abData[5] = uuid.byte13;
515            pDLSID->abData[6] = uuid.byte14;
516            pDLSID->abData[7] = uuid.byte15;
517    #else
518            uuid_t uuid;
519            uuid_generate(uuid);
520            pDLSID->ulData1 = uuid[0] | uuid[1] << 8 | uuid[2] << 16 | uuid[3] << 24;
521            pDLSID->usData2 = uuid[4] | uuid[5] << 8;
522            pDLSID->usData3 = uuid[6] | uuid[7] << 8;
523            memcpy(pDLSID->abData, &uuid[8], 8);
524    #endif
525    #endif
526        }
527        
528        /**
529         * Make a deep copy of the Resource object given by @a orig and assign it
530         * to this object.
531         *
532         * @param orig - original Resource object to be copied from
533         */
534        void Resource::CopyAssign(const Resource* orig) {
535            pInfo->CopyAssign(orig->pInfo);
536        }
537    
538    
539  // *************** Sampler ***************  // *************** Sampler ***************
# Line 410  namespace DLS { Line 550  namespace DLS {
550              SamplerOptions = wsmp->ReadUint32();              SamplerOptions = wsmp->ReadUint32();
551              SampleLoops    = wsmp->ReadUint32();              SampleLoops    = wsmp->ReadUint32();
552          } else { // 'wsmp' chunk missing          } else { // 'wsmp' chunk missing
553              uiHeaderSize   = 0;              uiHeaderSize   = 20;
554              UnityNote      = 64;              UnityNote      = 60;
555              FineTune       = 0; // +- 0 cents              FineTune       = 0; // +- 0 cents
556              Gain           = 0; // 0 dB              Gain           = 0; // 0 dB
557              SamplerOptions = F_WSMP_NO_COMPRESSION;              SamplerOptions = F_WSMP_NO_COMPRESSION;
# Line 435  namespace DLS { Line 575  namespace DLS {
575          if (pSampleLoops) delete[] pSampleLoops;          if (pSampleLoops) delete[] pSampleLoops;
576      }      }
577    
578        void Sampler::SetGain(int32_t gain) {
579            Gain = gain;
580        }
581    
582      /**      /**
583       * Apply all sample player options to the respective RIFF chunk. You       * Apply all sample player options to the respective RIFF chunk. You
584       * have to call File::Save() to make changes persistent.       * have to call File::Save() to make changes persistent.
# Line 442  namespace DLS { Line 586  namespace DLS {
586      void Sampler::UpdateChunks() {      void Sampler::UpdateChunks() {
587          // make sure 'wsmp' chunk exists          // make sure 'wsmp' chunk exists
588          RIFF::Chunk* wsmp = pParentList->GetSubChunk(CHUNK_ID_WSMP);          RIFF::Chunk* wsmp = pParentList->GetSubChunk(CHUNK_ID_WSMP);
589            int wsmpSize = uiHeaderSize + SampleLoops * 16;
590          if (!wsmp) {          if (!wsmp) {
591              uiHeaderSize = 20;              wsmp = pParentList->AddSubChunk(CHUNK_ID_WSMP, wsmpSize);
592              wsmp = pParentList->AddSubChunk(CHUNK_ID_WSMP, uiHeaderSize + SampleLoops * 16);          } else if (wsmp->GetSize() != wsmpSize) {
593                wsmp->Resize(wsmpSize);
594          }          }
595          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();
596          // update headers size          // update headers size
597          memccpy(&pData[0], &uiHeaderSize, 1, 4);          store32(&pData[0], uiHeaderSize);
598          // update respective sampler options bits          // update respective sampler options bits
599          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION
600                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);
601          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION
602                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);
603            store16(&pData[4], UnityNote);
604            store16(&pData[6], FineTune);
605            store32(&pData[8], Gain);
606            store32(&pData[12], SamplerOptions);
607            store32(&pData[16], SampleLoops);
608          // update loop definitions          // update loop definitions
609          for (uint32_t i = 0; i < SampleLoops; i++) {          for (uint32_t i = 0; i < SampleLoops; i++) {
610              //FIXME: this does not handle extended loop structs correctly              //FIXME: this does not handle extended loop structs correctly
611              memccpy(&pData[uiHeaderSize + i * 16], pSampleLoops + i, 4, 4);              store32(&pData[uiHeaderSize + i * 16], pSampleLoops[i].Size);
612                store32(&pData[uiHeaderSize + i * 16 + 4], pSampleLoops[i].LoopType);
613                store32(&pData[uiHeaderSize + i * 16 + 8], pSampleLoops[i].LoopStart);
614                store32(&pData[uiHeaderSize + i * 16 + 12], pSampleLoops[i].LoopLength);
615          }          }
616      }      }
617    
618        /**
619         * Adds a new sample loop with the provided loop definition.
620         *
621         * @param pLoopDef - points to a loop definition that is to be copied
622         */
623        void Sampler::AddSampleLoop(sample_loop_t* pLoopDef) {
624            sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops + 1];
625            // copy old loops array
626            for (int i = 0; i < SampleLoops; i++) {
627                pNewLoops[i] = pSampleLoops[i];
628            }
629            // add the new loop
630            pNewLoops[SampleLoops] = *pLoopDef;
631            // auto correct size field
632            pNewLoops[SampleLoops].Size = sizeof(DLS::sample_loop_t);
633            // free the old array and update the member variables
634            if (SampleLoops) delete[] pSampleLoops;
635            pSampleLoops = pNewLoops;
636            SampleLoops++;
637        }
638    
639        /**
640         * Deletes an existing sample loop.
641         *
642         * @param pLoopDef - pointer to existing loop definition
643         * @throws Exception - if given loop definition does not exist
644         */
645        void Sampler::DeleteSampleLoop(sample_loop_t* pLoopDef) {
646            sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops - 1];
647            // copy old loops array (skipping given loop)
648            for (int i = 0, o = 0; i < SampleLoops; i++) {
649                if (&pSampleLoops[i] == pLoopDef) continue;
650                if (o == SampleLoops - 1) {
651                    delete[] pNewLoops;
652                    throw Exception("Could not delete Sample Loop, because it does not exist");
653                }
654                pNewLoops[o] = pSampleLoops[i];
655                o++;
656            }
657            // free the old array and update the member variables
658            if (SampleLoops) delete[] pSampleLoops;
659            pSampleLoops = pNewLoops;
660            SampleLoops--;
661        }
662        
663        /**
664         * Make a deep copy of the Sampler object given by @a orig and assign it
665         * to this object.
666         *
667         * @param orig - original Sampler object to be copied from
668         */
669        void Sampler::CopyAssign(const Sampler* orig) {
670            // copy trivial scalars
671            UnityNote = orig->UnityNote;
672            FineTune = orig->FineTune;
673            Gain = orig->Gain;
674            NoSampleDepthTruncation = orig->NoSampleDepthTruncation;
675            NoSampleCompression = orig->NoSampleCompression;
676            SamplerOptions = orig->SamplerOptions;
677            
678            // copy sample loops
679            if (SampleLoops) delete[] pSampleLoops;
680            pSampleLoops = new sample_loop_t[orig->SampleLoops];
681            memcpy(pSampleLoops, orig->pSampleLoops, orig->SampleLoops * sizeof(sample_loop_t));
682            SampleLoops = orig->SampleLoops;
683        }
684    
685    
686  // *************** Sample ***************  // *************** Sample ***************
# Line 494  namespace DLS { Line 714  namespace DLS {
714              AverageBytesPerSecond  = pCkFormat->ReadUint32();              AverageBytesPerSecond  = pCkFormat->ReadUint32();
715              BlockAlign             = pCkFormat->ReadUint16();              BlockAlign             = pCkFormat->ReadUint16();
716              // PCM format specific              // PCM format specific
717              if (FormatTag == WAVE_FORMAT_PCM) {              if (FormatTag == DLS_WAVE_FORMAT_PCM) {
718                  BitDepth     = pCkFormat->ReadUint16();                  BitDepth     = pCkFormat->ReadUint16();
719                  FrameSize    = (FormatTag == WAVE_FORMAT_PCM) ? (BitDepth / 8) * Channels                  FrameSize    = (BitDepth / 8) * Channels;
                                                             : 0;  
720              } else { // unsupported sample data format              } else { // unsupported sample data format
721                  BitDepth     = 0;                  BitDepth     = 0;
722                  FrameSize    = 0;                  FrameSize    = 0;
723              }              }
724          } else { // 'fmt' chunk missing          } else { // 'fmt' chunk missing
725              FormatTag              = WAVE_FORMAT_PCM;              FormatTag              = DLS_WAVE_FORMAT_PCM;
726              BitDepth               = 16;              BitDepth               = 16;
727              Channels               = 1;              Channels               = 1;
728              SamplesPerSecond       = 44100;              SamplesPerSecond       = 44100;
# Line 511  namespace DLS { Line 730  namespace DLS {
730              FrameSize              = (BitDepth / 8) * Channels;              FrameSize              = (BitDepth / 8) * Channels;
731              BlockAlign             = FrameSize;              BlockAlign             = FrameSize;
732          }          }
733          SamplesTotal = (pCkData) ? (FormatTag == WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize          SamplesTotal = (pCkData) ? (FormatTag == DLS_WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize
734                                                                    : 0                                                                        : 0
735                                   : 0;                                   : 0;
736      }      }
737    
# Line 525  namespace DLS { Line 744  namespace DLS {
744          RIFF::List* pParent = pWaveList->GetParent();          RIFF::List* pParent = pWaveList->GetParent();
745          pParent->DeleteSubChunk(pWaveList);          pParent->DeleteSubChunk(pWaveList);
746      }      }
747        
748        /**
749         * Make a deep copy of the Sample object given by @a orig (without the
750         * actual sample waveform data however) and assign it to this object.
751         *
752         * This is a special internal variant of CopyAssign() which only copies the
753         * most mandatory member variables. It will be called by gig::Sample
754         * descendent instead of CopyAssign() since gig::Sample has its own
755         * implementation to access and copy the actual sample waveform data.
756         *
757         * @param orig - original Sample object to be copied from
758         */
759        void Sample::CopyAssignCore(const Sample* orig) {
760            // handle base classes
761            Resource::CopyAssign(orig);
762            // handle actual own attributes of this class
763            FormatTag = orig->FormatTag;
764            Channels = orig->Channels;
765            SamplesPerSecond = orig->SamplesPerSecond;
766            AverageBytesPerSecond = orig->AverageBytesPerSecond;
767            BlockAlign = orig->BlockAlign;
768            BitDepth = orig->BitDepth;
769            SamplesTotal = orig->SamplesTotal;
770            FrameSize = orig->FrameSize;
771        }
772        
773        /**
774         * Make a deep copy of the Sample object given by @a orig and assign it to
775         * this object.
776         *
777         * @param orig - original Sample object to be copied from
778         */
779        void Sample::CopyAssign(const Sample* orig) {
780            CopyAssignCore(orig);
781            
782            // copy sample waveform data (reading directly from disc)
783            Resize(orig->GetSize());
784            char* buf = (char*) LoadSampleData();
785            Sample* pOrig = (Sample*) orig; //HACK: circumventing the constness here for now
786            const unsigned long restorePos = pOrig->pCkData->GetPos();
787            pOrig->SetPos(0);
788            for (unsigned long todo = pOrig->GetSize(), i = 0; todo; ) {
789                const int iReadAtOnce = 64*1024;
790                unsigned long n = (iReadAtOnce < todo) ? iReadAtOnce : todo;
791                n = pOrig->Read(&buf[i], n);
792                if (!n) break;
793                todo -= n;
794                i += (n * pOrig->FrameSize);
795            }
796            pOrig->pCkData->SetPos(restorePos);
797        }
798    
799      /** @brief Load sample data into RAM.      /** @brief Load sample data into RAM.
800       *       *
# Line 572  namespace DLS { Line 842  namespace DLS {
842       * the RIFF chunk which encapsulates the sample's wave data. The       * the RIFF chunk which encapsulates the sample's wave data. The
843       * returned value is dependant to the current FrameSize value.       * returned value is dependant to the current FrameSize value.
844       *       *
845       * @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
846       * @see FrameSize, FormatTag       * @see FrameSize, FormatTag
847       */       */
848      unsigned long Sample::GetSize() {      unsigned long Sample::GetSize() const {
849          if (FormatTag != WAVE_FORMAT_PCM) return 0;          if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0;
850          return (pCkData) ? pCkData->GetSize() / FrameSize : 0;          return (pCkData) ? pCkData->GetSize() / FrameSize : 0;
851      }      }
852    
# Line 598  namespace DLS { Line 868  namespace DLS {
868       * calling File::Save() as this might exceed the current sample's       * calling File::Save() as this might exceed the current sample's
869       * boundary!       * boundary!
870       *       *
871       * Also note: only WAVE_FORMAT_PCM is currently supported, that is       * Also note: only DLS_WAVE_FORMAT_PCM is currently supported, that is
872       * FormatTag must be WAVE_FORMAT_PCM. Trying to resize samples with       * FormatTag must be DLS_WAVE_FORMAT_PCM. Trying to resize samples with
873       * other formats will fail!       * other formats will fail!
874       *       *
875       * @param iNewSize - new sample wave data size in sample points (must be       * @param iNewSize - new sample wave data size in sample points (must be
876       *                   greater than zero)       *                   greater than zero)
877       * @throws Excecption if FormatTag != WAVE_FORMAT_PCM       * @throws Excecption if FormatTag != DLS_WAVE_FORMAT_PCM
878       * @throws Exception if \a iNewSize is less than 1       * @throws Exception if \a iNewSize is less than 1
879       * @see File::Save(), FrameSize, FormatTag       * @see File::Save(), FrameSize, FormatTag
880       */       */
881      void Sample::Resize(int iNewSize) {      void Sample::Resize(int iNewSize) {
882          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");
883          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");
884          const int iSizeInBytes = iNewSize * FrameSize;          const int iSizeInBytes = iNewSize * FrameSize;
885          pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA);          pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA);
# Line 622  namespace DLS { Line 892  namespace DLS {
892       * 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
893       * the sample into RAM, thus for disk streaming.       * the sample into RAM, thus for disk streaming.
894       *       *
895       * Also note: only WAVE_FORMAT_PCM is currently supported, that is       * Also note: only DLS_WAVE_FORMAT_PCM is currently supported, that is
896       * FormatTag must be WAVE_FORMAT_PCM. Trying to reposition the sample       * FormatTag must be DLS_WAVE_FORMAT_PCM. Trying to reposition the sample
897       * with other formats will fail!       * with other formats will fail!
898       *       *
899       * @param SampleCount  number of sample points       * @param SampleCount  number of sample points
900       * @param Whence       to which relation \a SampleCount refers to       * @param Whence       to which relation \a SampleCount refers to
901       * @returns new position within the sample, 0 if       * @returns new position within the sample, 0 if
902       *          FormatTag != WAVE_FORMAT_PCM       *          FormatTag != DLS_WAVE_FORMAT_PCM
903       * @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
904       * @see FrameSize, FormatTag       * @see FrameSize, FormatTag
905       */       */
906      unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {      unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {
907          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
908          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");
909          unsigned long orderedBytes = SampleCount * FrameSize;          unsigned long orderedBytes = SampleCount * FrameSize;
910          unsigned long result = pCkData->SetPos(orderedBytes, Whence);          unsigned long result = pCkData->SetPos(orderedBytes, Whence);
# Line 652  namespace DLS { Line 922  namespace DLS {
922       * @param SampleCount  number of sample points to read       * @param SampleCount  number of sample points to read
923       */       */
924      unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {      unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {
925          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
926          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?
927      }      }
928    
# Line 672  namespace DLS { Line 942  namespace DLS {
942       * @see LoadSampleData()       * @see LoadSampleData()
943       */       */
944      unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) {      unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) {
945          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
946          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");
947          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?
948      }      }
# Line 681  namespace DLS { Line 951  namespace DLS {
951       * Apply sample and its settings to the respective RIFF chunks. You have       * Apply sample and its settings to the respective RIFF chunks. You have
952       * to call File::Save() to make changes persistent.       * to call File::Save() to make changes persistent.
953       *       *
954       * @throws Exception if FormatTag != WAVE_FORMAT_PCM or no sample data       * @throws Exception if FormatTag != DLS_WAVE_FORMAT_PCM or no sample data
955       *                   was provided yet       *                   was provided yet
956       */       */
957      void Sample::UpdateChunks() {      void Sample::UpdateChunks() {
958          if (FormatTag != WAVE_FORMAT_PCM)          if (FormatTag != DLS_WAVE_FORMAT_PCM)
959              throw Exception("Could not save sample, only PCM format is supported");              throw Exception("Could not save sample, only PCM format is supported");
960          // 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
961          if (!pCkData)          if (!pCkData)
# Line 697  namespace DLS { Line 967  namespace DLS {
967          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format
968          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();
969          // update 'fmt' chunk          // update 'fmt' chunk
970          memccpy(&pData[0], &FormatTag, 1, 2);          store16(&pData[0], FormatTag);
971          memccpy(&pData[2], &Channels,  1, 2);          store16(&pData[2], Channels);
972          memccpy(&pData[4], &SamplesPerSecond, 1, 4);          store32(&pData[4], SamplesPerSecond);
973          memccpy(&pData[8], &AverageBytesPerSecond, 1, 4);          store32(&pData[8], AverageBytesPerSecond);
974          memccpy(&pData[12], &BlockAlign, 1, 2);          store16(&pData[12], BlockAlign);
975          memccpy(&pData[14], &BitDepth, 1, 2); // assuming PCM format          store16(&pData[14], BitDepth); // assuming PCM format
976      }      }
977    
978    
# Line 786  namespace DLS { Line 1056  namespace DLS {
1056      }      }
1057    
1058      /**      /**
1059         * Modifies the key range of this Region and makes sure the respective
1060         * chunks are in correct order.
1061         *
1062         * @param Low  - lower end of key range
1063         * @param High - upper end of key range
1064         */
1065        void Region::SetKeyRange(uint16_t Low, uint16_t High) {
1066            KeyRange.low  = Low;
1067            KeyRange.high = High;
1068    
1069            // make sure regions are already loaded
1070            Instrument* pInstrument = (Instrument*) GetParent();
1071            if (!pInstrument->pRegions) pInstrument->LoadRegions();
1072            if (!pInstrument->pRegions) return;
1073    
1074            // find the r which is the first one to the right of this region
1075            // at its new position
1076            Region* r = NULL;
1077            Region* prev_region = NULL;
1078            for (
1079                Instrument::RegionList::iterator iter = pInstrument->pRegions->begin();
1080                iter != pInstrument->pRegions->end(); iter++
1081            ) {
1082                if ((*iter)->KeyRange.low > this->KeyRange.low) {
1083                    r = *iter;
1084                    break;
1085                }
1086                prev_region = *iter;
1087            }
1088    
1089            // place this region before r if it's not already there
1090            if (prev_region != this) pInstrument->MoveRegion(this, r);
1091        }
1092    
1093        /**
1094       * Apply Region settings to the respective RIFF chunks. You have to       * Apply Region settings to the respective RIFF chunks. You have to
1095       * call File::Save() to make changes persistent.       * call File::Save() to make changes persistent.
1096       *       *
# Line 794  namespace DLS { Line 1099  namespace DLS {
1099      void Region::UpdateChunks() {      void Region::UpdateChunks() {
1100          // make sure 'rgnh' chunk exists          // make sure 'rgnh' chunk exists
1101          RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH);          RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH);
1102          if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, 14);          if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, Layer ? 14 : 12);
1103          uint8_t* pData = (uint8_t*) rgnh->LoadChunkData();          uint8_t* pData = (uint8_t*) rgnh->LoadChunkData();
1104          FormatOptionFlags = (SelfNonExclusive)          FormatOptionFlags = (SelfNonExclusive)
1105                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE
1106                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);
1107          // update 'rgnh' chunk          // update 'rgnh' chunk
1108          memccpy(&pData[0], &KeyRange, 2, 2);          store16(&pData[0], KeyRange.low);
1109          memccpy(&pData[4], &VelocityRange, 2, 2);          store16(&pData[2], KeyRange.high);
1110          memccpy(&pData[8], &FormatOptionFlags, 1, 2);          store16(&pData[4], VelocityRange.low);
1111          memccpy(&pData[10], &KeyGroup, 1, 2);          store16(&pData[6], VelocityRange.high);
1112          memccpy(&pData[12], &Layer, 1, 2);          store16(&pData[8], FormatOptionFlags);
1113            store16(&pData[10], KeyGroup);
1114            if (rgnh->GetSize() >= 14) store16(&pData[12], Layer);
1115    
1116          // update chunks of base classes as well          // update chunks of base classes as well (but skip Resource,
1117          Resource::UpdateChunks();          // as a rgn doesn't seem to have dlid and INFO chunks)
1118          Articulator::UpdateChunks();          Articulator::UpdateChunks();
1119          Sampler::UpdateChunks();          Sampler::UpdateChunks();
1120    
# Line 834  namespace DLS { Line 1141  namespace DLS {
1141                  }                  }
1142              }              }
1143          }          }
         if (index < 0) throw Exception("Could not save Region, could not find Region's sample");  
1144          WavePoolTableIndex = index;          WavePoolTableIndex = index;
1145          // update 'wlnk' chunk          // update 'wlnk' chunk
1146          memccpy(&pData[0], &WaveLinkOptionFlags, 1, 2);          store16(&pData[0], WaveLinkOptionFlags);
1147          memccpy(&pData[2], &PhaseGroup, 1, 2);          store16(&pData[2], PhaseGroup);
1148          memccpy(&pData[4], &Channel, 1, 4);          store32(&pData[4], Channel);
1149          memccpy(&pData[8], &WavePoolTableIndex, 1, 4);          store32(&pData[8], WavePoolTableIndex);
1150        }
1151        
1152        /**
1153         * Make a (semi) deep copy of the Region object given by @a orig and assign
1154         * it to this object.
1155         *
1156         * Note that the sample pointer referenced by @a orig is simply copied as
1157         * memory address. Thus the respective sample is shared, not duplicated!
1158         *
1159         * @param orig - original Region object to be copied from
1160         */
1161        void Region::CopyAssign(const Region* orig) {
1162            // handle base classes
1163            Resource::CopyAssign(orig);
1164            Articulator::CopyAssign(orig);
1165            Sampler::CopyAssign(orig);
1166            // handle actual own attributes of this class
1167            // (the trivial ones)
1168            VelocityRange = orig->VelocityRange;
1169            KeyGroup = orig->KeyGroup;
1170            Layer = orig->Layer;
1171            SelfNonExclusive = orig->SelfNonExclusive;
1172            PhaseMaster = orig->PhaseMaster;
1173            PhaseGroup = orig->PhaseGroup;
1174            MultiChannel = orig->MultiChannel;
1175            Channel = orig->Channel;
1176            // only take the raw sample reference if the two Region objects are
1177            // part of the same file
1178            if (GetParent()->GetParent() == orig->GetParent()->GetParent()) {
1179                WavePoolTableIndex = orig->WavePoolTableIndex;
1180                pSample = orig->pSample;
1181            } else {
1182                WavePoolTableIndex = -1;
1183                pSample = NULL;
1184            }
1185            FormatOptionFlags = orig->FormatOptionFlags;
1186            WaveLinkOptionFlags = orig->WaveLinkOptionFlags;
1187            // handle the last, a bit sensible attribute
1188            SetKeyRange(orig->KeyRange.low, orig->KeyRange.high);
1189      }      }
   
1190    
1191    
1192  // *************** Instrument ***************  // *************** Instrument ***************
# Line 923  namespace DLS { Line 1267  namespace DLS {
1267          return pNewRegion;          return pNewRegion;
1268      }      }
1269    
1270        void Instrument::MoveRegion(Region* pSrc, Region* pDst) {
1271            RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
1272            lrgn->MoveSubChunk(pSrc->pCkRegion, pDst ? pDst->pCkRegion : 0);
1273    
1274            pRegions->remove(pSrc);
1275            RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pDst);
1276            pRegions->insert(iter, pSrc);
1277        }
1278    
1279      void Instrument::DeleteRegion(Region* pRegion) {      void Instrument::DeleteRegion(Region* pRegion) {
1280          if (!pRegions) return;          if (!pRegions) return;
1281          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);
# Line 953  namespace DLS { Line 1306  namespace DLS {
1306          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);
1307          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);
1308          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
1309          memccpy(&pData[0], &Regions, 1, 4);          store32(&pData[0], Regions);
1310          memccpy(&pData[4], &locale, 2, 4);          store32(&pData[4], locale.bank);
1311            store32(&pData[8], locale.instrument);
1312          // update Region's chunks          // update Region's chunks
1313          if (!pRegions) return;          if (!pRegions) return;
1314          RegionList::iterator iter = pRegions->begin();          RegionList::iterator iter = pRegions->begin();
# Line 983  namespace DLS { Line 1337  namespace DLS {
1337          RIFF::List* pParent = pCkInstrument->GetParent();          RIFF::List* pParent = pCkInstrument->GetParent();
1338          pParent->DeleteSubChunk(pCkInstrument);          pParent->DeleteSubChunk(pCkInstrument);
1339      }      }
1340        
1341        void Instrument::CopyAssignCore(const Instrument* orig) {
1342            // handle base classes
1343            Resource::CopyAssign(orig);
1344            Articulator::CopyAssign(orig);
1345            // handle actual own attributes of this class
1346            // (the trivial ones)
1347            IsDrum = orig->IsDrum;
1348            MIDIBank = orig->MIDIBank;
1349            MIDIBankCoarse = orig->MIDIBankCoarse;
1350            MIDIBankFine = orig->MIDIBankFine;
1351            MIDIProgram = orig->MIDIProgram;
1352        }
1353        
1354        /**
1355         * Make a (semi) deep copy of the Instrument object given by @a orig and assign
1356         * it to this object.
1357         *
1358         * Note that all sample pointers referenced by @a orig are simply copied as
1359         * memory address. Thus the respective samples are shared, not duplicated!
1360         *
1361         * @param orig - original Instrument object to be copied from
1362         */
1363        void Instrument::CopyAssign(const Instrument* orig) {
1364            CopyAssignCore(orig);
1365            // delete all regions first
1366            while (Regions) DeleteRegion(GetFirstRegion());
1367            // now recreate and copy regions
1368            {
1369                RegionList::const_iterator it = orig->pRegions->begin();
1370                for (int i = 0; i < orig->Regions; ++i, ++it) {
1371                    Region* dstRgn = AddRegion();
1372                    //NOTE: Region does semi-deep copy !
1373                    dstRgn->CopyAssign(*it);
1374                }
1375            }
1376        }
1377    
1378    
1379  // *************** File ***************  // *************** File ***************
# Line 996  namespace DLS { Line 1386  namespace DLS {
1386       * a DLS file.       * a DLS file.
1387       */       */
1388      File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) {      File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) {
1389            pRIFF->SetByteOrder(RIFF::endian_little);
1390          pVersion = new version_t;          pVersion = new version_t;
1391          pVersion->major   = 0;          pVersion->major   = 0;
1392          pVersion->minor   = 0;          pVersion->minor   = 0;
# Line 1039  namespace DLS { Line 1430  namespace DLS {
1430          Instruments = colh->ReadUint32();          Instruments = colh->ReadUint32();
1431    
1432          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);
1433          if (!ptbl) throw DLS::Exception("Mandatory <ptbl> chunk not found.");          if (!ptbl) { // pool table is missing - this is probably an ".art" file
1434          WavePoolHeaderSize = ptbl->ReadUint32();              WavePoolCount    = 0;
1435          WavePoolCount  = ptbl->ReadUint32();              pWavePoolTable   = NULL;
1436          pWavePoolTable = new uint32_t[WavePoolCount];              pWavePoolTableHi = NULL;
1437          pWavePoolTableHi = new uint32_t[WavePoolCount];              WavePoolHeaderSize = 8;
1438          ptbl->SetPos(WavePoolHeaderSize);              b64BitWavePoolOffsets = false;
1439            } else {
1440          // Check for 64 bit offsets (used in gig v3 files)              WavePoolHeaderSize = ptbl->ReadUint32();
1441          b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8);              WavePoolCount  = ptbl->ReadUint32();
1442          if (b64BitWavePoolOffsets) {              pWavePoolTable = new uint32_t[WavePoolCount];
1443              for (int i = 0 ; i < WavePoolCount ; i++) {              pWavePoolTableHi = new uint32_t[WavePoolCount];
1444                  pWavePoolTableHi[i] = ptbl->ReadUint32();              ptbl->SetPos(WavePoolHeaderSize);
1445                  pWavePoolTable[i] = ptbl->ReadUint32();  
1446                  if (pWavePoolTable[i] & 0x80000000)              // Check for 64 bit offsets (used in gig v3 files)
1447                      throw DLS::Exception("Files larger than 2 GB not yet supported");              b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8);
1448                if (b64BitWavePoolOffsets) {
1449                    for (int i = 0 ; i < WavePoolCount ; i++) {
1450                        pWavePoolTableHi[i] = ptbl->ReadUint32();
1451                        pWavePoolTable[i] = ptbl->ReadUint32();
1452                        if (pWavePoolTable[i] & 0x80000000)
1453                            throw DLS::Exception("Files larger than 2 GB not yet supported");
1454                    }
1455                } else { // conventional 32 bit offsets
1456                    ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));
1457                    for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;
1458              }              }
         } else { // conventional 32 bit offsets  
             ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));  
             for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;  
1459          }          }
1460    
1461          pSamples     = NULL;          pSamples     = NULL;
# Line 1228  namespace DLS { Line 1626  namespace DLS {
1626      }      }
1627    
1628      /**      /**
1629         * Returns extension file of given index. Extension files are used
1630         * sometimes to circumvent the 2 GB file size limit of the RIFF format and
1631         * of certain operating systems in general. In this case, instead of just
1632         * using one file, the content is spread among several files with similar
1633         * file name scheme. This is especially used by some GigaStudio sound
1634         * libraries.
1635         *
1636         * @param index - index of extension file
1637         * @returns sought extension file, NULL if index out of bounds
1638         * @see GetFileName()
1639         */
1640        RIFF::File* File::GetExtensionFile(int index) {
1641            if (index < 0 || index >= ExtensionFiles.size()) return NULL;
1642            std::list<RIFF::File*>::iterator iter = ExtensionFiles.begin();
1643            for (int i = 0; iter != ExtensionFiles.end(); ++iter, ++i)
1644                if (i == index) return *iter;
1645            return NULL;
1646        }
1647    
1648        /** @brief File name of this DLS file.
1649         *
1650         * This method returns the file name as it was provided when loading
1651         * the respective DLS file. However in case the File object associates
1652         * an empty, that is new DLS file, which was not yet saved to disk,
1653         * this method will return an empty string.
1654         *
1655         * @see GetExtensionFile()
1656         */
1657        String File::GetFileName() {
1658            return pRIFF->GetFileName();
1659        }
1660        
1661        /**
1662         * You may call this method store a future file name, so you don't have to
1663         * to pass it to the Save() call later on.
1664         */
1665        void File::SetFileName(const String& name) {
1666            pRIFF->SetFileName(name);
1667        }
1668    
1669        /**
1670       * Apply all the DLS file's current instruments, samples and settings to       * Apply all the DLS file's current instruments, samples and settings to
1671       * the respective RIFF chunks. You have to call Save() to make changes       * the respective RIFF chunks. You have to call Save() to make changes
1672       * persistent.       * persistent.
# Line 1243  namespace DLS { Line 1682  namespace DLS {
1682              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);
1683              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);
1684              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();
1685              memccpy(pData, pVersion, 2, 4);              store16(&pData[0], pVersion->minor);
1686                store16(&pData[2], pVersion->major);
1687                store16(&pData[4], pVersion->build);
1688                store16(&pData[6], pVersion->release);
1689          }          }
1690    
1691          // update 'colh' chunk          // update 'colh' chunk
# Line 1251  namespace DLS { Line 1693  namespace DLS {
1693          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);
1694          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);
1695          uint8_t* pData = (uint8_t*) colh->LoadChunkData();          uint8_t* pData = (uint8_t*) colh->LoadChunkData();
1696          memccpy(pData, &Instruments, 1, 4);          store32(pData, Instruments);
1697    
1698          // update instrument's chunks          // update instrument's chunks
1699          if (pInstruments) {          if (pInstruments) {
# Line 1271  namespace DLS { Line 1713  namespace DLS {
1713          ptbl->Resize(iPtblSize);          ptbl->Resize(iPtblSize);
1714          pData = (uint8_t*) ptbl->LoadChunkData();          pData = (uint8_t*) ptbl->LoadChunkData();
1715          WavePoolCount = iSamples;          WavePoolCount = iSamples;
1716          memccpy(&pData[4], &WavePoolCount, 1, 4);          store32(&pData[4], WavePoolCount);
1717          // 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()
1718          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);
1719    
# Line 1360  namespace DLS { Line 1802  namespace DLS {
1802          unsigned long ulOriginalPos = ptbl->GetPos();          unsigned long ulOriginalPos = ptbl->GetPos();
1803          // update headers          // update headers
1804          ptbl->SetPos(0);          ptbl->SetPos(0);
1805          ptbl->WriteUint32(&WavePoolHeaderSize);          uint32_t tmp = WavePoolHeaderSize;
1806          ptbl->WriteUint32(&WavePoolCount);          ptbl->WriteUint32(&tmp);
1807            tmp = WavePoolCount;
1808            ptbl->WriteUint32(&tmp);
1809          // update offsets          // update offsets
1810          ptbl->SetPos(WavePoolHeaderSize);          ptbl->SetPos(WavePoolHeaderSize);
1811          if (b64BitWavePoolOffsets) {          if (b64BitWavePoolOffsets) {
1812              for (int i = 0 ; i < WavePoolCount ; i++) {              for (int i = 0 ; i < WavePoolCount ; i++) {
1813                  ptbl->WriteUint32(&pWavePoolTableHi[i]);                  tmp = pWavePoolTableHi[i];
1814                  ptbl->WriteUint32(&pWavePoolTable[i]);                  ptbl->WriteUint32(&tmp);
1815                    tmp = pWavePoolTable[i];
1816                    ptbl->WriteUint32(&tmp);
1817              }              }
1818          } else { // conventional 32 bit offsets          } else { // conventional 32 bit offsets
1819              for (int i = 0 ; i < WavePoolCount ; i++)              for (int i = 0 ; i < WavePoolCount ; i++) {
1820                  ptbl->WriteUint32(&pWavePoolTable[i]);                  tmp = pWavePoolTable[i];
1821                    ptbl->WriteUint32(&tmp);
1822                }
1823          }          }
1824          // restore 'ptbl' chunk's original read/write position          // restore 'ptbl' chunk's original read/write position
1825          ptbl->SetPos(ulOriginalPos);          ptbl->SetPos(ulOriginalPos);

Legend:
Removed from v.834  
changed lines
  Added in v.2482

  ViewVC Help
Powered by ViewVC