39#include <wx/tokenzr.h>
40#include <wx/datetime.h>
61 return mpTrack->GetLabel(index)->selectedRegion.t1();
69std::shared_ptr<ChannelInterval>
73 return std::make_shared<ChannelInterval>();
90 auto result =
tracks.Add(std::make_shared<LabelTrack>());
91 result->AttachedTrackObjects::BuildAll();
97 auto track = std::make_shared<LabelTrack>();
119 for (
auto &original: orig.
mLabels) {
144 auto pNewTrack = std::make_shared<LabelTrack>();
145 pNewTrack->Init(*
this);
146 pNewTrack->Paste(0.0, *
this);
158 if (index >= mLabels.size())
160 return std::make_shared<Interval>(*
this, index);
163std::shared_ptr<WideChannelGroupInterval>
171 if( iLabel >=
mLabels.size() ) {
185 const auto offset = origin -
mLabels[0].selectedRegion.t0();
186 for (
auto &labelStruct:
mLabels) {
187 labelStruct.selectedRegion.move(offset);
195 for (
size_t i = 0; i <
mLabels.size(); ++i) {
196 auto &labelStruct =
mLabels[i];
198 labelStruct.RegionRelation(b, e,
this);
200 labelStruct.selectedRegion.move(- (e-b));
206 labelStruct.selectedRegion.setTimes(
208 labelStruct.getT1() - (e - b));
210 labelStruct.selectedRegion.setT1(b);
212 labelStruct.selectedRegion.moveT1( - (e-b));
218bool LabelTrack::SplitDelete(
double b,
double e)
221 for (
size_t i = 0, len =
mLabels.size(); i < len; ++i) {
222 auto &labelStruct =
mLabels[i];
224 labelStruct.RegionRelation(b, e,
this);
230 labelStruct.selectedRegion.moveT1( - (e-b));
232 labelStruct.selectedRegion.setT0(e);
234 labelStruct.selectedRegion.setT1(b);
243 for (
auto &labelStruct:
mLabels) {
245 labelStruct.RegionRelation(pt, pt,
this);
248 labelStruct.selectedRegion.move(length);
250 labelStruct.selectedRegion.moveT1(length);
256 for (
auto &labelStruct:
mLabels) {
257 if (labelStruct.RegionRelation(b, e,
this) ==
260 double aux = b + (e - labelStruct.getT1());
261 labelStruct.selectedRegion.setTimes(
263 e - (labelStruct.getT0() - b));
271 for (
auto &labelStruct:
mLabels) {
272 labelStruct.selectedRegion.setTimes(
286 double shift = (e-b)*change - (e-b);
289 double shift = (t-b)*change - (t-b);
298 for (
auto &labelStruct:
mLabels) {
299 labelStruct.selectedRegion.setTimes(
300 warper.
Warp(labelStruct.getT0()),
301 warper.
Warp(labelStruct.getT1()));
310 const wxString& aTitle)
311: selectedRegion(region)
323 double t0,
double t1,
324 const wxString& aTitle)
325: selectedRegion(region)
345 this->SharedPointer<LabelTrack>(), {}, -1, -1 });
387 wxT(
"/FileFormats/LabelStyleChoice"),
401 S.StartStatic(
XO(
"Exported Label Style:"));
403#if defined(__WXMAC__)
414 S.EndRadioButtonGroup();
416#if defined(__WXMAC__)
429 wxString::const_iterator
end;
432 if (!dt.ParseFormat(ts,
wxT(
"%H:%M:%S,%l"), &
end) ||
end != ts.end())
435 return dt.GetHour() * 3600 + dt.GetMinute() * 60 + dt.GetSecond()
436 + dt.GetMillisecond() / 1000.0;
444 wxString firstLine = file.GetLine(index++);
449 static const wxString continuation{
wxT(
"\\") };
455 wxStringTokenizer toker { firstLine,
wxT(
"\t") };
458 auto token = toker.GetNextToken();
464 token = toker.GetNextToken();
471 token = toker.GetNextToken();
489 while (index < (
int)file.GetLineCount() &&
490 file.GetLine(index).StartsWith(continuation))
493 if (index2 < index) {
494 wxStringTokenizer toker { file.GetLine(index2++),
wxT(
"\t") };
495 auto token = toker.GetNextToken();
496 if (token != continuation)
499 token = toker.GetNextToken();
504 token = toker.GetNextToken();
515 if ((
int)file.GetLineCount() < index + 2)
520 if (!firstLine.ToLong(&identifier))
523 wxString timestamp = file.GetLine(index++);
527 if (timestamp.length() != 29)
529 if (!timestamp.substr(12, 5).IsSameAs(
" --> "))
539 title = file[index++];
543 while (index < (
int)file.GetLineCount() &&
544 !file.GetLine(index).IsEmpty())
545 title +=
" " + file.GetLine(index);
561 static constexpr auto subripFormat =
wxT(
"%H:%M:%S,%l");
564 static constexpr auto webvttFormat =
wxT(
"%H:%M:%S.%l");
567 wxDateTime dt { (time_t) timestamp };
568 dt.SetMillisecond(wxRound(timestamp * 1000) % 1000);
572 return dt.Format(webvtt ? webvttFormat : subripFormat, wxDateTime::UTC);
581 file.AddLine(wxString::Format(
wxT(
"%s\t%s\t%s"),
597 file.AddLine(wxString::Format(
wxT(
"\\\t%s\t%s"),
610 file.AddLine(wxString::Format(
wxT(
"%d"), index + 1));
612 file.AddLine(wxString::Format(
wxT(
"%s --> %s"),
617 file.AddLine(
wxT(
""));
625 double reg_t0,
double reg_t1,
const LabelTrack * WXUNUSED(parent))
const
628 bool retainLabels =
false;
630 wxASSERT(reg_t0 <= reg_t1);
639 if (reg_t0 < getT0() && reg_t1 > getT1())
640 return SURROUNDS_LABEL;
641 else if (reg_t1 < getT0())
643 else if (reg_t0 > getT1())
646 else if (reg_t0 >= getT0() && reg_t0 <= getT1() &&
647 reg_t1 >= getT0() && reg_t1 <= getT1())
650 else if (reg_t0 >= getT0() && reg_t0 <= getT1())
651 return BEGINS_IN_LABEL;
653 return ENDS_IN_LABEL;
667 if (reg_t0 <= getT0() && reg_t1 >= getT1())
668 return SURROUNDS_LABEL;
669 else if (reg_t1 <= getT0())
671 else if (reg_t0 >= getT1())
676 else if (reg_t0 > getT0() && reg_t0 < getT1() &&
677 reg_t1 > getT0() && reg_t1 < getT1())
682 else if (reg_t0 > getT0() && reg_t0 < getT1())
683 return BEGINS_IN_LABEL;
685 return ENDS_IN_LABEL;
694 f.AddLine(
wxT(
"WEBVTT"));
700 for (
auto &labelStruct:
mLabels)
701 labelStruct.Export(f,
format, index++);
707 if (fileName.Right(4).CmpNoCase(
wxT(
".srt")) == 0) {
709 }
else if (fileName.Right(4).CmpNoCase(
wxT(
".vtt")) == 0) {
723 int lines = in.GetLineCount();
732 for (
int index = 0; index < lines;) {
747 if (tag ==
"label") {
754 for (
auto pair : attrs)
756 auto attr = pair.first;
757 auto value = pair.second;
762 else if (attr ==
"title")
763 title = value.ToWString();
779 else if (tag ==
"labeltrack") {
781 for (
auto pair : attrs)
783 auto attr = pair.first;
784 auto value = pair.second;
788 else if (attr ==
"numlabels" && value.TryGet(nValue))
792 wxLogWarning(
wxT(
"Project shows negative number of labels: %d"), nValue);
817 int len = mLabels.size();
819 xmlFile.StartTag(
wxT(
"labeltrack"));
821 xmlFile.WriteAttr(
wxT(
"numlabels"), len);
823 for (
auto &labelStruct: mLabels) {
824 xmlFile.StartTag(
wxT(
"label"));
825 labelStruct.getSelectedRegion()
826 .WriteXMLAttributes(xmlFile,
"t",
"t1");
828 xmlFile.WriteAttr(
wxT(
"title"), labelStruct.title);
829 xmlFile.EndTag(
wxT(
"label"));
832 xmlFile.EndTag(
wxT(
"labeltrack"));
837 auto tmp =
Copy(t0, t1);
849 if (!SplitDelete(t0, t1))
858 auto tmp = std::make_shared<LabelTrack>();
860 const auto lt =
static_cast<LabelTrack*
>(tmp.get());
862 for (
auto &labelStruct:
mLabels) {
864 labelStruct.RegionRelation(t0, t1,
this);
868 labelStruct.getT0() - t0,
869 labelStruct.getT1() - t0,
872 lt->mLabels.push_back(l);
881 lt->mLabels.push_back(l);
887 labelStruct.getT1() - t0,
890 lt->mLabels.push_back(l);
895 labelStruct.getT0() - t0,
899 lt->mLabels.push_back(l);
902 lt->mClipLen = (t1 - t0);
914 while (pos < len &&
mLabels[pos].getT0() < t)
917 for (
auto &labelStruct: sl.mLabels) {
920 labelStruct.getT0() + t,
921 labelStruct.getT1() + t,
940 double shiftAmt = lt.mClipLen > 0.0 ? lt.mClipLen : lt.GetEndTime();
957 if (n < 0 || t1 < t0)
960 double tLen = t1 - t0;
966 for (
unsigned int i = 0; i <
mLabels.size(); ++i)
969 mLabels[i].RegionRelation(t0, t1,
this);
974 unsigned int pos = i;
976 for (
int j = 1; j <= n; j++)
980 label.selectedRegion,
981 label.getT0() + j * tLen,
982 label.getT1() + j * tLen,
988 mLabels[pos].getT0() < l.getT0())
997 mLabels[i].selectedRegion.moveT1(n * tLen);
1008 if (newT1 > oldT1) {
1017 else if (newT1 < oldT1) {
1019 Clear(newT1, oldT1);
1028 for (
int i = 0; i < len; ++i) {
1030 mLabels[i].RegionRelation(t0, t1,
this);
1036 label.selectedRegion,
1042 mLabels[i].selectedRegion.setT1(t0);
1051 mLabels[i].selectedRegion.setT0(t1);
1056 mLabels[i].selectedRegion.setT1(t0);
1071 for (
auto &labelStruct:
mLabels) {
1072 double t0 = labelStruct.getT0();
1073 double t1 = labelStruct.getT1();
1079 labelStruct.selectedRegion.setTimes(t0, t1);
1094 const wxString &
title)
1101 while (pos < len &&
mLabels[pos].getT0() < selectedRegion.
t0())
1107 this->SharedPointer<LabelTrack>(),
title, -1, pos });
1114 wxASSERT((index < (
int)
mLabels.size()));
1115 auto iter =
mLabels.begin() + index;
1116 const auto title = iter->title;
1120 this->SharedPointer<LabelTrack>(),
title, index, -1 });
1130 const auto nn = (int)
mLabels.size();
1155 this->SharedPointer<LabelTrack>(),
mLabels[j].title, i, j });
1161 bool firstLabel =
true;
1164 for (
auto &labelStruct:
mLabels) {
1165 if (labelStruct.getT0() >= t0 &&
1166 labelStruct.getT1() <= t1)
1171 retVal += labelStruct.title;
1183 int len = (int)
mLabels.size();
1191 if (currentRegion.
t0() <
mLabels[len - 1].getT0()) {
1193 mLabels[i].getT0() <= currentRegion.
t0()) {
1209 int len = (int)
mLabels.size();
1217 if (currentRegion.
t0() >
mLabels[0].getT0()) {
1219 mLabels[i].getT0() >= currentRegion.
t0()) {
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
const TranslatableString name
XXO("&Cut/Copy/Paste Toolbar")
static ProjectFileIORegistry::ObjectReaderEntry readerEntry
static double SubRipTimestampToDouble(const wxString &ts)
static wxString SubRipTimestampFromDouble(double timestamp, bool webvtt)
static const Track::TypeInfo & typeInfo()
audacity::BasicSettings * gPrefs
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper,...
std::function< void(double)> ProgressReporter
std::vector< Attribute > AttributesList
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
double GetEndTime() const
Get the maximum of End() values of intervals, or 0 when none.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
static wxString ToString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, always uses the dot as decimal separator.
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
A LabelStruct holds information for ONE label in a LabelTrack.
static LabelStruct Import(wxTextFile &file, int &index, LabelFormat format)
void MoveLabel(int iEdge, double fNewTime)
int x1
Pixel position of left hand glyph.
int x
width of the text in pixels.
TimeRelations
Relationships between selection region and labels.
void Export(wxTextFile &file, LabelFormat format, int index) const
TimeRelations RegionRelation(double reg_t0, double reg_t1, const LabelTrack *parent=NULL) const
SelectedRegion selectedRegion
bool AdjustEdge(int iEdge, double fNewTime)
double getDuration() const
bool updated
Pixel position of label.
int width
Text of the label.
int xText
Pixel position of right hand glyph.
int y
Pixel position of left hand side of text box.
A LabelTrack is a Track that holds labels (LabelStruct).
bool HandleXMLTag(const std::string_view &tag, const AttributesList &attrs) override
bool Repeat(double t0, double t1, int n)
void ShiftLabelsOnInsert(double length, double pt)
void Paste(double t, const Track &src) override
Weak precondition allows overrides to replicate one channel into many.
void ScaleLabels(double b, double e, double change)
void Import(wxTextFile &f, LabelFormat format)
Import labels, handling files with or without end-times.
void InsertSilence(double t, double len) override
void Export(wxTextFile &f, LabelFormat format) const
Export labels including label start and end-times.
void WriteXML(XMLWriter &xmlFile) const override
void SyncLockAdjust(double oldT1, double newT1) override
const TypeInfo & GetTypeInfo() const override
std::shared_ptr< Interval > MakeInterval(size_t index)
int FindPrevLabel(const SelectedRegion ¤tSelection)
static const FileNames::FileType WebVTTFiles
const LabelStruct * GetLabel(int index) const
size_t NIntervals() const override
Report the number of intervals.
void DeleteLabel(int index)
int FindNextLabel(const SelectedRegion ¤tSelection)
void SetSelected(bool s) override
static LabelTrack * New(AudacityProject &project)
void WarpLabels(const TimeWarper &warper)
void ChangeLabelsOnReverse(double b, double e)
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
Create new tracks and don't modify this track.
bool PasteOver(double t, const Track &src)
XMLTagHandler * HandleXMLChild(const std::string_view &tag) override
Track::Holder Clone(bool backup) const override
void Silence(double t0, double t1, ProgressReporter reportProgress={}) override
Track::Holder Cut(double t0, double t1) override
Create tracks and modify this track.
wxString GetTextOfLabels(double t0, double t1) const
Track::Holder PasteInto(AudacityProject &project, TrackList &list) const override
std::shared_ptr< WideChannelGroupInterval > DoGetInterval(size_t iInterval) override
Retrieve an interval.
void SetLabel(size_t iLabel, const LabelStruct &newLabel)
static const FileNames::FileType SubripFiles
static LabelTrack * Create(TrackList &trackList, const wxString &name)
Create a new LabelTrack with specified name and append it to the trackList.
void Clear(double t0, double t1) override
double AdjustTimeStampOnScale(double t, double b, double e, double change)
void MoveTo(double dOffset) override
Change start time to given time point.
int AddLabel(const SelectedRegion ®ion, const wxString &title)
static wxString GetDefaultName()
static LabelFormat FormatForFileName(const wxString &fileName)
static const TypeInfo & ClassTypeInfo()
CallbackReturn Publish(const struct LabelTrackEvent &message)
Send a message to connected callbacks.
Defines a selected portion of a project.
bool setTimes(double t0, double t1)
bool HandleXMLAttribute(const std::string_view &attr, const XMLAttributeValueView &value, const char *legacyT0Name=sDefaultT0Name, const char *legacyT1Name=sDefaultT1Name)
bool setFrequencies(double f0, double f1)
bool setT0(double t, bool maySwap=true)
bool setT1(double t, bool maySwap=true)
static const int UndefinedFrequency
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
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.
bool GetSelected() const
Selectedness is always the same for all channels of a group.
virtual void SetSelected(bool s)
static const TypeInfo & ClassTypeInfo()
R TypeSwitch(const Functions &...functions)
std::shared_ptr< Track > Holder
bool HandleCommonXMLAttribute(const std::string_view &attr, const XMLAttributeValueView &valueView)
void WriteCommonXMLAttributes(XMLWriter &xmlFile, bool includeNameAndSelected=true) const
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
wxString MakeUniqueTrackName(const wxString &baseTrackName) const
Returns string that contains baseTrackName, but is guaranteed to be unique among other tracks in that...
static TrackList & Get(AudacityProject &project)
TrackKind * Add(const std::shared_ptr< TrackKind > &t, bool assignIds=true)
Generates overrides of channel-related functions.
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 bool Read(const wxString &key, bool *value) const =0
static EnumSetting< bool > LabelStyleSetting
void AddControls(ShuttleGui &S)
ImportExportPrefs::RegisteredControls reg
const char * end(const char *str) noexcept
const char * begin(const char *str) noexcept
void rotate(const float *oldPhase, const float *newPhase, std::complex< float > *dst, int32_t n)
const std::shared_ptr< const LabelTrack > mpTrack
std::shared_ptr< ChannelInterval > DoGetChannel(size_t iChannel) override
Retrieve a channel.
double Start() const override
size_t NChannels() const override
Report the number of channels.
double End() const override
Empty argument passed to some public constructors.