1
0
mirror of https://github.com/cookiengineer/audacity synced 2026-01-02 14:17:07 +01:00

Enh1349: export and import spectral selection in labels

Export and import the frequency information in labels
  Import and Export are methods of LabelStruct
  Simplify the label import routine
This commit is contained in:
Paul Licameli
2016-07-10 20:02:37 -04:00
2 changed files with 77 additions and 76 deletions

View File

@@ -47,6 +47,7 @@ for drawing different aspects of the label and its text box.
#include <wx/pen.h>
#include <wx/string.h>
#include <wx/textfile.h>
#include <wx/tokenzr.h>
#include <wx/utils.h>
#include "AudioIO.h"
@@ -1222,6 +1223,69 @@ void LabelStruct::MoveLabel( int iEdge, double fNewTime)
updated = true;
}
LabelStruct LabelStruct::Import(wxTextFile &file, int index)
{
wxString currentLine = file.GetLine(index);
// Assume tab is an impossible character within the exported text
// of the label, so can be only a delimiter. But other white space may
// be part of the label text.
wxStringTokenizer toker { currentLine, wxT("\t") };
//get the timepoint of the left edge of the label.
auto token = toker.GetNextToken();
SelectedRegion sr;
{
double t0;
if (!Internat::CompatibleToDouble(token, &t0))
throw BadFormatException{};
token = toker.GetNextToken();
double t1;
if (!Internat::CompatibleToDouble(token, &t1))
//s1 is not a number.
t1 = t0; //This is a one-sided label; t1 == t0.
else
token = toker.GetNextToken();
sr.setTimes( t0, t1 );
}
wxString title = token;
// Newer selection fields are written after the title, for historical
// reasons.
if (toker.HasMoreTokens()) {
token = toker.GetNextToken();
double f0;
if (!Internat::CompatibleToDouble(token, &f0))
throw BadFormatException{};
token = toker.GetNextToken();
double f1;
if (!Internat::CompatibleToDouble(token, &f1))
throw BadFormatException{};
sr.setFrequencies(f0, f1);
}
return LabelStruct{ sr, title };
}
void LabelStruct::Export(wxTextFile &file) const
{
file.AddLine(wxString::Format(wxT("%f\t%f\t%s\t%f\t%f"),
getT0(),
getT1(),
title.c_str(),
selectedRegion.f0(),
selectedRegion.f1()
));
}
auto LabelStruct::RegionRelation(
double reg_t0, double reg_t1, const LabelTrack * WXUNUSED(parent)) const
-> TimeRelations
@@ -2080,25 +2144,14 @@ bool LabelTrack::IsSelected() const
void LabelTrack::Export(wxTextFile & f) const
{
// PRL: to do: export other selection fields
for (auto &labelStruct: mLabels) {
f.AddLine(wxString::Format(wxT("%f\t%f\t%s"),
(double)labelStruct.getT0(),
(double)labelStruct.getT1(),
labelStruct.title.c_str()));
}
for (auto &labelStruct: mLabels)
labelStruct.Export(f);
}
/// Import labels, handling files with or without end-times.
void LabelTrack::Import(wxTextFile & in)
{
wxString currentLine;
int i, i2,len;
int index, lines;
wxString s,s1;
wxString title;
double t0,t1;
lines = in.GetLineCount();
int lines = in.GetLineCount();
mLabels.clear();
mLabels.reserve(lines);
@@ -2106,69 +2159,12 @@ void LabelTrack::Import(wxTextFile & in)
//Currently, we expect a tag file to have two values and a label
//on each line. If the second token is not a number, we treat
//it as a single-value label.
for (index = 0; index < lines; index++) {
currentLine = in.GetLine(index);
len = currentLine.Length();
if (len == 0)
return;
//get the timepoint of the left edge of the label.
i = 0;
while (i < len && currentLine.GetChar(i) != wxT(' ')
&& currentLine.GetChar(i) != wxT('\t'))
{
i++;
for (int index = 0; index < lines; index++) {
try {
LabelStruct l { LabelStruct::Import(in, index) };
mLabels.push_back(l);
}
s = currentLine.Left(i);
if (!Internat::CompatibleToDouble(s, &t0))
return;
//Increment one letter.
i++;
//Now, go until we find the start of the get the next token
while (i < len
&& (currentLine.GetChar(i) == wxT(' ')
|| currentLine.GetChar(i) == wxT('\t')))
{
i++;
}
//Keep track of the start of the second token
i2=i;
//Now, go to the end of the second token.
while (i < len && currentLine.GetChar(i) != wxT(' ')
&& currentLine.GetChar(i) != wxT('\t'))
{
i++;
}
//We are at the end of the second token.
s1 = currentLine.Mid(i2,i-i2+1).Strip(wxString::stripType(0x3));
if (!Internat::CompatibleToDouble(s1, &t1))
{
//s1 is not a number.
t1 = t0; //This is a one-sided label; t1 == t0.
//Because s1 is not a number, the label should be
//The rest of the line, starting at i2;
title = currentLine.Right(len - i2).Strip(wxString::stripType(0x3)); //0x3 indicates both
}
else
{
//s1 is a number, and it is stored correctly in t1.
//The title should be the remainder of the line,
//After we eat
//Get rid of spaces at either end
title = currentLine.Right(len - i).Strip(wxString::stripType(0x3)); //0x3 indicates both.
}
// PRL: to do: import other selection fields
LabelStruct l { SelectedRegion(t0, t1), title };
mLabels.push_back(l);
catch(const LabelStruct::BadFormatException&l) {}
}
SortLabels();
}

View File

@@ -62,6 +62,11 @@ public:
bool AdjustEdge( int iEdge, double fNewTime);
void MoveLabel( int iEdge, double fNewTime);
struct BadFormatException {};
static LabelStruct Import(wxTextFile &file, int index);
void Export(wxTextFile &file) const;
/// Relationships between selection region and labels
enum TimeRelations
{