45 |
Product = smpl->ReadInt32(); |
Product = smpl->ReadInt32(); |
46 |
SamplePeriod = smpl->ReadInt32(); |
SamplePeriod = smpl->ReadInt32(); |
47 |
MIDIUnityNote = smpl->ReadInt32(); |
MIDIUnityNote = smpl->ReadInt32(); |
48 |
MIDIPitchFraction = smpl->ReadInt32(); |
FineTune = smpl->ReadInt32(); |
49 |
smpl->Read(&SMPTEFormat, 1, 4); |
smpl->Read(&SMPTEFormat, 1, 4); |
50 |
SMPTEOffset = smpl->ReadInt32(); |
SMPTEOffset = smpl->ReadInt32(); |
51 |
Loops = smpl->ReadInt32(); |
Loops = smpl->ReadInt32(); |
52 |
|
uint32_t manufByt = smpl->ReadInt32(); |
53 |
LoopID = smpl->ReadInt32(); |
LoopID = smpl->ReadInt32(); |
54 |
smpl->Read(&LoopType, 1, 4); |
smpl->Read(&LoopType, 1, 4); |
55 |
LoopStart = smpl->ReadInt32(); |
LoopStart = smpl->ReadInt32(); |
72 |
} |
} |
73 |
} |
} |
74 |
FrameOffset = 0; // just for streaming compressed samples |
FrameOffset = 0; // just for streaming compressed samples |
75 |
|
|
76 |
|
LoopSize = LoopEnd - LoopStart; |
77 |
} |
} |
78 |
|
|
79 |
/// Scans compressed samples for mandatory informations (e.g. actual number of total sample points). |
/// Scans compressed samples for mandatory informations (e.g. actual number of total sample points). |
313 |
} |
} |
314 |
|
|
315 |
/** |
/** |
316 |
|
* Reads \a SampleCount number of sample points from the position stored |
317 |
|
* in \a pPlaybackState into the buffer pointed by \a pBuffer and moves |
318 |
|
* the position within the sample respectively, this method honors the |
319 |
|
* looping informations of the sample (if any). The sample wave stream |
320 |
|
* will be decompressed on the fly if using a compressed sample. Use this |
321 |
|
* method if you don't want to load the sample into RAM, thus for disk |
322 |
|
* streaming. All this methods needs to know to proceed with streaming |
323 |
|
* for the next time you call this method is stored in \a pPlaybackState. |
324 |
|
* You have to allocate and initialize the playback_state_t structure by |
325 |
|
* yourself before you use it to stream a sample: |
326 |
|
* |
327 |
|
* <i> |
328 |
|
* gig::playback_state_t playbackstate; <br> |
329 |
|
* playbackstate.position = 0; <br> |
330 |
|
* playbackstate.reverse = false; <br> |
331 |
|
* playbackstate.loop_cycles_left = pSample->LoopPlayCount; <br> |
332 |
|
* </i> |
333 |
|
* |
334 |
|
* You don't have to take care of things like if there is actually a loop |
335 |
|
* defined or if the current read position is located within a loop area. |
336 |
|
* The method already handles such cases by itself. |
337 |
|
* |
338 |
|
* @param pBuffer destination buffer |
339 |
|
* @param SampleCount number of sample points to read |
340 |
|
* @param pPlaybackState will be used to store and reload the playback |
341 |
|
* state for the next ReadAndLoop() call |
342 |
|
* @returns number of successfully read sample points |
343 |
|
*/ |
344 |
|
unsigned long Sample::ReadAndLoop(void* pBuffer, unsigned long SampleCount, playback_state_t* pPlaybackState) { |
345 |
|
unsigned long samplestoread = SampleCount, totalreadsamples = 0, readsamples, samplestoloopend; |
346 |
|
uint8_t* pDst = (uint8_t*) pBuffer; |
347 |
|
|
348 |
|
SetPos(pPlaybackState->position); // recover position from the last time |
349 |
|
|
350 |
|
if (this->Loops && GetPos() <= this->LoopEnd) { // honor looping if there are loop points defined |
351 |
|
|
352 |
|
switch (this->LoopType) { |
353 |
|
|
354 |
|
case loop_type_bidirectional: { //TODO: not tested yet! |
355 |
|
do { |
356 |
|
// if not endless loop check if max. number of loop cycles have been passed |
357 |
|
if (this->LoopPlayCount && !pPlaybackState->loop_cycles_left) break; |
358 |
|
|
359 |
|
if (!pPlaybackState->reverse) { // forward playback |
360 |
|
do { |
361 |
|
samplestoloopend = this->LoopEnd - GetPos(); |
362 |
|
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoread, samplestoloopend)); |
363 |
|
samplestoread -= readsamples; |
364 |
|
totalreadsamples += readsamples; |
365 |
|
if (readsamples == samplestoloopend) { |
366 |
|
pPlaybackState->reverse = true; |
367 |
|
break; |
368 |
|
} |
369 |
|
} while (samplestoread && readsamples); |
370 |
|
} |
371 |
|
else { // backward playback |
372 |
|
|
373 |
|
// as we can only read forward from disk, we have to |
374 |
|
// determine the end position within the loop first, |
375 |
|
// read forward from that 'end' and finally after |
376 |
|
// reading, swap all sample frames so it reflects |
377 |
|
// backward playback |
378 |
|
|
379 |
|
unsigned long swapareastart = totalreadsamples; |
380 |
|
unsigned long loopoffset = GetPos() - this->LoopStart; |
381 |
|
unsigned long samplestoreadinloop = Min(samplestoread, loopoffset); |
382 |
|
unsigned long reverseplaybackend = GetPos() - samplestoreadinloop; |
383 |
|
|
384 |
|
SetPos(reverseplaybackend); |
385 |
|
|
386 |
|
// read samples for backward playback |
387 |
|
do { |
388 |
|
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], samplestoreadinloop); |
389 |
|
samplestoreadinloop -= readsamples; |
390 |
|
samplestoread -= readsamples; |
391 |
|
totalreadsamples += readsamples; |
392 |
|
} while (samplestoreadinloop && readsamples); |
393 |
|
|
394 |
|
SetPos(reverseplaybackend); // pretend we really read backwards |
395 |
|
|
396 |
|
if (reverseplaybackend == this->LoopStart) { |
397 |
|
pPlaybackState->loop_cycles_left--; |
398 |
|
pPlaybackState->reverse = false; |
399 |
|
} |
400 |
|
|
401 |
|
// reverse the sample frames for backward playback |
402 |
|
SwapMemoryArea(&pDst[swapareastart * this->FrameSize], (totalreadsamples - swapareastart) * this->FrameSize, this->FrameSize); |
403 |
|
} |
404 |
|
} while (samplestoread && readsamples); |
405 |
|
break; |
406 |
|
} |
407 |
|
|
408 |
|
case loop_type_backward: { // TODO: not tested yet! |
409 |
|
// forward playback (not entered the loop yet) |
410 |
|
if (!pPlaybackState->reverse) do { |
411 |
|
samplestoloopend = this->LoopEnd - GetPos(); |
412 |
|
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoread, samplestoloopend)); |
413 |
|
samplestoread -= readsamples; |
414 |
|
totalreadsamples += readsamples; |
415 |
|
if (readsamples == samplestoloopend) { |
416 |
|
pPlaybackState->reverse = true; |
417 |
|
break; |
418 |
|
} |
419 |
|
} while (samplestoread && readsamples); |
420 |
|
|
421 |
|
if (!samplestoread) break; |
422 |
|
|
423 |
|
// as we can only read forward from disk, we have to |
424 |
|
// determine the end position within the loop first, |
425 |
|
// read forward from that 'end' and finally after |
426 |
|
// reading, swap all sample frames so it reflects |
427 |
|
// backward playback |
428 |
|
|
429 |
|
unsigned long swapareastart = totalreadsamples; |
430 |
|
unsigned long loopoffset = GetPos() - this->LoopStart; |
431 |
|
unsigned long samplestoreadinloop = (this->LoopPlayCount) ? Min(samplestoread, pPlaybackState->loop_cycles_left * LoopSize - loopoffset) |
432 |
|
: samplestoread; |
433 |
|
unsigned long reverseplaybackend = this->LoopStart + Abs((loopoffset - samplestoreadinloop) % this->LoopSize); |
434 |
|
|
435 |
|
SetPos(reverseplaybackend); |
436 |
|
|
437 |
|
// read samples for backward playback |
438 |
|
do { |
439 |
|
// if not endless loop check if max. number of loop cycles have been passed |
440 |
|
if (this->LoopPlayCount && !pPlaybackState->loop_cycles_left) break; |
441 |
|
samplestoloopend = this->LoopEnd - GetPos(); |
442 |
|
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoreadinloop, samplestoloopend)); |
443 |
|
samplestoreadinloop -= readsamples; |
444 |
|
samplestoread -= readsamples; |
445 |
|
totalreadsamples += readsamples; |
446 |
|
if (readsamples == samplestoloopend) { |
447 |
|
pPlaybackState->loop_cycles_left--; |
448 |
|
SetPos(this->LoopStart); |
449 |
|
} |
450 |
|
} while (samplestoreadinloop && readsamples); |
451 |
|
|
452 |
|
SetPos(reverseplaybackend); // pretend we really read backwards |
453 |
|
|
454 |
|
// reverse the sample frames for backward playback |
455 |
|
SwapMemoryArea(&pDst[swapareastart * this->FrameSize], (totalreadsamples - swapareastart) * this->FrameSize, this->FrameSize); |
456 |
|
break; |
457 |
|
} |
458 |
|
|
459 |
|
default: case loop_type_normal: { |
460 |
|
do { |
461 |
|
// if not endless loop check if max. number of loop cycles have been passed |
462 |
|
if (this->LoopPlayCount && !pPlaybackState->loop_cycles_left) break; |
463 |
|
samplestoloopend = this->LoopEnd - GetPos(); |
464 |
|
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], Min(samplestoread, samplestoloopend)); |
465 |
|
samplestoread -= readsamples; |
466 |
|
totalreadsamples += readsamples; |
467 |
|
if (readsamples == samplestoloopend) { |
468 |
|
pPlaybackState->loop_cycles_left--; |
469 |
|
SetPos(this->LoopStart); |
470 |
|
} |
471 |
|
} while (samplestoread && readsamples); |
472 |
|
break; |
473 |
|
} |
474 |
|
} |
475 |
|
} |
476 |
|
|
477 |
|
// read on without looping |
478 |
|
if (samplestoread) do { |
479 |
|
readsamples = Read(&pDst[totalreadsamples * this->FrameSize], samplestoread); |
480 |
|
samplestoread -= readsamples; |
481 |
|
totalreadsamples += readsamples; |
482 |
|
} while (readsamples && samplestoread); |
483 |
|
|
484 |
|
// store current position |
485 |
|
pPlaybackState->position = GetPos(); |
486 |
|
|
487 |
|
return totalreadsamples; |
488 |
|
} |
489 |
|
|
490 |
|
/** |
491 |
* Reads \a SampleCount number of sample points from the current |
* Reads \a SampleCount number of sample points from the current |
492 |
* position into the buffer pointed by \a pBuffer and increments the |
* position into the buffer pointed by \a pBuffer and increments the |
493 |
* position within the sample. The sample wave stream will be |
* position within the sample. The sample wave stream will be |
501 |
* @see SetPos() |
* @see SetPos() |
502 |
*/ |
*/ |
503 |
unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) { |
unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) { |
504 |
if (!Compressed) return pCkData->Read(pBuffer, SampleCount, FrameSize); |
if (SampleCount == 0) return 0; |
505 |
|
if (!Compressed) return pCkData->Read(pBuffer, SampleCount, FrameSize); //FIXME: channel inversion due to endian correction? |
506 |
else { //FIXME: no support for mono compressed samples yet, are there any? |
else { //FIXME: no support for mono compressed samples yet, are there any? |
507 |
|
if (this->SamplePos >= this->SamplesTotal) return 0; |
508 |
//TODO: efficiency: we simply assume here that all frames are compressed, maybe we should test for an average compression rate |
//TODO: efficiency: we simply assume here that all frames are compressed, maybe we should test for an average compression rate |
509 |
// best case needed buffer size (all frames compressed) |
// best case needed buffer size (all frames compressed) |
510 |
unsigned long assumedsize = (SampleCount << 1) + // *2 (16 Bit, stereo, but assume all frames compressed) |
unsigned long assumedsize = (SampleCount << 1) + // *2 (16 Bit, stereo, but assume all frames compressed) |
533 |
// reload from disk to local buffer if needed |
// reload from disk to local buffer if needed |
534 |
if (remainingbytes < 8194) { |
if (remainingbytes < 8194) { |
535 |
if (pCkData->GetState() != RIFF::stream_ready) { |
if (pCkData->GetState() != RIFF::stream_ready) { |
536 |
this->SamplePos += (SampleCount - remainingsamples); |
this->SamplePos = this->SamplesTotal; |
|
//if (this->SamplePos > this->SamplesTotal) this->SamplePos = this->SamplesTotal; |
|
537 |
return (SampleCount - remainingsamples); |
return (SampleCount - remainingsamples); |
538 |
} |
} |
539 |
assumedsize = remainingsamples; |
assumedsize = remainingsamples; |
653 |
} |
} |
654 |
} |
} |
655 |
this->SamplePos += (SampleCount - remainingsamples); |
this->SamplePos += (SampleCount - remainingsamples); |
656 |
//if (this->SamplePos > this->SamplesTotal) this->SamplePos = this->SamplesTotal; |
if (this->SamplePos > this->SamplesTotal) this->SamplePos = this->SamplesTotal; |
657 |
return (SampleCount - remainingsamples); |
return (SampleCount - remainingsamples); |
658 |
} |
} |
659 |
} |
} |
670 |
// *************** DimensionRegion *************** |
// *************** DimensionRegion *************** |
671 |
// * |
// * |
672 |
|
|
673 |
|
uint DimensionRegion::Instances = 0; |
674 |
|
DimensionRegion::VelocityTableMap* DimensionRegion::pVelocityTables = NULL; |
675 |
|
|
676 |
DimensionRegion::DimensionRegion(RIFF::List* _3ewl) : DLS::Sampler(_3ewl) { |
DimensionRegion::DimensionRegion(RIFF::List* _3ewl) : DLS::Sampler(_3ewl) { |
677 |
|
Instances++; |
678 |
|
|
679 |
memcpy(&Crossfade, &SamplerOptions, 4); |
memcpy(&Crossfade, &SamplerOptions, 4); |
680 |
|
if (!pVelocityTables) pVelocityTables = new VelocityTableMap; |
681 |
|
|
682 |
RIFF::Chunk* _3ewa = _3ewl->GetSubChunk(CHUNK_ID_3EWA); |
RIFF::Chunk* _3ewa = _3ewl->GetSubChunk(CHUNK_ID_3EWA); |
683 |
_3ewa->ReadInt32(); // unknown, allways 0x0000008C ? |
_3ewa->ReadInt32(); // unknown, allways 0x0000008C ? |
829 |
VCFVelocityDynamicRange = vcfvelocity % 5; |
VCFVelocityDynamicRange = vcfvelocity % 5; |
830 |
VCFVelocityCurve = static_cast<curve_type_t>(vcfvelocity / 5); |
VCFVelocityCurve = static_cast<curve_type_t>(vcfvelocity / 5); |
831 |
VCFType = static_cast<vcf_type_t>(_3ewa->ReadUint8()); |
VCFType = static_cast<vcf_type_t>(_3ewa->ReadUint8()); |
832 |
|
|
833 |
|
// get the corresponding velocity->volume table from the table map or create & calculate that table if it doesn't exist yet |
834 |
|
uint32_t tableKey = (VelocityResponseCurve<<16) | (VelocityResponseDepth<<8) | VelocityResponseCurveScaling; |
835 |
|
if (pVelocityTables->count(tableKey)) { // if key exists |
836 |
|
pVelocityAttenuationTable = (*pVelocityTables)[tableKey]; |
837 |
|
} |
838 |
|
else { |
839 |
|
pVelocityAttenuationTable = new double[128]; |
840 |
|
switch (VelocityResponseCurve) { // calculate the new table |
841 |
|
case curve_type_nonlinear: |
842 |
|
for (int velocity = 0; velocity < 128; velocity++) { |
843 |
|
pVelocityAttenuationTable[velocity] = |
844 |
|
GIG_VELOCITY_TRANSFORM_NONLINEAR((double)(velocity+1),(double)(VelocityResponseDepth+1),(double)VelocityResponseCurveScaling); |
845 |
|
if (pVelocityAttenuationTable[velocity] > 1.0) pVelocityAttenuationTable[velocity] = 1.0; |
846 |
|
else if (pVelocityAttenuationTable[velocity] < 0.0) pVelocityAttenuationTable[velocity] = 0.0; |
847 |
|
} |
848 |
|
break; |
849 |
|
case curve_type_linear: |
850 |
|
for (int velocity = 0; velocity < 128; velocity++) { |
851 |
|
pVelocityAttenuationTable[velocity] = |
852 |
|
GIG_VELOCITY_TRANSFORM_LINEAR((double)velocity,(double)(VelocityResponseDepth+1),(double)VelocityResponseCurveScaling); |
853 |
|
if (pVelocityAttenuationTable[velocity] > 1.0) pVelocityAttenuationTable[velocity] = 1.0; |
854 |
|
else if (pVelocityAttenuationTable[velocity] < 0.0) pVelocityAttenuationTable[velocity] = 0.0; |
855 |
|
} |
856 |
|
break; |
857 |
|
case curve_type_special: |
858 |
|
for (int velocity = 0; velocity < 128; velocity++) { |
859 |
|
pVelocityAttenuationTable[velocity] = |
860 |
|
GIG_VELOCITY_TRANSFORM_SPECIAL((double)(velocity+1),(double)(VelocityResponseDepth+1),(double)VelocityResponseCurveScaling); |
861 |
|
if (pVelocityAttenuationTable[velocity] > 1.0) pVelocityAttenuationTable[velocity] = 1.0; |
862 |
|
else if (pVelocityAttenuationTable[velocity] < 0.0) pVelocityAttenuationTable[velocity] = 0.0; |
863 |
|
} |
864 |
|
break; |
865 |
|
case curve_type_unknown: |
866 |
|
default: |
867 |
|
throw gig::Exception("Unknown transform curve type."); |
868 |
|
} |
869 |
|
(*pVelocityTables)[tableKey] = pVelocityAttenuationTable; // put the new table into the tables map |
870 |
|
} |
871 |
|
} |
872 |
|
|
873 |
|
DimensionRegion::~DimensionRegion() { |
874 |
|
Instances--; |
875 |
|
if (!Instances) { |
876 |
|
// delete the velocity->volume tables |
877 |
|
VelocityTableMap::iterator iter; |
878 |
|
for (iter = pVelocityTables->begin(); iter != pVelocityTables->end(); iter++) { |
879 |
|
double* pTable = iter->second; |
880 |
|
if (pTable) delete[] pTable; |
881 |
|
} |
882 |
|
pVelocityTables->clear(); |
883 |
|
delete pVelocityTables; |
884 |
|
pVelocityTables = NULL; |
885 |
|
} |
886 |
|
} |
887 |
|
|
888 |
|
/** |
889 |
|
* Returns the correct amplitude factor for the given \a MIDIKeyVelocity. |
890 |
|
* All involved parameters (VelocityResponseCurve, VelocityResponseDepth |
891 |
|
* and VelocityResponseCurveScaling) involved are taken into account to |
892 |
|
* calculate the amplitude factor. Use this method when a key was |
893 |
|
* triggered to get the volume with which the sample should be played |
894 |
|
* back. |
895 |
|
* |
896 |
|
* @param MIDI velocity value of the triggered key (between 0 and 127) |
897 |
|
* @returns amplitude factor (between 0.0 and 1.0) |
898 |
|
*/ |
899 |
|
double DimensionRegion::GetVelocityAttenuation(uint8_t MIDIKeyVelocity) { |
900 |
|
return pVelocityAttenuationTable[MIDIKeyVelocity]; |
901 |
} |
} |
902 |
|
|
903 |
|
|
1249 |
return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL; |
return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL; |
1250 |
} |
} |
1251 |
|
|
1252 |
|
/** |
1253 |
|
* Returns the instrument with the given index. |
1254 |
|
* |
1255 |
|
* @returns sought instrument or NULL if there's no such instrument |
1256 |
|
*/ |
1257 |
|
Instrument* File::GetInstrument(uint index) { |
1258 |
|
if (!pInstruments) LoadInstruments(); |
1259 |
|
if (!pInstruments) return NULL; |
1260 |
|
InstrumentsIterator = pInstruments->begin(); |
1261 |
|
for (uint i = 0; InstrumentsIterator != pInstruments->end(); i++) { |
1262 |
|
if (i == index) return *InstrumentsIterator; |
1263 |
|
InstrumentsIterator++; |
1264 |
|
} |
1265 |
|
return NULL; |
1266 |
|
} |
1267 |
|
|
1268 |
void File::LoadInstruments() { |
void File::LoadInstruments() { |
1269 |
RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS); |
RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS); |
1270 |
if (lstInstruments) { |
if (lstInstruments) { |