// VERSION CONTROL // Sheader: G:/PVCS/ARCHIVES/TPRTDLL/rate.cpv 1.23 Aug 15 1997 15:52:40 jclaar S #include "precomp.h" #include #include #include #include #include #include // FOLLOWING IS THE NEW FILTER IMPLEMENTATION, WHICH IS BASED ON THIS PSEUDO-CODE // First stage (sample frame number) // frameSamplePeriod should be nominalFramPeriod ? // nominalFramePeriod : kWorstCaseHardwareUpdateTime // minForwardFilterDepth = log2((frameUpdatePeriod + minForwardFilterLength) / frameSamplePeriod) + 2 // minReverseFilterDepth = log2 ((frameUpdatePeriod + minReverseFilterLength) / frameSamplePeriod) + 2 // every frameSamplePeriod (can use waitTime as a delay) // read beforeSampleNumber // read inputFrameNumber // read afterSampleNumber // inputSampleNumber = capturerTimeVaries ? (beforeSampleNumber + afterSampleNumber) 1 : beforeSampleNumber // Second stage (lowpass filter) // static samplePeriods = 0 // static currentPosition = 0 // static filterDepthLimit = 1 starting at 0, spaced apart by lnitialFrameNumber // / Initialize samples starting at 0, spaced apart by frameSamplePeriod // filterRate [kMaxFilterDepth+1] // newSamplePeriods = (currentTime + (frameSamplePeriod 1) lastIterateTime / frameSamplePeriod // if (kExternalFrameClock) // if (newSamplePeriods > 0) // lastIterateTime = currentTime else // lastIterateTime += newSamplePeriods * frameSamplePeriod // waitTime = lastIterateTime + framesamplePerlod - currentTime // samplePeriods += newSamplePeriods // if (samplePeriods = = 0 || newSamplePeriods > 1) return waitTime // lastPoint = mFilterArray[currentPosition - 1] mFllterArray[mCurrentPositlon - 2] // for (j = 1: j the case j = = samplePeriods // filterArray(currentPosition).frame = filterArray(currentPosition l].frame + // lastPoint.frame + (j* (inputFrameNumber - lastPoint.frame)) / samplePeriods // filterArraylcurrentPosltion] sample = fllterArray[currentPosition l].sample + lastPoint.sample + (j * (inputSampleNumber - lastPoint.sample)) / samplePeriods // // determine the minimum filter depth based on whether we're going forward or backward // minFilterDepth =max(minForwardFitlerDepth, minReverseFilterDepth) // minFilterDepth = filterArray[currentPosition].frme + // filterArray[currentPosition - (1 minFilterDepth)].frame // (filterArray[currentPosition - (1 1) > = 0 ? // minForwardFilterDepth : minReverseFilterDepth // // calculate rate in frames/period (really use fixed point) // rate = filterArray[currentPosition] + fllterArray[currentPosition (1 minFilterDepth)] // (filterArray[currentPosition - (1 2 // for (currentFilterDepth = kMaxFilterDepth, i = minFilterDepth; i kMaxFilterDepth; i++) filterRate[i] = filterArray[currentPosition] + filterArray[currentPosition - (1 frameSamplePeriod to the variance in the input frame rate // // if the variance in frameSamplePeriod is significant, rate should be calculated by dividing the difference // // in frame numbers by the difference in sample numbers // if (currentFilterDepth = = kMaxFilterDepth & & abs(rate.frame - filterRate [i].frame) > (5 = = minFilterDepth // currentFilterDepth = i - 1 // rate - filterRate[i] // if (1 > > currentFilterDepth filterDepthLimit) // limit increase in depth to prevent usage of "stable" filter that actually // currentFilterDepth -- // has equal but opposite transients passing through it // if (filterDepthLimit filterArray[currentPosition - il CurrentFilterDepth)] + // (filterRate [currentFilterDeph) > currentFilterDepth, // filterRate [currentFilterDepth] * kDecimate > > (currentFilterDepth - 1 pass = 0 // currentPositio stop/cue/play to simulate CD-type shuttling // if (newRate > kMaxRate) newRate = kMaxRate // if (newRate rateTolerance = (kMaxUnityError / samplesPerFrame) * nominalFrameperiod (frameSamplePeriod * kDecimate) kSyncWindowFactor = 8 // Use tighter rate & position windows before locking into unity speed // if (newRate > 1.0 - rateTolerance & & newRate > kMaxUnityError) if (unityRateTimer 1.0 - rateTolerance / kSyncWindowFactor & & // newRate kMaxUnityError / kSyncWindowFactor) // unityRateTimer++ else // newRate = 1.0 else if (newRate -1.0 - rateTolerance & & error reverseSyncLocDelay) // if (newRate -1.o - rateTolerance / kSyncWindowFactor & & error else // newRate = -1.0 else // unityRateTimer = 0 // currentRateCueHint = (currentRate =0 ? kForward : 0) // if (error > kMaxChaseError & & abs(newRate) = = kMaxRate | cueHint I = kBidirectional & & currentRate CueHint & -cueHint) // cueHint = currentRateCueHint // cueSettleTime = kCueSettleTime (cueHint = = kBidirectional) // if (cueSettleTime lock position = newFrameNumber * samplesPerFrame - currentRate (cueTimeStamp - newSampleNumber) // cue transport to position at commandTimeStamp with cueHint // cuePosition = position // else if (commandTimeStamp + newRateFilterDelta > = cueTimeStamp) lock = (unityRateTimer = - forwardSyncLockDelayIlunityRateTimer = = reverseSyncLockDelay) & & abs(newRate) = = 1.0 // lf (newRate != lastActualRate | lock != lastActualLock) // set transport rate to newRate at rateTimeStamp with lock // cueTimeStamp = rateTimeStamp // if (cueHint != kBidirectional) // if (position > - cuePosition + kCueSettleTime) // cueHint | = kBackward // else if (position lastActualRateTimeStamp) // lastActualRate = cmd.mRate // lastActualRateTimeStamp = cmd.mTimeStamp // lastActualLock = md.mLock // upon receipt of a transport cue command // actualPosition = cmd.mCue.mTime // lastActualRateTimeStamp = cmd.mTimeStamp static const Int16 INFINITE~SYNLOCK~DELAY = Ox7FFF; SyNewRateControl::SyNewRateControl IEEE32 sampleRate, // Samples/second IEEE32 nominalFramePeriod, // Milliseconds/frame for this type of time code at unity rate Bool32 victTypeUpdate, // TRUE iff frame numbers change only on nominal frame period boundaries UInt32 forwardSyncLockDelay, // Time in ms over which timecode rate must stay at play speed before a play command is issued UInt32 reverseSyncLockDelay, // Time in ms over which timecode rate must stay at play reverse speed before a play reverse command is issued UInt32 minForwardFilterLenght, // Period in ms over which average timecode rate is stable in the forward direction UInt32 mlnReverseFilterLength, // Period in ms over which average timecode rate is stable in the reverse direction UInt32 frameSamplePeriod, // Period between calls to CalculateRate ), should be Bool32 externalFrameSampleLock, // TRUE iff period between calls to CalculateRate is driven by external dock IEEE32 maxFrameSamplePeriodvarlance, // Ideally less than half of frameSamplePeriod (see note in FilterFrameNumber IEEE32 captureDelay, // ms between H/W capture of frame number and middle of CurrentFrameNumber () call Bool32 captureTimeVaries, // TRUE iff call to currentFrameNumber Boll32 throwAwayLateFilterPoints, // TRUE iff late calls to CalculateRate can happen, FALSE if calls to CalculateRate // might be skipped but will not affect subsequent calls Bool32 correctForFilterDelay, // TRUE if the output should be adjusted to correct for the positional // (time) delay through the filter; generally TRUE for time code filters // (so they lock at the right position) and FALSE for jog filters UIntl6 decimationFactor, // Transport rate will be updated every decimationFactor*frameSamplePeriod ms Int32 priority, // Should be not higher than the thread that calls CalculateRate( ), or // accuracy of ()'s return value may be adversely affected IEEE32 worstCaseHardwareUpdateTime // Max time for hardware to update frame number when inputtime code changes IEEE32 maxRate, // Max +/- rate at which we can move the transport (default +12.5% varispeed) IEEE32 maxUnityError, // Maximum number of frames we can off by and still maintain "unity" rate IEEE32 maxChaseError, // Maximum number of frames we can be off while chasing before cueing to catch up UIntl6 maxFilterDepth, // Lenght of the longest FIR filter will be 1 maxFilterDepth UInt32 pipeDepth // Depth of sync pipe used to pass decimated filter points to output stage SyTask(NULL, NULL, 0, TRUE, INFINITE, TRUE, priority), kSamplesPerMillisecond(SampleRate / 1000.0), mFrameUpdatePeriod vitcTypeUpdate & & worstCaseHardWareUpdateTime nominalFramePeriod worstCaseHardwareUpdateTime maxFrameSamplePeriodVariance FrameSamplePeriod(frameSamplePeriod) , kExternalFrameSampleClock(externalFrameSampleClock), kCaptureDelay(captureDelay +sampleRate / 1000.f), kCaptureTimeVaries(captureTimeVaries), kThrowAwayLateFllterPoints(throwAwayLateFllterPoints), mCorrectForFilterDelay(correctForFilterDelay) kMaxFilterDepth(maxFilterDepth), kDecimate(decimationFactor), mFilterArray(new SyFllterPoint[l size of the array to simplify indexing mFllterRate(new SyFxlterPolntEmaxFilterDepth + 11), mFllterPlpe(plpeDepth), kMaxRate(maxRate), kRateTolerance((maxUnityError * nominalFramePeriod) / (frameSamplePeriod decimationFactor)). kMaxUnuityError (maxUnityError * nominalFramePeriod * sampleRate / 1000.0). xMaxChaseError (maxChaseError * nominalFramePeriod * sampleRate / 1000,0), kRatePrecisionThreshold (5 * nominalFramePeriod * sampleRate / 100.0).