39#undef PACKAGE_BUGREPORT
42#include "SoundTouch.h"
45SoundTouchBase::SoundTouchBase()
51SoundTouchBase::~SoundTouchBase()
55bool SoundTouchBase::ProcessLabelTrack(
73bool SoundTouchBase::ProcessWithTimeWarper(InitFunction initer,
84 if (mT1 == warper.
Warp(mT1)) {
91 bool bGoodResult =
true;
93 mPreserveLength = preserveLength;
97 outputs.
Get().
Any().VisitWhile(bGoodResult,
98 [&](
auto &&fallthrough){
return [&](
LabelTrack <) {
101 return fallthrough();
102 if (!ProcessLabelTrack(<, warper))
106 [&](
auto &&fallthrough){
return [&](
NoteTrack &nt) {
109 return fallthrough();
110 if (!ProcessNoteTrack(&nt, warper))
114 [&](
auto &&fallthrough){
return [&](
WaveTrack &orig) {
115 if (!orig.GetSelected())
116 return fallthrough();
121 const auto start = orig.TimeToLongSamples(mT0);
122 const auto end = orig.TimeToLongSamples(mT1);
124 const auto tempTrack = orig.EmptyCopy();
125 auto &out = *tempTrack;
127 const auto pSoundTouch = std::make_unique<soundtouch::SoundTouch>();
128 initer(pSoundTouch.get());
131 auto channels = orig.Channels();
132 if (channels.size() > 1) {
135 pSoundTouch->setChannels(2);
138 if (!ProcessStereo(pSoundTouch.get(),
139 orig, out, start,
end, warper))
144 pSoundTouch->setChannels(1);
147 if (!ProcessOne(pSoundTouch.get(), **channels.begin(),
148 out, start,
end, warper))
157 t.SyncLockAdjust(mT1, warper.
Warp(mT1));
169bool SoundTouchBase::ProcessOne(soundtouch::SoundTouch *pSoundTouch,
178 pSoundTouch->setSampleRate(
179 static_cast<unsigned int>((orig.
GetRate() + 0.5)));
184 auto len = (
end - start).as_double();
196 const auto block = std::min<size_t>(8192,
203 pSoundTouch->putSamples(buffer.get(), block);
206 unsigned int outputCount = pSoundTouch->numSamples();
207 if (outputCount > 0) {
208 Floats buffer2{ outputCount };
209 pSoundTouch->receiveSamples(buffer2.get(), outputCount);
217 if (TrackProgress(mCurTrackNum, (s - start).as_double() / len))
222 pSoundTouch->flush();
224 unsigned int outputCount = pSoundTouch->numSamples();
225 if (outputCount > 0) {
226 Floats buffer2{ outputCount };
227 pSoundTouch->receiveSamples(buffer2.get(), outputCount);
235 Finalize(orig.
GetTrack(), out, warper);
238 m_maxNewLength = std::max(m_maxNewLength, newLength);
244bool SoundTouchBase::ProcessStereo(soundtouch::SoundTouch *pSoundTouch,
248 pSoundTouch->setSampleRate(
249 static_cast<unsigned int>(orig.
GetRate() + 0.5));
252 auto &leftTrack = **channels.first++;
253 auto &rightTrack = **channels.first;
255 auto newChannels = outputTrack.
Channels();
256 auto &outputLeftTrack = **newChannels.first++;
257 auto &outputRightTrack = **newChannels.first;
262 double len = (
end - start).as_double();
278 auto sourceSampleCount = start;
279 while (sourceSampleCount <
end) {
282 end - sourceSampleCount
286 leftTrack.GetFloats((leftBuffer.get()), sourceSampleCount, blockSize);
288 .GetFloats((rightBuffer.get()), sourceSampleCount, blockSize);
291 for (
decltype(blockSize) index = 0; index < blockSize; index++) {
292 soundTouchBuffer[index * 2] = leftBuffer[index];
293 soundTouchBuffer[(index * 2) + 1] = rightBuffer[index];
297 pSoundTouch->putSamples(soundTouchBuffer.get(), blockSize);
300 unsigned int outputCount = pSoundTouch->numSamples();
302 this->ProcessStereoResults(pSoundTouch,
303 outputCount, outputLeftTrack, outputRightTrack);
306 sourceSampleCount += blockSize;
310 int nWhichTrack = mCurTrackNum;
311 double frac = (sourceSampleCount - start).as_double() / len;
320 if (TrackProgress(nWhichTrack, frac))
325 pSoundTouch->flush();
327 unsigned int outputCount = pSoundTouch->numSamples();
329 this->ProcessStereoResults(pSoundTouch,
330 outputCount, outputLeftTrack, outputRightTrack);
336 Finalize(orig, outputTrack, warper);
341 m_maxNewLength = std::max(m_maxNewLength, newLength);
347bool SoundTouchBase::ProcessStereoResults(soundtouch::SoundTouch *pSoundTouch,
348 const size_t outputCount,
352 Floats outputSoundTouchBuffer{ outputCount * 2 };
353 pSoundTouch->receiveSamples(outputSoundTouchBuffer.get(), outputCount);
356 Floats outputLeftBuffer{ outputCount };
357 Floats outputRightBuffer{ outputCount };
358 for (
unsigned int index = 0; index < outputCount; ++index) {
359 outputLeftBuffer[index] = outputSoundTouchBuffer[index * 2];
360 outputRightBuffer[index] = outputSoundTouchBuffer[(index * 2) + 1];
371void SoundTouchBase::Finalize(
375 if (mPreserveLength) {
380 if (newLen < oldLen) {
386 else if (newLen > oldLen) {
394 std::vector<std::pair<double, double>> gaps;
397 auto front = clips.front();
398 auto back = clips.back();
399 for (
auto &clip : clips) {
400 auto st = clip->GetPlayStartTime();
401 auto et = clip->GetPlayEndTime();
403 if (st >= mT0 || et < mT1) {
404 if (mT0 < st && clip == front) {
405 gaps.push_back(std::make_pair(mT0, st));
407 else if (last < st && mT0 <= last ) {
408 gaps.push_back(std::make_pair(last, st));
411 if (et < mT1 && clip == back) {
412 gaps.push_back(std::make_pair(et, mT1));
422 for (
auto gap : gaps) {
425 if (st >= mT0 && et <= mT1 && st != et)
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper,...
Use this object to copy the input tracks to tentative outputTracks.
TrackList & Get()
Expose the output track list for iterations or even erasures.
A LabelTrack is a Track that holds labels (LabelStruct).
void WarpLabels(const TimeWarper &warper)
A Track that is used for Midi notes. (Somewhat old code).
void WarpAndTransposeNotes(double t0, double t1, const TimeWarper &warper, double semitones)
static bool IsSyncLockSelected(const Track &track)
Transforms one point in time to another point. For example, a time stretching effect might use one to...
virtual double Warp(double originalTime) const =0
Abstract base class for an object holding data associated with points on a time axis.
bool GetSelected() const
Selectedness is always the same for all channels of a group.
auto Any() -> TrackIterRange< TrackType >
double GetRate() const override
bool Append(constSamplePtr buffer, sampleFormat format, size_t len)
bool GetFloats(float *buffer, sampleCount start, size_t len, fillFormat fill=FillFormat::fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const
"narrow" overload fetches from the unique channel
size_t GetBestBlockSize(sampleCount t) const
A hint for sizing of well aligned fetches.
size_t GetMaxBlockSize() const
A Track that contains audio waveform data.
void SplitDelete(double t0, double t1)
void InsertSilence(double t, double len) override
bool Append(size_t iChannel, constSamplePtr buffer, sampleFormat format, size_t len, unsigned int stride=1, sampleFormat effectiveFormat=widestSampleFormat) override
IntervalHolders SortedIntervalArray()
Return all WaveClips sorted by clip play start time.
void Trim(double t0, double t1)
double GetEndTime() const override
Implement WideSampleSequence.
double GetRate() const override
size_t NChannels() const override
A constant property.
size_t GetMaxBlockSize() const
size_t GetBestBlockSize(sampleCount t) const
void ClearAndPaste(double t0, double t1, const WaveTrack &src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=nullptr, bool clearByTrimming=false)
sampleCount GetVisibleSampleCount() const
double LongSamplesToTime(sampleCount pos) const
sampleCount TimeToLongSamples(double t0) const
double SnapToSample(double t) const
Positions or offsets within audio files need a wide type.
constexpr auto maxBlockSize
const char * end(const char *str) noexcept