libgig 3.3.0
|
00001 /*************************************************************************** 00002 * * 00003 * libgig - C++ cross-platform Gigasampler format file access library * 00004 * * 00005 * Copyright (C) 2003-2009 by Christian Schoenebeck * 00006 * <cuse@users.sourceforge.net> * 00007 * * 00008 * This library is free software; you can redistribute it and/or modify * 00009 * it under the terms of the GNU General Public License as published by * 00010 * the Free Software Foundation; either version 2 of the License, or * 00011 * (at your option) any later version. * 00012 * * 00013 * This library is distributed in the hope that it will be useful, * 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00016 * GNU General Public License for more details. * 00017 * * 00018 * You should have received a copy of the GNU General Public License * 00019 * along with this library; if not, write to the Free Software * 00020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * 00021 * MA 02111-1307 USA * 00022 ***************************************************************************/ 00023 00024 #include "DLS.h" 00025 00026 #include <algorithm> 00027 #include <time.h> 00028 00029 #ifdef __APPLE__ 00030 #include <CoreFoundation/CFUUID.h> 00031 #elif defined(HAVE_UUID_UUID_H) 00032 #include <uuid/uuid.h> 00033 #endif 00034 00035 #include "helper.h" 00036 00037 // macros to decode connection transforms 00038 #define CONN_TRANSFORM_SRC(x) ((x >> 10) & 0x000F) 00039 #define CONN_TRANSFORM_CTL(x) ((x >> 4) & 0x000F) 00040 #define CONN_TRANSFORM_DST(x) (x & 0x000F) 00041 #define CONN_TRANSFORM_BIPOLAR_SRC(x) (x & 0x4000) 00042 #define CONN_TRANSFORM_BIPOLAR_CTL(x) (x & 0x0100) 00043 #define CONN_TRANSFORM_INVERT_SRC(x) (x & 0x8000) 00044 #define CONN_TRANSFORM_INVERT_CTL(x) (x & 0x0200) 00045 00046 // macros to encode connection transforms 00047 #define CONN_TRANSFORM_SRC_ENCODE(x) ((x & 0x000F) << 10) 00048 #define CONN_TRANSFORM_CTL_ENCODE(x) ((x & 0x000F) << 4) 00049 #define CONN_TRANSFORM_DST_ENCODE(x) (x & 0x000F) 00050 #define CONN_TRANSFORM_BIPOLAR_SRC_ENCODE(x) ((x) ? 0x4000 : 0) 00051 #define CONN_TRANSFORM_BIPOLAR_CTL_ENCODE(x) ((x) ? 0x0100 : 0) 00052 #define CONN_TRANSFORM_INVERT_SRC_ENCODE(x) ((x) ? 0x8000 : 0) 00053 #define CONN_TRANSFORM_INVERT_CTL_ENCODE(x) ((x) ? 0x0200 : 0) 00054 00055 #define DRUM_TYPE_MASK 0x80000000 00056 00057 #define F_RGN_OPTION_SELFNONEXCLUSIVE 0x0001 00058 00059 #define F_WAVELINK_PHASE_MASTER 0x0001 00060 #define F_WAVELINK_MULTICHANNEL 0x0002 00061 00062 #define F_WSMP_NO_TRUNCATION 0x0001 00063 #define F_WSMP_NO_COMPRESSION 0x0002 00064 00065 #define MIDI_BANK_COARSE(x) ((x & 0x00007F00) >> 8) // CC0 00066 #define MIDI_BANK_FINE(x) (x & 0x0000007F) // CC32 00067 #define MIDI_BANK_MERGE(coarse, fine) ((((uint16_t) coarse) << 7) | fine) // CC0 + CC32 00068 #define MIDI_BANK_ENCODE(coarse, fine) (((coarse & 0x0000007F) << 8) | (fine & 0x0000007F)) 00069 00070 namespace DLS { 00071 00072 // *************** Connection *************** 00073 // * 00074 00075 void Connection::Init(conn_block_t* Header) { 00076 Source = (conn_src_t) Header->source; 00077 Control = (conn_src_t) Header->control; 00078 Destination = (conn_dst_t) Header->destination; 00079 Scale = Header->scale; 00080 SourceTransform = (conn_trn_t) CONN_TRANSFORM_SRC(Header->transform); 00081 ControlTransform = (conn_trn_t) CONN_TRANSFORM_CTL(Header->transform); 00082 DestinationTransform = (conn_trn_t) CONN_TRANSFORM_DST(Header->transform); 00083 SourceInvert = CONN_TRANSFORM_INVERT_SRC(Header->transform); 00084 SourceBipolar = CONN_TRANSFORM_BIPOLAR_SRC(Header->transform); 00085 ControlInvert = CONN_TRANSFORM_INVERT_CTL(Header->transform); 00086 ControlBipolar = CONN_TRANSFORM_BIPOLAR_CTL(Header->transform); 00087 } 00088 00089 Connection::conn_block_t Connection::ToConnBlock() { 00090 conn_block_t c; 00091 c.source = Source; 00092 c.control = Control; 00093 c.destination = Destination; 00094 c.scale = Scale; 00095 c.transform = CONN_TRANSFORM_SRC_ENCODE(SourceTransform) | 00096 CONN_TRANSFORM_CTL_ENCODE(ControlTransform) | 00097 CONN_TRANSFORM_DST_ENCODE(DestinationTransform) | 00098 CONN_TRANSFORM_INVERT_SRC_ENCODE(SourceInvert) | 00099 CONN_TRANSFORM_BIPOLAR_SRC_ENCODE(SourceBipolar) | 00100 CONN_TRANSFORM_INVERT_CTL_ENCODE(ControlInvert) | 00101 CONN_TRANSFORM_BIPOLAR_CTL_ENCODE(ControlBipolar); 00102 return c; 00103 } 00104 00105 00106 00107 // *************** Articulation *************** 00108 // * 00109 00118 Articulation::Articulation(RIFF::Chunk* artl) { 00119 pArticulationCk = artl; 00120 if (artl->GetChunkID() != CHUNK_ID_ART2 && 00121 artl->GetChunkID() != CHUNK_ID_ARTL) { 00122 throw DLS::Exception("<artl-ck> or <art2-ck> chunk expected"); 00123 } 00124 HeaderSize = artl->ReadUint32(); 00125 Connections = artl->ReadUint32(); 00126 artl->SetPos(HeaderSize); 00127 00128 pConnections = new Connection[Connections]; 00129 Connection::conn_block_t connblock; 00130 for (uint32_t i = 0; i < Connections; i++) { 00131 artl->Read(&connblock.source, 1, 2); 00132 artl->Read(&connblock.control, 1, 2); 00133 artl->Read(&connblock.destination, 1, 2); 00134 artl->Read(&connblock.transform, 1, 2); 00135 artl->Read(&connblock.scale, 1, 4); 00136 pConnections[i].Init(&connblock); 00137 } 00138 } 00139 00140 Articulation::~Articulation() { 00141 if (pConnections) delete[] pConnections; 00142 } 00143 00148 void Articulation::UpdateChunks() { 00149 const int iEntrySize = 12; // 12 bytes per connection block 00150 pArticulationCk->Resize(HeaderSize + Connections * iEntrySize); 00151 uint8_t* pData = (uint8_t*) pArticulationCk->LoadChunkData(); 00152 store16(&pData[0], HeaderSize); 00153 store16(&pData[2], Connections); 00154 for (uint32_t i = 0; i < Connections; i++) { 00155 Connection::conn_block_t c = pConnections[i].ToConnBlock(); 00156 store16(&pData[HeaderSize + i * iEntrySize], c.source); 00157 store16(&pData[HeaderSize + i * iEntrySize + 2], c.control); 00158 store16(&pData[HeaderSize + i * iEntrySize + 4], c.destination); 00159 store16(&pData[HeaderSize + i * iEntrySize + 6], c.transform); 00160 store32(&pData[HeaderSize + i * iEntrySize + 8], c.scale); 00161 } 00162 } 00163 00164 00165 00166 // *************** Articulator *************** 00167 // * 00168 00169 Articulator::Articulator(RIFF::List* ParentList) { 00170 pParentList = ParentList; 00171 pArticulations = NULL; 00172 } 00173 00174 Articulation* Articulator::GetFirstArticulation() { 00175 if (!pArticulations) LoadArticulations(); 00176 if (!pArticulations) return NULL; 00177 ArticulationsIterator = pArticulations->begin(); 00178 return (ArticulationsIterator != pArticulations->end()) ? *ArticulationsIterator : NULL; 00179 } 00180 00181 Articulation* Articulator::GetNextArticulation() { 00182 if (!pArticulations) return NULL; 00183 ArticulationsIterator++; 00184 return (ArticulationsIterator != pArticulations->end()) ? *ArticulationsIterator : NULL; 00185 } 00186 00187 void Articulator::LoadArticulations() { 00188 // prefer articulation level 2 00189 RIFF::List* lart = pParentList->GetSubList(LIST_TYPE_LAR2); 00190 if (!lart) lart = pParentList->GetSubList(LIST_TYPE_LART); 00191 if (lart) { 00192 uint32_t artCkType = (lart->GetListType() == LIST_TYPE_LAR2) ? CHUNK_ID_ART2 00193 : CHUNK_ID_ARTL; 00194 RIFF::Chunk* art = lart->GetFirstSubChunk(); 00195 while (art) { 00196 if (art->GetChunkID() == artCkType) { 00197 if (!pArticulations) pArticulations = new ArticulationList; 00198 pArticulations->push_back(new Articulation(art)); 00199 } 00200 art = lart->GetNextSubChunk(); 00201 } 00202 } 00203 } 00204 00205 Articulator::~Articulator() { 00206 if (pArticulations) { 00207 ArticulationList::iterator iter = pArticulations->begin(); 00208 ArticulationList::iterator end = pArticulations->end(); 00209 while (iter != end) { 00210 delete *iter; 00211 iter++; 00212 } 00213 delete pArticulations; 00214 } 00215 } 00216 00221 void Articulator::UpdateChunks() { 00222 if (pArticulations) { 00223 ArticulationList::iterator iter = pArticulations->begin(); 00224 ArticulationList::iterator end = pArticulations->end(); 00225 for (; iter != end; ++iter) { 00226 (*iter)->UpdateChunks(); 00227 } 00228 } 00229 } 00230 00231 00232 00233 // *************** Info *************** 00234 // * 00235 00242 Info::Info(RIFF::List* list) { 00243 pFixedStringLengths = NULL; 00244 pResourceListChunk = list; 00245 if (list) { 00246 RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO); 00247 if (lstINFO) { 00248 LoadString(CHUNK_ID_INAM, lstINFO, Name); 00249 LoadString(CHUNK_ID_IARL, lstINFO, ArchivalLocation); 00250 LoadString(CHUNK_ID_ICRD, lstINFO, CreationDate); 00251 LoadString(CHUNK_ID_ICMT, lstINFO, Comments); 00252 LoadString(CHUNK_ID_IPRD, lstINFO, Product); 00253 LoadString(CHUNK_ID_ICOP, lstINFO, Copyright); 00254 LoadString(CHUNK_ID_IART, lstINFO, Artists); 00255 LoadString(CHUNK_ID_IGNR, lstINFO, Genre); 00256 LoadString(CHUNK_ID_IKEY, lstINFO, Keywords); 00257 LoadString(CHUNK_ID_IENG, lstINFO, Engineer); 00258 LoadString(CHUNK_ID_ITCH, lstINFO, Technician); 00259 LoadString(CHUNK_ID_ISFT, lstINFO, Software); 00260 LoadString(CHUNK_ID_IMED, lstINFO, Medium); 00261 LoadString(CHUNK_ID_ISRC, lstINFO, Source); 00262 LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm); 00263 LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned); 00264 LoadString(CHUNK_ID_ISBJ, lstINFO, Subject); 00265 } 00266 } 00267 } 00268 00269 Info::~Info() { 00270 } 00271 00283 void Info::SetFixedStringLengths(const string_length_t* lengths) { 00284 pFixedStringLengths = lengths; 00285 } 00286 00292 void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) { 00293 RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID); 00294 ::LoadString(ck, s); // function from helper.h 00295 } 00296 00312 void Info::SaveString(uint32_t ChunkID, RIFF::List* lstINFO, const String& s, const String& sDefault) { 00313 int size = 0; 00314 if (pFixedStringLengths) { 00315 for (int i = 0 ; pFixedStringLengths[i].length ; i++) { 00316 if (pFixedStringLengths[i].chunkId == ChunkID) { 00317 size = pFixedStringLengths[i].length; 00318 break; 00319 } 00320 } 00321 } 00322 RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID); 00323 ::SaveString(ChunkID, ck, lstINFO, s, sDefault, size != 0, size); // function from helper.h 00324 } 00325 00331 void Info::UpdateChunks() { 00332 if (!pResourceListChunk) return; 00333 00334 // make sure INFO list chunk exists 00335 RIFF::List* lstINFO = pResourceListChunk->GetSubList(LIST_TYPE_INFO); 00336 00337 String defaultName = ""; 00338 String defaultCreationDate = ""; 00339 String defaultSoftware = ""; 00340 String defaultComments = ""; 00341 00342 uint32_t resourceType = pResourceListChunk->GetListType(); 00343 00344 if (!lstINFO) { 00345 lstINFO = pResourceListChunk->AddSubList(LIST_TYPE_INFO); 00346 00347 // assemble default values 00348 defaultName = "NONAME"; 00349 00350 if (resourceType == RIFF_TYPE_DLS) { 00351 // get current date 00352 time_t now = time(NULL); 00353 tm* pNowBroken = localtime(&now); 00354 char buf[11]; 00355 strftime(buf, 11, "%F", pNowBroken); 00356 defaultCreationDate = buf; 00357 00358 defaultComments = "Created with " + libraryName() + " " + libraryVersion(); 00359 } 00360 if (resourceType == RIFF_TYPE_DLS || resourceType == LIST_TYPE_INS) 00361 { 00362 defaultSoftware = libraryName() + " " + libraryVersion(); 00363 } 00364 } 00365 00366 // save values 00367 00368 SaveString(CHUNK_ID_IARL, lstINFO, ArchivalLocation, String("")); 00369 SaveString(CHUNK_ID_IART, lstINFO, Artists, String("")); 00370 SaveString(CHUNK_ID_ICMS, lstINFO, Commissioned, String("")); 00371 SaveString(CHUNK_ID_ICMT, lstINFO, Comments, defaultComments); 00372 SaveString(CHUNK_ID_ICOP, lstINFO, Copyright, String("")); 00373 SaveString(CHUNK_ID_ICRD, lstINFO, CreationDate, defaultCreationDate); 00374 SaveString(CHUNK_ID_IENG, lstINFO, Engineer, String("")); 00375 SaveString(CHUNK_ID_IGNR, lstINFO, Genre, String("")); 00376 SaveString(CHUNK_ID_IKEY, lstINFO, Keywords, String("")); 00377 SaveString(CHUNK_ID_IMED, lstINFO, Medium, String("")); 00378 SaveString(CHUNK_ID_INAM, lstINFO, Name, defaultName); 00379 SaveString(CHUNK_ID_IPRD, lstINFO, Product, String("")); 00380 SaveString(CHUNK_ID_ISBJ, lstINFO, Subject, String("")); 00381 SaveString(CHUNK_ID_ISFT, lstINFO, Software, defaultSoftware); 00382 SaveString(CHUNK_ID_ISRC, lstINFO, Source, String("")); 00383 SaveString(CHUNK_ID_ISRF, lstINFO, SourceForm, String("")); 00384 SaveString(CHUNK_ID_ITCH, lstINFO, Technician, String("")); 00385 } 00386 00387 00388 00389 // *************** Resource *************** 00390 // * 00391 00401 Resource::Resource(Resource* Parent, RIFF::List* lstResource) { 00402 pParent = Parent; 00403 pResourceList = lstResource; 00404 00405 pInfo = new Info(lstResource); 00406 00407 RIFF::Chunk* ckDLSID = lstResource->GetSubChunk(CHUNK_ID_DLID); 00408 if (ckDLSID) { 00409 pDLSID = new dlsid_t; 00410 ckDLSID->Read(&pDLSID->ulData1, 1, 4); 00411 ckDLSID->Read(&pDLSID->usData2, 1, 2); 00412 ckDLSID->Read(&pDLSID->usData3, 1, 2); 00413 ckDLSID->Read(pDLSID->abData, 8, 1); 00414 } 00415 else pDLSID = NULL; 00416 } 00417 00418 Resource::~Resource() { 00419 if (pDLSID) delete pDLSID; 00420 if (pInfo) delete pInfo; 00421 } 00422 00431 void Resource::UpdateChunks() { 00432 pInfo->UpdateChunks(); 00433 00434 if (pDLSID) { 00435 // make sure 'dlid' chunk exists 00436 RIFF::Chunk* ckDLSID = pResourceList->GetSubChunk(CHUNK_ID_DLID); 00437 if (!ckDLSID) ckDLSID = pResourceList->AddSubChunk(CHUNK_ID_DLID, 16); 00438 uint8_t* pData = (uint8_t*)ckDLSID->LoadChunkData(); 00439 // update 'dlid' chunk 00440 store32(&pData[0], pDLSID->ulData1); 00441 store16(&pData[4], pDLSID->usData2); 00442 store16(&pData[6], pDLSID->usData3); 00443 memcpy(&pData[8], pDLSID->abData, 8); 00444 } 00445 } 00446 00450 void Resource::GenerateDLSID() { 00451 #if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE) 00452 00453 if (!pDLSID) pDLSID = new dlsid_t; 00454 00455 #ifdef WIN32 00456 00457 UUID uuid; 00458 UuidCreate(&uuid); 00459 pDLSID->ulData1 = uuid.Data1; 00460 pDLSID->usData2 = uuid.Data2; 00461 pDLSID->usData3 = uuid.Data3; 00462 memcpy(pDLSID->abData, uuid.Data4, 8); 00463 00464 #elif defined(__APPLE__) 00465 00466 CFUUIDRef uuidRef = CFUUIDCreate(NULL); 00467 CFUUIDBytes uuid = CFUUIDGetUUIDBytes(uuidRef); 00468 CFRelease(uuidRef); 00469 pDLSID->ulData1 = uuid.byte0 | uuid.byte1 << 8 | uuid.byte2 << 16 | uuid.byte3 << 24; 00470 pDLSID->usData2 = uuid.byte4 | uuid.byte5 << 8; 00471 pDLSID->usData3 = uuid.byte6 | uuid.byte7 << 8; 00472 pDLSID->abData[0] = uuid.byte8; 00473 pDLSID->abData[1] = uuid.byte9; 00474 pDLSID->abData[2] = uuid.byte10; 00475 pDLSID->abData[3] = uuid.byte11; 00476 pDLSID->abData[4] = uuid.byte12; 00477 pDLSID->abData[5] = uuid.byte13; 00478 pDLSID->abData[6] = uuid.byte14; 00479 pDLSID->abData[7] = uuid.byte15; 00480 #else 00481 uuid_t uuid; 00482 uuid_generate(uuid); 00483 pDLSID->ulData1 = uuid[0] | uuid[1] << 8 | uuid[2] << 16 | uuid[3] << 24; 00484 pDLSID->usData2 = uuid[4] | uuid[5] << 8; 00485 pDLSID->usData3 = uuid[6] | uuid[7] << 8; 00486 memcpy(pDLSID->abData, &uuid[8], 8); 00487 #endif 00488 #endif 00489 } 00490 00491 00492 // *************** Sampler *************** 00493 // * 00494 00495 Sampler::Sampler(RIFF::List* ParentList) { 00496 pParentList = ParentList; 00497 RIFF::Chunk* wsmp = ParentList->GetSubChunk(CHUNK_ID_WSMP); 00498 if (wsmp) { 00499 uiHeaderSize = wsmp->ReadUint32(); 00500 UnityNote = wsmp->ReadUint16(); 00501 FineTune = wsmp->ReadInt16(); 00502 Gain = wsmp->ReadInt32(); 00503 SamplerOptions = wsmp->ReadUint32(); 00504 SampleLoops = wsmp->ReadUint32(); 00505 } else { // 'wsmp' chunk missing 00506 uiHeaderSize = 20; 00507 UnityNote = 60; 00508 FineTune = 0; // +- 0 cents 00509 Gain = 0; // 0 dB 00510 SamplerOptions = F_WSMP_NO_COMPRESSION; 00511 SampleLoops = 0; 00512 } 00513 NoSampleDepthTruncation = SamplerOptions & F_WSMP_NO_TRUNCATION; 00514 NoSampleCompression = SamplerOptions & F_WSMP_NO_COMPRESSION; 00515 pSampleLoops = (SampleLoops) ? new sample_loop_t[SampleLoops] : NULL; 00516 if (SampleLoops) { 00517 wsmp->SetPos(uiHeaderSize); 00518 for (uint32_t i = 0; i < SampleLoops; i++) { 00519 wsmp->Read(pSampleLoops + i, 4, 4); 00520 if (pSampleLoops[i].Size > sizeof(sample_loop_t)) { // if loop struct was extended 00521 wsmp->SetPos(pSampleLoops[i].Size - sizeof(sample_loop_t), RIFF::stream_curpos); 00522 } 00523 } 00524 } 00525 } 00526 00527 Sampler::~Sampler() { 00528 if (pSampleLoops) delete[] pSampleLoops; 00529 } 00530 00531 void Sampler::SetGain(int32_t gain) { 00532 Gain = gain; 00533 } 00534 00539 void Sampler::UpdateChunks() { 00540 // make sure 'wsmp' chunk exists 00541 RIFF::Chunk* wsmp = pParentList->GetSubChunk(CHUNK_ID_WSMP); 00542 int wsmpSize = uiHeaderSize + SampleLoops * 16; 00543 if (!wsmp) { 00544 wsmp = pParentList->AddSubChunk(CHUNK_ID_WSMP, wsmpSize); 00545 } else if (wsmp->GetSize() != wsmpSize) { 00546 wsmp->Resize(wsmpSize); 00547 } 00548 uint8_t* pData = (uint8_t*) wsmp->LoadChunkData(); 00549 // update headers size 00550 store32(&pData[0], uiHeaderSize); 00551 // update respective sampler options bits 00552 SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION 00553 : SamplerOptions & (~F_WSMP_NO_TRUNCATION); 00554 SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION 00555 : SamplerOptions & (~F_WSMP_NO_COMPRESSION); 00556 store16(&pData[4], UnityNote); 00557 store16(&pData[6], FineTune); 00558 store32(&pData[8], Gain); 00559 store32(&pData[12], SamplerOptions); 00560 store32(&pData[16], SampleLoops); 00561 // update loop definitions 00562 for (uint32_t i = 0; i < SampleLoops; i++) { 00563 //FIXME: this does not handle extended loop structs correctly 00564 store32(&pData[uiHeaderSize + i * 16], pSampleLoops[i].Size); 00565 store32(&pData[uiHeaderSize + i * 16 + 4], pSampleLoops[i].LoopType); 00566 store32(&pData[uiHeaderSize + i * 16 + 8], pSampleLoops[i].LoopStart); 00567 store32(&pData[uiHeaderSize + i * 16 + 12], pSampleLoops[i].LoopLength); 00568 } 00569 } 00570 00576 void Sampler::AddSampleLoop(sample_loop_t* pLoopDef) { 00577 sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops + 1]; 00578 // copy old loops array 00579 for (int i = 0; i < SampleLoops; i++) { 00580 pNewLoops[i] = pSampleLoops[i]; 00581 } 00582 // add the new loop 00583 pNewLoops[SampleLoops] = *pLoopDef; 00584 // auto correct size field 00585 pNewLoops[SampleLoops].Size = sizeof(DLS::sample_loop_t); 00586 // free the old array and update the member variables 00587 if (SampleLoops) delete[] pSampleLoops; 00588 pSampleLoops = pNewLoops; 00589 SampleLoops++; 00590 } 00591 00598 void Sampler::DeleteSampleLoop(sample_loop_t* pLoopDef) { 00599 sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops - 1]; 00600 // copy old loops array (skipping given loop) 00601 for (int i = 0, o = 0; i < SampleLoops; i++) { 00602 if (&pSampleLoops[i] == pLoopDef) continue; 00603 if (o == SampleLoops - 1) 00604 throw Exception("Could not delete Sample Loop, because it does not exist"); 00605 pNewLoops[o] = pSampleLoops[i]; 00606 o++; 00607 } 00608 // free the old array and update the member variables 00609 if (SampleLoops) delete[] pSampleLoops; 00610 pSampleLoops = pNewLoops; 00611 SampleLoops--; 00612 } 00613 00614 00615 00616 // *************** Sample *************** 00617 // * 00618 00634 Sample::Sample(File* pFile, RIFF::List* waveList, unsigned long WavePoolOffset) : Resource(pFile, waveList) { 00635 pWaveList = waveList; 00636 ulWavePoolOffset = WavePoolOffset - LIST_HEADER_SIZE; 00637 pCkFormat = waveList->GetSubChunk(CHUNK_ID_FMT); 00638 pCkData = waveList->GetSubChunk(CHUNK_ID_DATA); 00639 if (pCkFormat) { 00640 // common fields 00641 FormatTag = pCkFormat->ReadUint16(); 00642 Channels = pCkFormat->ReadUint16(); 00643 SamplesPerSecond = pCkFormat->ReadUint32(); 00644 AverageBytesPerSecond = pCkFormat->ReadUint32(); 00645 BlockAlign = pCkFormat->ReadUint16(); 00646 // PCM format specific 00647 if (FormatTag == DLS_WAVE_FORMAT_PCM) { 00648 BitDepth = pCkFormat->ReadUint16(); 00649 FrameSize = (BitDepth / 8) * Channels; 00650 } else { // unsupported sample data format 00651 BitDepth = 0; 00652 FrameSize = 0; 00653 } 00654 } else { // 'fmt' chunk missing 00655 FormatTag = DLS_WAVE_FORMAT_PCM; 00656 BitDepth = 16; 00657 Channels = 1; 00658 SamplesPerSecond = 44100; 00659 AverageBytesPerSecond = (BitDepth / 8) * SamplesPerSecond * Channels; 00660 FrameSize = (BitDepth / 8) * Channels; 00661 BlockAlign = FrameSize; 00662 } 00663 SamplesTotal = (pCkData) ? (FormatTag == DLS_WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize 00664 : 0 00665 : 0; 00666 } 00667 00673 Sample::~Sample() { 00674 RIFF::List* pParent = pWaveList->GetParent(); 00675 pParent->DeleteSubChunk(pWaveList); 00676 } 00677 00704 void* Sample::LoadSampleData() { 00705 return (pCkData) ? pCkData->LoadChunkData() : NULL; 00706 } 00707 00713 void Sample::ReleaseSampleData() { 00714 if (pCkData) pCkData->ReleaseChunkData(); 00715 } 00716 00727 unsigned long Sample::GetSize() { 00728 if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0; 00729 return (pCkData) ? pCkData->GetSize() / FrameSize : 0; 00730 } 00731 00760 void Sample::Resize(int iNewSize) { 00761 if (FormatTag != DLS_WAVE_FORMAT_PCM) throw Exception("Sample's format is not DLS_WAVE_FORMAT_PCM"); 00762 if (iNewSize < 1) throw Exception("Sample size must be at least one sample point"); 00763 const int iSizeInBytes = iNewSize * FrameSize; 00764 pCkData = pWaveList->GetSubChunk(CHUNK_ID_DATA); 00765 if (pCkData) pCkData->Resize(iSizeInBytes); 00766 else pCkData = pWaveList->AddSubChunk(CHUNK_ID_DATA, iSizeInBytes); 00767 } 00768 00785 unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) { 00786 if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format 00787 if (!pCkData) throw Exception("No data chunk created for sample yet, call Sample::Resize() to create one"); 00788 unsigned long orderedBytes = SampleCount * FrameSize; 00789 unsigned long result = pCkData->SetPos(orderedBytes, Whence); 00790 return (result == orderedBytes) ? SampleCount 00791 : result / FrameSize; 00792 } 00793 00803 unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) { 00804 if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format 00805 return pCkData->Read(pBuffer, SampleCount, FrameSize); // FIXME: channel inversion due to endian correction? 00806 } 00807 00823 unsigned long Sample::Write(void* pBuffer, unsigned long SampleCount) { 00824 if (FormatTag != DLS_WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format 00825 if (GetSize() < SampleCount) throw Exception("Could not write sample data, current sample size to small"); 00826 return pCkData->Write(pBuffer, SampleCount, FrameSize); // FIXME: channel inversion due to endian correction? 00827 } 00828 00836 void Sample::UpdateChunks() { 00837 if (FormatTag != DLS_WAVE_FORMAT_PCM) 00838 throw Exception("Could not save sample, only PCM format is supported"); 00839 // we refuse to do anything if not sample wave form was provided yet 00840 if (!pCkData) 00841 throw Exception("Could not save sample, there is no sample data to save"); 00842 // update chunks of base class as well 00843 Resource::UpdateChunks(); 00844 // make sure 'fmt' chunk exists 00845 RIFF::Chunk* pCkFormat = pWaveList->GetSubChunk(CHUNK_ID_FMT); 00846 if (!pCkFormat) pCkFormat = pWaveList->AddSubChunk(CHUNK_ID_FMT, 16); // assumes PCM format 00847 uint8_t* pData = (uint8_t*) pCkFormat->LoadChunkData(); 00848 // update 'fmt' chunk 00849 store16(&pData[0], FormatTag); 00850 store16(&pData[2], Channels); 00851 store32(&pData[4], SamplesPerSecond); 00852 store32(&pData[8], AverageBytesPerSecond); 00853 store16(&pData[12], BlockAlign); 00854 store16(&pData[14], BitDepth); // assuming PCM format 00855 } 00856 00857 00858 00859 // *************** Region *************** 00860 // * 00861 00862 Region::Region(Instrument* pInstrument, RIFF::List* rgnList) : Resource(pInstrument, rgnList), Articulator(rgnList), Sampler(rgnList) { 00863 pCkRegion = rgnList; 00864 00865 // articulation informations 00866 RIFF::Chunk* rgnh = rgnList->GetSubChunk(CHUNK_ID_RGNH); 00867 if (rgnh) { 00868 rgnh->Read(&KeyRange, 2, 2); 00869 rgnh->Read(&VelocityRange, 2, 2); 00870 FormatOptionFlags = rgnh->ReadUint16(); 00871 KeyGroup = rgnh->ReadUint16(); 00872 // Layer is optional 00873 if (rgnh->RemainingBytes() >= sizeof(uint16_t)) { 00874 rgnh->Read(&Layer, 1, sizeof(uint16_t)); 00875 } else Layer = 0; 00876 } else { // 'rgnh' chunk is missing 00877 KeyRange.low = 0; 00878 KeyRange.high = 127; 00879 VelocityRange.low = 0; 00880 VelocityRange.high = 127; 00881 FormatOptionFlags = F_RGN_OPTION_SELFNONEXCLUSIVE; 00882 KeyGroup = 0; 00883 Layer = 0; 00884 } 00885 SelfNonExclusive = FormatOptionFlags & F_RGN_OPTION_SELFNONEXCLUSIVE; 00886 00887 // sample informations 00888 RIFF::Chunk* wlnk = rgnList->GetSubChunk(CHUNK_ID_WLNK); 00889 if (wlnk) { 00890 WaveLinkOptionFlags = wlnk->ReadUint16(); 00891 PhaseGroup = wlnk->ReadUint16(); 00892 Channel = wlnk->ReadUint32(); 00893 WavePoolTableIndex = wlnk->ReadUint32(); 00894 } else { // 'wlnk' chunk is missing 00895 WaveLinkOptionFlags = 0; 00896 PhaseGroup = 0; 00897 Channel = 0; // mono 00898 WavePoolTableIndex = 0; // first entry in wave pool table 00899 } 00900 PhaseMaster = WaveLinkOptionFlags & F_WAVELINK_PHASE_MASTER; 00901 MultiChannel = WaveLinkOptionFlags & F_WAVELINK_MULTICHANNEL; 00902 00903 pSample = NULL; 00904 } 00905 00910 Region::~Region() { 00911 RIFF::List* pParent = pCkRegion->GetParent(); 00912 pParent->DeleteSubChunk(pCkRegion); 00913 } 00914 00915 Sample* Region::GetSample() { 00916 if (pSample) return pSample; 00917 File* file = (File*) GetParent()->GetParent(); 00918 unsigned long soughtoffset = file->pWavePoolTable[WavePoolTableIndex]; 00919 Sample* sample = file->GetFirstSample(); 00920 while (sample) { 00921 if (sample->ulWavePoolOffset == soughtoffset) return (pSample = sample); 00922 sample = file->GetNextSample(); 00923 } 00924 return NULL; 00925 } 00926 00932 void Region::SetSample(Sample* pSample) { 00933 this->pSample = pSample; 00934 WavePoolTableIndex = 0; // we update this offset when we Save() 00935 } 00936 00944 void Region::SetKeyRange(uint16_t Low, uint16_t High) { 00945 KeyRange.low = Low; 00946 KeyRange.high = High; 00947 00948 // make sure regions are already loaded 00949 Instrument* pInstrument = (Instrument*) GetParent(); 00950 if (!pInstrument->pRegions) pInstrument->LoadRegions(); 00951 if (!pInstrument->pRegions) return; 00952 00953 // find the r which is the first one to the right of this region 00954 // at its new position 00955 Region* r = NULL; 00956 Region* prev_region = NULL; 00957 for ( 00958 Instrument::RegionList::iterator iter = pInstrument->pRegions->begin(); 00959 iter != pInstrument->pRegions->end(); iter++ 00960 ) { 00961 if ((*iter)->KeyRange.low > this->KeyRange.low) { 00962 r = *iter; 00963 break; 00964 } 00965 prev_region = *iter; 00966 } 00967 00968 // place this region before r if it's not already there 00969 if (prev_region != this) pInstrument->MoveRegion(this, r); 00970 } 00971 00978 void Region::UpdateChunks() { 00979 // make sure 'rgnh' chunk exists 00980 RIFF::Chunk* rgnh = pCkRegion->GetSubChunk(CHUNK_ID_RGNH); 00981 if (!rgnh) rgnh = pCkRegion->AddSubChunk(CHUNK_ID_RGNH, Layer ? 14 : 12); 00982 uint8_t* pData = (uint8_t*) rgnh->LoadChunkData(); 00983 FormatOptionFlags = (SelfNonExclusive) 00984 ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE 00985 : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE); 00986 // update 'rgnh' chunk 00987 store16(&pData[0], KeyRange.low); 00988 store16(&pData[2], KeyRange.high); 00989 store16(&pData[4], VelocityRange.low); 00990 store16(&pData[6], VelocityRange.high); 00991 store16(&pData[8], FormatOptionFlags); 00992 store16(&pData[10], KeyGroup); 00993 if (rgnh->GetSize() >= 14) store16(&pData[12], Layer); 00994 00995 // update chunks of base classes as well (but skip Resource, 00996 // as a rgn doesn't seem to have dlid and INFO chunks) 00997 Articulator::UpdateChunks(); 00998 Sampler::UpdateChunks(); 00999 01000 // make sure 'wlnk' chunk exists 01001 RIFF::Chunk* wlnk = pCkRegion->GetSubChunk(CHUNK_ID_WLNK); 01002 if (!wlnk) wlnk = pCkRegion->AddSubChunk(CHUNK_ID_WLNK, 12); 01003 pData = (uint8_t*) wlnk->LoadChunkData(); 01004 WaveLinkOptionFlags = (PhaseMaster) 01005 ? WaveLinkOptionFlags | F_WAVELINK_PHASE_MASTER 01006 : WaveLinkOptionFlags & (~F_WAVELINK_PHASE_MASTER); 01007 WaveLinkOptionFlags = (MultiChannel) 01008 ? WaveLinkOptionFlags | F_WAVELINK_MULTICHANNEL 01009 : WaveLinkOptionFlags & (~F_WAVELINK_MULTICHANNEL); 01010 // get sample's wave pool table index 01011 int index = -1; 01012 File* pFile = (File*) GetParent()->GetParent(); 01013 if (pFile->pSamples) { 01014 File::SampleList::iterator iter = pFile->pSamples->begin(); 01015 File::SampleList::iterator end = pFile->pSamples->end(); 01016 for (int i = 0; iter != end; ++iter, i++) { 01017 if (*iter == pSample) { 01018 index = i; 01019 break; 01020 } 01021 } 01022 } 01023 WavePoolTableIndex = index; 01024 // update 'wlnk' chunk 01025 store16(&pData[0], WaveLinkOptionFlags); 01026 store16(&pData[2], PhaseGroup); 01027 store32(&pData[4], Channel); 01028 store32(&pData[8], WavePoolTableIndex); 01029 } 01030 01031 01032 01033 // *************** Instrument *************** 01034 // * 01035 01049 Instrument::Instrument(File* pFile, RIFF::List* insList) : Resource(pFile, insList), Articulator(insList) { 01050 pCkInstrument = insList; 01051 01052 midi_locale_t locale; 01053 RIFF::Chunk* insh = pCkInstrument->GetSubChunk(CHUNK_ID_INSH); 01054 if (insh) { 01055 Regions = insh->ReadUint32(); 01056 insh->Read(&locale, 2, 4); 01057 } else { // 'insh' chunk missing 01058 Regions = 0; 01059 locale.bank = 0; 01060 locale.instrument = 0; 01061 } 01062 01063 MIDIProgram = locale.instrument; 01064 IsDrum = locale.bank & DRUM_TYPE_MASK; 01065 MIDIBankCoarse = (uint8_t) MIDI_BANK_COARSE(locale.bank); 01066 MIDIBankFine = (uint8_t) MIDI_BANK_FINE(locale.bank); 01067 MIDIBank = MIDI_BANK_MERGE(MIDIBankCoarse, MIDIBankFine); 01068 01069 pRegions = NULL; 01070 } 01071 01072 Region* Instrument::GetFirstRegion() { 01073 if (!pRegions) LoadRegions(); 01074 if (!pRegions) return NULL; 01075 RegionsIterator = pRegions->begin(); 01076 return (RegionsIterator != pRegions->end()) ? *RegionsIterator : NULL; 01077 } 01078 01079 Region* Instrument::GetNextRegion() { 01080 if (!pRegions) return NULL; 01081 RegionsIterator++; 01082 return (RegionsIterator != pRegions->end()) ? *RegionsIterator : NULL; 01083 } 01084 01085 void Instrument::LoadRegions() { 01086 if (!pRegions) pRegions = new RegionList; 01087 RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); 01088 if (lrgn) { 01089 uint32_t regionCkType = (lrgn->GetSubList(LIST_TYPE_RGN2)) ? LIST_TYPE_RGN2 : LIST_TYPE_RGN; // prefer regions level 2 01090 RIFF::List* rgn = lrgn->GetFirstSubList(); 01091 while (rgn) { 01092 if (rgn->GetListType() == regionCkType) { 01093 pRegions->push_back(new Region(this, rgn)); 01094 } 01095 rgn = lrgn->GetNextSubList(); 01096 } 01097 } 01098 } 01099 01100 Region* Instrument::AddRegion() { 01101 if (!pRegions) LoadRegions(); 01102 RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); 01103 if (!lrgn) lrgn = pCkInstrument->AddSubList(LIST_TYPE_LRGN); 01104 RIFF::List* rgn = lrgn->AddSubList(LIST_TYPE_RGN); 01105 Region* pNewRegion = new Region(this, rgn); 01106 pRegions->push_back(pNewRegion); 01107 Regions = pRegions->size(); 01108 return pNewRegion; 01109 } 01110 01111 void Instrument::MoveRegion(Region* pSrc, Region* pDst) { 01112 RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); 01113 lrgn->MoveSubChunk(pSrc->pCkRegion, pDst ? pDst->pCkRegion : 0); 01114 01115 pRegions->remove(pSrc); 01116 RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pDst); 01117 pRegions->insert(iter, pSrc); 01118 } 01119 01120 void Instrument::DeleteRegion(Region* pRegion) { 01121 if (!pRegions) return; 01122 RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion); 01123 if (iter == pRegions->end()) return; 01124 pRegions->erase(iter); 01125 Regions = pRegions->size(); 01126 delete pRegion; 01127 } 01128 01135 void Instrument::UpdateChunks() { 01136 // first update base classes' chunks 01137 Resource::UpdateChunks(); 01138 Articulator::UpdateChunks(); 01139 // make sure 'insh' chunk exists 01140 RIFF::Chunk* insh = pCkInstrument->GetSubChunk(CHUNK_ID_INSH); 01141 if (!insh) insh = pCkInstrument->AddSubChunk(CHUNK_ID_INSH, 12); 01142 uint8_t* pData = (uint8_t*) insh->LoadChunkData(); 01143 // update 'insh' chunk 01144 Regions = (pRegions) ? pRegions->size() : 0; 01145 midi_locale_t locale; 01146 locale.instrument = MIDIProgram; 01147 locale.bank = MIDI_BANK_ENCODE(MIDIBankCoarse, MIDIBankFine); 01148 locale.bank = (IsDrum) ? locale.bank | DRUM_TYPE_MASK : locale.bank & (~DRUM_TYPE_MASK); 01149 MIDIBank = MIDI_BANK_MERGE(MIDIBankCoarse, MIDIBankFine); // just a sync, when we're at it 01150 store32(&pData[0], Regions); 01151 store32(&pData[4], locale.bank); 01152 store32(&pData[8], locale.instrument); 01153 // update Region's chunks 01154 if (!pRegions) return; 01155 RegionList::iterator iter = pRegions->begin(); 01156 RegionList::iterator end = pRegions->end(); 01157 for (; iter != end; ++iter) { 01158 (*iter)->UpdateChunks(); 01159 } 01160 } 01161 01167 Instrument::~Instrument() { 01168 if (pRegions) { 01169 RegionList::iterator iter = pRegions->begin(); 01170 RegionList::iterator end = pRegions->end(); 01171 while (iter != end) { 01172 delete *iter; 01173 iter++; 01174 } 01175 delete pRegions; 01176 } 01177 // remove instrument's chunks 01178 RIFF::List* pParent = pCkInstrument->GetParent(); 01179 pParent->DeleteSubChunk(pCkInstrument); 01180 } 01181 01182 01183 01184 // *************** File *************** 01185 // * 01186 01193 File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) { 01194 pRIFF->SetByteOrder(RIFF::endian_little); 01195 pVersion = new version_t; 01196 pVersion->major = 0; 01197 pVersion->minor = 0; 01198 pVersion->release = 0; 01199 pVersion->build = 0; 01200 01201 Instruments = 0; 01202 WavePoolCount = 0; 01203 pWavePoolTable = NULL; 01204 pWavePoolTableHi = NULL; 01205 WavePoolHeaderSize = 8; 01206 01207 pSamples = NULL; 01208 pInstruments = NULL; 01209 01210 b64BitWavePoolOffsets = false; 01211 } 01212 01222 File::File(RIFF::File* pRIFF) : Resource(NULL, pRIFF) { 01223 if (!pRIFF) throw DLS::Exception("NULL pointer reference to RIFF::File object."); 01224 this->pRIFF = pRIFF; 01225 01226 RIFF::Chunk* ckVersion = pRIFF->GetSubChunk(CHUNK_ID_VERS); 01227 if (ckVersion) { 01228 pVersion = new version_t; 01229 ckVersion->Read(pVersion, 4, 2); 01230 } 01231 else pVersion = NULL; 01232 01233 RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH); 01234 if (!colh) throw DLS::Exception("Mandatory chunks in RIFF list chunk not found."); 01235 Instruments = colh->ReadUint32(); 01236 01237 RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL); 01238 if (!ptbl) { // pool table is missing - this is probably an ".art" file 01239 WavePoolCount = 0; 01240 pWavePoolTable = NULL; 01241 pWavePoolTableHi = NULL; 01242 WavePoolHeaderSize = 8; 01243 b64BitWavePoolOffsets = false; 01244 } else { 01245 WavePoolHeaderSize = ptbl->ReadUint32(); 01246 WavePoolCount = ptbl->ReadUint32(); 01247 pWavePoolTable = new uint32_t[WavePoolCount]; 01248 pWavePoolTableHi = new uint32_t[WavePoolCount]; 01249 ptbl->SetPos(WavePoolHeaderSize); 01250 01251 // Check for 64 bit offsets (used in gig v3 files) 01252 b64BitWavePoolOffsets = (ptbl->GetSize() - WavePoolHeaderSize == WavePoolCount * 8); 01253 if (b64BitWavePoolOffsets) { 01254 for (int i = 0 ; i < WavePoolCount ; i++) { 01255 pWavePoolTableHi[i] = ptbl->ReadUint32(); 01256 pWavePoolTable[i] = ptbl->ReadUint32(); 01257 if (pWavePoolTable[i] & 0x80000000) 01258 throw DLS::Exception("Files larger than 2 GB not yet supported"); 01259 } 01260 } else { // conventional 32 bit offsets 01261 ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t)); 01262 for (int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0; 01263 } 01264 } 01265 01266 pSamples = NULL; 01267 pInstruments = NULL; 01268 } 01269 01270 File::~File() { 01271 if (pInstruments) { 01272 InstrumentList::iterator iter = pInstruments->begin(); 01273 InstrumentList::iterator end = pInstruments->end(); 01274 while (iter != end) { 01275 delete *iter; 01276 iter++; 01277 } 01278 delete pInstruments; 01279 } 01280 01281 if (pSamples) { 01282 SampleList::iterator iter = pSamples->begin(); 01283 SampleList::iterator end = pSamples->end(); 01284 while (iter != end) { 01285 delete *iter; 01286 iter++; 01287 } 01288 delete pSamples; 01289 } 01290 01291 if (pWavePoolTable) delete[] pWavePoolTable; 01292 if (pWavePoolTableHi) delete[] pWavePoolTableHi; 01293 if (pVersion) delete pVersion; 01294 for (std::list<RIFF::File*>::iterator i = ExtensionFiles.begin() ; i != ExtensionFiles.end() ; i++) 01295 delete *i; 01296 } 01297 01298 Sample* File::GetFirstSample() { 01299 if (!pSamples) LoadSamples(); 01300 if (!pSamples) return NULL; 01301 SamplesIterator = pSamples->begin(); 01302 return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL; 01303 } 01304 01305 Sample* File::GetNextSample() { 01306 if (!pSamples) return NULL; 01307 SamplesIterator++; 01308 return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL; 01309 } 01310 01311 void File::LoadSamples() { 01312 if (!pSamples) pSamples = new SampleList; 01313 RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL); 01314 if (wvpl) { 01315 unsigned long wvplFileOffset = wvpl->GetFilePos(); 01316 RIFF::List* wave = wvpl->GetFirstSubList(); 01317 while (wave) { 01318 if (wave->GetListType() == LIST_TYPE_WAVE) { 01319 unsigned long waveFileOffset = wave->GetFilePos(); 01320 pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset)); 01321 } 01322 wave = wvpl->GetNextSubList(); 01323 } 01324 } 01325 else { // Seen a dwpl list chunk instead of a wvpl list chunk in some file (officially not DLS compliant) 01326 RIFF::List* dwpl = pRIFF->GetSubList(LIST_TYPE_DWPL); 01327 if (dwpl) { 01328 unsigned long dwplFileOffset = dwpl->GetFilePos(); 01329 RIFF::List* wave = dwpl->GetFirstSubList(); 01330 while (wave) { 01331 if (wave->GetListType() == LIST_TYPE_WAVE) { 01332 unsigned long waveFileOffset = wave->GetFilePos(); 01333 pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset)); 01334 } 01335 wave = dwpl->GetNextSubList(); 01336 } 01337 } 01338 } 01339 } 01340 01348 Sample* File::AddSample() { 01349 if (!pSamples) LoadSamples(); 01350 __ensureMandatoryChunksExist(); 01351 RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL); 01352 // create new Sample object and its respective 'wave' list chunk 01353 RIFF::List* wave = wvpl->AddSubList(LIST_TYPE_WAVE); 01354 Sample* pSample = new Sample(this, wave, 0 /*arbitrary value, we update offsets when we save*/); 01355 pSamples->push_back(pSample); 01356 return pSample; 01357 } 01358 01366 void File::DeleteSample(Sample* pSample) { 01367 if (!pSamples) return; 01368 SampleList::iterator iter = find(pSamples->begin(), pSamples->end(), pSample); 01369 if (iter == pSamples->end()) return; 01370 pSamples->erase(iter); 01371 delete pSample; 01372 } 01373 01374 Instrument* File::GetFirstInstrument() { 01375 if (!pInstruments) LoadInstruments(); 01376 if (!pInstruments) return NULL; 01377 InstrumentsIterator = pInstruments->begin(); 01378 return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL; 01379 } 01380 01381 Instrument* File::GetNextInstrument() { 01382 if (!pInstruments) return NULL; 01383 InstrumentsIterator++; 01384 return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL; 01385 } 01386 01387 void File::LoadInstruments() { 01388 if (!pInstruments) pInstruments = new InstrumentList; 01389 RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS); 01390 if (lstInstruments) { 01391 RIFF::List* lstInstr = lstInstruments->GetFirstSubList(); 01392 while (lstInstr) { 01393 if (lstInstr->GetListType() == LIST_TYPE_INS) { 01394 pInstruments->push_back(new Instrument(this, lstInstr)); 01395 } 01396 lstInstr = lstInstruments->GetNextSubList(); 01397 } 01398 } 01399 } 01400 01408 Instrument* File::AddInstrument() { 01409 if (!pInstruments) LoadInstruments(); 01410 __ensureMandatoryChunksExist(); 01411 RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS); 01412 RIFF::List* lstInstr = lstInstruments->AddSubList(LIST_TYPE_INS); 01413 Instrument* pInstrument = new Instrument(this, lstInstr); 01414 pInstruments->push_back(pInstrument); 01415 return pInstrument; 01416 } 01417 01425 void File::DeleteInstrument(Instrument* pInstrument) { 01426 if (!pInstruments) return; 01427 InstrumentList::iterator iter = find(pInstruments->begin(), pInstruments->end(), pInstrument); 01428 if (iter == pInstruments->end()) return; 01429 pInstruments->erase(iter); 01430 delete pInstrument; 01431 } 01432 01440 void File::UpdateChunks() { 01441 // first update base class's chunks 01442 Resource::UpdateChunks(); 01443 01444 // if version struct exists, update 'vers' chunk 01445 if (pVersion) { 01446 RIFF::Chunk* ckVersion = pRIFF->GetSubChunk(CHUNK_ID_VERS); 01447 if (!ckVersion) ckVersion = pRIFF->AddSubChunk(CHUNK_ID_VERS, 8); 01448 uint8_t* pData = (uint8_t*) ckVersion->LoadChunkData(); 01449 store16(&pData[0], pVersion->minor); 01450 store16(&pData[2], pVersion->major); 01451 store16(&pData[4], pVersion->build); 01452 store16(&pData[6], pVersion->release); 01453 } 01454 01455 // update 'colh' chunk 01456 Instruments = (pInstruments) ? pInstruments->size() : 0; 01457 RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH); 01458 if (!colh) colh = pRIFF->AddSubChunk(CHUNK_ID_COLH, 4); 01459 uint8_t* pData = (uint8_t*) colh->LoadChunkData(); 01460 store32(pData, Instruments); 01461 01462 // update instrument's chunks 01463 if (pInstruments) { 01464 InstrumentList::iterator iter = pInstruments->begin(); 01465 InstrumentList::iterator end = pInstruments->end(); 01466 for (; iter != end; ++iter) { 01467 (*iter)->UpdateChunks(); 01468 } 01469 } 01470 01471 // update 'ptbl' chunk 01472 const int iSamples = (pSamples) ? pSamples->size() : 0; 01473 const int iPtblOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4; 01474 RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL); 01475 if (!ptbl) ptbl = pRIFF->AddSubChunk(CHUNK_ID_PTBL, 1 /*anything, we'll resize*/); 01476 const int iPtblSize = WavePoolHeaderSize + iPtblOffsetSize * iSamples; 01477 ptbl->Resize(iPtblSize); 01478 pData = (uint8_t*) ptbl->LoadChunkData(); 01479 WavePoolCount = iSamples; 01480 store32(&pData[4], WavePoolCount); 01481 // we actually update the sample offsets in the pool table when we Save() 01482 memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize); 01483 01484 // update sample's chunks 01485 if (pSamples) { 01486 SampleList::iterator iter = pSamples->begin(); 01487 SampleList::iterator end = pSamples->end(); 01488 for (; iter != end; ++iter) { 01489 (*iter)->UpdateChunks(); 01490 } 01491 } 01492 } 01493 01507 void File::Save(const String& Path) { 01508 UpdateChunks(); 01509 pRIFF->Save(Path); 01510 __UpdateWavePoolTableChunk(); 01511 } 01512 01522 void File::Save() { 01523 UpdateChunks(); 01524 pRIFF->Save(); 01525 __UpdateWavePoolTableChunk(); 01526 } 01527 01533 void File::__ensureMandatoryChunksExist() { 01534 // enusre 'lins' list chunk exists (mandatory for instrument definitions) 01535 RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS); 01536 if (!lstInstruments) pRIFF->AddSubList(LIST_TYPE_LINS); 01537 // ensure 'ptbl' chunk exists (mandatory for samples) 01538 RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL); 01539 if (!ptbl) { 01540 const int iOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4; 01541 ptbl = pRIFF->AddSubChunk(CHUNK_ID_PTBL, WavePoolHeaderSize + iOffsetSize); 01542 } 01543 // enusre 'wvpl' list chunk exists (mandatory for samples) 01544 RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL); 01545 if (!wvpl) pRIFF->AddSubList(LIST_TYPE_WVPL); 01546 } 01547 01557 void File::__UpdateWavePoolTableChunk() { 01558 __UpdateWavePoolTable(); 01559 RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL); 01560 const int iOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4; 01561 // check if 'ptbl' chunk is large enough 01562 WavePoolCount = (pSamples) ? pSamples->size() : 0; 01563 const unsigned long ulRequiredSize = WavePoolHeaderSize + iOffsetSize * WavePoolCount; 01564 if (ptbl->GetSize() < ulRequiredSize) throw Exception("Fatal error, 'ptbl' chunk too small"); 01565 // save the 'ptbl' chunk's current read/write position 01566 unsigned long ulOriginalPos = ptbl->GetPos(); 01567 // update headers 01568 ptbl->SetPos(0); 01569 uint32_t tmp = WavePoolHeaderSize; 01570 ptbl->WriteUint32(&tmp); 01571 tmp = WavePoolCount; 01572 ptbl->WriteUint32(&tmp); 01573 // update offsets 01574 ptbl->SetPos(WavePoolHeaderSize); 01575 if (b64BitWavePoolOffsets) { 01576 for (int i = 0 ; i < WavePoolCount ; i++) { 01577 tmp = pWavePoolTableHi[i]; 01578 ptbl->WriteUint32(&tmp); 01579 tmp = pWavePoolTable[i]; 01580 ptbl->WriteUint32(&tmp); 01581 } 01582 } else { // conventional 32 bit offsets 01583 for (int i = 0 ; i < WavePoolCount ; i++) { 01584 tmp = pWavePoolTable[i]; 01585 ptbl->WriteUint32(&tmp); 01586 } 01587 } 01588 // restore 'ptbl' chunk's original read/write position 01589 ptbl->SetPos(ulOriginalPos); 01590 } 01591 01597 void File::__UpdateWavePoolTable() { 01598 WavePoolCount = (pSamples) ? pSamples->size() : 0; 01599 // resize wave pool table arrays 01600 if (pWavePoolTable) delete[] pWavePoolTable; 01601 if (pWavePoolTableHi) delete[] pWavePoolTableHi; 01602 pWavePoolTable = new uint32_t[WavePoolCount]; 01603 pWavePoolTableHi = new uint32_t[WavePoolCount]; 01604 if (!pSamples) return; 01605 // update offsets int wave pool table 01606 RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL); 01607 uint64_t wvplFileOffset = wvpl->GetFilePos(); 01608 if (b64BitWavePoolOffsets) { 01609 SampleList::iterator iter = pSamples->begin(); 01610 SampleList::iterator end = pSamples->end(); 01611 for (int i = 0 ; iter != end ; ++iter, i++) { 01612 uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - wvplFileOffset - LIST_HEADER_SIZE; 01613 (*iter)->ulWavePoolOffset = _64BitOffset; 01614 pWavePoolTableHi[i] = (uint32_t) (_64BitOffset >> 32); 01615 pWavePoolTable[i] = (uint32_t) _64BitOffset; 01616 } 01617 } else { // conventional 32 bit offsets 01618 SampleList::iterator iter = pSamples->begin(); 01619 SampleList::iterator end = pSamples->end(); 01620 for (int i = 0 ; iter != end ; ++iter, i++) { 01621 uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - wvplFileOffset - LIST_HEADER_SIZE; 01622 (*iter)->ulWavePoolOffset = _64BitOffset; 01623 pWavePoolTable[i] = (uint32_t) _64BitOffset; 01624 } 01625 } 01626 } 01627 01628 01629 01630 // *************** Exception *************** 01631 // * 01632 01633 Exception::Exception(String Message) : RIFF::Exception(Message) { 01634 } 01635 01636 void Exception::PrintMessage() { 01637 std::cout << "DLS::Exception: " << Message << std::endl; 01638 } 01639 01640 01641 // *************** functions *************** 01642 // * 01643 01649 String libraryName() { 01650 return PACKAGE; 01651 } 01652 01657 String libraryVersion() { 01658 return VERSION; 01659 } 01660 01661 } // namespace DLS