142 sampleCount start,
size_t len,
bool mayThrow)
const
150 sampleCount start,
size_t length,
bool mayThrow)
const
183 const std::shared_ptr<WaveClip> &pClip,
184 const std::shared_ptr<WaveClip> &pClip1
186 pClip->GetPlayStartTime(), pClip->GetPlayEndTime() }
208 for (
unsigned channel = 0; channel <
NChannels(); ++channel)
209 GetClip(channel)->AppendNewBlock(buffer[channel],
format, len);
214 ForEachClip([](
auto& clip) { clip.Flush(); });
219 for(
unsigned channel = 0; channel <
NChannels(); ++channel)
220 GetClip(channel)->TrimLeftTo(t);
225 for(
unsigned channel = 0; channel <
NChannels(); ++channel)
226 GetClip(channel)->TrimRightTo(t);
231 for(
unsigned channel = 0; channel <
NChannels(); ++channel)
232 GetClip(channel)->SetTrimLeft(t);
237 for(
unsigned channel = 0; channel <
NChannels(); ++channel)
238 GetClip(channel)->SetTrimRight(t);
243 for(
unsigned channel = 0; channel <
NChannels(); ++channel)
244 GetClip(channel)->ClearLeft(t);
249 for(
unsigned channel = 0; channel <
NChannels(); ++channel)
250 GetClip(channel)->ClearRight(t);
255 for(
unsigned channel = 0; channel <
NChannels(); ++channel)
256 GetClip(channel)->StretchLeftTo(t);
261 for(
unsigned channel = 0; channel <
NChannels(); ++channel)
262 GetClip(channel)->StretchRightTo(t);
266 const std::function<
void(
double)>& reportProgress,
const ChannelGroup& group,
269 if (GetStretchRatio() == 1)
270 return std::make_shared<Interval>(group, mpClip, mpClip1);
272 const auto dst = std::make_shared<Interval>(
275 const auto originalPlayStartTime = GetPlayStartTime();
276 const auto originalPlayEndTime = GetPlayEndTime();
277 const auto stretchRatio = GetStretchRatio();
279 auto success =
false;
291 const auto tmpPlayStartTime =
292 std::max(GetSequenceStartTime(), originalPlayStartTime - stretchRatio);
293 const auto tmpPlayEndTime =
294 std::min(GetSequenceEndTime(), originalPlayEndTime + stretchRatio);
298 WideClip wideClip { mpClip, mpClip1 };
300 constexpr auto sourceDurationToDiscard = 0.;
301 constexpr auto blockSize = 1024;
306 params.timeRatio = stretchRatio;
308 stretcherSource, std::move(
params) };
311 const auto totalNumOutSamples =
318 while (numOutSamples < totalNumOutSamples)
320 const auto numSamplesToGet =
322 stretcher.GetSamples(container.
Get(), numSamplesToGet);
328 numOutSamples += numSamplesToGet;
331 numOutSamples.as_double() / totalNumOutSamples.as_double());
337 dst->SetPlayStartTime(tmpPlayStartTime);
338 dst->ClearLeft(originalPlayStartTime);
339 dst->ClearRight(originalPlayEndTime);
342 Envelope dstEnvelope = GetEnvelope();
343 const auto samplePeriod = 1. / mpClip->GetRate();
345 originalPlayEndTime, GetSequenceEndTime() + samplePeriod, samplePeriod);
346 dstEnvelope.
CollapseRegion(0, originalPlayStartTime, samplePeriod);
347 dstEnvelope.
SetOffset(originalPlayStartTime);
348 dst->SetEnvelope(dstEnvelope);
352 assert(dst->GetStretchRatio() == 1);
358 for (
unsigned channel = 0; channel <
NChannels(); ++channel)
360 if (!GetClip(channel)->StretchRatioEquals(value))
368 ForEachClip([&](
auto& clip) { clip.SetName(
name); });
374 return mpClip->GetName();
379 ForEachClip([&](
auto& clip) { clip.SetColourIndex(index); });
385 return mpClip->GetColourIndex();
390 ForEachClip([&](
auto& clip) { clip.SetPlayStartTime(time); });
396 return mpClip->GetPlayStartTime();
403 return mpClip->GetPlayEndTime();
410 return mpClip->IntersectsPlayRegion(t0, t1);
415 return mpClip->WithinPlayRegion(t);
421 return mpClip->GetStretchRatio();
426 return mpClip->TimeToSamples(time);
431 return mpClip->SamplesToTime(s);
436 return mpClip->GetSequenceStartTime();
441 ForEachClip([t](
auto& clip) { clip.SetSequenceStartTime(t); });
446 return mpClip->GetSequenceEndTime();
452 return mpClip->GetTrimLeft();
458 return mpClip->GetTrimRight();
463 return mpClip->GetIsPlaceholder();
468 return *mpClip->GetEnvelope();
473 mpClip->SetEnvelope(std::make_unique<Envelope>(envelope));
478 for(
unsigned channel = 0,
480 channel < channelCount; ++channel)
482 op(*GetClip(channel));
486std::shared_ptr<ChannelInterval>
491 const auto pClip = (
iChannel == 0 ? mpClip : mpClip1);
492 return std::make_shared<WaveChannelInterval>(*mpClip,
498std::shared_ptr<const WaveTrack::Interval>
501 std::shared_ptr<const Interval> result;
503 ? std::numeric_limits<double>::max()
504 : std::numeric_limits<double>::lowest();
509 (other->Start() > interval.
Start() && other->Start() < bestMatchTime))
512 (other->Start() < interval.
Start() && other->Start() > bestMatchTime)))
515 bestMatchTime = other->Start();
524 return std::const_pointer_cast<Interval>(
525 std::as_const(*this).GetNextInterval(interval, searchDirection));
532 if (interval->WithinPlayRegion(t))
551 double GetOrigin()
const;
552 void SetOrigin(
double origin);
567 std::atomic<float> mGain{ 1.0f };
569 std::atomic<float> mPan{ 0.0f };
572 double mOrigin{ 0.0 };
573 int mWaveColorIndex{ 0 };
579 [](
auto &) {
return std::make_unique<WaveTrackData>(); } };
582WaveTrackData::WaveTrackData(
const WaveTrackData &other) {
586 mOrigin = other.mOrigin;
587 mWaveColorIndex = other.mWaveColorIndex;
588 mFormat = other.mFormat;
591WaveTrackData::~WaveTrackData() =
default;
594 return std::make_unique<WaveTrackData>(*
this);
607int WaveTrackData::GetWaveColorIndex()
const
609 return mWaveColorIndex;
612void WaveTrackData::SetWaveColorIndex(
int index)
614 mWaveColorIndex = index;
617double WaveTrackData::GetOrigin()
const
621void WaveTrackData::SetOrigin(
double origin)
636float WaveTrackData::GetGain()
const
638 return mGain.load(std::memory_order_relaxed);
641void WaveTrackData::SetGain(
float value)
643 mGain.store(value, std::memory_order_relaxed);
646float WaveTrackData::GetPan()
const
648 return mPan.load(std::memory_order_relaxed);
651void WaveTrackData::SetPan(
float value)
653 mPan.store(value, std::memory_order_relaxed);
661void WaveTrackData::SetRate(
int value)
668 if (a.size() != b.size())
675 return a->GetPlayStartTime() == b->GetPlayStartTime() &&
676 a->GetSequenceStartTime() == b->GetSequenceStartTime() &&
677 a->GetPlayEndTime() == b->GetPlayEndTime() &&
678 a->GetSequenceEndTime() == b->GetSequenceEndTime();
681 return std::mismatch(a.begin(), a.end(), b.begin(), compare).first == a.end();
743 auto channels = std::vector<std::shared_ptr<Track>>{ };
745 std::back_inserter(channels),
747 [&] {
return Create(
format, rate); }
756 auto channels = std::vector<std::shared_ptr<Track>>{};
758 std::back_inserter(channels),
771 auto result =
tracks.Add(trackFactory.Create());
772 result->AttachedTrackObjects::BuildAll();
788 , mpFactory( orig.mpFactory )
791 for (
const auto &clip : orig.
mClips)
836 for (
const auto pChannel : channels)
837 pChannel->Init(**iter++);
850 for (
const auto &clip : pChannel->mClips)
852 clip->ShiftBy(delta);
858 const std::optional<double>& oldTempo,
double newTempo)
862 for (
const auto& clip : pChannel->mClips)
863 clip->OnProjectTempoChange(oldTempo, newTempo);
882 for (
auto it = clips.begin(); it != clips.end();)
884 if ((*it)->IsEmpty())
885 it = clips.erase(it);
896 if (next ==
nullptr) {
899 wxLogWarning(L
"Right track %s is expected to be a WaveTrack."
900 "\n Removing link from left wave track %s.",
919 next->DestroyGroupData();
924 removeZeroClips(next->mClips);
946 {
"wave",
"wave",
XO(
"Wave Track") },
966 auto &pSampleBlockFactory = trackFactory.GetSampleBlockFactory();
970 auto pNewTrack = pChannel->
EmptyCopy(pSampleBlockFactory);
972 assert(pNewTrack->IsLeader() == pChannel->IsLeader());
974 pFirstTrack = pNewTrack;
975 pFirstChannel = pChannel;
978 pFirstTrack->Paste(0.0, *pFirstChannel);
987std::shared_ptr<WideChannelGroupInterval>
995 if (
auto right = ChannelGroup::GetChannel<WaveTrack>(1)
996 ; right && iInterval < right->mClips.size()
998 pClip1 = right->mClips[iInterval];
999 return std::make_shared<Interval>(*
this, pClip, pClip1);
1006 for (
const auto& clip :
mClips)
1008 if (clip->GetName() ==
name)
1025 return { pTrack->shared_from_this(), alias };
1036 const Track *pTrack =
this;
1038 pTrack = *pOwner->
Find(
this);
1047 const auto cloneOne = [&](
const WaveTrack *pChannel){
1050 pTrack->Init(*pChannel);
1051 result->Add(pTrack);
1063 auto name = originalName;
1064 for (
auto i = 1;; ++i)
1069 name =
XC(
"%s.%i",
"clip name template").Format(originalName, i).Translation();
1076 for (
auto i = 1;; ++i)
1081 name =
XC(
"%s %i",
"clip name template").Format(
GetName(), i).Translation();
1092 assert( newRate > 0 );
1093 newRate = std::max( 1.0, newRate );
1096 for(
const auto& channel :
Channels())
1097 channel->GetTrack().SetClipRates(newRate);
1103 data.SetRate(
static_cast<int>(newRate));
1108 for (
const auto &clip :
mClips)
1109 clip->SetRate(
static_cast<int>(newRate));
1144 else if (newPan < -1.0)
1147 if (
GetPan() != newPan ) {
1158 const auto pan =
GetPan();
1160 right = (pan + 1.0);
1165 if ((channel%2) == 0)
1168 return right * gain;
1181 for (
const auto &clip : pChannel->mClips)
1182 clip->SetColourIndex(colorIndex);
1191 for (
const auto& clip :
mClips)
1192 result += clip->GetVisibleSampleCount();
1203 for (
const auto& clip : pChannel->mClips)
1204 result += clip->GetSequenceSamplesCount();
1214 for (
auto& clip : pChannel->GetClips())
1215 result += clip->GetWidth() * clip->GetSequenceBlockArray(0)->size();
1227 const std::function<
void(
size_t)> & progressReport)
1231 for (
const auto& clip : pChannel->mClips)
1232 clip->ConvertToSampleFormat(
format, progressReport);
1244 for (
const auto &clip :
mClips)
1246 if (clip->IntersectsPlayRegion(t0, t1)) {
1266 auto result =
Copy(t0, t1);
1279 auto result =
Copy(t0, t1);
1290 bool inside0 =
false;
1291 bool inside1 =
false;
1294 for (
auto pChannel : range) {
1295 for (
const auto &clip : pChannel->mClips) {
1296 if (t1 > clip->GetPlayStartTime() && t1 < clip->GetPlayEndTime()) {
1298 clip->GetTrimRight() + clip->GetPlayEndTime() - t1);
1302 if (t0 > clip->GetPlayStartTime() && t0 < clip->GetPlayEndTime()) {
1304 clip->GetTrimLeft() + t0 - clip->GetPlayStartTime());
1313 ; !inside1 && t1 < endTime
1318 ; !inside0 && t0 > startTime
1327 auto result = std::make_shared<WaveTrack>(pFactory,
GetSampleFormat(), rate);
1328 result->Init(*
this);
1334 result->DoSetRate(rate);
1335 result->mpFactory = pFactory ? pFactory :
mpFactory;
1348 const auto pNewTrack =
1349 result->Add(pChannel->EmptyCopy(pFactory, keepLink));
1350 assert(!keepLink || pNewTrack->IsLeader() == pChannel->IsLeader());
1360 result->MakeMultiChannelTrack(**result->begin(), 2);
1372 list->Add(
CopyOne(*pChannel, t0, t1, forClipboard));
1377 const WaveTrack &track,
double t0,
double t1,
bool forClipboard) ->
Holder
1379 const auto &pFactory = track.mpFactory;
1380 auto result = track.EmptyCopy();
1387 for (
const auto &clip : track.mClips) {
1391 if (t0 <= clip->GetPlayStartTime() && t1 >= clip->GetPlayEndTime()) {
1396 std::make_shared<WaveClip>(*clip, pFactory, !forClipboard));
1400 else if (clip->CountSamples(t0, t1) >= 1) {
1404 auto newClip = std::make_shared<WaveClip>(
1405 *clip, pFactory, !forClipboard, t0, t1);
1406 newClip->SetName(clip->GetName());
1408 newClip->ShiftBy(-t0);
1409 if (newClip->GetPlayStartTime() < 0)
1410 newClip->SetPlayStartTime(0);
1423 auto placeholder = std::make_shared<WaveClip>(1, pFactory,
1425 static_cast<int>(newTrack->
GetRate()),
1427 placeholder->SetIsPlaceholder(
true);
1428 placeholder->InsertSilence(0, (t1 - t0) - newTrack->
GetEndTime());
1429 placeholder->ShiftBy(newTrack->
GetEndTime());
1430 newTrack->
InsertClip(std::move(placeholder));
1440 pChannel->HandleClear(t0, t1,
false,
false);
1448 pChannel->HandleClear(t0, t1,
true,
false);
1505 bool clearByTrimming)
1510 if (!tempo.has_value())
1515 t0, t1, *
copy, preserve, merge, effectWarper, clearByTrimming);
1519 double t0,
double t1,
const WaveTrack& src,
bool preserve,
bool merge,
1520 const TimeWarper* effectWarper,
bool clearByTrimming)
1522 const auto srcNChannels = src.
NChannels();
1525 assert(srcNChannels == 1 || srcNChannels ==
NChannels());
1535 double dur =
std::min(t1 - t0, endTime);
1546 for (
const auto pChannel : myChannels) {
1548 *pChannel, t0, t1, startTime, endTime, **iter, preserve, merge,
1549 effectWarper, clearByTrimming);
1550 if (srcNChannels > 1)
1556 WaveTrack& track,
double t0,
double t1,
const double startTime,
1557 const double endTime,
const WaveTrack& src,
bool preserve,
bool merge,
1558 const TimeWarper* effectWarper,
bool clearByTrimming)
1562 std::vector<SplitInfo> splits;
1567 auto get_split = [&](
double time) {
1568 auto it = std::find_if(splits.begin(), splits.end(),
1569 [time](
const SplitInfo& split) { return split.time == time; });
1570 if(it == splits.end())
1573 { time, nullptr, nullptr, std::nullopt, std::nullopt }
1580 const TimeWarper *warper = (effectWarper ? effectWarper : &localWarper);
1582 const auto roundTime = [&track](
double t){
1593 for (
const auto &clip : track.
mClips) {
1599 st = roundTime(clip->GetPlayStartTime());
1600 if (st >= t0 && st <= t1) {
1601 auto it = get_split(st);
1602 if (clip->GetTrimLeft() != 0) {
1604 it->right = std::make_shared<WaveClip>(*clip, pFactory,
false);
1605 it->right->SetTrimLeft(.0);
1606 it->right->ClearRight(clip->GetPlayStartTime());
1608 it->rightClipName = clip->GetName();
1611 st = roundTime(clip->GetPlayEndTime());
1612 if (st >= t0 && st <= t1) {
1613 auto it = get_split(st);
1614 if (clip->GetTrimRight() != 0) {
1616 it->left = std::make_shared<WaveClip>(*clip, pFactory,
false);
1617 it->left->SetTrimRight(.0);
1618 it->left->ClearLeft(clip->GetPlayEndTime());
1620 it->leftClipName = clip->GetName();
1624 auto &cutlines = clip->GetCutLines();
1626 for (
auto it = cutlines.begin(); it != cutlines.end(); ) {
1628 const double cs = roundTime(
1632 if (cs >= t0 && cs <= t1) {
1635 cuts.push_back(std::move(*it));
1636 it = cutlines.erase(it);
1643 const auto tolerance = 2.0 / track.
GetRate();
1646 constexpr auto split =
false;
1649 track.
HandleClear(t0, t1,
false, split, clearByTrimming);
1652 PasteOne(track, t0, src, startTime, endTime, merge);
1655 if (merge && splits.size() > 0) {
1667 for (
const auto clip : clips) {
1670 if (fabs(t1 - clip->GetPlayStartTime()) < tolerance) {
1688 for (
const auto clip : clips) {
1693 if (clip->HasEqualStretchRatio(*prev))
1698 if (fabs(t0 - clip->GetPlayEndTime()) < tolerance)
1723 auto trim = src.GetPlayEndTime() - src.GetPlayStartTime();
1741 auto trim = src.GetPlayEndTime() - src.GetPlayStartTime();
1748 for (
const auto& split: splits) {
1749 auto at = roundTime(warper->
Warp(split.time));
1750 for (
const auto& clip : track.
GetClips()) {
1754 if (clip->SplitsPlayRegion(at))
1757 std::make_shared<WaveClip>(*clip, pFactory,
true);
1759 clip->ClearRight(at);
1760 newClip->ClearLeft(at);
1763 attachRight(*clip, *split.left);
1766 attachLeft(*newClip, *split.right);
1767 bool success = track.
AddClip(std::move(newClip));
1771 else if (clip->GetPlayStartSample() ==
1774 const auto trim = clip->GetTrimLeft();
1775 const auto seqStartTime = clip->GetSequenceStartTime();
1776 clip->Clear(seqStartTime, seqStartTime + trim);
1779 clip->ShiftBy(trim);
1780 attachLeft(*clip, *split.right);
1783 else if (clip->GetPlayEndSample() ==
1787 clip->GetPlayEndTime(), clip->GetSequenceEndTime());
1788 attachRight(*clip, *split.left);
1795 for (
const auto& split : splits)
1798 for (
auto& clip : track.
GetClips()) {
1799 if (split.rightClipName.has_value() && clip->GetPlayStartSample() == s)
1800 clip->SetName(*split.rightClipName);
1801 else if (split.leftClipName.has_value() && clip->GetPlayEndSample() == s)
1802 clip->SetName(*split.leftClipName);
1807 for (
const auto &clip : track.
mClips) {
1811 st = clip->GetPlayStartTime();
1812 et = clip->GetPlayEndTime();
1815 for (
auto it = cuts.begin(); it != cuts.end();) {
1822 if (cs >= st && cs <= et) {
1824 clip->GetCutLines().push_back( std::move(*it) );
1825 it = cuts.erase(it);
1838 bool addCutLines =
false;
1841 pChannel->HandleClear(t0, t1, addCutLines, split);
1846 WaveClipHolders::const_iterator
1851 auto it = list.begin();
1852 for (
const auto end = list.end(); it !=
end; ++it)
1854 if (it->get() == clip)
1862 WaveClipHolders::iterator
1867 auto it = list.begin();
1868 for (
const auto end = list.end(); it !=
end; ++it)
1870 if (it->get() == clip)
1883 if (it !=
mClips.end()) {
1884 auto result = std::move(*it);
1895 if (clip->GetSequence(0)->GetFactory() != this->mpFactory)
1898 if (clip->GetWidth() !=
GetWidth())
1910 double t0,
double t1,
bool addCutLines,
bool split,
bool clearByTrimming)
1914 wxASSERT( t1 >= t0 );
1928 for (
const auto &clip :
mClips)
1930 if (clip->PartlyWithinPlayRegion(t0, t1))
1932 addCutLines =
false;
1938 for (
const auto &clip :
mClips)
1940 if (clip->CoversEntirePlayRegion(t0, t1))
1943 clipsToDelete.push_back(clip.get());
1945 else if (clip->IntersectsPlayRegion(t0, t1))
1952 clipsToDelete.push_back( clip.get() );
1954 std::make_shared<WaveClip>(*clip,
mpFactory,
true);
1955 newClip->ClearAndAddCutLine( t0, t1 );
1956 clipsToAdd.push_back( std::move( newClip ) );
1960 if (split || clearByTrimming) {
1963 if (clip->BeforePlayRegion(t0)) {
1968 clipsToDelete.push_back( clip.get() );
1970 std::make_shared<WaveClip>(*clip,
mpFactory,
true);
1971 newClip->TrimLeft(t1 - clip->GetPlayStartTime());
1975 newClip->ShiftBy(t0 - t1);
1976 clipsToAdd.push_back( std::move( newClip ) );
1978 else if (clip->AfterPlayRegion(t1)) {
1983 clipsToDelete.push_back( clip.get() );
1985 std::make_shared<WaveClip>(*clip,
mpFactory,
true);
1986 newClip->TrimRight(clip->GetPlayEndTime() - t0);
1988 clipsToAdd.push_back( std::move( newClip ) );
1995 std::make_shared<WaveClip>(*clip,
mpFactory,
true);
1996 leftClip->TrimRight(clip->GetPlayEndTime() - t0);
1997 clipsToAdd.push_back(std::move(leftClip));
2000 std::make_shared<WaveClip>(*clip,
mpFactory,
true);
2001 rightClip->TrimLeft(t1 - clip->GetPlayStartTime());
2005 rightClip->ShiftBy(t0 - t1);
2006 clipsToAdd.push_back(std::move(rightClip));
2008 clipsToDelete.push_back(clip.get());
2016 clipsToDelete.push_back( clip.get() );
2018 std::make_shared<WaveClip>(*clip,
mpFactory,
true);
2021 newClip->Clear(t0,t1);
2023 clipsToAdd.push_back( std::move( newClip ) );
2036 for (
const auto& clip :
mClips)
2037 if (clip->AtOrBeforePlayRegion(t1))
2038 clip->ShiftBy(-(t1 - t0));
2040 for (
const auto &clip: clipsToDelete)
2043 if (myIt !=
mClips.end())
2049 for (
auto &clip: clipsToAdd)
2057 if (newT1 > oldT1 &&
2064 if (newT1 > oldT1) {
2071 const auto offset = newT1 - oldT1;
2073 for (
const auto pChannel : channels)
2074 for (
const auto& clip : pChannel->mClips)
2075 if (clip->GetPlayStartTime() > oldT1 - (1.0 / rate))
2076 clip->ShiftBy(offset);
2083 const auto duration = newT1 - oldT1;
2084 for (
const auto pChannel : channels) {
2085 auto tmp = std::make_shared<WaveTrack>(
2089 assert(tmp->IsLeader());
2090 tmp->InsertSilence(0.0, duration);
2092 PasteOne(*pChannel, oldT1, *tmp, 0.0, duration);
2096 else if (newT1 < oldT1)
2097 Clear(newT1, oldT1);
2105 if (!tempo.has_value())
2113 double t0,
const WaveTrack& other,
bool merge)
2116 const auto otherNChannels = other.
NChannels();
2117 assert(otherNChannels == 1 || otherNChannels ==
NChannels());
2125 PasteOne(*pChannel, t0, **iter, startTime, endTime, merge);
2126 if (otherNChannels > 1)
2133 const double insertDuration,
bool merge)
2166 const auto stretchRatiosMatch =
2167 !clipAtT0 || (clipAtT0->HasEqualStretchRatio(*otherFirstClip) &&
2168 clipAtT0->HasEqualStretchRatio(*otherLastClip));
2172 const bool singleClipMode =
2175 stretchRatiosMatch && merge;
2177 const auto rate = track.
GetRate();
2178 if (insertDuration != 0 && insertDuration < 1.0 / rate)
2187 auto pastingFromTempTrack = !other.
GetOwner();
2192 XO(
"There is not enough room available to paste the selection"),
2193 XO(
"Warning"),
"Error:_Insufficient_space_in_track"
2197 if (editClipCanMove) {
2198 if (!singleClipMode) {
2205 for (
const auto& clip : track.
mClips)
2206 if (clip->GetPlayStartTime() > t0 - (1.0 / rate))
2207 clip->ShiftBy(insertDuration);
2215 if (!track.
IsEmpty(t, t + insertDuration))
2216 throw notEnoughSpaceException;
2223 if (singleClipMode && merge) {
2228 for (
const auto& clip : track.
mClips) {
2229 if (editClipCanMove) {
2230 if (clip->SplitsPlayRegion(t0)) {
2233 insideClip = clip.get();
2239 if (clip->WithinPlayRegion(t0))
2241 insideClip = clip.get();
2250 if (!editClipCanMove) {
2253 for (
const auto& clip : track.
mClips) {
2256 clip->GetPlayStartTime())
2259 throw notEnoughSpaceException;
2266 bool success = insideClip->
Paste(t0, *pClip);
2281 if (!editClipCanMove &&
2282 !track.
IsEmpty(t0, t0 + insertDuration - 1.0 / rate))
2285 throw notEnoughSpaceException;
2287 for (
const auto& clip : other.
mClips) {
2289 if (!clip->GetIsPlaceholder()) {
2291 std::make_shared<WaveClip>(*clip, track.
mpFactory,
true);
2292 newClip->Resample(rate);
2293 newClip->ShiftBy(t0);
2294 newClip->MarkChanged();
2295 if (pastingFromTempTrack)
2311 std::optional<double> oRate;
2313 return std::all_of(channels.begin(), channels.end(),
2318 const auto rate = pTrack->mLegacyRate;
2321 else if (*oRate != rate)
2332 return std::all_of(channels.begin(), channels.end(),
2334 return pTrack && pTrack->mLegacyFormat == mLegacyFormat;
2340 if(!clip->GetIsPlaceholder() && clip->IsEmpty())
2344 if (tempo.has_value())
2345 clip->OnProjectTempoChange(std::nullopt, *tempo);
2346 mClips.push_back(std::move(clip));
2357 assert(!interval.has_value() ||
2358 interval->first <= interval->second);
2361 const auto startTime =
2364 const auto endTime =
2367 if (startTime >= endTime)
2373 !clipAtT0->StretchRatioEquals(1))
2374 Split(startTime, startTime);
2377 !clipAtT1->StretchRatioEquals(1))
2378 Split(endTime, endTime);
2380 std::vector<IntervalHolder> srcIntervals;
2382 while (clip && clip->GetPlayStartTime() < endTime)
2384 if (clip->GetStretchRatio() != 1)
2385 srcIntervals.push_back(clip);
2396 if (
const auto other =
dynamic_cast<const WaveTrack*
>(&src))
2400 constexpr auto merge =
true;
2420 for (
const auto &clip : pChannel->mClips) {
2421 auto clipStart = clip->GetPlayStartSample();
2422 auto clipEnd = clip->GetPlayEndSample();
2423 if (clipEnd > start && clipStart <
end) {
2424 auto offset = std::max(start - clipStart,
sampleCount(0));
2426 auto length =
std::min(
end, clipEnd) - (clipStart + offset);
2427 clip->SetSilence(offset, length);
2445 auto &clips = pChannel->mClips;
2446 if (clips.empty()) {
2449 auto clip = std::make_shared<WaveClip>(1,
2451 clip->InsertSilence(0, len);
2453 pChannel->InsertClip(move(clip));
2458 const auto end = clips.end();
2459 const auto it = std::find_if(clips.begin(),
end,
2460 [&](
const WaveClipHolder &clip) { return clip->SplitsPlayRegion(t); } );
2464 it->get()->InsertSilence(t, len);
2467 for (
const auto &clip : clips)
2468 if (clip->BeforePlayRegion(t))
2481 const size_t maxAtOnce = 1048576;
2482 std::vector<float> buffer;
2483 std::vector<samplePtr> buffers;
2488 for (
const auto &interval :
Intervals()) {
2489 double startTime = interval->Start();
2490 double endTime = interval->End();
2492 if (endTime < t0 || startTime > t1)
2496 if (buffer.empty()) {
2497 buffer.resize(maxAtOnce * width);
2498 buffers.resize(width);
2499 auto pBuffer = buffer.data();
2500 for (
size_t ii = 0; ii < width; ++ii, pBuffer += maxAtOnce)
2501 buffers[ii] =
reinterpret_cast<samplePtr>(pBuffer);
2504 const auto allZeroesAt = [&](
size_t i) {
2505 auto pData = buffer.data() + i;
2506 for (
size_t ii = 0; ii < width; ++ii, pData += maxAtOnce) {
2517 auto start = interval->TimeToSamples(std::max(.0, t0 - startTime));
2518 auto end = interval->TimeToSamples(
std::min(endTime, t1) - startTime);
2520 auto len = (
end - start);
2521 for (
decltype(len) done = 0; done < len; done += maxAtOnce) {
2524 auto bufferIt = buffers.begin();
2526 for (
auto channel : interval->Channels())
2527 channel->GetSamples(
2528 *bufferIt++,
floatSample, start + done, numSamples);
2530 for (
decltype(numSamples) i = 0; i < numSamples; ++i) {
2531 auto curSamplePos = start + done + i;
2534 if (seqStart == -1 && allZeroesAt(i))
2535 seqStart = curSamplePos;
2536 else if (curSamplePos ==
end - 1 || !allZeroesAt(i)) {
2537 if (seqStart != -1) {
2538 decltype(
end) seqEnd;
2541 if (curSamplePos ==
end - 1 && allZeroesAt(i))
2544 seqEnd = curSamplePos;
2545 if (seqEnd - seqStart + 1 > minSamples) {
2548 startTime + interval->SamplesToTime(seqStart),
2549 startTime + interval->SamplesToTime(seqEnd)
2560 for (
const auto ®ion : regions)
2571 std::vector<IntervalHolder> intervalsToJoin;
2572 for (
auto interval : intervals)
2573 if (interval->IntersectsPlayRegion(t0, t1))
2574 intervalsToJoin.push_back(interval);
2575 if (intervalsToJoin.size() < 2u)
2578 intervalsToJoin.begin() + 1, intervalsToJoin.end(),
2580 intervalsToJoin[0]->GetStretchRatio()](
const auto& interval) {
2581 return first != interval->GetStretchRatio();
2595 const auto rate = track.
GetRate();
2596 auto &clips = track.
mClips;
2597 for (
const auto &clip: clips) {
2598 if (clip->IntersectsPlayRegion(t0, t1)) {
2600 auto it = clipsToDelete.begin(),
end = clipsToDelete.end();
2601 for (; it !=
end; ++it)
2602 if ((*it)->GetPlayStartTime() > clip->GetPlayStartTime())
2605 clipsToDelete.insert(it, clip.get());
2610 if (clipsToDelete.empty())
2613 auto t = clipsToDelete[0]->GetPlayStartTime();
2615 newClip = track.
CreateClip(clipsToDelete[0]->GetSequenceStartTime(),
2618 for (
auto clip : clipsToDelete) {
2623 if (clip->GetPlayStartTime() - t > (1.0 / rate))
2625 double addedSilence = (clip->GetPlayStartTime() - t);
2628 auto value = clip->GetEnvelope()->GetValue(offset);
2629 newClip->AppendSilence(addedSilence, value);
2634 bool success = newClip->Paste(t, *clip);
2637 t = newClip->GetPlayEndTime();
2648 size_t len,
unsigned stride,
sampleFormat effectiveFormat)
2666 size_t len,
unsigned int stride,
sampleFormat effectiveFormat,
2675 return pTrack->RightmostOrNewClip()
2676 ->Append(buffers,
format, len, stride, effectiveFormat);
2683 for (
const auto &clip :
mClips)
2685 auto startSample = clip->GetPlayStartSample();
2686 auto endSample = clip->GetPlayEndSample();
2687 if (s >= startSample && s < endSample)
2690 bestBlockSize = clip->GetSequence(0)
2691 ->GetBestBlockSize(s - clip->GetSequenceStartSample());
2696 return bestBlockSize;
2702 for (
const auto &clip :
mClips)
2703 for (
size_t ii = 0, width = clip->GetWidth(); ii < width; ++ii)
2704 maxblocksize = std::max(maxblocksize,
2705 clip->GetSequence(ii)->GetMaxBlockSize());
2707 if (maxblocksize == 0)
2716 wxASSERT(maxblocksize > 0);
2718 return maxblocksize;
2738 pChannel->FlushOne();
2749 if (channels.size() != 2)
2752 const auto left = *channels.begin();
2753 auto it =
begin(left->mClips),
2754 last =
end(left->mClips);
2755 const auto right = *channels.rbegin();
2756 auto it2 =
begin(right->mClips),
2757 last2 =
end(right->mClips);
2758 for (; it != last; ++it, ++it2) {
2763 (*it2)->SetEnvelope(std::make_unique<Envelope>(*(*it)->GetEnvelope()));
2800 if (tag ==
"wavetrack") {
2804 for (
const auto& pair : attrs)
2806 const auto& attr = pair.first;
2807 const auto& value = pair.second;
2812 if (!value.TryGet(dblValue) ||
2813 (dblValue < 1.0) || (dblValue > 1000000.0))
2819 else if (attr ==
"offset" && value.TryGet(dblValue))
2830 else if (attr ==
"gain" && value.TryGet(dblValue))
2832 else if (attr ==
"pan" && value.TryGet(dblValue) &&
2833 (dblValue >= -1.0) && (dblValue <= 1.0))
2835 else if (attr ==
"linked" && value.TryGet(nValue))
2837 else if (attr ==
"colorindex" && value.TryGet(nValue))
2840 else if (attr ==
"sampleformat" && value.TryGet(nValue) &&
2868 .CallObjectAccessor(tag, *
this) )
2874 if (tag ==
"sequence" || tag ==
"envelope")
2880 if (tag ==
"sequence")
2882 else if (tag ==
"envelope")
2888 if (tag ==
"waveblock")
2899 if (tag ==
"waveclip")
2905 auto clip = std::make_shared<WaveClip>(1,
2907 const auto xmlHandler = clip.get();
2908 mClips.push_back(std::move(clip));
2921 nChannels = channels.size();
2922 for (
const auto pChannel : channels)
2923 WriteOneXML(*pChannel, xmlFile,
iChannel++, nChannels);
2931 track.Track::WriteCommonXMLAttributes(xmlFile);
2941 const auto channelType = (nChannels == 0)
2950 track.WritableSampleTrack::WriteXMLAttributes(xmlFile);
2964 for (
const auto &clip : track.
mClips)
2965 clip->WriteXML(xmlFile);
2974 for (
const auto &clip : pChannel->mClips)
2975 for (
size_t ii = 0, width = clip->GetWidth(); ii < width; ++ii)
2976 if (clip->GetSequence(ii)->GetErrorOpening())
2977 return XO(
"A track has a corrupted sample sequence.");
2986 for (
const auto &clip : pChannel->mClips)
2995 return std::min_element(
2997 [](
const auto& a,
const auto b) {
2998 return a->GetPlayStartTime() < b->GetPlayStartTime();
3006 return std::max_element(
3008 [](
const auto& a,
const auto b) {
3009 return a->GetPlayEndTime() < b->GetPlayEndTime();
3021 wideClips.reserve(
mClips.size());
3022 for (
auto clipIndex = 0u; clipIndex <
mClips.size(); ++clipIndex)
3024 const auto leftClip =
mClips[clipIndex];
3028 const auto& rightClips =
3035 assert(clipIndex < rightClips.size());
3036 if (clipIndex < rightClips.size())
3037 rightClip = rightClips[clipIndex];
3039 wideClips.emplace_back(
3040 std::make_shared<WideClip>(leftClip, std::move(rightClip)));
3061 double t0,
double t1,
bool mayThrow)
const
3063 std::pair<float, float> results {
3067 bool clipFound =
false;
3078 for (
const auto &clip:
GetTrack().mClips)
3080 if (t1 >= clip->GetPlayStartTime() && t0 <= clip->GetPlayEndTime())
3084 auto clipResults = clip->GetMinMax(0, t0, t1, mayThrow);
3085 if (clipResults.first < results.first)
3086 results.first = clipResults.first;
3087 if (clipResults.second > results.second)
3088 results.second = clipResults.second;
3094 results = { 0.f, 0.f };
3112 double duration = 0;
3114 for (
const auto &clip:
GetTrack().mClips)
3119 if (t1 >= clip->GetPlayStartTime() && t0 <= clip->GetPlayEndTime())
3121 const auto clipStart = std::max(t0, clip->GetPlayStartTime());
3122 const auto clipEnd =
std::min(t1, clip->GetPlayEndTime());
3125 float cliprms = clip->GetRMS(0, t0, t1, mayThrow);
3127 sumsq += cliprms * cliprms * (clipEnd - clipStart);
3128 duration += (clipEnd - clipStart);
3131 return duration > 0 ?
sqrt(sumsq / duration) : 0.0;
3137 bool mayThrow,
sampleCount* pNumWithinClips)
const
3140 assert(
iChannel + nBuffers <= nChannels);
3144 assert(nChannels == 1);
3145 nBuffers = std::min<size_t>(nBuffers, 1);
3147 std::optional<TrackIter<const WaveTrack>> iter;
3154 return std::all_of(buffers, buffers + nBuffers, [&](
samplePtr buffer) {
3155 const auto result = pTrack->GetOne(
3156 buffer,
format, start, len, backwards, fill, mayThrow,
3159 pTrack = *(++ *iter);
3170 t = clip->
SamplesToTime(clip->TimeToSamples(t - clip->GetPlayStartTime())) +
3171 clip->GetPlayStartTime();
3176 double t,
size_t iChannel,
float* buffer,
size_t numSideSamples,
3177 bool mayThrow)
const
3182 t,
iChannel, buffer + numSideSamples, numSideSamples + 1, mayThrow,
3184 return { numSideSamples - numSamplesReadLeft,
3185 numSideSamples + numSamplesReadRight };
3190template <
typename FloatType>
3192 std::is_const_v<std::remove_pointer_t<FloatType>>,
constSamplePtr,
3202template <
typename BufferType>
3204 const WaveClip& clip,
double startOrEndTime , BufferType buffer,
3205 size_t totalToRead,
size_t alreadyRead,
bool forward)
3207 assert(totalToRead >= alreadyRead);
3208 const auto remainingToRead = totalToRead - alreadyRead;
3213 const auto startTime =
3216 if (startSamp >= sampsInClip)
3221 buffer + alreadyRead),
3229 const auto startSamp =
3230 std::max(endSamp - remainingToRead,
sampleCount { 0 });
3233 const auto len = (endSamp - startSamp).as_size_t();
3234 if (len == 0 || startSamp >= sampsInClip)
3236 const auto bufferEnd = buffer + remainingToRead;
3244 double t,
size_t iChannel,
float* buffer,
size_t numSamples,
bool mayThrow,
3249 auto numSamplesRead = 0u;
3254 *clip, t, buffer, numSamples, numSamplesRead,
forward);
3255 if (!clip->GetSamples(
3259 numSamplesRead += args.len;
3260 if (numSamplesRead >= numSamples)
3264 return numSamplesRead;
3268 double t,
size_t iChannel,
float& value,
bool mayThrow)
const
3273 clip->GetFloatAtTime(
3274 t - clip->GetPlayStartTime(),
iChannel, value, mayThrow);
3279 double t,
size_t iChannel,
const float* buffer,
size_t numSideSamples,
3283 t,
iChannel, buffer, numSideSamples, effectiveFormat,
3286 t,
iChannel, buffer + numSideSamples, numSideSamples + 1, effectiveFormat,
3291 double t,
size_t iChannel,
const float* buffer,
size_t numSamples,
3296 auto numSamplesWritten = 0u;
3301 *clip, t, buffer, numSamples, numSamplesWritten,
forward);
3307 numSamplesWritten += args.len;
3308 if (numSamplesWritten >= numSamples)
3322 double t0,
double t1,
size_t iChannel,
3323 const std::function<
float(
double sampleTime)>& producer,
3329 if (sortedClips.empty())
3331 t0 = std::max(t0, (*sortedClips.begin())->GetPlayStartTime());
3332 t1 =
std::min(t1, (*sortedClips.rbegin())->GetPlayEndTime());
3335 const auto clipStartTime = clip->GetPlayStartTime();
3336 const auto clipEndTime = clip->GetPlayEndTime();
3337 const auto sampsPerSec = clip->GetRate() / clip->GetStretchRatio();
3338 const auto roundedT0 =
3339 std::round((t0 - clipStartTime) * sampsPerSec) / sampsPerSec +
3341 const auto roundedT1 =
3342 std::round((t1 - clipStartTime) * sampsPerSec) / sampsPerSec +
3344 if (clipStartTime > roundedT1)
3346 const auto tt0 = std::max(clipStartTime, roundedT0);
3347 const auto tt1 =
std::min(clipEndTime, roundedT1);
3348 const size_t numSamples = (tt1 - tt0) * sampsPerSec + .5;
3349 std::vector<float>
values(numSamples);
3350 for (
auto i = 0u; i < numSamples; ++i)
3351 values[i] = producer(tt0 + clip->SamplesToTime(i));
3352 clip->SetFloatsFromTime(
3361 bool backwards,
fillFormat fill,
bool mayThrow,
3369 bool doClear =
true;
3372 for (
const auto &clip:
mClips)
3374 if (start >= clip->GetPlayStartSample() && start+len <= clip->GetPlayEndSample())
3389 float * pBuffer = (
float*)buffer;
3390 for(
size_t i=0;i<len;i++)
3395 wxFAIL_MSG(
wxT(
"Invalid fill format"));
3400 for (
const auto &clip:
mClips)
3402 auto clipStart = clip->GetPlayStartSample();
3403 auto clipEnd = clip->GetPlayEndSample();
3405 if (clipEnd > start && clipStart < start+len)
3408 if (clip->GetStretchRatio() != 1.0)
3412 auto samplesToCopy =
3413 std::min( start+len - clipStart, clip->GetVisibleSampleCount() );
3414 auto startDelta = clipStart - start;
3415 decltype(startDelta) inclipDelta = 0;
3418 inclipDelta = -startDelta;
3419 samplesToCopy -= inclipDelta;
3433 if (!clip->GetSamples(0,
3435 startDelta.as_size_t() *
3437 format, inclipDelta, samplesToCopy.as_size_t(), mayThrow ))
3440 samplesCopied += samplesToCopy;
3443 if( pNumWithinClips )
3444 *pNumWithinClips = samplesCopied;
3445 if (result ==
true && backwards)
3455 for (
const auto& channel :
Channels()) {
3456 result.push_back(channel->GetSampleView(t0, t1, mayThrow));
3464 std::vector<std::shared_ptr<const WaveChannelInterval>>
3465 intersectingIntervals;
3466 for (
const auto& interval :
Intervals())
3467 if (interval->Intersects(t0, t1))
3468 intersectingIntervals.push_back(interval);
3469 if (intersectingIntervals.empty())
3473 intersectingIntervals.begin(), intersectingIntervals.end(),
3474 [](
const auto& a,
const auto& b) { return a->Start() < b->Start(); });
3475 std::vector<AudioSegmentSampleView> segments;
3476 segments.reserve(2 * intersectingIntervals.size() + 1);
3477 for (
auto i = 0u; i < intersectingIntervals.size();++i)
3479 const auto& interval = intersectingIntervals[i];
3480 const auto intervalStartTime = interval->Start();
3481 if (t0 < intervalStartTime)
3485 t0 = intervalStartTime;
3487 const auto intervalT0 = t0 - intervalStartTime;
3488 const auto intervalT1 =
std::min(t1, interval->End()) - intervalStartTime;
3489 if(intervalT1 > intervalT0)
3492 interval->GetSampleView(intervalT0, intervalT1, mayThrow);
3493 t0 += intervalT1 - intervalT0;
3494 segments.push_back(std::move(newSegment));
3509 for (
const auto &clip:
GetTrack().mClips)
3511 auto clipStart = clip->GetPlayStartSample();
3512 auto clipEnd = clip->GetPlayEndSample();
3514 if (clipEnd > start && clipStart < start+len)
3517 if (clip->GetStretchRatio() != 1.0)
3521 auto samplesToCopy =
3522 std::min( start+len - clipStart, clip->GetVisibleSampleCount() );
3523 auto startDelta = clipStart - start;
3524 decltype(startDelta) inclipDelta = 0;
3527 inclipDelta = -startDelta;
3528 samplesToCopy -= inclipDelta;
3544 format, inclipDelta, samplesToCopy.as_size_t(), effectiveFormat );
3545 clip->MarkChanged();
3554 const auto accumulate = [&](
const WaveTrack &track) {
3555 for (
const auto &pClip : track.GetClips())
3556 for (
size_t ii = 0, width = pClip->GetWidth(); ii < width; ++ii)
3557 result = std::max(result,
3558 pClip->GetSequence(ii)->GetSampleFormats().Effective());
3562 accumulate(*channel);
3575 auto &clips = pTrack->GetClips();
3576 return std::all_of(clips.begin(), clips.end(),
3577 [](
const auto &pClip){ return pClip->GetEnvelope()->IsTrivial(); });
3581 double* buffer,
size_t bufferLen,
double t0,
bool backwards)
const
3600 for (
decltype(bufferLen) i = 0; i < bufferLen; i++)
3605 double startTime = t0;
3607 auto tstep = 1.0 / rate;
3608 double endTime = t0 + tstep * bufferLen;
3609 for (
const auto &clip: pTrack->mClips)
3612 auto dClipStartTime = clip->GetPlayStartTime();
3613 auto dClipEndTime = clip->GetPlayEndTime();
3614 if ((dClipStartTime < endTime) && (dClipEndTime > startTime))
3617 auto rlen = bufferLen;
3620 if (rt0 < dClipStartTime)
3624 auto nDiff = (
sampleCount)floor((dClipStartTime - rt0) * rate + 0.5);
3625 auto snDiff = nDiff.as_size_t();
3627 wxASSERT(snDiff <= rlen);
3629 rt0 = dClipStartTime;
3632 if (rt0 + rlen*tstep > dClipEndTime)
3634 auto nClipLen = clip->GetPlayEndSample() - clip->GetPlayStartSample();
3645 rlen =
std::min(rlen,
size_t(floor(0.5 + (dClipEndTime - rt0) / tstep)));
3649 clip->GetEnvelope()->GetValues(rbuf, rlen, rt0, tstep);
3653 std::reverse(buffer, buffer + bufferLen);
3659 const auto neighbour =
GetNextClip(clip, direction);
3663 return std::abs(clip.
GetPlayEndTime() - neighbour->GetPlayStartTime()) <
3678 std::as_const(*this).GetAdjacentClip(clip, direction));
3685 return const_cast<WaveClip*
>(std::as_const(*this).GetClipAtTime(time));
3692 const auto p = std::find(clips.begin(), clips.end(), &clip);
3693 if (p == clips.end())
3696 return p == clips.end() - 1 ? nullptr : *(p + 1);
3698 return p == clips.begin() ? nullptr : *(p - 1);
3705 for (
const auto& clip :
mClips)
3706 if (clip->IntersectsPlayRegion(t0, t1))
3707 intersectingClips.push_back(clip);
3708 return intersectingClips;
3715 std::as_const(*this).GetNextClip(clip, direction));
3721 auto p = std::find_if(
3722 clips.rbegin(), clips.rend(), [&](
const WaveClip*
const& clip) {
3723 return clip->WithinPlayRegion(time);
3731 if (p != clips.rend() && p != clips.rbegin() &&
3732 time == (*p)->GetPlayEndTime() &&
3733 (*p)->SharesBoundaryWithNextClip(*(p-1))) {
3737 return p != clips.rend() ? *p :
nullptr;
3746 WaveClip* clip = pTrack->GetClipAtTime(time);
3757 channel->CreateClip(offset,
name);
3763 auto clip = std::make_shared<WaveClip>(1,
3765 clip->SetName(
name);
3766 clip->SetSequenceStartTime(offset);
3769 if (tempo.has_value())
3770 clip->OnProjectTempoChange(std::nullopt, *tempo);
3771 mClips.push_back(std::move(clip));
3773 auto result =
mClips.back().get();
3776 assert(result->GetWidth() ==
GetWidth());
3786 return mClips.back().get();
3797 auto it =
mClips.begin();
3798 WaveClip *rightmost = (*it++).get();
3804 if (maxOffset < offset)
3805 maxOffset = offset, rightmost = clip;
3820 if(index < (
int)
mClips.size())
3821 return mClips[index].get();
3840 const auto firstIn = std::lower_bound(clips.begin(), clips.end(), t0,
3841 [](
const auto& clip,
double t0) {
3842 return clip->GetPlayEndTime() <= t0;
3845 const auto firstOut = std::lower_bound(firstIn, clips.end(), t1,
3846 [](
const auto& clip,
double t1) {
3847 return clip->GetPlayStartTime() < t1;
3849 return std::distance(firstIn, firstOut);
3853 const std::vector<WaveClip*> &clips,
3855 double *allowedAmount )
3858 *allowedAmount = amount;
3860 const auto &moving = [&](
WaveClip *clip){
3863 return clips.end() != std::find( clips.begin(), clips.end(), clip );
3866 for (
const auto &c:
mClips) {
3867 if ( moving( c.get() ) )
3869 for (
const auto clip : clips) {
3870 if (c->GetPlayStartTime() < clip->GetPlayEndTime() + amount &&
3871 c->GetPlayEndTime() > clip->GetPlayStartTime() + amount)
3878 if (c->GetPlayStartTime() - clip->GetPlayEndTime() < *allowedAmount)
3879 *allowedAmount = c->GetPlayStartTime() - clip->GetPlayEndTime();
3880 if (*allowedAmount < 0)
3884 if (c->GetPlayEndTime() - clip->GetPlayStartTime() > *allowedAmount)
3885 *allowedAmount = c->GetPlayEndTime() - clip->GetPlayStartTime();
3886 if (*allowedAmount > 0)
3895 if (*allowedAmount == amount)
3911 const WaveClip& candidateClip,
double& slideBy,
double tolerance)
const
3917 const auto candidateClipEndTime = candidateClip.
GetPlayEndTime();
3918 const auto t0 =
SnapToSample(candidateClipStartTime + slideBy);
3919 const auto t1 =
SnapToSample(candidateClipEndTime + slideBy);
3920 std::vector<double> overlaps;
3922 mClips.begin(),
mClips.end(), std::back_inserter(overlaps),
3923 [&](
const auto& pClip) {
3924 return pClip->IntersectsPlayRegion(t0, t1) ?
3925 std::min(pClip->GetPlayEndTime(), t1) -
3926 std::max(pClip->GetPlayStartTime(), t0) :
3929 const auto maxOverlap = std::max_element(overlaps.begin(), overlaps.end());
3930 if (*maxOverlap > tolerance)
3932 const auto overlappedClip =
3933 mClips[std::distance(overlaps.begin(), maxOverlap)];
3934 const auto requiredOffset = slideBy +
3935 *maxOverlap * (overlappedClip->GetPlayStartTime() < t0 ? 1 : -1);
3939 [&](
const auto& pClip)
3941 const auto result = pClip->IntersectsPlayRegion(
3942 SnapToSample(candidateClipStartTime + requiredOffset),
3943 SnapToSample(candidateClipEndTime + requiredOffset));
3947 slideBy = requiredOffset;
3956 pChannel->SplitAt(t0);
3958 pChannel->SplitAt(t1);
3965 for (
const auto &c :
mClips)
3967 if (c->SplitsPlayRegion(t))
3970 auto newClip = std::make_shared<WaveClip>(*c,
mpFactory,
true);
3972 newClip->TrimLeftTo(t);
3989 pChannel->ExpandOneCutLine(cutLinePosition, cutlineStart, cutlineEnd);
3991 cutlineStart = cutlineEnd =
nullptr;
3997 double* cutlineStart,
double* cutlineEnd)
4002 double start = 0,
end = 0;
4003 auto pEnd =
mClips.end();
4004 auto pClip = std::find_if(
mClips.begin(), pEnd,
4006 return clip->FindCutLine(cutLinePosition, &start, &end); } );
4009 auto &clip = *pClip;
4010 if (!editClipCanMove)
4014 for (
const auto &clip2:
mClips)
4016 if (clip2->GetPlayStartTime() > clip->GetPlayStartTime() &&
4017 clip->GetPlayEndTime() +
end - start > clip2->GetPlayStartTime())
4021 XO(
"There is not enough room available to expand the cut line"),
4023 "Error:_Insufficient_space_in_track"
4028 clip->ExpandCutLine(cutLinePosition);
4033 *cutlineStart = start;
4038 if (editClipCanMove)
4040 for (
const auto &clip2 :
mClips)
4042 if (clip2->GetPlayStartTime() > clip->GetPlayStartTime())
4043 clip2->ShiftBy(
end - start);
4053 bool removed =
false;
4055 for (
const auto &clip : pChannel->mClips)
4056 if (clip->RemoveCutLine(cutLinePosition)) {
4068 return std::all_of(channels.begin(), channels.end(),
4069 [&](
const auto pChannel){
4070 return pChannel->MergeOneClipPair(clipidx1, clipidx2); });
4079 if (!clip1 || !clip2)
4083 if (!stretchRatiosEqual)
4100 const std::vector<IntervalHolder>& srcIntervals,
4103 std::vector<IntervalHolder> dstIntervals;
4104 dstIntervals.reserve(srcIntervals.size());
4106 srcIntervals.begin(), srcIntervals.end(),
4107 std::back_inserter(dstIntervals), [&](
const IntervalHolder& interval) {
4108 return interval->GetStretchRenderedCopy(
4109 reportProgress, *this, mpFactory, GetSampleFormat());
4114 for (
auto i = 0; i < srcIntervals.size(); ++i)
4124 const auto clip = interval->GetClip(channel++);
4126 pChannel->InsertClip(clip);
4136 const auto clip = interval->GetClip(channel);
4138 pChannel->RemoveAndReturnClip(clip.get());
4147 assert(oldOne->NChannels() == newOne->NChannels());
4150 newOne->SetName(oldOne->GetName());
4158 for (
const auto &clip : pChannel->mClips)
4159 clip->Resample(rate, progress);
4169 const auto myProgress = [&](
double fraction){
4170 return progress((count + fraction) / range.size());
4172 for (
const auto pChannel : range) {
4173 if (!
ReverseOne(*pChannel, start, len, myProgress))
4187 auto end = start + len;
4192 const auto &clips = track.
GetClips();
4195 for (
size_t ii = 0; ii < clips.size(); ++ii) {
4196 const auto &clip = clips[ii].get();
4197 auto clipStart = clip->GetPlayStartSample();
4198 auto clipEnd = clip->GetPlayEndSample();
4199 if (clipStart < start && clipEnd > start && clipEnd <=
end) {
4204 else if (clipStart >= start && clipStart < end && clipEnd >
end) {
4209 else if (clipStart < start && clipEnd >
end) {
4222 bool checkedFirstClip =
false;
4226 auto currentEnd =
end;
4233 for (
size_t i = 0; i < clipArray.size(); ++i) {
4238 if (clipStart >= start && clipEnd <=
end) {
4244 if (!checkedFirstClip && clipStart > start) {
4245 checkedFirstClip =
true;
4247 if (clipArray[i - 1]->GetPlayEndSample() <= start)
4248 currentEnd -= (clipStart - start);
4251 currentEnd -= (clipStart - start);
4254 auto revStart = std::max(clipStart, start);
4256 auto revLen = revEnd - revStart;
4257 if (revEnd >= revStart) {
4266 auto clipOffsetStart = currentEnd - (clipEnd - clipStart);
4268 if (i + 1 < clipArray.size()) {
4270 auto nextClipStart = clipArray[i + 1]->GetPlayStartSample();
4271 currentEnd = currentEnd -
4272 (clipEnd - clipStart) - (nextClipStart - clipEnd);
4278 revClips.back()->SetPlayStartTime(
4282 else if (clipStart >=
end) {
4294 for (
auto it = revClips.rbegin(), revEnd = revClips.rend();
4295 rValue && it != revEnd; ++it)
4301 for (
auto &clip : otherClips)
4302 if (!(rValue = track.
AddClip(clip)))
4318 Floats buffer1{ blockSize };
4319 const auto pBuffer1 = buffer1.get();
4320 Floats buffer2{ blockSize };
4321 const auto pBuffer2 = buffer2.get();
4323 auto originalLen = originalEnd - originalStart;
4328 auto second = first + (len - block);
4330 track.
GetFloats(buffer1.get(), first, block);
4331 std::reverse(pBuffer1, pBuffer1 + block);
4332 track.
GetFloats(buffer2.get(), second, block);
4333 std::reverse(pBuffer2, pBuffer2 + block);
4335 const bool success =
4348 2 * (first - originalStart).as_double() / originalLen.as_double()
4359 template <
typename Cont1,
typename Cont2 >
4363 for (
const auto &clip : mClips)
4364 clips.push_back(clip.get());
4365 std::sort(clips.begin(), clips.end(),
4367 { return a->GetPlayStartTime() < b->GetPlayStartTime(); });
4374 return FillSortedClipArray<WaveClipPointers>(
mClips);
4379 return FillSortedClipArray<WaveClipConstPointers>(
mClips);
4386 for (
const auto& clip : pChannel->GetClips())
4387 if (clip->GetTrimLeft() != 0 || clip->GetTrimRight() != 0)
4396 for (
auto clip : pChannel->GetClips()) {
4397 if (clip->GetTrimLeft() != 0) {
4398 auto t0 = clip->GetPlayStartTime();
4399 clip->SetTrimLeft(0);
4400 clip->ClearLeft(t0);
4402 if (clip->GetTrimRight() != 0) {
4403 auto t1 = clip->GetPlayEndTime();
4404 clip->SetTrimRight(0);
4405 clip->ClearRight(t1);
4415 if ( !mStack.empty() ) {
4416 auto &pair = mStack.back();
4417 if ( ++pair.first == pair.second ) {
4421 push( (*pair.first)->GetCutLines() );
4429 auto pClips = &clips;
4430 while (!pClips->empty()) {
4431 auto first = pClips->begin();
4432 mStack.push_back(
Pair( first, pClips->end() ) );
4433 pClips = &(*first)->GetCutLines();
4443 for (
const auto &clip : pChannel->GetAllClips())
4445 for (
size_t ii = 0, width = clip->GetWidth(); ii < width; ++ii) {
4446 auto blocks = clip->GetSequenceBlockArray(ii);
4447 for (
const auto &block : *blocks) {
4448 auto &pBlock = block.sb;
4450 if (pIDs && !pIDs->insert(pBlock->GetBlockID()).second)
4467 return std::make_shared< WaveTrackFactory >(
4506 for (
const auto& clip : pChannel->GetAllClips())
4507 if (clip->GetTrimLeft() > 0.0 || clip->GetTrimRight() > 0.0)
4508 return { 3, 1, 0, 0 };
4520 for (
const auto& clip : pChannel->GetAllClips())
4521 if (clip->GetStretchRatio() != 1.0)
4522 return { 3, 4, 0, 0 };
4529 L
"/GUI/TrackNames/DefaultTrackName",
4543 bool editClipsCanMove;
4548 L
"/GUI/EditClipCanMove",
false };
@ BadUserAction
Indicates that the user performed an action that is not allowed.
std::vector< std::shared_ptr< const ClipInterface > > ClipConstHolders
An audio segment is either a whole clip or the silence between clips. Views allow shared references t...
std::vector< AudioSegmentSampleView > ChannelSampleView
Toolkit-neutral facade for basic user interface services.
EffectDistortionSettings params
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::vector< std::vector< AudioSegmentSampleView > > ChannelGroupSampleView
an object holding per-project preferred sample rate
std::shared_ptr< SampleBlockFactory > SampleBlockFactoryPtr
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
BoolSetting SyncLockTracks
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper,...
std::function< void(double)> ProgressReporter
std::shared_ptr< TrackList > TrackListHolder
std::shared_ptr< WaveClip > WaveClipHolder
std::vector< WaveClipHolder > WaveClipHolders
std::vector< std::shared_ptr< const WaveClip > > WaveClipConstHolders
bool GetEditClipsCanMove()
static ProjectFileIORegistry::ObjectReaderEntry readerEntry
static const AudacityProject::AttachedObjects::RegisteredFactory key2
DEFINE_XML_METHOD_REGISTRY(WaveTrackIORegistry)
BoolSetting EditClipsCanMove
static auto TrackFactoryFactory
void VisitBlocks(TrackList &tracks, BlockVisitor visitor, SampleBlockIDSet *pIDs)
StringSetting AudioTrackNameSetting
void InspectBlocks(const TrackList &tracks, BlockInspector inspector, SampleBlockIDSet *pIDs)
static const Track::TypeInfo & typeInfo()
std::function< void(SampleBlock &) > BlockVisitor
#define WAVETRACK_MERGE_POINT_TOLERANCE
std::unordered_set< SampleBlockID > SampleBlockIDSet
std::function< void(const SampleBlock &) > BlockInspector
std::vector< WaveClip * > WaveClipPointers
std::vector< const WaveClip * > WaveClipConstPointers
std::vector< Attribute > AttributesList
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Abstraction of a progress dialog with well defined time-to-completion estimate.
This specialization of Setting for bool adds a Toggle method to negate the saved value.
double GetEndTime() const
Get the maximum of End() values of intervals, or 0 when none.
double GetStartTime() const
Get the minimum of Start() values of intervals, or 0 when none.
LinkType
For two tracks describes the type of the linkage.
@ Group
compatibility with projects that were generated by older versions of Audacity
@ Aligned
Tracks are grouped and changes should be synchronized.
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Subclass * Find(const RegisteredFactory &key)
Get a (bare) pointer to an attachment, or null, down-cast it to Subclass *; will not create on demand...
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
Piecewise linear or piecewise exponential function from double to double.
void SetOffset(double newOffset)
void CollapseRegion(double t0, double t1, double sampleDur)
No change to time at all.
bool HandleXMLAttribute(const std::string_view &attr, const XMLAttributeValueView &value)
static ProjectRate & Get(AudacityProject &project)
static SampleBlockFactoryPtr New(AudacityProject &project)
A WaveTrack contains WaveClip(s). A WaveClip contains a Sequence. A Sequence is primarily an interfac...
size_t GetIdealBlockSize() const
static bool IsValidSampleFormat(const int nValue)
true if nValue is one of the sampleFormat enum values
bool ReadWithDefault(T *pVar, const T &defaultValue) const
overload of ReadWithDefault returning a boolean that is true if the value was previously defined */
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined */
A MessageBoxException that shows a given, unvarying string.
Specialization of Setting for strings.
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.
void Notify(bool allChannels, int code=-1)
TrackList * GetHolder() const
std::shared_ptr< TrackList > GetOwner() const
virtual bool LinkConsistencyFix(bool doFix=true)
Check consistency of channel groups, and maybe fix it.
void SetLinkType(LinkType linkType, bool completeList=true)
std::shared_ptr< Subclass > SharedPointer()
bool IsLeader() const override
std::shared_ptr< Track > Holder
bool HandleCommonXMLAttribute(const std::string_view &attr, const XMLAttributeValueView &valueView)
virtual TrackListHolder Duplicate() const
public nonvirtual duplication function that invokes Clone()
ChannelGroupData & GetGroupData()
const wxString & GetName() const
Name is always the same for all channels of a group.
void Init(const Track &orig)
void OnProjectTempoChange(double newTempo)
method to set project tempo on track
LinkType GetLinkType() const noexcept
const std::optional< double > & GetProjectTempo() const
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
static TrackListHolder Create(AudacityProject *pOwner)
TrackKind * Add(const std::shared_ptr< TrackKind > &t)
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
static TrackListHolder Temporary(AudacityProject *pProject, const Track::Holder &left={}, const Track::Holder &right={})
ChannelSampleView GetSampleView(double t0, double t1, bool mayThrow) const
Request channel samples within [t0, t1), not knowing in advance how many this will be.
std::pair< float, float > GetMinMax(double t0, double t1, bool mayThrow=true) const
bool Set(constSamplePtr buffer, sampleFormat format, sampleCount start, size_t len, sampleFormat effectiveFormat=widestSampleFormat)
Random-access assignment of a range of samples.
bool Append(constSamplePtr buffer, sampleFormat format, size_t len)
float GetRMS(double t0, double t1, bool mayThrow=true) const
Get root-mean-square.
bool AppendBuffer(constSamplePtr buffer, sampleFormat format, size_t len, unsigned stride, sampleFormat effectiveFormat)
double GetStretchRatio() const override
constSamplePtr GetAppendBuffer() const
size_t GetAppendBufferLen() const
double GetTrimLeft() const
const Sequence & GetSequence() const
double GetTrimRight() const
bool Intersects(double t0, double t1) const
double GetPlayStartTime() const override
sampleCount GetVisibleSampleCount() const override
const WaveClip & GetNarrowClip() const
int GetRate() const override
int GetColourIndex() const
~WaveChannelInterval() override
sampleCount TimeToSamples(double time) const override
double GetPlayEndTime() const override
bool GetSamples(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, bool mayThrow=true) const
const Envelope & GetEnvelope() const
AudioSegmentSampleView GetSampleView(double t0, double t1, bool mayThrow) const
Request interval samples within [t0, t1). t0 and t1 are truncated to the interval start and end....
This allows multiple clips to be a part of one WaveTrack.
double GetStretchRatio() const override
double GetSequenceStartTime() const noexcept
void SetSequenceStartTime(double startTime)
sampleCount TimeToSamples(double time) const override
void ShiftBy(double delta) noexcept
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
int GetRate() const override
double GetTrimLeft() const noexcept
Returns the play start offset in seconds from the beginning of the underlying sequence.
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
sampleCount GetPlayStartSample() const
Real start time of the clip, quantized to raw sample rate (track's rate)
void HandleXMLEndTag(const std::string_view &tag) override
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.
void SetTrimRight(double trim)
Sets the play end offset in seconds from the ending of the underlying sequence.
double SamplesToTime(sampleCount s) const noexcept
double GetPlayDuration() const
bool HasEqualStretchRatio(const WaveClip &other) const
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 SetTrimLeft(double trim)
Sets the play start offset in seconds from the beginning of the underlying sequence.
Sequence * GetSequence(size_t ii)
bool Paste(double t0, const WaveClip &other)
size_t GetAppendBufferLen() const
int GetColourIndex() const
size_t GetWidth() const override
void Flush()
Flush must be called after last Append.
std::pair< Iterator, Iterator > Pair
void push(WaveClipHolders &clips)
AllClipsIterator & operator++()
void ForEachClip(const std::function< void(WaveClip &)> &op)
double GetTrimRight() const
double SamplesToTime(sampleCount s) const
double GetTrimLeft() const
bool WithinPlayRegion(double t) const
double GetPlayStartTime() const
double GetPlayEndTime() const
void SetTrimRight(double t)
bool IsPlaceholder() const
void SetTrimLeft(double t)
double GetStretchRatio() const
std::shared_ptr< Interval > GetStretchRenderedCopy(const std::function< void(double)> &reportProgress, const ChannelGroup &group, const SampleBlockFactoryPtr &factory, sampleFormat format)
void SetEnvelope(const Envelope &envelope)
bool IntersectsPlayRegion(double t0, double t1) const
void SetSequenceStartTime(double t)
std::shared_ptr< ChannelInterval > DoGetChannel(size_t iChannel) override
Retrieve a channel.
const wxString & GetName() const
Interval(const ChannelGroup &group, const std::shared_ptr< WaveClip > &pClip, const std::shared_ptr< WaveClip > &pClip1)
sampleCount TimeToSamples(double time) const
void TrimRightTo(double t)
double GetSequenceStartTime() const
void SetPlayStartTime(double time)
void ClearRight(double t)
void SetColorIndex(int index)
const Envelope & GetEnvelope() const
int GetColorIndex() const
bool StretchRatioEquals(double value) const
double GetSequenceEndTime() const
void TrimLeftTo(double t)
void Append(constSamplePtr buffer[], sampleFormat format, size_t len)
void SetName(const wxString &name)
void StretchLeftTo(double t)
void StretchRightTo(double t)
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
std::shared_ptr< WaveTrack > Create()
Creates an unnamed empty WaveTrack with default sample format and default rate.
static void Destroy(AudacityProject &project)
static WaveTrackFactory & Get(AudacityProject &project)
static WaveTrackFactory & Reset(AudacityProject &project)
A Track that contains audio waveform data.
void HandleXMLEndTag(const std::string_view &tag) override
std::pair< size_t, size_t > GetFloatsCenteredAroundTime(double t, size_t iChannel, float *buffer, size_t numSideSamples, bool mayThrow) const
Gets as many samples as it can, but no more than 2 * numSideSamples + 1, centered around t....
SampleBlockFactoryPtr mpFactory
bool MergeClips(int clipidx1, int clipidx2)
bool GetMute() const override
May vary asynchronously.
bool HasHiddenData() const
Whether any clips have hidden audio.
void SetRate(double newRate)
const WaveClip * GetClipAtTime(double time) const
void DoSetPan(float value)
TrackListHolder Clone() const override
size_t GetWidth() const
The width of every WaveClip in this track; for now always 1.
static WaveTrack * New(AudacityProject &project)
ChannelGroup & DoGetChannelGroup() const override
Subclass must override.
void SplitDelete(double t0, double t1)
std::vector< Region > Regions
void SetFloatsFromTime(double t, size_t iChannel, const float *buffer, size_t numSamples, sampleFormat effectiveFormat, PlaybackDirection direction)
Similar to GetFloatsFromTime, but for writing. Sets as many samples as it can according to the same r...
bool InsertClip(WaveClipHolder clip)
void Silence(double t0, double t1, ProgressReporter reportProgress) override
bool AddClip(const std::shared_ptr< WaveClip > &clip)
bool DoGet(size_t iChannel, size_t nBuffers, const samplePtr buffers[], sampleFormat format, sampleCount start, size_t len, bool backwards, fillFormat fill=FillFormat::fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const override
This fails if any clip overlapping the range has non-unit stretch ratio!
WaveClipConstHolders GetClipsIntersecting(double t0, double t1) const
void Reinit(const WaveTrack &orig)
bool CanOffsetClips(const std::vector< WaveClip * > &clips, double amount, double *allowedAmount=nullptr)
Decide whether the clips could be offset (and inserted) together without overlapping other clips.
bool CloseLock() noexcept
Should be called upon project close. Not balanced by unlocking calls.
void SetFloatsCenteredAroundTime(double t, size_t iChannel, const float *buffer, size_t numSideSamples, sampleFormat effectiveFormat)
Similar to GetFloatsCenteredAroundTime, but for writing. Sets as many samples as it can according to ...
double GetStartTime() const override
Implement WideSampleSequence.
void ConvertToSampleFormat(sampleFormat format, const std::function< void(size_t)> &progressReport={})
TrackListHolder Cut(double t0, double t1) override
Create tracks and modify this track.
int mLegacyRate
used only during deserialization
void InsertSilence(double t, double len) override
WaveClipPointers SortedClipArray()
Track::Holder PasteInto(AudacityProject &project, TrackList &list) const override
void SetFloatsWithinTimeRange(double t0, double t1, size_t iChannel, const std::function< float(double sampleTime)> &producer, sampleFormat effectiveFormat)
Provides a means of setting clip values as a function of time. Included are closest sample to t0 up t...
void WriteXML(XMLWriter &xmlFile) const override
wxString MakeNewClipName() const
static bool ReverseOne(WaveTrack &track, sampleCount start, sampleCount len, const ProgressReport &report={})
size_t NIntervals() const override
used only during deserialization
WaveClip * CreateClip(double offset=.0, const wxString &name=wxEmptyString)
Create new clip and add it to this track.
static wxString GetDefaultAudioTrackNamePreference()
bool LinkConsistencyFix(bool doFix) override
Check consistency of channel groups, and maybe fix it.
static void PasteOne(WaveTrack &track, double t0, const WaveTrack &other, double startTime, double insertDuration, bool merge=true)
int GetWaveColorIndex() const
const WaveClip * GetNextClip(const WaveClip &clip, PlaybackDirection searchDirection) const
Returns clips next to clip in the given direction, or nullptr if there is none.
WaveClip * NewestOrNewClip()
Get access to the most recently added clip, or create a clip, if there is not already one....
IntervalConstHolder GetNextInterval(const Interval &interval, PlaybackDirection searchDirection) const
std::optional< TranslatableString > GetErrorOpening() const override
std::shared_ptr<::Channel > DoGetChannel(size_t iChannel) override
Retrieve a channel.
ChannelGroup & ReallyDoGetChannelGroup() const override
This is temporary! It defaults to call the above.
sampleFormat GetSampleFormat() const override
void Join(double t0, double t1, const ProgressReporter &reportProgress)
void ClearAndAddCutLine(double t0, double t1)
void SyncLockAdjust(double oldT1, double newT1) override
void ExpandOneCutLine(double cutLinePosition, double *cutlineStart, double *cutlineEnd)
const TypeInfo & GetTypeInfo() const override
std::function< bool(double)> ProgressReport
WaveClip * GetClipByIndex(int index)
Get the nth clip in this WaveTrack (will return nullptr if not found).
WaveTrack(const SampleBlockFactoryPtr &pFactory, sampleFormat format, double rate)
size_t GetIdealBlockSize()
void ApplyStretchRatio(std::optional< TimeInterval > interval, ProgressReporter reportProgress)
size_t CountBlocks() const
ChannelGroupSampleView GetSampleView(double t0, double t1, bool mayThrow=true) const
Request samples within [t0, t1), not knowing in advance how many this will be.
void ApplyStretchRatioOnIntervals(const std::vector< IntervalHolder > &intervals, const ProgressReporter &reportProgress)
void CreateWideClip(double offset=.0, const wxString &name=wxEmptyString)
static Holder CopyOne(const WaveTrack &track, double t0, double t1, bool forClipboard)
void Clear(double t0, double t1) override
void Init(const WaveTrack &orig)
void DoSetRate(double newRate)
std::shared_ptr< Interval > IntervalHolder
bool IsLeader() const override
void Split(double t0, double t1)
void ExpandCutLine(double cutLinePosition, double *cutlineStart=nullptr, double *cutlineEnd=nullptr)
bool RemoveCutLine(double cutLinePosition)
Remove cut line, without expanding the audio in it.
void DoOnProjectTempoChange(const std::optional< double > &oldTempo, double newTempo) override
void ReplaceInterval(const IntervalHolder &oldOne, const IntervalHolder &newOne)
size_t GetFloatsFromTime(double t, size_t iChannel, float *buffer, size_t numSamples, bool mayThrow, PlaybackDirection direction) const
Helper for GetFloatsCenteredAroundTime. If direction == PlaybackDirection::Backward,...
void SetWaveColorIndex(int colorIndex)
sampleCount GetSequenceSamplesCount() const
static void JoinOne(WaveTrack &track, double t0, double t1)
void SetFloatAtTime(double t, size_t iChannel, float value, sampleFormat effectiveFormat)
Sets sample nearest to t to value. Silently fails if GetClipAtTime(t) == nullptr.
bool IsEmpty(double t0, double t1) const
Returns true if there are no WaveClips in the specified region.
sampleFormat WidestEffectiveFormat() const override
void SetPan(float newPan)
XMLTagHandler * HandleXMLChild(const std::string_view &tag) override
bool HandleXMLTag(const std::string_view &tag, const AttributesList &attrs) override
static const TypeInfo & ClassTypeInfo()
void Paste(double t0, const Track &src) override
bool MergeOneClipPair(int clipidx1, int clipidx2)
void MoveTo(double o) override
void SetLegacyFormat(sampleFormat format)
std::shared_ptr< WaveClip > RemoveAndReturnClip(WaveClip *clip)
void Trim(double t0, double t1)
void Disjoin(double t0, double t1)
void InsertInterval(const IntervalHolder &interval)
TrackListHolder WideEmptyCopy(const SampleBlockFactoryPtr &pFactory={}, bool keepLink=true) const
void DoSetGain(float value)
void Resample(int rate, BasicUI::ProgressDialog *progress=NULL)
static void WriteOneXML(const WaveTrack &track, XMLWriter &xmlFile, size_t iChannel, size_t nChannels)
void SetClipRates(double newRate)
double GetEndTime() const override
Implement WideSampleSequence.
static void ClearAndPasteOne(WaveTrack &track, double t0, double t1, double startTime, double endTime, const WaveTrack &src, bool preserve, bool merge, const TimeWarper *effectWarper, bool clearByTrimming)
const WaveClip * FindClipByName(const wxString &name) const
Returns nullptr if clip with such name was not found.
const WaveClip * GetRightmostClip() const
std::shared_ptr< WideChannelGroupInterval > DoGetInterval(size_t iInterval) override
Retrieve an interval.
int GetClipIndex(const WaveClip *clip) const
AudioGraph::ChannelType GetChannelType() const override
Classify this channel.
bool FormatConsistencyCheck() const
Whether all tracks in group and all clips have a common sample format.
void SetGain(float newGain)
double GetRate() const override
WaveClip * RightmostOrNewClip()
Get access to the last (rightmost) clip, or create a clip, if there is not already one.
void ClearAndPasteAtSameTempo(double t0, double t1, const WaveTrack &src, bool preserve, bool merge, const TimeWarper *effectWarper, bool clearByTrimming)
TrackListHolder Copy(double t0, double t1, bool forClipboard=true) const override
Create new tracks and don't modify this track.
WaveClipHolders & GetClips()
TrackListHolder MonoToStereo()
bool RateConsistencyCheck() const
Whether all clips of a leader track have a common rate.
bool GetSolo() const override
May vary asynchronously.
bool GetFloatAtTime(double t, size_t iChannel, float &value, bool mayThrow) const
float GetChannelGain(int channel) const override
Takes gain and pan into account.
bool CanInsertClip(const WaveClip &clip, double &slideBy, double tolerance) const
const ChannelGroup * FindChannelGroup() const override
Find associated ChannelGroup if any.
ClipConstHolders GetClipInterfaces() const
Get access to the (visible) clips in the tracks, in unspecified order.
size_t NChannels() const override
May report more than one only when this is a leader track.
void DiscardTrimmed()
Remove hidden audio from all clips.
size_t GetMaxBlockSize() const
void PasteWaveTrackAtSameTempo(double t0, const WaveTrack &other, bool merge)
void GetEnvelopeValues(double *buffer, size_t bufferLen, double t0, bool backwards) const override
static bool ReverseOneClip(WaveTrack &track, sampleCount start, sampleCount len, sampleCount originalStart, sampleCount originalEnd, const ProgressReport &report={})
bool HasTrivialEnvelope() const override
const WaveClip * GetLeftmostClip() const
void PasteWaveTrack(double t0, const WaveTrack &other, bool merge)
double mLegacyProjectFileOffset
size_t GetBestBlockSize(sampleCount t) const
sampleFormat mLegacyFormat
used only during deserialization
std::shared_ptr< WaveTrack > Holder
bool Reverse(sampleCount start, sampleCount len, const ProgressReport &report={})
static double ProjectNyquistFrequency(const AudacityProject &project)
TrackListHolder DuplicateWithOtherTempo(double newTempo, WaveTrack *&leader) const
void ClearAndPaste(double t0, double t1, const WaveTrack &src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=nullptr, bool clearByTrimming=false)
const WaveClip * GetAdjacentClip(const WaveClip &clip, PlaybackDirection searchDirection) const
Similar to GetNextClip, but returns nullptr if the neighbour clip is not adjacent.
void RemoveInterval(const IntervalHolder &interval)
sampleCount GetVisibleSampleCount() const
Envelope * GetEnvelopeAtTime(double time)
bool GetOne(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, bool backwards, fillFormat fill, bool mayThrow, sampleCount *pNumWithinClips) const
Holder EmptyCopy(const SampleBlockFactoryPtr &pFactory={}, bool keepLink=true) const
bool Append(constSamplePtr buffer, sampleFormat format, size_t len, unsigned int stride=1, sampleFormat effectiveFormat=widestSampleFormat, size_t iChannel=0) override
void HandleClear(double t0, double t1, bool addCutLines, bool split, bool clearByTrimming=false)
wxString MakeClipCopyName(const wxString &originalName) const
bool GetFloats(float *buffer, sampleCount start, size_t len, fillFormat fill=FillFormat::fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const
"narrow" overload fetches first channel only
TrackListHolder SplitCut(double t0, double t1)
IntervalHolder GetIntervalAtTime(double t)
double LongSamplesToTime(sampleCount pos) const
sampleCount TimeToLongSamples(double t0) const
double SnapToSample(double t) const
static const TypeInfo & ClassTypeInfo()
static XMLMethodRegistry & Get()
Get the unique instance.
void CallWriters(const Host &host, XMLWriter &writer)
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...
virtual void StartTag(const wxString &name)
void WriteAttr(const wxString &name, const Identifier &value)
virtual void EndTag(const wxString &name)
Positions or offsets within audio files need a wide type.
ChannelType
Mutually exclusive channel classifications.
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
template struct REGISTRIES_API Cloneable<>
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
PROJECT_RATE_API sampleFormat SampleFormatChoice()
double GetRate(const Track &track)
void TrimLeftTo(WaveTrack::Interval &interval, double t)
void TrimRightTo(WaveTrack::Interval &interval, double t)
WaveClipHolders::iterator FindClip(WaveClipHolders &list, const WaveClip *clip, int *distance=nullptr)
std::conditional_t< std::is_const_v< std::remove_pointer_t< FloatType > >, constSamplePtr, samplePtr > BufferCharType
void RoundToNearestClipSample(const WaveTrack &track, double &t)
bool AreAligned(const WaveClipPointers &a, const WaveClipPointers &b)
ProjectFormatExtensionsRegistry::Extension smartClipsExtension([](const AudacityProject &project) -> ProjectFormatVersion { const TrackList &trackList=TrackList::Get(project);for(auto wt :trackList.Any< const WaveTrack >()) for(const auto pChannel :TrackList::Channels(wt)) for(const auto &clip :pChannel->GetAllClips()) if(clip->GetTrimLeft() > 0.0||clip->GetTrimRight() > 0.0) return { 3, 1, 0, 0 };return BaseProjectFormatVersion;})
SampleAccessArgs< BufferType > GetSampleAccessArgs(const WaveClip &clip, double startOrEndTime, BufferType buffer, size_t totalToRead, size_t alreadyRead, bool forward)
static const ChannelGroup::Attachments::RegisteredFactory waveTrackDataFactory
ProjectFormatExtensionsRegistry::Extension stretchedClipsExtension([](const AudacityProject &project) -> ProjectFormatVersion { const TrackList &trackList=TrackList::Get(project);for(auto wt :trackList.Any< const WaveTrack >()) for(const auto pChannel :TrackList::Channels(wt)) for(const auto &clip :pChannel->GetAllClips()) if(clip->GetStretchRatio() !=1.0) return { 3, 4, 0, 0 };return BaseProjectFormatVersion;})
Track::LinkType ToLinkType(int value)
Cont1 FillSortedClipArray(const Cont2 &mClips)
static RegisteredToolbarFactory factory
fastfloat_really_inline void round(adjusted_mantissa &am, callback cb) noexcept
__finl float_x4 __vecc sqrt(const float_x4 &a)
void copy(const T *src, T *dst, int32_t n)
float *const * Get() const
A convenient base class defining abstract virtual Clone() for a given kind of pointer.
"finally" as in The C++ Programming Language, 4th ed., p. 358 Useful for defining ad-hoc RAII actions...
Empty argument passed to some public constructors.
const BufferCharType< BufferType > offsetBuffer
std::optional< wxString > leftClipName
std::shared_ptr< WaveClip > right
std::optional< wxString > rightClipName
std::shared_ptr< WaveClip > left
~WaveTrackData() override
WaveTrackData & operator=(const WaveTrackData &)=delete
WaveTrackData(const WaveTrackData &)