49 pSequence = std::make_unique<Sequence>(
factory,
52 mEnvelope = std::make_unique<Envelope>(
true, 1e-7, 2.0, 1.0);
59 : mClipStretchRatio { orig.mClipStretchRatio }
60 , mRawAudioTempo { orig.mRawAudioTempo }
61 , mProjectTempo { orig.mProjectTempo }
75 std::make_unique<Sequence>(*pSequence,
factory));
93 bool copyCutlines,
double t0,
double t1)
94 : mClipStretchRatio { orig.mClipStretchRatio }
95 , mRawAudioTempo { orig.mRawAudioTempo }
96 , mProjectTempo { orig.mProjectTempo }
127 std::make_unique<Sequence>(*pSequence,
factory));
132 for (
const auto &cutline : orig.
mCutLines)
134 std::make_shared<WaveClip>(*cutline,
factory,
true));
146 size_t ii,
sampleCount start,
size_t length,
bool mayThrow)
const
154 size_t iChannel,
double t0,
double t1,
bool mayThrow)
const
170 sampleCount start,
size_t len,
bool mayThrow)
const
178 sampleCount start,
size_t len,
bool mayThrow)
const
181 for (
size_t ii = 0, width =
GetWidth(); result && ii < width; ++ii)
201 double t,
size_t iChannel,
float& value,
bool mayThrow)
const
212 double t,
size_t iChannel,
const float* buffer,
size_t numFloats,
216 const auto maybeOutOfBoundEnd = maybeNegativeStart + numFloats;
217 const auto effectiveStart = std::max(
sampleCount { 0 }, maybeNegativeStart);
218 const auto effectiveEnd =
220 if (effectiveStart >= effectiveEnd)
223 const auto effectiveLen = (effectiveEnd - effectiveStart).as_size_t();
225 const auto numLeadingZeros =
226 (effectiveStart - maybeNegativeStart).as_size_t();
227 const auto offsetBuffer =
228 reinterpret_cast<const char*
>(buffer + numLeadingZeros);
235 double t,
size_t iChannel,
const float* buffer,
size_t numSideSamples,
240 2 * numSideSamples + 1, effectiveFormat);
273 const std::optional<double>& oldTempo,
double newTempo)
282 if (oldTempo.has_value())
284 const auto ratioChange = *oldTempo / newTempo;
300 const auto newPlayDuration = pet - to;
301 const auto ratioChange = newPlayDuration / oldPlayDuration;
317 const auto newPlayDuration = to - pst;
318 const auto ratioChange = newPlayDuration / oldPlayDuration;
332 cutline->mSequenceOffset *= ratioChange;
333 cutline->mTrimLeft *= ratioChange;
334 cutline->mTrimRight *= ratioChange;
335 cutline->mClipStretchRatio *= ratioChange;
336 cutline->mEnvelope->RescaleTimesBy(ratioChange);
342 const auto dstSrcRatio =
383 newSequences.push_back(std::make_unique<Sequence>(
384 pSequence->GetFactory(), pSequence->GetSampleFormats()));
400 double t0,
double t1,
bool mayThrow)
const
420 return mSequences[ii]->GetMinMax(s0, s1 - s0, mayThrow);
438 return mSequences[ii]->GetRMS(s0, s1-s0, mayThrow);
442 const std::function<
void(
size_t)> & progressReport)
449 auto bChanged =
mSequences[0]->ConvertToSampleFormat(
format, progressReport);
450 for (
size_t ii = 1, width =
GetWidth(); ii < width; ++ii) {
454 assert(bChanged == alsoChanged);
459 transaction.Commit();
472std::shared_ptr<SampleBlock>
491 size_t len,
unsigned int stride,
sampleFormat effectiveFormat)
500 bool appended =
false;
503 pSequence->Append(buffers[ii++],
format, len, stride, effectiveFormat)
539 if (tag ==
"waveclip")
543 for (
auto pair : attrs)
545 auto attr = pair.first;
546 auto value = pair.second;
548 if (attr ==
"offset")
550 if (!value.TryGet(dblValue))
554 else if (attr ==
"trimLeft")
556 if (!value.TryGet(dblValue))
560 else if (attr ==
"trimRight")
562 if (!value.TryGet(dblValue))
566 else if (attr ==
"rawAudioTempo")
568 if (!value.TryGet(dblValue))
575 else if (attr ==
"clipStretchRatio")
577 if (!value.TryGet(dblValue))
581 else if (attr ==
"name")
583 if(value.IsStringView())
586 else if (attr ==
"colorindex")
588 if (!value.TryGet(longValue))
605 if (tag ==
"waveclip")
616 if (tag ==
"sequence") {
617 mSequences.push_back(std::make_unique<Sequence>(
618 pFirst->GetFactory(), pFirst->GetSampleFormats()));
621 else if (tag ==
"envelope")
623 else if (tag ==
"waveclip")
626 auto format = pFirst->GetSampleFormats().Stored();
631 std::make_shared<WaveClip>(
634 1, pFirst->GetFactory(),
645 if (GetSequenceSamplesCount() <= 0)
650 xmlFile.StartTag(
wxT(
"waveclip"));
651 xmlFile.WriteAttr(
wxT(
"offset"), mSequenceOffset, 8);
652 xmlFile.WriteAttr(
wxT(
"trimLeft"), mTrimLeft, 8);
653 xmlFile.WriteAttr(
wxT(
"trimRight"), mTrimRight, 8);
654 xmlFile.WriteAttr(
wxT(
"rawAudioTempo"), mRawAudioTempo.value_or(0.), 8);
655 xmlFile.WriteAttr(
wxT(
"clipStretchRatio"), mClipStretchRatio, 8);
656 xmlFile.WriteAttr(
wxT(
"name"), mName);
657 xmlFile.WriteAttr(
wxT(
"colorindex"), mColourIndex );
659 for (
auto &pSequence : mSequences)
660 pSequence->WriteXML(xmlFile);
661 mEnvelope->WriteXML(xmlFile);
663 for (
const auto &clip: mCutLines)
664 clip->WriteXML(xmlFile);
666 xmlFile.EndTag(
wxT(
"waveclip"));
689 const bool clipNeedsResampling = other.
mRate !=
mRate;
690 const bool clipNeedsNewFormat =
692 std::shared_ptr<WaveClip> newClip;
703 auto copy = std::make_shared<WaveClip>(other,
factory,
true);
704 copy->ClearSequence(
copy->GetPlayEndTime(),
copy->GetSequenceEndTime());
705 newClip = std::move(
copy);
712 auto copy = std::make_shared<WaveClip>(other,
factory,
true);
713 copy->ClearSequence(
copy->GetSequenceStartTime(),
copy->GetPlayStartTime());
714 newClip = std::move(
copy);
718 newClip = std::make_shared<WaveClip>(other,
factory,
true);
719 newClip->ClearSequence(newClip->GetPlayEndTime(), newClip->GetSequenceEndTime());
720 newClip->ClearSequence(newClip->GetSequenceStartTime(), newClip->GetPlayStartTime());
721 newClip->SetTrimLeft(0);
722 newClip->SetTrimRight(0);
725 if (clipNeedsResampling || clipNeedsNewFormat)
727 auto copy = std::make_shared<WaveClip>(*newClip.get(),
factory,
true);
729 if (clipNeedsResampling)
733 if (clipNeedsNewFormat)
736 newClip = std::move(
copy);
741 for (
const auto &cutline: newClip->mCutLines)
743 auto cutlineCopy = std::make_shared<WaveClip>(*cutline,
factory,
748 newCutlines.push_back(std::move(cutlineCopy));
754 assert(other.
GetWidth() == newClip->GetWidth());
757 for (
size_t ii = 0, width =
GetWidth(); ii < width; ++ii)
760 transaction.Commit();
764 const auto sampleTime = 1.0 /
GetRate();
765 const auto timeOffsetInEnvelope =
768 timeOffsetInEnvelope, newClip->mEnvelope.get(), sampleTime);
769 OffsetCutLines(t0, newClip->GetPlayEndTime() - newClip->GetPlayStartTime());
771 for (
auto &holder : newCutlines)
794 pSequence->InsertSilence(s0, slen);
796 transaction.Commit();
801 const auto sampleTime = 1.0 /
GetRate();
803 if ( pEnvelopeValue ) {
806 auto oldLen = pEnvelope->GetTrackLen();
807 auto newLen = oldLen + len;
808 pEnvelope->Cap( sampleTime );
811 pEnvelope->SetTrackLen( newLen, sampleTime );
812 pEnvelope->InsertOrReplace
813 ( pEnvelope->GetOffset() + newLen, *pEnvelopeValue );
816 pEnvelope->InsertSpace( t, len );
885 pSequence->Delete(s0, s1 - s0);
907 if (cutlinePosition >= t0 && cutlinePosition <= t1)
914 if (cutlinePosition >= t1)
916 clip->
ShiftBy(clip_t0 - clip_t1);
923 auto sampleTime = 1.0 /
GetRate();
927 transaction.Commit();
944 auto newClip = std::make_shared<WaveClip>(
948 newClip->ClearSequence(t1, newClip->GetSequenceEndTime());
949 newClip->SetTrimRight(.0);
953 newClip->ClearSequence(newClip->GetSequenceStartTime(), t0);
954 newClip->SetTrimLeft(.0);
966 if (cutlinePosition >= t0 && cutlinePosition <= t1)
970 if (cutlinePosition >= t1)
972 clip->
ShiftBy(clip_t0 - clip_t1);
984 pSequence->Delete(s0, s1-s0);
987 auto sampleTime = 1.0 /
GetRate();
990 transaction.Commit();
1000 double* cutlineStart ,
1001 double* cutlineEnd )
const
1009 *cutlineStart = startTime;
1011 *cutlineEnd = startTime + cutline->SamplesToTime(cutline->GetVisibleSampleCount());
1025 return fabs(GetSequenceStartTime() + cutline->GetSequenceStartTime() - cutLinePosition) < 0.0001;
1029 auto *cutline = it->get();
1034 cutline->mEnvelope->SetOffset(0);
1035 bool success =
Paste(
1058 const auto &cutline = *it;
1076 cutLine->ShiftBy(len);
1084 pSequence->CloseLock();
1086 cutline->CloseLock();
1093 auto ratio =
static_cast<double>(
mRate) / rate;
1097 const auto newLength =
1115 double factor = (double)rate / (
double)
mRate;
1118 const size_t bufsize = 65536;
1119 Floats inBuffer{ bufsize };
1120 Floats outBuffer{ bufsize };
1123 int outGenerated = 0;
1134 while (pos < numSamples || outGenerated > 0) {
1137 bool isLast = ((pos + inLen) == numSamples);
1139 auto ppNewSequence = newSequences.begin();
1140 std::optional<std::pair<size_t, size_t>> results{};
1142 auto &pNewSequence = *ppNewSequence++;
1150 auto newResults = resample.
Process(factor, inBuffer.get(), inLen,
1151 isLast, outBuffer.get(), bufsize);
1153 results.emplace(newResults);
1154 else if (*results != newResults) {
1159 outGenerated = results->second;
1160 if (outGenerated < 0) {
1171 pos += results->first;
1175 auto updateResult = progress->
Poll(
1177 numSamples.as_long_long()
1188 XO(
"Resampling failed."),
1214 return fabs(startNext - endThis) < 0.5;
1234 return s.as_double() * GetStretchRatio() / mRate;
1247 pSequence->SetSilence(start, length);
1376 SetSequenceStartTime(GetSequenceStartTime() + delta);
1462 auto &pFirst = *iter++;
1467 std::all_of(iter,
end, [&](
decltype(pFirst) pSequence) {
1469 pSequence->GetNumSamples() == pFirst->GetNumSamples() &&
1470 pSequence->GetAppendBufferLen() == pFirst->GetAppendBufferLen()
1472 pSequence->GetSampleFormats() == pFirst->GetSampleFormats() &&
1473 pSequence->GetFactory() == pFirst->GetFactory();
1478 return pCutLine && pCutLine->GetWidth() == width &&
1479 pCutLine->CheckInvariants();
1488 , mTrimLeft{ clip.mTrimLeft }
1489 , mTrimRight{ clip.mTrimRight }
1496 std::make_unique<Sequence>(*pSequence,
factory));
1502 clip.mSequences.swap(sequences);
@ Internal
Indicates internal failure from Audacity.
Toolkit-neutral facade for basic user interface services.
const TranslatableString name
MessageBoxException for violation of preconditions or assertions.
#define THROW_INCONSISTENCY_EXCEPTION
Throw InconsistencyException, using C++ preprocessor to identify the source code location.
std::shared_ptr< SampleBlockFactory > SampleBlockFactoryPtr
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
An AudacityException with no visible message.
std::shared_ptr< WaveClip > WaveClipHolder
std::vector< WaveClipHolder > WaveClipHolders
std::vector< Attribute > AttributesList
Abstraction of a progress dialog with well defined time-to-completion estimate.
virtual ProgressResult Poll(unsigned long long numerator, unsigned long long denominator, const TranslatableString &message={})=0
Update the bar and poll for clicks. Call only on the main thread.
void CollapseRegion(double t0, double t1, double sampleDur)
std::pair< size_t, size_t > Process(double factor, float *inBuffer, size_t inBufferLen, bool lastFlag, float *outBuffer, size_t outBufferLen)
Main processing function. Resamples from the input buffer to the output buffer.
A MessageBoxException that shows a given, unvarying string.
static bool IsPassThroughMode(double stretchRatio)
Can be thrown when user cancels operations, as with a progress dialog. Delayed handler does nothing.
This allows multiple clips to be a part of one WaveTrack.
bool WithinPlayRegion(double t) const
t ∈ [...)
std::optional< double > mRawAudioTempo
std::vector< std::unique_ptr< Sequence > > GetEmptySequenceCopies() const
bool Append(constSamplePtr buffers[], sampleFormat format, size_t len, unsigned int stride, sampleFormat effectiveFormat)
void ClearRight(double t)
bool CoversEntirePlayRegion(double t0, double t1) const
t0 <= [ and ) <= t1, such that removing [t0, t1) from the track deletes this clip.
double GetStretchRatio() const override
double GetSequenceStartTime() const noexcept
bool CheckInvariants() const
Check invariant conditions on mSequences and mCutlines.
void SetPlayStartTime(double time)
void SetSequenceStartTime(double startTime)
void SetEnvelope(std::unique_ptr< Envelope > p)
void CloseLock() noexcept
Should be called upon project close. Not balanced by unlocking calls.
void SetName(const wxString &name)
sampleCount TimeToSamples(double time) const override
bool RemoveCutLine(double cutLinePosition)
Remove cut line, without expanding the audio in it.
sampleCount TimeToSequenceSamples(double t) const
bool StretchRatioEquals(double value) const
void ShiftBy(double delta) noexcept
std::unique_ptr< Envelope > mEnvelope
Envelope is unique, not per-sequence.
sampleCount GetVisibleSampleCount() const override
double GetTrimRight() const noexcept
Returns the play end offset in seconds from the ending of the underlying sequence.
double GetPlayStartTime() const noexcept override
std::optional< double > mProjectTempo
bool AtOrBeforePlayRegion(double t) const
t <= [
int GetRate() const override
int mRate
Sample rate of the raw audio, i.e., before stretching.
double GetTrimLeft() const noexcept
Returns the play start offset in seconds from the beginning of the underlying sequence.
XMLTagHandler * HandleXMLChild(const std::string_view &tag) override
sampleCount CountSamples(double t0, double t1) const
sampleCount GetPlayEndSample() const
Real end time of the clip, quantized to raw sample rate (track's rate)
constSamplePtr GetAppendBuffer(size_t ii) const
Get one channel of the append buffer.
double GetPlayEndTime() const override
void SetFloatsFromTime(double t, size_t iChannel, const float *buffer, size_t numSamples, sampleFormat effectiveFormat)
Considers buffer as audio starting at TimeToSamples(t) (relative to clip play start time) and with eq...
const wxString & GetName() const
void Resample(int rate, BasicUI::ProgressDialog *progress=nullptr)
std::shared_ptr< SampleBlock > AppendNewBlock(constSamplePtr buffer, sampleFormat format, size_t len)
void TrimLeftTo(double to)
Sets the the left trimming to the absolute time (if that is in bounds)
bool FindCutLine(double cutLinePosition, double *cutLineStart=NULL, double *cutLineEnd=NULL) const
sampleCount GetPlayStartSample() const
Real start time of the clip, quantized to raw sample rate (track's rate)
void AppendSilence(double len, double envelopeValue)
SampleFormats GetSampleFormats() const
sampleCount GetSequenceStartSample() const
Returns the index of the first sample of the underlying sequence.
void OnProjectTempoChange(const std::optional< double > &oldTempo, double newTempo)
bool GetIsPlaceholder() const
void HandleXMLEndTag(const std::string_view &tag) override
void InsertSilence(double t, double len, double *pEnvelopeValue=nullptr)
bool HandleXMLTag(const std::string_view &tag, const AttributesList &attrs) override
void SetColourIndex(int index)
BlockArray * GetSequenceBlockArray(size_t ii)
void SetSilence(sampleCount offset, sampleCount length)
Silences the 'length' amount of samples starting from 'offset'(relative to the play start)
bool BeforePlayRegion(double t) const
t < [
void SetSamples(size_t ii, constSamplePtr buffer, sampleFormat format, sampleCount start, size_t len, sampleFormat effectiveFormat)
void TrimRightTo(double to)
Sets the the right trimming to the absolute time (if that is in bounds)
bool SplitsPlayRegion(double t) const
[ < t and t < ), such that if the track were split at t, it would split this clip in two of lengths >...
bool GetSamples(size_t ii, samplePtr buffer, sampleFormat format, sampleCount start, size_t len, bool mayThrow=true) const
Get samples from one channel.
bool SharesBoundaryWithNextClip(const WaveClip *next) const
void SetFloatsCenteredAroundTime(double t, size_t iChannel, const float *buffer, size_t numSideSamples, sampleFormat effectiveFormat)
Same as SetFloatsFromTime, but with buffer starting at TimeToSamples(t0 - SamplesToTime(numSideSample...
float GetRMS(size_t ii, double t0, double t1, bool mayThrow) const
double SnapToTrackSample(double time) const noexcept
void StretchRightTo(double to)
Sets from the right to the absolute time (if in expected range)
bool EntirelyWithinPlayRegion(double t0, double t1) const
t0 and t1 both ∈ [...)
void OffsetCutLines(double t0, double len)
Offset cutlines right to time 't0' by time amount 'len'.
void SetTrimRight(double trim)
Sets the play end offset in seconds from the ending of the underlying sequence.
std::pair< float, float > GetMinMax(size_t ii, double t0, double t1, bool mayThrow) const
void TrimRight(double deltaTime)
Moves play end position by deltaTime.
bool AfterPlayRegion(double t) const
) <= t
double SamplesToTime(sampleCount s) const noexcept
const SampleBlockFactoryPtr & GetFactory()
void WriteXML(XMLWriter &xmlFile) const
sampleCount GetSequenceSamplesCount() const
void ExpandCutLine(double cutLinePosition)
void AppendSharedBlock(const std::shared_ptr< SampleBlock > &pBlock)
void ConvertToSampleFormat(sampleFormat format, const std::function< void(size_t)> &progressReport={})
double GetPlayDuration() const
void ClearSequence(double t0, double t1)
bool HasEqualStretchRatio(const WaveClip &other) const
WaveClip(const WaveClip &)=delete
void SetFloatAtTime(double t, size_t iChannel, float value, sampleFormat effectiveFormat)
bool IntersectsPlayRegion(double t0, double t1) const
[t0, t1) ∩ [...) != ∅
AudioSegmentSampleView GetSampleView(size_t iChannel, sampleCount start, size_t length, bool mayThrow=true) const override
Request up to length samples. The actual number of samples available from the returned view is querie...
void ClearAndAddCutLine(double t0, double t1)
sampleCount GetNumSamples() const
WaveClipHolders mCutLines
void SetTrimLeft(double trim)
Sets the play start offset in seconds from the beginning of the underlying sequence.
double GetSequenceEndTime() const
void Clear(double t0, double t1)
bool Paste(double t0, const WaveClip &other)
void UpdateEnvelopeTrackLen()
void StretchCutLines(double ratioChange)
size_t GetAppendBufferLen() const
void StretchLeftTo(double to)
Stretches from left to the absolute time (if in expected range)
bool PartlyWithinPlayRegion(double t0, double t1) const
t0 xor t1 ∈ [...)
size_t GetWidth() const override
bool GetFloatAtTime(double t, size_t iChannel, float &value, bool mayThrow) const
void Flush()
Flush must be called after last Append.
std::vector< std::unique_ptr< Sequence > > mSequences
void TrimLeft(double deltaTime)
Moves play start position by deltaTime.
This class is an interface which should be implemented by classes which wish to be able to load and s...
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
Positions or offsets within audio files need a wide type.
long long as_long_long() const
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
static RegisteredToolbarFactory factory
fastfloat_really_inline void round(adjusted_mantissa &am, callback cb) noexcept
void copy(const T *src, T *dst, int32_t n)
"finally" as in The C++ Programming Language, 4th ed., p. 358 Useful for defining ad-hoc RAII actions...
Restores state when an update loop over mSequences fails midway.
std::vector< std::unique_ptr< Sequence > > sequences
Transaction(WaveClip &clip)
virtual void MarkChanged()=0
virtual ~WaveClipListener()=0
virtual void Invalidate()=0