229 |
unsigned long Sample::ReadAndLoop ( |
unsigned long Sample::ReadAndLoop ( |
230 |
void* pBuffer, |
void* pBuffer, |
231 |
unsigned long FrameCount, |
unsigned long FrameCount, |
232 |
PlaybackState* pPlaybackState |
PlaybackState* pPlaybackState, |
233 |
|
Region* pRegion |
234 |
) { |
) { |
235 |
|
// TODO: startAddrsCoarseOffset, endAddrsCoarseOffset |
236 |
|
unsigned long samplestoread = FrameCount, totalreadsamples = 0, readsamples, samplestoloopend; |
237 |
|
uint8_t* pDst = (uint8_t*) pBuffer; |
238 |
SetPos(pPlaybackState->position); |
SetPos(pPlaybackState->position); |
239 |
long frames = Read(pBuffer, FrameCount); |
if (pRegion->HasLoop) { |
240 |
|
do { |
241 |
|
samplestoloopend = pRegion->LoopEnd - GetPos(); |
242 |
|
readsamples = Read(&pDst[totalreadsamples * GetFrameSize()], Min(samplestoread, samplestoloopend)); |
243 |
|
samplestoread -= readsamples; |
244 |
|
totalreadsamples += readsamples; |
245 |
|
if (readsamples == samplestoloopend) { |
246 |
|
SetPos(pRegion->LoopStart); |
247 |
|
} |
248 |
|
} while (samplestoread && readsamples); |
249 |
|
} else { |
250 |
|
totalreadsamples = Read(pBuffer, FrameCount); |
251 |
|
} |
252 |
|
|
253 |
pPlaybackState->position = GetPos(); |
pPlaybackState->position = GetPos(); |
254 |
// TODO: Implement looping |
|
255 |
return frames; |
return totalreadsamples; |
256 |
} |
} |
257 |
|
|
258 |
Region::Region() { |
Region::Region() { |
260 |
pInstrument = NULL; |
pInstrument = NULL; |
261 |
loKey = hiKey = NONE; |
loKey = hiKey = NONE; |
262 |
minVel = maxVel = NONE; |
minVel = maxVel = NONE; |
263 |
startAddrsOffset = startAddrsCoarseOffset = endAddrsOffset = 0; |
startAddrsOffset = startAddrsCoarseOffset = endAddrsOffset = endAddrsCoarseOffset = 0; |
264 |
startloopAddrsOffset = endloopAddrsOffset = 0; |
startloopAddrsOffset = startloopAddrsCoarseOffset = endloopAddrsOffset = endloopAddrsCoarseOffset = 0; |
265 |
pan = fineTune = 0; |
pan = fineTune = coarseTune = 0; |
266 |
|
overridingRootKey = -1; // -1 means not used |
267 |
|
|
268 |
|
HasLoop = false; |
269 |
|
LoopStart = LoopEnd = 0; |
270 |
|
|
271 |
EG1PreAttackDelay = EG1Attack = EG1Hold = EG1Decay = EG1Release = ToSeconds(-12000); |
EG1PreAttackDelay = EG1Attack = EG1Hold = EG1Decay = EG1Release = ToSeconds(-12000); |
272 |
EG1Sustain = 0; |
EG1Sustain = 0; |
274 |
EG2Sustain = 0; |
EG2Sustain = 0; |
275 |
} |
} |
276 |
|
|
277 |
|
int Region::GetUnityNote() { |
278 |
|
return overridingRootKey != -1 ? overridingRootKey : pSample->OriginalPitch; |
279 |
|
} |
280 |
|
|
281 |
void Region::SetGenerator(sf2::File* pFile, GenList& Gen) { |
void Region::SetGenerator(sf2::File* pFile, GenList& Gen) { |
282 |
switch(Gen.GenOper) { |
switch(Gen.GenOper) { |
283 |
case START_ADDRS_OFFSET: |
case START_ADDRS_OFFSET: |
292 |
break; |
break; |
293 |
case STARTLOOP_ADDRS_OFFSET: |
case STARTLOOP_ADDRS_OFFSET: |
294 |
startloopAddrsOffset = Gen.GenAmount.shAmount; |
startloopAddrsOffset = Gen.GenAmount.shAmount; |
295 |
|
LoopStart += startloopAddrsOffset; |
296 |
break; |
break; |
297 |
case ENDLOOP_ADDRS_OFFSET: |
case ENDLOOP_ADDRS_OFFSET: |
298 |
endloopAddrsOffset = Gen.GenAmount.shAmount; |
endloopAddrsOffset = Gen.GenAmount.shAmount; |
299 |
|
LoopEnd += endloopAddrsOffset; |
300 |
break; |
break; |
301 |
case START_ADDRS_COARSE_OFFSET: |
case START_ADDRS_COARSE_OFFSET: |
302 |
startAddrsCoarseOffset = Gen.GenAmount.wAmount; |
startAddrsCoarseOffset = Gen.GenAmount.wAmount; |
316 |
case MOD_ENV_TO_FILTER_FC: |
case MOD_ENV_TO_FILTER_FC: |
317 |
break; |
break; |
318 |
case END_ADDRS_COARSE_OFFSET: |
case END_ADDRS_COARSE_OFFSET: |
319 |
|
endAddrsCoarseOffset = Gen.GenAmount.wAmount; |
320 |
break; |
break; |
321 |
case MOD_LFO_TO_VOLUME: |
case MOD_LFO_TO_VOLUME: |
322 |
break; |
break; |
399 |
maxVel = Gen.GenAmount.ranges.byHi; |
maxVel = Gen.GenAmount.ranges.byHi; |
400 |
break; |
break; |
401 |
case STARTLOOP_ADDRS_COARSE_OFFSET: |
case STARTLOOP_ADDRS_COARSE_OFFSET: |
402 |
|
startloopAddrsCoarseOffset = Gen.GenAmount.wAmount; |
403 |
|
LoopStart += startloopAddrsCoarseOffset * 32768; |
404 |
break; |
break; |
405 |
case KEYNUM: |
case KEYNUM: |
406 |
break; |
break; |
409 |
case INITIAL_ATTENUATION: |
case INITIAL_ATTENUATION: |
410 |
break; |
break; |
411 |
case ENDLOOP_ADDRS_COARSE_OFFSET: |
case ENDLOOP_ADDRS_COARSE_OFFSET: |
412 |
|
endloopAddrsCoarseOffset = Gen.GenAmount.wAmount; |
413 |
|
LoopEnd += endloopAddrsCoarseOffset * 32768; |
414 |
break; |
break; |
415 |
case COARSE_TUNE: |
case COARSE_TUNE: |
416 |
|
coarseTune = Gen.GenAmount.shAmount; |
417 |
break; |
break; |
418 |
case FINE_TUNE: |
case FINE_TUNE: |
419 |
fineTune = Gen.GenAmount.shAmount; |
fineTune = Gen.GenAmount.shAmount; |
424 |
throw Exception("Broken SF2 file (missing samples)"); |
throw Exception("Broken SF2 file (missing samples)"); |
425 |
} |
} |
426 |
pSample = pFile->Samples[sid]; |
pSample = pFile->Samples[sid]; |
427 |
|
|
428 |
|
if (HasLoop) { |
429 |
|
LoopStart += pSample->StartLoop; |
430 |
|
LoopEnd += pSample->EndLoop; |
431 |
|
if ( LoopStart < pSample->Start || LoopStart > pSample->End || |
432 |
|
LoopStart > LoopEnd || LoopEnd > pSample->End ) { |
433 |
|
throw Exception("Broken SF2 file (invalid loops)"); |
434 |
|
} |
435 |
|
LoopStart -= pSample->Start; // Relative to the sample start |
436 |
|
LoopEnd -= pSample->Start; // Relative to the sample start |
437 |
|
} |
438 |
break; |
break; |
439 |
} |
} |
440 |
case SAMPLE_MODES: |
case SAMPLE_MODES: |
441 |
|
HasLoop = Gen.GenAmount.wAmount & 1; |
442 |
|
// TODO: 3 indicates a sound which loops for the duration of key depression |
443 |
|
// then proceeds to play the remainder of the sample. |
444 |
break; |
break; |
445 |
case SCALE_TUNING: |
case SCALE_TUNING: |
446 |
break; |
break; |
447 |
case EXCLUSIVE_CLASS: |
case EXCLUSIVE_CLASS: |
448 |
break; |
break; |
449 |
case OVERRIDING_ROOT_KEY: |
case OVERRIDING_ROOT_KEY: |
450 |
|
overridingRootKey = Gen.GenAmount.shAmount; |
451 |
break; |
break; |
452 |
} |
} |
453 |
} |
} |
488 |
} |
} |
489 |
|
|
490 |
int InstrumentBase::GetRegionCount() { |
int InstrumentBase::GetRegionCount() { |
491 |
return regions.size() - 1; // exclude terminal region |
return regions.size(); |
492 |
} |
} |
493 |
|
|
494 |
Region* InstrumentBase::GetRegion(int idx) { |
Region* InstrumentBase::GetRegion(int idx) { |
524 |
|
|
525 |
} |
} |
526 |
|
|
527 |
|
Region* Instrument::CreateRegion() { |
528 |
|
Region* r = new Region; |
529 |
|
if (pGlobalRegion != NULL) { |
530 |
|
r->loKey = pGlobalRegion->loKey; |
531 |
|
r->hiKey = pGlobalRegion->hiKey; |
532 |
|
r->minVel = pGlobalRegion->minVel; |
533 |
|
r->maxVel = pGlobalRegion->maxVel; |
534 |
|
r->pan = pGlobalRegion->pan; |
535 |
|
r->fineTune = pGlobalRegion->fineTune; |
536 |
|
r->coarseTune = pGlobalRegion->coarseTune; |
537 |
|
r->overridingRootKey = pGlobalRegion->overridingRootKey; |
538 |
|
r->startAddrsOffset = pGlobalRegion->startAddrsOffset; |
539 |
|
r->startAddrsCoarseOffset = pGlobalRegion->startAddrsCoarseOffset; |
540 |
|
r->endAddrsOffset = pGlobalRegion->endAddrsOffset; |
541 |
|
r->endAddrsCoarseOffset = pGlobalRegion->endAddrsCoarseOffset; |
542 |
|
r->startloopAddrsOffset = pGlobalRegion->startloopAddrsOffset; |
543 |
|
r->startloopAddrsCoarseOffset = pGlobalRegion->startloopAddrsCoarseOffset; |
544 |
|
r->endloopAddrsOffset = pGlobalRegion->endloopAddrsOffset; |
545 |
|
r->endloopAddrsCoarseOffset = pGlobalRegion->endloopAddrsCoarseOffset; |
546 |
|
|
547 |
|
r->EG1PreAttackDelay = pGlobalRegion->EG1PreAttackDelay; |
548 |
|
r->EG1Attack = pGlobalRegion->EG1Attack; |
549 |
|
r->EG1Hold = pGlobalRegion->EG1Hold; |
550 |
|
r->EG1Decay = pGlobalRegion->EG1Decay; |
551 |
|
r->EG1Sustain = pGlobalRegion->EG1Sustain; |
552 |
|
r->EG1Release = pGlobalRegion->EG1Release; |
553 |
|
|
554 |
|
r->EG2PreAttackDelay = pGlobalRegion->EG2PreAttackDelay; |
555 |
|
r->EG2Attack = pGlobalRegion->EG2Attack; |
556 |
|
r->EG2Hold = pGlobalRegion->EG2Hold; |
557 |
|
r->EG2Decay = pGlobalRegion->EG2Decay; |
558 |
|
r->EG2Sustain = pGlobalRegion->EG2Sustain; |
559 |
|
r->EG2Release = pGlobalRegion->EG2Release; |
560 |
|
|
561 |
|
r->HasLoop = pGlobalRegion->HasLoop; |
562 |
|
r->LoopStart = pGlobalRegion->LoopStart; |
563 |
|
r->LoopEnd = pGlobalRegion->LoopEnd; |
564 |
|
} |
565 |
|
|
566 |
|
return r; |
567 |
|
} |
568 |
|
|
569 |
|
void Instrument::DeleteRegion(Region* pRegion) { |
570 |
|
for (int i = 0; i < regions.size(); i++) { |
571 |
|
if (regions[i] == pRegion) { |
572 |
|
delete pRegion; |
573 |
|
regions[i] = NULL; |
574 |
|
return; |
575 |
|
} |
576 |
|
} |
577 |
|
|
578 |
|
std::cerr << "Can't remove unknown Region" << std::endl; |
579 |
|
} |
580 |
|
|
581 |
void Instrument::LoadRegions(int idx1, int idx2) { |
void Instrument::LoadRegions(int idx1, int idx2) { |
582 |
for (int i = idx1; i < idx2 - 1; i++) { |
for (int i = idx1; i < idx2; i++) { |
583 |
int gIdx1 = pFile->InstBags[i].InstGenNdx; |
int gIdx1 = pFile->InstBags[i].InstGenNdx; |
584 |
int gIdx2 = pFile->InstBags[i + 1].InstGenNdx; |
int gIdx2 = pFile->InstBags[i + 1].InstGenNdx; |
585 |
|
|
594 |
throw Exception("Broken SF2 file (invalid InstModNdx)"); |
throw Exception("Broken SF2 file (invalid InstModNdx)"); |
595 |
} |
} |
596 |
|
|
597 |
Region* reg = new Region; |
Region* reg = CreateRegion(); |
598 |
|
|
599 |
for (int j = gIdx1; j < gIdx2; j++) { |
for (int j = gIdx1; j < gIdx2; j++) { |
600 |
reg->SetGenerator(pFile, pFile->InstGenLists[j]); |
reg->SetGenerator(pFile, pFile->InstGenLists[j]); |
606 |
} |
} |
607 |
|
|
608 |
if (reg->pSample == NULL) { |
if (reg->pSample == NULL) { |
609 |
if (i == idx1) { |
if (i == idx1 && idx2 - idx1 > 1) { |
610 |
pGlobalRegion = reg; // global zone |
pGlobalRegion = reg; // global zone |
611 |
} else { |
} else { |
612 |
std::cerr << "Ignoring instrument's region without sample" << std::endl; |
std::cerr << "Ignoring instrument's region without sample" << std::endl; |
634 |
} |
} |
635 |
|
|
636 |
void Preset::LoadRegions(int idx1, int idx2) { |
void Preset::LoadRegions(int idx1, int idx2) { |
637 |
for (int i = idx1; i < idx2 - 1; i++) { |
for (int i = idx1; i < idx2; i++) { |
638 |
int gIdx1 = pFile->PresetBags[i].GenNdx; |
int gIdx1 = pFile->PresetBags[i].GenNdx; |
639 |
int gIdx2 = pFile->PresetBags[i + 1].GenNdx; |
int gIdx2 = pFile->PresetBags[i + 1].GenNdx; |
640 |
|
|
648 |
reg->SetGenerator(pFile, pFile->PresetGenLists[j]); |
reg->SetGenerator(pFile, pFile->PresetGenLists[j]); |
649 |
} |
} |
650 |
if (reg->pInstrument == NULL) { |
if (reg->pInstrument == NULL) { |
651 |
if (i == idx1) { |
if (i == idx1 && idx2 - idx1 > 1) { |
652 |
pGlobalRegion = reg; // global zone |
pGlobalRegion = reg; // global zone |
653 |
} else { |
} else { |
654 |
std::cerr << "Ignoring preset's region without instrument" << std::endl; |
std::cerr << "Ignoring preset's region without instrument" << std::endl; |
882 |
return Instruments[idx]; |
return Instruments[idx]; |
883 |
} |
} |
884 |
|
|
885 |
|
void File::DeleteInstrument(Instrument* pInstrument) { |
886 |
|
for (int i = 0; i < GetPresetCount(); i++) { |
887 |
|
Preset* p = GetPreset(i); |
888 |
|
if (p == NULL) continue; |
889 |
|
for (int j = p->GetRegionCount() - 1; j >= 0 ; j--) { |
890 |
|
if (p->GetRegion(j) && p->GetRegion(j)->pInstrument == pInstrument) { |
891 |
|
p->GetRegion(j)->pInstrument = NULL; |
892 |
|
} |
893 |
|
} |
894 |
|
} |
895 |
|
|
896 |
|
for (int i = 0; i < GetInstrumentCount(); i++) { |
897 |
|
if (GetInstrument(i) == pInstrument) { |
898 |
|
Instruments[i] = NULL; |
899 |
|
delete pInstrument; |
900 |
|
} |
901 |
|
} |
902 |
|
} |
903 |
|
|
904 |
int File::GetSampleCount() { |
int File::GetSampleCount() { |
905 |
return Samples.size() - 1; // exclude terminal sample (EOS) |
return Samples.size() - 1; // exclude terminal sample (EOS) |
906 |
} |
} |
914 |
} |
} |
915 |
|
|
916 |
void File::DeleteSample(Sample* pSample) { |
void File::DeleteSample(Sample* pSample) { |
917 |
|
// Sanity check |
918 |
|
for (int i = GetInstrumentCount() - 1; i >= 0; i--) { |
919 |
|
Instrument* pInstr = GetInstrument(i); |
920 |
|
if (pInstr == NULL) continue; |
921 |
|
|
922 |
|
for (int j = pInstr->GetRegionCount() - 1; j >= 0 ; j--) { |
923 |
|
if (pInstr->GetRegion(j) && pInstr->GetRegion(j)->GetSample() == pSample) { |
924 |
|
std::cerr << "Deleting sample which is still in use" << std::endl; |
925 |
|
} |
926 |
|
} |
927 |
|
} |
928 |
|
/////// |
929 |
|
|
930 |
for (int i = 0; i < GetSampleCount(); i++) { |
for (int i = 0; i < GetSampleCount(); i++) { |
931 |
if (Samples[i] == pSample) { |
if (Samples[i] == pSample) { |
932 |
delete pSample; |
delete pSample; |
1116 |
* @see SetPos() |
* @see SetPos() |
1117 |
*/ |
*/ |
1118 |
unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) { |
unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) { |
1119 |
|
// TODO: startAddrsCoarseOffset, endAddrsCoarseOffset |
1120 |
if (SampleCount == 0) return 0; |
if (SampleCount == 0) return 0; |
1121 |
long pos = GetPos(); |
long pos = GetPos(); |
1122 |
if (pos + SampleCount > GetTotalFrameCount()) SampleCount = GetTotalFrameCount() - pos; |
if (pos + SampleCount > GetTotalFrameCount()) SampleCount = GetTotalFrameCount() - pos; |
1124 |
if (GetFrameSize() / GetChannelCount() == 3 /* 24 bit */) { |
if (GetFrameSize() / GetChannelCount() == 3 /* 24 bit */) { |
1125 |
uint8_t* pBuf = (uint8_t*)pBuffer; |
uint8_t* pBuf = (uint8_t*)pBuffer; |
1126 |
if (SampleType == MONO_SAMPLE || SampleType == ROM_MONO_SAMPLE) { |
if (SampleType == MONO_SAMPLE || SampleType == ROM_MONO_SAMPLE) { |
1127 |
for (int i = 0; i < SampleCount; i++) { |
pCkSmpl->Read(pBuf, SampleCount, 2); |
1128 |
pBuf[i*3] = pCkSmpl->ReadInt16(); |
pCkSm24->Read(pBuf + SampleCount * 2, SampleCount, 1); |
1129 |
pBuf[i*3 + 2] = pCkSm24->ReadInt8(); |
for (int i = SampleCount - 1; i >= 0; i--) { |
1130 |
|
pBuf[i*3] = pBuf[(SampleCount * 2) + i]; |
1131 |
|
pBuf[i*3 + 2] = pBuf[i*2 + 1]; |
1132 |
|
pBuf[i*3 + 1] = pBuf[i*2]; |
1133 |
} |
} |
1134 |
} else if (SampleType == LEFT_SAMPLE || SampleType == ROM_LEFT_SAMPLE) { |
} else if (SampleType == LEFT_SAMPLE || SampleType == ROM_LEFT_SAMPLE) { |
1135 |
for (int i = 0; i < SampleCount; i++) { |
pCkSmpl->Read(pBuf, SampleCount, 2); |
1136 |
pBuf[i*6] = pCkSmpl->ReadInt16(); |
pCkSm24->Read(pBuf + SampleCount * 2, SampleCount, 1); |
1137 |
pBuf[i*6 + 2] = pCkSm24->ReadInt8(); |
for (int i = SampleCount - 1; i >= 0; i--) { |
1138 |
|
pBuf[i*6] = pBuf[(SampleCount * 2) + i]; |
1139 |
|
pBuf[i*6 + 2] = pBuf[i*2 + 1]; |
1140 |
|
pBuf[i*6 + 1] = pBuf[i*2]; |
1141 |
pBuf[i*6 + 3] = pBuf[i*6 + 4] = pBuf[i*6 + 5] = 0; |
pBuf[i*6 + 3] = pBuf[i*6 + 4] = pBuf[i*6 + 5] = 0; |
1142 |
} |
} |
1143 |
} else if (SampleType == RIGHT_SAMPLE || SampleType == ROM_RIGHT_SAMPLE) { |
} else if (SampleType == RIGHT_SAMPLE || SampleType == ROM_RIGHT_SAMPLE) { |
1144 |
for (int i = 0; i < SampleCount; i++) { |
pCkSmpl->Read(pBuf, SampleCount, 2); |
1145 |
|
pCkSm24->Read(pBuf + SampleCount * 2, SampleCount, 1); |
1146 |
|
for (int i = SampleCount - 1; i >= 0; i--) { |
1147 |
|
pBuf[i*6 + 3] = pBuf[(SampleCount * 2) + i]; |
1148 |
|
pBuf[i*6 + 5] = pBuf[i*2 + 1]; |
1149 |
|
pBuf[i*6 + 4] = pBuf[i*2]; |
1150 |
pBuf[i*6] = pBuf[i*6 + 1] = pBuf[i*6 + 2] = 0; |
pBuf[i*6] = pBuf[i*6 + 1] = pBuf[i*6 + 2] = 0; |
|
pBuf[i*6 + 3] = pCkSmpl->ReadInt16(); |
|
|
pBuf[i*6 + 5] = pCkSm24->ReadInt8(); |
|
1151 |
} |
} |
1152 |
} |
} |
1153 |
} else { |
} else { |