28 |
#include <algorithm> |
#include <algorithm> |
29 |
#include <math.h> |
#include <math.h> |
30 |
#include <iostream> |
#include <iostream> |
31 |
|
#include <assert.h> |
32 |
|
|
33 |
/// Initial size of the sample buffer which is used for decompression of |
/// Initial size of the sample buffer which is used for decompression of |
34 |
/// compressed sample wave streams - this value should always be bigger than |
/// compressed sample wave streams - this value should always be bigger than |
3389 |
if (pDimDef->dimension == dimension_layer) Layers = 1; |
if (pDimDef->dimension == dimension_layer) Layers = 1; |
3390 |
} |
} |
3391 |
|
|
3392 |
|
/** @brief Delete one split zone of a dimension (decrement zone amount). |
3393 |
|
* |
3394 |
|
* Instead of deleting an entire dimensions, this method will only delete |
3395 |
|
* one particular split zone given by @a zone of the Region's dimension |
3396 |
|
* given by @a type. So this method will simply decrement the amount of |
3397 |
|
* zones by one of the dimension in question. To be able to do that, the |
3398 |
|
* respective dimension must exist on this Region and it must have at least |
3399 |
|
* 3 zones. All DimensionRegion objects associated with the zone will be |
3400 |
|
* deleted. |
3401 |
|
* |
3402 |
|
* @param type - identifies the dimension where a zone shall be deleted |
3403 |
|
* @param zone - index of the dimension split zone that shall be deleted |
3404 |
|
* @throws gig::Exception if requested zone could not be deleted |
3405 |
|
*/ |
3406 |
|
void Region::DeleteDimensionZone(dimension_t type, int zone) { |
3407 |
|
dimension_def_t* oldDef = GetDimensionDefinition(type); |
3408 |
|
if (!oldDef) |
3409 |
|
throw gig::Exception("Could not delete dimension zone, no such dimension of given type"); |
3410 |
|
if (oldDef->zones <= 2) |
3411 |
|
throw gig::Exception("Could not delete dimension zone, because it would end up with only one zone."); |
3412 |
|
if (zone < 0 || zone >= oldDef->zones) |
3413 |
|
throw gig::Exception("Could not delete dimension zone, requested zone index out of bounds."); |
3414 |
|
|
3415 |
|
const int newZoneSize = oldDef->zones - 1; |
3416 |
|
|
3417 |
|
// create a temporary Region which just acts as a temporary copy |
3418 |
|
// container and will be deleted at the end of this function and will |
3419 |
|
// also not be visible through the API during this process |
3420 |
|
gig::Region* tempRgn = NULL; |
3421 |
|
{ |
3422 |
|
// adding these temporary chunks is probably not even necessary |
3423 |
|
Instrument* instr = static_cast<Instrument*>(GetParent()); |
3424 |
|
RIFF::List* pCkInstrument = instr->pCkInstrument; |
3425 |
|
RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); |
3426 |
|
if (!lrgn) lrgn = pCkInstrument->AddSubList(LIST_TYPE_LRGN); |
3427 |
|
RIFF::List* rgn = lrgn->AddSubList(LIST_TYPE_RGN); |
3428 |
|
tempRgn = new Region(instr, rgn); |
3429 |
|
} |
3430 |
|
|
3431 |
|
// copy this region's dimensions (with already the dimension split size |
3432 |
|
// requested by the arguments of this method call) to the temporary |
3433 |
|
// region, and don't use Region::CopyAssign() here for this task, since |
3434 |
|
// it would also alter fast lookup helper variables here and there |
3435 |
|
dimension_def_t newDef; |
3436 |
|
for (int i = 0; i < Dimensions; ++i) { |
3437 |
|
dimension_def_t def = pDimensionDefinitions[i]; // copy, don't reference |
3438 |
|
// is this the dimension requested by the method arguments? ... |
3439 |
|
if (def.dimension == type) { // ... if yes, decrement zone amount by one |
3440 |
|
def.zones = newZoneSize; |
3441 |
|
if ((1 << (def.bits - 1)) == def.zones) def.bits--; |
3442 |
|
newDef = def; |
3443 |
|
} |
3444 |
|
tempRgn->AddDimension(&def); |
3445 |
|
} |
3446 |
|
|
3447 |
|
// find the dimension index in the tempRegion which is the dimension |
3448 |
|
// type passed to this method (paranoidly expecting different order) |
3449 |
|
int tempReducedDimensionIndex = -1; |
3450 |
|
for (int d = 0; d < tempRgn->Dimensions; ++d) { |
3451 |
|
if (tempRgn->pDimensionDefinitions[d].dimension == type) { |
3452 |
|
tempReducedDimensionIndex = d; |
3453 |
|
break; |
3454 |
|
} |
3455 |
|
} |
3456 |
|
|
3457 |
|
// copy dimension regions from this region to the temporary region |
3458 |
|
for (int iDst = 0; iDst < 256; ++iDst) { |
3459 |
|
DimensionRegion* dstDimRgn = tempRgn->pDimensionRegions[iDst]; |
3460 |
|
if (!dstDimRgn) continue; |
3461 |
|
std::map<dimension_t,int> dimCase; |
3462 |
|
bool isValidZone = true; |
3463 |
|
for (int d = 0, baseBits = 0; d < tempRgn->Dimensions; ++d) { |
3464 |
|
const int dstBits = tempRgn->pDimensionDefinitions[d].bits; |
3465 |
|
dimCase[tempRgn->pDimensionDefinitions[d].dimension] = |
3466 |
|
(iDst >> baseBits) & ((1 << dstBits) - 1); |
3467 |
|
baseBits += dstBits; |
3468 |
|
// there are also DimensionRegion objects of unused zones, skip them |
3469 |
|
if (dimCase[tempRgn->pDimensionDefinitions[d].dimension] >= tempRgn->pDimensionDefinitions[d].zones) { |
3470 |
|
isValidZone = false; |
3471 |
|
break; |
3472 |
|
} |
3473 |
|
} |
3474 |
|
if (!isValidZone) continue; |
3475 |
|
// a bit paranoid: cope with the chance that the dimensions would |
3476 |
|
// have different order in source and destination regions |
3477 |
|
const bool isLastZone = (dimCase[type] == newZoneSize - 1); |
3478 |
|
if (dimCase[type] >= zone) dimCase[type]++; |
3479 |
|
DimensionRegion* srcDimRgn = GetDimensionRegionByBit(dimCase); |
3480 |
|
dstDimRgn->CopyAssign(srcDimRgn); |
3481 |
|
// if this is the upper most zone of the dimension passed to this |
3482 |
|
// method, then correct (raise) its upper limit to 127 |
3483 |
|
if (newDef.split_type == split_type_normal && isLastZone) |
3484 |
|
dstDimRgn->DimensionUpperLimits[tempReducedDimensionIndex] = 127; |
3485 |
|
} |
3486 |
|
|
3487 |
|
// now tempRegion's dimensions and DimensionRegions basically reflect |
3488 |
|
// what we wanted to get for this actual Region here, so we now just |
3489 |
|
// delete and recreate the dimension in question with the new amount |
3490 |
|
// zones and then copy back from tempRegion |
3491 |
|
DeleteDimension(oldDef); |
3492 |
|
AddDimension(&newDef); |
3493 |
|
for (int iSrc = 0; iSrc < 256; ++iSrc) { |
3494 |
|
DimensionRegion* srcDimRgn = tempRgn->pDimensionRegions[iSrc]; |
3495 |
|
if (!srcDimRgn) continue; |
3496 |
|
std::map<dimension_t,int> dimCase; |
3497 |
|
for (int d = 0, baseBits = 0; d < tempRgn->Dimensions; ++d) { |
3498 |
|
const int srcBits = tempRgn->pDimensionDefinitions[d].bits; |
3499 |
|
dimCase[tempRgn->pDimensionDefinitions[d].dimension] = |
3500 |
|
(iSrc >> baseBits) & ((1 << srcBits) - 1); |
3501 |
|
baseBits += srcBits; |
3502 |
|
} |
3503 |
|
// a bit paranoid: cope with the chance that the dimensions would |
3504 |
|
// have different order in source and destination regions |
3505 |
|
DimensionRegion* dstDimRgn = GetDimensionRegionByBit(dimCase); |
3506 |
|
if (!dstDimRgn) continue; |
3507 |
|
dstDimRgn->CopyAssign(srcDimRgn); |
3508 |
|
} |
3509 |
|
|
3510 |
|
// delete temporary region |
3511 |
|
delete tempRgn; |
3512 |
|
} |
3513 |
|
|
3514 |
|
/** @brief Divide split zone of a dimension in two (increment zone amount). |
3515 |
|
* |
3516 |
|
* This will increment the amount of zones for the dimension (given by |
3517 |
|
* @a type) by one. It will do so by dividing the zone (given by @a zone) |
3518 |
|
* in the middle of its zone range in two. So the two zones resulting from |
3519 |
|
* the zone being splitted, will be an equivalent copy regarding all their |
3520 |
|
* articulation informations and sample reference. The two zones will only |
3521 |
|
* differ in their zone's upper limit |
3522 |
|
* (DimensionRegion::DimensionUpperLimits). |
3523 |
|
* |
3524 |
|
* @param type - identifies the dimension where a zone shall be splitted |
3525 |
|
* @param zone - index of the dimension split zone that shall be splitted |
3526 |
|
* @throws gig::Exception if requested zone could not be splitted |
3527 |
|
*/ |
3528 |
|
void Region::SplitDimensionZone(dimension_t type, int zone) { |
3529 |
|
dimension_def_t* oldDef = GetDimensionDefinition(type); |
3530 |
|
if (!oldDef) |
3531 |
|
throw gig::Exception("Could not split dimension zone, no such dimension of given type"); |
3532 |
|
if (zone < 0 || zone >= oldDef->zones) |
3533 |
|
throw gig::Exception("Could not split dimension zone, requested zone index out of bounds."); |
3534 |
|
|
3535 |
|
const int newZoneSize = oldDef->zones + 1; |
3536 |
|
|
3537 |
|
// create a temporary Region which just acts as a temporary copy |
3538 |
|
// container and will be deleted at the end of this function and will |
3539 |
|
// also not be visible through the API during this process |
3540 |
|
gig::Region* tempRgn = NULL; |
3541 |
|
{ |
3542 |
|
// adding these temporary chunks is probably not even necessary |
3543 |
|
Instrument* instr = static_cast<Instrument*>(GetParent()); |
3544 |
|
RIFF::List* pCkInstrument = instr->pCkInstrument; |
3545 |
|
RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN); |
3546 |
|
if (!lrgn) lrgn = pCkInstrument->AddSubList(LIST_TYPE_LRGN); |
3547 |
|
RIFF::List* rgn = lrgn->AddSubList(LIST_TYPE_RGN); |
3548 |
|
tempRgn = new Region(instr, rgn); |
3549 |
|
} |
3550 |
|
|
3551 |
|
// copy this region's dimensions (with already the dimension split size |
3552 |
|
// requested by the arguments of this method call) to the temporary |
3553 |
|
// region, and don't use Region::CopyAssign() here for this task, since |
3554 |
|
// it would also alter fast lookup helper variables here and there |
3555 |
|
dimension_def_t newDef; |
3556 |
|
for (int i = 0; i < Dimensions; ++i) { |
3557 |
|
dimension_def_t def = pDimensionDefinitions[i]; // copy, don't reference |
3558 |
|
// is this the dimension requested by the method arguments? ... |
3559 |
|
if (def.dimension == type) { // ... if yes, increment zone amount by one |
3560 |
|
def.zones = newZoneSize; |
3561 |
|
if ((1 << oldDef->bits) < newZoneSize) def.bits++; |
3562 |
|
newDef = def; |
3563 |
|
} |
3564 |
|
tempRgn->AddDimension(&def); |
3565 |
|
} |
3566 |
|
|
3567 |
|
// find the dimension index in the tempRegion which is the dimension |
3568 |
|
// type passed to this method (paranoidly expecting different order) |
3569 |
|
int tempIncreasedDimensionIndex = -1; |
3570 |
|
for (int d = 0; d < tempRgn->Dimensions; ++d) { |
3571 |
|
if (tempRgn->pDimensionDefinitions[d].dimension == type) { |
3572 |
|
tempIncreasedDimensionIndex = d; |
3573 |
|
break; |
3574 |
|
} |
3575 |
|
} |
3576 |
|
|
3577 |
|
// copy dimension regions from this region to the temporary region |
3578 |
|
for (int iSrc = 0; iSrc < 256; ++iSrc) { |
3579 |
|
DimensionRegion* srcDimRgn = pDimensionRegions[iSrc]; |
3580 |
|
if (!srcDimRgn) continue; |
3581 |
|
std::map<dimension_t,int> dimCase; |
3582 |
|
bool isValidZone = true; |
3583 |
|
for (int d = 0, baseBits = 0; d < Dimensions; ++d) { |
3584 |
|
const int srcBits = pDimensionDefinitions[d].bits; |
3585 |
|
dimCase[pDimensionDefinitions[d].dimension] = |
3586 |
|
(iSrc >> baseBits) & ((1 << srcBits) - 1); |
3587 |
|
// there are also DimensionRegion objects for unused zones, skip them |
3588 |
|
if (dimCase[pDimensionDefinitions[d].dimension] >= pDimensionDefinitions[d].zones) { |
3589 |
|
isValidZone = false; |
3590 |
|
break; |
3591 |
|
} |
3592 |
|
baseBits += srcBits; |
3593 |
|
} |
3594 |
|
if (!isValidZone) continue; |
3595 |
|
// a bit paranoid: cope with the chance that the dimensions would |
3596 |
|
// have different order in source and destination regions |
3597 |
|
if (dimCase[type] > zone) dimCase[type]++; |
3598 |
|
DimensionRegion* dstDimRgn = tempRgn->GetDimensionRegionByBit(dimCase); |
3599 |
|
dstDimRgn->CopyAssign(srcDimRgn); |
3600 |
|
// if this is the requested zone to be splitted, then also copy |
3601 |
|
// the source DimensionRegion to the newly created target zone |
3602 |
|
// and set the old zones upper limit lower |
3603 |
|
if (dimCase[type] == zone) { |
3604 |
|
// lower old zones upper limit |
3605 |
|
if (newDef.split_type == split_type_normal) { |
3606 |
|
const int high = |
3607 |
|
dstDimRgn->DimensionUpperLimits[tempIncreasedDimensionIndex]; |
3608 |
|
int low = 0; |
3609 |
|
if (zone > 0) { |
3610 |
|
std::map<dimension_t,int> lowerCase = dimCase; |
3611 |
|
lowerCase[type]--; |
3612 |
|
DimensionRegion* dstDimRgnLow = tempRgn->GetDimensionRegionByBit(lowerCase); |
3613 |
|
low = dstDimRgnLow->DimensionUpperLimits[tempIncreasedDimensionIndex]; |
3614 |
|
} |
3615 |
|
dstDimRgn->DimensionUpperLimits[tempIncreasedDimensionIndex] = low + (high - low) / 2; |
3616 |
|
} |
3617 |
|
// fill the newly created zone of the divided zone as well |
3618 |
|
dimCase[type]++; |
3619 |
|
dstDimRgn = tempRgn->GetDimensionRegionByBit(dimCase); |
3620 |
|
dstDimRgn->CopyAssign(srcDimRgn); |
3621 |
|
} |
3622 |
|
} |
3623 |
|
|
3624 |
|
// now tempRegion's dimensions and DimensionRegions basically reflect |
3625 |
|
// what we wanted to get for this actual Region here, so we now just |
3626 |
|
// delete and recreate the dimension in question with the new amount |
3627 |
|
// zones and then copy back from tempRegion |
3628 |
|
DeleteDimension(oldDef); |
3629 |
|
AddDimension(&newDef); |
3630 |
|
for (int iSrc = 0; iSrc < 256; ++iSrc) { |
3631 |
|
DimensionRegion* srcDimRgn = tempRgn->pDimensionRegions[iSrc]; |
3632 |
|
if (!srcDimRgn) continue; |
3633 |
|
std::map<dimension_t,int> dimCase; |
3634 |
|
for (int d = 0, baseBits = 0; d < tempRgn->Dimensions; ++d) { |
3635 |
|
const int srcBits = tempRgn->pDimensionDefinitions[d].bits; |
3636 |
|
dimCase[tempRgn->pDimensionDefinitions[d].dimension] = |
3637 |
|
(iSrc >> baseBits) & ((1 << srcBits) - 1); |
3638 |
|
baseBits += srcBits; |
3639 |
|
} |
3640 |
|
// a bit paranoid: cope with the chance that the dimensions would |
3641 |
|
// have different order in source and destination regions |
3642 |
|
DimensionRegion* dstDimRgn = GetDimensionRegionByBit(dimCase); |
3643 |
|
if (!dstDimRgn) continue; |
3644 |
|
dstDimRgn->CopyAssign(srcDimRgn); |
3645 |
|
} |
3646 |
|
|
3647 |
|
// delete temporary region |
3648 |
|
delete tempRgn; |
3649 |
|
} |
3650 |
|
|
3651 |
|
DimensionRegion* Region::GetDimensionRegionByBit(const std::map<dimension_t,int>& DimCase) { |
3652 |
|
uint8_t bits[8] = {}; |
3653 |
|
for (std::map<dimension_t,int>::const_iterator it = DimCase.begin(); |
3654 |
|
it != DimCase.end(); ++it) |
3655 |
|
{ |
3656 |
|
for (int d = 0; d < Dimensions; ++d) { |
3657 |
|
if (pDimensionDefinitions[d].dimension == it->first) { |
3658 |
|
bits[d] = it->second; |
3659 |
|
goto nextDimCaseSlice; |
3660 |
|
} |
3661 |
|
} |
3662 |
|
assert(false); // do crash ... too harsh maybe ? ignore it instead ? |
3663 |
|
nextDimCaseSlice: |
3664 |
|
; // noop |
3665 |
|
} |
3666 |
|
return GetDimensionRegionByBit(bits); |
3667 |
|
} |
3668 |
|
|
3669 |
/** |
/** |
3670 |
* Searches in the current Region for a dimension of the given dimension |
* Searches in the current Region for a dimension of the given dimension |
3671 |
* type and returns the precise configuration of that dimension in this |
* type and returns the precise configuration of that dimension in this |