/[svn]/libgig/trunk/src/gig.cpp
ViewVC logotype

Diff of /libgig/trunk/src/gig.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2547 by schoenebeck, Tue May 13 11:17:24 2014 UTC revision 2555 by schoenebeck, Fri May 16 23:08:42 2014 UTC
# Line 28  Line 28 
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
# Line 3388  namespace { Line 3389  namespace {
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

Legend:
Removed from v.2547  
changed lines
  Added in v.2555

  ViewVC Help
Powered by ViewVC