31 #define _1200TH_ROOT_OF_2 1.000577789506555 32 #define _200TH_ROOT_OF_10 1.011579454259899 35 double ToSeconds(
int Timecents) {
36 if (Timecents == NONE)
return NONE;
37 if (Timecents == 0)
return 1.0;
38 if (Timecents == -32768)
return 0.0;
39 return pow(_1200TH_ROOT_OF_2, Timecents);
42 double ToRatio(
int Centibels) {
43 if (Centibels == NONE)
return NONE;
44 if (Centibels == 0)
return 1.0;
45 return pow(_200TH_ROOT_OF_10, Centibels);
48 double ToHz(
int cents) {
49 if (cents == NONE)
return NONE;
50 if (cents == 0)
return 8.176;
51 return pow(_1200TH_ROOT_OF_2, cents) * 8.176;
56 if(ck == NULL)
throw Exception(
"Mandatory chunk in RIFF list chunk not found: " + ToString(chunkId));
60 void LoadString(
RIFF::Chunk* ck, std::string& s,
int strLength) {
61 if(ck == NULL)
return;
62 char* buf =
new char[strLength];
64 for(
int i = 0; i < strLength; i++) {
66 if(buf[i] == 0 && !len) len = i;
68 if(!len) len = strLength;
78 if (ck == NULL)
throw Exception(
"NULL chunk");
80 throw Exception(
"Invalid chunk size. Chunk ID: " + ToString(ck->
GetChunkID()));
84 Modulator::Modulator(SFModulator mod) {
86 Polarity = mod & (1 << 9);
87 Direction = mod & (1 << 8);
88 MidiPalete = mod & (1 << 7);
93 ModulatorItem::ModulatorItem(ModList& mod) :
94 ModSrcOper(Modulator(mod.ModSrcOper)),
95 ModAmtSrcOper(Modulator(mod.ModAmtSrcOper))
119 pVer =
new Version(GetMandatoryChunk(lstINFO, CHUNK_ID_IFIL));
120 LoadString(CHUNK_ID_ISNG, lstINFO, SoundEngine);
121 LoadString(CHUNK_ID_INAM, lstINFO, BankName);
122 LoadString(CHUNK_ID_IROM, lstINFO, RomName);
123 pRomVer =
new Version(lstINFO->
GetSubChunk(CHUNK_ID_IVER));
124 LoadString(CHUNK_ID_ICRD, lstINFO, CreationDate);
125 LoadString(CHUNK_ID_IENG, lstINFO, Engineers);
126 LoadString(CHUNK_ID_IPRD, lstINFO, Product);
127 LoadString(CHUNK_ID_ICOP, lstINFO, Copyright);
128 LoadString(CHUNK_ID_ICMT, lstINFO, Comments);
129 LoadString(CHUNK_ID_ISFT, lstINFO, Software);
145 void Info::LoadString(uint32_t ChunkID,
RIFF::List* lstINFO, String& s) {
152 this->pCkSmpl = pCkSmpl;
153 this->pCkSm24 = pCkSm24;
155 LoadString(ck, Name, 20);
166 if (Start > End || !pCkSmpl || pCkSmpl->
GetSize() <= End) {
167 throw Exception(
"Broken SF2 file (invalid sample info)");
173 case sf2::Sample::MONO_SAMPLE :
174 case sf2::Sample::ROM_MONO_SAMPLE :
break;
175 case sf2::Sample::RIGHT_SAMPLE :
176 case sf2::Sample::LEFT_SAMPLE :
177 case sf2::Sample::ROM_RIGHT_SAMPLE :
178 case sf2::Sample::ROM_LEFT_SAMPLE : ChannelCount = 2;
break;
179 case sf2::Sample::LINKED_SAMPLE :
180 case sf2::Sample::ROM_LINKED_SAMPLE : std::cerr <<
"Linked samples not implemented yet";
break;
181 default:
throw Exception(
"Broken SF2 file (invalid sample type)");
185 RAMCache.pStart = NULL;
186 RAMCache.NullExtensionSize = 0;
189 int Sample::GetChannelCount() {
193 long Sample::GetTotalFrameCount() {
194 return (End - Start);
200 int Sample::GetFrameSize() {
201 return ChannelCount * ((pCkSm24 != NULL) ? 3 : 2);
204 bool Sample::HasLoops() {
205 return StartLoop != 0 && EndLoop != 0;
234 unsigned long Sample::ReadAndLoop (
236 unsigned long FrameCount,
237 PlaybackState* pPlaybackState,
241 unsigned long samplestoread = FrameCount, totalreadsamples = 0, readsamples, samplestoloopend;
242 uint8_t* pDst = (uint8_t*) pBuffer;
243 SetPos(pPlaybackState->position);
244 if (pRegion->HasLoop) {
246 samplestoloopend = pRegion->LoopEnd - GetPos();
247 readsamples = Read(&pDst[totalreadsamples * GetFrameSize()], Min(samplestoread, samplestoloopend));
248 samplestoread -= readsamples;
249 totalreadsamples += readsamples;
250 if (readsamples == samplestoloopend) {
251 SetPos(pRegion->LoopStart);
253 }
while (samplestoread && readsamples);
255 totalreadsamples = Read(pBuffer, FrameCount);
258 pPlaybackState->position = GetPos();
260 return totalreadsamples;
266 pParentInstrument = NULL;
267 loKey = hiKey = NONE;
268 minVel = maxVel = NONE;
269 startAddrsOffset = startAddrsCoarseOffset = endAddrsOffset = endAddrsCoarseOffset = 0;
270 startloopAddrsOffset = startloopAddrsCoarseOffset = endloopAddrsOffset = endloopAddrsCoarseOffset = 0;
271 pan = fineTune = coarseTune = 0;
272 overridingRootKey = -1;
275 LoopStart = LoopEnd = 0;
277 EG1PreAttackDelay = EG1Attack = EG1Hold = EG1Decay = EG1Release = -12000;
279 EG2PreAttackDelay = EG2Attack = EG2Hold = EG2Decay = EG2Release = -12000;
282 modEnvToPitch = modLfoToPitch = modEnvToFilterFc = modLfoToFilterFc = modLfoToVolume = 0;
284 delayModLfo = -12000;
287 delayVibLfo = -12000;
291 initialFilterFc = 13500;
295 int Region::GetUnityNote() {
296 return overridingRootKey != -1 ? overridingRootKey : pSample->OriginalPitch;
299 int CheckRange(std::string genName,
int min,
int max,
int& gen) {
300 if (gen == NONE)
return gen;
303 std::cerr <<
"sf2: " << genName;
304 std::cerr <<
" is below the minimum allowed value (min=" << min <<
"): " << gen << std::endl;
308 std::cerr <<
"sf2: " << genName;
309 std::cerr <<
" is above the maximum allowed value (max=" << max <<
"): " << gen << std::endl;
316 void Region::SetGenerator(sf2::File* pFile, GenList& Gen) {
317 switch(Gen.GenOper) {
318 case START_ADDRS_OFFSET:
319 startAddrsOffset = Gen.GenAmount.wAmount;
321 case END_ADDRS_OFFSET:
322 if (Gen.GenAmount.shAmount <= 0) {
323 endAddrsOffset = Gen.GenAmount.shAmount;
325 std::cerr <<
"Ignoring invalid endAddrsOffset" << std::endl;
328 case STARTLOOP_ADDRS_OFFSET:
329 startloopAddrsOffset = Gen.GenAmount.shAmount;
330 LoopStart += startloopAddrsOffset;
332 case ENDLOOP_ADDRS_OFFSET:
333 endloopAddrsOffset = Gen.GenAmount.shAmount;
334 LoopEnd += endloopAddrsOffset;
336 case START_ADDRS_COARSE_OFFSET:
337 startAddrsCoarseOffset = Gen.GenAmount.wAmount;
339 case MOD_LFO_TO_PITCH:
340 modLfoToPitch = Gen.GenAmount.shAmount;
341 CheckRange(
"modLfoToPitch", -12000, 12000, modLfoToPitch);
343 case VIB_LFO_TO_PITCH:
344 vibLfoToPitch = Gen.GenAmount.shAmount;
345 CheckRange(
"vibLfoToPitch", -12000, 12000, vibLfoToPitch);
347 case MOD_ENV_TO_PITCH:
348 modEnvToPitch = Gen.GenAmount.shAmount;
349 CheckRange(
"modEnvToPitch", -12000, 12000, modEnvToPitch);
351 case INITIAL_FILTER_FC:
352 initialFilterFc = Gen.GenAmount.wAmount;
353 CheckRange(
"initialFilterFc", 1500, 13500, initialFilterFc);
355 case INITIAL_FILTER_Q:
356 initialFilterQ = Gen.GenAmount.wAmount;
357 CheckRange(
"initialFilterQ", 0, 960, initialFilterQ);
359 case MOD_LFO_TO_FILTER_FC:
360 modLfoToFilterFc = Gen.GenAmount.shAmount;
361 CheckRange(
"modLfoToFilterFc", -12000, 12000, modLfoToFilterFc);
363 case MOD_ENV_TO_FILTER_FC:
364 modEnvToFilterFc = Gen.GenAmount.shAmount;
365 CheckRange(
"modEnvToFilterFc", -12000, 12000, modEnvToFilterFc);
367 case END_ADDRS_COARSE_OFFSET:
368 endAddrsCoarseOffset = Gen.GenAmount.wAmount;
370 case MOD_LFO_TO_VOLUME:
371 modLfoToVolume = Gen.GenAmount.shAmount;
372 CheckRange(
"modLfoToVolume", -960, 960, modLfoToVolume);
374 case CHORUS_EFFECTS_SEND:
376 case REVERB_EFFECTS_SEND:
379 pan = Gen.GenAmount.shAmount;
380 CheckRange(
"pan", -500, 500, pan);
381 pan = pan * 64 / 500;
382 if (pan > 63) pan = 63;
385 delayModLfo = Gen.GenAmount.shAmount;
386 CheckRange(
"delayModLfo", -12000, 5000, delayModLfo);
389 freqModLfo = Gen.GenAmount.shAmount;
390 CheckRange(
"freqModLfo", -16000, 4500, freqModLfo);
393 delayVibLfo = Gen.GenAmount.shAmount;
394 CheckRange(
"delayVibLfo", -12000, 5000, delayVibLfo);
397 freqVibLfo = Gen.GenAmount.shAmount;
398 CheckRange(
"freqModLfo", -16000, 4500, freqModLfo);
401 EG2PreAttackDelay = Gen.GenAmount.shAmount;
402 CheckRange(
"delayModEnv", -12000, 5000, EG2PreAttackDelay);
405 EG2Attack = Gen.GenAmount.shAmount;
406 CheckRange(
"attackModEnv", -12000, 8000, EG2Attack);
409 EG2Hold = Gen.GenAmount.shAmount;
410 CheckRange(
"holdModEnv", -12000, 5000, EG2Hold);
413 EG2Decay = Gen.GenAmount.shAmount;
414 CheckRange(
"decayModEnv", -12000, 8000, EG2Decay);
416 case SUSTAIN_MOD_ENV:
417 EG2Sustain = Gen.GenAmount.shAmount;
418 CheckRange(
"sustainModEnv", 0, 1000, EG2Sustain);
420 case RELEASE_MOD_ENV:
421 EG2Release = Gen.GenAmount.shAmount;
422 CheckRange(
"releaseModEnv", -12000, 8000, EG2Release);
424 case KEYNUM_TO_MOD_ENV_HOLD:
426 case KEYNUM_TO_MOD_ENV_DECAY:
429 EG1PreAttackDelay = Gen.GenAmount.shAmount;
430 CheckRange(
"delayVolEnv", -12000, 5000, EG1PreAttackDelay);
433 EG1Attack = Gen.GenAmount.shAmount;
434 CheckRange(
"attackVolEnv", -12000, 8000, EG1Attack);
437 EG1Hold = Gen.GenAmount.shAmount;
438 CheckRange(
"holdVolEnv", -12000, 5000, EG1Hold);
441 EG1Decay = Gen.GenAmount.shAmount;
442 CheckRange(
"decayVolEnv", -12000, 8000, EG1Decay);
444 case SUSTAIN_VOL_ENV:
445 EG1Sustain = Gen.GenAmount.shAmount;
446 CheckRange(
"sustainVolEnv", 0, 1440, EG1Sustain);
448 case RELEASE_VOL_ENV:
449 EG1Release = Gen.GenAmount.shAmount;
450 CheckRange(
"releaseVolEnv", -12000, 8000, EG1Release);
452 case KEYNUM_TO_VOL_ENV_HOLD:
454 case KEYNUM_TO_VOL_ENV_DECAY:
457 uint16_t
id = Gen.GenAmount.wAmount;
458 if (
id >= pFile->Instruments.size()) {
459 throw Exception(
"Broken SF2 file (missing instruments)");
461 pInstrument = pFile->Instruments[id];
465 loKey = Gen.GenAmount.ranges.byLo;
466 CheckRange(
"loKey", 0, 127, loKey);
467 hiKey = Gen.GenAmount.ranges.byHi;
468 CheckRange(
"hiKey", 0, 127, hiKey);
471 minVel = Gen.GenAmount.ranges.byLo;
472 CheckRange(
"minVel", 0, 127, minVel);
473 maxVel = Gen.GenAmount.ranges.byHi;
474 CheckRange(
"maxVel", 0, 127, maxVel);
476 case STARTLOOP_ADDRS_COARSE_OFFSET:
477 startloopAddrsCoarseOffset = Gen.GenAmount.wAmount;
478 LoopStart += startloopAddrsCoarseOffset * 32768;
484 case INITIAL_ATTENUATION:
486 case ENDLOOP_ADDRS_COARSE_OFFSET:
487 endloopAddrsCoarseOffset = Gen.GenAmount.wAmount;
488 LoopEnd += endloopAddrsCoarseOffset * 32768;
491 coarseTune = Gen.GenAmount.shAmount;
492 CheckRange(
"coarseTune", -120, 120, coarseTune);
495 fineTune = Gen.GenAmount.shAmount;
496 CheckRange(
"fineTune", -99, 99, fineTune);
499 uint16_t sid = Gen.GenAmount.wAmount;
500 if (sid >= pFile->Samples.size()) {
501 throw Exception(
"Broken SF2 file (missing samples)");
503 pSample = pFile->Samples[sid];
506 LoopStart += pSample->StartLoop;
507 LoopEnd += pSample->EndLoop;
508 if ( LoopStart < pSample->Start || LoopStart > pSample->End ||
509 LoopStart > LoopEnd || LoopEnd > pSample->End ) {
510 throw Exception(
"Broken SF2 file (invalid loops)");
512 LoopStart -= pSample->Start;
513 LoopEnd -= pSample->Start;
518 HasLoop = Gen.GenAmount.wAmount & 1;
524 case EXCLUSIVE_CLASS:
525 exclusiveClass = Gen.GenAmount.wAmount;
527 case OVERRIDING_ROOT_KEY:
528 overridingRootKey = Gen.GenAmount.shAmount;
529 CheckRange(
"overridingRootKey", -1, 127, overridingRootKey);
534 void Region::SetModulator(sf2::File* pFile, ModList& Mod) {
535 modulators.push_back(ModulatorItem(Mod));
557 int Region::GetPan(
Region* pPresetRegion) {
558 if (pPresetRegion == NULL)
return pan;
559 int p = pPresetRegion->pan + pan;
560 if (p < -64) p = -64;
565 int Region::GetFineTune(
Region* pPresetRegion) {
566 if (pPresetRegion == NULL)
return fineTune;
567 int t = pPresetRegion->fineTune + fineTune;
568 if (t < -99) t = -99;
573 int Region::GetCoarseTune(
Region* pPresetRegion) {
574 if (pPresetRegion == NULL)
return coarseTune;
575 int t = pPresetRegion->coarseTune + coarseTune;
576 if (t < -120) t = -120;
577 if (t > 120) t = 120;
581 double Region::GetEG1PreAttackDelay(
Region* pPresetRegion) {
582 int val = (pPresetRegion == NULL || pPresetRegion->EG1PreAttackDelay == NONE) ?
583 EG1PreAttackDelay : pPresetRegion->EG1PreAttackDelay + EG1PreAttackDelay;
584 return ToSeconds(CheckRange(
"GetEG1PreAttackDelay()", -12000, 5000, val));
587 double Region::GetEG1Attack(
Region* pPresetRegion) {
588 int val = (pPresetRegion == NULL || pPresetRegion->EG1Attack == NONE) ?
589 EG1Attack : pPresetRegion->EG1Attack + EG1Attack;
590 return ToSeconds(CheckRange(
"GetEG1Attack()", -12000, 8000, val));
593 double Region::GetEG1Hold(
Region* pPresetRegion) {
594 int val = (pPresetRegion == NULL || pPresetRegion->EG1Hold == NONE) ?
595 EG1Hold : pPresetRegion->EG1Hold + EG1Hold;
596 return ToSeconds(CheckRange(
"GetEG1Hold()", -12000, 5000, val));
599 double Region::GetEG1Decay(
Region* pPresetRegion) {
600 int val = (pPresetRegion == NULL || pPresetRegion->EG1Decay == NONE) ?
601 EG1Decay : pPresetRegion->EG1Decay + EG1Decay;
602 return ToSeconds(CheckRange(
"GetEG1Decay()", -12000, 8000, val));
605 int Region::GetEG1Sustain(
Region* pPresetRegion) {
606 int val = (pPresetRegion == NULL || pPresetRegion->EG1Sustain == NONE) ?
607 EG1Sustain : pPresetRegion->EG1Sustain + EG1Sustain;
608 return CheckRange(
"GetEG1Sustain()", 0, 1440, val);
611 double Region::GetEG1Release(
Region* pPresetRegion) {
612 int val = (pPresetRegion == NULL || pPresetRegion->EG1Release == NONE) ?
613 EG1Release : pPresetRegion->EG1Release + EG1Release;
614 return ToSeconds(CheckRange(
"GetEG1Release()", -12000, 8000, val));
617 double Region::GetEG2PreAttackDelay(
Region* pPresetRegion) {
618 int val = (pPresetRegion == NULL || pPresetRegion->EG2PreAttackDelay == NONE) ?
619 EG2PreAttackDelay : pPresetRegion->EG2PreAttackDelay + EG2PreAttackDelay;
620 return ToSeconds(CheckRange(
"GetEG2PreAttackDelay()", -12000, 5000, val));
623 double Region::GetEG2Attack(
Region* pPresetRegion) {
624 int val = (pPresetRegion == NULL || pPresetRegion->EG2Attack == NONE) ?
625 EG2Attack : pPresetRegion->EG2Attack + EG2Attack;
626 return ToSeconds(CheckRange(
"GetEG2Attack()", -12000, 8000, val));
629 double Region::GetEG2Hold(
Region* pPresetRegion) {
630 int val = (pPresetRegion == NULL || pPresetRegion->EG2Hold == NONE) ?
631 EG2Hold : pPresetRegion->EG2Hold + EG2Hold;
632 return ToSeconds(CheckRange(
"GetEG2Hold()", -12000, 5000, val));
635 double Region::GetEG2Decay(
Region* pPresetRegion) {
636 int val = (pPresetRegion == NULL || pPresetRegion->EG2Decay == NONE) ?
637 EG2Decay : pPresetRegion->EG2Decay + EG2Decay;
638 return ToSeconds(CheckRange(
"GetEG2Decay()", -12000, 8000, val));
641 int Region::GetEG2Sustain(
Region* pPresetRegion) {
642 int val = (pPresetRegion == NULL || pPresetRegion->EG2Sustain == NONE) ?
643 EG2Sustain : pPresetRegion->EG2Sustain + EG2Sustain;
644 return CheckRange(
"GetEG2Sustain()", 0, 1000, val);
647 double Region::GetEG2Release(
Region* pPresetRegion) {
648 int val = (pPresetRegion == NULL || pPresetRegion->EG2Release == NONE) ?
649 EG2Release : pPresetRegion->EG2Release + EG2Release;
650 return ToSeconds(CheckRange(
"GetEG2Release()", -12000, 8000, val));
653 int Region::GetModEnvToPitch(
Region* pPresetRegion) {
654 int val = (pPresetRegion == NULL || pPresetRegion->modEnvToPitch == NONE) ?
655 modEnvToPitch : pPresetRegion->modEnvToPitch + modEnvToPitch;
656 return CheckRange(
"GetModEnvToPitch()", -12000, 12000, val);
659 int Region::GetModLfoToPitch(
Region* pPresetRegion) {
660 int val = (pPresetRegion == NULL || pPresetRegion->modLfoToPitch == NONE) ?
661 modLfoToPitch : pPresetRegion->modLfoToPitch + modLfoToPitch;
662 return CheckRange(
"GetModLfoToPitch()", -12000, 12000, val);
665 int Region::GetModEnvToFilterFc(
Region* pPresetRegion) {
666 int val = (pPresetRegion == NULL || pPresetRegion->modEnvToFilterFc == NONE) ?
667 modEnvToFilterFc : pPresetRegion->modEnvToFilterFc + modEnvToFilterFc;
668 return CheckRange(
"GetModEnvToFilterFc()", -12000, +12000, val);
671 int Region::GetModLfoToFilterFc(
Region* pPresetRegion) {
672 int val = (pPresetRegion == NULL || pPresetRegion->modLfoToFilterFc == NONE) ?
673 modLfoToFilterFc : pPresetRegion->modLfoToFilterFc + modLfoToFilterFc;
674 return CheckRange(
"GetModLfoToFilterFc()", -12000, +12000, val);
677 double Region::GetModLfoToVolume(
Region* pPresetRegion) {
678 int val = (pPresetRegion == NULL || pPresetRegion->modLfoToVolume == NONE) ?
679 modLfoToVolume : pPresetRegion->modLfoToVolume + modLfoToVolume;
680 return CheckRange(
"GetModLfoToVolume()", -960, 960, val);
683 double Region::GetFreqModLfo(
Region* pPresetRegion) {
684 int val = (pPresetRegion == NULL || pPresetRegion->freqModLfo == NONE) ?
685 freqModLfo : pPresetRegion->freqModLfo + freqModLfo;
686 return ToHz(CheckRange(
"GetFreqModLfo()", -16000, 4500, val));
689 double Region::GetDelayModLfo(
Region* pPresetRegion) {
690 int val = (pPresetRegion == NULL || pPresetRegion->delayModLfo == NONE) ?
691 delayModLfo : pPresetRegion->delayModLfo + delayModLfo;
692 return ToSeconds(CheckRange(
"GetDelayModLfo()", -12000, 5000, val));
695 int Region::GetVibLfoToPitch(
Region* pPresetRegion) {
696 int val = (pPresetRegion == NULL || pPresetRegion->vibLfoToPitch == NONE) ?
697 vibLfoToPitch : pPresetRegion->vibLfoToPitch + vibLfoToPitch;
698 return CheckRange(
"GetVibLfoToPitch()", -12000, 12000, val);
701 double Region::GetFreqVibLfo(
Region* pPresetRegion) {
702 int val = (pPresetRegion == NULL || pPresetRegion->freqVibLfo == NONE) ?
703 freqVibLfo : pPresetRegion->freqVibLfo + freqVibLfo;
704 return ToHz(CheckRange(
"GetFreqVibLfo()", -16000, 4500, val));
707 double Region::GetDelayVibLfo(
Region* pPresetRegion) {
708 int val = (pPresetRegion == NULL || pPresetRegion->delayVibLfo == NONE) ?
709 delayVibLfo : pPresetRegion->delayVibLfo + delayVibLfo;
710 return ToSeconds(CheckRange(
"GetDelayVibLfo()", -12000, 5000, val));
713 int Region::GetInitialFilterFc(
Region* pPresetRegion) {
714 if (pPresetRegion == NULL || pPresetRegion->initialFilterFc == NONE)
return initialFilterFc;
715 int val = pPresetRegion->initialFilterFc + initialFilterFc;
716 return CheckRange(
"GetInitialFilterFc()", 1500, 13500, val);
719 int Region::GetInitialFilterQ(
Region* pPresetRegion) {
720 int val = (pPresetRegion == NULL || pPresetRegion->initialFilterQ == NONE) ?
721 initialFilterQ : pPresetRegion->initialFilterQ + initialFilterQ;
722 return CheckRange(
"GetInitialFilterQ()", 0, 960, val);
725 InstrumentBase::InstrumentBase(sf2::File* pFile) {
727 pGlobalRegion = NULL;
730 InstrumentBase::~InstrumentBase() {
731 if (pGlobalRegion)
delete pGlobalRegion;
732 for (ssize_t i = regions.size() - 1; i >= 0; i--) {
733 if (regions[i])
delete (regions[i]);
737 int InstrumentBase::GetRegionCount() {
738 return (
int) regions.size();
741 Region* InstrumentBase::GetRegion(
int idx) {
742 if (idx < 0 || idx >= GetRegionCount()) {
743 throw Exception(
"Region index out of bounds");
749 Query::Query(InstrumentBase& instrument) : instrument(instrument) {
754 while (i < instrument.GetRegionCount()) {
755 Region* r = instrument.GetRegion(i++);
756 if (((r->loKey == NONE && r->hiKey == NONE) || (key >= r->loKey && key <= r->hiKey)) &&
757 ((r->minVel == NONE && r->maxVel == NONE) || (vel >= r->minVel && vel <= r->maxVel))) {
764 Instrument::Instrument(sf2::File* pFile,
RIFF::Chunk* ck) : InstrumentBase(pFile) {
766 LoadString(ck, Name, 20);
770 Instrument::~Instrument() {
773 Region* Instrument::CreateRegion() {
775 r->pParentInstrument =
this;
777 if (pGlobalRegion != NULL) {
778 r->loKey = pGlobalRegion->loKey;
779 r->hiKey = pGlobalRegion->hiKey;
780 r->minVel = pGlobalRegion->minVel;
781 r->maxVel = pGlobalRegion->maxVel;
782 r->pan = pGlobalRegion->pan;
783 r->fineTune = pGlobalRegion->fineTune;
784 r->coarseTune = pGlobalRegion->coarseTune;
785 r->overridingRootKey = pGlobalRegion->overridingRootKey;
786 r->startAddrsOffset = pGlobalRegion->startAddrsOffset;
787 r->startAddrsCoarseOffset = pGlobalRegion->startAddrsCoarseOffset;
788 r->endAddrsOffset = pGlobalRegion->endAddrsOffset;
789 r->endAddrsCoarseOffset = pGlobalRegion->endAddrsCoarseOffset;
790 r->startloopAddrsOffset = pGlobalRegion->startloopAddrsOffset;
791 r->startloopAddrsCoarseOffset = pGlobalRegion->startloopAddrsCoarseOffset;
792 r->endloopAddrsOffset = pGlobalRegion->endloopAddrsOffset;
793 r->endloopAddrsCoarseOffset = pGlobalRegion->endloopAddrsCoarseOffset;
795 r->EG1PreAttackDelay = pGlobalRegion->EG1PreAttackDelay;
796 r->EG1Attack = pGlobalRegion->EG1Attack;
797 r->EG1Hold = pGlobalRegion->EG1Hold;
798 r->EG1Decay = pGlobalRegion->EG1Decay;
799 r->EG1Sustain = pGlobalRegion->EG1Sustain;
800 r->EG1Release = pGlobalRegion->EG1Release;
802 r->EG2PreAttackDelay = pGlobalRegion->EG2PreAttackDelay;
803 r->EG2Attack = pGlobalRegion->EG2Attack;
804 r->EG2Hold = pGlobalRegion->EG2Hold;
805 r->EG2Decay = pGlobalRegion->EG2Decay;
806 r->EG2Sustain = pGlobalRegion->EG2Sustain;
807 r->EG2Release = pGlobalRegion->EG2Release;
809 r->modEnvToPitch = pGlobalRegion->modEnvToPitch;
810 r->modLfoToPitch = pGlobalRegion->modLfoToPitch;
811 r->modEnvToFilterFc = pGlobalRegion->modEnvToFilterFc;
812 r->modLfoToFilterFc = pGlobalRegion->modLfoToFilterFc;
813 r->modLfoToVolume = pGlobalRegion->modLfoToVolume;
814 r->freqModLfo = pGlobalRegion->freqModLfo;
815 r->delayModLfo = pGlobalRegion->delayModLfo;
816 r->vibLfoToPitch = pGlobalRegion->vibLfoToPitch;
817 r->freqVibLfo = pGlobalRegion->freqVibLfo;
818 r->delayVibLfo = pGlobalRegion->delayVibLfo;
819 r->initialFilterFc = pGlobalRegion->initialFilterFc;
820 r->initialFilterQ = pGlobalRegion->initialFilterQ;
822 r->HasLoop = pGlobalRegion->HasLoop;
823 r->LoopStart = pGlobalRegion->LoopStart;
824 r->LoopEnd = pGlobalRegion->LoopEnd;
826 r->exclusiveClass = pGlobalRegion->exclusiveClass;
832 void Instrument::DeleteRegion(
Region* pRegion) {
833 for (
int i = 0; i < regions.size(); i++) {
834 if (regions[i] == pRegion) {
841 std::cerr <<
"Can't remove unknown Region" << std::endl;
844 void Instrument::LoadRegions(
int idx1,
int idx2) {
845 for (
int i = idx1; i < idx2; i++) {
846 int gIdx1 = pFile->InstBags[i].InstGenNdx;
847 int gIdx2 = pFile->InstBags[i + 1].InstGenNdx;
849 if (gIdx1 < 0 || gIdx2 < 0 || gIdx1 > gIdx2 || gIdx2 >= pFile->InstGenLists.size()) {
850 throw Exception(
"Broken SF2 file (invalid InstGenNdx)");
853 int mIdx1 = pFile->InstBags[i].InstModNdx;
854 int mIdx2 = pFile->InstBags[i + 1].InstModNdx;
856 if (mIdx1 < 0 || mIdx2 < 0 || mIdx1 > mIdx2 || mIdx2 >= pFile->InstModLists.size()) {
857 throw Exception(
"Broken SF2 file (invalid InstModNdx)");
860 Region* reg = CreateRegion();
862 for (
int j = gIdx1; j < gIdx2; j++) {
863 reg->SetGenerator(pFile, pFile->InstGenLists[j]);
867 for (
int j = mIdx1; j < mIdx2; j++) {
868 reg->SetModulator(pFile, pFile->InstModLists[j]);
871 if (reg->pSample == NULL) {
872 if (i == idx1 && idx2 - idx1 > 1) {
875 std::cerr <<
"Ignoring instrument's region without sample" << std::endl;
879 regions.push_back(reg);
884 Preset::Preset(sf2::File* pFile,
RIFF::Chunk* ck): InstrumentBase(pFile) {
886 LoadString(ck, Name, 20);
898 Region* Preset::CreateRegion() {
901 r->EG1PreAttackDelay = r->EG1Attack = r->EG1Hold = r->EG1Decay = r->EG1Sustain = r->EG1Release = NONE;
902 r->EG2PreAttackDelay = r->EG2Attack = r->EG2Hold = r->EG2Decay = r->EG2Sustain = r->EG2Release = NONE;
903 r->freqModLfo = r->delayModLfo = r->freqVibLfo = r->delayVibLfo = NONE;
904 r->initialFilterFc = r->initialFilterQ = NONE;
906 if (pGlobalRegion != NULL) {
907 r->pan = pGlobalRegion->pan;
908 r->fineTune = pGlobalRegion->fineTune;
909 r->coarseTune = pGlobalRegion->coarseTune;
911 r->EG1PreAttackDelay = pGlobalRegion->EG1PreAttackDelay;
912 r->EG1Attack = pGlobalRegion->EG1Attack;
913 r->EG1Hold = pGlobalRegion->EG1Hold;
914 r->EG1Decay = pGlobalRegion->EG1Decay;
915 r->EG1Sustain = pGlobalRegion->EG1Sustain;
916 r->EG1Release = pGlobalRegion->EG1Release;
918 r->EG2PreAttackDelay = pGlobalRegion->EG2PreAttackDelay;
919 r->EG2Attack = pGlobalRegion->EG2Attack;
920 r->EG2Hold = pGlobalRegion->EG2Hold;
921 r->EG2Decay = pGlobalRegion->EG2Decay;
922 r->EG2Sustain = pGlobalRegion->EG2Sustain;
923 r->EG2Release = pGlobalRegion->EG2Release;
925 r->modEnvToPitch = pGlobalRegion->modEnvToPitch;
926 r->modLfoToPitch = pGlobalRegion->modLfoToPitch;
927 r->modEnvToFilterFc = pGlobalRegion->modEnvToFilterFc;
928 r->modLfoToFilterFc = pGlobalRegion->modLfoToFilterFc;
929 r->modLfoToVolume = pGlobalRegion->modLfoToVolume;
930 r->freqModLfo = pGlobalRegion->freqModLfo;
931 r->delayModLfo = pGlobalRegion->delayModLfo;
932 r->vibLfoToPitch = pGlobalRegion->vibLfoToPitch;
933 r->freqVibLfo = pGlobalRegion->freqVibLfo;
934 r->delayVibLfo = pGlobalRegion->delayVibLfo;
935 r->initialFilterFc = pGlobalRegion->initialFilterFc;
936 r->initialFilterQ = pGlobalRegion->initialFilterQ;
942 void Preset::LoadRegions(
int idx1,
int idx2) {
943 for (
int i = idx1; i < idx2; i++) {
944 int gIdx1 = pFile->PresetBags[i].GenNdx;
945 int gIdx2 = pFile->PresetBags[i + 1].GenNdx;
947 if (gIdx1 < 0 || gIdx2 < 0 || gIdx1 > gIdx2 || gIdx2 >= pFile->PresetGenLists.size()) {
948 throw Exception(
"Broken SF2 file (invalid PresetGenNdx)");
951 Region* reg = CreateRegion();
953 for (
int j = gIdx1; j < gIdx2; j++) {
954 reg->SetGenerator(pFile, pFile->PresetGenLists[j]);
956 if (reg->pInstrument == NULL) {
957 if (i == idx1 && idx2 - idx1 > 1) {
960 std::cerr <<
"Ignoring preset's region without instrument" << std::endl;
964 regions.push_back(reg);
979 if (!pRIFF)
throw Exception(
"NULL pointer reference to RIFF::File object.");
983 throw Exception(
"Not a SF2 file");
986 pInfo =
new Info(pRIFF);
987 if (pInfo->pVer->Major != 2) {
988 throw Exception(
"Unsupported version: " + ToString(pInfo->pVer->Major));
992 if (lstSDTA == NULL) {
993 throw Exception(
"Broken SF2 file (missing sdta)");
998 if (pCkSmpl != NULL && pCkSm24 != NULL) {
999 long l = pCkSmpl->
GetSize() / 2;
1001 if (pCkSm24->
GetSize() != l) {
1007 if (lstPDTA == NULL) {
1008 throw Exception(
"Broken SF2 file (missing pdta)");
1013 throw Exception(
"Broken SF2 file (broken phdr)");
1016 int count = (int) ck->
GetSize() / 38;
1017 for (
int i = 0; i < count; i++) {
1018 Presets.push_back(
new Preset(
this, ck));
1021 ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PBAG);
1023 throw Exception(
"Broken SF2 file (broken pbag)");
1026 count = int(ck->
GetSize() / 4);
1027 for (
int i = 0; i < count; i++) {
1031 PresetBags.push_back(pb);
1035 ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PMOD);
1037 throw Exception(
"Broken SF2 file (broken pmod)");
1040 count = int(ck->
GetSize() / 10);
1041 for (
int i = 0; i < count; i++) {
1048 PresetModLists.push_back(ml);
1052 ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PGEN);
1054 throw Exception(
"Broken SF2 file (broken pgen)");
1057 count = int(ck->
GetSize() / 4);
1058 for (
int i = 0; i < count; i++) {
1062 PresetGenLists.push_back(gl);
1066 ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_INST);
1068 throw Exception(
"Broken SF2 file (broken inst)");
1070 count = int(ck->
GetSize() / 22);
1071 for (
int i = 0; i < count; i++) {
1072 Instruments.push_back(
new Instrument(
this, ck));
1075 ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IBAG);
1077 throw Exception(
"Broken SF2 file (broken ibag)");
1080 count = int(ck->
GetSize() / 4);
1081 for (
int i = 0; i < count; i++) {
1085 InstBags.push_back(ib);
1089 ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IMOD);
1091 throw Exception(
"Broken SF2 file (broken imod)");
1094 count = int(ck->
GetSize() / 10);
1095 for (
int i = 0; i < count; i++) {
1102 InstModLists.push_back(ml);
1106 ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IGEN);
1108 throw Exception(
"Broken SF2 file (broken igen)");
1111 count = int(ck->
GetSize() / 4);
1112 for (
int i = 0; i < count; i++) {
1116 InstGenLists.push_back(gl);
1120 ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_SHDR);
1122 throw Exception(
"Broken SF2 file (broken shdr)");
1124 count = int(ck->
GetSize() / 46);
1125 for (
int i = 0; i < count; i++) {
1126 Samples.push_back(
new Sample(
this, ck, pCkSmpl, pCkSm24));
1130 for (
int i = 0; i < Instruments.size() - 1; i++) {
1131 Instrument* instr = Instruments[i];
1132 int x1 = instr->InstBagNdx;
1133 int x2 = Instruments[i + 1]->InstBagNdx;
1134 if (x1 < 0 || x2 < 0 || x1 > x2 || x2 >= InstBags.size()) {
1135 throw Exception(
"Broken SF2 file (invalid InstBagNdx)");
1138 instr->LoadRegions(x1, x2);
1142 for (
int i = 0; i < Presets.size() - 1; i++) {
1143 Preset* preset = Presets[i];
1144 int x1 = preset->PresetBagNdx;
1145 int x2 = Presets[i + 1]->PresetBagNdx;
1146 if (x1 < 0 || x2 < 0 || x1 > x2 || x2 >= PresetBags.size()) {
1147 throw Exception(
"Broken SF2 file (invalid PresetBagNdx)");
1150 preset->LoadRegions(x1, x2);
1156 for (ssize_t i = Presets.size() - 1; i >= 0; i--) {
1157 if (Presets[i])
delete (Presets[i]);
1159 for (ssize_t i = Instruments.size() - 1; i >= 0; i--) {
1160 if (Instruments[i])
delete (Instruments[i]);
1162 for (ssize_t i = Samples.size() - 1; i >= 0; i--) {
1163 if (Samples[i])
delete (Samples[i]);
1167 int File::GetPresetCount() {
1168 return (
int) Presets.size() - 1;
1171 Preset* File::GetPreset(
int idx) {
1172 if (idx < 0 || idx >= GetPresetCount()) {
1173 throw Exception(
"Preset index out of bounds");
1176 return Presets[idx];
1179 int File::GetInstrumentCount() {
1180 return (
int) Instruments.size() - 1;
1183 Instrument* File::GetInstrument(
int idx) {
1184 if (idx < 0 || idx >= GetInstrumentCount()) {
1185 throw Exception(
"Instrument index out of bounds");
1188 return Instruments[idx];
1191 void File::DeleteInstrument(Instrument* pInstrument) {
1192 if (!pInstrument)
return;
1194 for (
int i = 0; i < GetPresetCount(); i++) {
1195 Preset* p = GetPreset(i);
1196 if (p == NULL)
continue;
1197 for (
int j = p->GetRegionCount() - 1; j >= 0 ; j--) {
1198 if (p->GetRegion(j) && p->GetRegion(j)->pInstrument == pInstrument) {
1199 p->GetRegion(j)->pInstrument = NULL;
1204 for (
int i = 0; i < GetInstrumentCount(); i++) {
1205 if (GetInstrument(i) == pInstrument) {
1206 Instruments[i] = NULL;
1216 int File::GetSampleCount() {
1217 return (
int) Samples.size() - 1;
1220 Sample* File::GetSample(
int idx) {
1221 if (idx < 0 || idx >= GetSampleCount()) {
1222 throw Exception(
"Sample index out of bounds");
1225 return Samples[idx];
1228 void File::DeleteSample(Sample* pSample) {
1230 for (
int i = GetInstrumentCount() - 1; i >= 0; i--) {
1231 Instrument* pInstr = GetInstrument(i);
1232 if (pInstr == NULL)
continue;
1234 for (
int j = pInstr->GetRegionCount() - 1; j >= 0 ; j--) {
1235 if (pInstr->GetRegion(j) && pInstr->GetRegion(j)->GetSample() == pSample) {
1236 std::cerr <<
"Deleting sample which is still in use" << std::endl;
1242 for (
int i = 0; i < GetSampleCount(); i++) {
1243 if (Samples[i] == pSample) {
1250 throw Exception(
"Unknown sample: " + pSample->Name);
1253 bool File::HasSamples() {
1254 for (
int i = 0; i < GetSampleCount(); i++) {
1255 if (Samples[i] != NULL)
return true;
1275 return LoadSampleDataWithNullSamplesExtension(GetTotalFrameCount(), 0);
1297 return LoadSampleDataWithNullSamplesExtension(SampleCount, 0);
1319 Sample::buffer_t Sample::LoadSampleDataWithNullSamplesExtension(uint NullSamplesCount) {
1320 return LoadSampleDataWithNullSamplesExtension(GetTotalFrameCount(), NullSamplesCount);
1351 Sample::buffer_t Sample::LoadSampleDataWithNullSamplesExtension(
unsigned long SampleCount, uint NullSamplesCount) {
1352 if (SampleCount > GetTotalFrameCount()) SampleCount = GetTotalFrameCount();
1353 if (RAMCache.pStart)
delete[] (int8_t*) RAMCache.pStart;
1354 unsigned long allocationsize = (SampleCount + NullSamplesCount) * GetFrameSize();
1356 RAMCache.pStart =
new int8_t[allocationsize];
1357 RAMCache.Size = Read(RAMCache.pStart, SampleCount) * GetFrameSize();
1358 RAMCache.NullExtensionSize = allocationsize - RAMCache.Size;
1360 memset((int8_t*)RAMCache.pStart + RAMCache.Size, 0, RAMCache.NullExtensionSize);
1377 result.
Size = this->RAMCache.Size;
1378 result.pStart = this->RAMCache.pStart;
1379 result.NullExtensionSize = this->RAMCache.NullExtensionSize;
1389 void Sample::ReleaseSampleData() {
1390 if (RAMCache.pStart)
delete[] (int8_t*) RAMCache.pStart;
1391 RAMCache.pStart = NULL;
1393 RAMCache.NullExtensionSize = 0;
1405 unsigned long Sample::SetPos(
unsigned long SampleCount) {
1406 pCkSmpl->
SetPos((Start * 2) + (SampleCount * 2), RIFF::stream_start);
1407 if(pCkSm24) pCkSm24->
SetPos(Start + SampleCount, RIFF::stream_start);
1414 unsigned long Sample::GetPos() {
1415 return (pCkSmpl->
GetPos() - (Start * 2)) / 2;
1419 template<
bool CLEAR>
1420 inline unsigned long ReadSample(Sample* pSample,
void* pBuffer,
unsigned long SampleCount,
Sample::buffer_t* tempBuffer = NULL) {
1422 if (SampleCount == 0)
return 0;
1423 long pos = pSample->GetPos();
1424 if (pos + SampleCount > pSample->GetTotalFrameCount())
1425 SampleCount = pSample->GetTotalFrameCount() - pos;
1427 if (tempBuffer->Size < SampleCount * pSample->GetFrameSize()) {
1428 std::cerr <<
"sf2::Sample error: tempBuffer too small. This is a BUG!" << std::endl;
1433 if (pSample->GetFrameSize() / pSample->GetChannelCount() == 3 ) {
1434 uint8_t*
const pTmpBuf = (uint8_t*) ((CLEAR) ? pBuffer : tempBuffer->pStart);
1435 uint8_t*
const pBuf = (uint8_t*)pBuffer;
1436 if (pSample->SampleType == Sample::MONO_SAMPLE || pSample->SampleType == Sample::ROM_MONO_SAMPLE) {
1437 pSample->pCkSmpl->Read(pTmpBuf, SampleCount, 2);
1438 pSample->pCkSm24->Read(pTmpBuf + SampleCount * 2, SampleCount, 1);
1439 for (
long i = SampleCount - 1; i >= 0; i--) {
1440 pBuf[i*3] = pTmpBuf[(SampleCount * 2) + i];
1441 pBuf[i*3 + 2] = pTmpBuf[i*2 + 1];
1442 pBuf[i*3 + 1] = pTmpBuf[i*2];
1444 }
else if (pSample->SampleType == Sample::LEFT_SAMPLE || pSample->SampleType == Sample::ROM_LEFT_SAMPLE) {
1445 pSample->pCkSmpl->Read(pTmpBuf, SampleCount, 2);
1446 pSample->pCkSm24->Read(pTmpBuf + SampleCount * 2, SampleCount, 1);
1447 for (
long i = SampleCount - 1; i >= 0; i--) {
1448 pBuf[i*6] = pTmpBuf[(SampleCount * 2) + i];
1449 pBuf[i*6 + 2] = pTmpBuf[i*2 + 1];
1450 pBuf[i*6 + 1] = pTmpBuf[i*2];
1452 pBuf[i*6 + 3] = pBuf[i*6 + 4] = pBuf[i*6 + 5] = 0;
1454 }
else if (pSample->SampleType == Sample::RIGHT_SAMPLE || pSample->SampleType == Sample::ROM_RIGHT_SAMPLE) {
1455 pSample->pCkSmpl->Read(pTmpBuf, SampleCount, 2);
1456 pSample->pCkSm24->Read(pTmpBuf + SampleCount * 2, SampleCount, 1);
1457 for (
long i = SampleCount - 1; i >= 0; i--) {
1458 pBuf[i*6 + 3] = pTmpBuf[(SampleCount * 2) + i];
1459 pBuf[i*6 + 5] = pTmpBuf[i*2 + 1];
1460 pBuf[i*6 + 4] = pTmpBuf[i*2];
1462 pBuf[i*6] = pBuf[i*6 + 1] = pBuf[i*6 + 2] = 0;
1466 if (pSample->SampleType == Sample::MONO_SAMPLE || pSample->SampleType == Sample::ROM_MONO_SAMPLE) {
1467 return pSample->pCkSmpl->Read(pBuffer, SampleCount, 2);
1470 int16_t*
const pTmpBuf = (int16_t*) ((CLEAR) ? pBuffer : tempBuffer->pStart);
1471 int16_t*
const pBuf = (int16_t*) pBuffer;
1472 if (pSample->SampleType == Sample::LEFT_SAMPLE || pSample->SampleType == Sample::ROM_LEFT_SAMPLE) {
1473 pSample->pCkSmpl->Read(pTmpBuf, SampleCount, 2);
1474 for (
long i = SampleCount - 1; i >= 0; i--) {
1475 pBuf[i*2] = pTmpBuf[i];
1479 }
else if (pSample->SampleType == Sample::RIGHT_SAMPLE || pSample->SampleType == Sample::ROM_RIGHT_SAMPLE) {
1480 pSample->pCkSmpl->Read(pTmpBuf, SampleCount, 2);
1481 for (
long i = SampleCount - 1; i >= 0; i--) {
1484 pBuf[i*2 + 1] = pTmpBuf[i];
1489 if (pSample->pCkSmpl->GetPos() > (pSample->End * 2)) {
1490 std::cerr <<
"Read after the sample end. This is a BUG!" << std::endl;
1491 std::cerr <<
"Current position: " << pSample->GetPos() << std::endl;
1492 std::cerr <<
"Total number of frames: " << pSample->GetTotalFrameCount() << std::endl << std::endl;
1520 unsigned long Sample::Read(
void* pBuffer,
unsigned long SampleCount) {
1521 return ReadSample<true>(
this, pBuffer, SampleCount);
1554 unsigned long Sample::ReadNoClear(
void* pBuffer,
unsigned long SampleCount, buffer_t& tempBuffer) {
1555 return ReadSample<false>(
this, pBuffer, SampleCount, &tempBuffer);
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...
file_offset_t GetSize() const
Chunk size in bytes (without header, thus the chunk data body)
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...
String libraryVersion()
Returns version of this C++ library.
file_offset_t Size
Size of the actual data in the buffer in bytes.
String libraryName()
Returns the name of this C++ library.
void VerifySize(RIFF::Chunk *ck, int size)
Throws an error if the chunk is NULL or the chunk data size is less than size (in bytes)...
List * GetSubList(uint32_t ListType)
Returns sublist chunk with list type ListType within this chunk list.
SoundFont specific classes and definitions.
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)...
Chunk * GetSubChunk(uint32_t ChunkID)
Returns subchunk with chunk ID ChunkID within this chunk list.
uint32_t GetChunkID() const
Chunk ID in unsigned integer representation.
uint32_t GetListType() const
Returns unsigned integer representation of the list's ID.
file_offset_t ReadInt8(int8_t *pData, file_offset_t WordCount=1)
Reads WordCount number of 8 Bit signed integer words and copies it into the buffer pointed by pData...
Pointer address and size of a buffer.
file_offset_t GetPos() const
Current read/write position within the chunk data body (starting with 0).
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...