/[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 839 by persson, Fri Feb 10 19:23:59 2006 UTC revision 1179 by persson, Sat May 12 11:25:04 2007 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   libgig - C++ cross-platform Gigasampler format file loader library    *   *   libgig - C++ cross-platform Gigasampler format file access library    *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003-2005 by Christian Schoenebeck                      *   *   Copyright (C) 2003-2007 by Christian Schoenebeck                      *
6   *                              <cuse@users.sourceforge.net>               *   *                              <cuse@users.sourceforge.net>               *
7   *                                                                         *   *                                                                         *
8   *   This library is free software; you can redistribute it and/or modify  *   *   This library is free software; you can redistribute it and/or modify  *
# Line 45  Line 45 
45  #define CONN_TRANSFORM_INVERT_SRC_ENCODE(x)             ((x) ? 0x8000 : 0)  #define CONN_TRANSFORM_INVERT_SRC_ENCODE(x)             ((x) ? 0x8000 : 0)
46  #define CONN_TRANSFORM_INVERT_CTL_ENCODE(x)             ((x) ? 0x0200 : 0)  #define CONN_TRANSFORM_INVERT_CTL_ENCODE(x)             ((x) ? 0x0200 : 0)
47    
48  #define DRUM_TYPE_MASK                  0x00000001  #define DRUM_TYPE_MASK                  0x80000000
49    
50  #define F_RGN_OPTION_SELFNONEXCLUSIVE   0x0001  #define F_RGN_OPTION_SELFNONEXCLUSIVE   0x0001
51    
# Line 142  namespace DLS { Line 142  namespace DLS {
142          const int iEntrySize = 12; // 12 bytes per connection block          const int iEntrySize = 12; // 12 bytes per connection block
143          pArticulationCk->Resize(HeaderSize + Connections * iEntrySize);          pArticulationCk->Resize(HeaderSize + Connections * iEntrySize);
144          uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData();          uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData();
145          memccpy(&pData[0], &HeaderSize, 1, 2);          store16(&pData[0], HeaderSize);
146          memccpy(&pData[2], &Connections, 1, 2);          store16(&pData[2], Connections);
147          for (uint32_t i = 0; i < Connections; i++) {          for (uint32_t i = 0; i < Connections; i++) {
148              Connection::conn_block_t c = pConnections[i].ToConnBlock();              Connection::conn_block_t c = pConnections[i].ToConnBlock();
149              memccpy(&pData[HeaderSize + i * iEntrySize],     &c.source, 1, 2);              store16(&pData[HeaderSize + i * iEntrySize],     c.source);
150              memccpy(&pData[HeaderSize + i * iEntrySize + 2], &c.control, 1, 2);              store16(&pData[HeaderSize + i * iEntrySize + 2], c.control);
151              memccpy(&pData[HeaderSize + i * iEntrySize + 4], &c.destination, 1, 2);              store16(&pData[HeaderSize + i * iEntrySize + 4], c.destination);
152              memccpy(&pData[HeaderSize + i * iEntrySize + 6], &c.transform, 1, 2);              store16(&pData[HeaderSize + i * iEntrySize + 6], c.transform);
153              memccpy(&pData[HeaderSize + i * iEntrySize + 8], &c.scale, 1, 4);              store32(&pData[HeaderSize + i * iEntrySize + 8], c.scale);
154          }          }
155      }      }
156    
# Line 228  namespace DLS { Line 228  namespace DLS {
228    
229      /** @brief Constructor.      /** @brief Constructor.
230       *       *
231       * Initializes the info strings with values provided by a INFO list chunk.       * Initializes the info strings with values provided by an INFO list chunk.
232       *       *
233       * @param list - pointer to a list chunk which contains a INFO list chunk       * @param list - pointer to a list chunk which contains an INFO list chunk
234       */       */
235      Info::Info(RIFF::List* list) {      Info::Info(RIFF::List* list) {
236            UseFixedLengthStrings = false;
237          pResourceListChunk = list;          pResourceListChunk = list;
238          if (list) {          if (list) {
239              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);              RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);
# Line 253  namespace DLS { Line 254  namespace DLS {
254                  LoadString(CHUNK_ID_ISRC, lstINFO, Source);                  LoadString(CHUNK_ID_ISRC, lstINFO, Source);
255                  LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);                  LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);
256                  LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);                  LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);
257                    LoadString(CHUNK_ID_ISBJ, lstINFO, Subject);
258              }              }
259          }          }
260      }      }
# Line 267  namespace DLS { Line 269  namespace DLS {
269       */       */
270      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {
271          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
272          if (ck) {          ::LoadString(ck, s); // function from helper.h
             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();  
         }  
273      }      }
274    
275      /** @brief Apply given INFO field to the respective chunk.      /** @brief Apply given INFO field to the respective chunk.
# Line 292  namespace DLS { Line 286  namespace DLS {
286       * @param lstINFO  - parent (INFO) RIFF list chunk       * @param lstINFO  - parent (INFO) RIFF list chunk
287       * @param s        - current value of info field       * @param s        - current value of info field
288       * @param sDefault - default value       * @param sDefault - default value
289         * @param bUseFixedLengthStrings - should a specific string size be forced in the chunk?
290         * @param size     - wanted size of the INFO chunk. This is ignored if bUseFixedLengthStrings is false.
291       */       */
292      void Info::SaveString(uint32_t ChunkID, RIFF::List* lstINFO, const String& s, const String& sDefault) {      void Info::SaveString(uint32_t ChunkID, RIFF::List* lstINFO, const String& s, const String& sDefault, bool bUseFixedLengthStrings, int size) {
293          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
294          if (ck) { // if chunk exists already, use 's' as value          ::SaveString(ChunkID, ck, lstINFO, s, sDefault, bUseFixedLengthStrings, size); // function from helper.h
             ck->Resize(s.size() + 1);  
             char* pData = (char*) ck->LoadChunkData();  
             memcpy(pData, s.c_str(), s.size() + 1);  
         } else if (s != "" || sDefault != "") { // create chunk  
             const String& sToSave = (s != "") ? s : sDefault;  
             ck = lstINFO->AddSubChunk(ChunkID, sToSave.size() + 1);  
             char* pData = (char*) ck->LoadChunkData();  
             memcpy(pData, sToSave.c_str(), sToSave.size() + 1);  
         }  
295      }      }
296    
297      /** @brief Update chunks with current info values.      /** @brief Update chunks with current info values.
# Line 317  namespace DLS { Line 304  namespace DLS {
304    
305          // make sure INFO list chunk exists          // make sure INFO list chunk exists
306          RIFF::List* lstINFO   = pResourceListChunk->GetSubList(LIST_TYPE_INFO);          RIFF::List* lstINFO   = pResourceListChunk->GetSubList(LIST_TYPE_INFO);
         if (!lstINFO) lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO);  
307    
308          // assemble default values in case the respective chunk is missing yet          String defaultName = "";
309          String defaultName = "NONAME";          String defaultCreationDate = "";
310          // get current date          String defaultSoftware = "";
311          time_t now = time(NULL);          String defaultComments = "";
312          tm* pNowBroken = localtime(&now);  
313          String defaultCreationDate = ToString(1900 + pNowBroken->tm_year) + "-" +          uint32_t resourceType = pResourceListChunk->GetListType();
314                                       ToString(pNowBroken->tm_mon + 1)  + "-" +  
315                                       ToString(pNowBroken->tm_mday);          if (!lstINFO) {
316          String defaultSoftware = libraryName() + " " + libraryVersion();              lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO);
317          String defaultComments = "Created with " + libraryName() + " " + libraryVersion();  
318                // assemble default values
319                defaultName = "NONAME";
320    
321                if (resourceType == RIFF_TYPE_DLS) {
322                    // get current date
323                    time_t now = time(NULL);
324                    tm* pNowBroken = localtime(&now);
325                    char buf[11];
326                    strftime(buf, 11, "%F", pNowBroken);
327                    defaultCreationDate = buf;
328    
329                    defaultComments = "Created with " + libraryName() + " " + libraryVersion();
330                }
331                if (resourceType == RIFF_TYPE_DLS || resourceType == LIST_TYPE_INS)
332                {
333                    defaultSoftware = libraryName() + " " + libraryVersion();
334                }
335            }
336    
337          // save values          // save values
338          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName);  
339          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""));          // (the string size values are for gig files; they are only
340          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate);          // used if UseFixedLengthStrings is set to true)
341          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments);          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName, UseFixedLengthStrings,
342          SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""));                     resourceType == RIFF_TYPE_DLS ? 128 : 64);
343          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""));          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""), UseFixedLengthStrings, 256);
344          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""));          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate, UseFixedLengthStrings, 128);
345          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""));          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments, UseFixedLengthStrings, 1024);
346          SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String(""));          SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""), UseFixedLengthStrings, 128);
347          SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""));          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""), UseFixedLengthStrings, 128);
348          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""));          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""), UseFixedLengthStrings, 128);
349          SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware);          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""), UseFixedLengthStrings, 128);
350          SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""));          SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String(""), UseFixedLengthStrings, 128);
351          SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""));          SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""), UseFixedLengthStrings, 128);
352          SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""));          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""), UseFixedLengthStrings, 128);
353          SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""));          SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware, UseFixedLengthStrings,
354                       resourceType == LIST_TYPE_INS ?
355                       (Software == "" ? defaultSoftware.length()+1 : Software.length()+1) : 128);
356            SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""), UseFixedLengthStrings, 128);
357            SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""), UseFixedLengthStrings, 128);
358            SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""), UseFixedLengthStrings, 128);
359            SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""), UseFixedLengthStrings, 128);
360            SaveString(CHUNK_ID_ISBJ, lstINFO, Subject, String(""), UseFixedLengthStrings, 128);
361      }      }
362    
363    
# Line 452  namespace DLS { Line 463  namespace DLS {
463          }          }
464          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();
465          // update headers size          // update headers size
466          memccpy(&pData[0], &uiHeaderSize, 1, 4);          store32(&pData[0], uiHeaderSize);
467          // update respective sampler options bits          // update respective sampler options bits
468          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION
469                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);
470          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION
471                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);
472            store16(&pData[4], UnityNote);
473            store16(&pData[6], FineTune);
474            store32(&pData[8], Gain);
475            store32(&pData[12], SamplerOptions);
476            store32(&pData[16], SampleLoops);
477          // update loop definitions          // update loop definitions
478          for (uint32_t i = 0; i < SampleLoops; i++) {          for (uint32_t i = 0; i < SampleLoops; i++) {
479              //FIXME: this does not handle extended loop structs correctly              //FIXME: this does not handle extended loop structs correctly
480              memccpy(&pData[uiHeaderSize + i * 16], pSampleLoops + i, 4, 4);              store32(&pData[uiHeaderSize + i * 16], pSampleLoops[i].Size);
481                store32(&pData[uiHeaderSize + i * 16 + 4], pSampleLoops[i].LoopType);
482                store32(&pData[uiHeaderSize + i * 16 + 8], pSampleLoops[i].LoopStart);
483                store32(&pData[uiHeaderSize + i * 16 + 12], pSampleLoops[i].LoopLength);
484          }          }
485      }      }
486    
487        /**
488         * Adds a new sample loop with the provided loop definition.
489         *
490         * @param - points to a loop definition that is to be copied
491         */
492        void Sampler::AddSampleLoop(sample_loop_t* pLoopDef) {
493            sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops + 1];
494            // copy old loops array
495            for (int i = 0; i < SampleLoops; i++) {
496                pNewLoops[i] = pSampleLoops[i];
497            }
498            // add the new loop
499            pNewLoops[SampleLoops] = *pLoopDef;
500            // auto correct size field
501            pNewLoops[SampleLoops].Size = sizeof(DLS::sample_loop_t);
502            // free the old array and update the member variables
503            if (SampleLoops) delete[] pSampleLoops;
504            pSampleLoops = pNewLoops;
505            SampleLoops++;
506        }
507    
508        /**
509         * Deletes an existing sample loop.
510         *
511         * @param pLoopDef - pointer to existing loop definition
512         * @throws Exception - if given loop definition does not exist
513         */
514        void Sampler::DeleteSampleLoop(sample_loop_t* pLoopDef) {
515            sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops - 1];
516            // copy old loops array (skipping given loop)
517            for (int i = 0, o = 0; i < SampleLoops; i++) {
518                if (&pSampleLoops[i] == pLoopDef) continue;
519                if (o == SampleLoops - 1)
520                    throw Exception("Could not delete Sample Loop, because it does not exist");
521                pNewLoops[o] = pSampleLoops[i];
522                o++;
523            }
524            // free the old array and update the member variables
525            if (SampleLoops) delete[] pSampleLoops;
526            pSampleLoops = pNewLoops;
527            SampleLoops--;
528        }
529    
530    
531    
532  // *************** Sample ***************  // *************** Sample ***************
# Line 498  namespace DLS { Line 560  namespace DLS {
560              AverageBytesPerSecond  = pCkFormat->ReadUint32();              AverageBytesPerSecond  = pCkFormat->ReadUint32();
561              BlockAlign             = pCkFormat->ReadUint16();              BlockAlign             = pCkFormat->ReadUint16();
562              // PCM format specific              // PCM format specific
563              if (FormatTag == WAVE_FORMAT_PCM) {              if (FormatTag == DLS_WAVE_FORMAT_PCM) {
564                  BitDepth     = pCkFormat->ReadUint16();                  BitDepth     = pCkFormat->ReadUint16();
565                  FrameSize    = (FormatTag == WAVE_FORMAT_PCM) ? (BitDepth / 8) * Channels                  FrameSize    = (BitDepth / 8) * Channels;
                                                             : 0;  
566              } else { // unsupported sample data format              } else { // unsupported sample data format
567                  BitDepth     = 0;                  BitDepth     = 0;
568                  FrameSize    = 0;                  FrameSize    = 0;
569              }              }
570          } else { // 'fmt' chunk missing          } else { // 'fmt' chunk missing
571              FormatTag              = WAVE_FORMAT_PCM;              FormatTag              = DLS_WAVE_FORMAT_PCM;
572              BitDepth               = 16;              BitDepth               = 16;
573              Channels               = 1;              Channels               = 1;
574              SamplesPerSecond       = 44100;              SamplesPerSecond       = 44100;
# Line 515  namespace DLS { Line 576  namespace DLS {
576              FrameSize              = (BitDepth / 8) * Channels;              FrameSize              = (BitDepth / 8) * Channels;
577              BlockAlign             = FrameSize;              BlockAlign             = FrameSize;
578          }          }
579          SamplesTotal = (pCkData) ? (FormatTag == WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize          SamplesTotal = (pCkData) ? (FormatTag == DLS_WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize
580                                                                    : 0                                                                        : 0
581                                   : 0;                                   : 0;
582      }      }
583    
# Line 576  namespace DLS { Line 637  namespace DLS {
637       * the RIFF chunk which encapsulates the sample's wave data. The       * the RIFF chunk which encapsulates the sample's wave data. The
638       * returned value is dependant to the current FrameSize value.       * returned value is dependant to the current FrameSize value.
639       *       *
640       * @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
641       * @see FrameSize, FormatTag       * @see FrameSize, FormatTag
642       */       */
643      unsigned long Sample::GetSize() {      unsigned long Sample::GetSize() {
644          if (FormatTag != WAVE_FORMAT_PCM) return 0;          if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0;
645          return (pCkData) ? pCkData->GetSize() / FrameSize : 0;          return (pCkData) ? pCkData->GetSize() / FrameSize : 0;
646      }      }
647    
# Line 602  namespace DLS { Line 663  namespace DLS {
663       * calling File::Save() as this might exceed the current sample's       * calling File::Save() as this might exceed the current sample's
664       * boundary!       * boundary!
665       *       *
666       * Also note: only WAVE_FORMAT_PCM is currently supported, that is       * Also note: only DLS_WAVE_FORMAT_PCM is currently supported, that is
667       * FormatTag must be WAVE_FORMAT_PCM. Trying to resize samples with       * FormatTag must be DLS_WAVE_FORMAT_PCM. Trying to resize samples with
668       * other formats will fail!       * other formats will fail!
669       *       *
670       * @param iNewSize - new sample wave data size in sample points (must be       * @param iNewSize - new sample wave data size in sample points (must be
671       *                   greater than zero)       *                   greater than zero)
672       * @throws Excecption if FormatTag != WAVE_FORMAT_PCM       * @throws Excecption if FormatTag != DLS_WAVE_FORMAT_PCM
673       * @throws Exception if \a iNewSize is less than 1       * @throws Exception if \a iNewSize is less than 1
674       * @see File::Save(), FrameSize, FormatTag       * @see File::Save(), FrameSize, FormatTag
675       */       */
676      void Sample::Resize(int iNewSize) {      void Sample::Resize(int iNewSize) {
677          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");
678          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");
679          const int iSizeInBytes = iNewSize * FrameSize;          const int iSizeInBytes = iNewSize * FrameSize;
680          pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA);          pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA);
# Line 626  namespace DLS { Line 687  namespace DLS {
687       * 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
688       * the sample into RAM, thus for disk streaming.       * the sample into RAM, thus for disk streaming.
689       *       *
690       * Also note: only WAVE_FORMAT_PCM is currently supported, that is       * Also note: only DLS_WAVE_FORMAT_PCM is currently supported, that is
691       * FormatTag must be WAVE_FORMAT_PCM. Trying to reposition the sample       * FormatTag must be DLS_WAVE_FORMAT_PCM. Trying to reposition the sample
692       * with other formats will fail!       * with other formats will fail!
693       *       *
694       * @param SampleCount  number of sample points       * @param SampleCount  number of sample points
695       * @param Whence       to which relation \a SampleCount refers to       * @param Whence       to which relation \a SampleCount refers to
696       * @returns new position within the sample, 0 if       * @returns new position within the sample, 0 if
697       *          FormatTag != WAVE_FORMAT_PCM       *          FormatTag != DLS_WAVE_FORMAT_PCM
698       * @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
699       * @see FrameSize, FormatTag       * @see FrameSize, FormatTag
700       */       */
701      unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {      unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {
702          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
703          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");
704          unsigned long orderedBytes = SampleCount * FrameSize;          unsigned long orderedBytes = SampleCount * FrameSize;
705          unsigned long result = pCkData->SetPos(orderedBytes, Whence);          unsigned long result = pCkData->SetPos(orderedBytes, Whence);
# Line 656  namespace DLS { Line 717  namespace DLS {
717       * @param SampleCount  number of sample points to read       * @param SampleCount  number of sample points to read
718       */       */
719      unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {      unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {
720          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
721          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?
722      }      }
723    
# Line 676  namespace DLS { Line 737  namespace DLS {
737       * @see LoadSampleData()       * @see LoadSampleData()
738       */       */
739      unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) {      unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) {
740          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
741          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");
742          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?
743      }      }
# Line 685  namespace DLS { Line 746  namespace DLS {
746       * Apply sample and its settings to the respective RIFF chunks. You have       * Apply sample and its settings to the respective RIFF chunks. You have
747       * to call File::Save() to make changes persistent.       * to call File::Save() to make changes persistent.
748       *       *
749       * @throws Exception if FormatTag != WAVE_FORMAT_PCM or no sample data       * @throws Exception if FormatTag != DLS_WAVE_FORMAT_PCM or no sample data
750       *                   was provided yet       *                   was provided yet
751       */       */
752      void Sample::UpdateChunks() {      void Sample::UpdateChunks() {
753          if (FormatTag != WAVE_FORMAT_PCM)          if (FormatTag != DLS_WAVE_FORMAT_PCM)
754              throw Exception("Could not save sample, only PCM format is supported");              throw Exception("Could not save sample, only PCM format is supported");
755          // 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
756          if (!pCkData)          if (!pCkData)
# Line 701  namespace DLS { Line 762  namespace DLS {
762          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format
763          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();
764          // update 'fmt' chunk          // update 'fmt' chunk
765          memccpy(&pData[0], &FormatTag, 1, 2);          store16(&pData[0], FormatTag);
766          memccpy(&pData[2], &Channels,  1, 2);          store16(&pData[2], Channels);
767          memccpy(&pData[4], &SamplesPerSecond, 1, 4);          store32(&pData[4], SamplesPerSecond);
768          memccpy(&pData[8], &AverageBytesPerSecond, 1, 4);          store32(&pData[8], AverageBytesPerSecond);
769          memccpy(&pData[12], &BlockAlign, 1, 2);          store16(&pData[12], BlockAlign);
770          memccpy(&pData[14], &BitDepth, 1, 2); // assuming PCM format          store16(&pData[14], BitDepth); // assuming PCM format
771      }      }
772    
773    
# Line 798  namespace DLS { Line 859  namespace DLS {
859      void Region::UpdateChunks() {      void Region::UpdateChunks() {
860          // make sure 'rgnh' chunk exists          // make sure 'rgnh' chunk exists
861          RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH);          RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH);
862          if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, 14);          if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, Layer ? 14 : 12);
863          uint8_t* pData = (uint8_t*) rgnh->LoadChunkData();          uint8_t* pData = (uint8_t*) rgnh->LoadChunkData();
864          FormatOptionFlags = (SelfNonExclusive)          FormatOptionFlags = (SelfNonExclusive)
865                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE
866                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);
867          // update 'rgnh' chunk          // update 'rgnh' chunk
868          memccpy(&pData[0], &KeyRange, 2, 2);          store16(&pData[0], KeyRange.low);
869          memccpy(&pData[4], &VelocityRange, 2, 2);          store16(&pData[2], KeyRange.high);
870          memccpy(&pData[8], &FormatOptionFlags, 1, 2);          store16(&pData[4], VelocityRange.low);
871          memccpy(&pData[10], &KeyGroup, 1, 2);          store16(&pData[6], VelocityRange.high);
872          memccpy(&pData[12], &Layer, 1, 2);          store16(&pData[8], FormatOptionFlags);
873            store16(&pData[10], KeyGroup);
874            if (rgnh->GetSize() >= 14) store16(&pData[12], Layer);
875    
876          // update chunks of base classes as well          // update chunks of base classes as well (but skip Resource,
877          Resource::UpdateChunks();          // as a rgn doesn't seem to have dlid and INFO chunks)
878          Articulator::UpdateChunks();          Articulator::UpdateChunks();
879          Sampler::UpdateChunks();          Sampler::UpdateChunks();
880    
# Line 841  namespace DLS { Line 904  namespace DLS {
904          if (index < 0) throw Exception("Could not save Region, could not find Region's sample");          if (index < 0) throw Exception("Could not save Region, could not find Region's sample");
905          WavePoolTableIndex = index;          WavePoolTableIndex = index;
906          // update 'wlnk' chunk          // update 'wlnk' chunk
907          memccpy(&pData[0], &WaveLinkOptionFlags, 1, 2);          store16(&pData[0], WaveLinkOptionFlags);
908          memccpy(&pData[2], &PhaseGroup, 1, 2);          store16(&pData[2], PhaseGroup);
909          memccpy(&pData[4], &Channel, 1, 4);          store32(&pData[4], Channel);
910          memccpy(&pData[8], &WavePoolTableIndex, 1, 4);          store32(&pData[8], WavePoolTableIndex);
911      }      }
912    
913    
# Line 927  namespace DLS { Line 990  namespace DLS {
990          return pNewRegion;          return pNewRegion;
991      }      }
992    
993        void Instrument::MoveRegion(Region* pSrc, Region* pDst) {
994            RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
995            lrgn->MoveSubChunk(pSrc->pCkRegion, pDst ? pDst->pCkRegion : 0);
996    
997            pRegions->remove(pSrc);
998            RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pDst);
999            pRegions->insert(iter, pSrc);
1000        }
1001    
1002      void Instrument::DeleteRegion(Region* pRegion) {      void Instrument::DeleteRegion(Region* pRegion) {
1003          if (!pRegions) return;          if (!pRegions) return;
1004          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);
# Line 957  namespace DLS { Line 1029  namespace DLS {
1029          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);
1030          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);
1031          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
1032          memccpy(&pData[0], &Regions, 1, 4);          store32(&pData[0], Regions);
1033          memccpy(&pData[4], &locale, 2, 4);          store32(&pData[4], locale.bank);
1034            store32(&pData[8], locale.instrument);
1035          // update Region's chunks          // update Region's chunks
1036          if (!pRegions) return;          if (!pRegions) return;
1037          RegionList::iterator iter = pRegions->begin();          RegionList::iterator iter = pRegions->begin();
# Line 1043  namespace DLS { Line 1116  namespace DLS {
1116          Instruments = colh->ReadUint32();          Instruments = colh->ReadUint32();
1117    
1118          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);
1119          if (!ptbl) throw DLS::Exception("Mandatory <ptbl> chunk not found.");          if (!ptbl) { // pool table is missing - this is probably an ".art" file
1120          WavePoolHeaderSize = ptbl->ReadUint32();              WavePoolCount    = 0;
1121          WavePoolCount  = ptbl->ReadUint32();              pWavePoolTable   = NULL;
1122          pWavePoolTable = new uint32_t[WavePoolCount];              pWavePoolTableHi = NULL;
1123          pWavePoolTableHi = new uint32_t[WavePoolCount];              WavePoolHeaderSize = 8;
1124          ptbl->SetPos(WavePoolHeaderSize);              b64BitWavePoolOffsets = false;
1125            } else {
1126          // Check for 64 bit offsets (used in gig v3 files)              WavePoolHeaderSize = ptbl->ReadUint32();
1127          b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8);              WavePoolCount  = ptbl->ReadUint32();
1128          if (b64BitWavePoolOffsets) {              pWavePoolTable = new uint32_t[WavePoolCount];
1129              for (int i = 0 ; i < WavePoolCount ; i++) {              pWavePoolTableHi = new uint32_t[WavePoolCount];
1130                  pWavePoolTableHi[i] = ptbl->ReadUint32();              ptbl->SetPos(WavePoolHeaderSize);
1131                  pWavePoolTable[i] = ptbl->ReadUint32();  
1132                  if (pWavePoolTable[i] & 0x80000000)              // Check for 64 bit offsets (used in gig v3 files)
1133                      throw DLS::Exception("Files larger than 2 GB not yet supported");              b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8);
1134                if (b64BitWavePoolOffsets) {
1135                    for (int i = 0 ; i < WavePoolCount ; i++) {
1136                        pWavePoolTableHi[i] = ptbl->ReadUint32();
1137                        pWavePoolTable[i] = ptbl->ReadUint32();
1138                        if (pWavePoolTable[i] & 0x80000000)
1139                            throw DLS::Exception("Files larger than 2 GB not yet supported");
1140                    }
1141                } else { // conventional 32 bit offsets
1142                    ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));
1143                    for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;
1144              }              }
         } else { // conventional 32 bit offsets  
             ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));  
             for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;  
1145          }          }
1146    
1147          pSamples     = NULL;          pSamples     = NULL;
# Line 1247  namespace DLS { Line 1327  namespace DLS {
1327              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);
1328              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);
1329              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();
1330              memccpy(pData, pVersion, 2, 4);              store16(&pData[0], pVersion->minor);
1331                store16(&pData[2], pVersion->major);
1332                store16(&pData[4], pVersion->build);
1333                store16(&pData[6], pVersion->release);
1334          }          }
1335    
1336          // update 'colh' chunk          // update 'colh' chunk
# Line 1255  namespace DLS { Line 1338  namespace DLS {
1338          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);
1339          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);
1340          uint8_t* pData = (uint8_t*) colh->LoadChunkData();          uint8_t* pData = (uint8_t*) colh->LoadChunkData();
1341          memccpy(pData, &Instruments, 1, 4);          store32(pData, Instruments);
1342    
1343          // update instrument's chunks          // update instrument's chunks
1344          if (pInstruments) {          if (pInstruments) {
# Line 1275  namespace DLS { Line 1358  namespace DLS {
1358          ptbl->Resize(iPtblSize);          ptbl->Resize(iPtblSize);
1359          pData = (uint8_t*) ptbl->LoadChunkData();          pData = (uint8_t*) ptbl->LoadChunkData();
1360          WavePoolCount = iSamples;          WavePoolCount = iSamples;
1361          memccpy(&pData[4], &WavePoolCount, 1, 4);          store32(&pData[4], WavePoolCount);
1362          // 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()
1363          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);
1364    
# Line 1364  namespace DLS { Line 1447  namespace DLS {
1447          unsigned long ulOriginalPos = ptbl->GetPos();          unsigned long ulOriginalPos = ptbl->GetPos();
1448          // update headers          // update headers
1449          ptbl->SetPos(0);          ptbl->SetPos(0);
1450          ptbl->WriteUint32(&WavePoolHeaderSize);          uint32_t tmp = WavePoolHeaderSize;
1451          ptbl->WriteUint32(&WavePoolCount);          ptbl->WriteUint32(&tmp);
1452            tmp = WavePoolCount;
1453            ptbl->WriteUint32(&tmp);
1454          // update offsets          // update offsets
1455          ptbl->SetPos(WavePoolHeaderSize);          ptbl->SetPos(WavePoolHeaderSize);
1456          if (b64BitWavePoolOffsets) {          if (b64BitWavePoolOffsets) {
1457              for (int i = 0 ; i < WavePoolCount ; i++) {              for (int i = 0 ; i < WavePoolCount ; i++) {
1458                  ptbl->WriteUint32(&pWavePoolTableHi[i]);                  tmp = pWavePoolTableHi[i];
1459                  ptbl->WriteUint32(&pWavePoolTable[i]);                  ptbl->WriteUint32(&tmp);
1460                    tmp = pWavePoolTable[i];
1461                    ptbl->WriteUint32(&tmp);
1462              }              }
1463          } else { // conventional 32 bit offsets          } else { // conventional 32 bit offsets
1464              for (int i = 0 ; i < WavePoolCount ; i++)              for (int i = 0 ; i < WavePoolCount ; i++) {
1465                  ptbl->WriteUint32(&pWavePoolTable[i]);                  tmp = pWavePoolTable[i];
1466                    ptbl->WriteUint32(&tmp);
1467                }
1468          }          }
1469          // restore 'ptbl' chunk's original read/write position          // restore 'ptbl' chunk's original read/write position
1470          ptbl->SetPos(ulOriginalPos);          ptbl->SetPos(ulOriginalPos);

Legend:
Removed from v.839  
changed lines
  Added in v.1179

  ViewVC Help
Powered by ViewVC