/[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 919 by schoenebeck, Fri Sep 15 19:35:11 2006 UTC revision 1266 by persson, Thu Aug 2 14:12:55 2007 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   libgig - C++ cross-platform Gigasampler format file loader library    *   *   libgig - C++ cross-platform Gigasampler format file access library    *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003-2005 by Christian Schoenebeck                      *   *   Copyright (C) 2003-2007 by Christian Schoenebeck                      *
6   *                              <cuse@users.sourceforge.net>               *   *                              <cuse@users.sourceforge.net>               *
7   *                                                                         *   *                                                                         *
8   *   This library is free software; you can redistribute it and/or modify  *   *   This library is free software; you can redistribute it and/or modify  *
# Line 25  Line 25 
25    
26  #include <time.h>  #include <time.h>
27    
28    #ifdef __APPLE__
29    #include <CoreFoundation/CFUUID.h>
30    #elif defined(HAVE_UUID_UUID_H)
31    #include <uuid/uuid.h>
32    #endif
33    
34  #include "helper.h"  #include "helper.h"
35    
36  // macros to decode connection transforms  // macros to decode connection transforms
# Line 142  namespace DLS { Line 148  namespace DLS {
148          const int iEntrySize = 12; // 12 bytes per connection block          const int iEntrySize = 12; // 12 bytes per connection block
149          pArticulationCk->Resize(HeaderSize + Connections * iEntrySize);          pArticulationCk->Resize(HeaderSize + Connections * iEntrySize);
150          uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData();          uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData();
151          memcpy(&pData[0], &HeaderSize, 2);          store16(&pData[0], HeaderSize);
152          memcpy(&pData[2], &Connections, 2);          store16(&pData[2], Connections);
153          for (uint32_t i = 0; i < Connections; i++) {          for (uint32_t i = 0; i < Connections; i++) {
154              Connection::conn_block_t c = pConnections[i].ToConnBlock();              Connection::conn_block_t c = pConnections[i].ToConnBlock();
155              memcpy(&pData[HeaderSize + i * iEntrySize],     &c.source, 2);              store16(&pData[HeaderSize + i * iEntrySize],     c.source);
156              memcpy(&pData[HeaderSize + i * iEntrySize + 2], &c.control, 2);              store16(&pData[HeaderSize + i * iEntrySize + 2], c.control);
157              memcpy(&pData[HeaderSize + i * iEntrySize + 4], &c.destination, 2);              store16(&pData[HeaderSize + i * iEntrySize + 4], c.destination);
158              memcpy(&pData[HeaderSize + i * iEntrySize + 6], &c.transform, 2);              store16(&pData[HeaderSize + i * iEntrySize + 6], c.transform);
159              memcpy(&pData[HeaderSize + i * iEntrySize + 8], &c.scale, 4);              store32(&pData[HeaderSize + i * iEntrySize + 8], c.scale);
160          }          }
161      }      }
162    
# Line 228  namespace DLS { Line 234  namespace DLS {
234    
235      /** @brief Constructor.      /** @brief Constructor.
236       *       *
237       * Initializes the info strings with values provided by a INFO list chunk.       * Initializes the info strings with values provided by an INFO list chunk.
238       *       *
239       * @param list - pointer to a list chunk which contains a INFO list chunk       * @param list - pointer to a list chunk which contains an INFO list chunk
240       */       */
241      Info::Info(RIFF::List* list) {      Info::Info(RIFF::List* list) {
242          UseFixedLengthStrings = false;          FixedStringLengths = NULL;
243          pResourceListChunk = list;          pResourceListChunk = list;
244          if (list) {          if (list) {
245              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);
# Line 254  namespace DLS { Line 260  namespace DLS {
260                  LoadString(CHUNK_ID_ISRC, lstINFO, Source);                  LoadString(CHUNK_ID_ISRC, lstINFO, Source);
261                  LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);                  LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);
262                  LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);                  LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);
263                    LoadString(CHUNK_ID_ISBJ, lstINFO, Subject);
264              }              }
265          }          }
266      }      }
# Line 268  namespace DLS { Line 275  namespace DLS {
275       */       */
276      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {
277          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
278          if (ck) {          ::LoadString(ck, s); // function from helper.h
             const char* str = (char*)ck->LoadChunkData();  
             int size = ck->GetSize();  
             int len;  
             for (len = 0 ; len < size ; len++)  
                 if (str[len] == '\0') break;  
             s.assign(str, len);  
             ck->ReleaseChunkData();  
         }  
279      }      }
280    
281      /** @brief Apply given INFO field to the respective chunk.      /** @brief Apply given INFO field to the respective chunk.
# Line 293  namespace DLS { Line 292  namespace DLS {
292       * @param lstINFO  - parent (INFO) RIFF list chunk       * @param lstINFO  - parent (INFO) RIFF list chunk
293       * @param s        - current value of info field       * @param s        - current value of info field
294       * @param sDefault - default value       * @param sDefault - default value
      * @param size     - wanted size of the INFO chunk. This is ignored if UseFixedLengthStrings is false.  
295       */       */
296      void Info::SaveString(uint32_t ChunkID, RIFF::List* lstINFO, const String& s, const String& sDefault, int size) {      void Info::SaveString(uint32_t ChunkID, RIFF::List* lstINFO, const String& s, const String& sDefault) {
297          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          int size = 0;
298          if (ck) { // if chunk exists already, use 's' as value          if (FixedStringLengths) {
299              if (!UseFixedLengthStrings) size = s.size() + 1;              for (int i = 0 ; FixedStringLengths[i].length ; i++) {
300              ck->Resize(size);                  if (FixedStringLengths[i].chunkId == ChunkID) {
301              char* pData = (char*) ck->LoadChunkData();                      size = FixedStringLengths[i].length;
302              strncpy(pData, s.c_str(), size);                      break;
303          } else if (s != "" || sDefault != "") { // create chunk                  }
304              const String& sToSave = (s != "") ? s : sDefault;              }
             if (!UseFixedLengthStrings) size = sToSave.size() + 1;  
             ck = lstINFO->AddSubChunk(ChunkID, size);  
             char* pData = (char*) ck->LoadChunkData();  
             strncpy(pData, sToSave.c_str(), size);  
305          }          }
306            RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
307            ::SaveString(ChunkID, ck, lstINFO, s, sDefault, size != 0, size); // function from helper.h
308      }      }
309    
310      /** @brief Update chunks with current info values.      /** @brief Update chunks with current info values.
# Line 353  namespace DLS { Line 349  namespace DLS {
349    
350          // save values          // save values
351    
352          // (the string size values are for gig files; they are only          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""));
353          // used if UseFixedLengthStrings is set to true)          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""));
354          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName,          SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""));
355                     resourceType == RIFF_TYPE_DLS ? 128 : 64);          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments);
356          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""), 256);          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""));
357          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate, 128);          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate);
358          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments, 1024);          SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""));
359          SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""), 128);          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""));
360          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""), 128);          SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String(""));
361          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""), 128);          SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""));
362          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""), 128);          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName);
363          SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String(""), 128);          SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""));
364          SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""), 128);          SaveString(CHUNK_ID_ISBJ, lstINFO, Subject, String(""));
365          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""), 128);          SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware);
366          SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware,          SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""));
367                     resourceType == LIST_TYPE_INS ?          SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""));
368                     (Software == "" ? defaultSoftware.length() : Software.length()) : 128);          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""));
         SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""), 128);  
         SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""), 128);  
         SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""), 128);  
         SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""), 128);  
369      }      }
370    
371    
# Line 422  namespace DLS { Line 414  namespace DLS {
414       */       */
415      void Resource::UpdateChunks() {      void Resource::UpdateChunks() {
416          pInfo->UpdateChunks();          pInfo->UpdateChunks();
417          //TODO: save DLSID  
418            if (pDLSID) {
419                // make sure 'dlid' chunk exists
420                RIFF::Chunk* ckDLSID = pResourceList->GetSubChunk(CHUNK_ID_DLID);
421                if (!ckDLSID) ckDLSID = pResourceList->AddSubChunk(CHUNK_ID_DLID, 16);
422                uint8_t* pData = (uint8_t*)ckDLSID->LoadChunkData();
423                // update 'dlid' chunk
424                store32(&pData[0], pDLSID->ulData1);
425                store16(&pData[4], pDLSID->usData2);
426                store16(&pData[6], pDLSID->usData3);
427                memcpy(&pData[8], pDLSID->abData, 8);
428            }
429      }      }
430    
431        /**
432         * Generates a new DLSID for the resource.
433         */
434        void Resource::GenerateDLSID() {
435    #if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE)
436    
437            if (!pDLSID) pDLSID = new dlsid_t;
438    
439    #ifdef WIN32
440    
441            UUID uuid;
442            UuidCreate(&uuid);
443            pDLSID->ulData1 = uuid.Data1;
444            pDLSID->usData1 = uuid.Data2;
445            pDLSID->usData2 = uuid.Data3;
446            memcpy(pDLSID->abData, uuid.Data4, 8);
447    
448    #elif defined(__APPLE__)
449    
450            CFUUIDRef uuidRef = CFUUIDCreate(NULL);
451            CFUUIDBytes uuid = CFUUIDGetUUIDBytes(uuidRef);
452            CFRelease(uuidRef);
453            pDLSID->ulData1 = uuid.byte0 | uuid.byte1 << 8 | uuid.byte2 << 16 | uuid.byte3 << 24;
454            pDLSID->usData2 = uuid.byte4 | uuid.byte5 << 8;
455            pDLSID->usData3 = uuid.byte6 | uuid.byte7 << 8;
456            pDLSID->abData[0] = uuid.byte8;
457            pDLSID->abData[1] = uuid.byte9;
458            pDLSID->abData[2] = uuid.byte10;
459            pDLSID->abData[3] = uuid.byte11;
460            pDLSID->abData[4] = uuid.byte12;
461            pDLSID->abData[5] = uuid.byte13;
462            pDLSID->abData[6] = uuid.byte14;
463            pDLSID->abData[7] = uuid.byte15;
464    #else
465            uuid_t uuid;
466            uuid_generate(uuid);
467            pDLSID->ulData1 = uuid[0] | uuid[1] << 8 | uuid[2] << 16 | uuid[3] << 24;
468            pDLSID->usData2 = uuid[4] | uuid[5] << 8;
469            pDLSID->usData3 = uuid[6] | uuid[7] << 8;
470            memcpy(pDLSID->abData, &uuid[8], 8);
471    #endif
472    #endif
473        }
474    
475    
476  // *************** Sampler ***************  // *************** Sampler ***************
# Line 442  namespace DLS { Line 488  namespace DLS {
488              SampleLoops    = wsmp->ReadUint32();              SampleLoops    = wsmp->ReadUint32();
489          } else { // 'wsmp' chunk missing          } else { // 'wsmp' chunk missing
490              uiHeaderSize   = 0;              uiHeaderSize   = 0;
491              UnityNote      = 64;              UnityNote      = 60;
492              FineTune       = 0; // +- 0 cents              FineTune       = 0; // +- 0 cents
493              Gain           = 0; // 0 dB              Gain           = 0; // 0 dB
494              SamplerOptions = F_WSMP_NO_COMPRESSION;              SamplerOptions = F_WSMP_NO_COMPRESSION;
# Line 479  namespace DLS { Line 525  namespace DLS {
525          }          }
526          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();
527          // update headers size          // update headers size
528          memcpy(&pData[0], &uiHeaderSize, 4);          store32(&pData[0], uiHeaderSize);
529          // update respective sampler options bits          // update respective sampler options bits
530          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION
531                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);
532          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION
533                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);
534          memcpy(&pData[4], &UnityNote, 2);          store16(&pData[4], UnityNote);
535          memcpy(&pData[6], &FineTune, 2);          store16(&pData[6], FineTune);
536          memcpy(&pData[8], &Gain, 4);          store32(&pData[8], Gain);
537          memcpy(&pData[12], &SamplerOptions, 4);          store32(&pData[12], SamplerOptions);
538          memcpy(&pData[16], &SampleLoops, 4);          store32(&pData[16], SampleLoops);
539          // update loop definitions          // update loop definitions
540          for (uint32_t i = 0; i < SampleLoops; i++) {          for (uint32_t i = 0; i < SampleLoops; i++) {
541              //FIXME: this does not handle extended loop structs correctly              //FIXME: this does not handle extended loop structs correctly
542              memcpy(&pData[uiHeaderSize + i * 16], pSampleLoops + i, 4 * 4);              store32(&pData[uiHeaderSize + i * 16], pSampleLoops[i].Size);
543                store32(&pData[uiHeaderSize + i * 16 + 4], pSampleLoops[i].LoopType);
544                store32(&pData[uiHeaderSize + i * 16 + 8], pSampleLoops[i].LoopStart);
545                store32(&pData[uiHeaderSize + i * 16 + 12], pSampleLoops[i].LoopLength);
546          }          }
547      }      }
548    
549        /**
550         * Adds a new sample loop with the provided loop definition.
551         *
552         * @param pLoopDef - points to a loop definition that is to be copied
553         */
554        void Sampler::AddSampleLoop(sample_loop_t* pLoopDef) {
555            sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops + 1];
556            // copy old loops array
557            for (int i = 0; i < SampleLoops; i++) {
558                pNewLoops[i] = pSampleLoops[i];
559            }
560            // add the new loop
561            pNewLoops[SampleLoops] = *pLoopDef;
562            // auto correct size field
563            pNewLoops[SampleLoops].Size = sizeof(DLS::sample_loop_t);
564            // free the old array and update the member variables
565            if (SampleLoops) delete[] pSampleLoops;
566            pSampleLoops = pNewLoops;
567            SampleLoops++;
568        }
569    
570        /**
571         * Deletes an existing sample loop.
572         *
573         * @param pLoopDef - pointer to existing loop definition
574         * @throws Exception - if given loop definition does not exist
575         */
576        void Sampler::DeleteSampleLoop(sample_loop_t* pLoopDef) {
577            sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops - 1];
578            // copy old loops array (skipping given loop)
579            for (int i = 0, o = 0; i < SampleLoops; i++) {
580                if (&pSampleLoops[i] == pLoopDef) continue;
581                if (o == SampleLoops - 1)
582                    throw Exception("Could not delete Sample Loop, because it does not exist");
583                pNewLoops[o] = pSampleLoops[i];
584                o++;
585            }
586            // free the old array and update the member variables
587            if (SampleLoops) delete[] pSampleLoops;
588            pSampleLoops = pNewLoops;
589            SampleLoops--;
590        }
591    
592    
593    
594  // *************** Sample ***************  // *************** Sample ***************
# Line 530  namespace DLS { Line 622  namespace DLS {
622              AverageBytesPerSecond  = pCkFormat->ReadUint32();              AverageBytesPerSecond  = pCkFormat->ReadUint32();
623              BlockAlign             = pCkFormat->ReadUint16();              BlockAlign             = pCkFormat->ReadUint16();
624              // PCM format specific              // PCM format specific
625              if (FormatTag == WAVE_FORMAT_PCM) {              if (FormatTag == DLS_WAVE_FORMAT_PCM) {
626                  BitDepth     = pCkFormat->ReadUint16();                  BitDepth     = pCkFormat->ReadUint16();
627                  FrameSize    = (FormatTag == WAVE_FORMAT_PCM) ? (BitDepth / 8) * Channels                  FrameSize    = (BitDepth / 8) * Channels;
                                                             : 0;  
628              } else { // unsupported sample data format              } else { // unsupported sample data format
629                  BitDepth     = 0;                  BitDepth     = 0;
630                  FrameSize    = 0;                  FrameSize    = 0;
631              }              }
632          } else { // 'fmt' chunk missing          } else { // 'fmt' chunk missing
633              FormatTag              = WAVE_FORMAT_PCM;              FormatTag              = DLS_WAVE_FORMAT_PCM;
634              BitDepth               = 16;              BitDepth               = 16;
635              Channels               = 1;              Channels               = 1;
636              SamplesPerSecond       = 44100;              SamplesPerSecond       = 44100;
# Line 547  namespace DLS { Line 638  namespace DLS {
638              FrameSize              = (BitDepth / 8) * Channels;              FrameSize              = (BitDepth / 8) * Channels;
639              BlockAlign             = FrameSize;              BlockAlign             = FrameSize;
640          }          }
641          SamplesTotal = (pCkData) ? (FormatTag == WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize          SamplesTotal = (pCkData) ? (FormatTag == DLS_WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize
642                                                                    : 0                                                                        : 0
643                                   : 0;                                   : 0;
644      }      }
645    
# Line 608  namespace DLS { Line 699  namespace DLS {
699       * the RIFF chunk which encapsulates the sample's wave data. The       * the RIFF chunk which encapsulates the sample's wave data. The
700       * returned value is dependant to the current FrameSize value.       * returned value is dependant to the current FrameSize value.
701       *       *
702       * @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
703       * @see FrameSize, FormatTag       * @see FrameSize, FormatTag
704       */       */
705      unsigned long Sample::GetSize() {      unsigned long Sample::GetSize() {
706          if (FormatTag != WAVE_FORMAT_PCM) return 0;          if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0;
707          return (pCkData) ? pCkData->GetSize() / FrameSize : 0;          return (pCkData) ? pCkData->GetSize() / FrameSize : 0;
708      }      }
709    
# Line 634  namespace DLS { Line 725  namespace DLS {
725       * calling File::Save() as this might exceed the current sample's       * calling File::Save() as this might exceed the current sample's
726       * boundary!       * boundary!
727       *       *
728       * Also note: only WAVE_FORMAT_PCM is currently supported, that is       * Also note: only DLS_WAVE_FORMAT_PCM is currently supported, that is
729       * FormatTag must be WAVE_FORMAT_PCM. Trying to resize samples with       * FormatTag must be DLS_WAVE_FORMAT_PCM. Trying to resize samples with
730       * other formats will fail!       * other formats will fail!
731       *       *
732       * @param iNewSize - new sample wave data size in sample points (must be       * @param iNewSize - new sample wave data size in sample points (must be
733       *                   greater than zero)       *                   greater than zero)
734       * @throws Excecption if FormatTag != WAVE_FORMAT_PCM       * @throws Excecption if FormatTag != DLS_WAVE_FORMAT_PCM
735       * @throws Exception if \a iNewSize is less than 1       * @throws Exception if \a iNewSize is less than 1
736       * @see File::Save(), FrameSize, FormatTag       * @see File::Save(), FrameSize, FormatTag
737       */       */
738      void Sample::Resize(int iNewSize) {      void Sample::Resize(int iNewSize) {
739          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");
740          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");
741          const int iSizeInBytes = iNewSize * FrameSize;          const int iSizeInBytes = iNewSize * FrameSize;
742          pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA);          pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA);
# Line 658  namespace DLS { Line 749  namespace DLS {
749       * 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
750       * the sample into RAM, thus for disk streaming.       * the sample into RAM, thus for disk streaming.
751       *       *
752       * Also note: only WAVE_FORMAT_PCM is currently supported, that is       * Also note: only DLS_WAVE_FORMAT_PCM is currently supported, that is
753       * FormatTag must be WAVE_FORMAT_PCM. Trying to reposition the sample       * FormatTag must be DLS_WAVE_FORMAT_PCM. Trying to reposition the sample
754       * with other formats will fail!       * with other formats will fail!
755       *       *
756       * @param SampleCount  number of sample points       * @param SampleCount  number of sample points
757       * @param Whence       to which relation \a SampleCount refers to       * @param Whence       to which relation \a SampleCount refers to
758       * @returns new position within the sample, 0 if       * @returns new position within the sample, 0 if
759       *          FormatTag != WAVE_FORMAT_PCM       *          FormatTag != DLS_WAVE_FORMAT_PCM
760       * @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
761       * @see FrameSize, FormatTag       * @see FrameSize, FormatTag
762       */       */
763      unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {      unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {
764          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
765          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");
766          unsigned long orderedBytes = SampleCount * FrameSize;          unsigned long orderedBytes = SampleCount * FrameSize;
767          unsigned long result = pCkData->SetPos(orderedBytes, Whence);          unsigned long result = pCkData->SetPos(orderedBytes, Whence);
# Line 688  namespace DLS { Line 779  namespace DLS {
779       * @param SampleCount  number of sample points to read       * @param SampleCount  number of sample points to read
780       */       */
781      unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {      unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {
782          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
783          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?
784      }      }
785    
# Line 708  namespace DLS { Line 799  namespace DLS {
799       * @see LoadSampleData()       * @see LoadSampleData()
800       */       */
801      unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) {      unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) {
802          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
803          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");
804          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?
805      }      }
# Line 717  namespace DLS { Line 808  namespace DLS {
808       * Apply sample and its settings to the respective RIFF chunks. You have       * Apply sample and its settings to the respective RIFF chunks. You have
809       * to call File::Save() to make changes persistent.       * to call File::Save() to make changes persistent.
810       *       *
811       * @throws Exception if FormatTag != WAVE_FORMAT_PCM or no sample data       * @throws Exception if FormatTag != DLS_WAVE_FORMAT_PCM or no sample data
812       *                   was provided yet       *                   was provided yet
813       */       */
814      void Sample::UpdateChunks() {      void Sample::UpdateChunks() {
815          if (FormatTag != WAVE_FORMAT_PCM)          if (FormatTag != DLS_WAVE_FORMAT_PCM)
816              throw Exception("Could not save sample, only PCM format is supported");              throw Exception("Could not save sample, only PCM format is supported");
817          // 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
818          if (!pCkData)          if (!pCkData)
# Line 733  namespace DLS { Line 824  namespace DLS {
824          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format
825          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();
826          // update 'fmt' chunk          // update 'fmt' chunk
827          memcpy(&pData[0], &FormatTag, 2);          store16(&pData[0], FormatTag);
828          memcpy(&pData[2], &Channels,  2);          store16(&pData[2], Channels);
829          memcpy(&pData[4], &SamplesPerSecond, 4);          store32(&pData[4], SamplesPerSecond);
830          memcpy(&pData[8], &AverageBytesPerSecond, 4);          store32(&pData[8], AverageBytesPerSecond);
831          memcpy(&pData[12], &BlockAlign, 2);          store16(&pData[12], BlockAlign);
832          memcpy(&pData[14], &BitDepth, 2); // assuming PCM format          store16(&pData[14], BitDepth); // assuming PCM format
833      }      }
834    
835    
# Line 836  namespace DLS { Line 927  namespace DLS {
927                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE
928                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);
929          // update 'rgnh' chunk          // update 'rgnh' chunk
930          memcpy(&pData[0], &KeyRange, 2 * 2);          store16(&pData[0], KeyRange.low);
931          memcpy(&pData[4], &VelocityRange, 2 * 2);          store16(&pData[2], KeyRange.high);
932          memcpy(&pData[8], &FormatOptionFlags, 2);          store16(&pData[4], VelocityRange.low);
933          memcpy(&pData[10], &KeyGroup, 2);          store16(&pData[6], VelocityRange.high);
934          if (rgnh->GetSize() >= 14) memcpy(&pData[12], &Layer, 2);          store16(&pData[8], FormatOptionFlags);
935            store16(&pData[10], KeyGroup);
936            if (rgnh->GetSize() >= 14) store16(&pData[12], Layer);
937    
938          // update chunks of base classes as well (but skip Resource,          // update chunks of base classes as well (but skip Resource,
939          // as a rgn doesn't seem to have dlid and INFO chunks)          // as a rgn doesn't seem to have dlid and INFO chunks)
# Line 870  namespace DLS { Line 963  namespace DLS {
963                  }                  }
964              }              }
965          }          }
         if (index < 0) throw Exception("Could not save Region, could not find Region's sample");  
966          WavePoolTableIndex = index;          WavePoolTableIndex = index;
967          // update 'wlnk' chunk          // update 'wlnk' chunk
968          memcpy(&pData[0], &WaveLinkOptionFlags, 2);          store16(&pData[0], WaveLinkOptionFlags);
969          memcpy(&pData[2], &PhaseGroup, 2);          store16(&pData[2], PhaseGroup);
970          memcpy(&pData[4], &Channel, 4);          store32(&pData[4], Channel);
971          memcpy(&pData[8], &WavePoolTableIndex, 4);          store32(&pData[8], WavePoolTableIndex);
972      }      }
973    
974    
# Line 959  namespace DLS { Line 1051  namespace DLS {
1051          return pNewRegion;          return pNewRegion;
1052      }      }
1053    
1054        void Instrument::MoveRegion(Region* pSrc, Region* pDst) {
1055            RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
1056            lrgn->MoveSubChunk(pSrc->pCkRegion, pDst ? pDst->pCkRegion : 0);
1057    
1058            pRegions->remove(pSrc);
1059            RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pDst);
1060            pRegions->insert(iter, pSrc);
1061        }
1062    
1063      void Instrument::DeleteRegion(Region* pRegion) {      void Instrument::DeleteRegion(Region* pRegion) {
1064          if (!pRegions) return;          if (!pRegions) return;
1065          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);
# Line 989  namespace DLS { Line 1090  namespace DLS {
1090          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);
1091          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);
1092          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
1093          memcpy(&pData[0], &Regions, 4);          store32(&pData[0], Regions);
1094          memcpy(&pData[4], &locale, 2 * 4);          store32(&pData[4], locale.bank);
1095            store32(&pData[8], locale.instrument);
1096          // update Region's chunks          // update Region's chunks
1097          if (!pRegions) return;          if (!pRegions) return;
1098          RegionList::iterator iter = pRegions->begin();          RegionList::iterator iter = pRegions->begin();
# Line 1032  namespace DLS { Line 1134  namespace DLS {
1134       * a DLS file.       * a DLS file.
1135       */       */
1136      File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) {      File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) {
1137            pRIFF->SetByteOrder(RIFF::endian_little);
1138          pVersion = new version_t;          pVersion = new version_t;
1139          pVersion->major   = 0;          pVersion->major   = 0;
1140          pVersion->minor   = 0;          pVersion->minor   = 0;
# Line 1286  namespace DLS { Line 1389  namespace DLS {
1389              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);
1390              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);
1391              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();
1392              memcpy(pData, pVersion, 2 * 4);              store16(&pData[0], pVersion->minor);
1393                store16(&pData[2], pVersion->major);
1394                store16(&pData[4], pVersion->build);
1395                store16(&pData[6], pVersion->release);
1396          }          }
1397    
1398          // update 'colh' chunk          // update 'colh' chunk
# Line 1294  namespace DLS { Line 1400  namespace DLS {
1400          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);
1401          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);
1402          uint8_t* pData = (uint8_t*) colh->LoadChunkData();          uint8_t* pData = (uint8_t*) colh->LoadChunkData();
1403          memcpy(pData, &Instruments, 4);          store32(pData, Instruments);
1404    
1405          // update instrument's chunks          // update instrument's chunks
1406          if (pInstruments) {          if (pInstruments) {
# Line 1314  namespace DLS { Line 1420  namespace DLS {
1420          ptbl->Resize(iPtblSize);          ptbl->Resize(iPtblSize);
1421          pData = (uint8_t*) ptbl->LoadChunkData();          pData = (uint8_t*) ptbl->LoadChunkData();
1422          WavePoolCount = iSamples;          WavePoolCount = iSamples;
1423          memcpy(&pData[4], &WavePoolCount, 4);          store32(&pData[4], WavePoolCount);
1424          // 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()
1425          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);
1426    
# Line 1403  namespace DLS { Line 1509  namespace DLS {
1509          unsigned long ulOriginalPos = ptbl->GetPos();          unsigned long ulOriginalPos = ptbl->GetPos();
1510          // update headers          // update headers
1511          ptbl->SetPos(0);          ptbl->SetPos(0);
1512          ptbl->WriteUint32(&WavePoolHeaderSize);          uint32_t tmp = WavePoolHeaderSize;
1513          ptbl->WriteUint32(&WavePoolCount);          ptbl->WriteUint32(&tmp);
1514            tmp = WavePoolCount;
1515            ptbl->WriteUint32(&tmp);
1516          // update offsets          // update offsets
1517          ptbl->SetPos(WavePoolHeaderSize);          ptbl->SetPos(WavePoolHeaderSize);
1518          if (b64BitWavePoolOffsets) {          if (b64BitWavePoolOffsets) {
1519              for (int i = 0 ; i < WavePoolCount ; i++) {              for (int i = 0 ; i < WavePoolCount ; i++) {
1520                  ptbl->WriteUint32(&pWavePoolTableHi[i]);                  tmp = pWavePoolTableHi[i];
1521                  ptbl->WriteUint32(&pWavePoolTable[i]);                  ptbl->WriteUint32(&tmp);
1522                    tmp = pWavePoolTable[i];
1523                    ptbl->WriteUint32(&tmp);
1524              }              }
1525          } else { // conventional 32 bit offsets          } else { // conventional 32 bit offsets
1526              for (int i = 0 ; i < WavePoolCount ; i++)              for (int i = 0 ; i < WavePoolCount ; i++) {
1527                  ptbl->WriteUint32(&pWavePoolTable[i]);                  tmp = pWavePoolTable[i];
1528                    ptbl->WriteUint32(&tmp);
1529                }
1530          }          }
1531          // restore 'ptbl' chunk's original read/write position          // restore 'ptbl' chunk's original read/write position
1532          ptbl->SetPos(ulOriginalPos);          ptbl->SetPos(ulOriginalPos);

Legend:
Removed from v.919  
changed lines
  Added in v.1266

  ViewVC Help
Powered by ViewVC