--- libgig/trunk/src/gig.cpp 2003/10/25 20:15:04 2 +++ libgig/trunk/src/gig.cpp 2003/11/29 14:56:16 16 @@ -323,8 +323,9 @@ * @see SetPos() */ unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) { - if (!Compressed) return pCkData->Read(pBuffer, SampleCount, FrameSize); + if (!Compressed) return pCkData->Read(pBuffer, SampleCount, FrameSize); //FIXME: channel inversion due to endian correction? else { //FIXME: no support for mono compressed samples yet, are there any? + if (this->SamplePos >= this->SamplesTotal) return 0; //TODO: efficiency: we simply assume here that all frames are compressed, maybe we should test for an average compression rate // best case needed buffer size (all frames compressed) unsigned long assumedsize = (SampleCount << 1) + // *2 (16 Bit, stereo, but assume all frames compressed) @@ -353,8 +354,7 @@ // reload from disk to local buffer if needed if (remainingbytes < 8194) { if (pCkData->GetState() != RIFF::stream_ready) { - this->SamplePos += (SampleCount - remainingsamples); - //if (this->SamplePos > this->SamplesTotal) this->SamplePos = this->SamplesTotal; + this->SamplePos = this->SamplesTotal; return (SampleCount - remainingsamples); } assumedsize = remainingsamples; @@ -474,7 +474,7 @@ } } this->SamplePos += (SampleCount - remainingsamples); - //if (this->SamplePos > this->SamplesTotal) this->SamplePos = this->SamplesTotal; + if (this->SamplePos > this->SamplesTotal) this->SamplePos = this->SamplesTotal; return (SampleCount - remainingsamples); } } @@ -491,8 +491,14 @@ // *************** DimensionRegion *************** // * + uint DimensionRegion::Instances = 0; + DimensionRegion::VelocityTableMap* DimensionRegion::pVelocityTables = NULL; + DimensionRegion::DimensionRegion(RIFF::List* _3ewl) : DLS::Sampler(_3ewl) { + Instances++; + memcpy(&Crossfade, &SamplerOptions, 4); + if (!pVelocityTables) pVelocityTables = new VelocityTableMap; RIFF::Chunk* _3ewa = _3ewl->GetSubChunk(CHUNK_ID_3EWA); _3ewa->ReadInt32(); // unknown, allways 0x0000008C ? @@ -644,6 +650,75 @@ VCFVelocityDynamicRange = vcfvelocity % 5; VCFVelocityCurve = static_cast(vcfvelocity / 5); VCFType = static_cast(_3ewa->ReadUint8()); + + // get the corresponding velocity->volume table from the table map or create & calculate that table if it doesn't exist yet + uint32_t tableKey = (VelocityResponseCurve<<16) | (VelocityResponseDepth<<8) | VelocityResponseCurveScaling; + if (pVelocityTables->count(tableKey)) { // if key exists + pVelocityAttenuationTable = (*pVelocityTables)[tableKey]; + } + else { + pVelocityAttenuationTable = new double[128]; + switch (VelocityResponseCurve) { // calculate the new table + case curve_type_nonlinear: + for (int velocity = 0; velocity < 128; velocity++) { + pVelocityAttenuationTable[velocity] = + GIG_VELOCITY_TRANSFORM_NONLINEAR((double)(velocity+1),(double)(VelocityResponseDepth+1),(double)VelocityResponseCurveScaling); + if (pVelocityAttenuationTable[velocity] > 1.0) pVelocityAttenuationTable[velocity] = 1.0; + else if (pVelocityAttenuationTable[velocity] < 0.0) pVelocityAttenuationTable[velocity] = 0.0; + } + break; + case curve_type_linear: + for (int velocity = 0; velocity < 128; velocity++) { + pVelocityAttenuationTable[velocity] = + GIG_VELOCITY_TRANSFORM_LINEAR((double)velocity,(double)(VelocityResponseDepth+1),(double)VelocityResponseCurveScaling); + if (pVelocityAttenuationTable[velocity] > 1.0) pVelocityAttenuationTable[velocity] = 1.0; + else if (pVelocityAttenuationTable[velocity] < 0.0) pVelocityAttenuationTable[velocity] = 0.0; + } + break; + case curve_type_special: + for (int velocity = 0; velocity < 128; velocity++) { + pVelocityAttenuationTable[velocity] = + GIG_VELOCITY_TRANSFORM_SPECIAL((double)(velocity+1),(double)(VelocityResponseDepth+1),(double)VelocityResponseCurveScaling); + if (pVelocityAttenuationTable[velocity] > 1.0) pVelocityAttenuationTable[velocity] = 1.0; + else if (pVelocityAttenuationTable[velocity] < 0.0) pVelocityAttenuationTable[velocity] = 0.0; + } + break; + case curve_type_unknown: + default: + throw gig::Exception("Unknown transform curve type."); + } + (*pVelocityTables)[tableKey] = pVelocityAttenuationTable; // put the new table into the tables map + } + } + + DimensionRegion::~DimensionRegion() { + Instances--; + if (!Instances) { + // delete the velocity->volume tables + VelocityTableMap::iterator iter; + for (iter = pVelocityTables->begin(); iter != pVelocityTables->end(); iter++) { + double* pTable = iter->second; + if (pTable) delete[] pTable; + } + pVelocityTables->clear(); + delete pVelocityTables; + pVelocityTables = NULL; + } + } + + /** + * Returns the correct amplitude factor for the given \a MIDIKeyVelocity. + * All involved parameters (VelocityResponseCurve, VelocityResponseDepth + * and VelocityResponseCurveScaling) involved are taken into account to + * calculate the amplitude factor. Use this method when a key was + * triggered to get the volume with which the sample should be played + * back. + * + * @param MIDI velocity value of the triggered key (between 0 and 127) + * @returns amplitude factor (between 0.0 and 1.0) + */ + double DimensionRegion::GetVelocityAttenuation(uint8_t MIDIKeyVelocity) { + return pVelocityAttenuationTable[MIDIKeyVelocity]; }