70 std::unique_ptr<ClientData::Cloneable<>> Clone()
const override;
75 float GetGain()
const;
76 void SetGain(
float value);
78 void SetPan(
float value);
82 std::atomic<float> mGain{ 1.0f };
84 std::atomic<float> mPan{ 0.0f };
91GainAndPan::GainAndPan(
const GainAndPan &other) {
92 SetGain(other.GetGain());
93 SetPan(other.GetPan());
96GainAndPan::~GainAndPan() =
default;
98std::unique_ptr<ClientData::Cloneable<>> GainAndPan::Clone()
const {
99 return std::make_unique<GainAndPan>(*
this);
103 return track.
GetGroupData().Track::ChannelGroupAttachments
112float GainAndPan::GetGain()
const
114 return mGain.load(std::memory_order_relaxed);
117void GainAndPan::SetGain(
float value)
119 mGain.store(value, std::memory_order_relaxed);
122float GainAndPan::GetPan()
const
124 return mPan.load(std::memory_order_relaxed);
127void GainAndPan::SetPan(
float value)
129 mPan.store(value, std::memory_order_relaxed);
134 if (a.size() != b.size())
141 return a->GetPlayStartTime() == b->GetPlayStartTime() &&
142 a->GetSequenceStartTime() == b->GetSequenceStartTime() &&
143 a->GetPlayEndTime() == b->GetPlayEndTime() &&
144 a->GetSequenceEndTime() == b->GetSequenceEndTime();
147 return std::mismatch(a.begin(), a.end(), b.begin(), compare).first == a.end();
196 auto result = tracks.Add(trackFactory.Create());
197 result->AttachedTrackObjects::BuildAll();
204 , mpFactory(pFactory)
215 , mpFactory( orig.mpFactory )
218 for (
const auto &clip : orig.
mClips)
220 ( std::make_unique<WaveClip>( *clip,
mpFactory,
true ) );
267 for (
const auto &clip :
mClips)
279 if (
static_cast<int>(linkType) == 1 ||
283 if (next ==
nullptr) {
286 wxLogWarning(L
"Right track %s is expected to be a WaveTrack."
287 "\n Removing link from left wave track %s.",
298 if (newLinkType != linkType)
310 {
"wave",
"wave",
XO(
"Wave Track") },
325template<
typename Container >
329 for (
const auto &clip: clips) {
330 result.emplace_back( clip->GetPlayStartTime(), clip->GetPlayEndTime(),
331 std::make_unique<WaveTrack::IntervalData>( clip ) );
339 auto &pSampleBlockFactory = trackFactory.GetSampleBlockFactory();
340 auto pNewTrack =
EmptyCopy( pSampleBlockFactory );
341 pNewTrack->Paste(0.0,
this);
347 return MakeIntervals<ConstIntervals>(
mClips );
352 return MakeIntervals<Intervals>( mClips );
357 for (
const auto& clip :
mClips)
359 if (clip->GetName() ==
name)
374 auto name = originalName;
375 for (
auto i = 1;; ++i)
380 name =
XC(
"%s.%i",
"clip name template").Format(originalName, i).Translation();
387 for (
auto i = 1;; ++i)
392 name =
XC(
"%s %i",
"clip name template").Format(
GetName(), i).Translation();
403 wxASSERT( newRate > 0 );
404 newRate = std::max( 1.0, newRate );
405 auto ratio =
mRate / newRate;
406 mRate = (int) newRate;
407 for (
const auto &clip :
mClips) {
408 clip->SetRate((
int)newRate);
409 clip->SetSequenceStartTime( clip->GetSequenceStartTime() * ratio );
445 else if (newPan < -1.0)
448 if (
GetPan() != newPan ) {
459 const auto pan =
GetPan();
466 if ((channel%2) == 0)
475 for (
const auto &clip :
mClips)
476 clip->SetColourIndex( colorIndex );
484 for (
const auto& clip :
mClips)
485 result += clip->GetPlaySamplesCount();
494 for (
const auto& clip :
mClips)
495 result += clip->GetSequenceSamplesCount();
502 const std::function<
void(
size_t)> & progressReport)
504 for (
const auto& clip :
mClips)
505 clip->ConvertToSampleFormat(
format, progressReport);
516 for (
const auto &clip :
mClips)
518 if (!clip->BeforePlayStartTime(t1) && !clip->AfterPlayEndTime(t0)) {
537 auto tmp =
Copy(t0, t1);
551 auto tmp =
Copy(t0, t1);
559Track::Holder WaveTrack::CutAndAddCutLine(
double t0,
double t1)
565 auto tmp =
Copy(t0, t1);
580 bool inside0 =
false;
581 bool inside1 =
false;
583 for (
const auto &clip :
mClips)
585 if(t1 > clip->GetPlayStartTime() && t1 < clip->GetPlayEndTime())
587 clip->SetTrimRight(clip->GetTrimRight() + clip->GetPlayEndTime() - t1);
591 if(t0 > clip->GetPlayStartTime() && t0 < clip->GetPlayEndTime())
593 clip->SetTrimLeft(clip->GetTrimLeft() + t0 - clip->GetPlayStartTime());
613 auto result = std::make_shared<WaveTrack>( pFactory,
mFormat,
mRate );
615 result->mpFactory = pFactory ? pFactory :
mpFactory;
633 for (
const auto &clip :
mClips)
635 if (t0 <= clip->GetPlayStartTime() && t1 >= clip->GetPlayEndTime())
640 newTrack->
mClips.push_back
641 (std::make_unique<WaveClip>(*clip,
mpFactory, ! forClipboard));
645 else if (clip->CountSamples(t0, t1) >= 1)
650 auto newClip = std::make_unique<WaveClip>
651 (*clip,
mpFactory, ! forClipboard, t0, t1);
652 newClip->SetName(clip->GetName());
654 newClip->Offset(-t0);
655 if (newClip->GetPlayStartTime() < 0)
656 newClip->SetPlayStartTime(0);
658 newTrack->
mClips.push_back(std::move(newClip));
669 auto placeholder = std::make_unique<WaveClip>(
mpFactory,
671 static_cast<int>(newTrack->
GetRate()),
673 placeholder->SetIsPlaceholder(
true);
674 placeholder->InsertSilence(0, (t1 - t0) - newTrack->
GetEndTime());
676 newTrack->
mClips.push_back(std::move(placeholder));
711 std::shared_ptr<WaveClip>
left;
763 std::vector<SplitInfo> splits;
768 auto get_split = [&](
double time) {
769 auto it = std::find_if(splits.begin(), splits.end(), [time](
const SplitInfo& split) {
770 return split.time == time;
772 if(it == splits.end())
775 { time, nullptr, nullptr, std::nullopt, std::nullopt }
782 const TimeWarper *warper = (effectWarper ? effectWarper : &localWarper);
791 for (
const auto &clip :
mClips) {
798 if (st >= t0 && st <= t1) {
799 auto it = get_split(st);
800 if (clip->GetTrimLeft() != 0)
803 it->right = std::make_shared<WaveClip>(*clip,
mpFactory,
false);
804 it->right->SetTrimLeft(.0);
805 it->right->ClearRight(clip->GetPlayStartTime());
807 it->rightClipName = clip->GetName();
811 if (st >= t0 && st <= t1) {
812 auto it = get_split(st);
813 if (clip->GetTrimRight() != 0)
816 it->left = std::make_shared<WaveClip>(*clip,
mpFactory,
false);
817 it->left->SetTrimRight(.0);
818 it->left->ClearLeft(clip->GetPlayEndTime());
820 it->leftClipName = clip->GetName();
824 auto &cutlines = clip->GetCutLines();
826 for (
auto it = cutlines.begin(); it != cutlines.end(); ) {
832 if (cs >= t0 && cs <= t1) {
836 cuts.push_back(std::move(*it));
837 it = cutlines.erase(it);
844 const auto tolerance = 2.0 /
GetRate();
854 if (merge && splits.size() > 0)
866 for (
const auto clip : clips) {
869 if (fabs(t1 - clip->GetPlayStartTime()) < tolerance) {
886 for (
const auto clip : clips) {
894 if (fabs(t0 - clip->GetPlayEndTime()) < tolerance)
913 auto trim = src->GetPlayEndTime() - src->GetPlayStartTime();
927 auto trim = src->GetPlayEndTime() - src->GetPlayStartTime();
933 for (
const auto& split: splits) {
937 if (clip->WithinPlayRegion(at))
939 auto newClip = std::make_unique<WaveClip>(*clip,
mpFactory,
true);
941 clip->ClearRight(at);
942 newClip->ClearLeft(at);
944 attachRight(clip.get(), split.left.get());
946 attachLeft(newClip.get(), split.right.get());
952 attachLeft(clip.get(), split.right.get());
957 attachRight(clip.get(), split.left.get());
964 for (
const auto& split : splits)
969 if (split.rightClipName.has_value() && clip->GetPlayStartSample() == s)
970 clip->SetName(*split.rightClipName);
971 else if (split.leftClipName.has_value() && clip->GetPlayEndSample() == s)
972 clip->SetName(*split.leftClipName);
977 for (
const auto &clip :
mClips) {
981 st = clip->GetPlayStartTime();
982 et = clip->GetPlayEndTime();
985 for (
auto it = cuts.begin(); it != cuts.end();) {
992 if (cs >= st && cs <= et) {
994 clip->GetCutLines().push_back( std::move(*it) );
1008 bool addCutLines =
false;
1015 WaveClipHolders::const_iterator
1020 auto it = list.begin();
1021 for (
const auto end = list.end(); it !=
end; ++it)
1023 if (it->get() == clip)
1031 WaveClipHolders::iterator
1036 auto it = list.begin();
1037 for (
const auto end = list.end(); it !=
end; ++it)
1039 if (it->get() == clip)
1052 if (it !=
mClips.end()) {
1053 auto result = std::move(*it);
1063 if (clip->GetSequence()->GetFactory() != this->mpFactory)
1075 bool addCutLines,
bool split)
1079 wxASSERT( t1 >= t0 );
1092 for (
const auto &clip :
mClips)
1094 if (!clip->BeforePlayStartTime(t1) && !clip->AfterPlayEndTime(t0) &&
1095 (clip->BeforePlayStartTime(t0) || clip->AfterPlayEndTime(t1)))
1097 addCutLines =
false;
1103 for (
const auto &clip :
mClips)
1105 if (clip->BeforePlayStartTime(t0) && clip->AfterPlayEndTime(t1))
1108 clipsToDelete.push_back(clip.get());
1110 else if (!clip->BeforePlayStartTime(t1) && !clip->AfterPlayEndTime(t0))
1117 clipsToDelete.push_back( clip.get() );
1118 auto newClip = std::make_unique<WaveClip>( *clip,
mpFactory,
true );
1119 newClip->ClearAndAddCutLine( t0, t1 );
1120 clipsToAdd.push_back( std::move( newClip ) );
1127 if (clip->BeforePlayStartTime(t0)) {
1132 clipsToDelete.push_back( clip.get() );
1133 auto newClip = std::make_unique<WaveClip>( *clip,
mpFactory,
true );
1134 newClip->TrimLeft(t1 - clip->GetPlayStartTime());
1135 clipsToAdd.push_back( std::move( newClip ) );
1137 else if (clip->AfterPlayEndTime(t1)) {
1142 clipsToDelete.push_back( clip.get() );
1143 auto newClip = std::make_unique<WaveClip>( *clip,
mpFactory,
true );
1144 newClip->TrimRight(clip->GetPlayEndTime() - t0);
1146 clipsToAdd.push_back( std::move( newClip ) );
1152 auto leftClip = std::make_unique<WaveClip>(*clip,
mpFactory,
true);
1153 leftClip->TrimRight(clip->GetPlayEndTime() - t0);
1154 clipsToAdd.push_back(std::move(leftClip));
1156 auto rightClip = std::make_unique<WaveClip>(*clip,
mpFactory,
true);
1157 rightClip->TrimLeft(t1 - rightClip->GetPlayStartTime());
1158 clipsToAdd.push_back(std::move(rightClip));
1160 clipsToDelete.push_back(clip.get());
1168 clipsToDelete.push_back( clip.get() );
1169 auto newClip = std::make_unique<WaveClip>( *clip,
mpFactory,
true );
1172 newClip->Clear(t0,t1);
1174 clipsToAdd.push_back( std::move( newClip ) );
1183 if (!split && editClipCanMove)
1187 for (
const auto& clip :
mClips)
1189 if (clip->BeforePlayStartTime(t1))
1190 clip->Offset(-(t1 - t0));
1194 for (
const auto &clip: clipsToDelete)
1197 if (myIt !=
mClips.end())
1203 for (
auto &clip: clipsToAdd)
1204 mClips.push_back(std::move(clip));
1209 if (newT1 > oldT1) {
1223 const auto offset = newT1 - oldT1;
1224 for(
const auto& clip :
mClips)
1226 if (clip->GetPlayStartTime() > oldT1 - (1.0 /
mRate))
1227 clip->Offset(offset);
1235 auto tmp = std::make_shared<WaveTrack>(
1238 tmp->InsertSilence(0.0, newT1 - oldT1);
1240 Paste(oldT1, tmp.get());
1243 else if (newT1 < oldT1) {
1244 Clear(newT1, oldT1);
1276 bool singleClipMode = other->
GetNumClips() == 1 &&
1279 const double insertDuration = other->
GetEndTime();
1280 if (insertDuration != 0 && insertDuration < 1.0 /
mRate)
1289 auto pastingFromTempTrack = !other->
GetOwner();
1293 if (editClipCanMove) {
1294 if (!singleClipMode) {
1301 for (
const auto& clip :
mClips)
1303 if (clip->GetPlayStartTime() > t0 - (1.0 /
mRate))
1304 clip->Offset(insertDuration);
1315 for (
const auto& clip :
mClips)
1317 if (editClipCanMove)
1319 if (clip->WithinPlayRegion(t0))
1323 insideClip = clip.get();
1330 if (clip->WithinPlayRegion(t0) ||
1333 insideClip = clip.get();
1343 if (!editClipCanMove)
1347 for (
const auto& clip :
mClips)
1351 clip->GetPlayStartTime())
1356 XO(
"There is not enough room available to paste the selection"),
1358 "Error:_Insufficient_space_in_track"
1371 if (!editClipCanMove && !
IsEmpty(t0, t0 + insertDuration - 1.0 /
mRate))
1376 XO(
"There is not enough room available to paste the selection"),
1378 "Error:_Insufficient_space_in_track"
1381 for (
const auto& clip : other->
mClips)
1384 if (!clip->GetIsPlaceholder())
1387 std::make_unique<WaveClip>(*clip,
mpFactory,
true);
1388 newClip->Resample(
mRate);
1389 newClip->Offset(t0);
1390 newClip->MarkChanged();
1391 if (pastingFromTempTrack)
1397 mClips.push_back(std::move(newClip));
1405 if (
auto other =
dynamic_cast<const WaveTrack*
>(src))
1420 for (
const auto &clip :
mClips)
1422 auto clipStart = clip->GetPlayStartSample();
1423 auto clipEnd = clip->GetPlayEndSample();
1425 if (clipEnd > start && clipStart <
end)
1427 auto offset = std::max(start - clipStart,
sampleCount(0));
1429 auto length =
std::min(
end, clipEnd) - (clipStart + offset);
1431 clip->SetSilence(offset, length);
1450 clip->InsertSilence(0, len);
1452 mClips.push_back( std::move( clip ) );
1458 const auto it = std::find_if(
mClips.begin(),
end,
1459 [&](
const WaveClipHolder &clip) { return clip->WithinPlayRegion(t); } );
1463 it->get()->InsertSilence(t, len);
1466 for (
const auto &clip :
mClips)
1468 if (clip->BeforePlayStartTime(t))
1480 const size_t maxAtOnce = 1048576;
1481 Floats buffer{ maxAtOnce };
1484 for (
const auto &clip :
mClips)
1486 double startTime = clip->GetPlayStartTime();
1487 double endTime = clip->GetPlayEndTime();
1489 if( endTime < t0 || startTime > t1 )
1496 auto start = clip->TimeToSamples(std::max(.0, t0 - startTime));
1497 auto end = clip->TimeToSamples(
std::min(endTime, t1) - startTime);
1499 auto len = (
end - start );
1500 for(
decltype(len) done = 0; done < len; done += maxAtOnce )
1506 for(
decltype(numSamples) i = 0; i < numSamples; i++ )
1508 auto curSamplePos = start + done + i;
1511 if( buffer[ i ] == 0.0 && seqStart == -1 )
1512 seqStart = curSamplePos;
1513 else if( buffer[ i ] != 0.0 || curSamplePos ==
end - 1 )
1515 if( seqStart != -1 )
1517 decltype(
end) seqEnd;
1520 if( curSamplePos ==
end - 1 && buffer[ i ] == 0.0 )
1523 seqEnd = curSamplePos;
1524 if( seqEnd - seqStart + 1 > minSamples )
1528 startTime + clip->SamplesToTime(seqStart),
1529 startTime + clip->SamplesToTime(seqEnd)
1540 for(
unsigned int i = 0; i < regions.size(); i++ )
1542 const Region ®ion = regions.at(i);
1555 for (
const auto &clip:
mClips)
1557 if (clip->GetPlayStartTime() < t1-(1.0/
mRate) &&
1558 clip->GetPlayEndTime()-(1.0/
mRate) > t0) {
1561 auto it = clipsToDelete.begin(),
end = clipsToDelete.end();
1562 for (; it !=
end; ++it)
1563 if ((*it)->GetPlayStartTime() > clip->GetPlayStartTime())
1566 clipsToDelete.insert(it, clip.get());
1571 if( clipsToDelete.size() == 0 )
1574 auto t = clipsToDelete[0]->GetPlayStartTime();
1576 newClip =
CreateClip(clipsToDelete[0]->GetSequenceStartTime(),
1579 for (
const auto &clip : clipsToDelete)
1584 if (clip->GetPlayStartTime() - t > (1.0 /
mRate)) {
1585 double addedSilence = (clip->GetPlayStartTime() - t);
1587 auto offset = clip->GetPlayStartTime();
1588 auto value = clip->GetEnvelope()->GetValue( offset );
1589 newClip->AppendSilence( addedSilence, value );
1594 newClip->Paste(t, clip);
1596 t = newClip->GetPlayEndTime();
1607 size_t len,
unsigned int stride,
sampleFormat effectiveFormat)
1610 ->
Append(buffer,
format, len, stride, effectiveFormat);
1615 for (
const auto &clip :
mClips)
1617 const auto startSample = clip->GetPlayStartSample();
1618 const auto endSample = clip->GetPlayEndSample();
1619 if (s >= startSample && s < endSample)
1621 auto blockStartOffset = clip->GetSequence()->GetBlockStart(clip->ToSequenceSamples(s));
1622 return std::max(startSample, clip->GetSequenceStartSample() + blockStartOffset);
1633 for (
const auto &clip :
mClips)
1635 auto startSample = clip->GetPlayStartSample();
1636 auto endSample = clip->GetPlayEndSample();
1637 if (s >= startSample && s < endSample)
1639 bestBlockSize = clip->GetSequence()->GetBestBlockSize(s - clip->GetSequenceStartSample());
1644 return bestBlockSize;
1650 for (
const auto &clip :
mClips)
1652 maxblocksize = std::max(maxblocksize, clip->GetSequence()->GetMaxBlockSize());
1655 if (maxblocksize == 0)
1664 wxASSERT(maxblocksize > 0);
1666 return maxblocksize;
1687 if (tag ==
"wavetrack") {
1691 for (
auto pair : attrs)
1693 auto attr = pair.first;
1694 auto value = pair.second;
1699 if (!value.TryGet(dblValue) ||
1700 (dblValue < 1.0) || (dblValue > 1000000.0))
1705 else if (attr ==
"offset" && value.TryGet(dblValue))
1716 else if (attr ==
"gain" && value.TryGet(dblValue))
1718 else if (attr ==
"pan" && value.TryGet(dblValue) &&
1719 (dblValue >= -1.0) && (dblValue <= 1.0))
1721 else if (attr ==
"linked" && value.TryGet(nValue))
1723 else if (attr ==
"colorindex" && value.TryGet(nValue))
1726 else if (attr ==
"sampleformat" && value.TryGet(nValue) &&
1746 .CallObjectAccessor(tag, *
this) )
1752 if (tag ==
"sequence" || tag ==
"envelope")
1758 if (tag ==
"sequence")
1760 else if (tag ==
"envelope")
1766 if (tag ==
"waveblock")
1777 if (tag ==
"waveclip")
1786 xmlFile.StartTag(
wxT(
"wavetrack"));
1788 xmlFile.WriteAttr(
wxT(
"linked"),
static_cast<int>(GetLinkType()));
1790 xmlFile.WriteAttr(
wxT(
"rate"), mRate);
1795 xmlFile.WriteAttr(
wxT(
"gain"),
static_cast<double>(GetGain()));
1796 xmlFile.WriteAttr(
wxT(
"pan"),
static_cast<double>(GetPan()));
1797 xmlFile.WriteAttr(
wxT(
"colorindex"), mWaveColorIndex );
1799 xmlFile.WriteAttr(
wxT(
"sampleformat"),
static_cast<long>(mFormat) );
1803 for (
const auto &clip : mClips)
1805 clip->WriteXML(xmlFile);
1808 xmlFile.EndTag(
wxT(
"wavetrack"));
1813 for (
const auto &clip :
mClips)
1814 if (clip->GetSequence()->GetErrorOpening())
1822 for (
const auto &clip :
mClips)
1836 for (
const auto &clip :
mClips)
1840 best = clip->GetPlayStartTime();
1842 else if (clip->GetPlayStartTime() < best)
1843 best = clip->GetPlayStartTime();
1856 for (
const auto &clip :
mClips)
1860 best = clip->GetPlayEndTime();
1862 else if (clip->GetPlayEndTime() > best)
1863 best = clip->GetPlayEndTime();
1874 double t0,
double t1,
bool mayThrow)
const
1876 std::pair<float, float> results {
1880 bool clipFound =
false;
1891 for (
const auto &clip:
mClips)
1893 if (t1 >= clip->GetPlayStartTime() && t0 <= clip->GetPlayEndTime())
1896 auto clipResults = clip->GetMinMax(t0, t1, mayThrow);
1897 if (clipResults.first < results.first)
1898 results.first = clipResults.first;
1899 if (clipResults.second > results.second)
1900 results.second = clipResults.second;
1906 results = { 0.f, 0.f };
1926 for (
const auto &clip:
mClips)
1931 if (t1 >= clip->GetPlayStartTime() && t0 <= clip->GetPlayEndTime())
1933 auto clipStart = clip->TimeToSequenceSamples(std::max(t0, clip->GetPlayStartTime()));
1934 auto clipEnd = clip->TimeToSequenceSamples(
std::min(t1, clip->GetPlayEndTime()));
1936 float cliprms = clip->GetRMS(t0, t1, mayThrow);
1938 sumsq += cliprms * cliprms * (clipEnd - clipStart).as_float();
1939 length += (clipEnd - clipStart);
1947 bool mayThrow,
sampleCount * pNumWithinClips)
const
1952 bool doClear =
true;
1955 for (
const auto &clip:
mClips)
1957 if (start >= clip->GetPlayStartSample() && start+len <= clip->GetPlayEndSample())
1972 float * pBuffer = (
float*)buffer;
1973 for(
size_t i=0;i<len;i++)
1978 wxFAIL_MSG(
wxT(
"Invalid fill format"));
1983 for (
const auto &clip:
mClips)
1985 auto clipStart = clip->GetPlayStartSample();
1986 auto clipEnd = clip->GetPlayEndSample();
1988 if (clipEnd > start && clipStart < start+len)
1991 auto samplesToCopy =
1992 std::min( start+len - clipStart, clip->GetPlaySamplesCount() );
1993 auto startDelta = clipStart - start;
1994 decltype(startDelta) inclipDelta = 0;
1997 inclipDelta = -startDelta;
1998 samplesToCopy -= inclipDelta;
2012 if (!clip->GetSamples(
2014 startDelta.as_size_t() *
2016 format, inclipDelta, samplesToCopy.as_size_t(), mayThrow ))
2019 samplesCopied += samplesToCopy;
2022 if( pNumWithinClips )
2023 *pNumWithinClips = samplesCopied;
2031 for (
const auto &clip:
mClips)
2033 auto clipStart = clip->GetPlayStartSample();
2034 auto clipEnd = clip->GetPlayEndSample();
2036 if (clipEnd > start && clipStart < start+len)
2039 auto samplesToCopy =
2040 std::min( start+len - clipStart, clip->GetPlaySamplesCount() );
2041 auto startDelta = clipStart - start;
2042 decltype(startDelta) inclipDelta = 0;
2045 inclipDelta = -startDelta;
2046 samplesToCopy -= inclipDelta;
2062 format, inclipDelta, samplesToCopy.as_size_t(), effectiveFormat );
2063 clip->MarkChanged();
2073 return std::max(format,
2074 pClip->GetSequence()->GetSampleFormats().Effective());
2081 return std::all_of(clips.begin(), clips.end(),
2082 [](
const auto &pClip){ return pClip->GetEnvelope()->IsTrivial(); });
2098 for (
decltype(bufferLen) i = 0; i < bufferLen; i++)
2103 double startTime = t0;
2104 auto tstep = 1.0 /
mRate;
2105 double endTime = t0 + tstep * bufferLen;
2106 for (
const auto &clip:
mClips)
2109 auto dClipStartTime = clip->GetPlayStartTime();
2110 auto dClipEndTime = clip->GetPlayEndTime();
2111 if ((dClipStartTime < endTime) && (dClipEndTime > startTime))
2114 auto rlen = bufferLen;
2117 if (rt0 < dClipStartTime)
2122 auto snDiff = nDiff.as_size_t();
2124 wxASSERT(snDiff <= rlen);
2126 rt0 = dClipStartTime;
2129 if (rt0 + rlen*tstep > dClipEndTime)
2131 auto nClipLen = clip->GetPlayEndSample() - clip->GetPlayStartSample();
2142 rlen =
std::min(rlen,
size_t(floor(0.5 + (dClipEndTime - rt0) / tstep)));
2146 clip->GetEnvelope()->GetValues(rbuf, rlen, rt0, tstep);
2157 auto p = std::find_if(clips.rbegin(), clips.rend(), [&] (
WaveClip*
const& clip) {
2158 return time >= clip->GetPlayStartTime() && time <= clip->GetPlayEndTime(); });
2165 if (p != clips.rend() && p != clips.rbegin() &&
2166 time == (*p)->GetPlayEndTime() &&
2167 (*p)->SharesBoundaryWithNextClip(*(p-1))) {
2171 return p != clips.rend() ? *p :
nullptr;
2195 clip->SetName(
name);
2196 clip->SetSequenceStartTime(offset);
2197 mClips.push_back(std::move(clip));
2199 return mClips.back().get();
2208 return mClips.back().get();
2219 auto it =
mClips.begin();
2220 WaveClip *rightmost = (*it++).get();
2226 if (maxOffset < offset)
2227 maxOffset = offset, rightmost = clip;
2242 if(index < (
int)
mClips.size())
2243 return mClips[index].get();
2259 const std::vector<WaveClip*> &clips,
2261 double *allowedAmount )
2264 *allowedAmount = amount;
2266 const auto &moving = [&](
WaveClip *clip){
2269 return clips.end() != std::find( clips.begin(), clips.end(), clip );
2272 for (
const auto &c:
mClips) {
2273 if ( moving( c.get() ) )
2275 for (
const auto clip : clips) {
2276 if (c->GetPlayStartTime() < clip->GetPlayEndTime() + amount &&
2277 c->GetPlayEndTime() > clip->GetPlayStartTime() + amount)
2284 if (c->GetPlayStartTime() - clip->GetPlayEndTime() < *allowedAmount)
2285 *allowedAmount = c->GetPlayStartTime() - clip->GetPlayEndTime();
2286 if (*allowedAmount < 0)
2290 if (c->GetPlayEndTime() - clip->GetPlayStartTime() > *allowedAmount)
2291 *allowedAmount = c->GetPlayEndTime() - clip->GetPlayStartTime();
2292 if (*allowedAmount > 0)
2301 if (*allowedAmount == amount)
2317 WaveClip* clip,
double &slideBy,
double &tolerance)
const
2319 for (
const auto &c :
mClips)
2322 double d1 = c->GetPlayStartTime() - (clip->
GetPlayEndTime()+slideBy);
2324 if ( (d1<0) && (d2<0) )
2335 if( -d1 < tolerance ){
2340 }
else if( -d2 < tolerance ){
2365 for (
const auto &c :
mClips)
2367 if (c->WithinPlayRegion(t))
2370 auto newClip = std::make_unique<WaveClip>( *c,
mpFactory,
true );
2372 newClip->TrimLeftTo(t);
2376 mClips.push_back(std::move(newClip));
2390 double start = 0,
end = 0;
2391 auto pEnd =
mClips.end();
2392 auto pClip = std::find_if(
mClips.begin(), pEnd,
2394 return clip->FindCutLine(cutLinePosition, &start, &end); } );
2397 auto &clip = *pClip;
2398 if (!editClipCanMove)
2402 for (
const auto &clip2:
mClips)
2404 if (clip2->GetPlayStartTime() > clip->GetPlayStartTime() &&
2405 clip->GetPlayEndTime() +
end - start > clip2->GetPlayStartTime())
2409 XO(
"There is not enough room available to expand the cut line"),
2411 "Error:_Insufficient_space_in_track"
2416 clip->ExpandCutLine(cutLinePosition);
2421 *cutlineStart = start;
2426 if (editClipCanMove)
2428 for (
const auto &clip2 :
mClips)
2430 if (clip2->GetPlayStartTime() > clip->GetPlayStartTime())
2431 clip2->Offset(
end - start);
2439 for (
const auto &clip :
mClips)
2440 if (clip->RemoveCutLine(cutLinePosition))
2452 if (!clip1 || !clip2)
2469 for (
const auto &clip :
mClips)
2470 clip->Resample(rate, progress);
2476 template <
typename Cont1,
typename Cont2 >
2480 for (
const auto &clip : mClips)
2481 clips.push_back(clip.get());
2482 std::sort(clips.begin(), clips.end(),
2484 { return a->GetPlayStartTime() < b->GetPlayStartTime(); });
2491 return FillSortedClipArray<WaveClipPointers>(
mClips);
2496 return FillSortedClipArray<WaveClipConstPointers>(
mClips);
2503 if ( !mStack.empty() ) {
2504 auto &pair = mStack.back();
2505 if ( ++pair.first == pair.second ) {
2509 push( (*pair.first)->GetCutLines() );
2517 auto pClips = &clips;
2518 while (!pClips->empty()) {
2519 auto first = pClips->begin();
2520 mStack.push_back(
Pair( first, pClips->end() ) );
2521 pClips = &(*first)->GetCutLines();
2531 for(
const auto &clip : wt->GetAllClips()) {
2533 auto blocks = clip->GetSequenceBlockArray();
2534 for (
const auto &block : *blocks) {
2535 auto &pBlock = block.sb;
2537 if ( pIDs && !pIDs->insert(pBlock->GetBlockID()).second )
2551 const_cast<TrackList &
>(tracks), std::move( inspector ), pIDs );
2557 return std::make_shared< WaveTrackFactory >(
2579 project.AttachedObjects::Assign(
key2, result );
2585 project.AttachedObjects::Assign(
key2,
nullptr );
2595 for (
const auto& clip : wt->GetAllClips())
2597 if (clip->GetTrimLeft() > 0.0 || clip->GetTrimRight() > 0.0)
2598 return { 3, 1, 0, 0 };
2607 L
"/GUI/TrackNames/DefaultTrackName",
2621 bool editClipsCanMove;
2626 L
"/GUI/EditClipCanMove",
false };
@ BadUserAction
Indicates that the user performed an action that is not allowed.
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.
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::shared_ptr< WaveClip > WaveClipHolder
std::vector< WaveClipHolder > WaveClipHolders
ProjectFormatExtensionsRegistry::Extension smartClipsExtension([](const AudacityProject &project) -> ProjectFormatVersion { const TrackList &trackList=TrackList::Get(project);for(auto wt :trackList.Any< const WaveTrack >()) { for(const auto &clip :wt->GetAllClips()) { if(clip->GetTrimLeft() > 0.0||clip->GetTrimRight() > 0.0) return { 3, 1, 0, 0 };} } return BaseProjectFormatVersion;})
bool GetEditClipsCanMove()
static ProjectFileIORegistry::ObjectReaderEntry readerEntry
static const AudacityProject::AttachedObjects::RegisteredFactory key2
DEFINE_XML_METHOD_REGISTRY(WaveTrackIORegistry)
BoolSetting EditClipsCanMove
static Container MakeIntervals(const std::vector< WaveClipHolder > &clips)
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.
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Utility to register hooks into a host class that attach client data.
Subclass * Find(const RegisteredFactory &key)
Get a (bare) pointer to an attachment, or null, down-cast it to Subclass *; will not create on demand...
Piecewise linear or piecewise exponential function from double to double.
No change to time at all.
bool HandleXMLAttribute(const std::string_view &attr, const XMLAttributeValueView &value)
void WriteXMLAttributes(XMLWriter &xmlFile) const
static ProjectRate & Get(AudacityProject &project)
static SampleBlockFactoryPtr New(AudacityProject &project)
double LongSamplesToTime(sampleCount pos) const
Convert correctly between a number of samples and an (absolute) time in seconds.
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
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)
virtual bool LinkConsistencyFix(bool doFix=true, bool completeList=true)
Check consistency of channel groups, and maybe fix it.
ChannelGroupData & GetGroupData()
std::shared_ptr< TrackList > GetOwner() const
R TypeSwitch(const Functions &...functions)
Use this function rather than testing track type explicitly and making down-casts.
void SetLinkType(LinkType linkType, bool completeList=true)
std::shared_ptr< Track > Holder
bool HandleCommonXMLAttribute(const std::string_view &attr, const XMLAttributeValueView &valueView)
const wxString & GetName() const
Name is always the same for all channels of a group.
void Init(const Track &orig)
void WriteCommonXMLAttributes(XMLWriter &xmlFile, bool includeNameAndSelected=true) const
virtual double GetEndTime() const =0
std::vector< Interval > Intervals
LinkType
For two tracks describes the type of the linkage.
LinkType GetLinkType() const noexcept
std::vector< ConstInterval > ConstIntervals
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
This allows multiple clips to be a part of one WaveTrack.
double GetSequenceStartTime() const noexcept
void SetSequenceStartTime(double startTime)
bool Append(constSamplePtr buffer, sampleFormat format, size_t len, unsigned int stride, sampleFormat effectiveFormat)
double GetPlayStartTime() const noexcept
double GetTrimRight() const noexcept
Returns the play end offset in seconds from the ending of the underlying sequence.
double GetTrimLeft() const noexcept
Returns the play start offset in seconds from the beginning of the underlying sequence.
void Paste(double t0, const WaveClip *other)
Paste data from other clip, resampling it if not equal rate.
void HandleXMLEndTag(const std::string_view &tag) override
double GetPlayEndTime() const
void SetTrimRight(double trim)
Sets the play end offset in seconds from the ending of the underlying sequence.
void Offset(double delta) noexcept
void SetTrimLeft(double trim)
Sets the play start offset in seconds from the beginning of the underlying sequence.
void Flush()
Flush must be called after last Append.
std::pair< Iterator, Iterator > Pair
void push(WaveClipHolders &clips)
AllClipsIterator & operator++()
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)
SampleBlockFactoryPtr mpFactory
const ProjectRate & mRate
A Track that contains audio waveform data.
void HandleXMLEndTag(const std::string_view &tag) override
bool LinkConsistencyFix(bool doFix, bool completeList) override
Check consistency of channel groups, and maybe fix it.
Track::Holder PasteInto(AudacityProject &) const override
Find or create the destination track for a paste, maybe in a different project.
SampleBlockFactoryPtr mpFactory
bool Append(constSamplePtr buffer, sampleFormat format, size_t len, unsigned int stride=1, sampleFormat effectiveFormat=widestSampleFormat) override
void SetRate(double newRate)
void Paste(double t0, const Track *src) override
void DoSetPan(float value)
bool CanInsertClip(WaveClip *clip, double &slideBy, double &tolerance) const
static WaveTrack * New(AudacityProject &project)
void SplitDelete(double t0, double t1)
std::vector< Region > Regions
bool Get(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, fillFormat fill=fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const override
bool AddClip(const std::shared_ptr< WaveClip > &clip)
Append a clip to the track; which must have the same block factory as this track; return success.
void Reinit(const WaveTrack &orig)
ConstIntervals GetIntervals() const override
Report times on the track where important intervals begin and end, for UI to snap to.
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.
void ExpandCutLine(double cutLinePosition, double *cutlineStart=NULL, double *cutlineEnd=NULL)
double GetStartTime() const override
Get the time at which the first clip in the track starts.
void ConvertToSampleFormat(sampleFormat format, const std::function< void(size_t)> &progressReport={})
size_t GetMaxBlockSize() const override
This returns a nonnegative number of samples meant to size a memory buffer.
void InsertSilence(double t, double len) override
size_t GetBestBlockSize(sampleCount t) const override
This returns a nonnegative number of samples meant to size a memory buffer.
WaveClipPointers SortedClipArray()
void WriteXML(XMLWriter &xmlFile) const override
wxString MakeNewClipName() const
WaveClip * CreateClip(double offset=.0, const wxString &name=wxEmptyString)
static wxString GetDefaultAudioTrackNamePreference()
sampleCount GetBlockStart(sampleCount t) const override
This returns a possibly large or negative value.
void Join(double t0, double t1)
std::pair< float, float > GetMinMax(double t0, double t1, bool mayThrow=true) const
int GetWaveColorIndex() const
WaveClip * NewestOrNewClip()
Get access to the most recently added clip, or create a clip, if there is not already one....
sampleFormat GetSampleFormat() const override
void Silence(double t0, double t1) override
void ClearAndAddCutLine(double t0, double t1)
void SyncLockAdjust(double oldT1, double newT1) override
const TypeInfo & GetTypeInfo() const override
WaveClip * GetClipByIndex(int index)
WaveTrack(const SampleBlockFactoryPtr &pFactory, sampleFormat format, double rate)
size_t GetIdealBlockSize()
WaveClip * GetClipAtTime(double time)
Track::Holder Cut(double t0, double t1) override
bool GetErrorOpening() override
void Clear(double t0, double t1) override
void Init(const WaveTrack &orig)
void Split(double t0, double t1)
bool RemoveCutLine(double cutLinePosition)
sampleCount GetPlaySamplesCount() const
void SetWaveColorIndex(int colorIndex)
sampleCount GetSequenceSamplesCount() const
Track::Holder Clone() const override
double GetOffset() const override
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()
std::shared_ptr< WaveClip > RemoveAndReturnClip(WaveClip *clip)
void Trim(double t0, double t1)
void Disjoin(double t0, double t1)
void DoSetGain(float value)
void Resample(int rate, BasicUI::ProgressDialog *progress=NULL)
float GetRMS(double t0, double t1, bool mayThrow=true) const
double GetEndTime() const override
Get the time at which the last clip in the track ends, plus recorded stuff.
const WaveClip * FindClipByName(const wxString &name) const
Returns nullptr if clip with such name was not found.
int GetClipIndex(const WaveClip *clip) const
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.
Sequence * GetSequenceAtTime(double time)
Track::Holder CopyNonconst(double t0, double t1)
WaveClipHolders & GetClips()
float GetChannelGain(int channel) const override
Takes gain and pan into account.
void Merge(const Track &orig)
void Set(constSamplePtr buffer, sampleFormat format, sampleCount start, size_t len, sampleFormat effectiveFormat=widestSampleFormat)
bool HasTrivialEnvelope() const override
void MergeClips(int clipidx1, int clipidx2)
double mLegacyProjectFileOffset
void ClearAndPaste(double t0, double t1, const Track *src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=NULL)
std::shared_ptr< WaveTrack > Holder
void HandleClear(double t0, double t1, bool addCutLines, bool split)
void SetOffset(double o) override
Track::Holder SplitCut(double t0, double t1)
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
Envelope * GetEnvelopeAtTime(double time)
Holder EmptyCopy(const SampleBlockFactoryPtr &pFactory={}, bool keepLink=true) const
void PasteWaveTrack(double t0, const WaveTrack *other)
void GetEnvelopeValues(double *buffer, size_t bufferLen, double t0) const override
Fetch envelope values corresponding to uniformly separated sample times starting at the given time.
wxString MakeClipCopyName(const wxString &originalName) 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...
Positions or offsets within audio files need a wide type.
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
PROJECT_RATE_API sampleFormat SampleFormatChoice()
static const Track::ChannelGroupAttachments::RegisteredFactory gainAndPanFactory
WaveClipHolders::iterator FindClip(WaveClipHolders &list, const WaveClip *clip, int *distance=nullptr)
bool AreAligned(const WaveClipPointers &a, const WaveClipPointers &b)
Track::LinkType ToLinkType(int value)
Cont1 FillSortedClipArray(const Cont2 &mClips)
__finl float_x4 __vecc sqrt(const float_x4 &a)
A convenient base class defining abstract virtual Clone() for a given kind of pointer.
Empty argument passed to some public constructors.
Structure to hold region of a wavetrack and a comparison function for sortability.
GainAndPan(const GainAndPan &)
GainAndPan & operator=(const GainAndPan &)=delete
std::optional< wxString > leftClipName
std::shared_ptr< WaveClip > right
std::optional< wxString > rightClipName
std::shared_ptr< WaveClip > left