30 #include <CoreFoundation/CFUUID.h> 31 #elif defined(HAVE_UUID_UUID_H) 32 #include <uuid/uuid.h> 38 #define CONN_TRANSFORM_SRC(x) ((x >> 10) & 0x000F) 39 #define CONN_TRANSFORM_CTL(x) ((x >> 4) & 0x000F) 40 #define CONN_TRANSFORM_DST(x) (x & 0x000F) 41 #define CONN_TRANSFORM_BIPOLAR_SRC(x) (x & 0x4000) 42 #define CONN_TRANSFORM_BIPOLAR_CTL(x) (x & 0x0100) 43 #define CONN_TRANSFORM_INVERT_SRC(x) (x & 0x8000) 44 #define CONN_TRANSFORM_INVERT_CTL(x) (x & 0x0200) 47 #define CONN_TRANSFORM_SRC_ENCODE(x) ((x & 0x000F) << 10) 48 #define CONN_TRANSFORM_CTL_ENCODE(x) ((x & 0x000F) << 4) 49 #define CONN_TRANSFORM_DST_ENCODE(x) (x & 0x000F) 50 #define CONN_TRANSFORM_BIPOLAR_SRC_ENCODE(x) ((x) ? 0x4000 : 0) 51 #define CONN_TRANSFORM_BIPOLAR_CTL_ENCODE(x) ((x) ? 0x0100 : 0) 52 #define CONN_TRANSFORM_INVERT_SRC_ENCODE(x) ((x) ? 0x8000 : 0) 53 #define CONN_TRANSFORM_INVERT_CTL_ENCODE(x) ((x) ? 0x0200 : 0) 55 #define DRUM_TYPE_MASK 0x80000000 57 #define F_RGN_OPTION_SELFNONEXCLUSIVE 0x0001 59 #define F_WAVELINK_PHASE_MASTER 0x0001 60 #define F_WAVELINK_MULTICHANNEL 0x0002 62 #define F_WSMP_NO_TRUNCATION 0x0001 63 #define F_WSMP_NO_COMPRESSION 0x0002 65 #define MIDI_BANK_COARSE(x) ((x & 0x00007F00) >> 8) // CC0 66 #define MIDI_BANK_FINE(x) (x & 0x0000007F) // CC32 67 #define MIDI_BANK_MERGE(coarse, fine) ((((uint16_t) coarse) << 7) | fine) // CC0 + CC32 68 #define MIDI_BANK_ENCODE(coarse, fine) (((coarse & 0x0000007F) << 8) | (fine & 0x0000007F)) 75 void Connection::Init(conn_block_t* Header) {
78 Destination = (
conn_dst_t) Header->destination;
79 Scale = Header->scale;
80 SourceTransform = (
conn_trn_t) CONN_TRANSFORM_SRC(Header->transform);
81 ControlTransform = (
conn_trn_t) CONN_TRANSFORM_CTL(Header->transform);
82 DestinationTransform = (
conn_trn_t) CONN_TRANSFORM_DST(Header->transform);
83 SourceInvert = CONN_TRANSFORM_INVERT_SRC(Header->transform);
84 SourceBipolar = CONN_TRANSFORM_BIPOLAR_SRC(Header->transform);
85 ControlInvert = CONN_TRANSFORM_INVERT_CTL(Header->transform);
86 ControlBipolar = CONN_TRANSFORM_BIPOLAR_CTL(Header->transform);
89 Connection::conn_block_t Connection::ToConnBlock() {
93 c.destination = Destination;
95 c.transform = CONN_TRANSFORM_SRC_ENCODE(SourceTransform) |
96 CONN_TRANSFORM_CTL_ENCODE(ControlTransform) |
97 CONN_TRANSFORM_DST_ENCODE(DestinationTransform) |
98 CONN_TRANSFORM_INVERT_SRC_ENCODE(SourceInvert) |
99 CONN_TRANSFORM_BIPOLAR_SRC_ENCODE(SourceBipolar) |
100 CONN_TRANSFORM_INVERT_CTL_ENCODE(ControlInvert) |
101 CONN_TRANSFORM_BIPOLAR_CTL_ENCODE(ControlBipolar);
119 pArticulationCk = artl;
129 Connection::conn_block_t connblock;
131 artl->
Read(&connblock.source, 1, 2);
132 artl->
Read(&connblock.control, 1, 2);
133 artl->
Read(&connblock.destination, 1, 2);
134 artl->
Read(&connblock.transform, 1, 2);
135 artl->
Read(&connblock.scale, 1, 4);
140 Articulation::~Articulation() {
151 const int iEntrySize = 12;
153 uint8_t* pData = (uint8_t*) pArticulationCk->
LoadChunkData();
154 store16(&pData[0], HeaderSize);
157 Connection::conn_block_t c =
pConnections[i].ToConnBlock();
158 store16(&pData[HeaderSize + i * iEntrySize], c.source);
159 store16(&pData[HeaderSize + i * iEntrySize + 2], c.control);
160 store16(&pData[HeaderSize + i * iEntrySize + 4], c.destination);
161 store16(&pData[HeaderSize + i * iEntrySize + 6], c.transform);
162 store32(&pData[HeaderSize + i * iEntrySize + 8], c.scale);
171 Articulator::Articulator(
RIFF::List* ParentList) {
172 pParentList = ParentList;
173 pArticulations = NULL;
176 Articulation* Articulator::GetFirstArticulation() {
177 if (!pArticulations) LoadArticulations();
178 if (!pArticulations)
return NULL;
179 ArticulationsIterator = pArticulations->begin();
180 return (ArticulationsIterator != pArticulations->end()) ? *ArticulationsIterator : NULL;
183 Articulation* Articulator::GetNextArticulation() {
184 if (!pArticulations)
return NULL;
185 ArticulationsIterator++;
186 return (ArticulationsIterator != pArticulations->end()) ? *ArticulationsIterator : NULL;
189 void Articulator::LoadArticulations() {
192 if (!lart) lart = pParentList->
GetSubList(LIST_TYPE_LART);
194 uint32_t artCkType = (lart->
GetListType() == LIST_TYPE_LAR2) ? CHUNK_ID_ART2
199 if (!pArticulations) pArticulations =
new ArticulationList;
200 pArticulations->push_back(
new Articulation(art));
207 Articulator::~Articulator() {
208 if (pArticulations) {
209 ArticulationList::iterator iter = pArticulations->begin();
210 ArticulationList::iterator end = pArticulations->end();
211 while (iter != end) {
215 delete pArticulations;
226 if (pArticulations) {
227 ArticulationList::iterator iter = pArticulations->begin();
228 ArticulationList::iterator end = pArticulations->end();
229 for (; iter != end; ++iter) {
230 (*iter)->UpdateChunks(pProgress);
256 pFixedStringLengths = NULL;
257 pResourceListChunk = list;
261 LoadString(CHUNK_ID_INAM, lstINFO,
Name);
264 LoadString(CHUNK_ID_ICMT, lstINFO,
Comments);
265 LoadString(CHUNK_ID_IPRD, lstINFO,
Product);
266 LoadString(CHUNK_ID_ICOP, lstINFO,
Copyright);
267 LoadString(CHUNK_ID_IART, lstINFO,
Artists);
268 LoadString(CHUNK_ID_IGNR, lstINFO,
Genre);
269 LoadString(CHUNK_ID_IKEY, lstINFO,
Keywords);
270 LoadString(CHUNK_ID_IENG, lstINFO,
Engineer);
271 LoadString(CHUNK_ID_ITCH, lstINFO,
Technician);
272 LoadString(CHUNK_ID_ISFT, lstINFO,
Software);
273 LoadString(CHUNK_ID_IMED, lstINFO,
Medium);
274 LoadString(CHUNK_ID_ISRC, lstINFO,
Source);
275 LoadString(CHUNK_ID_ISRF, lstINFO,
SourceForm);
277 LoadString(CHUNK_ID_ISBJ, lstINFO,
Subject);
297 pFixedStringLengths = lengths;
305 void Info::LoadString(uint32_t ChunkID,
RIFF::List* lstINFO, String& s) {
325 void Info::SaveString(uint32_t ChunkID,
RIFF::List* lstINFO,
const String& s,
const String& sDefault) {
327 if (pFixedStringLengths) {
328 for (
int i = 0 ; pFixedStringLengths[i].length ; i++) {
329 if (pFixedStringLengths[i].chunkId == ChunkID) {
330 size = pFixedStringLengths[i].length;
336 ::SaveString(ChunkID, ck, lstINFO, s, sDefault, size != 0, size);
347 if (!pResourceListChunk)
return;
352 String defaultName =
"";
353 String defaultCreationDate =
"";
354 String defaultSoftware =
"";
355 String defaultComments =
"";
357 uint32_t resourceType = pResourceListChunk->
GetListType();
360 lstINFO = pResourceListChunk->
AddSubList(LIST_TYPE_INFO);
363 defaultName =
"NONAME";
365 if (resourceType == RIFF_TYPE_DLS) {
367 time_t now = time(NULL);
368 tm* pNowBroken = localtime(&now);
370 strftime(buf, 11,
"%F", pNowBroken);
371 defaultCreationDate = buf;
375 if (resourceType == RIFF_TYPE_DLS || resourceType == LIST_TYPE_INS)
384 SaveString(CHUNK_ID_IART, lstINFO,
Artists, String(
""));
385 SaveString(CHUNK_ID_ICMS, lstINFO,
Commissioned, String(
""));
386 SaveString(CHUNK_ID_ICMT, lstINFO,
Comments, defaultComments);
387 SaveString(CHUNK_ID_ICOP, lstINFO,
Copyright, String(
""));
388 SaveString(CHUNK_ID_ICRD, lstINFO,
CreationDate, defaultCreationDate);
389 SaveString(CHUNK_ID_IENG, lstINFO,
Engineer, String(
""));
390 SaveString(CHUNK_ID_IGNR, lstINFO,
Genre, String(
""));
391 SaveString(CHUNK_ID_IKEY, lstINFO,
Keywords, String(
""));
392 SaveString(CHUNK_ID_IMED, lstINFO,
Medium, String(
""));
393 SaveString(CHUNK_ID_INAM, lstINFO,
Name, defaultName);
394 SaveString(CHUNK_ID_IPRD, lstINFO,
Product, String(
""));
395 SaveString(CHUNK_ID_ISBJ, lstINFO,
Subject, String(
""));
396 SaveString(CHUNK_ID_ISFT, lstINFO,
Software, defaultSoftware);
397 SaveString(CHUNK_ID_ISRC, lstINFO,
Source, String(
""));
398 SaveString(CHUNK_ID_ISRF, lstINFO,
SourceForm, String(
""));
399 SaveString(CHUNK_ID_ITCH, lstINFO,
Technician, String(
""));
427 pFixedStringLengths = orig->pFixedStringLengths;
446 pResourceList = lstResource;
461 Resource::~Resource() {
482 if (!ckDLSID) ckDLSID = pResourceList->
AddSubChunk(CHUNK_ID_DLID, 16);
485 store32(&pData[0],
pDLSID->ulData1);
486 store16(&pData[4],
pDLSID->usData2);
487 store16(&pData[6],
pDLSID->usData3);
488 memcpy(&pData[8],
pDLSID->abData, 8);
496 #if defined(WIN32) || defined(__APPLE__) || defined(HAVE_UUID_GENERATE) 504 pDLSID->ulData1 = uuid.Data1;
505 pDLSID->usData2 = uuid.Data2;
506 pDLSID->usData3 = uuid.Data3;
507 memcpy(
pDLSID->abData, uuid.Data4, 8);
509 #elif defined(__APPLE__) 511 CFUUIDRef uuidRef = CFUUIDCreate(NULL);
512 CFUUIDBytes uuid = CFUUIDGetUUIDBytes(uuidRef);
514 pDLSID->ulData1 = uuid.byte0 | uuid.byte1 << 8 | uuid.byte2 << 16 | uuid.byte3 << 24;
515 pDLSID->usData2 = uuid.byte4 | uuid.byte5 << 8;
516 pDLSID->usData3 = uuid.byte6 | uuid.byte7 << 8;
517 pDLSID->abData[0] = uuid.byte8;
518 pDLSID->abData[1] = uuid.byte9;
519 pDLSID->abData[2] = uuid.byte10;
520 pDLSID->abData[3] = uuid.byte11;
521 pDLSID->abData[4] = uuid.byte12;
522 pDLSID->abData[5] = uuid.byte13;
523 pDLSID->abData[6] = uuid.byte14;
524 pDLSID->abData[7] = uuid.byte15;
528 pDLSID->ulData1 = uuid[0] | uuid[1] << 8 | uuid[2] << 16 | uuid[3] << 24;
529 pDLSID->usData2 = uuid[4] | uuid[5] << 8;
530 pDLSID->usData3 = uuid[6] | uuid[7] << 8;
531 memcpy(
pDLSID->abData, &uuid[8], 8);
551 pParentList = ParentList;
565 SamplerOptions = F_WSMP_NO_COMPRESSION;
568 NoSampleDepthTruncation = SamplerOptions & F_WSMP_NO_TRUNCATION;
569 NoSampleCompression = SamplerOptions & F_WSMP_NO_COMPRESSION;
572 wsmp->
SetPos(uiHeaderSize);
582 Sampler::~Sampler() {
586 void Sampler::SetGain(int32_t gain) {
601 wsmp = pParentList->
AddSubChunk(CHUNK_ID_WSMP, wsmpSize);
602 }
else if (wsmp->
GetSize() != wsmpSize) {
607 store32(&pData[0], uiHeaderSize);
609 SamplerOptions = (NoSampleDepthTruncation) ? SamplerOptions | F_WSMP_NO_TRUNCATION
610 : SamplerOptions & (~F_WSMP_NO_TRUNCATION);
611 SamplerOptions = (NoSampleCompression) ? SamplerOptions | F_WSMP_NO_COMPRESSION
612 : SamplerOptions & (~F_WSMP_NO_COMPRESSION);
613 store16(&pData[4], UnityNote);
614 store16(&pData[6], FineTune);
615 store32(&pData[8],
Gain);
616 store32(&pData[12], SamplerOptions);
621 store32(&pData[uiHeaderSize + i * 16],
pSampleLoops[i].Size);
622 store32(&pData[uiHeaderSize + i * 16 + 4],
pSampleLoops[i].LoopType);
623 store32(&pData[uiHeaderSize + i * 16 + 8],
pSampleLoops[i].LoopStart);
624 store32(&pData[uiHeaderSize + i * 16 + 12],
pSampleLoops[i].LoopLength);
662 throw Exception(
"Could not delete Sample Loop, because it does not exist");
681 UnityNote = orig->UnityNote;
682 FineTune = orig->FineTune;
684 NoSampleDepthTruncation = orig->NoSampleDepthTruncation;
685 NoSampleCompression = orig->NoSampleCompression;
686 SamplerOptions = orig->SamplerOptions;
715 pWaveList = waveList;
796 const file_offset_t restorePos = pOrig->pCkData->
GetPos();
798 for (file_offset_t todo = pOrig->
GetSize(), i = 0; todo; ) {
799 const int iReadAtOnce = 64*1024;
800 file_offset_t n = (iReadAtOnce < todo) ? iReadAtOnce : todo;
801 n = pOrig->
Read(&buf[i], n);
806 pOrig->pCkData->
SetPos(restorePos);
859 if (
FormatTag != DLS_WAVE_FORMAT_PCM)
return 0;
892 if (
FormatTag != DLS_WAVE_FORMAT_PCM)
throw Exception(
"Sample's format is not DLS_WAVE_FORMAT_PCM");
893 if (NewSize < 1)
throw Exception(
"Sample size must be at least one sample point");
894 if ((NewSize >> 48) != 0)
895 throw Exception(
"Unrealistic high DLS sample size detected");
896 const file_offset_t sizeInBytes = NewSize *
FrameSize;
898 if (pCkData) pCkData->
Resize(sizeInBytes);
899 else pCkData = pWaveList->
AddSubChunk(CHUNK_ID_DATA, sizeInBytes);
919 if (
FormatTag != DLS_WAVE_FORMAT_PCM)
return 0;
920 if (!pCkData)
throw Exception(
"No data chunk created for sample yet, call Sample::Resize() to create one");
921 file_offset_t orderedBytes = SampleCount *
FrameSize;
922 file_offset_t result = pCkData->
SetPos(orderedBytes, Whence);
923 return (result == orderedBytes) ? SampleCount
937 if (
FormatTag != DLS_WAVE_FORMAT_PCM)
return 0;
957 if (
FormatTag != DLS_WAVE_FORMAT_PCM)
return 0;
958 if (
GetSize() < SampleCount)
throw Exception(
"Could not write sample data, current sample size to small");
972 throw Exception(
"Could not save sample, only PCM format is supported");
975 throw Exception(
"Could not save sample, there is no sample data to save");
980 if (!pCkFormat) pCkFormat = pWaveList->
AddSubChunk(CHUNK_ID_FMT, 16);
1002 rgnh->
Read(&KeyRange, 2, 2);
1003 rgnh->
Read(&VelocityRange, 2, 2);
1008 rgnh->
Read(&Layer, 1,
sizeof(uint16_t));
1012 KeyRange.high = 127;
1013 VelocityRange.low = 0;
1014 VelocityRange.high = 127;
1015 FormatOptionFlags = F_RGN_OPTION_SELFNONEXCLUSIVE;
1019 SelfNonExclusive = FormatOptionFlags & F_RGN_OPTION_SELFNONEXCLUSIVE;
1029 WaveLinkOptionFlags = 0;
1032 WavePoolTableIndex = 0;
1034 PhaseMaster = WaveLinkOptionFlags & F_WAVELINK_PHASE_MASTER;
1035 MultiChannel = WaveLinkOptionFlags & F_WAVELINK_MULTICHANNEL;
1049 Sample* Region::GetSample() {
1050 if (pSample)
return pSample;
1051 File* file = (
File*) GetParent()->GetParent();
1052 uint64_t soughtoffset = file->pWavePoolTable[WavePoolTableIndex];
1055 if (sample->ullWavePoolOffset == soughtoffset)
return (pSample = sample);
1067 this->pSample = pSample;
1068 WavePoolTableIndex = 0;
1084 if (!pInstrument->pRegions) pInstrument->LoadRegions();
1085 if (!pInstrument->pRegions)
return;
1090 Region* prev_region = NULL;
1092 Instrument::RegionList::iterator iter = pInstrument->pRegions->begin();
1093 iter != pInstrument->pRegions->end(); iter++
1095 if ((*iter)->KeyRange.low > this->KeyRange.low) {
1099 prev_region = *iter;
1103 if (prev_region !=
this) pInstrument->MoveRegion(
this, r);
1116 if (!rgnh) rgnh = pCkRegion->
AddSubChunk(CHUNK_ID_RGNH, Layer ? 14 : 12);
1118 FormatOptionFlags = (SelfNonExclusive)
1119 ? FormatOptionFlags | F_RGN_OPTION_SELFNONEXCLUSIVE
1120 : FormatOptionFlags & (~F_RGN_OPTION_SELFNONEXCLUSIVE);
1124 store16(&pData[4], VelocityRange.
low);
1125 store16(&pData[6], VelocityRange.
high);
1126 store16(&pData[8], FormatOptionFlags);
1127 store16(&pData[10], KeyGroup);
1128 if (rgnh->
GetSize() >= 14) store16(&pData[12], Layer);
1137 if (!wlnk) wlnk = pCkRegion->
AddSubChunk(CHUNK_ID_WLNK, 12);
1139 WaveLinkOptionFlags = (PhaseMaster)
1140 ? WaveLinkOptionFlags | F_WAVELINK_PHASE_MASTER
1141 : WaveLinkOptionFlags & (~F_WAVELINK_PHASE_MASTER);
1142 WaveLinkOptionFlags = (MultiChannel)
1143 ? WaveLinkOptionFlags | F_WAVELINK_MULTICHANNEL
1144 : WaveLinkOptionFlags & (~F_WAVELINK_MULTICHANNEL);
1147 File* pFile = (
File*) GetParent()->GetParent();
1148 if (pFile->pSamples) {
1149 File::SampleList::iterator iter = pFile->pSamples->begin();
1150 File::SampleList::iterator end = pFile->pSamples->end();
1151 for (
int i = 0; iter != end; ++iter, i++) {
1152 if (*iter == pSample) {
1158 WavePoolTableIndex = index;
1160 store16(&pData[0], WaveLinkOptionFlags);
1161 store16(&pData[2], PhaseGroup);
1162 store32(&pData[4], Channel);
1163 store32(&pData[8], WavePoolTableIndex);
1182 VelocityRange = orig->VelocityRange;
1183 KeyGroup = orig->KeyGroup;
1184 Layer = orig->Layer;
1185 SelfNonExclusive = orig->SelfNonExclusive;
1186 PhaseMaster = orig->PhaseMaster;
1187 PhaseGroup = orig->PhaseGroup;
1188 MultiChannel = orig->MultiChannel;
1189 Channel = orig->Channel;
1192 if (GetParent()->GetParent() == orig->GetParent()->GetParent()) {
1193 WavePoolTableIndex = orig->WavePoolTableIndex;
1194 pSample = orig->pSample;
1196 WavePoolTableIndex = -1;
1199 FormatOptionFlags = orig->FormatOptionFlags;
1200 WaveLinkOptionFlags = orig->WaveLinkOptionFlags;
1223 pCkInstrument = insList;
1225 midi_locale_t locale;
1229 insh->
Read(&locale, 2, 4);
1233 locale.instrument = 0;
1237 IsDrum = locale.bank & DRUM_TYPE_MASK;
1245 Region* Instrument::GetFirstRegion() {
1246 if (!pRegions) LoadRegions();
1247 if (!pRegions)
return NULL;
1248 RegionsIterator = pRegions->begin();
1249 return (RegionsIterator != pRegions->end()) ? *RegionsIterator : NULL;
1252 Region* Instrument::GetNextRegion() {
1253 if (!pRegions)
return NULL;
1255 return (RegionsIterator != pRegions->end()) ? *RegionsIterator : NULL;
1258 void Instrument::LoadRegions() {
1259 if (!pRegions) pRegions =
new RegionList;
1262 uint32_t regionCkType = (lrgn->
GetSubList(LIST_TYPE_RGN2)) ? LIST_TYPE_RGN2 : LIST_TYPE_RGN;
1266 pRegions->push_back(
new Region(
this, rgn));
1273 Region* Instrument::AddRegion() {
1274 if (!pRegions) LoadRegions();
1276 if (!lrgn) lrgn = pCkInstrument->
AddSubList(LIST_TYPE_LRGN);
1278 Region* pNewRegion =
new Region(
this, rgn);
1279 pRegions->push_back(pNewRegion);
1280 Regions = (uint32_t) pRegions->size();
1284 void Instrument::MoveRegion(Region* pSrc, Region* pDst) {
1288 pRegions->remove(pSrc);
1289 RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pDst);
1290 pRegions->insert(iter, pSrc);
1293 void Instrument::DeleteRegion(Region* pRegion) {
1294 if (!pRegions)
return;
1295 RegionList::iterator iter = find(pRegions->begin(), pRegions->end(), pRegion);
1296 if (iter == pRegions->end())
return;
1297 pRegions->erase(iter);
1298 Regions = (uint32_t) pRegions->size();
1315 if (!insh) insh = pCkInstrument->
AddSubChunk(CHUNK_ID_INSH, 12);
1318 Regions = (pRegions) ? uint32_t(pRegions->size()) : 0;
1319 midi_locale_t locale;
1322 locale.bank = (
IsDrum) ? locale.bank | DRUM_TYPE_MASK : locale.bank & (~DRUM_TYPE_MASK);
1325 store32(&pData[4], locale.bank);
1326 store32(&pData[8], locale.instrument);
1328 if (!pRegions)
return;
1329 RegionList::iterator iter = pRegions->begin();
1330 RegionList::iterator end = pRegions->end();
1331 for (
int i = 0; iter != end; ++iter, ++i) {
1334 __divide_progress(pProgress, &subprogress, pRegions->size(), i);
1336 (*iter)->UpdateChunks(&subprogress);
1338 __notify_progress(pProgress, 1.0);
1348 RegionList::iterator iter = pRegions->begin();
1349 RegionList::iterator end = pRegions->end();
1350 while (iter != end) {
1361 void Instrument::CopyAssignCore(
const Instrument* orig) {
1384 CopyAssignCore(orig);
1386 while (
Regions) DeleteRegion(GetFirstRegion());
1389 RegionList::const_iterator it = orig->pRegions->begin();
1390 for (
int i = 0; i < orig->
Regions; ++i, ++it) {
1391 Region* dstRgn = AddRegion();
1418 pWavePoolTable = NULL;
1419 pWavePoolTableHi = NULL;
1420 WavePoolHeaderSize = 8;
1423 pInstruments = NULL;
1425 b64BitWavePoolOffsets =
false;
1438 if (!pRIFF)
throw DLS::Exception(
"NULL pointer reference to RIFF::File object.");
1439 this->pRIFF = pRIFF;
1449 if (!colh)
throw DLS::Exception(
"Mandatory chunks in RIFF list chunk not found.");
1455 pWavePoolTable = NULL;
1456 pWavePoolTableHi = NULL;
1457 WavePoolHeaderSize = 8;
1458 b64BitWavePoolOffsets =
false;
1462 pWavePoolTable =
new uint32_t[WavePoolCount];
1463 pWavePoolTableHi =
new uint32_t[WavePoolCount];
1464 ptbl->
SetPos(WavePoolHeaderSize);
1467 b64BitWavePoolOffsets = (ptbl->
GetSize() - WavePoolHeaderSize == WavePoolCount * 8);
1468 if (b64BitWavePoolOffsets) {
1469 for (
int i = 0 ; i < WavePoolCount ; i++) {
1477 ptbl->
Read(pWavePoolTable, WavePoolCount,
sizeof(uint32_t));
1478 for (
int i = 0 ; i < WavePoolCount ; i++) pWavePoolTableHi[i] = 0;
1483 pInstruments = NULL;
1488 InstrumentList::iterator iter = pInstruments->begin();
1489 InstrumentList::iterator end = pInstruments->end();
1490 while (iter != end) {
1494 delete pInstruments;
1498 SampleList::iterator iter = pSamples->begin();
1499 SampleList::iterator end = pSamples->end();
1500 while (iter != end) {
1507 if (pWavePoolTable)
delete[] pWavePoolTable;
1508 if (pWavePoolTableHi)
delete[] pWavePoolTableHi;
1510 for (std::list<RIFF::File*>::iterator i = ExtensionFiles.begin() ; i != ExtensionFiles.end() ; i++)
1515 if (!pSamples) LoadSamples();
1516 if (!pSamples)
return NULL;
1517 SamplesIterator = pSamples->begin();
1518 return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL;
1522 if (!pSamples)
return NULL;
1524 return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL;
1527 void File::LoadSamples() {
1528 if (!pSamples) pSamples =
new SampleList;
1531 file_offset_t wvplFileOffset = wvpl->
GetFilePos();
1535 file_offset_t waveFileOffset = wave->
GetFilePos();
1536 pSamples->push_back(
new Sample(
this, wave, waveFileOffset - wvplFileOffset));
1549 pSamples->push_back(
new Sample(
this, wave, waveFileOffset - dwplFileOffset));
1565 if (!pSamples) LoadSamples();
1571 pSamples->push_back(pSample);
1583 if (!pSamples)
return;
1584 SampleList::iterator iter = find(pSamples->begin(), pSamples->end(), pSample);
1585 if (iter == pSamples->end())
return;
1586 pSamples->erase(iter);
1591 if (!pInstruments) LoadInstruments();
1592 if (!pInstruments)
return NULL;
1593 InstrumentsIterator = pInstruments->begin();
1594 return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL;
1598 if (!pInstruments)
return NULL;
1599 InstrumentsIterator++;
1600 return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL;
1603 void File::LoadInstruments() {
1604 if (!pInstruments) pInstruments =
new InstrumentList;
1606 if (lstInstruments) {
1610 pInstruments->push_back(
new Instrument(
this, lstInstr));
1625 if (!pInstruments) LoadInstruments();
1630 pInstruments->push_back(pInstrument);
1642 if (!pInstruments)
return;
1643 InstrumentList::iterator iter = find(pInstruments->begin(), pInstruments->end(), pInstrument);
1644 if (iter == pInstruments->end())
return;
1645 pInstruments->erase(iter);
1662 if (index < 0 || index >= ExtensionFiles.size())
return NULL;
1663 std::list<RIFF::File*>::iterator iter = ExtensionFiles.begin();
1664 for (
int i = 0; iter != ExtensionFiles.end(); ++iter, ++i)
1665 if (i == index)
return *iter;
1679 return pRIFF->GetFileName();
1687 pRIFF->SetFileName(name);
1705 if (!ckVersion) ckVersion = pRIFF->
AddSubChunk(CHUNK_ID_VERS, 8);
1707 store16(&pData[0],
pVersion->minor);
1708 store16(&pData[2],
pVersion->major);
1709 store16(&pData[4],
pVersion->build);
1710 store16(&pData[6],
pVersion->release);
1714 Instruments = (pInstruments) ? uint32_t(pInstruments->size()) : 0;
1716 if (!colh) colh = pRIFF->
AddSubChunk(CHUNK_ID_COLH, 4);
1724 __divide_progress(pProgress, &subprogress, 20.f, 0.f);
1727 InstrumentList::iterator iter = pInstruments->begin();
1728 InstrumentList::iterator end = pInstruments->end();
1729 for (
int i = 0; iter != end; ++iter, ++i) {
1732 __divide_progress(&subprogress, &subsubprogress, pInstruments->size(), i);
1734 (*iter)->UpdateChunks(&subsubprogress);
1737 __notify_progress(&subprogress, 1.0);
1741 const int iSamples = (pSamples) ?
int(pSamples->size()) : 0;
1742 int iPtblOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4;
1744 if (!ptbl) ptbl = pRIFF->
AddSubChunk(CHUNK_ID_PTBL, 1 );
1745 int iPtblSize = WavePoolHeaderSize + iPtblOffsetSize * iSamples;
1748 WavePoolCount = iSamples;
1749 store32(&pData[4], WavePoolCount);
1751 memset(&pData[WavePoolHeaderSize], 0, iPtblSize - WavePoolHeaderSize);
1757 __divide_progress(pProgress, &subprogress, 20.f, 1.f);
1760 SampleList::iterator iter = pSamples->begin();
1761 SampleList::iterator end = pSamples->end();
1762 for (
int i = 0; iter != end; ++iter, ++i) {
1765 __divide_progress(&subprogress, &subsubprogress, pSamples->size(), i);
1767 (*iter)->UpdateChunks(&subsubprogress);
1770 __notify_progress(&subprogress, 1.0);
1778 const bool bRequires64Bit = (finalFileSize >> 32) != 0;
1779 if (b64BitWavePoolOffsets != bRequires64Bit) {
1780 b64BitWavePoolOffsets = bRequires64Bit;
1781 iPtblOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4;
1782 iPtblSize = WavePoolHeaderSize + iPtblOffsetSize * iSamples;
1786 __notify_progress(pProgress, 1.0);
1807 __divide_progress(pProgress, &subprogress, 2.f, 0.f);
1815 __divide_progress(pProgress, &subprogress, 2.f, 1.f);
1817 pRIFF->
Save(Path, &subprogress);
1820 __notify_progress(pProgress, 1.0);
1837 __divide_progress(pProgress, &subprogress, 2.f, 0.f);
1844 __divide_progress(pProgress, &subprogress, 2.f, 1.f);
1846 pRIFF->
Save(&subprogress);
1849 __notify_progress(pProgress, 1.0);
1863 __UpdateWavePoolTableChunk();
1874 if (!lstInstruments) pRIFF->
AddSubList(LIST_TYPE_LINS);
1878 const int iOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4;
1879 ptbl = pRIFF->
AddSubChunk(CHUNK_ID_PTBL, WavePoolHeaderSize + iOffsetSize);
1883 if (!wvpl) pRIFF->
AddSubList(LIST_TYPE_WVPL);
1895 void File::__UpdateWavePoolTableChunk() {
1896 __UpdateWavePoolTable();
1898 const int iOffsetSize = (b64BitWavePoolOffsets) ? 8 : 4;
1900 WavePoolCount = (pSamples) ? uint32_t(pSamples->size()) : 0;
1901 const file_offset_t ulRequiredSize = WavePoolHeaderSize + iOffsetSize * WavePoolCount;
1902 if (ptbl->
GetSize() < ulRequiredSize)
throw Exception(
"Fatal error, 'ptbl' chunk too small");
1904 file_offset_t ullOriginalPos = ptbl->
GetPos();
1907 uint32_t tmp = WavePoolHeaderSize;
1909 tmp = WavePoolCount;
1912 ptbl->
SetPos(WavePoolHeaderSize);
1913 if (b64BitWavePoolOffsets) {
1914 for (
int i = 0 ; i < WavePoolCount ; i++) {
1915 tmp = pWavePoolTableHi[i];
1917 tmp = pWavePoolTable[i];
1921 for (
int i = 0 ; i < WavePoolCount ; i++) {
1922 tmp = pWavePoolTable[i];
1927 ptbl->
SetPos(ullOriginalPos);
1935 void File::__UpdateWavePoolTable() {
1936 WavePoolCount = (pSamples) ? uint32_t(pSamples->size()) : 0;
1938 if (pWavePoolTable)
delete[] pWavePoolTable;
1939 if (pWavePoolTableHi)
delete[] pWavePoolTableHi;
1940 pWavePoolTable =
new uint32_t[WavePoolCount];
1941 pWavePoolTableHi =
new uint32_t[WavePoolCount];
1942 if (!pSamples)
return;
1945 uint64_t wvplFileOffset = wvpl->
GetFilePos();
1946 if (b64BitWavePoolOffsets) {
1947 SampleList::iterator iter = pSamples->begin();
1948 SampleList::iterator end = pSamples->end();
1949 for (
int i = 0 ; iter != end ; ++iter, i++) {
1950 uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - wvplFileOffset - LIST_HEADER_SIZE(pRIFF->
GetFileOffsetSize());
1951 (*iter)->ullWavePoolOffset = _64BitOffset;
1952 pWavePoolTableHi[i] = (uint32_t) (_64BitOffset >> 32);
1953 pWavePoolTable[i] = (uint32_t) _64BitOffset;
1956 SampleList::iterator iter = pSamples->begin();
1957 SampleList::iterator end = pSamples->end();
1958 for (
int i = 0 ; iter != end ; ++iter, i++) {
1959 uint64_t _64BitOffset = (*iter)->pWaveList->GetFilePos() - wvplFileOffset - LIST_HEADER_SIZE(pRIFF->
GetFileOffsetSize());
1960 (*iter)->ullWavePoolOffset = _64BitOffset;
1961 pWavePoolTable[i] = (uint32_t) _64BitOffset;
1971 Exception::Exception() :
RIFF::Exception() {
1974 Exception::Exception(String format, ...) :
RIFF::Exception() {
1976 va_start(arg, format);
1977 Message = assemble(format, arg);
1981 Exception::Exception(String format, va_list arg) :
RIFF::Exception() {
1982 Message = assemble(format, arg);
1985 void Exception::PrintMessage() {
1986 std::cout <<
"DLS::Exception: " << Message << std::endl;
file_offset_t WriteUint32(uint32_t *pData, file_offset_t WordCount=1)
Writes WordCount number of 32 Bit unsigned integer words from the buffer pointed by pData to the chun...
virtual void CopyAssign(const Instrument *orig)
Make a (semi) deep copy of the Instrument object given by orig and assign it to this object...
uint16_t BlockAlign
The block alignment (in bytes) of the waveform data. Playback software needs to process a multiple of...
sample_loop_t * pSampleLoops
Points to the beginning of a sample loop array, or is NULL if there are no loops defined.
uint32_t Regions
Reflects the number of Region defintions this Instrument has.
Parses DLS Level 1 and 2 compliant files and provides abstract access to the data.
file_offset_t ReadUint16(uint16_t *pData, file_offset_t WordCount=1)
Reads WordCount number of 16 Bit unsigned integer words and copies it into the buffer pointed by pDat...
stream_whence_t
File stream position dependent to these relations.
String CreationDate
<ICRD-ck>. Specifies the date the subject of the file was created. List dates in yyyy-mm-dd format...
Chunk * GetFirstSubChunk()
Returns the first subchunk within the list (which may be an ordinary chunk as well as a list chunk)...
String Engineer
<IENG-ck>. Stores the name of the engineer who worked on the file. Multiple engineer names are separa...
virtual void SetKeyRange(uint16_t Low, uint16_t High)
Modifies the key range of this Region and makes sure the respective chunks are in correct order...
void __ensureMandatoryChunksExist()
Checks if all (for DLS) mandatory chunks exist, if not they will be created.
String Artists
<IART-ck>. Lists the artist of the original subject of the file.
file_offset_t GetSize() const
Chunk size in bytes (without header, thus the chunk data body)
Sample * GetFirstSample()
Returns a pointer to the first Sample object of the file, NULL otherwise.
file_offset_t SetPos(file_offset_t SampleCount, RIFF::stream_whence_t Whence=RIFF::stream_start)
Sets the position within the sample (in sample points, not in bytes).
Instrument * GetNextInstrument()
Returns a pointer to the next Instrument object of the file, NULL otherwise.
Will be thrown whenever a DLS specific error occurs while trying to access a DLS File.
file_offset_t ReadInt32(int32_t *pData, file_offset_t WordCount=1)
Reads WordCount number of 32 Bit signed integer words and copies it into the buffer pointed by pData...
Optional information for DLS files, instruments, samples, etc.
virtual void CopyAssign(const Region *orig)
Make a (semi) deep copy of the Region object given by orig and assign it to this object.
virtual void UpdateChunks(progress_t *pProgress)
Update chunks with current Resource data.
RIFF::File * GetExtensionFile(int index)
Returns extension file of given index.
virtual ~Region()
Destructor.
Instrument * AddInstrument()
Add a new instrument definition.
Instrument * GetFirstInstrument()
Returns a pointer to the first Instrument object of the file, NULL otherwise.
String Keywords
<IKEY-ck>. Provides a list of keywords that refer to the file or subject of the file. Keywords are separated with semicolon and blank, e.g., FX; death; murder.
conn_src_t
Connection Sources.
file_offset_t GetSize() const
Returns sample size.
uint16_t Channels
Number of channels represented in the waveform data, e.g. 1 for mono, 2 for stereo (defaults to 1=mon...
file_offset_t SamplesTotal
Reflects total number of sample points (only if known sample data format is used, 0 otherwise)...
String SourceForm
<ISRF-ck>. Identifies the original form of the material that was digitized, such as record...
List * GetSubList(uint32_t ListType)
Returns sublist chunk with list type ListType within this chunk list.
void DeleteSubChunk(Chunk *pSubChunk)
Removes a sub chunk.
Defines Sample Loop Points.
virtual ~Sample()
Destructor.
uint16_t MIDIBank
Reflects combination of MIDIBankCoarse and MIDIBankFine (bank 1 - bank 16384). Do not change this val...
List * GetFirstSubList()
Returns the first sublist within the list (that is a subchunk with chunk ID "LIST").
virtual void CopyAssign(const Info *orig)
Make a deep copy of the Info object given by orig and assign it to this object.
uint8_t MIDIBankCoarse
Reflects the MIDI Bank number for MIDI Control Change 0 (bank 1 - 128).
void GenerateDLSID()
Generates a new DLSID for the resource.
uint FrameSize
Reflects the size (in bytes) of one single sample point (only if known sample data format is used...
List * GetParent() const
Returns pointer to the chunk's parent list chunk.
Every subject of an DLS file and the file itself can have an unique, computer generated ID...
virtual void CopyAssign(const Sample *orig)
Make a deep copy of the Sample object given by orig and assign it to this object. ...
void DeleteSampleLoop(sample_loop_t *pLoopDef)
Deletes an existing sample loop.
virtual ~Instrument()
Destructor.
uint16_t low
Low value of range.
void SetByteOrder(endian_t Endian)
Set the byte order to be used when saving.
void SetFixedStringLengths(const string_length_t *lengths)
Forces specific Info fields to be of a fixed length when being saved to a file.
uint16_t FormatTag
Format ID of the waveform data (should be DLS_WAVE_FORMAT_PCM for DLS1 compliant files, this is also the default value if Sample was created with Instrument::AddSample()).
file_offset_t Read(void *pData, file_offset_t WordCount, file_offset_t WordSize)
Reads WordCount number of data words with given WordSize and copies it into a buffer pointed by pData...
virtual void CopyAssign(const Sampler *orig)
Make a deep copy of the Sampler object given by orig and assign it to this object.
void ReleaseSampleData()
Free sample data from RAM.
virtual void CopyAssign(const Articulator *orig)
Not yet implemented in this version, since the .gig format does not need to copy DLS articulators and...
Abstract base class which provides mandatory informations about sample players in general...
String libraryName()
Returns the name of this C++ library.
file_offset_t SetPos(file_offset_t Where, stream_whence_t Whence=stream_start)
Sets the position within the chunk body, thus within the data portion of the chunk (in bytes)...
conn_trn_t
Connection Transforms.
void SetFileName(const String &name)
You may call this method store a future file name, so you don't have to to pass it to the Save() call...
uint32_t SampleLoops
Reflects the number of sample loops.
virtual void Save(const String &Path, progress_t *pProgress=NULL)
Save changes to another file.
void Resize(file_offset_t NewSize)
Resize sample.
conn_dst_t
Connection Destinations.
void DeleteSample(Sample *pSample)
Delete a sample.
uint16_t high
High value of range.
uint64_t file_offset_t
Type used by libgig for handling file positioning during file I/O tasks.
file_offset_t ReadUint32(uint32_t *pData, file_offset_t WordCount=1)
Reads WordCount number of 32 Bit unsigned integer words and copies it into the buffer pointed by pDat...
uint32_t Size
For internal usage only: usually reflects exactly sizeof(sample_loop_t), otherwise if the value is la...
Chunk * GetSubChunk(uint32_t ChunkID)
Returns subchunk with chunk ID ChunkID within this chunk list.
Chunk * GetNextSubChunk()
Returns the next subchunk within the list (which may be an ordinary chunk as well as a list chunk)...
Info(RIFF::List *list)
Constructor.
virtual void Save(progress_t *pProgress=NULL)
Save changes to same file.
String Source
<ISRC-ck>. Identifies the name of the person or organization who supplied the original subject of the...
uint16_t BitDepth
Size of each sample per channel (only if known sample data format is used, 0 otherwise).
Sample(File *pFile, RIFF::List *waveList, file_offset_t WavePoolOffset)
Constructor.
uint32_t MIDIProgram
Specifies the MIDI Program Change Number this Instrument should be assigned to.
file_offset_t GetRequiredFileSize()
Returns the required size (in bytes) for this RIFF File to be saved to disk.
virtual void UpdateChunks(progress_t *pProgress)
Update chunks with current info values.
String Commissioned
<ICMS-ck>. Lists the name of the person or organization that commissioned the subject of the file...
int GetFileOffsetSize() const
Returns the current size (in bytes) of file offsets stored in the headers of all chunks of this file...
uint32_t GetChunkID() const
Chunk ID in unsigned integer representation.
void SetSample(Sample *pSample)
Assign another sample to this Region.
file_offset_t RemainingBytes() const
Returns the number of bytes left to read in the chunk body.
Used for indicating the progress of a certain task.
file_offset_t Write(void *pData, file_offset_t WordCount, file_offset_t WordSize)
Writes WordCount number of data words with given WordSize from the buffer pointed by pData...
uint32_t GetListType() const
Returns unsigned integer representation of the list's ID.
virtual void UpdateChunks(progress_t *pProgress)
Apply Instrument with all its Regions to the respective RIFF chunks.
void DeleteInstrument(Instrument *pInstrument)
Delete an instrument.
version_t * pVersion
Points to a version_t structure if the file provided a version number else is set to NULL...
String Technician
<ITCH-ck>. Identifies the technician who sampled the subject file.
Instrument(File *pFile, RIFF::List *insList)
Constructor.
void * LoadChunkData()
Load chunk body into RAM.
uint32_t AverageBytesPerSecond
The average number of bytes per second at which the waveform data should be transferred (Playback sof...
uint8_t MIDIBankFine
Reflects the MIDI Bank number for MIDI Control Change 32 (bank 1 - 128).
virtual void UpdateChunks(progress_t *pProgress)
Apply all articulations to the respective RIFF chunks.
Abstract base class which encapsulates data structures which all DLS resources are able to provide...
void Resize(file_offset_t NewSize)
Resize chunk.
List * AddSubList(uint32_t uiListType)
Creates a new list sub chunk.
RIFF specific classes and definitions.
virtual void UpdateChunks(progress_t *pProgress)
Apply all sample player options to the respective RIFF chunk.
String Software
<ISFT-ck>. Identifies the name of the sofware package used to create the file.
String ArchivalLocation
<IARL-ck>. Indicates where the subject of the file is stored.
Encapsulates sample waves used for playback.
Sample * GetNextSample()
Returns a pointer to the next Sample object of the file, NULL otherwise.
void MoveSubChunk(Chunk *pSrc, Chunk *pDst)
Moves a sub chunk witin this list.
String Name
<INAM-ck>. Stores the title of the subject of the file, such as, Seattle From Above.
uint32_t SamplesPerSecond
Sampling rate at which each channel should be played (defaults to 44100 if Sample was created with In...
String Product
<IPRD-ck>. Specifies the name of the title the file was originally intended for, such as World Ruler ...
File * GetFile() const
Returns pointer to the chunk's File object.
String GetFileName()
File name of this DLS file.
String Medium
<IMED-ck>. Describes the original subject of the file, such as, record, CD, and so forth...
String Subject
<ISBJ-ck>. Describes the contents of the file.
file_offset_t Read(void *pBuffer, file_offset_t SampleCount)
Reads SampleCount number of sample points from the current position into the buffer pointed by pBuffe...
void CopyAssignCore(const Sample *orig)
Make a deep copy of the Sample object given by orig (without the actual sample waveform data however)...
file_offset_t GetFilePos() const
Current, actual offset of chunk data body start in file.
void ReleaseChunkData()
Free loaded chunk body from RAM.
Abstract base class for classes that provide articulation information (thus for Instrument and Region...
Connection * pConnections
Points to the beginning of a Connection array.
uint32_t Connections
Reflects the number of Connections.
virtual void UpdateChunks(progress_t *pProgress)
Apply sample and its settings to the respective RIFF chunks.
virtual void UpdateChunks(progress_t *pProgress)
Apply articulation connections to the respective RIFF chunks.
dlsid_t * pDLSID
Points to a dlsid_t structure if the file provided a DLS ID else is NULL.
uint32_t Instruments
Reflects the number of available Instrument objects.
String Genre
<IGNR-ck>. Descirbes the original work, such as, Jazz, Classic, Rock, Techno, Rave, etc.
Provides all neccessary information for the synthesis of a DLS Instrument.
Quadtuple version number ("major.minor.release.build").
virtual void CopyAssign(const Resource *orig)
Make a deep copy of the Resource object given by orig and assign it to this object.
String Copyright
<ICOP-ck>. Records the copyright information for the file.
file_offset_t Write(void *pBuffer, file_offset_t SampleCount)
Write sample wave data.
Sample * AddSample()
Add a new sample.
file_offset_t GetPos() const
Position within the chunk data body (starting with 0).
DLS specific classes and definitions.
Info * pInfo
Points (in any case) to an Info object, providing additional, optional infos and comments.
String libraryVersion()
Returns version of this C++ library.
Defines a connection within the synthesis model.
file_offset_t ReadInt16(int16_t *pData, file_offset_t WordCount=1)
Reads WordCount number of 16 Bit signed integer words and copies it into the buffer pointed by pData...
virtual void UpdateChunks(progress_t *pProgress)
Apply Region settings to the respective RIFF chunks.
String Comments
<ICMT-ck>. Provides general comments about the file or the subject of the file. Sentences might end w...
List * GetNextSubList()
Returns the next sublist (that is a subchunk with chunk ID "LIST") within the list.
Defines Region information of an Instrument.
Articulation(RIFF::Chunk *artl)
Constructor.
Chunk * AddSubChunk(uint32_t uiChunkID, file_offset_t ullBodySize)
Creates a new sub chunk.
bool IsDrum
Indicates if the Instrument is a drum type, as they differ in the synthesis model of DLS from melodic...
virtual void UpdateChunks(progress_t *pProgress)
Apply all the DLS file's current instruments, samples and settings to the respective RIFF chunks...
void * LoadSampleData()
Load sample data into RAM.
void AddSampleLoop(sample_loop_t *pLoopDef)
Adds a new sample loop with the provided loop definition.
virtual void UpdateFileOffsets()
Updates all file offsets stored all over the file.
Resource(Resource *Parent, RIFF::List *lstResource)
Constructor.