--- libgig/trunk/src/DLS.cpp 2007/05/12 12:39:25 1180 +++ libgig/trunk/src/DLS.cpp 2008/03/06 20:42:22 1713 @@ -23,8 +23,15 @@ #include "DLS.h" +#include #include +#ifdef __APPLE__ +#include +#elif defined(HAVE_UUID_UUID_H) +#include +#endif + #include "helper.h" // macros to decode connection transforms @@ -233,7 +240,7 @@ * @param list - pointer to a list chunk which contains an INFO list chunk */ Info::Info(RIFF::List* list) { - FixedStringLengths = NULL; + pFixedStringLengths = NULL; pResourceListChunk = list; if (list) { RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO); @@ -262,6 +269,21 @@ Info::~Info() { } + /** + * Forces specific Info fields to be of a fixed length when being saved + * to a file. By default the respective RIFF chunk of an Info field + * will have a size analogue to its actual string length. With this + * method however this behavior can be overridden, allowing to force an + * arbitrary fixed size individually for each Info field. + * + * This method is used as a workaround for the gig format, not for DLS. + * + * @param lengths - NULL terminated array of string_length_t elements + */ + void Info::SetFixedStringLengths(const string_length_t* lengths) { + pFixedStringLengths = lengths; + } + /** @brief Load given INFO field. * * Load INFO field from INFO chunk with chunk ID \a ChunkID from INFO @@ -289,10 +311,11 @@ */ void Info::SaveString(uint32_t ChunkID, RIFF::List* lstINFO, const String& s, const String& sDefault) { int size = 0; - if (FixedStringLengths) { - for (int i = 0 ; FixedStringLengths[i].length ; i++) { - if (FixedStringLengths[i].chunkId == ChunkID) { - size = FixedStringLengths[i].length; + if (pFixedStringLengths) { + for (int i = 0 ; pFixedStringLengths[i].length ; i++) { + if (pFixedStringLengths[i].chunkId == ChunkID) { + size = pFixedStringLengths[i].length; + break; } } } @@ -407,9 +430,63 @@ */ void Resource::UpdateChunks() { pInfo->UpdateChunks(); - //TODO: save DLSID + + if (pDLSID) { + // make sure 'dlid' chunk exists + RIFF::Chunk* ckDLSID = pResourceList->GetSubChunk(CHUNK_ID_DLID); + if (!ckDLSID) ckDLSID = pResourceList->AddSubChunk(CHUNK_ID_DLID, 16); + uint8_t* pData = (uint8_t*)ckDLSID->LoadChunkData(); + // update 'dlid' chunk + store32(&pData[0], pDLSID->ulData1); + store16(&pData[4], pDLSID->usData2); + store16(&pData[6], pDLSID->usData3); + memcpy(&pData[8], pDLSID->abData, 8); + } } + /** + * Generates a new DLSID for the resource. + */ + void Resource::GenerateDLSID() { +#if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE) + + if (!pDLSID) pDLSID = new dlsid_t; + +#ifdef WIN32 + + UUID uuid; + UuidCreate(&uuid); + pDLSID->ulData1 = uuid.Data1; + pDLSID->usData2 = uuid.Data2; + pDLSID->usData3 = uuid.Data3; + memcpy(pDLSID->abData, uuid.Data4, 8); + +#elif defined(__APPLE__) + + CFUUIDRef uuidRef = CFUUIDCreate(NULL); + CFUUIDBytes uuid = CFUUIDGetUUIDBytes(uuidRef); + CFRelease(uuidRef); + pDLSID->ulData1 = uuid.byte0 | uuid.byte1 << 8 | uuid.byte2 << 16 | uuid.byte3 << 24; + pDLSID->usData2 = uuid.byte4 | uuid.byte5 << 8; + pDLSID->usData3 = uuid.byte6 | uuid.byte7 << 8; + pDLSID->abData[0] = uuid.byte8; + pDLSID->abData[1] = uuid.byte9; + pDLSID->abData[2] = uuid.byte10; + pDLSID->abData[3] = uuid.byte11; + pDLSID->abData[4] = uuid.byte12; + pDLSID->abData[5] = uuid.byte13; + pDLSID->abData[6] = uuid.byte14; + pDLSID->abData[7] = uuid.byte15; +#else + uuid_t uuid; + uuid_generate(uuid); + pDLSID->ulData1 = uuid[0] | uuid[1] << 8 | uuid[2] << 16 | uuid[3] << 24; + pDLSID->usData2 = uuid[4] | uuid[5] << 8; + pDLSID->usData3 = uuid[6] | uuid[7] << 8; + memcpy(pDLSID->abData, &uuid[8], 8); +#endif +#endif + } // *************** Sampler *************** @@ -426,8 +503,8 @@ SamplerOptions = wsmp->ReadUint32(); SampleLoops = wsmp->ReadUint32(); } else { // 'wsmp' chunk missing - uiHeaderSize = 0; - UnityNote = 64; + uiHeaderSize = 20; + UnityNote = 60; FineTune = 0; // +- 0 cents Gain = 0; // 0 dB SamplerOptions = F_WSMP_NO_COMPRESSION; @@ -451,6 +528,10 @@ if (pSampleLoops) delete[] pSampleLoops; } + void Sampler::SetGain(int32_t gain) { + Gain = gain; + } + /** * Apply all sample player options to the respective RIFF chunk. You * have to call File::Save() to make changes persistent. @@ -458,9 +539,11 @@ void Sampler::UpdateChunks() { // make sure 'wsmp' chunk exists RIFF::Chunk* wsmp = pParentList->GetSubChunk(CHUNK_ID_WSMP); + int wsmpSize = uiHeaderSize + SampleLoops * 16; if (!wsmp) { - uiHeaderSize = 20; - wsmp = pParentList->AddSubChunk(CHUNK_ID_WSMP, uiHeaderSize + SampleLoops * 16); + wsmp = pParentList->AddSubChunk(CHUNK_ID_WSMP, wsmpSize); + } else if (wsmp->GetSize() != wsmpSize) { + wsmp->Resize(wsmpSize); } uint8_t* pData = (uint8_t*) wsmp->LoadChunkData(); // update headers size @@ -488,7 +571,7 @@ /** * Adds a new sample loop with the provided loop definition. * - * @param - points to a loop definition that is to be copied + * @param pLoopDef - points to a loop definition that is to be copied */ void Sampler::AddSampleLoop(sample_loop_t* pLoopDef) { sample_loop_t* pNewLoops = new sample_loop_t[SampleLoops + 1]; @@ -852,6 +935,41 @@ } /** + * Modifies the key range of this Region and makes sure the respective + * chunks are in correct order. + * + * @param Low - lower end of key range + * @param High - upper end of key range + */ + void Region::SetKeyRange(uint16_t Low, uint16_t High) { + KeyRange.low = Low; + KeyRange.high = High; + + // make sure regions are already loaded + Instrument* pInstrument = (Instrument*) GetParent(); + if (!pInstrument->pRegions) pInstrument->LoadRegions(); + if (!pInstrument->pRegions) return; + + // find the r which is the first one to the right of this region + // at its new position + Region* r = NULL; + Region* prev_region = NULL; + for ( + Instrument::RegionList::iterator iter = pInstrument->pRegions->begin(); + iter != pInstrument->pRegions->end(); iter++ + ) { + if ((*iter)->KeyRange.low > this->KeyRange.low) { + r = *iter; + break; + } + prev_region = *iter; + } + + // place this region before r if it's not already there + if (prev_region != this) pInstrument->MoveRegion(this, r); + } + + /** * Apply Region settings to the respective RIFF chunks. You have to * call File::Save() to make changes persistent. * @@ -902,7 +1020,6 @@ } } } - if (index < 0) throw Exception("Could not save Region, could not find Region's sample"); WavePoolTableIndex = index; // update 'wlnk' chunk store16(&pData[0], WaveLinkOptionFlags); @@ -1074,6 +1191,7 @@ * a DLS file. */ File::File() : Resource(NULL, pRIFF = new RIFF::File(RIFF_TYPE_DLS)) { + pRIFF->SetByteOrder(RIFF::endian_little); pVersion = new version_t; pVersion->major = 0; pVersion->minor = 0;