/[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 1292 by schoenebeck, Sat Aug 11 14:38:51 2007 UTC revision 1358 by schoenebeck, Sun Sep 30 18:13:33 2007 UTC
# Line 1262  namespace { Line 1262  namespace {
1262      uint                               DimensionRegion::Instances       = 0;      uint                               DimensionRegion::Instances       = 0;
1263      DimensionRegion::VelocityTableMap* DimensionRegion::pVelocityTables = NULL;      DimensionRegion::VelocityTableMap* DimensionRegion::pVelocityTables = NULL;
1264    
1265      DimensionRegion::DimensionRegion(RIFF::List* _3ewl) : DLS::Sampler(_3ewl) {      DimensionRegion::DimensionRegion(Region* pParent, RIFF::List* _3ewl) : DLS::Sampler(_3ewl) {
1266          Instances++;          Instances++;
1267    
1268          pSample = NULL;          pSample = NULL;
1269            pRegion = pParent;
1270    
1271          if (_3ewl->GetSubChunk(CHUNK_ID_WSMP)) memcpy(&Crossfade, &SamplerOptions, 4);          if (_3ewl->GetSubChunk(CHUNK_ID_WSMP)) memcpy(&Crossfade, &SamplerOptions, 4);
1272          else memset(&Crossfade, 0, 4);          else memset(&Crossfade, 0, 4);
# Line 1511  namespace { Line 1512  namespace {
1512                                                       VelocityResponseDepth,                                                       VelocityResponseDepth,
1513                                                       VelocityResponseCurveScaling);                                                       VelocityResponseCurveScaling);
1514    
1515          curve_type_t curveType = ReleaseVelocityResponseCurve;          pVelocityReleaseTable = GetReleaseVelocityTable(
1516          uint8_t depth = ReleaseVelocityResponseDepth;                                      ReleaseVelocityResponseCurve,
1517                                        ReleaseVelocityResponseDepth
1518                                    );
1519    
1520            pVelocityCutoffTable = GetCutoffVelocityTable(VCFVelocityCurve,
1521                                                          VCFVelocityDynamicRange,
1522                                                          VCFVelocityScale,
1523                                                          VCFCutoffController);
1524    
1525          // this models a strange behaviour or bug in GSt: two of the          SampleAttenuation = pow(10.0, -Gain / (20.0 * 655360));
1526          // velocity response curves for release time are not used even          VelocityTable = 0;
1527          // if specified, instead another curve is chosen.      }
         if ((curveType == curve_type_nonlinear && depth == 0) ||  
             (curveType == curve_type_special   && depth == 4)) {  
             curveType = curve_type_nonlinear;  
             depth = 3;  
         }  
         pVelocityReleaseTable = GetVelocityTable(curveType, depth, 0);  
1528    
1529          curveType = VCFVelocityCurve;      /*
1530          depth = VCFVelocityDynamicRange;       * Constructs a DimensionRegion by copying all parameters from
1531         * another DimensionRegion
1532         */
1533        DimensionRegion::DimensionRegion(RIFF::List* _3ewl, const DimensionRegion& src) : DLS::Sampler(_3ewl) {
1534            Instances++;
1535            *this = src; // default memberwise shallow copy of all parameters
1536            pParentList = _3ewl; // restore the chunk pointer
1537    
1538          // even stranger GSt: two of the velocity response curves for          // deep copy of owned structures
1539          // filter cutoff are not used, instead another special curve          if (src.VelocityTable) {
1540          // is chosen. This curve is not used anywhere else.              VelocityTable = new uint8_t[128];
1541          if ((curveType == curve_type_nonlinear && depth == 0) ||              for (int k = 0 ; k < 128 ; k++)
1542              (curveType == curve_type_special   && depth == 4)) {                  VelocityTable[k] = src.VelocityTable[k];
1543              curveType = curve_type_special;          }
1544              depth = 5;          if (src.pSampleLoops) {
1545                pSampleLoops = new DLS::sample_loop_t[src.SampleLoops];
1546                for (int k = 0 ; k < src.SampleLoops ; k++)
1547                    pSampleLoops[k] = src.pSampleLoops[k];
1548          }          }
1549          pVelocityCutoffTable = GetVelocityTable(curveType, depth,      }
                                                 VCFCutoffController <= vcf_cutoff_ctrl_none2 ? VCFVelocityScale : 0);  
1550    
1551        /**
1552         * Updates the respective member variable and updates @c SampleAttenuation
1553         * which depends on this value.
1554         */
1555        void DimensionRegion::SetGain(int32_t gain) {
1556            DLS::Sampler::SetGain(gain);
1557          SampleAttenuation = pow(10.0, -Gain / (20.0 * 655360));          SampleAttenuation = pow(10.0, -Gain / (20.0 * 655360));
         VelocityTable = 0;  
1558      }      }
1559    
1560      /**      /**
# Line 1550  namespace { Line 1565  namespace {
1565       * It will be called automatically when File::Save() was called.       * It will be called automatically when File::Save() was called.
1566       */       */
1567      void DimensionRegion::UpdateChunks() {      void DimensionRegion::UpdateChunks() {
         // check if wsmp is going to be created by  
         // DLS::Sampler::UpdateChunks  
         bool wsmp_created = !pParentList->GetSubChunk(CHUNK_ID_WSMP);  
   
1568          // first update base class's chunk          // first update base class's chunk
1569          DLS::Sampler::UpdateChunks();          DLS::Sampler::UpdateChunks();
1570    
# Line 1566  namespace { Line 1577  namespace {
1577    
1578          // make sure '3ewa' chunk exists          // make sure '3ewa' chunk exists
1579          RIFF::Chunk* _3ewa = pParentList->GetSubChunk(CHUNK_ID_3EWA);          RIFF::Chunk* _3ewa = pParentList->GetSubChunk(CHUNK_ID_3EWA);
1580          if (!_3ewa)  _3ewa = pParentList->AddSubChunk(CHUNK_ID_3EWA, 140);          if (!_3ewa) {
1581          else if (wsmp_created) {              File* pFile = (File*) GetParent()->GetParent()->GetParent();
1582              // make sure the chunk order is: wsmp, 3ewa              bool version3 = pFile->pVersion && pFile->pVersion->major == 3;
1583              pParentList->MoveSubChunk(_3ewa, 0);              _3ewa = pParentList->AddSubChunk(CHUNK_ID_3EWA, version3 ? 148 : 140);
1584          }          }
1585          pData = (uint8_t*) _3ewa->LoadChunkData();          pData = (uint8_t*) _3ewa->LoadChunkData();
1586    
# Line 1837  namespace { Line 1848  namespace {
1848          }          }
1849      }      }
1850    
1851        double* DimensionRegion::GetReleaseVelocityTable(curve_type_t releaseVelocityResponseCurve, uint8_t releaseVelocityResponseDepth) {
1852            curve_type_t curveType = releaseVelocityResponseCurve;
1853            uint8_t depth = releaseVelocityResponseDepth;
1854            // this models a strange behaviour or bug in GSt: two of the
1855            // velocity response curves for release time are not used even
1856            // if specified, instead another curve is chosen.
1857            if ((curveType == curve_type_nonlinear && depth == 0) ||
1858                (curveType == curve_type_special   && depth == 4)) {
1859                curveType = curve_type_nonlinear;
1860                depth = 3;
1861            }
1862            return GetVelocityTable(curveType, depth, 0);
1863        }
1864    
1865        double* DimensionRegion::GetCutoffVelocityTable(curve_type_t vcfVelocityCurve,
1866                                                        uint8_t vcfVelocityDynamicRange,
1867                                                        uint8_t vcfVelocityScale,
1868                                                        vcf_cutoff_ctrl_t vcfCutoffController)
1869        {
1870            curve_type_t curveType = vcfVelocityCurve;
1871            uint8_t depth = vcfVelocityDynamicRange;
1872            // even stranger GSt: two of the velocity response curves for
1873            // filter cutoff are not used, instead another special curve
1874            // is chosen. This curve is not used anywhere else.
1875            if ((curveType == curve_type_nonlinear && depth == 0) ||
1876                (curveType == curve_type_special   && depth == 4)) {
1877                curveType = curve_type_special;
1878                depth = 5;
1879            }
1880            return GetVelocityTable(curveType, depth,
1881                                    (vcfCutoffController <= vcf_cutoff_ctrl_none2)
1882                                        ? vcfVelocityScale : 0);
1883        }
1884    
1885      // get the corresponding velocity table from the table map or create & calculate that table if it doesn't exist yet      // get the corresponding velocity table from the table map or create & calculate that table if it doesn't exist yet
1886      double* DimensionRegion::GetVelocityTable(curve_type_t curveType, uint8_t depth, uint8_t scaling)      double* DimensionRegion::GetVelocityTable(curve_type_t curveType, uint8_t depth, uint8_t scaling)
1887      {      {
# Line 1852  namespace { Line 1897  namespace {
1897          return table;          return table;
1898      }      }
1899    
1900        Region* DimensionRegion::GetParent() const {
1901            return pRegion;
1902        }
1903    
1904      leverage_ctrl_t DimensionRegion::DecodeLeverageController(_lev_ctrl_t EncodedController) {      leverage_ctrl_t DimensionRegion::DecodeLeverageController(_lev_ctrl_t EncodedController) {
1905          leverage_ctrl_t decodedcontroller;          leverage_ctrl_t decodedcontroller;
1906          switch (EncodedController) {          switch (EncodedController) {
# Line 2105  namespace { Line 2154  namespace {
2154          return pVelocityCutoffTable[MIDIKeyVelocity];          return pVelocityCutoffTable[MIDIKeyVelocity];
2155      }      }
2156    
2157        /**
2158         * Updates the respective member variable and the lookup table / cache
2159         * that depends on this value.
2160         */
2161        void DimensionRegion::SetVelocityResponseCurve(curve_type_t curve) {
2162            pVelocityAttenuationTable =
2163                GetVelocityTable(
2164                    curve, VelocityResponseDepth, VelocityResponseCurveScaling
2165                );
2166            VelocityResponseCurve = curve;
2167        }
2168    
2169        /**
2170         * Updates the respective member variable and the lookup table / cache
2171         * that depends on this value.
2172         */
2173        void DimensionRegion::SetVelocityResponseDepth(uint8_t depth) {
2174            pVelocityAttenuationTable =
2175                GetVelocityTable(
2176                    VelocityResponseCurve, depth, VelocityResponseCurveScaling
2177                );
2178            VelocityResponseDepth = depth;
2179        }
2180    
2181        /**
2182         * Updates the respective member variable and the lookup table / cache
2183         * that depends on this value.
2184         */
2185        void DimensionRegion::SetVelocityResponseCurveScaling(uint8_t scaling) {
2186            pVelocityAttenuationTable =
2187                GetVelocityTable(
2188                    VelocityResponseCurve, VelocityResponseDepth, scaling
2189                );
2190            VelocityResponseCurveScaling = scaling;
2191        }
2192    
2193        /**
2194         * Updates the respective member variable and the lookup table / cache
2195         * that depends on this value.
2196         */
2197        void DimensionRegion::SetReleaseVelocityResponseCurve(curve_type_t curve) {
2198            pVelocityReleaseTable = GetReleaseVelocityTable(curve, ReleaseVelocityResponseDepth);
2199            ReleaseVelocityResponseCurve = curve;
2200        }
2201    
2202        /**
2203         * Updates the respective member variable and the lookup table / cache
2204         * that depends on this value.
2205         */
2206        void DimensionRegion::SetReleaseVelocityResponseDepth(uint8_t depth) {
2207            pVelocityReleaseTable = GetReleaseVelocityTable(ReleaseVelocityResponseCurve, depth);
2208            ReleaseVelocityResponseDepth = depth;
2209        }
2210    
2211        /**
2212         * Updates the respective member variable and the lookup table / cache
2213         * that depends on this value.
2214         */
2215        void DimensionRegion::SetVCFCutoffController(vcf_cutoff_ctrl_t controller) {
2216            pVelocityCutoffTable = GetCutoffVelocityTable(VCFVelocityCurve, VCFVelocityDynamicRange, VCFVelocityScale, controller);
2217            VCFCutoffController = controller;
2218        }
2219    
2220        /**
2221         * Updates the respective member variable and the lookup table / cache
2222         * that depends on this value.
2223         */
2224        void DimensionRegion::SetVCFVelocityCurve(curve_type_t curve) {
2225            pVelocityCutoffTable = GetCutoffVelocityTable(curve, VCFVelocityDynamicRange, VCFVelocityScale, VCFCutoffController);
2226            VCFVelocityCurve = curve;
2227        }
2228    
2229        /**
2230         * Updates the respective member variable and the lookup table / cache
2231         * that depends on this value.
2232         */
2233        void DimensionRegion::SetVCFVelocityDynamicRange(uint8_t range) {
2234            pVelocityCutoffTable = GetCutoffVelocityTable(VCFVelocityCurve, range, VCFVelocityScale, VCFCutoffController);
2235            VCFVelocityDynamicRange = range;
2236        }
2237    
2238        /**
2239         * Updates the respective member variable and the lookup table / cache
2240         * that depends on this value.
2241         */
2242        void DimensionRegion::SetVCFVelocityScale(uint8_t scaling) {
2243            pVelocityCutoffTable = GetCutoffVelocityTable(VCFVelocityCurve, VCFVelocityDynamicRange, scaling, VCFCutoffController);
2244            VCFVelocityScale = scaling;
2245        }
2246    
2247      double* DimensionRegion::CreateVelocityTable(curve_type_t curveType, uint8_t depth, uint8_t scaling) {      double* DimensionRegion::CreateVelocityTable(curve_type_t curveType, uint8_t depth, uint8_t scaling) {
2248    
2249          // line-segment approximations of the 15 velocity curves          // line-segment approximations of the 15 velocity curves
# Line 2251  namespace { Line 2390  namespace {
2390              RIFF::List* _3prg = rgnList->GetSubList(LIST_TYPE_3PRG);              RIFF::List* _3prg = rgnList->GetSubList(LIST_TYPE_3PRG);
2391              if (!_3prg) _3prg = rgnList->AddSubList(LIST_TYPE_3PRG);              if (!_3prg) _3prg = rgnList->AddSubList(LIST_TYPE_3PRG);
2392              RIFF::List* _3ewl = _3prg->AddSubList(LIST_TYPE_3EWL);              RIFF::List* _3ewl = _3prg->AddSubList(LIST_TYPE_3EWL);
2393              pDimensionRegions[0] = new DimensionRegion(_3ewl);              pDimensionRegions[0] = new DimensionRegion(this, _3ewl);
2394              DimensionRegions = 1;              DimensionRegions = 1;
2395          }          }
2396      }      }
# Line 2275  namespace { Line 2414  namespace {
2414          // first update base class's chunks          // first update base class's chunks
2415          DLS::Region::UpdateChunks();          DLS::Region::UpdateChunks();
2416    
         File* pFile = (File*) GetParent()->GetParent();  
         bool version3 = pFile->pVersion && pFile->pVersion->major == 3;  
   
2417          // update dimension region's chunks          // update dimension region's chunks
2418          for (int i = 0; i < DimensionRegions; i++) {          for (int i = 0; i < DimensionRegions; i++) {
2419              DimensionRegion* d = pDimensionRegions[i];              pDimensionRegions[i]->UpdateChunks();
   
             // make sure '3ewa' chunk exists (we need to this before  
             // calling DimensionRegion::UpdateChunks, as  
             // DimensionRegion doesn't know which file version it is)  
             RIFF::Chunk* _3ewa = d->pParentList->GetSubChunk(CHUNK_ID_3EWA);  
             if (!_3ewa) d->pParentList->AddSubChunk(CHUNK_ID_3EWA, version3 ? 148 : 140);  
   
             d->UpdateChunks();  
2420          }          }
2421    
2422            File* pFile = (File*) GetParent()->GetParent();
2423            bool version3 = pFile->pVersion && pFile->pVersion->major == 3;
2424          const int iMaxDimensions =  version3 ? 8 : 5;          const int iMaxDimensions =  version3 ? 8 : 5;
2425          const int iMaxDimensionRegions = version3 ? 256 : 32;          const int iMaxDimensionRegions = version3 ? 256 : 32;
2426    
# Line 2346  namespace { Line 2476  namespace {
2476              RIFF::List* _3ewl = _3prg->GetFirstSubList();              RIFF::List* _3ewl = _3prg->GetFirstSubList();
2477              while (_3ewl) {              while (_3ewl) {
2478                  if (_3ewl->GetListType() == LIST_TYPE_3EWL) {                  if (_3ewl->GetListType() == LIST_TYPE_3EWL) {
2479                      pDimensionRegions[dimensionRegionNr] = new DimensionRegion(_3ewl);                      pDimensionRegions[dimensionRegionNr] = new DimensionRegion(this, _3ewl);
2480                      dimensionRegionNr++;                      dimensionRegionNr++;
2481                  }                  }
2482                  _3ewl = _3prg->GetNextSubList();                  _3ewl = _3prg->GetNextSubList();
# Line 2355  namespace { Line 2485  namespace {
2485          }          }
2486      }      }
2487    
2488        void Region::SetKeyRange(uint16_t Low, uint16_t High) {
2489            // update KeyRange struct and make sure regions are in correct order
2490            DLS::Region::SetKeyRange(Low, High);
2491            // update Region key table for fast lookup
2492            ((gig::Instrument*)GetParent())->UpdateRegionKeyTable();
2493        }
2494    
2495      void Region::UpdateVelocityTable() {      void Region::UpdateVelocityTable() {
2496          // get velocity dimension's index          // get velocity dimension's index
2497          int veldim = -1;          int veldim = -1;
# Line 2460  namespace { Line 2597  namespace {
2597              if (pDimensionDefinitions[i].dimension == pDimDef->dimension)              if (pDimensionDefinitions[i].dimension == pDimDef->dimension)
2598                  throw gig::Exception("Could not add new dimension, there is already a dimension of the same type");                  throw gig::Exception("Could not add new dimension, there is already a dimension of the same type");
2599    
2600            // pos is where the new dimension should be placed, normally
2601            // last in list, except for the samplechannel dimension which
2602            // has to be first in list
2603            int pos = pDimDef->dimension == dimension_samplechannel ? 0 : Dimensions;
2604            int bitpos = 0;
2605            for (int i = 0 ; i < pos ; i++)
2606                bitpos += pDimensionDefinitions[i].bits;
2607    
2608            // make room for the new dimension
2609            for (int i = Dimensions ; i > pos ; i--) pDimensionDefinitions[i] = pDimensionDefinitions[i - 1];
2610            for (int i = 0 ; i < (1 << iCurrentBits) ; i++) {
2611                for (int j = Dimensions ; j > pos ; j--) {
2612                    pDimensionRegions[i]->DimensionUpperLimits[j] =
2613                        pDimensionRegions[i]->DimensionUpperLimits[j - 1];
2614                }
2615            }
2616    
2617          // assign definition of new dimension          // assign definition of new dimension
2618          pDimensionDefinitions[Dimensions] = *pDimDef;          pDimensionDefinitions[pos] = *pDimDef;
2619    
2620          // auto correct certain dimension definition fields (where possible)          // auto correct certain dimension definition fields (where possible)
2621          pDimensionDefinitions[Dimensions].split_type  =          pDimensionDefinitions[pos].split_type  =
2622              __resolveSplitType(pDimensionDefinitions[Dimensions].dimension);              __resolveSplitType(pDimensionDefinitions[pos].dimension);
2623          pDimensionDefinitions[Dimensions].zone_size =          pDimensionDefinitions[pos].zone_size =
2624              __resolveZoneSize(pDimensionDefinitions[Dimensions]);              __resolveZoneSize(pDimensionDefinitions[pos]);
2625    
2626          // create new dimension region(s) for this new dimension          // create new dimension region(s) for this new dimension, and make
2627          for (int i = 1 << iCurrentBits; i < 1 << iNewBits; i++) {          // sure that the dimension regions are placed correctly in both the
2628              //TODO: maybe we should copy existing dimension regions if possible instead of simply creating new ones with default values          // RIFF list and the pDimensionRegions array
2629              RIFF::List* _3prg = pCkRegion->GetSubList(LIST_TYPE_3PRG);          RIFF::Chunk* moveTo = NULL;
2630              RIFF::List* pNewDimRgnListChunk = _3prg->AddSubList(LIST_TYPE_3EWL);          RIFF::List* _3prg = pCkRegion->GetSubList(LIST_TYPE_3PRG);
2631              pDimensionRegions[i] = new DimensionRegion(pNewDimRgnListChunk);          for (int i = (1 << iCurrentBits) - (1 << bitpos) ; i >= 0 ; i -= (1 << bitpos)) {
2632                for (int k = 0 ; k < (1 << bitpos) ; k++) {
2633              // copy the upper limits for the other dimensions                  pDimensionRegions[(i << pDimDef->bits) + k] = pDimensionRegions[i + k];
2634              memcpy(pDimensionRegions[i]->DimensionUpperLimits,              }
2635                     pDimensionRegions[i & ((1 << iCurrentBits) - 1)]->DimensionUpperLimits, 8);              for (int j = 1 ; j < (1 << pDimDef->bits) ; j++) {
2636                    for (int k = 0 ; k < (1 << bitpos) ; k++) {
2637                        RIFF::List* pNewDimRgnListChunk = _3prg->AddSubList(LIST_TYPE_3EWL);
2638                        if (moveTo) _3prg->MoveSubChunk(pNewDimRgnListChunk, moveTo);
2639                        // create a new dimension region and copy all parameter values from
2640                        // an existing dimension region
2641                        pDimensionRegions[(i << pDimDef->bits) + (j << bitpos) + k] =
2642                            new DimensionRegion(pNewDimRgnListChunk, *pDimensionRegions[i + k]);
2643    
2644              DimensionRegions++;                      DimensionRegions++;
2645                    }
2646                }
2647                moveTo = pDimensionRegions[i]->pParentList;
2648          }          }
2649    
2650          // initialize the upper limits for this dimension          // initialize the upper limits for this dimension
2651          for (int z = 0, j = 0 ; z < pDimDef->zones ; z++, j += 1 << iCurrentBits) {          int mask = (1 << bitpos) - 1;
2652            for (int z = 0 ; z < pDimDef->zones ; z++) {
2653              uint8_t upperLimit = uint8_t((z + 1) * 128.0 / pDimDef->zones - 1);              uint8_t upperLimit = uint8_t((z + 1) * 128.0 / pDimDef->zones - 1);
2654              for (int i = 0 ; i < 1 << iCurrentBits ; i++) {              for (int i = 0 ; i < 1 << iCurrentBits ; i++) {
2655                  pDimensionRegions[j + i]->DimensionUpperLimits[Dimensions] = upperLimit;                  pDimensionRegions[((i & ~mask) << pDimDef->bits) |
2656                                      (z << bitpos) |
2657                                      (i & mask)]->DimensionUpperLimits[pos] = upperLimit;
2658              }              }
2659          }          }
2660    
# Line 2764  namespace { Line 2931  namespace {
2931      }      }
2932    
2933      void Instrument::UpdateRegionKeyTable() {      void Instrument::UpdateRegionKeyTable() {
2934            for (int i = 0; i < 128; i++) RegionKeyTable[i] = NULL;
2935          RegionList::iterator iter = pRegions->begin();          RegionList::iterator iter = pRegions->begin();
2936          RegionList::iterator end  = pRegions->end();          RegionList::iterator end  = pRegions->end();
2937          for (; iter != end; ++iter) {          for (; iter != end; ++iter) {
# Line 2831  namespace { Line 2999  namespace {
2999       *             there is no Region defined for the given \a Key       *             there is no Region defined for the given \a Key
3000       */       */
3001      Region* Instrument::GetRegion(unsigned int Key) {      Region* Instrument::GetRegion(unsigned int Key) {
3002          if (!pRegions || !pRegions->size() || Key > 127) return NULL;          if (!pRegions || pRegions->empty() || Key > 127) return NULL;
3003          return RegionKeyTable[Key];          return RegionKeyTable[Key];
3004    
3005          /*for (int i = 0; i < Regions; i++) {          /*for (int i = 0; i < Regions; i++) {

Legend:
Removed from v.1292  
changed lines
  Added in v.1358

  ViewVC Help
Powered by ViewVC