Audacity 3.2.0
SBSMSEffect.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5SBSMSEffect.cpp
6
7Clayton Otey
8
9This class contains all of the common code for an
10effect that uses SBSMS to do its processing (TimeScale)
11
12**********************************************************************/
13
14
15
16#if USE_SBSMS
17#include "SBSMSEffect.h"
18
19#include <math.h>
20
21#include "../LabelTrack.h"
22#include "../SyncLock.h"
23#include "../WaveClip.h"
24#include "../WaveTrack.h"
25#include "TimeWarper.h"
26
27enum {
29};
30
32{
33public:
35 {
36 processed = 0;
37 }
38
40 {
41 }
42
43 bool bPitch;
45 double ratio;
47 size_t blockSize;
55 std::unique_ptr<SBSMS> sbsms;
56 std::unique_ptr<SBSMSInterface> iface;
58
59 // Not required by callbacks, but makes for easier cleanup
60 std::unique_ptr<Resampler> resampler;
61 std::unique_ptr<SBSMSQuality> quality;
62 std::shared_ptr<WaveTrack> outputLeftTrack;
63 std::shared_ptr<WaveTrack> outputRightTrack;
64
65 std::exception_ptr mpException {};
66};
67
68class SBSMSEffectInterface final : public SBSMSInterfaceSliding {
69public:
71 Slide *rateSlide, Slide *pitchSlide,
72 bool bReferenceInput,
73 const SampleCountType samples, long preSamples,
74 SBSMSQuality *quality)
75 : SBSMSInterfaceSliding(rateSlide,pitchSlide,bReferenceInput,samples,preSamples,quality)
76 {
77 this->resampler = resampler;
78 }
80
81 long samples(audio *buf, long n) {
82 return resampler->read(buf, n);
83 }
84
85protected:
86 Resampler *resampler;
87};
88
89long resampleCB(void *cb_data, SBSMSFrame *data)
90{
91 ResampleBuf *r = (ResampleBuf*) cb_data;
92
93 auto blockSize = limitSampleBufferSize(
95 r->end - r->offset
96 );
97
98 // Get the samples from the tracks and put them in the buffers.
99 // I don't know if we can safely propagate errors through sbsms, and it
100 // does not seem to let us report error codes, so use this roundabout to
101 // stop the effect early.
102 try {
104 (r->leftBuffer.get()), r->offset, blockSize);
106 (r->rightBuffer.get()), r->offset, blockSize);
107 }
108 catch ( ... ) {
109 // Save the exception object for re-throw when out of the library
110 r->mpException = std::current_exception();
111 data->size = 0;
112 return 0;
113 }
114
115 // convert to sbsms audio format
116 for(decltype(blockSize) i=0; i<blockSize; i++) {
117 r->buf[i][0] = r->leftBuffer[i];
118 r->buf[i][1] = r->rightBuffer[i];
119 }
120
121 data->buf = r->buf.get();
122 data->size = blockSize;
123 if(r->bPitch) {
124 float t0 = r->processed.as_float() / r->iface->getSamplesToInput();
125 float t1 = (r->processed + blockSize).as_float() / r->iface->getSamplesToInput();
126 data->ratio0 = r->iface->getStretch(t0);
127 data->ratio1 = r->iface->getStretch(t1);
128 } else {
129 data->ratio0 = r->ratio;
130 data->ratio1 = r->ratio;
131 }
132 r->processed += blockSize;
133 r->offset += blockSize;
134 return blockSize;
135}
136
137long postResampleCB(void *cb_data, SBSMSFrame *data)
138{
139 ResampleBuf *r = (ResampleBuf*) cb_data;
140 auto count = r->sbsms->read(r->iface.get(), r->SBSMSBuf.get(), r->SBSMSBlockSize);
141 data->buf = r->SBSMSBuf.get();
142 data->size = count;
143 data->ratio0 = 1.0 / r->ratio;
144 data->ratio1 = 1.0 / r->ratio;
145 return count;
146}
147
148void EffectSBSMS :: setParameters(double rateStartIn, double rateEndIn, double pitchStartIn, double pitchEndIn,
149 SlideType rateSlideTypeIn, SlideType pitchSlideTypeIn,
150 bool bLinkRatePitchIn, bool bRateReferenceInputIn, bool bPitchReferenceInputIn)
151{
152 this->rateStart = rateStartIn;
153 this->rateEnd = rateEndIn;
154 this->pitchStart = pitchStartIn;
155 this->pitchEnd = pitchEndIn;
156 this->bLinkRatePitch = bLinkRatePitchIn;
157 this->rateSlideType = rateSlideTypeIn;
158 this->pitchSlideType = pitchSlideTypeIn;
159 this->bRateReferenceInput = bRateReferenceInputIn;
160 this->bPitchReferenceInput = bPitchReferenceInputIn;
161}
162
163void EffectSBSMS::setParameters(double tempoRatio, double pitchRatio)
164{
165 setParameters(tempoRatio, tempoRatio, pitchRatio, pitchRatio,
166 SlideConstant, SlideConstant, false, false, false);
167}
168
169std::unique_ptr<TimeWarper> createTimeWarper(double t0, double t1, double duration,
170 double rateStart, double rateEnd, SlideType rateSlideType)
171{
172 std::unique_ptr<TimeWarper> warper;
173 if (rateStart == rateEnd || rateSlideType == SlideConstant) {
174 warper = std::make_unique<LinearTimeWarper>(t0, t0, t1, t0+duration);
175 } else if(rateSlideType == SlideLinearInputRate) {
176 warper = std::make_unique<LinearInputRateTimeWarper>(t0, t1, rateStart, rateEnd);
177 } else if(rateSlideType == SlideLinearOutputRate) {
178 warper = std::make_unique<LinearOutputRateTimeWarper>(t0, t1, rateStart, rateEnd);
179 } else if(rateSlideType == SlideLinearInputStretch) {
180 warper = std::make_unique<LinearInputStretchTimeWarper>(t0, t1, rateStart, rateEnd);
181 } else if(rateSlideType == SlideLinearOutputStretch) {
182 warper = std::make_unique<LinearOutputStretchTimeWarper>(t0, t1, rateStart, rateEnd);
183 } else if(rateSlideType == SlideGeometricInput) {
184 warper = std::make_unique<GeometricInputTimeWarper>(t0, t1, rateStart, rateEnd);
185 } else if(rateSlideType == SlideGeometricOutput) {
186 warper = std::make_unique<GeometricOutputTimeWarper>(t0, t1, rateStart, rateEnd);
187 }
188 return warper;
189}
190
191// Labels inside the affected region are moved to match the audio; labels after
192// it are shifted along appropriately.
194{
196 RegionTimeWarper warper{ mT0, mT1, std::move(warper1) };
197 lt->WarpLabels(warper);
198 return true;
199}
200
201double EffectSBSMS::getInvertedStretchedTime(double rateStart, double rateEnd, SlideType slideType, double outputTime)
202{
203 Slide slide(slideType,rateStart,rateEnd,0);
204 return slide.getInverseStretchedTime(outputTime);
205}
206
207double EffectSBSMS::getRate(double rateStart, double rateEnd, SlideType slideType, double t)
208{
209 Slide slide(slideType,rateStart,rateEnd,0);
210 return slide.getRate(t);
211}
212
214{
215 bool bGoodResult = true;
216
217 //Iterate over each track
218 //all needed because this effect needs to introduce silence in the group tracks to keep sync
219 this->CopyInputTracks(true); // Set up mOutputTracks.
220 mCurTrackNum = 0;
221
222 double maxDuration = 0.0;
223
224 // Must sync if selection length will change
225 bool mustSync = (rateStart != rateEnd);
226 Slide rateSlide(rateSlideType,rateStart,rateEnd);
227 Slide pitchSlide(pitchSlideType,pitchStart,pitchEnd);
228 mTotalStretch = rateSlide.getTotalStretch();
229
230 mOutputTracks->Leaders().VisitWhile( bGoodResult,
231 [&](LabelTrack *lt, const Track::Fallthrough &fallthrough) {
232 if (!(lt->GetSelected() ||
233 (mustSync && SyncLock::IsSyncLockSelected(lt))))
234 return fallthrough();
235 if (!ProcessLabelTrack(lt))
236 bGoodResult = false;
237 },
238 [&](WaveTrack *leftTrack, const Track::Fallthrough &fallthrough) {
239 if (!leftTrack->GetSelected())
240 return fallthrough();
241
242 //Get start and end times from selection
243 mCurT0 = mT0;
244 mCurT1 = mT1;
245
246 //Set the current bounds to whichever left marker is
247 //greater and whichever right marker is less
248 mCurT0 = wxMax(mT0, mCurT0);
249 mCurT1 = wxMin(mT1, mCurT1);
250
251 // Process only if the right marker is to the right of the left marker
252 if (mCurT1 > mCurT0) {
253 auto start = leftTrack->TimeToLongSamples(mCurT0);
254 auto end = leftTrack->TimeToLongSamples(mCurT1);
255
256 // TODO: more-than-two-channels
257 auto channels = TrackList::Channels(leftTrack);
258 WaveTrack *rightTrack = (channels.size() > 1)
259 ? * ++ channels.first
260 : nullptr;
261 if (rightTrack) {
262 double t;
263
264 //Adjust bounds by the right tracks markers
265 t = rightTrack->GetStartTime();
266 t = wxMax(mT0, t);
267 mCurT0 = wxMin(mCurT0, t);
268 t = rightTrack->GetEndTime();
269 t = wxMin(mT1, t);
270 mCurT1 = wxMax(mCurT1, t);
271
272 //Transform the marker timepoints to samples
273 start = leftTrack->TimeToLongSamples(mCurT0);
274 end = leftTrack->TimeToLongSamples(mCurT1);
275
276 mCurTrackNum++; // Increment for rightTrack, too.
277 }
278
279 // SBSMS has a fixed sample rate - we just convert to its sample rate and then convert back
280 float srTrack = leftTrack->GetRate();
281 float srProcess = bLinkRatePitch ? srTrack : 44100.0;
282
283 // the resampler needs a callback to supply its samples
284 ResampleBuf rb;
285 auto maxBlockSize = leftTrack->GetMaxBlockSize();
286 rb.blockSize = maxBlockSize;
287 rb.buf.reinit(rb.blockSize, true);
288 rb.leftTrack = leftTrack;
289 rb.rightTrack = rightTrack?rightTrack:leftTrack;
290 rb.leftBuffer.reinit(maxBlockSize, true);
291 rb.rightBuffer.reinit(maxBlockSize, true);
292
293 // Samples in selection
294 auto samplesIn = end - start;
295
296 // Samples for SBSMS to process after resampling
297 auto samplesToProcess = (sampleCount) (samplesIn.as_float() * (srProcess/srTrack));
298
299 SlideType outSlideType;
300 SBSMSResampleCB outResampleCB;
301
302 if(bLinkRatePitch) {
303 rb.bPitch = true;
304 outSlideType = rateSlideType;
305 outResampleCB = resampleCB;
306 rb.offset = start;
307 rb.end = end;
308 // Third party library has its own type alias, check it
309 static_assert(sizeof(sampleCount::type) <=
310 sizeof(_sbsms_::SampleCountType),
311 "Type _sbsms_::SampleCountType is too narrow to hold a sampleCount");
312 rb.iface = std::make_unique<SBSMSInterfaceSliding>
313 (&rateSlide, &pitchSlide, bPitchReferenceInput,
314 static_cast<_sbsms_::SampleCountType>
315 ( samplesToProcess.as_long_long() ),
316 0, nullptr);
317
318 }
319 else {
320 rb.bPitch = false;
321 outSlideType = (srProcess==srTrack?SlideIdentity:SlideConstant);
322 outResampleCB = postResampleCB;
323 rb.ratio = srProcess/srTrack;
324 rb.quality = std::make_unique<SBSMSQuality>(&SBSMSQualityStandard);
325 rb.resampler = std::make_unique<Resampler>(resampleCB, &rb, srProcess==srTrack?SlideIdentity:SlideConstant);
326 rb.sbsms = std::make_unique<SBSMS>(rightTrack ? 2 : 1, rb.quality.get(), true);
327 rb.SBSMSBlockSize = rb.sbsms->getInputFrameSize();
328 rb.SBSMSBuf.reinit(static_cast<size_t>(rb.SBSMSBlockSize), true);
329 rb.offset = start;
330 rb.end = end;
331 rb.iface = std::make_unique<SBSMSEffectInterface>
332 (rb.resampler.get(), &rateSlide, &pitchSlide,
334 static_cast<_sbsms_::SampleCountType>( samplesToProcess.as_long_long() ),
335 0,
336 rb.quality.get());
337 }
338
339 Resampler resampler(outResampleCB,&rb,outSlideType);
340
341 audio outBuf[SBSMSOutBlockSize];
342 float outBufLeft[2*SBSMSOutBlockSize];
343 float outBufRight[2*SBSMSOutBlockSize];
344
345 // Samples in output after SBSMS
346 sampleCount samplesToOutput = rb.iface->getSamplesToOutput();
347
348 // Samples in output after resampling back
349 auto samplesOut = (sampleCount) (samplesToOutput.as_float() * (srTrack/srProcess));
350
351 // Duration in track time
352 double duration = (mCurT1-mCurT0) * mTotalStretch;
353
354 if(duration > maxDuration)
355 maxDuration = duration;
356
357 auto warper = createTimeWarper(mCurT0,mCurT1,maxDuration,rateStart,rateEnd,rateSlideType);
358
359 rb.outputLeftTrack = leftTrack->EmptyCopy();
360 if(rightTrack)
361 rb.outputRightTrack = rightTrack->EmptyCopy();
362
363 long pos = 0;
364 long outputCount = -1;
365
366 // process
367 while(pos<samplesOut && outputCount) {
368 const auto frames =
369 limitSampleBufferSize( SBSMSOutBlockSize, samplesOut - pos );
370
371 outputCount = resampler.read(outBuf,frames);
372 for(int i = 0; i < outputCount; i++) {
373 outBufLeft[i] = outBuf[i][0];
374 if(rightTrack)
375 outBufRight[i] = outBuf[i][1];
376 }
377 pos += outputCount;
378 rb.outputLeftTrack->Append((samplePtr)outBufLeft, floatSample, outputCount);
379 if(rightTrack)
380 rb.outputRightTrack->Append((samplePtr)outBufRight, floatSample, outputCount);
381
382 double frac = (double)pos / samplesOut.as_double();
383 int nWhichTrack = mCurTrackNum;
384 if(rightTrack) {
385 nWhichTrack = 2*(mCurTrackNum/2);
386 if (frac < 0.5)
387 frac *= 2.0; // Show twice as far for each track, because we're doing 2 at once.
388 else {
389 nWhichTrack++;
390 frac -= 0.5;
391 frac *= 2.0; // Show twice as far for each track, because we're doing 2 at once.
392 }
393 }
394 if (TrackProgress(nWhichTrack, frac)) {
395 bGoodResult = false;
396 return;
397 }
398 }
399
400 {
401 auto pException = rb.mpException;
402 rb.mpException = {};
403 if (pException)
404 std::rethrow_exception(pException);
405 }
406
407 rb.outputLeftTrack->Flush();
408 if(rightTrack)
409 rb.outputRightTrack->Flush();
410
411 Finalize(leftTrack, rb.outputLeftTrack.get(), warper.get());
412 if(rightTrack)
413 Finalize(rightTrack, rb.outputRightTrack.get(), warper.get());
414 }
415 mCurTrackNum++;
416 },
417 [&](Track *t) {
418 if (mustSync && SyncLock::IsSyncLockSelected(t))
419 {
420 t->SyncLockAdjust(mCurT1, mCurT0 + (mCurT1 - mCurT0) * mTotalStretch);
421 }
422 }
423 );
424
425 if (bGoodResult) {
426 ReplaceProcessedTracks(bGoodResult);
427 }
428
429 return bGoodResult;
430}
431
432void EffectSBSMS::Finalize(WaveTrack* orig, WaveTrack* out, const TimeWarper *warper)
433{
434 // Silenced samples will be inserted in gaps between clips, so capture where these
435 // gaps are for later deletion
436 std::vector<std::pair<double, double>> gaps;
437 double last = mCurT0;
438 auto clips = orig->SortedClipArray();
439 auto front = clips.front();
440 auto back = clips.back();
441 for (auto &clip : clips) {
442 auto st = clip->GetPlayStartTime();
443 auto et = clip->GetPlayEndTime();
444
445 if (st >= mCurT0 || et < mCurT1) {
446 if (mCurT0 < st && clip == front) {
447 gaps.push_back(std::make_pair(mCurT0, st));
448 }
449 else if (last < st && mCurT0 <= last ) {
450 gaps.push_back(std::make_pair(last, st));
451 }
452
453 if (et < mCurT1 && clip == back) {
454 gaps.push_back(std::make_pair(et, mCurT1));
455 }
456 }
457 last = et;
458 }
459
460 // Take the output track and insert it in place of the original sample data
461 orig->ClearAndPaste(mCurT0, mCurT1, out, true, true, warper);
462
463 // Finally, recreate the gaps
464 for (auto gap : gaps) {
465 auto st = orig->LongSamplesToTime(orig->TimeToLongSamples(gap.first));
466 auto et = orig->LongSamplesToTime(orig->TimeToLongSamples(gap.second));
467 if (st >= mCurT0 && et <= mCurT1 && st != et)
468 {
469 orig->SplitDelete(warper->Warp(st), warper->Warp(et));
470 }
471 }
472}
473
474#endif
static const int gap
Definition: MeterPanel.cpp:259
std::unique_ptr< TimeWarper > createTimeWarper(double t0, double t1, double duration, double rateStart, double rateEnd, SlideType rateSlideType)
@ SBSMSOutBlockSize
Definition: SBSMSEffect.cpp:28
long postResampleCB(void *cb_data, SBSMSFrame *data)
long resampleCB(void *cb_data, SBSMSFrame *data)
Definition: SBSMSEffect.cpp:89
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: SampleCount.cpp:23
@ floatSample
Definition: SampleFormat.h:34
char * samplePtr
Definition: SampleFormat.h:49
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper,...
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:57
double mT1
Definition: EffectBase.h:107
std::shared_ptr< TrackList > mOutputTracks
Definition: EffectBase.h:105
double mT0
Definition: EffectBase.h:106
void ReplaceProcessedTracks(const bool bGoodResult)
Definition: EffectBase.cpp:236
void CopyInputTracks(bool allSyncLockSelected=false)
Definition: Effect.cpp:741
bool TrackProgress(int whichTrack, double frac, const TranslatableString &={}) const
Definition: Effect.cpp:693
Performs effect computation.
SlideType rateSlideType
Definition: SBSMSEffect.h:53
bool bLinkRatePitch
Definition: SBSMSEffect.h:52
void setParameters(double rateStart, double rateEnd, double pitchStart, double pitchEnd, SlideType rateSlideType, SlideType pitchSlideType, bool bLinkRatePitch, bool bRateReferenceInput, bool bPitchReferenceInput)
double pitchStart
Definition: SBSMSEffect.h:51
bool ProcessLabelTrack(LabelTrack *track)
double mCurT0
Definition: SBSMSEffect.h:56
double mCurT1
Definition: SBSMSEffect.h:57
int mCurTrackNum
Definition: SBSMSEffect.h:55
bool bPitchReferenceInput
Definition: SBSMSEffect.h:52
float mTotalStretch
Definition: SBSMSEffect.h:58
static double getInvertedStretchedTime(double rateStart, double rateEnd, SlideType slideType, double outputTime)
double rateStart
Definition: SBSMSEffect.h:51
SlideType pitchSlideType
Definition: SBSMSEffect.h:54
void Finalize(WaveTrack *orig, WaveTrack *out, const TimeWarper *warper)
double pitchEnd
Definition: SBSMSEffect.h:51
bool bRateReferenceInput
Definition: SBSMSEffect.h:52
double rateEnd
Definition: SBSMSEffect.h:51
bool Process(EffectInstance &instance, EffectSettings &settings) override
Actually do the effect here.
static double getRate(double rateStart, double rateEnd, SlideType slideType, double t)
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:89
void WarpLabels(const TimeWarper &warper)
Definition: LabelTrack.cpp:287
No change before the specified region; during the region, warp according to the given warper; after t...
Definition: TimeWarper.h:192
ArrayOf< audio > SBSMSBuf
Definition: SBSMSEffect.cpp:57
sampleCount offset
Definition: SBSMSEffect.cpp:49
std::shared_ptr< WaveTrack > outputRightTrack
Definition: SBSMSEffect.cpp:63
std::unique_ptr< SBSMSInterface > iface
Definition: SBSMSEffect.cpp:56
ArrayOf< audio > buf
Definition: SBSMSEffect.cpp:44
WaveTrack * rightTrack
Definition: SBSMSEffect.cpp:54
ArrayOf< float > leftBuffer
Definition: SBSMSEffect.cpp:51
long SBSMSBlockSize
Definition: SBSMSEffect.cpp:48
std::unique_ptr< SBSMSQuality > quality
Definition: SBSMSEffect.cpp:61
sampleCount processed
Definition: SBSMSEffect.cpp:46
std::shared_ptr< WaveTrack > outputLeftTrack
Definition: SBSMSEffect.cpp:62
std::exception_ptr mpException
Definition: SBSMSEffect.cpp:65
ArrayOf< float > rightBuffer
Definition: SBSMSEffect.cpp:52
double ratio
Definition: SBSMSEffect.cpp:45
std::unique_ptr< SBSMS > sbsms
Definition: SBSMSEffect.cpp:55
std::unique_ptr< Resampler > resampler
Definition: SBSMSEffect.cpp:60
size_t blockSize
Definition: SBSMSEffect.cpp:47
sampleCount end
Definition: SBSMSEffect.cpp:50
WaveTrack * leftTrack
Definition: SBSMSEffect.cpp:53
long samples(audio *buf, long n)
Definition: SBSMSEffect.cpp:81
Resampler * resampler
Definition: SBSMSEffect.cpp:86
virtual ~SBSMSEffectInterface()
Definition: SBSMSEffect.cpp:79
SBSMSEffectInterface(Resampler *resampler, Slide *rateSlide, Slide *pitchSlide, bool bReferenceInput, const SampleCountType samples, long preSamples, SBSMSQuality *quality)
Definition: SBSMSEffect.cpp:70
bool GetFloats(float *buffer, sampleCount start, size_t len, fillFormat fill=fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const
Retrieve samples from a track in floating-point format, regardless of the storage format.
Definition: SampleTrack.h:67
double LongSamplesToTime(sampleCount pos) const
Convert correctly between a number of samples and an (absolute) time in seconds.
Definition: SampleTrack.cpp:47
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: SampleTrack.cpp:42
static bool IsSyncLockSelected(const Track *pTrack)
Definition: SyncLock.cpp:43
Transforms one point in time to another point. For example, a time stretching effect might use one to...
Definition: TimeWarper.h:62
virtual double Warp(double originalTime) const =0
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:225
bool GetSelected() const
Definition: Track.h:469
Continuation<> Fallthrough
Type of arguments passed as optional second parameter to TypeSwitch<void>() cases.
Definition: Track.h:541
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1539
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
void SplitDelete(double t0, double t1)
Definition: WaveTrack.cpp:1165
double GetStartTime() const override
Get the time at which the first clip in the track starts.
Definition: WaveTrack.cpp:1995
size_t GetMaxBlockSize() const override
This returns a nonnegative number of samples meant to size a memory buffer.
Definition: WaveTrack.cpp:1806
size_t GetBestBlockSize(sampleCount t) const override
This returns a nonnegative number of samples meant to size a memory buffer.
Definition: WaveTrack.cpp:1788
WaveClipPointers SortedClipArray()
Definition: WaveTrack.cpp:2723
double GetEndTime() const override
Get the time at which the last clip in the track ends, plus recorded stuff.
Definition: WaveTrack.cpp:2015
double GetRate() const override
Definition: WaveTrack.cpp:479
void ClearAndPaste(double t0, double t1, const Track *src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=NULL)
Definition: WaveTrack.cpp:915
Holder EmptyCopy(const SampleBlockFactoryPtr &pFactory={}, bool keepLink=true) const
Definition: WaveTrack.cpp:705
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
long long type
Definition: SampleCount.h:20
float as_float() const
Definition: SampleCount.h:44
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
Externalized state of a plug-in.