/[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 384 by schoenebeck, Thu Feb 17 02:22:26 2005 UTC revision 613 by persson, Mon Jun 6 16:50:58 2005 UTC
# Line 25  Line 25 
25    
26  #include <iostream>  #include <iostream>
27    
28  namespace gig { namespace {  namespace gig {
29    
30    // *************** progress_t ***************
31    // *
32    
33        progress_t::progress_t() {
34            callback    = NULL;
35            custom      = NULL;
36            __range_min = 0.0f;
37            __range_max = 1.0f;
38        }
39    
40        // private helper function to convert progress of a subprocess into the global progress
41        static void __notify_progress(progress_t* pProgress, float subprogress) {
42            if (pProgress && pProgress->callback) {
43                const float totalrange    = pProgress->__range_max - pProgress->__range_min;
44                const float totalprogress = pProgress->__range_min + subprogress * totalrange;
45                pProgress->factor         = totalprogress;
46                pProgress->callback(pProgress); // now actually notify about the progress
47            }
48        }
49    
50        // private helper function to divide a progress into subprogresses
51        static void __divide_progress(progress_t* pParentProgress, progress_t* pSubProgress, float totalTasks, float currentTask) {
52            if (pParentProgress && pParentProgress->callback) {
53                const float totalrange    = pParentProgress->__range_max - pParentProgress->__range_min;
54                pSubProgress->callback    = pParentProgress->callback;
55                pSubProgress->custom      = pParentProgress->custom;
56                pSubProgress->__range_min = pParentProgress->__range_min + totalrange * currentTask / totalTasks;
57                pSubProgress->__range_max = pSubProgress->__range_min + totalrange / totalTasks;
58            }
59        }
60    
61    
62  // *************** Internal functions for sample decopmression ***************  // *************** Internal functions for sample decopmression ***************
63  // *  // *
64    
65    namespace {
66    
67      inline int get12lo(const unsigned char* pSrc)      inline int get12lo(const unsigned char* pSrc)
68      {      {
69          const int x = pSrc[0] | (pSrc[1] & 0x0f) << 8;          const int x = pSrc[0] | (pSrc[1] & 0x0f) << 8;
# Line 94  namespace gig { namespace { Line 128  namespace gig { namespace {
128      void Decompress24(int compressionmode, const unsigned char* params,      void Decompress24(int compressionmode, const unsigned char* params,
129                        int dstStep, const unsigned char* pSrc, int16_t* pDst,                        int dstStep, const unsigned char* pSrc, int16_t* pDst,
130                        unsigned long currentframeoffset,                        unsigned long currentframeoffset,
131                        unsigned long copysamples)                        unsigned long copysamples, int truncatedBits)
132      {      {
133          // Note: The 24 bits are truncated to 16 bits for now.          // Note: The 24 bits are truncated to 16 bits for now.
134    
# Line 106  namespace gig { namespace { Line 140  namespace gig { namespace {
140          //          //
141          // Strange thing #2: The formula in SKIP_ONE gives values for          // Strange thing #2: The formula in SKIP_ONE gives values for
142          // y that are twice as high as they should be. That's why          // y that are twice as high as they should be. That's why
143          // COPY_ONE shifts 9 steps instead of 8, and also why y is          // COPY_ONE shifts an extra step, and also why y is
144          // initialized with a sum instead of a mean value.          // initialized with a sum instead of a mean value.
145    
146          int y, dy, ddy;          int y, dy, ddy;
147    
148            const int shift = 8 - truncatedBits;
149            const int shift1 = shift + 1;
150    
151  #define GET_PARAMS(params)                              \  #define GET_PARAMS(params)                              \
152          y = (get24(params) + get24((params) + 3));      \          y = (get24(params) + get24((params) + 3));      \
153          dy  = get24((params) + 6);                      \          dy  = get24((params) + 6);                      \
# Line 123  namespace gig { namespace { Line 160  namespace gig { namespace {
160    
161  #define COPY_ONE(x)                             \  #define COPY_ONE(x)                             \
162          SKIP_ONE(x);                            \          SKIP_ONE(x);                            \
163          *pDst = y >> 9;                         \          *pDst = y >> shift1;                    \
164          pDst += dstStep          pDst += dstStep
165    
166          switch (compressionmode) {          switch (compressionmode) {
167              case 2: // 24 bit uncompressed              case 2: // 24 bit uncompressed
168                  pSrc += currentframeoffset * 3;                  pSrc += currentframeoffset * 3;
169                  while (copysamples) {                  while (copysamples) {
170                      *pDst = get24(pSrc) >> 8;                      *pDst = get24(pSrc) >> shift;
171                      pDst += dstStep;                      pDst += dstStep;
172                      pSrc += 3;                      pSrc += 3;
173                      copysamples--;                      copysamples--;
# Line 239  namespace gig { namespace { Line 276  namespace gig { namespace {
276    
277          if (BitDepth > 24) throw gig::Exception("Only samples up to 24 bit supported");          if (BitDepth > 24) throw gig::Exception("Only samples up to 24 bit supported");
278    
279          Compressed = (waveList->GetSubChunk(CHUNK_ID_EWAV));          RIFF::Chunk* ewav = waveList->GetSubChunk(CHUNK_ID_EWAV);
280            Compressed        = ewav;
281            Dithered          = false;
282            TruncatedBits     = 0;
283          if (Compressed) {          if (Compressed) {
284                uint32_t version = ewav->ReadInt32();
285                if (version == 3 && BitDepth == 24) {
286                    Dithered = ewav->ReadInt32();
287                    ewav->SetPos(Channels == 2 ? 84 : 64);
288                    TruncatedBits = ewav->ReadInt32();
289                }
290              ScanCompressedSample();              ScanCompressedSample();
291          }          }
292    
# Line 249  namespace gig { namespace { Line 295  namespace gig { namespace {
295              InternalDecompressionBuffer.pStart = new unsigned char[INITIAL_SAMPLE_BUFFER_SIZE];              InternalDecompressionBuffer.pStart = new unsigned char[INITIAL_SAMPLE_BUFFER_SIZE];
296              InternalDecompressionBuffer.Size   = INITIAL_SAMPLE_BUFFER_SIZE;              InternalDecompressionBuffer.Size   = INITIAL_SAMPLE_BUFFER_SIZE;
297          }          }
298          FrameOffset = 0; // just for streaming compressed samples          FrameOffset = 0; // just for streaming compressed samples
299    
300          LoopSize = LoopEnd - LoopStart;          LoopSize = LoopEnd - LoopStart;
301      }      }
# Line 846  namespace gig { namespace { Line 892  namespace gig { namespace {
892                              const unsigned char* const param_r = pSrc;                              const unsigned char* const param_r = pSrc;
893                              if (mode_r != 2) pSrc += 12;                              if (mode_r != 2) pSrc += 12;
894    
895                              Decompress24(mode_l, param_l, 2, pSrc, pDst, skipsamples, copysamples);                              Decompress24(mode_l, param_l, 2, pSrc, pDst,
896                                             skipsamples, copysamples, TruncatedBits);
897                              Decompress24(mode_r, param_r, 2, pSrc + rightChannelOffset, pDst + 1,                              Decompress24(mode_r, param_r, 2, pSrc + rightChannelOffset, pDst + 1,
898                                           skipsamples, copysamples);                                           skipsamples, copysamples, TruncatedBits);
899                              pDst += copysamples << 1;                              pDst += copysamples << 1;
900                          }                          }
901                          else { // Mono                          else { // Mono
902                              Decompress24(mode_l, param_l, 1, pSrc, pDst, skipsamples, copysamples);                              Decompress24(mode_l, param_l, 1, pSrc, pDst,
903                                             skipsamples, copysamples, TruncatedBits);
904                              pDst += copysamples;                              pDst += copysamples;
905                          }                          }
906                      }                      }
# Line 1113  namespace gig { namespace { Line 1161  namespace gig { namespace {
1161                  VCFType = vcf_type_lowpassturbo;                  VCFType = vcf_type_lowpassturbo;
1162          }          }
1163    
1164          // get the corresponding velocity->volume table from the table map or create & calculate that table if it doesn't exist yet          pVelocityAttenuationTable = GetVelocityTable(VelocityResponseCurve,
1165          uint32_t tableKey = (VelocityResponseCurve<<16) | (VelocityResponseDepth<<8) | VelocityResponseCurveScaling;                                                       VelocityResponseDepth,
1166                                                         VelocityResponseCurveScaling);
1167    
1168            curve_type_t curveType = ReleaseVelocityResponseCurve;
1169            uint8_t depth = ReleaseVelocityResponseDepth;
1170    
1171            // this models a strange behaviour or bug in GSt: two of the
1172            // velocity response curves for release time are not used even
1173            // if specified, instead another curve is chosen.
1174    
1175            if ((curveType == curve_type_nonlinear && depth == 0) ||
1176                (curveType == curve_type_special   && depth == 4)) {
1177                curveType = curve_type_nonlinear;
1178                depth = 3;
1179            }
1180            pVelocityReleaseTable = GetVelocityTable(curveType, depth, 0);
1181    
1182            SampleAttenuation = pow(10.0, -Gain / (20.0 * 655360));
1183        }
1184    
1185        // get the corresponding velocity table from the table map or create & calculate that table if it doesn't exist yet
1186        double* DimensionRegion::GetVelocityTable(curve_type_t curveType, uint8_t depth, uint8_t scaling)
1187        {
1188            double* table;
1189            uint32_t tableKey = (curveType<<16) | (depth<<8) | scaling;
1190          if (pVelocityTables->count(tableKey)) { // if key exists          if (pVelocityTables->count(tableKey)) { // if key exists
1191              pVelocityAttenuationTable = (*pVelocityTables)[tableKey];              table = (*pVelocityTables)[tableKey];
1192          }          }
1193          else {          else {
1194              pVelocityAttenuationTable =              table = CreateVelocityTable(curveType, depth, scaling);
1195                  CreateVelocityTable(VelocityResponseCurve,              (*pVelocityTables)[tableKey] = table; // put the new table into the tables map
                                     VelocityResponseDepth,  
                                     VelocityResponseCurveScaling);  
             (*pVelocityTables)[tableKey] = pVelocityAttenuationTable; // put the new table into the tables map  
1196          }          }
1197            return table;
1198      }      }
1199    
1200      leverage_ctrl_t DimensionRegion::DecodeLeverageController(_lev_ctrl_t EncodedController) {      leverage_ctrl_t DimensionRegion::DecodeLeverageController(_lev_ctrl_t EncodedController) {
# Line 1275  namespace gig { namespace { Line 1345  namespace gig { namespace {
1345          return pVelocityAttenuationTable[MIDIKeyVelocity];          return pVelocityAttenuationTable[MIDIKeyVelocity];
1346      }      }
1347    
1348        double DimensionRegion::GetVelocityRelease(uint8_t MIDIKeyVelocity) {
1349            return pVelocityReleaseTable[MIDIKeyVelocity];
1350        }
1351    
1352      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) {
1353    
1354          // line-segment approximations of the 15 velocity curves          // line-segment approximations of the 15 velocity curves
# Line 1376  namespace gig { namespace { Line 1450  namespace gig { namespace {
1450                      pDimensionDefinitions[i].zones     = 0x01 << bits; // = pow(2,bits)                      pDimensionDefinitions[i].zones     = 0x01 << bits; // = pow(2,bits)
1451                      pDimensionDefinitions[i].split_type = (dimension == dimension_layer ||                      pDimensionDefinitions[i].split_type = (dimension == dimension_layer ||
1452                                                             dimension == dimension_samplechannel ||                                                             dimension == dimension_samplechannel ||
1453                                                             dimension == dimension_releasetrigger) ? split_type_bit                                                             dimension == dimension_releasetrigger ||
1454                                                                                                    : split_type_normal;                                                             dimension == dimension_roundrobin ||
1455                                                               dimension == dimension_random) ? split_type_bit
1456                                                                                              : split_type_normal;
1457                      pDimensionDefinitions[i].ranges = NULL; // it's not possible to check velocity dimensions for custom defined ranges at this point                      pDimensionDefinitions[i].ranges = NULL; // it's not possible to check velocity dimensions for custom defined ranges at this point
1458                      pDimensionDefinitions[i].zone_size  =                      pDimensionDefinitions[i].zone_size  =
1459                          (pDimensionDefinitions[i].split_type == split_type_normal) ? 128 / pDimensionDefinitions[i].zones                          (pDimensionDefinitions[i].split_type == split_type_normal) ? 128 / pDimensionDefinitions[i].zones
# Line 1533  namespace gig { namespace { Line 1609  namespace gig { namespace {
1609          else         return static_cast<gig::Sample*>(pSample = GetSampleFromWavePool(WavePoolTableIndex));          else         return static_cast<gig::Sample*>(pSample = GetSampleFromWavePool(WavePoolTableIndex));
1610      }      }
1611    
1612      Sample* Region::GetSampleFromWavePool(unsigned int WavePoolTableIndex) {      Sample* Region::GetSampleFromWavePool(unsigned int WavePoolTableIndex, progress_t* pProgress) {
1613          if ((int32_t)WavePoolTableIndex == -1) return NULL;          if ((int32_t)WavePoolTableIndex == -1) return NULL;
1614          File* file = (File*) GetParent()->GetParent();          File* file = (File*) GetParent()->GetParent();
1615          unsigned long soughtoffset = file->pWavePoolTable[WavePoolTableIndex];          unsigned long soughtoffset = file->pWavePoolTable[WavePoolTableIndex];
1616          Sample* sample = file->GetFirstSample();          Sample* sample = file->GetFirstSample(pProgress);
1617          while (sample) {          while (sample) {
1618              if (sample->ulWavePoolOffset == soughtoffset) return static_cast<gig::Sample*>(pSample = sample);              if (sample->ulWavePoolOffset == soughtoffset) return static_cast<gig::Sample*>(pSample = sample);
1619              sample = file->GetNextSample();              sample = file->GetNextSample();
# Line 1550  namespace gig { namespace { Line 1626  namespace gig { namespace {
1626  // *************** Instrument ***************  // *************** Instrument ***************
1627  // *  // *
1628    
1629      Instrument::Instrument(File* pFile, RIFF::List* insList) : DLS::Instrument((DLS::File*)pFile, insList) {      Instrument::Instrument(File* pFile, RIFF::List* insList, progress_t* pProgress) : DLS::Instrument((DLS::File*)pFile, insList) {
1630          // Initialization          // Initialization
1631          for (int i = 0; i < 128; i++) RegionKeyTable[i] = NULL;          for (int i = 0; i < 128; i++) RegionKeyTable[i] = NULL;
1632          RegionIndex = -1;          RegionIndex = -1;
# Line 1581  namespace gig { namespace { Line 1657  namespace gig { namespace {
1657          unsigned int iRegion = 0;          unsigned int iRegion = 0;
1658          while (rgn) {          while (rgn) {
1659              if (rgn->GetListType() == LIST_TYPE_RGN) {              if (rgn->GetListType() == LIST_TYPE_RGN) {
1660                    __notify_progress(pProgress, (float) iRegion / (float) Regions);
1661                  pRegions[iRegion] = new Region(this, rgn);                  pRegions[iRegion] = new Region(this, rgn);
1662                  iRegion++;                  iRegion++;
1663              }              }
# Line 1593  namespace gig { namespace { Line 1670  namespace gig { namespace {
1670                  RegionKeyTable[iKey] = pRegions[iReg];                  RegionKeyTable[iKey] = pRegions[iReg];
1671              }              }
1672          }          }
1673    
1674            __notify_progress(pProgress, 1.0f); // notify done
1675      }      }
1676    
1677      Instrument::~Instrument() {      Instrument::~Instrument() {
# Line 1681  namespace gig { namespace { Line 1760  namespace gig { namespace {
1760          }          }
1761      }      }
1762    
1763      Sample* File::GetFirstSample() {      Sample* File::GetFirstSample(progress_t* pProgress) {
1764          if (!pSamples) LoadSamples();          if (!pSamples) LoadSamples(pProgress);
1765          if (!pSamples) return NULL;          if (!pSamples) return NULL;
1766          SamplesIterator = pSamples->begin();          SamplesIterator = pSamples->begin();
1767          return static_cast<gig::Sample*>( (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL );          return static_cast<gig::Sample*>( (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL );
# Line 1694  namespace gig { namespace { Line 1773  namespace gig { namespace {
1773          return static_cast<gig::Sample*>( (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL );          return static_cast<gig::Sample*>( (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL );
1774      }      }
1775    
1776      void File::LoadSamples() {      void File::LoadSamples(progress_t* pProgress) {
1777          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);          RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
1778          if (wvpl) {          if (wvpl) {
1779                // just for progress calculation
1780                int iSampleIndex  = 0;
1781                int iTotalSamples = wvpl->CountSubLists(LIST_TYPE_WAVE);
1782    
1783              unsigned long wvplFileOffset = wvpl->GetFilePos();              unsigned long wvplFileOffset = wvpl->GetFilePos();
1784              RIFF::List* wave = wvpl->GetFirstSubList();              RIFF::List* wave = wvpl->GetFirstSubList();
1785              while (wave) {              while (wave) {
1786                  if (wave->GetListType() == LIST_TYPE_WAVE) {                  if (wave->GetListType() == LIST_TYPE_WAVE) {
1787                        // notify current progress
1788                        const float subprogress = (float) iSampleIndex / (float) iTotalSamples;
1789                        __notify_progress(pProgress, subprogress);
1790    
1791                      if (!pSamples) pSamples = new SampleList;                      if (!pSamples) pSamples = new SampleList;
1792                      unsigned long waveFileOffset = wave->GetFilePos();                      unsigned long waveFileOffset = wave->GetFilePos();
1793                      pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));                      pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));
1794    
1795                        iSampleIndex++;
1796                  }                  }
1797                  wave = wvpl->GetNextSubList();                  wave = wvpl->GetNextSubList();
1798              }              }
1799                __notify_progress(pProgress, 1.0); // notify done
1800          }          }
1801          else throw gig::Exception("Mandatory <wvpl> chunk not found.");          else throw gig::Exception("Mandatory <wvpl> chunk not found.");
1802      }      }
# Line 1727  namespace gig { namespace { Line 1817  namespace gig { namespace {
1817      /**      /**
1818       * Returns the instrument with the given index.       * Returns the instrument with the given index.
1819       *       *
1820         * @param index     - number of the sought instrument (0..n)
1821         * @param pProgress - optional: callback function for progress notification
1822       * @returns  sought instrument or NULL if there's no such instrument       * @returns  sought instrument or NULL if there's no such instrument
1823       */       */
1824      Instrument* File::GetInstrument(uint index) {      Instrument* File::GetInstrument(uint index, progress_t* pProgress) {
1825          if (!pInstruments) LoadInstruments();          if (!pInstruments) {
1826                // TODO: hack - we simply load ALL samples here, it would have been done in the Region constructor anyway (ATM)
1827    
1828                // sample loading subtask
1829                progress_t subprogress;
1830                __divide_progress(pProgress, &subprogress, 3.0f, 0.0f); // randomly schedule 33% for this subtask
1831                __notify_progress(&subprogress, 0.0f);
1832                GetFirstSample(&subprogress); // now force all samples to be loaded
1833                __notify_progress(&subprogress, 1.0f);
1834    
1835                // instrument loading subtask
1836                if (pProgress && pProgress->callback) {
1837                    subprogress.__range_min = subprogress.__range_max;
1838                    subprogress.__range_max = pProgress->__range_max; // schedule remaining percentage for this subtask
1839                }
1840                __notify_progress(&subprogress, 0.0f);
1841                LoadInstruments(&subprogress);
1842                __notify_progress(&subprogress, 1.0f);
1843            }
1844          if (!pInstruments) return NULL;          if (!pInstruments) return NULL;
1845          InstrumentsIterator = pInstruments->begin();          InstrumentsIterator = pInstruments->begin();
1846          for (uint i = 0; InstrumentsIterator != pInstruments->end(); i++) {          for (uint i = 0; InstrumentsIterator != pInstruments->end(); i++) {
# Line 1740  namespace gig { namespace { Line 1850  namespace gig { namespace {
1850          return NULL;          return NULL;
1851      }      }
1852    
1853      void File::LoadInstruments() {      void File::LoadInstruments(progress_t* pProgress) {
1854          RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);          RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
1855          if (lstInstruments) {          if (lstInstruments) {
1856                int iInstrumentIndex = 0;
1857              RIFF::List* lstInstr = lstInstruments->GetFirstSubList();              RIFF::List* lstInstr = lstInstruments->GetFirstSubList();
1858              while (lstInstr) {              while (lstInstr) {
1859                  if (lstInstr->GetListType() == LIST_TYPE_INS) {                  if (lstInstr->GetListType() == LIST_TYPE_INS) {
1860                        // notify current progress
1861                        const float localProgress = (float) iInstrumentIndex / (float) Instruments;
1862                        __notify_progress(pProgress, localProgress);
1863    
1864                        // divide local progress into subprogress for loading current Instrument
1865                        progress_t subprogress;
1866                        __divide_progress(pProgress, &subprogress, Instruments, iInstrumentIndex);
1867    
1868                      if (!pInstruments) pInstruments = new InstrumentList;                      if (!pInstruments) pInstruments = new InstrumentList;
1869                      pInstruments->push_back(new Instrument(this, lstInstr));                      pInstruments->push_back(new Instrument(this, lstInstr, &subprogress));
1870    
1871                        iInstrumentIndex++;
1872                  }                  }
1873                  lstInstr = lstInstruments->GetNextSubList();                  lstInstr = lstInstruments->GetNextSubList();
1874              }              }
1875                __notify_progress(pProgress, 1.0); // notify done
1876          }          }
1877          else throw gig::Exception("Mandatory <lins> list chunk not found.");          else throw gig::Exception("Mandatory <lins> list chunk not found.");
1878      }      }
# Line 1767  namespace gig { namespace { Line 1889  namespace gig { namespace {
1889          std::cout << "gig::Exception: " << Message << std::endl;          std::cout << "gig::Exception: " << Message << std::endl;
1890      }      }
1891    
1892    
1893    // *************** functions ***************
1894    // *
1895    
1896        /**
1897         * Returns the name of this C++ library. This is usually "libgig" of
1898         * course. This call is equivalent to RIFF::libraryName() and
1899         * DLS::libraryName().
1900         */
1901        String libraryName() {
1902            return PACKAGE;
1903        }
1904    
1905        /**
1906         * Returns version of this C++ library. This call is equivalent to
1907         * RIFF::libraryVersion() and DLS::libraryVersion().
1908         */
1909        String libraryVersion() {
1910            return VERSION;
1911        }
1912    
1913  } // namespace gig  } // namespace gig

Legend:
Removed from v.384  
changed lines
  Added in v.613

  ViewVC Help
Powered by ViewVC