49 pSequence = std::make_unique<Sequence>(
factory,
52 mEnvelope = std::make_unique<Envelope>(
true, 1e-7, 2.0, 1.0);
59 : mCentShift { orig.mCentShift }
60 , mPitchAndSpeedPreset { orig.mPitchAndSpeedPreset }
61 , mClipStretchRatio { orig.mClipStretchRatio }
62 , mRawAudioTempo { orig.mRawAudioTempo }
63 , mProjectTempo { orig.mProjectTempo }
77 std::make_unique<Sequence>(*pSequence,
factory));
95 bool copyCutlines,
double t0,
double t1)
96 : mCentShift { orig.mCentShift }
97 , mClipStretchRatio { orig.mClipStretchRatio }
98 , mRawAudioTempo { orig.mRawAudioTempo }
99 , mProjectTempo { orig.mProjectTempo }
130 std::make_unique<Sequence>(*pSequence,
factory));
135 for (
const auto &cutline : orig.
mCutLines)
137 std::make_shared<WaveClip>(*cutline,
factory,
true));
150 size_t ii,
sampleCount start,
size_t length,
bool mayThrow)
const
158 size_t iChannel,
double t0,
double t1,
bool mayThrow)
const
174 sampleCount start,
size_t len,
bool mayThrow)
const
182 sampleCount start,
size_t len,
bool mayThrow)
const
185 for (
size_t ii = 0, width =
GetWidth(); result && ii < width; ++ii)
205 double t,
size_t iChannel,
float& value,
bool mayThrow)
const
216 double t,
size_t iChannel,
const float* buffer,
size_t numFloats,
220 const auto maybeOutOfBoundEnd = maybeNegativeStart + numFloats;
221 const auto effectiveStart = std::max(
sampleCount { 0 }, maybeNegativeStart);
222 const auto effectiveEnd =
224 if (effectiveStart >= effectiveEnd)
227 const auto effectiveLen = (effectiveEnd - effectiveStart).as_size_t();
229 const auto numLeadingZeros =
230 (effectiveStart - maybeNegativeStart).as_size_t();
231 const auto offsetBuffer =
232 reinterpret_cast<const char*
>(buffer + numLeadingZeros);
239 double t,
size_t iChannel,
const float* buffer,
size_t numSideSamples,
244 2 * numSideSamples + 1, effectiveFormat);
277 const std::optional<double>& oldTempo,
double newTempo)
286 if (oldTempo.has_value())
288 const auto ratioChange = *oldTempo / newTempo;
306 const auto newPlayDuration = pet - to;
307 const auto ratioChange = newPlayDuration / oldPlayDuration;
325 const auto newPlayDuration = to - pst;
326 const auto ratioChange = newPlayDuration / oldPlayDuration;
348 cutline->mSequenceOffset *= ratioChange;
349 cutline->mTrimLeft *= ratioChange;
350 cutline->mTrimRight *= ratioChange;
351 cutline->mClipStretchRatio *= ratioChange;
352 cutline->mEnvelope->RescaleTimesBy(ratioChange);
358 const auto dstSrcRatio =
426 newSequences.push_back(std::make_unique<Sequence>(
427 pSequence->GetFactory(), pSequence->GetSampleFormats()));
443 double t0,
double t1,
bool mayThrow)
const
463 return mSequences[ii]->GetMinMax(s0, s1 - s0, mayThrow);
481 return mSequences[ii]->GetRMS(s0, s1-s0, mayThrow);
485 const std::function<
void(
size_t)> & progressReport)
492 auto bChanged =
mSequences[0]->ConvertToSampleFormat(
format, progressReport);
493 for (
size_t ii = 1, width =
GetWidth(); ii < width; ++ii) {
497 assert(bChanged == alsoChanged);
502 transaction.Commit();
515std::shared_ptr<SampleBlock>
534 size_t len,
unsigned int stride,
sampleFormat effectiveFormat)
544 bool appended =
false;
547 pSequence->Append(buffers[ii++],
format, len, stride, effectiveFormat)
582 if (tag ==
"waveclip")
586 for (
auto pair : attrs)
588 auto attr = pair.first;
589 auto value = pair.second;
591 if (attr ==
"offset")
593 if (!value.TryGet(dblValue))
597 else if (attr ==
"trimLeft")
599 if (!value.TryGet(dblValue))
603 else if (attr ==
"trimRight")
605 if (!value.TryGet(dblValue))
609 else if (attr ==
"centShift")
611 if (!value.TryGet(dblValue))
615 else if (attr ==
"pitchAndSpeedPreset")
617 if (!value.TryGet(longValue))
621 else if (attr ==
"rawAudioTempo")
623 if (!value.TryGet(dblValue))
630 else if (attr ==
"clipStretchRatio")
632 if (!value.TryGet(dblValue))
636 else if (attr ==
"name")
638 if(value.IsStringView())
641 else if (attr ==
"colorindex")
643 if (!value.TryGet(longValue))
660 if (tag ==
"waveclip")
671 if (tag ==
"sequence") {
672 mSequences.push_back(std::make_unique<Sequence>(
673 pFirst->GetFactory(), pFirst->GetSampleFormats()));
676 else if (tag ==
"envelope")
678 else if (tag ==
"waveclip")
681 auto format = pFirst->GetSampleFormats().Stored();
686 std::make_shared<WaveClip>(
689 1, pFirst->GetFactory(),
700 if (GetSequenceSamplesCount() <= 0)
705 xmlFile.StartTag(
wxT(
"waveclip"));
706 xmlFile.WriteAttr(
wxT(
"offset"), mSequenceOffset, 8);
707 xmlFile.WriteAttr(
wxT(
"trimLeft"), mTrimLeft, 8);
708 xmlFile.WriteAttr(
wxT(
"trimRight"), mTrimRight, 8);
709 xmlFile.WriteAttr(
wxT(
"centShift"), mCentShift);
711 wxT(
"pitchAndSpeedPreset"),
static_cast<long>(mPitchAndSpeedPreset));
712 xmlFile.WriteAttr(
wxT(
"rawAudioTempo"), mRawAudioTempo.value_or(0.), 8);
713 xmlFile.WriteAttr(
wxT(
"clipStretchRatio"), mClipStretchRatio, 8);
714 xmlFile.WriteAttr(
wxT(
"name"), mName);
715 xmlFile.WriteAttr(
wxT(
"colorindex"), mColourIndex );
717 for (
auto &pSequence : mSequences)
718 pSequence->WriteXML(xmlFile);
719 mEnvelope->WriteXML(xmlFile);
721 for (
const auto &clip: mCutLines)
722 clip->WriteXML(xmlFile);
724 xmlFile.EndTag(
wxT(
"waveclip"));
747 const bool clipNeedsResampling = other.
mRate !=
mRate;
748 const bool clipNeedsNewFormat =
750 std::shared_ptr<WaveClip> newClip;
761 auto copy = std::make_shared<WaveClip>(other,
factory,
true);
762 copy->ClearSequence(
copy->GetPlayEndTime(),
copy->GetSequenceEndTime());
763 newClip = std::move(
copy);
770 auto copy = std::make_shared<WaveClip>(other,
factory,
true);
771 copy->ClearSequence(
copy->GetSequenceStartTime(),
copy->GetPlayStartTime());
772 newClip = std::move(
copy);
776 newClip = std::make_shared<WaveClip>(other,
factory,
true);
777 newClip->ClearSequence(newClip->GetPlayEndTime(), newClip->GetSequenceEndTime());
778 newClip->ClearSequence(newClip->GetSequenceStartTime(), newClip->GetPlayStartTime());
779 newClip->SetTrimLeft(0);
780 newClip->SetTrimRight(0);
783 if (clipNeedsResampling || clipNeedsNewFormat)
785 auto copy = std::make_shared<WaveClip>(*newClip.get(),
factory,
true);
787 if (clipNeedsResampling)
791 if (clipNeedsNewFormat)
794 newClip = std::move(
copy);
799 for (
const auto &cutline: newClip->mCutLines)
801 auto cutlineCopy = std::make_shared<WaveClip>(*cutline,
factory,
806 newCutlines.push_back(std::move(cutlineCopy));
812 assert(other.
GetWidth() == newClip->GetWidth());
815 for (
size_t ii = 0, width =
GetWidth(); ii < width; ++ii)
818 transaction.Commit();
822 const auto sampleTime = 1.0 /
GetRate();
823 const auto timeOffsetInEnvelope =
826 timeOffsetInEnvelope, newClip->mEnvelope.get(), sampleTime);
827 OffsetCutLines(t0, newClip->GetPlayEndTime() - newClip->GetPlayStartTime());
829 for (
auto &holder : newCutlines)
852 pSequence->InsertSilence(s0, slen);
854 transaction.Commit();
859 const auto sampleTime = 1.0 /
GetRate();
861 if ( pEnvelopeValue ) {
864 auto oldLen = pEnvelope->GetTrackLen();
865 auto newLen = oldLen + len;
866 pEnvelope->Cap( sampleTime );
869 pEnvelope->SetTrackLen( newLen, sampleTime );
870 pEnvelope->InsertOrReplace
871 ( pEnvelope->GetOffset() + newLen, *pEnvelopeValue );
874 pEnvelope->InsertSpace( t, len );
943 pSequence->Delete(s0, s1 - s0);
965 if (cutlinePosition >= t0 && cutlinePosition <= t1)
972 if (cutlinePosition >= t1)
974 clip->
ShiftBy(clip_t0 - clip_t1);
981 auto sampleTime = 1.0 /
GetRate();
985 transaction.Commit();
1002 auto newClip = std::make_shared<WaveClip>(
1003 *
this,
GetFactory(),
true, clip_t0, clip_t1);
1006 newClip->ClearSequence(t1, newClip->GetSequenceEndTime());
1007 newClip->SetTrimRight(.0);
1011 newClip->ClearSequence(newClip->GetSequenceStartTime(), t0);
1012 newClip->SetTrimLeft(.0);
1024 if (cutlinePosition >= t0 && cutlinePosition <= t1)
1028 if (cutlinePosition >= t1)
1030 clip->
ShiftBy(clip_t0 - clip_t1);
1042 pSequence->Delete(s0, s1-s0);
1045 auto sampleTime = 1.0 /
GetRate();
1048 transaction.Commit();
1051 mCutLines.push_back(std::move(newClip));
1058 double* cutlineStart ,
1059 double* cutlineEnd )
const
1067 *cutlineStart = startTime;
1069 *cutlineEnd = startTime + cutline->SamplesToTime(cutline->GetVisibleSampleCount());
1083 return fabs(GetSequenceStartTime() + cutline->GetSequenceStartTime() - cutLinePosition) < 0.0001;
1087 auto *cutline = it->get();
1092 cutline->mEnvelope->SetOffset(0);
1093 bool success =
Paste(
1116 const auto &cutline = *it;
1134 cutLine->ShiftBy(len);
1142 pSequence->CloseLock();
1144 cutline->CloseLock();
1151 auto ratio =
static_cast<double>(
mRate) / rate;
1155 const auto newLength =
1201 double factor = (double)rate / (
double)
mRate;
1204 const size_t bufsize = 65536;
1205 Floats inBuffer{ bufsize };
1206 Floats outBuffer{ bufsize };
1209 int outGenerated = 0;
1220 while (pos < numSamples || outGenerated > 0) {
1223 bool isLast = ((pos + inLen) == numSamples);
1225 auto ppNewSequence = newSequences.begin();
1226 std::optional<std::pair<size_t, size_t>> results{};
1228 auto &pNewSequence = *ppNewSequence++;
1236 auto newResults = resample.
Process(factor, inBuffer.get(), inLen,
1237 isLast, outBuffer.get(), bufsize);
1239 results.emplace(newResults);
1240 else if (*results != newResults) {
1245 outGenerated = results->second;
1246 if (outGenerated < 0) {
1257 pos += results->first;
1261 auto updateResult = progress->
Poll(
1263 numSamples.as_long_long()
1274 XO(
"Resampling failed."),
1300 return fabs(startNext - endThis) < 0.5;
1320 return s.as_double() * GetStretchRatio() / mRate;
1333 pSequence->SetSilence(start, length);
1435 const auto quantizedTrim =
1481 SetSequenceStartTime(GetSequenceStartTime() + delta);
1567 auto &pFirst = *iter++;
1571 std::all_of(iter,
end, [&](
decltype(pFirst) pSequence) {
1573 pSequence->GetSampleFormats() == pFirst->GetSampleFormats() &&
1574 pSequence->GetFactory() == pFirst->GetFactory();
1579 return pCutLine && pCutLine->GetWidth() == width &&
1580 pCutLine->CheckInvariants();
1589 , mTrimLeft{ clip.mTrimLeft }
1590 , mTrimRight{ clip.mTrimRight }
1597 std::make_unique<Sequence>(*pSequence,
factory));
1603 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.
EffectReverbSettings preset
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)
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
CallbackReturn Publish(const Message &message)
Send a message to connected callbacks.
A move-only handle representing a connection to a Publisher.
std::pair< size_t, size_t > Process(double factor, const 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 constexpr auto MaxCents
static constexpr auto MinCents
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 ∈ [...)
int GetCentShift() const override
PitchAndSpeedPreset mPitchAndSpeedPreset
std::optional< double > mRawAudioTempo
std::vector< std::unique_ptr< Sequence > > GetEmptySequenceCopies() const
bool SetCentShift(int cents)
bool HasPitchOrSpeed() 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)
Observer::Subscription SubscribeToPitchAndSpeedPresetChange(std::function< void(PitchAndSpeedPreset)> cb) override
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
Observer::Subscription SubscribeToCentShiftChange(std::function< void(int)> cb) override
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 TrimQuarternotesFromRight(double quarters)
Same as TrimRight, but expressed as quarter notes.
void SetPitchAndSpeedPreset(PitchAndSpeedPreset preset)
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'.
PitchAndSpeedPreset GetPitchAndSpeedPreset() const override
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 SetRawAudioTempo(double tempo)
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)
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)
bool HasEqualPitchAndSpeed(const WaveClip &other) const
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 ∈ [...)
void StretchBy(double ratio)
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...
const PitchAndSpeedPreset newValue
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