39#include <wx/tokenzr.h>
40#include <wx/datetime.h>
52 wxT(
"/FileFormats/LabelStyleChoice"),
56 XXO(
"E&xtended (with frequency ranges)") },
75 return mpTrack->GetLabel(index)->selectedRegion.t1();
83std::shared_ptr<ChannelInterval>
87 return std::make_shared<ChannelInterval>();
104 auto result =
tracks.Add(std::make_shared<LabelTrack>());
105 result->AttachedTrackObjects::BuildAll();
111 auto track = std::make_shared<LabelTrack>();
112 track->SetName(
name);
113 trackList.
Add(track);
133 for (
auto &original: orig.
mLabels) {
158 auto pNewTrack = std::make_shared<LabelTrack>();
159 pNewTrack->Init(*
this);
160 pNewTrack->Paste(0.0, *
this);
172 if (index >= mLabels.size())
174 return std::make_shared<Interval>(*
this, index);
177std::shared_ptr<WideChannelGroupInterval>
185 if( iLabel >=
mLabels.size() ) {
200 const auto offset = origin -
mLabels[0].selectedRegion.t0();
201 for (
auto &labelStruct:
mLabels) {
202 labelStruct.selectedRegion.move(offset);
211 for (
auto &labelStruct:
mLabels)
213 if(labelStruct.selectedRegion.t0() >= t0)
214 labelStruct.selectedRegion.move(delta);
221 for (
size_t i = 0; i <
mLabels.size(); ++i) {
222 auto &labelStruct =
mLabels[i];
224 labelStruct.RegionRelation(b, e,
this);
226 labelStruct.selectedRegion.move(- (e-b));
232 labelStruct.selectedRegion.setTimes(
234 labelStruct.getT1() - (e - b));
236 labelStruct.selectedRegion.setT1(b);
238 labelStruct.selectedRegion.moveT1( - (e-b));
244bool LabelTrack::SplitDelete(
double b,
double e)
247 for (
size_t i = 0, len =
mLabels.size(); i < len; ++i) {
248 auto &labelStruct =
mLabels[i];
250 labelStruct.RegionRelation(b, e,
this);
256 labelStruct.selectedRegion.moveT1( - (e-b));
258 labelStruct.selectedRegion.setT0(e);
260 labelStruct.selectedRegion.setT1(b);
269 for (
auto &labelStruct:
mLabels) {
271 labelStruct.RegionRelation(pt, pt,
this);
274 labelStruct.selectedRegion.move(length);
276 labelStruct.selectedRegion.moveT1(length);
282 for (
auto &labelStruct:
mLabels) {
283 if (labelStruct.RegionRelation(b, e,
this) ==
286 double aux = b + (e - labelStruct.getT1());
287 labelStruct.selectedRegion.setTimes(
289 e - (labelStruct.getT0() - b));
297 for (
auto &labelStruct:
mLabels) {
298 labelStruct.selectedRegion.setTimes(
312 double shift = (e-b)*change - (e-b);
315 double shift = (t-b)*change - (t-b);
324 for (
auto &labelStruct:
mLabels) {
325 labelStruct.selectedRegion.setTimes(
326 warper.
Warp(labelStruct.getT0()),
327 warper.
Warp(labelStruct.getT1()));
336 const wxString& aTitle)
337: selectedRegion(region)
349 double t0,
double t1,
350 const wxString& aTitle)
351: selectedRegion(region)
371 this->SharedPointer<LabelTrack>(), {}, -1, -1 });
410 wxString::const_iterator
end;
413 if (!dt.ParseFormat(ts,
wxT(
"%H:%M:%S,%l"), &
end) ||
end != ts.end())
416 return dt.GetHour() * 3600 + dt.GetMinute() * 60 + dt.GetSecond()
417 + dt.GetMillisecond() / 1000.0;
425 wxString firstLine = file.GetLine(index++);
430 static const wxString continuation{
wxT(
"\\") };
436 wxStringTokenizer toker { firstLine,
wxT(
"\t") };
439 auto token = toker.GetNextToken();
445 token = toker.GetNextToken();
452 token = toker.GetNextToken();
470 while (index < (
int)file.GetLineCount() &&
471 file.GetLine(index).StartsWith(continuation))
474 if (index2 < index) {
475 wxStringTokenizer toker { file.GetLine(index2++),
wxT(
"\t") };
476 auto token = toker.GetNextToken();
477 if (token != continuation)
480 token = toker.GetNextToken();
485 token = toker.GetNextToken();
496 if ((
int)file.GetLineCount() < index + 2)
501 if (!firstLine.ToLong(&identifier))
504 wxString timestamp = file.GetLine(index++);
508 if (timestamp.length() != 29)
510 if (!timestamp.substr(12, 5).IsSameAs(
" --> "))
520 title = file[index++];
524 while (index < (
int)file.GetLineCount() &&
525 !file.GetLine(index).IsEmpty())
526 title +=
" " + file.GetLine(index);
542 static constexpr auto subripFormat =
wxT(
"%H:%M:%S,%l");
545 static constexpr auto webvttFormat =
wxT(
"%H:%M:%S.%l");
548 wxDateTime dt { (time_t) timestamp };
549 dt.SetMillisecond(wxRound(timestamp * 1000) % 1000);
553 return dt.Format(webvtt ? webvttFormat : subripFormat, wxDateTime::UTC);
562 file.AddLine(wxString::Format(
wxT(
"%s\t%s\t%s"),
578 file.AddLine(wxString::Format(
wxT(
"\\\t%s\t%s"),
591 file.AddLine(wxString::Format(
wxT(
"%d"), index + 1));
593 file.AddLine(wxString::Format(
wxT(
"%s --> %s"),
598 file.AddLine(
wxT(
""));
606 double reg_t0,
double reg_t1,
const LabelTrack * WXUNUSED(parent))
const
609 bool retainLabels =
false;
611 wxASSERT(reg_t0 <= reg_t1);
620 if (reg_t0 < getT0() && reg_t1 > getT1())
621 return SURROUNDS_LABEL;
622 else if (reg_t1 < getT0())
624 else if (reg_t0 > getT1())
627 else if (reg_t0 >= getT0() && reg_t0 <= getT1() &&
628 reg_t1 >= getT0() && reg_t1 <= getT1())
631 else if (reg_t0 >= getT0() && reg_t0 <= getT1())
632 return BEGINS_IN_LABEL;
634 return ENDS_IN_LABEL;
648 if (reg_t0 <= getT0() && reg_t1 >= getT1())
649 return SURROUNDS_LABEL;
650 else if (reg_t1 <= getT0())
652 else if (reg_t0 >= getT1())
657 else if (reg_t0 > getT0() && reg_t0 < getT1() &&
658 reg_t1 > getT0() && reg_t1 < getT1())
663 else if (reg_t0 > getT0() && reg_t0 < getT1())
664 return BEGINS_IN_LABEL;
666 return ENDS_IN_LABEL;
675 f.AddLine(
wxT(
"WEBVTT"));
681 for (
auto &labelStruct:
mLabels)
682 labelStruct.Export(f,
format, index++);
688 if (fileName.Right(4).CmpNoCase(
wxT(
".srt")) == 0) {
690 }
else if (fileName.Right(4).CmpNoCase(
wxT(
".vtt")) == 0) {
704 int lines = in.GetLineCount();
713 for (
int index = 0; index < lines;) {
728 if (tag ==
"label") {
735 for (
auto pair : attrs)
737 auto attr = pair.first;
738 auto value = pair.second;
743 else if (attr ==
"title")
744 title = value.ToWString();
760 else if (tag ==
"labeltrack") {
762 for (
auto pair : attrs)
764 auto attr = pair.first;
765 auto value = pair.second;
769 else if (attr ==
"numlabels" && value.TryGet(nValue))
773 wxLogWarning(
wxT(
"Project shows negative number of labels: %d"), nValue);
798 int len = mLabels.size();
800 xmlFile.StartTag(
wxT(
"labeltrack"));
802 xmlFile.WriteAttr(
wxT(
"numlabels"), len);
804 for (
auto &labelStruct: mLabels) {
805 xmlFile.StartTag(
wxT(
"label"));
806 labelStruct.getSelectedRegion()
807 .WriteXMLAttributes(xmlFile,
"t",
"t1");
809 xmlFile.WriteAttr(
wxT(
"title"), labelStruct.title);
810 xmlFile.EndTag(
wxT(
"label"));
813 xmlFile.EndTag(
wxT(
"labeltrack"));
818 auto tmp =
Copy(t0, t1);
830 if (!SplitDelete(t0, t1))
839 auto tmp = std::make_shared<LabelTrack>();
841 const auto lt =
static_cast<LabelTrack*
>(tmp.get());
843 for (
auto &labelStruct:
mLabels) {
845 labelStruct.RegionRelation(t0, t1,
this);
849 labelStruct.getT0() - t0,
850 labelStruct.getT1() - t0,
853 lt->mLabels.push_back(l);
862 lt->mLabels.push_back(l);
868 labelStruct.getT1() - t0,
871 lt->mLabels.push_back(l);
876 labelStruct.getT0() - t0,
880 lt->mLabels.push_back(l);
883 lt->mClipLen = (t1 - t0);
895 while (pos < len &&
mLabels[pos].getT0() < t)
898 for (
auto &labelStruct: sl.mLabels) {
901 labelStruct.getT0() + t,
902 labelStruct.getT1() + t,
921 double shiftAmt = lt.mClipLen > 0.0 ? lt.mClipLen : lt.GetEndTime();
938 if (n < 0 || t1 < t0)
941 double tLen = t1 - t0;
947 for (
unsigned int i = 0; i <
mLabels.size(); ++i)
950 mLabels[i].RegionRelation(t0, t1,
this);
955 unsigned int pos = i;
957 for (
int j = 1; j <= n; j++)
961 label.selectedRegion,
962 label.getT0() + j * tLen,
963 label.getT1() + j * tLen,
969 mLabels[pos].getT0() < l.getT0())
978 mLabels[i].selectedRegion.moveT1(n * tLen);
998 else if (newT1 < oldT1) {
1000 Clear(newT1, oldT1);
1009 for (
int i = 0; i < len; ++i) {
1011 mLabels[i].RegionRelation(t0, t1,
this);
1017 label.selectedRegion,
1023 mLabels[i].selectedRegion.setT1(t0);
1032 mLabels[i].selectedRegion.setT0(t1);
1037 mLabels[i].selectedRegion.setT1(t0);
1052 for (
auto &labelStruct:
mLabels) {
1053 double t0 = labelStruct.getT0();
1054 double t1 = labelStruct.getT1();
1060 labelStruct.selectedRegion.setTimes(t0, t1);
1075 const wxString &
title)
1082 while (pos < len &&
mLabels[pos].getT0() < selectedRegion.
t0())
1088 this->SharedPointer<LabelTrack>(),
title, -1, pos });
1095 wxASSERT((index < (
int)
mLabels.size()));
1096 auto iter =
mLabels.begin() + index;
1097 const auto title = iter->title;
1101 this->SharedPointer<LabelTrack>(),
title, index, -1 });
1111 const auto nn = (int)
mLabels.size();
1136 this->SharedPointer<LabelTrack>(),
mLabels[j].title, i, j });
1142 bool firstLabel =
true;
1145 for (
auto &labelStruct:
mLabels) {
1146 if (labelStruct.getT0() >= t0 &&
1147 labelStruct.getT1() <= t1)
1152 retVal += labelStruct.title;
1164 int len = (int)
mLabels.size();
1172 if (currentRegion.
t0() <
mLabels[len - 1].getT0()) {
1174 mLabels[i].getT0() <= currentRegion.
t0()) {
1190 int len = (int)
mLabels.size();
1198 if (currentRegion.
t0() >
mLabels[0].getT0()) {
1200 mLabels[i].getT0() >= currentRegion.
t0()) {
Toolkit-neutral facade for basic user interface services.
XXO("&Cut/Copy/Paste Toolbar")
static ProjectFileIORegistry::ObjectReaderEntry readerEntry
static double SubRipTimestampToDouble(const wxString &ts)
static wxString SubRipTimestampFromDouble(double timestamp, bool webvtt)
EnumSetting< bool > LabelStyleSetting
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.
void ShiftBy(double t0, double delta) override
Shift all intervals that starts after t0 by delta seconds.
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
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
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
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.