/[svn]/libgig/trunk/src/DLS.cpp
ViewVC logotype

Diff of /libgig/trunk/src/DLS.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 800 by schoenebeck, Wed Nov 9 20:04:11 2005 UTC revision 919 by schoenebeck, Fri Sep 15 19:35:11 2006 UTC
# Line 45  Line 45 
45  #define CONN_TRANSFORM_INVERT_SRC_ENCODE(x)             ((x) ? 0x8000 : 0)  #define CONN_TRANSFORM_INVERT_SRC_ENCODE(x)             ((x) ? 0x8000 : 0)
46  #define CONN_TRANSFORM_INVERT_CTL_ENCODE(x)             ((x) ? 0x0200 : 0)  #define CONN_TRANSFORM_INVERT_CTL_ENCODE(x)             ((x) ? 0x0200 : 0)
47    
48  #define DRUM_TYPE_MASK                  0x00000001  #define DRUM_TYPE_MASK                  0x80000000
49    
50  #define F_RGN_OPTION_SELFNONEXCLUSIVE   0x0001  #define F_RGN_OPTION_SELFNONEXCLUSIVE   0x0001
51    
# Line 142  namespace DLS { Line 142  namespace DLS {
142          const int iEntrySize = 12; // 12 bytes per connection block          const int iEntrySize = 12; // 12 bytes per connection block
143          pArticulationCk->Resize(HeaderSize + Connections * iEntrySize);          pArticulationCk->Resize(HeaderSize + Connections * iEntrySize);
144          uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData();          uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData();
145          memccpy(&pData[0], &HeaderSize, 1, 2);          memcpy(&pData[0], &HeaderSize, 2);
146          memccpy(&pData[2], &Connections, 1, 2);          memcpy(&pData[2], &Connections, 2);
147          for (uint32_t i = 0; i < Connections; i++) {          for (uint32_t i = 0; i < Connections; i++) {
148              Connection::conn_block_t c = pConnections[i].ToConnBlock();              Connection::conn_block_t c = pConnections[i].ToConnBlock();
149              memccpy(&pData[HeaderSize + i * iEntrySize],     &c.source, 1, 2);              memcpy(&pData[HeaderSize + i * iEntrySize],     &c.source, 2);
150              memccpy(&pData[HeaderSize + i * iEntrySize + 2], &c.control, 1, 2);              memcpy(&pData[HeaderSize + i * iEntrySize + 2], &c.control, 2);
151              memccpy(&pData[HeaderSize + i * iEntrySize + 4], &c.destination, 1, 2);              memcpy(&pData[HeaderSize + i * iEntrySize + 4], &c.destination, 2);
152              memccpy(&pData[HeaderSize + i * iEntrySize + 6], &c.transform, 1, 2);              memcpy(&pData[HeaderSize + i * iEntrySize + 6], &c.transform, 2);
153              memccpy(&pData[HeaderSize + i * iEntrySize + 8], &c.scale, 1, 4);              memcpy(&pData[HeaderSize + i * iEntrySize + 8], &c.scale, 4);
154          }          }
155      }      }
156    
# Line 212  namespace DLS { Line 212  namespace DLS {
212       * call File::Save() to make changes persistent.       * call File::Save() to make changes persistent.
213       */       */
214      void Articulator::UpdateChunks() {      void Articulator::UpdateChunks() {
215          ArticulationList::iterator iter = pArticulations->begin();          if (pArticulations) {
216          ArticulationList::iterator end  = pArticulations->end();              ArticulationList::iterator iter = pArticulations->begin();
217          for (; iter != end; ++iter) {              ArticulationList::iterator end  = pArticulations->end();
218              (*iter)->UpdateChunks();              for (; iter != end; ++iter) {
219                    (*iter)->UpdateChunks();
220                }
221          }          }
222      }      }
223    
# Line 231  namespace DLS { Line 233  namespace DLS {
233       * @param list - pointer to a list chunk which contains a INFO list chunk       * @param list - pointer to a list chunk which contains a 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 255  namespace DLS { Line 258  namespace DLS {
258          }          }
259      }      }
260    
261        Info::~Info() {
262        }
263    
264      /** @brief Load given INFO field.      /** @brief Load given INFO field.
265       *       *
266       * 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 263  namespace DLS { Line 269  namespace DLS {
269      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {      void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {
270          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
271          if (ck) {          if (ck) {
272              // TODO: no check for ZSTR terminated strings yet              const char* str = (char*)ck->LoadChunkData();
273              s = (char*) ck->LoadChunkData();              int size = ck->GetSize();
274                int len;
275                for (len = 0 ; len < size ; len++)
276                    if (str[len] == '\0') break;
277                s.assign(str, len);
278              ck->ReleaseChunkData();              ck->ReleaseChunkData();
279          }          }
280      }      }
# Line 273  namespace DLS { Line 283  namespace DLS {
283       *       *
284       * Apply given info value to info chunk with ID \a ChunkID, which is a       * Apply given info value to info chunk with ID \a ChunkID, which is a
285       * subchunk of INFO list chunk \a lstINFO. If the given chunk already       * subchunk of INFO list chunk \a lstINFO. If the given chunk already
286       * exists, value \a s will be applied, otherwise if it doesn't exist yet       * exists, value \a s will be applied. Otherwise if it doesn't exist yet
287       * and \a sDefault is not an empty string, such a chunk will be created       * and either \a s or \a sDefault is not an empty string, such a chunk
288       * and \a sDefault will be applied.       * will be created and either \a s or \a sDefault will be applied
289         * (depending on which one is not an empty string, if both are not an
290         * empty string \a s will be preferred).
291       *       *
292       * @param ChunkID  - 32 bit RIFF chunk ID of INFO subchunk       * @param ChunkID  - 32 bit RIFF chunk ID of INFO subchunk
293       * @param lstINFO  - parent (INFO) RIFF list chunk       * @param lstINFO  - parent (INFO) RIFF list chunk
294       * @param s        - current value of info field       * @param s        - current value of info field
295       * @param sDefault - default value       * @param sDefault - default value
296         * @param size     - wanted size of the INFO chunk. This is ignored if UseFixedLengthStrings is false.
297       */       */
298      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, int size) {
299          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);          RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
300          if (ck) { // if chunk exists already, use 's' as value          if (ck) { // if chunk exists already, use 's' as value
301              ck->Resize(s.size() + 1);              if (!UseFixedLengthStrings) size = s.size() + 1;
302                ck->Resize(size);
303              char* pData = (char*) ck->LoadChunkData();              char* pData = (char*) ck->LoadChunkData();
304              memcpy(pData, s.c_str(), s.size() + 1);              strncpy(pData, s.c_str(), size);
305          } else if (sDefault != "") { // create chunk and use default value          } else if (s != "" || sDefault != "") { // create chunk
306              ck = lstINFO->AddSubChunk(ChunkID, sDefault.size() + 1);              const String& sToSave = (s != "") ? s : sDefault;
307                if (!UseFixedLengthStrings) size = sToSave.size() + 1;
308                ck = lstINFO->AddSubChunk(ChunkID, size);
309              char* pData = (char*) ck->LoadChunkData();              char* pData = (char*) ck->LoadChunkData();
310              memcpy(pData, sDefault.c_str(), sDefault.size() + 1);              strncpy(pData, sToSave.c_str(), size);
311          }          }
312      }      }
313    
# Line 305  namespace DLS { Line 321  namespace DLS {
321    
322          // make sure INFO list chunk exists          // make sure INFO list chunk exists
323          RIFF::List* lstINFO   = pResourceListChunk->GetSubList(LIST_TYPE_INFO);          RIFF::List* lstINFO   = pResourceListChunk->GetSubList(LIST_TYPE_INFO);
         if (!lstINFO) lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO);  
324    
325          // assemble default values in case the respective chunk is missing yet          String defaultName = "";
326          String defaultName = "NONAME";          String defaultCreationDate = "";
327          // get current date          String defaultSoftware = "";
328          time_t now = time(NULL);          String defaultComments = "";
329          tm* pNowBroken = localtime(&now);  
330          String defaultCreationDate = ToString(pNowBroken->tm_year) + "-" +          uint32_t resourceType = pResourceListChunk->GetListType();
331                                       ToString(pNowBroken->tm_mon)  + "-" +  
332                                       ToString(pNowBroken->tm_mday);          if (!lstINFO) {
333          String defaultSoftware = libraryName() + " " + libraryVersion();              lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO);
334          String defaultComments = "Created with " + libraryName() + " " + libraryVersion();  
335                // assemble default values
336                defaultName = "NONAME";
337    
338                if (resourceType == RIFF_TYPE_DLS) {
339                    // get current date
340                    time_t now = time(NULL);
341                    tm* pNowBroken = localtime(&now);
342                    char buf[11];
343                    strftime(buf, 11, "%F", pNowBroken);
344                    defaultCreationDate = buf;
345    
346                    defaultComments = "Created with " + libraryName() + " " + libraryVersion();
347                }
348                if (resourceType == RIFF_TYPE_DLS || resourceType == LIST_TYPE_INS)
349                {
350                    defaultSoftware = libraryName() + " " + libraryVersion();
351                }
352            }
353    
354          // save values          // save values
355          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName);  
356          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""));          // (the string size values are for gig files; they are only
357          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate);          // used if UseFixedLengthStrings is set to true)
358          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments);          SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName,
359          SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""));                     resourceType == RIFF_TYPE_DLS ? 128 : 64);
360          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""));          SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String(""), 256);
361          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""));          SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate, 128);
362          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""));          SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments, 1024);
363          SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String(""));          SaveString(CHUNK_ID_IPRD, lstINFO, Product, String(""), 128);
364          SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""));          SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String(""), 128);
365          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""));          SaveString(CHUNK_ID_IART, lstINFO, Artists, String(""), 128);
366          SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware);          SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String(""), 128);
367          SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""));          SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String(""), 128);
368          SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""));          SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String(""), 128);
369          SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""));          SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String(""), 128);
370          SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""));          SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware,
371                       resourceType == LIST_TYPE_INS ?
372                       (Software == "" ? defaultSoftware.length() : Software.length()) : 128);
373            SaveString(CHUNK_ID_IMED, lstINFO, Medium, String(""), 128);
374            SaveString(CHUNK_ID_ISRC, lstINFO, Source, String(""), 128);
375            SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String(""), 128);
376            SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String(""), 128);
377      }      }
378    
379    
# Line 440  namespace DLS { Line 479  namespace DLS {
479          }          }
480          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();          uint8_t* pData = (uint8_t*) wsmp->LoadChunkData();
481          // update headers size          // update headers size
482          memccpy(&pData[0], &uiHeaderSize, 1, 4);          memcpy(&pData[0], &uiHeaderSize, 4);
483          // update respective sampler options bits          // update respective sampler options bits
484          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION          SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION
485                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);                                                     : SamplerOptions & (~F_WSMP_NO_TRUNCATION);
486          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION          SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION
487                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);                                                 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);
488            memcpy(&pData[4], &UnityNote, 2);
489            memcpy(&pData[6], &FineTune, 2);
490            memcpy(&pData[8], &Gain, 4);
491            memcpy(&pData[12], &SamplerOptions, 4);
492            memcpy(&pData[16], &SampleLoops, 4);
493          // update loop definitions          // update loop definitions
494          for (uint32_t i = 0; i < SampleLoops; i++) {          for (uint32_t i = 0; i < SampleLoops; i++) {
495              //FIXME: this does not handle extended loop structs correctly              //FIXME: this does not handle extended loop structs correctly
496              memccpy(&pData[uiHeaderSize + i * 16], pSampleLoops + i, 4, 4);              memcpy(&pData[uiHeaderSize + i * 16], pSampleLoops + i, 4 * 4);
497          }          }
498      }      }
499    
# Line 689  namespace DLS { Line 733  namespace DLS {
733          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format          if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format
734          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();          uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData();
735          // update 'fmt' chunk          // update 'fmt' chunk
736          memccpy(&pData[0], &FormatTag, 1, 2);          memcpy(&pData[0], &FormatTag, 2);
737          memccpy(&pData[2], &Channels,  1, 2);          memcpy(&pData[2], &Channels,  2);
738          memccpy(&pData[4], &SamplesPerSecond, 1, 4);          memcpy(&pData[4], &SamplesPerSecond, 4);
739          memccpy(&pData[8], &AverageBytesPerSecond, 1, 4);          memcpy(&pData[8], &AverageBytesPerSecond, 4);
740          memccpy(&pData[12], &BlockAlign, 1, 2);          memcpy(&pData[12], &BlockAlign, 2);
741          memccpy(&pData[14], &BitDepth, 1, 2); // assuming PCM format          memcpy(&pData[14], &BitDepth, 2); // assuming PCM format
742      }      }
743    
744    
# Line 786  namespace DLS { Line 830  namespace DLS {
830      void Region::UpdateChunks() {      void Region::UpdateChunks() {
831          // make sure 'rgnh' chunk exists          // make sure 'rgnh' chunk exists
832          RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH);          RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH);
833          if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, 14);          if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, Layer ? 14 : 12);
834          uint8_t* pData = (uint8_t*) rgnh->LoadChunkData();          uint8_t* pData = (uint8_t*) rgnh->LoadChunkData();
835          FormatOptionFlags = (SelfNonExclusive)          FormatOptionFlags = (SelfNonExclusive)
836                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE                                  ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE
837                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);                                  : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);
838          // update 'rgnh' chunk          // update 'rgnh' chunk
839          memccpy(&pData[0], &KeyRange, 2, 2);          memcpy(&pData[0], &KeyRange, 2 * 2);
840          memccpy(&pData[4], &VelocityRange, 2, 2);          memcpy(&pData[4], &VelocityRange, 2 * 2);
841          memccpy(&pData[8], &FormatOptionFlags, 1, 2);          memcpy(&pData[8], &FormatOptionFlags, 2);
842          memccpy(&pData[10], &KeyGroup, 1, 2);          memcpy(&pData[10], &KeyGroup, 2);
843          memccpy(&pData[12], &Layer, 1, 2);          if (rgnh->GetSize() >= 14) memcpy(&pData[12], &Layer, 2);
844    
845          // update chunks of base classes as well          // update chunks of base classes as well (but skip Resource,
846          Resource::UpdateChunks();          // as a rgn doesn't seem to have dlid and INFO chunks)
847          Articulator::UpdateChunks();          Articulator::UpdateChunks();
848          Sampler::UpdateChunks();          Sampler::UpdateChunks();
849    
# Line 816  namespace DLS { Line 860  namespace DLS {
860          // get sample's wave pool table index          // get sample's wave pool table index
861          int index = -1;          int index = -1;
862          File* pFile = (File*) GetParent()->GetParent();          File* pFile = (File*) GetParent()->GetParent();
863          File::SampleList::iterator iter = pFile->pSamples->begin();          if (pFile->pSamples) {
864          File::SampleList::iterator end  = pFile->pSamples->end();              File::SampleList::iterator iter = pFile->pSamples->begin();
865          for (int i = 0; iter != end; ++iter, i++) {              File::SampleList::iterator end  = pFile->pSamples->end();
866              if (*iter == pSample) {              for (int i = 0; iter != end; ++iter, i++) {
867                  index = i;                  if (*iter == pSample) {
868                  break;                      index = i;
869                        break;
870                    }
871              }              }
872          }          }
873          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");
874          WavePoolTableIndex = index;          WavePoolTableIndex = index;
875          // update 'wlnk' chunk          // update 'wlnk' chunk
876          memccpy(&pData[0], &WaveLinkOptionFlags, 1, 2);          memcpy(&pData[0], &WaveLinkOptionFlags, 2);
877          memccpy(&pData[2], &PhaseGroup, 1, 2);          memcpy(&pData[2], &PhaseGroup, 2);
878          memccpy(&pData[4], &Channel, 1, 4);          memcpy(&pData[4], &Channel, 4);
879          memccpy(&pData[8], &WavePoolTableIndex, 1, 4);          memcpy(&pData[8], &WavePoolTableIndex, 4);
880      }      }
881    
882    
# Line 888  namespace DLS { Line 934  namespace DLS {
934      }      }
935    
936      void Instrument::LoadRegions() {      void Instrument::LoadRegions() {
937            if (!pRegions) pRegions = new RegionList;
938          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
939          if (!lrgn) throw DLS::Exception("Mandatory chunks in <ins > chunk not found.");          if (lrgn) {
940          uint32_t regionCkType = (lrgn->GetSubList(LIST_TYPE_RGN2)) ? LIST_TYPE_RGN2 : LIST_TYPE_RGN; // prefer regions level 2              uint32_t regionCkType = (lrgn->GetSubList(LIST_TYPE_RGN2)) ? LIST_TYPE_RGN2 : LIST_TYPE_RGN; // prefer regions level 2
941          RIFF::List* rgn = lrgn->GetFirstSubList();              RIFF::List* rgn = lrgn->GetFirstSubList();
942          while (rgn) {              while (rgn) {
943              if (rgn->GetListType() == regionCkType) {                  if (rgn->GetListType() == regionCkType) {
944                  if (!pRegions) pRegions = new RegionList;                      pRegions->push_back(new Region(this, rgn));
945                  pRegions->push_back(new Region(this, rgn));                  }
946                    rgn = lrgn->GetNextSubList();
947              }              }
             rgn = lrgn->GetNextSubList();  
948          }          }
949      }      }
950    
951      Region* Instrument::AddRegion() {      Region* Instrument::AddRegion() {
952          if (!pRegions) pRegions = new RegionList;          if (!pRegions) LoadRegions();
953          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);          RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
954          if (!lrgn)  lrgn = pCkInstrument->AddSubList(LIST_TYPE_LRGN);          if (!lrgn)  lrgn = pCkInstrument->AddSubList(LIST_TYPE_LRGN);
955          RIFF::List* rgn = lrgn->AddSubList(LIST_TYPE_RGN);          RIFF::List* rgn = lrgn->AddSubList(LIST_TYPE_RGN);
956          Region* pNewRegion = new Region(this, rgn);          Region* pNewRegion = new Region(this, rgn);
957          pRegions->push_back(pNewRegion);          pRegions->push_back(pNewRegion);
958            Regions = pRegions->size();
959          return pNewRegion;          return pNewRegion;
960      }      }
961    
962      void Instrument::DeleteRegion(Region* pRegion) {      void Instrument::DeleteRegion(Region* pRegion) {
963            if (!pRegions) return;
964          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);          RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);
965          if (iter == pRegions->end()) return;          if (iter == pRegions->end()) return;
966          pRegions->erase(iter);          pRegions->erase(iter);
967            Regions = pRegions->size();
968          delete pRegion;          delete pRegion;
969      }      }
970    
# Line 933  namespace DLS { Line 983  namespace DLS {
983          if (!insh) insh = pCkInstrument->AddSubChunk(CHUNK_ID_INSH, 12);          if (!insh) insh = pCkInstrument->AddSubChunk(CHUNK_ID_INSH, 12);
984          uint8_t* pData = (uint8_t*) insh->LoadChunkData();          uint8_t* pData = (uint8_t*) insh->LoadChunkData();
985          // update 'insh' chunk          // update 'insh' chunk
986          Regions = pRegions->size();          Regions = (pRegions) ? pRegions->size() : 0;
987          midi_locale_t locale;          midi_locale_t locale;
988          locale.instrument = MIDIProgram;          locale.instrument = MIDIProgram;
989          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);          locale.bank       = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine);
990          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);
991          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
992          memccpy(&pData[0], &Regions, 1, 4);          memcpy(&pData[0], &Regions, 4);
993          memccpy(&pData[4], &locale, 2, 4);          memcpy(&pData[4], &locale, 2 * 4);
994          // update Region's chunks          // update Region's chunks
995            if (!pRegions) return;
996          RegionList::iterator iter = pRegions->begin();          RegionList::iterator iter = pRegions->begin();
997          RegionList::iterator end  = pRegions->end();          RegionList::iterator end  = pRegions->end();
998          for (; iter != end; ++iter) {          for (; iter != end; ++iter) {
# Line 980  namespace DLS { Line 1031  namespace DLS {
1031       * to add samples, instruments and finally call Save() to actually write       * to add samples, instruments and finally call Save() to actually write
1032       * a DLS file.       * a DLS file.
1033       */       */
1034      File::File() : pRIFF(new RIFF::File(RIFF_TYPE_DLS)), Resource(NULL, pRIFF) {      File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) {
1035          pVersion = new version_t;          pVersion = new version_t;
1036          pVersion->major   = 0;          pVersion->major   = 0;
1037          pVersion->minor   = 0;          pVersion->minor   = 0;
# Line 1024  namespace DLS { Line 1075  namespace DLS {
1075          Instruments = colh->ReadUint32();          Instruments = colh->ReadUint32();
1076    
1077          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);
1078          if (!ptbl) throw DLS::Exception("Mandatory <ptbl> chunk not found.");          if (!ptbl) { // pool table is missing - this is probably an ".art" file
1079          WavePoolHeaderSize = ptbl->ReadUint32();              WavePoolCount    = 0;
1080          WavePoolCount  = ptbl->ReadUint32();              pWavePoolTable   = NULL;
1081          pWavePoolTable = new uint32_t[WavePoolCount];              pWavePoolTableHi = NULL;
1082          pWavePoolTableHi = new uint32_t[WavePoolCount];              WavePoolHeaderSize = 8;
1083          ptbl->SetPos(WavePoolHeaderSize);              b64BitWavePoolOffsets = false;
1084            } else {
1085          // Check for 64 bit offsets (used in gig v3 files)              WavePoolHeaderSize = ptbl->ReadUint32();
1086          b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8);              WavePoolCount  = ptbl->ReadUint32();
1087          if (b64BitWavePoolOffsets) {              pWavePoolTable = new uint32_t[WavePoolCount];
1088              for (int i = 0 ; i < WavePoolCount ; i++) {              pWavePoolTableHi = new uint32_t[WavePoolCount];
1089                  pWavePoolTableHi[i] = ptbl->ReadUint32();              ptbl->SetPos(WavePoolHeaderSize);
1090                  pWavePoolTable[i] = ptbl->ReadUint32();  
1091                  if (pWavePoolTable[i] & 0x80000000)              // Check for 64 bit offsets (used in gig v3 files)
1092                      throw DLS::Exception("Files larger than 2 GB not yet supported");              b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8);
1093                if (b64BitWavePoolOffsets) {
1094                    for (int i = 0 ; i < WavePoolCount ; i++) {
1095                        pWavePoolTableHi[i] = ptbl->ReadUint32();
1096                        pWavePoolTable[i] = ptbl->ReadUint32();
1097                        if (pWavePoolTable[i] & 0x80000000)
1098                            throw DLS::Exception("Files larger than 2 GB not yet supported");
1099                    }
1100                } else { // conventional 32 bit offsets
1101                    ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));
1102                    for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;
1103              }              }
         } else { // conventional 32 bit offsets  
             ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));  
             for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;  
1104          }          }
1105    
1106          pSamples     = NULL;          pSamples     = NULL;
# Line 1073  namespace DLS { Line 1131  namespace DLS {
1131          if (pWavePoolTable) delete[] pWavePoolTable;          if (pWavePoolTable) delete[] pWavePoolTable;
1132          if (pWavePoolTableHi) delete[] pWavePoolTableHi;          if (pWavePoolTableHi) delete[] pWavePoolTableHi;
1133          if (pVersion) delete pVersion;          if (pVersion) delete pVersion;
1134            for (std::list<RIFF::File*>::iterator i = ExtensionFiles.begin() ; i != ExtensionFiles.end() ; i++)
1135                delete *i;
1136      }      }
1137    
1138      Sample* File::GetFirstSample() {      Sample* File::GetFirstSample() {
# Line 1089  namespace DLS { Line 1149  namespace DLS {
1149      }      }
1150    
1151      void File::LoadSamples() {      void File::LoadSamples() {
1152            if (!pSamples) pSamples = new SampleList;
1153          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
1154          if (wvpl) {          if (wvpl) {
1155              unsigned long wvplFileOffset = wvpl->GetFilePos();              unsigned long wvplFileOffset = wvpl->GetFilePos();
1156              RIFF::List* wave = wvpl->GetFirstSubList();              RIFF::List* wave = wvpl->GetFirstSubList();
1157              while (wave) {              while (wave) {
1158                  if (wave->GetListType() == LIST_TYPE_WAVE) {                  if (wave->GetListType() == LIST_TYPE_WAVE) {
                     if (!pSamples) pSamples = new SampleList;  
1159                      unsigned long waveFileOffset = wave->GetFilePos();                      unsigned long waveFileOffset = wave->GetFilePos();
1160                      pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));                      pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));
1161                  }                  }
# Line 1109  namespace DLS { Line 1169  namespace DLS {
1169                  RIFF::List* wave = dwpl->GetFirstSubList();                  RIFF::List* wave = dwpl->GetFirstSubList();
1170                  while (wave) {                  while (wave) {
1171                      if (wave->GetListType() == LIST_TYPE_WAVE) {                      if (wave->GetListType() == LIST_TYPE_WAVE) {
                         if (!pSamples) pSamples = new SampleList;  
1172                          unsigned long waveFileOffset = wave->GetFilePos();                          unsigned long waveFileOffset = wave->GetFilePos();
1173                          pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset));                          pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset));
1174                      }                      }
# Line 1127  namespace DLS { Line 1186  namespace DLS {
1186       * @returns pointer to new Sample object       * @returns pointer to new Sample object
1187       */       */
1188      Sample* File::AddSample() {      Sample* File::AddSample() {
1189           if (!pSamples) LoadSamples();
1190         __ensureMandatoryChunksExist();         __ensureMandatoryChunksExist();
1191         RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);         RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
1192         // create new Sample object and its respective 'wave' list chunk         // create new Sample object and its respective 'wave' list chunk
        if (!pSamples) pSamples = new SampleList;  
1193         RIFF::List* wave = wvpl->AddSubList(LIST_TYPE_WAVE);         RIFF::List* wave = wvpl->AddSubList(LIST_TYPE_WAVE);
1194         Sample* pSample = new Sample(this, wave, 0 /*arbitrary value, we update offsets when we save*/);         Sample* pSample = new Sample(this, wave, 0 /*arbitrary value, we update offsets when we save*/);
1195         pSamples->push_back(pSample);         pSamples->push_back(pSample);
# Line 1145  namespace DLS { Line 1204  namespace DLS {
1204       * @param pSample - sample to delete       * @param pSample - sample to delete
1205       */       */
1206      void File::DeleteSample(Sample* pSample) {      void File::DeleteSample(Sample* pSample) {
1207            if (!pSamples) return;
1208          SampleList::iterator iter = find(pSamples->begin(), pSamples->end(), pSample);          SampleList::iterator iter = find(pSamples->begin(), pSamples->end(), pSample);
1209          if (iter == pSamples->end()) return;          if (iter == pSamples->end()) return;
1210          pSamples->erase(iter);          pSamples->erase(iter);
# Line 1165  namespace DLS { Line 1225  namespace DLS {
1225      }      }
1226    
1227      void File::LoadInstruments() {      void File::LoadInstruments() {
1228            if (!pInstruments) pInstruments = new InstrumentList;
1229          RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);          RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
1230          if (lstInstruments) {          if (lstInstruments) {
1231              RIFF::List* lstInstr = lstInstruments->GetFirstSubList();              RIFF::List* lstInstr = lstInstruments->GetFirstSubList();
1232              while (lstInstr) {              while (lstInstr) {
1233                  if (lstInstr->GetListType() == LIST_TYPE_INS) {                  if (lstInstr->GetListType() == LIST_TYPE_INS) {
                     if (!pInstruments) pInstruments = new InstrumentList;  
1234                      pInstruments->push_back(new Instrument(this, lstInstr));                      pInstruments->push_back(new Instrument(this, lstInstr));
1235                  }                  }
1236                  lstInstr = lstInstruments->GetNextSubList();                  lstInstr = lstInstruments->GetNextSubList();
# Line 1186  namespace DLS { Line 1246  namespace DLS {
1246       * @returns pointer to new Instrument object       * @returns pointer to new Instrument object
1247       */       */
1248      Instrument* File::AddInstrument() {      Instrument* File::AddInstrument() {
1249           if (!pInstruments) LoadInstruments();
1250         __ensureMandatoryChunksExist();         __ensureMandatoryChunksExist();
        if (!pInstruments) pInstruments = new InstrumentList;  
1251         RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);         RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
1252         RIFF::List* lstInstr = lstInstruments->AddSubList(LIST_TYPE_INS);         RIFF::List* lstInstr = lstInstruments->AddSubList(LIST_TYPE_INS);
1253         Instrument* pInstrument = new Instrument(this, lstInstr);         Instrument* pInstrument = new Instrument(this, lstInstr);
# Line 1195  namespace DLS { Line 1255  namespace DLS {
1255         return pInstrument;         return pInstrument;
1256      }      }
1257    
1258      /** @brief Delete a instrument.      /** @brief Delete an instrument.
1259       *       *
1260       * This will delete the given Instrument object from the DLS file. You       * This will delete the given Instrument object from the DLS file. You
1261       * have to call Save() to make this persistent to the file.       * have to call Save() to make this persistent to the file.
# Line 1203  namespace DLS { Line 1263  namespace DLS {
1263       * @param pInstrument - instrument to delete       * @param pInstrument - instrument to delete
1264       */       */
1265      void File::DeleteInstrument(Instrument* pInstrument) {      void File::DeleteInstrument(Instrument* pInstrument) {
1266            if (!pInstruments) return;
1267          InstrumentList::iterator iter = find(pInstruments->begin(), pInstruments->end(), pInstrument);          InstrumentList::iterator iter = find(pInstruments->begin(), pInstruments->end(), pInstrument);
1268          if (iter == pInstruments->end()) return;          if (iter == pInstruments->end()) return;
1269          pInstruments->erase(iter);          pInstruments->erase(iter);
# Line 1225  namespace DLS { Line 1286  namespace DLS {
1286              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);              RIFF::Chunk* ckVersion    = pRIFF->GetSubChunk(CHUNK_ID_VERS);
1287              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);              if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8);
1288              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();              uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData();
1289              memccpy(pData, pVersion, 2, 4);              memcpy(pData, pVersion, 2 * 4);
1290          }          }
1291    
1292          // update 'colh' chunk          // update 'colh' chunk
# Line 1233  namespace DLS { Line 1294  namespace DLS {
1294          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);          RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);
1295          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);          if (!colh)   colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4);
1296          uint8_t* pData = (uint8_t*) colh->LoadChunkData();          uint8_t* pData = (uint8_t*) colh->LoadChunkData();
1297          memccpy(pData, &Instruments, 1, 4);          memcpy(pData, &Instruments, 4);
1298    
1299          // update instrument's chunks          // update instrument's chunks
1300          if (pInstruments) {          if (pInstruments) {
# Line 1253  namespace DLS { Line 1314  namespace DLS {
1314          ptbl->Resize(iPtblSize);          ptbl->Resize(iPtblSize);
1315          pData = (uint8_t*) ptbl->LoadChunkData();          pData = (uint8_t*) ptbl->LoadChunkData();
1316          WavePoolCount = iSamples;          WavePoolCount = iSamples;
1317          memccpy(&pData[4], &WavePoolCount, 1, 4);          memcpy(&pData[4], &WavePoolCount, 4);
1318          // 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()
1319          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);          memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);
1320    
# Line 1324  namespace DLS { Line 1385  namespace DLS {
1385      /**      /**
1386       * Updates (persistently) the wave pool table with offsets to all       * Updates (persistently) the wave pool table with offsets to all
1387       * currently available samples. <b>Caution:</b> this method assumes the       * currently available samples. <b>Caution:</b> this method assumes the
1388       * 'ptbl' chunk to be already of the correct size, so usually this       * 'ptbl' chunk to be already of the correct size and the file to be
1389       * method is only called after a Save() call.       * writable, so usually this method is only called after a Save() call.
1390       *       *
1391       * @throws Exception - if 'ptbl' chunk is too small (should only occur       * @throws Exception - if 'ptbl' chunk is too small (should only occur
1392       *                     if there's a bug)       *                     if there's a bug)
# Line 1335  namespace DLS { Line 1396  namespace DLS {
1396          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);          RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);
1397          const int iOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4;          const int iOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4;
1398          // check if 'ptbl' chunk is large enough          // check if 'ptbl' chunk is large enough
1399          WavePoolCount = pSamples->size();          WavePoolCount = (pSamples) ? pSamples->size() : 0;
1400          const unsigned long ulRequiredSize = WavePoolHeaderSize + iOffsetSize * WavePoolCount;          const unsigned long ulRequiredSize = WavePoolHeaderSize + iOffsetSize * WavePoolCount;
1401          if (ptbl->GetSize() < ulRequiredSize) throw Exception("Fatal error, 'ptbl' chunk too small");          if (ptbl->GetSize() < ulRequiredSize) throw Exception("Fatal error, 'ptbl' chunk too small");
1402          uint8_t* pData = (uint8_t*) ptbl->LoadChunkData();          // save the 'ptbl' chunk's current read/write position
1403            unsigned long ulOriginalPos = ptbl->GetPos();
1404          // update headers          // update headers
1405          memccpy(&pData[0], &WavePoolHeaderSize, 1, 4);          ptbl->SetPos(0);
1406          memccpy(&pData[4], &WavePoolCount, 1, 4);          ptbl->WriteUint32(&WavePoolHeaderSize);
1407            ptbl->WriteUint32(&WavePoolCount);
1408          // update offsets          // update offsets
1409            ptbl->SetPos(WavePoolHeaderSize);
1410          if (b64BitWavePoolOffsets) {          if (b64BitWavePoolOffsets) {
1411              for (int i = 0 ; i < WavePoolCount ; i++) {              for (int i = 0 ; i < WavePoolCount ; i++) {
1412                  memccpy(&pData[WavePoolHeaderSize + i*iOffsetSize], &pWavePoolTableHi[i], 1, 4);                  ptbl->WriteUint32(&pWavePoolTableHi[i]);
1413                  memccpy(&pData[WavePoolHeaderSize + i*iOffsetSize], &pWavePoolTable[i],   1, 4);                  ptbl->WriteUint32(&pWavePoolTable[i]);
1414              }              }
1415          } else { // conventional 32 bit offsets          } else { // conventional 32 bit offsets
1416              for (int i = 0 ; i < WavePoolCount ; i++)              for (int i = 0 ; i < WavePoolCount ; i++)
1417                  memccpy(&pData[WavePoolHeaderSize + i*iOffsetSize], &pWavePoolTable[i], 1, 4);                  ptbl->WriteUint32(&pWavePoolTable[i]);
1418          }          }
1419            // restore 'ptbl' chunk's original read/write position
1420            ptbl->SetPos(ulOriginalPos);
1421      }      }
1422    
1423      /**      /**
# Line 1360  namespace DLS { Line 1426  namespace DLS {
1426       * exists already.       * exists already.
1427       */       */
1428      void File::__UpdateWavePoolTable() {      void File::__UpdateWavePoolTable() {
1429          WavePoolCount = pSamples->size();          WavePoolCount = (pSamples) ? pSamples->size() : 0;
1430          // resize wave pool table arrays          // resize wave pool table arrays
1431          if (pWavePoolTable)   delete[] pWavePoolTable;          if (pWavePoolTable)   delete[] pWavePoolTable;
1432          if (pWavePoolTableHi) delete[] pWavePoolTableHi;          if (pWavePoolTableHi) delete[] pWavePoolTableHi;
1433          pWavePoolTable   = new uint32_t[WavePoolCount];          pWavePoolTable   = new uint32_t[WavePoolCount];
1434          pWavePoolTableHi = new uint32_t[WavePoolCount];          pWavePoolTableHi = new uint32_t[WavePoolCount];
1435            if (!pSamples) return;
1436          // update offsets int wave pool table          // update offsets int wave pool table
1437          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
1438          uint64_t wvplFileOffset = wvpl->GetFilePos();          uint64_t wvplFileOffset = wvpl->GetFilePos();
# Line 1373  namespace DLS { Line 1440  namespace DLS {
1440              SampleList::iterator iter = pSamples->begin();              SampleList::iterator iter = pSamples->begin();
1441              SampleList::iterator end  = pSamples->end();              SampleList::iterator end  = pSamples->end();
1442              for (int i = 0 ; iter != end ; ++iter, i++) {              for (int i = 0 ; iter != end ; ++iter, i++) {
1443                  uint64_t _64BitOffset = wvplFileOffset - (*iter)->pWaveList->GetFilePos() - LIST_HEADER_SIZE;                  uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - wvplFileOffset - LIST_HEADER_SIZE;
1444                  (*iter)->ulWavePoolOffset = _64BitOffset;                  (*iter)->ulWavePoolOffset = _64BitOffset;
1445                  pWavePoolTableHi[i] = (uint32_t) (_64BitOffset >> 32);                  pWavePoolTableHi[i] = (uint32_t) (_64BitOffset >> 32);
1446                  pWavePoolTable[i]   = (uint32_t) _64BitOffset;                  pWavePoolTable[i]   = (uint32_t) _64BitOffset;
# Line 1382  namespace DLS { Line 1449  namespace DLS {
1449              SampleList::iterator iter = pSamples->begin();              SampleList::iterator iter = pSamples->begin();
1450              SampleList::iterator end  = pSamples->end();              SampleList::iterator end  = pSamples->end();
1451              for (int i = 0 ; iter != end ; ++iter, i++) {              for (int i = 0 ; iter != end ; ++iter, i++) {
1452                  uint64_t _64BitOffset = wvplFileOffset - (*iter)->pWaveList->GetFilePos() - LIST_HEADER_SIZE;                  uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - wvplFileOffset - LIST_HEADER_SIZE;
1453                  (*iter)->ulWavePoolOffset = _64BitOffset;                  (*iter)->ulWavePoolOffset = _64BitOffset;
1454                  pWavePoolTable[i] = (uint32_t) _64BitOffset;                  pWavePoolTable[i] = (uint32_t) _64BitOffset;
1455              }              }

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

  ViewVC Help
Powered by ViewVC