|
|
|
|
@ -210,6 +210,35 @@ void TDStretch::clear()
|
|
|
|
|
{ |
|
|
|
|
outputBuffer.clear(); |
|
|
|
|
clearInput(); |
|
|
|
|
sourceInput = sourceOutput = sourceMid = 0; |
|
|
|
|
sourceValid = sourceCallback != nullptr; |
|
|
|
|
if (sourceCallback) sourceCallback(sourceContext, {SourceKind::Reset}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// uTun: метаданные принадлежат потребителю, SoundTouch не выделяет память для карты.
|
|
|
|
|
void TDStretch::setSourceCallback(SourceCallback callback, void* context, unsigned offset) |
|
|
|
|
{ |
|
|
|
|
sourceCallback = callback; |
|
|
|
|
sourceContext = context; |
|
|
|
|
sourceOffset = offset; |
|
|
|
|
sourceInput = sourceOutput = sourceMid = 0; |
|
|
|
|
sourceValid = callback != nullptr; |
|
|
|
|
if (callback) callback(context, {SourceKind::Reset}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void TDStretch::invalidateSource(SourceError reason) |
|
|
|
|
{ |
|
|
|
|
if (!sourceValid) return; |
|
|
|
|
sourceValid = false; |
|
|
|
|
sourceCallback(sourceContext, {SourceKind::Invalid, reason}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void TDStretch::emitSource(SourceKind kind, uint64_t first, uint64_t second, unsigned count) |
|
|
|
|
{ |
|
|
|
|
if (!sourceValid || !count) return; |
|
|
|
|
sourceCallback(sourceContext, {kind, SourceError::None, sourceOutput, |
|
|
|
|
first + sourceOffset, second + sourceOffset, count}); |
|
|
|
|
sourceOutput += count; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -645,6 +674,7 @@ void TDStretch::processSamples()
|
|
|
|
|
// (that's in 'midBuffer')
|
|
|
|
|
overlap(outputBuffer.ptrEnd((uint)overlapLength), inputBuffer.ptrBegin(), (uint)offset); |
|
|
|
|
outputBuffer.putSamples((uint)overlapLength); |
|
|
|
|
emitSource(SourceKind::Mix, sourceMid, sourceInput + offset, (unsigned)overlapLength); |
|
|
|
|
offset += overlapLength; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
@ -683,6 +713,7 @@ void TDStretch::processSamples()
|
|
|
|
|
// length of sequence
|
|
|
|
|
temp = (seekWindowLength - 2 * overlapLength); |
|
|
|
|
outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * offset, (uint)temp); |
|
|
|
|
emitSource(SourceKind::Copy, sourceInput + offset, 0, (unsigned)temp); |
|
|
|
|
|
|
|
|
|
// Copies the end of the current sequence from 'inputBuffer' to
|
|
|
|
|
// 'midBuffer' for being mixed with the beginning of the next
|
|
|
|
|
@ -690,6 +721,7 @@ void TDStretch::processSamples()
|
|
|
|
|
assert((offset + temp + overlapLength) <= (int)inputBuffer.numSamples()); |
|
|
|
|
memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp), |
|
|
|
|
channels * sizeof(SAMPLETYPE) * overlapLength); |
|
|
|
|
sourceMid = sourceInput + offset + temp; |
|
|
|
|
|
|
|
|
|
// Remove the processed samples from the input buffer. Update
|
|
|
|
|
// the difference between integer & nominal skip step to 'skipFract'
|
|
|
|
|
@ -697,7 +729,7 @@ void TDStretch::processSamples()
|
|
|
|
|
skipFract += nominalSkip; // real skip size
|
|
|
|
|
ovlSkip = (int)skipFract; // rounded to integer skip
|
|
|
|
|
skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip
|
|
|
|
|
inputBuffer.receiveSamples((uint)ovlSkip); |
|
|
|
|
sourceInput += inputBuffer.receiveSamples((uint)ovlSkip); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|