mirror of
https://github.com/cookiengineer/audacity
synced 2026-02-05 03:03:10 +01:00
commit a large patch by Maarten Baert maarten-baert<at>hotmail<dot>com to fix and improve time track support. Several fix-me issues remain but none are new with this patch.
This commit is contained in:
@@ -31,16 +31,19 @@ TimeTrack *TrackFactory::NewTimeTrack()
|
||||
TimeTrack::TimeTrack(DirManager *projDirManager):
|
||||
Track(projDirManager)
|
||||
{
|
||||
mHeight = 50;
|
||||
mHeight = 100;
|
||||
|
||||
mRangeLower = 90;
|
||||
mRangeUpper = 110;
|
||||
mRangeLower = 0.9;
|
||||
mRangeUpper = 1.1;
|
||||
mDisplayLog = false;
|
||||
|
||||
mEnvelope = new Envelope();
|
||||
mEnvelope->SetTrackLen(1000000000.0);
|
||||
mEnvelope->SetInterpolateDB(false);
|
||||
mEnvelope->Flatten(0.5);
|
||||
mEnvelope->SetInterpolateDB(true);
|
||||
mEnvelope->Flatten(1.0);
|
||||
mEnvelope->Mirror(false);
|
||||
mEnvelope->SetOffset(0);
|
||||
|
||||
SetDefaultName(_("Time Track"));
|
||||
SetName(GetDefaultName());
|
||||
|
||||
@@ -57,15 +60,10 @@ TimeTrack::TimeTrack(TimeTrack &orig):
|
||||
{
|
||||
Init(orig);
|
||||
|
||||
mHeight = 50;
|
||||
|
||||
mRangeLower = 90;
|
||||
mRangeUpper = 110;
|
||||
|
||||
mEnvelope = new Envelope();
|
||||
mEnvelope->SetTrackLen(1000000000.0);
|
||||
mEnvelope->SetInterpolateDB(false);
|
||||
mEnvelope->Flatten(0.5);
|
||||
SetInterpolateLog(orig.GetInterpolateLog()); // this calls Envelope::SetInterpolateDB
|
||||
mEnvelope->Flatten(1.0);
|
||||
mEnvelope->Mirror(false);
|
||||
mEnvelope->Paste(0.0, orig.mEnvelope);
|
||||
mEnvelope->SetOffset(0);
|
||||
@@ -84,6 +82,9 @@ void TimeTrack::Init(const TimeTrack &orig)
|
||||
Track::Init(orig);
|
||||
SetDefaultName(orig.GetDefaultName());
|
||||
SetName(orig.GetName());
|
||||
SetRangeLower(orig.GetRangeLower());
|
||||
SetRangeUpper(orig.GetRangeUpper());
|
||||
SetDisplayLog(orig.GetDisplayLog());
|
||||
}
|
||||
|
||||
TimeTrack::~TimeTrack()
|
||||
@@ -99,35 +100,35 @@ Track *TimeTrack::Duplicate()
|
||||
return new TimeTrack(*this);
|
||||
}
|
||||
|
||||
// Our envelope represents the playback speed, which is the rate of change of
|
||||
// playback position. We want to find the playback position at time t, so
|
||||
// we have to integrate the playback speed.
|
||||
double TimeTrack::warp( double t )
|
||||
bool TimeTrack::GetInterpolateLog() const
|
||||
{
|
||||
double result = GetEnvelope()->Integral( 0.0, t,
|
||||
GetRangeLower()/100.0,
|
||||
GetRangeUpper()/100.0 );
|
||||
//printf( "Warping %.2f to %.2f\n", t, result );
|
||||
return result;
|
||||
return mEnvelope->GetInterpolateDB();
|
||||
}
|
||||
|
||||
//Compute the integral warp factor between two non-warped time points
|
||||
void TimeTrack::SetInterpolateLog(bool interpolateLog) {
|
||||
mEnvelope->SetInterpolateDB(interpolateLog);
|
||||
}
|
||||
|
||||
//Compute the (average) warp factor between two non-warped time points
|
||||
double TimeTrack::ComputeWarpFactor(double t0, double t1)
|
||||
{
|
||||
double factor;
|
||||
factor = GetEnvelope()->Average(t0, t1);
|
||||
factor = (GetRangeLower() *
|
||||
(1 - factor) +
|
||||
factor *
|
||||
GetRangeUpper()) /
|
||||
100.0;
|
||||
return factor;
|
||||
return GetEnvelope()->AverageOfInverse(t0, t1);
|
||||
}
|
||||
|
||||
double TimeTrack::ComputeWarpedLength(double t0, double t1)
|
||||
{
|
||||
return GetEnvelope()->IntegralOfInverse(t0, t1);
|
||||
}
|
||||
|
||||
double TimeTrack::SolveWarpedLength(double t0, double length)
|
||||
{
|
||||
return GetEnvelope()->SolveIntegralOfInverse(t0, length);
|
||||
}
|
||||
|
||||
bool TimeTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
|
||||
{
|
||||
if (!wxStrcmp(tag, wxT("timetrack"))) {
|
||||
double dblValue;
|
||||
mRescaleXMLValues = true; // will be set to false if upper/lower is found
|
||||
long nValue;
|
||||
while(*attrs) {
|
||||
const wxChar *attr = *attrs++;
|
||||
@@ -137,29 +138,36 @@ bool TimeTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
|
||||
break;
|
||||
|
||||
const wxString strValue = value;
|
||||
if (!wxStrcmp(attr, wxT("offset")))
|
||||
{
|
||||
if (!XMLValueChecker::IsGoodString(strValue) ||
|
||||
!Internat::CompatibleToDouble(strValue, &dblValue))
|
||||
return false;
|
||||
mOffset = dblValue;
|
||||
mEnvelope->SetOffset(mOffset);
|
||||
}
|
||||
else if (!wxStrcmp(attr, wxT("name")) && XMLValueChecker::IsGoodString(strValue))
|
||||
if (!wxStrcmp(attr, wxT("name")) && XMLValueChecker::IsGoodString(strValue))
|
||||
mName = strValue;
|
||||
else if (!wxStrcmp(attr, wxT("channel")))
|
||||
{
|
||||
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&nValue) ||
|
||||
!XMLValueChecker::IsValidChannel(nValue))
|
||||
return false;
|
||||
mChannel = nValue;
|
||||
}
|
||||
else if (!wxStrcmp(attr, wxT("height")) &&
|
||||
XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
|
||||
mHeight = nValue;
|
||||
else if (!wxStrcmp(attr, wxT("minimized")) &&
|
||||
XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
|
||||
mMinimized = (nValue != 0);
|
||||
else if (!wxStrcmp(attr, wxT("rangelower")))
|
||||
{
|
||||
mRangeLower = Internat::CompatibleToDouble(value);
|
||||
mRescaleXMLValues = false;
|
||||
}
|
||||
else if (!wxStrcmp(attr, wxT("rangeupper")))
|
||||
{
|
||||
mRangeUpper = Internat::CompatibleToDouble(value);
|
||||
mRescaleXMLValues = false; //TODO-MB: figure out how to rescale after loading
|
||||
}
|
||||
else if (!wxStrcmp(attr, wxT("displaylog")) &&
|
||||
XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
|
||||
{
|
||||
SetDisplayLog(nValue != 0);
|
||||
//TODO-MB: This causes a graphical glitch, TrackPanel should probably be Refresh()ed after loading.
|
||||
// I don't know where to do this though.
|
||||
}
|
||||
else if (!wxStrcmp(attr, wxT("interpolatelog")) &&
|
||||
XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
|
||||
{
|
||||
SetInterpolateLog(nValue != 0);
|
||||
}
|
||||
|
||||
} // while
|
||||
return true;
|
||||
@@ -181,10 +189,14 @@ void TimeTrack::WriteXML(XMLWriter &xmlFile)
|
||||
xmlFile.StartTag(wxT("timetrack"));
|
||||
|
||||
xmlFile.WriteAttr(wxT("name"), mName);
|
||||
xmlFile.WriteAttr(wxT("channel"), mChannel);
|
||||
xmlFile.WriteAttr(wxT("offset"), mOffset, 8);
|
||||
xmlFile.WriteAttr(wxT("height"), this->GetActualHeight());
|
||||
xmlFile.WriteAttr(wxT("minimized"), this->GetMinimized());
|
||||
//xmlFile.WriteAttr(wxT("channel"), mChannel);
|
||||
//xmlFile.WriteAttr(wxT("offset"), mOffset, 8);
|
||||
xmlFile.WriteAttr(wxT("height"), GetActualHeight());
|
||||
xmlFile.WriteAttr(wxT("minimized"), GetMinimized());
|
||||
xmlFile.WriteAttr(wxT("rangelower"), mRangeLower, 12);
|
||||
xmlFile.WriteAttr(wxT("rangeupper"), mRangeUpper, 12);
|
||||
xmlFile.WriteAttr(wxT("displaylog"), GetDisplayLog());
|
||||
xmlFile.WriteAttr(wxT("interpolatelog"), GetInterpolateLog());
|
||||
|
||||
mEnvelope->WriteXML(xmlFile);
|
||||
|
||||
@@ -222,31 +234,26 @@ void TimeTrack::Draw(wxDC & dc, const wxRect & r, double h, double pps)
|
||||
//
|
||||
// LL: It's because the ruler only Invalidate()s when the new value is different
|
||||
// than the current value.
|
||||
mRuler->SetFlip(GetHeight() > 75 ? true : true);
|
||||
mRuler->SetFlip(GetHeight() > 75 ? true : true); // MB: so why don't we just call Invalidate()? :)
|
||||
mRuler->Draw(dc, this);
|
||||
|
||||
int *heights = new int[mid.width];
|
||||
double *envValues = new double[mid.width];
|
||||
GetEnvelope()->GetValues(envValues, mid.width, t0, tstep);
|
||||
|
||||
double t = t0;
|
||||
int x;
|
||||
for (x = 0; x < mid.width; x++)
|
||||
{
|
||||
heights[x] = (int)(mid.height * (1 - envValues[x]));
|
||||
t += tstep;
|
||||
}
|
||||
|
||||
dc.SetPen(AColor::envelopePen);
|
||||
|
||||
for (x = 0; x < mid.width; x++)
|
||||
double logLower = log(std::max(1.0e-7, mRangeLower)), logUpper = log(std::max(1.0e-7, mRangeUpper));
|
||||
for (int x = 0; x < mid.width; x++)
|
||||
{
|
||||
int thisy = r.y + heights[x];
|
||||
AColor::Line(dc, mid.x + x, thisy, mid.x + x, thisy+3);
|
||||
double y;
|
||||
if(mDisplayLog)
|
||||
y = (double)mid.height * (logUpper - log(envValues[x])) / (logUpper - logLower);
|
||||
else
|
||||
y = (double)mid.height * (mRangeUpper - envValues[x]) / (mRangeUpper - mRangeLower);
|
||||
int thisy = r.y + (int)y;
|
||||
AColor::Line(dc, mid.x + x, thisy - 1, mid.x + x, thisy+2);
|
||||
}
|
||||
|
||||
if (heights)
|
||||
delete[]heights;
|
||||
if (envValues)
|
||||
delete[]envValues;
|
||||
}
|
||||
@@ -255,11 +262,25 @@ void TimeTrack::testMe()
|
||||
{
|
||||
GetEnvelope()->SetDefaultValue(0.5);
|
||||
GetEnvelope()->Flatten(0.0);
|
||||
GetEnvelope()->Insert( 0.0, 0.0 );
|
||||
GetEnvelope()->Insert( 5.0, 1.0 );
|
||||
GetEnvelope()->Insert( 10.0, 0.0 );
|
||||
GetEnvelope()->Insert( 0.0, 0.2 );
|
||||
GetEnvelope()->Insert( 5.0 - 0.001, 0.2 );
|
||||
GetEnvelope()->Insert( 5.0 + 0.001, 1.3 );
|
||||
GetEnvelope()->Insert( 10.0, 1.3 );
|
||||
|
||||
double value1 = GetEnvelope()->Integral(2.0, 13.0);
|
||||
double expected1 = (5.0 - 2.0) * 0.2 + (13.0 - 5.0) * 1.3;
|
||||
double value2 = GetEnvelope()->IntegralOfInverse(2.0, 13.0);
|
||||
double expected2 = (5.0 - 2.0) / 0.2 + (13.0 - 5.0) / 1.3;
|
||||
if( fabs(value1 - expected1) > 0.01 )
|
||||
{
|
||||
printf( "TimeTrack: Integral failed! expected %f got %f\n", expected1, value1);
|
||||
}
|
||||
if( fabs(value2 - expected2) > 0.01 )
|
||||
{
|
||||
printf( "TimeTrack: IntegralOfInverse failed! expected %f got %f\n", expected2, value2);
|
||||
}
|
||||
|
||||
double reqt0 = 10.0 - .1;
|
||||
/*double reqt0 = 10.0 - .1;
|
||||
double reqt1 = 10.0 + .1;
|
||||
double t0 = warp( reqt0 );
|
||||
double t1 = warp( reqt1 );
|
||||
@@ -268,17 +289,6 @@ void TimeTrack::testMe()
|
||||
printf( "TimeTrack: Warping reverses an interval! [%.2f,%.2f] -> [%.2f,%.2f]\n",
|
||||
reqt0, reqt1,
|
||||
t0, t1 );
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
// Indentation settings for Vim and Emacs and unique identifier for Arch, a
|
||||
// version control system. Please do not modify past this point.
|
||||
//
|
||||
// Local Variables:
|
||||
// c-basic-offset: 3
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
//
|
||||
// vim: et sts=3 sw=3
|
||||
// arch-tag: 8622daf1-c09a-4dcd-8b71-615d194343c7
|
||||
|
||||
|
||||
Reference in New Issue
Block a user