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

Legend:
Removed from v.2  
changed lines
  Added in v.24

  ViewVC Help
Powered by ViewVC