sampleCount Mixer::MixSameRate(int *channelFlags, WaveTrack *track, longSampleCount *pos) { int slen = mMaxOut; int c; double t = *pos / track->GetRate(); if (t + slen/track->GetRate() > mT1) slen = (int)((mT1 - t) * track->GetRate() + 0.5); if (slen <= 0) return 0; if (slen > mMaxOut) slen = mMaxOut; track->Get((samplePtr)mFloatBuffer, floatSample, *pos, slen); track->GetEnvelopeValues(mEnvValues, slen, t, 1.0 / mRate); for(int i=0; i<slen; i++) mFloatBuffer[i] *= mEnvValues[i]; // Track gain control will go here? for(c=0; c<mNumChannels; c++) if (mApplyTrackGains) mGains[c] = track->GetChannelGain(c); else mGains[c] = 1.0; MixBuffers(mNumChannels, channelFlags, mGains, (samplePtr)mFloatBuffer, mTemp, slen, mInterleaved); *pos += slen; return slen; }
sampleCount Mixer::MixSameRate(int *channelFlags, WaveTrack *track, sampleCount *pos) { int slen = mMaxOut; int c; const double t = *pos / track->GetRate(); const double trackEndTime = track->GetEndTime(); const double trackStartTime = track->GetStartTime(); const bool backwards = (mT1 < mT0); const double tEnd = backwards ? std::max(trackStartTime, mT1) : std::min(trackEndTime, mT1); //don't process if we're at the end of the selection or track. if ((backwards ? t <= tEnd : t >= tEnd)) return 0; //if we're about to approach the end of the track or selection, figure out how much we need to grab if (backwards) { if (t - slen/track->GetRate() < tEnd) slen = (int)((t - tEnd) * track->GetRate() + 0.5); } else { if (t + slen/track->GetRate() > tEnd) slen = (int)((tEnd - t) * track->GetRate() + 0.5); } if (slen > mMaxOut) slen = mMaxOut; if (backwards) { track->Get((samplePtr)mFloatBuffer, floatSample, *pos - (slen - 1), slen); track->GetEnvelopeValues(mEnvValues, slen, t - (slen - 1) / mRate, 1.0 / mRate); for(int i=0; i<slen; i++) mFloatBuffer[i] *= mEnvValues[i]; // Track gain control will go here? ReverseSamples((samplePtr)mFloatBuffer, floatSample, 0, slen); *pos -= slen; } else { track->Get((samplePtr)mFloatBuffer, floatSample, *pos, slen); track->GetEnvelopeValues(mEnvValues, slen, t, 1.0 / mRate); for(int i=0; i<slen; i++) mFloatBuffer[i] *= mEnvValues[i]; // Track gain control will go here? *pos += slen; } for(c=0; c<mNumChannels; c++) if (mApplyTrackGains) mGains[c] = track->GetChannelGain(c); else mGains[c] = 1.0; MixBuffers(mNumChannels, channelFlags, mGains, (samplePtr)mFloatBuffer, mTemp, slen, mInterleaved); return slen; }
sampleCount Mixer::MixSameRate(int *channelFlags, WaveTrack *track, sampleCount *pos) { int slen = mMaxOut; int c; double t = *pos / track->GetRate(); double trackEndTime = track->GetEndTime(); double tEnd = trackEndTime > mT1 ? mT1 : trackEndTime; //don't process if we're at the end of the selection or track. if (t>=tEnd) return 0; //if we're about to approach the end of the track or selection, figure out how much we need to grab if (t + slen/track->GetRate() > tEnd) slen = (int)((tEnd - t) * track->GetRate() + 0.5); if (slen > mMaxOut) slen = mMaxOut; track->Get((samplePtr)mFloatBuffer, floatSample, *pos, slen); track->GetEnvelopeValues(mEnvValues, slen, t, 1.0 / mRate); for(int i=0; i<slen; i++) mFloatBuffer[i] *= mEnvValues[i]; // Track gain control will go here? for(c=0; c<mNumChannels; c++) if (mApplyTrackGains) mGains[c] = track->GetChannelGain(c); else mGains[c] = 1.0; MixBuffers(mNumChannels, channelFlags, mGains, (samplePtr)mFloatBuffer, mTemp, slen, mInterleaved); *pos += slen; return slen; }
sampleCount Mixer::MixVariableRates(int *channelFlags, WaveTrack *track, longSampleCount *pos, float *queue, int *queueStart, int *queueLen, Resample *SRC) { double initialWarp = mRate / track->GetRate(); double t = *pos / track->GetRate(); int sampleSize = SAMPLE_SIZE(floatSample); int i, c; sampleCount out = 0; while(out < mMaxOut) { if (*queueLen < mProcessLen) { memmove(queue, &queue[*queueStart], (*queueLen)*sampleSize); *queueStart = 0; int getLen = mQueueMaxLen - *queueLen; #if 0 // TODO: fix this code so that extra silence isn't added // to the end of a track double trackTime = (*pos + getLen) / track->GetRate(); if (trackTime > track->GetEndTime()) { getLen = (int)(0.5 + track->GetRate() * (track->GetEndTime() - ((*pos) / track->GetRate()))); } #endif track->Get((samplePtr)&queue[*queueLen], floatSample, *pos, getLen); track->GetEnvelopeValues(mEnvValues, getLen, (*pos) / track->GetRate(), 1.0 / track->GetRate()); for(i=0; i<getLen; i++) queue[(*queueLen)+i] *= mEnvValues[i]; *queueLen += getLen; *pos += getLen; } sampleCount thisProcessLen = mProcessLen; if (*queueLen < mProcessLen) thisProcessLen = *queueLen; double factor = initialWarp; if (mTimeTrack) { double warpFactor = mTimeTrack->GetEnvelope()->GetValue(t); warpFactor = (mTimeTrack->GetRangeLower() * (1 - warpFactor) + warpFactor * mTimeTrack->GetRangeUpper())/100.0; factor /= warpFactor; } int input_used; bool last = (*queueLen < mProcessLen); int outgen = SRC->Process(factor, &queue[*queueStart], thisProcessLen, last, &input_used, &mFloatBuffer[out], mMaxOut - out); if (outgen < 0) return 0; *queueStart += input_used; *queueLen -= input_used; out += outgen; t += (input_used / track->GetRate()); if (last) break; } for(c=0; c<mNumChannels; c++) if (mApplyTrackGains) mGains[c] = track->GetChannelGain(c); else mGains[c] = 1.0; MixBuffers(mNumChannels, channelFlags, mGains, (samplePtr)mFloatBuffer, mTemp, mMaxOut, mInterleaved); return mMaxOut; }
sampleCount Mixer::MixVariableRates(int *channelFlags, WaveTrack *track, longSampleCount *pos, float *queue, int *queueStart, int *queueLen, Resample *SRC) { double trackRate = track->GetRate(); double initialWarp = mRate / trackRate; double t = *pos / trackRate; int sampleSize = SAMPLE_SIZE(floatSample); int i, c; sampleCount out = 0; // Find the last sample longSampleCount last = -1; WaveClipList::Node* it = track->GetClipIterator(); while (it) { longSampleCount end = it->GetData()->GetEndSample(); if (end > last) { last = end; } it = it->GetNext(); } longSampleCount max = trackRate * mT1; if (last > max) last = max; while(out < mMaxOut) { if (*queueLen < mProcessLen) { memmove(queue, &queue[*queueStart], (*queueLen)*sampleSize); *queueStart = 0; int getLen = mQueueMaxLen - *queueLen; // Constrain if (*pos + getLen > last) { getLen = last - *pos; } // Nothing to do if past end of track if (getLen <= 0) { break; } track->Get((samplePtr)&queue[*queueLen], floatSample, *pos, getLen); track->GetEnvelopeValues(mEnvValues, getLen, (*pos) / trackRate, 1.0 / trackRate); for(i=0; i<getLen; i++) queue[(*queueLen)+i] *= mEnvValues[i]; *queueLen += getLen; *pos += getLen; } sampleCount thisProcessLen = mProcessLen; if (*queueLen < mProcessLen) thisProcessLen = *queueLen; double factor = initialWarp; if (mTimeTrack) { double warpFactor = mTimeTrack->GetEnvelope()->GetValue(t); warpFactor = (mTimeTrack->GetRangeLower() * (1 - warpFactor) + warpFactor * mTimeTrack->GetRangeUpper())/100.0; factor /= warpFactor; } int input_used; bool last = (*queueLen < mProcessLen); int outgen = SRC->Process(factor, &queue[*queueStart], thisProcessLen, last, &input_used, &mFloatBuffer[out], mMaxOut - out); if (outgen < 0) return 0; *queueStart += input_used; *queueLen -= input_used; out += outgen; t += (input_used / trackRate); if (last) break; } for(c=0; c<mNumChannels; c++) if (mApplyTrackGains) mGains[c] = track->GetChannelGain(c); else mGains[c] = 1.0; MixBuffers(mNumChannels, channelFlags, mGains, (samplePtr)mFloatBuffer, mTemp, out, mInterleaved); return out; }
sampleCount Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache, sampleCount *pos, float *queue, int *queueStart, int *queueLen, Resample * pResample) { const WaveTrack *const track = cache.GetTrack(); const double trackRate = track->GetRate(); const double initialWarp = mRate / mSpeed / trackRate; const double tstep = 1.0 / trackRate; int sampleSize = SAMPLE_SIZE(floatSample); sampleCount out = 0; /* time is floating point. Sample rate is integer. The number of samples * has to be integer, but the multiplication gives a float result, which we * round to get an integer result. TODO: is this always right or can it be * off by one sometimes? Can we not get this information directly from the * clip (which must know) rather than convert the time? * * LLL: Not at this time. While WaveClips provide methods to retrieve the * start and end sample, they do the same float->sampleCount conversion * to calculate the position. */ // Find the last sample double endTime = track->GetEndTime(); double startTime = track->GetStartTime(); const bool backwards = (mT1 < mT0); const double tEnd = backwards ? std::max(startTime, mT1) : std::min(endTime, mT1); const sampleCount endPos = track->TimeToLongSamples(tEnd); // Find the time corresponding to the start of the queue, for use with time track double t = (*pos + (backwards ? *queueLen : - *queueLen)) / trackRate; while (out < mMaxOut) { if (*queueLen < mProcessLen) { // Shift pending portion to start of the buffer memmove(queue, &queue[*queueStart], (*queueLen) * sampleSize); *queueStart = 0; int getLen = std::min((backwards ? *pos - endPos : endPos - *pos), sampleCount(mQueueMaxLen - *queueLen)); // Nothing to do if past end of play interval if (getLen > 0) { if (backwards) { auto results = cache.Get(floatSample, *pos - (getLen - 1), getLen); memcpy(&queue[*queueLen], results, sizeof(float) * getLen); track->GetEnvelopeValues(mEnvValues, getLen, (*pos - (getLen- 1)) / trackRate, tstep); *pos -= getLen; } else { auto results = cache.Get(floatSample, *pos, getLen); memcpy(&queue[*queueLen], results, sizeof(float) * getLen); track->GetEnvelopeValues(mEnvValues, getLen, (*pos) / trackRate, tstep); *pos += getLen; } for (int i = 0; i < getLen; i++) { queue[(*queueLen) + i] *= mEnvValues[i]; } if (backwards) ReverseSamples((samplePtr)&queue[0], floatSample, *queueLen, getLen); *queueLen += getLen; } } sampleCount thisProcessLen = mProcessLen; bool last = (*queueLen < mProcessLen); if (last) { thisProcessLen = *queueLen; } double factor = initialWarp; if (mTimeTrack) { //TODO-MB: The end time is wrong when the resampler doesn't use all input samples, // as a result of this the warp factor may be slightly wrong, so AudioIO will stop too soon // or too late (resulting in missing sound or inserted silence). This can't be fixed // without changing the way the resampler works, because the number of input samples that will be used // is unpredictable. Maybe it can be compensated later though. if (backwards) factor *= mTimeTrack->ComputeWarpFactor (t - (double)thisProcessLen / trackRate + tstep, t + tstep); else factor *= mTimeTrack->ComputeWarpFactor (t, t + (double)thisProcessLen / trackRate); } int input_used; int outgen = pResample->Process(factor, &queue[*queueStart], thisProcessLen, last, &input_used, &mFloatBuffer[out], mMaxOut - out); if (outgen < 0) { return 0; } *queueStart += input_used; *queueLen -= input_used; out += outgen; t += ((backwards ? -input_used : input_used) / trackRate); if (last) { break; } } for (int c = 0; c < mNumChannels; c++) { if (mApplyTrackGains) { mGains[c] = track->GetChannelGain(c); } else { mGains[c] = 1.0; } } MixBuffers(mNumChannels, channelFlags, mGains, (samplePtr)mFloatBuffer, mTemp, out, mInterleaved); return out; }
sampleCount Mixer::MixVariableRates(int *channelFlags, WaveTrack *track, sampleCount *pos, float *queue, int *queueStart, int *queueLen, Resample * pResample) { double trackRate = track->GetRate(); double initialWarp = mRate / trackRate; double tstep = 1.0 / trackRate; double t = (*pos - *queueLen) / trackRate; int sampleSize = SAMPLE_SIZE(floatSample); sampleCount out = 0; /* time is floating point. Sample rate is integer. The number of samples * has to be integer, but the multiplication gives a float result, which we * round to get an integer result. TODO: is this always right or can it be * off by one sometimes? Can we not get this information directly from the * clip (which must know) rather than convert the time? * * LLL: Not at this time. While WaveClips provide methods to retrieve the * start and end sample, they do the same float->sampleCount conversion * to calculate the position. */ // Find the last sample sampleCount endPos; double endTime = track->GetEndTime(); if (endTime > mT1) { endPos = track->TimeToLongSamples(mT1); } else { endPos = track->TimeToLongSamples(endTime); } while (out < mMaxOut) { if (*queueLen < mProcessLen) { memmove(queue, &queue[*queueStart], (*queueLen) * sampleSize); *queueStart = 0; int getLen = mQueueMaxLen - *queueLen; // Constrain if (*pos + getLen > endPos) { getLen = endPos - *pos; } // Nothing to do if past end of track if (getLen > 0) { track->Get((samplePtr)&queue[*queueLen], floatSample, *pos, getLen); track->GetEnvelopeValues(mEnvValues, getLen, (*pos) / trackRate, tstep); for (int i = 0; i < getLen; i++) { queue[(*queueLen) + i] *= mEnvValues[i]; } *queueLen += getLen; *pos += getLen; } } sampleCount thisProcessLen = mProcessLen; bool last = (*queueLen < mProcessLen); if (last) { thisProcessLen = *queueLen; } double factor = initialWarp; if (mTimeTrack) { //TODO-MB: The end time is wrong when the resampler doesn't use all input samples, // as a result of this the warp factor may be slightly wrong, so AudioIO will stop too soon // or too late (resulting in missing sound or inserted silence). This can't be fixed // without changing the way the resampler works, because the number of input samples that will be used // is unpredictable. Maybe it can be compensated lated though. factor *= mTimeTrack->ComputeWarpFactor(t, t + (double)thisProcessLen / trackRate); } int input_used; int outgen = pResample->Process(factor, &queue[*queueStart], thisProcessLen, last, &input_used, &mFloatBuffer[out], mMaxOut - out); if (outgen < 0) { return 0; } *queueStart += input_used; *queueLen -= input_used; out += outgen; t += (input_used / trackRate); if (last) { break; } } for (int c = 0; c < mNumChannels; c++) { if (mApplyTrackGains) { mGains[c] = track->GetChannelGain(c); } else { mGains[c] = 1.0; } } MixBuffers(mNumChannels, channelFlags, mGains, (samplePtr)mFloatBuffer, mTemp, out, mInterleaved); return out; }