2 |
* * |
* * |
3 |
* libgig - C++ cross-platform Gigasampler format file access library * |
* libgig - C++ cross-platform Gigasampler format file access library * |
4 |
* * |
* * |
5 |
* Copyright (C) 2003-2019 by Christian Schoenebeck * |
* Copyright (C) 2003-2021 by Christian Schoenebeck * |
6 |
* <cuse@users.sourceforge.net> * |
* <cuse@users.sourceforge.net> * |
7 |
* * |
* * |
8 |
* This library is free software; you can redistribute it and/or modify * |
* This library is free software; you can redistribute it and/or modify * |
209 |
if (lart) { |
if (lart) { |
210 |
uint32_t artCkType = (lart->GetListType() == LIST_TYPE_LAR2) ? CHUNK_ID_ART2 |
uint32_t artCkType = (lart->GetListType() == LIST_TYPE_LAR2) ? CHUNK_ID_ART2 |
211 |
: CHUNK_ID_ARTL; |
: CHUNK_ID_ARTL; |
212 |
RIFF::Chunk* art = lart->GetFirstSubChunk(); |
size_t i = 0; |
213 |
while (art) { |
for (RIFF::Chunk* art = lart->GetSubChunkAt(i); art; |
214 |
|
art = lart->GetSubChunkAt(++i)) |
215 |
|
{ |
216 |
if (art->GetChunkID() == artCkType) { |
if (art->GetChunkID() == artCkType) { |
217 |
if (!pArticulations) pArticulations = new ArticulationList; |
if (!pArticulations) pArticulations = new ArticulationList; |
218 |
pArticulations->push_back(new Articulation(art)); |
pArticulations->push_back(new Articulation(art)); |
219 |
} |
} |
|
art = lart->GetNextSubChunk(); |
|
220 |
} |
} |
221 |
} |
} |
222 |
} |
} |
557 |
} |
} |
558 |
|
|
559 |
void Resource::GenerateDLSID(dlsid_t* pDLSID) { |
void Resource::GenerateDLSID(dlsid_t* pDLSID) { |
|
#if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE) |
|
560 |
#ifdef WIN32 |
#ifdef WIN32 |
561 |
UUID uuid; |
UUID uuid; |
562 |
UuidCreate(&uuid); |
UuidCreate(&uuid); |
581 |
pDLSID->abData[5] = uuid.byte13; |
pDLSID->abData[5] = uuid.byte13; |
582 |
pDLSID->abData[6] = uuid.byte14; |
pDLSID->abData[6] = uuid.byte14; |
583 |
pDLSID->abData[7] = uuid.byte15; |
pDLSID->abData[7] = uuid.byte15; |
584 |
#else |
#elif defined(HAVE_UUID_GENERATE) |
585 |
uuid_t uuid; |
uuid_t uuid; |
586 |
uuid_generate(uuid); |
uuid_generate(uuid); |
587 |
pDLSID->ulData1 = uuid[0] | uuid[1] << 8 | uuid[2] << 16 | uuid[3] << 24; |
pDLSID->ulData1 = uuid[0] | uuid[1] << 8 | uuid[2] << 16 | uuid[3] << 24; |
588 |
pDLSID->usData2 = uuid[4] | uuid[5] << 8; |
pDLSID->usData2 = uuid[4] | uuid[5] << 8; |
589 |
pDLSID->usData3 = uuid[6] | uuid[7] << 8; |
pDLSID->usData3 = uuid[6] | uuid[7] << 8; |
590 |
memcpy(pDLSID->abData, &uuid[8], 8); |
memcpy(pDLSID->abData, &uuid[8], 8); |
591 |
#endif |
#else |
592 |
|
# error "Missing support for uuid generation" |
593 |
#endif |
#endif |
594 |
} |
} |
595 |
|
|
1358 |
pRegions = NULL; |
pRegions = NULL; |
1359 |
} |
} |
1360 |
|
|
1361 |
|
/** |
1362 |
|
* Returns Region at supplied @a pos position within the region list of |
1363 |
|
* this instrument. If supplied @a pos is out of bounds then @c NULL is |
1364 |
|
* returned. |
1365 |
|
* |
1366 |
|
* @param pos - position of sought Region in region list |
1367 |
|
* @returns pointer address to requested region or @c NULL if @a pos is |
1368 |
|
* out of bounds |
1369 |
|
*/ |
1370 |
|
Region* Instrument::GetRegionAt(size_t pos) { |
1371 |
|
if (!pRegions) LoadRegions(); |
1372 |
|
if (!pRegions) return NULL; |
1373 |
|
if (pos >= pRegions->size()) return NULL; |
1374 |
|
return (*pRegions)[pos]; |
1375 |
|
} |
1376 |
|
|
1377 |
|
/** |
1378 |
|
* Returns the first Region of the instrument. You have to call this |
1379 |
|
* method once before you use GetNextRegion(). |
1380 |
|
* |
1381 |
|
* @returns pointer address to first region or NULL if there is none |
1382 |
|
* @see GetNextRegion() |
1383 |
|
* @deprecated This method is not reentrant-safe, use GetRegionAt() |
1384 |
|
* instead. |
1385 |
|
*/ |
1386 |
Region* Instrument::GetFirstRegion() { |
Region* Instrument::GetFirstRegion() { |
1387 |
if (!pRegions) LoadRegions(); |
if (!pRegions) LoadRegions(); |
1388 |
if (!pRegions) return NULL; |
if (!pRegions) return NULL; |
1390 |
return (RegionsIterator != pRegions->end()) ? *RegionsIterator : NULL; |
return (RegionsIterator != pRegions->end()) ? *RegionsIterator : NULL; |
1391 |
} |
} |
1392 |
|
|
1393 |
|
/** |
1394 |
|
* Returns the next Region of the instrument. You have to call |
1395 |
|
* GetFirstRegion() once before you can use this method. By calling this |
1396 |
|
* method multiple times it iterates through the available Regions. |
1397 |
|
* |
1398 |
|
* @returns pointer address to the next region or NULL if end reached |
1399 |
|
* @see GetFirstRegion() |
1400 |
|
* @deprecated This method is not reentrant-safe, use GetRegionAt() |
1401 |
|
* instead. |
1402 |
|
*/ |
1403 |
Region* Instrument::GetNextRegion() { |
Region* Instrument::GetNextRegion() { |
1404 |
if (!pRegions) return NULL; |
if (!pRegions) return NULL; |
1405 |
RegionsIterator++; |
RegionsIterator++; |
1411 |
RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); |
RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); |
1412 |
if (lrgn) { |
if (lrgn) { |
1413 |
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 |
1414 |
RIFF::List* rgn = lrgn->GetFirstSubList(); |
size_t i = 0; |
1415 |
while (rgn) { |
for (RIFF::List* rgn = lrgn->GetSubListAt(i); rgn; |
1416 |
|
rgn = lrgn->GetSubListAt(++i)) |
1417 |
|
{ |
1418 |
if (rgn->GetListType() == regionCkType) { |
if (rgn->GetListType() == regionCkType) { |
1419 |
pRegions->push_back(new Region(this, rgn)); |
pRegions->push_back(new Region(this, rgn)); |
1420 |
} |
} |
|
rgn = lrgn->GetNextSubList(); |
|
1421 |
} |
} |
1422 |
} |
} |
1423 |
} |
} |
1436 |
void Instrument::MoveRegion(Region* pSrc, Region* pDst) { |
void Instrument::MoveRegion(Region* pSrc, Region* pDst) { |
1437 |
RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); |
RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); |
1438 |
lrgn->MoveSubChunk(pSrc->pCkRegion, (RIFF::Chunk*) (pDst ? pDst->pCkRegion : 0)); |
lrgn->MoveSubChunk(pSrc->pCkRegion, (RIFF::Chunk*) (pDst ? pDst->pCkRegion : 0)); |
1439 |
|
for (size_t i = 0; i < pRegions->size(); ++i) { |
1440 |
pRegions->remove(pSrc); |
if ((*pRegions)[i] == pSrc) { |
1441 |
RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pDst); |
pRegions->erase(pRegions->begin() + i); |
1442 |
pRegions->insert(iter, pSrc); |
RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pDst); |
1443 |
|
pRegions->insert(iter, pSrc); |
1444 |
|
} |
1445 |
|
} |
1446 |
} |
} |
1447 |
|
|
1448 |
void Instrument::DeleteRegion(Region* pRegion) { |
void Instrument::DeleteRegion(Region* pRegion) { |
1564 |
void Instrument::CopyAssign(const Instrument* orig) { |
void Instrument::CopyAssign(const Instrument* orig) { |
1565 |
CopyAssignCore(orig); |
CopyAssignCore(orig); |
1566 |
// delete all regions first |
// delete all regions first |
1567 |
while (Regions) DeleteRegion(GetFirstRegion()); |
while (Regions) DeleteRegion(GetRegionAt(0)); |
1568 |
// now recreate and copy regions |
// now recreate and copy regions |
1569 |
{ |
{ |
1570 |
RegionList::const_iterator it = orig->pRegions->begin(); |
RegionList::const_iterator it = orig->pRegions->begin(); |
1700 |
delete pRIFF; |
delete pRIFF; |
1701 |
} |
} |
1702 |
|
|
1703 |
|
/** |
1704 |
|
* Returns Sample object of @a index. |
1705 |
|
* |
1706 |
|
* @param index - position of sample in sample list (0..n) |
1707 |
|
* @returns sample object or NULL if index is out of bounds |
1708 |
|
*/ |
1709 |
|
Sample* File::GetSample(size_t index) { |
1710 |
|
if (!pSamples) LoadSamples(); |
1711 |
|
if (!pSamples) return NULL; |
1712 |
|
if (index >= pSamples->size()) return NULL; |
1713 |
|
return (*pSamples)[index]; |
1714 |
|
} |
1715 |
|
|
1716 |
|
/** |
1717 |
|
* Returns a pointer to the first <i>Sample</i> object of the file, |
1718 |
|
* <i>NULL</i> otherwise. |
1719 |
|
* |
1720 |
|
* @deprecated This method is not reentrant-safe, use GetSample() |
1721 |
|
* instead. |
1722 |
|
*/ |
1723 |
Sample* File::GetFirstSample() { |
Sample* File::GetFirstSample() { |
1724 |
if (!pSamples) LoadSamples(); |
if (!pSamples) LoadSamples(); |
1725 |
if (!pSamples) return NULL; |
if (!pSamples) return NULL; |
1727 |
return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL; |
return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL; |
1728 |
} |
} |
1729 |
|
|
1730 |
|
/** |
1731 |
|
* Returns a pointer to the next <i>Sample</i> object of the file, |
1732 |
|
* <i>NULL</i> otherwise. |
1733 |
|
* |
1734 |
|
* @deprecated This method is not reentrant-safe, use GetSample() |
1735 |
|
* instead. |
1736 |
|
*/ |
1737 |
Sample* File::GetNextSample() { |
Sample* File::GetNextSample() { |
1738 |
if (!pSamples) return NULL; |
if (!pSamples) return NULL; |
1739 |
SamplesIterator++; |
SamplesIterator++; |
1746 |
if (wvpl) { |
if (wvpl) { |
1747 |
file_offset_t wvplFileOffset = wvpl->GetFilePos() - |
file_offset_t wvplFileOffset = wvpl->GetFilePos() - |
1748 |
wvpl->GetPos(); // should be zero, but just to be sure |
wvpl->GetPos(); // should be zero, but just to be sure |
1749 |
RIFF::List* wave = wvpl->GetFirstSubList(); |
size_t i = 0; |
1750 |
while (wave) { |
for (RIFF::List* wave = wvpl->GetSubListAt(i); wave; |
1751 |
|
wave = wvpl->GetSubListAt(++i)) |
1752 |
|
{ |
1753 |
if (wave->GetListType() == LIST_TYPE_WAVE) { |
if (wave->GetListType() == LIST_TYPE_WAVE) { |
1754 |
file_offset_t waveFileOffset = wave->GetFilePos() - |
file_offset_t waveFileOffset = wave->GetFilePos() - |
1755 |
wave->GetPos(); // should be zero, but just to be sure |
wave->GetPos(); // should be zero, but just to be sure |
1756 |
pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset)); |
pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset)); |
1757 |
} |
} |
|
wave = wvpl->GetNextSubList(); |
|
1758 |
} |
} |
1759 |
} |
} |
1760 |
else { // Seen a dwpl list chunk instead of a wvpl list chunk in some file (officially not DLS compliant) |
else { // Seen a dwpl list chunk instead of a wvpl list chunk in some file (officially not DLS compliant) |
1762 |
if (dwpl) { |
if (dwpl) { |
1763 |
file_offset_t dwplFileOffset = dwpl->GetFilePos() - |
file_offset_t dwplFileOffset = dwpl->GetFilePos() - |
1764 |
dwpl->GetPos(); // should be zero, but just to be sure |
dwpl->GetPos(); // should be zero, but just to be sure |
1765 |
RIFF::List* wave = dwpl->GetFirstSubList(); |
size_t i = 0; |
1766 |
while (wave) { |
for (RIFF::List* wave = dwpl->GetSubListAt(i); wave; |
1767 |
|
wave = dwpl->GetSubListAt(++i)) |
1768 |
|
{ |
1769 |
if (wave->GetListType() == LIST_TYPE_WAVE) { |
if (wave->GetListType() == LIST_TYPE_WAVE) { |
1770 |
file_offset_t waveFileOffset = wave->GetFilePos() - |
file_offset_t waveFileOffset = wave->GetFilePos() - |
1771 |
wave->GetPos(); // should be zero, but just to be sure |
wave->GetPos(); // should be zero, but just to be sure |
1772 |
pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset)); |
pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset)); |
1773 |
} |
} |
|
wave = dwpl->GetNextSubList(); |
|
1774 |
} |
} |
1775 |
} |
} |
1776 |
} |
} |
1827 |
if (!pInstruments) pInstruments = new InstrumentList; |
if (!pInstruments) pInstruments = new InstrumentList; |
1828 |
RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS); |
RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS); |
1829 |
if (lstInstruments) { |
if (lstInstruments) { |
1830 |
RIFF::List* lstInstr = lstInstruments->GetFirstSubList(); |
size_t i = 0; |
1831 |
while (lstInstr) { |
for (RIFF::List* lstInstr = lstInstruments->GetSubListAt(i); |
1832 |
|
lstInstr; lstInstr = lstInstruments->GetSubListAt(++i)) |
1833 |
|
{ |
1834 |
if (lstInstr->GetListType() == LIST_TYPE_INS) { |
if (lstInstr->GetListType() == LIST_TYPE_INS) { |
1835 |
pInstruments->push_back(new Instrument(this, lstInstr)); |
pInstruments->push_back(new Instrument(this, lstInstr)); |
1836 |
} |
} |
|
lstInstr = lstInstruments->GetNextSubList(); |
|
1837 |
} |
} |
1838 |
} |
} |
1839 |
} |
} |