1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-16 16:10:06 +02:00

Timetrack fixes and refactoring.

Possibly fixes:

Bug 206 - Time Tracks: Ruler warp goes in wrong direction
Bug 205 - Time Tracks that slow down the audio result in truncated exports
This commit is contained in:
mchinen 2010-10-07 23:01:49 +00:00
parent 2fd5555378
commit a9a0d51454
14 changed files with 77 additions and 41 deletions

View File

@ -1124,14 +1124,9 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
mCutPreviewGapLen = cutPreviewGapLen; mCutPreviewGapLen = cutPreviewGapLen;
double factor = 1.0; double factor = 1.0;
if (mTimeTrack) { if (mTimeTrack)
factor = mTimeTrack->GetEnvelope()->Average(mT0, mT1); factor = mTimeTrack->ComputeWarpFactor(mT0, mT1);
factor = (mTimeTrack->GetRangeLower() *
(1 - factor) +
factor *
mTimeTrack->GetRangeUpper()) /
100.0;
}
mWarpedT1 = factor >= 1 ? mT1 : mT0 + ((mT1 - mT0) / factor); mWarpedT1 = factor >= 1 ? mT1 : mT0 + ((mT1 - mT0) / factor);
// //

View File

@ -109,6 +109,19 @@ double TimeTrack::warp( double t )
return result; return result;
} }
//Compute the integral 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;
}
bool TimeTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs) bool TimeTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
{ {
if (!wxStrcmp(tag, wxT("timetrack"))) { if (!wxStrcmp(tag, wxT("timetrack"))) {
@ -208,7 +221,7 @@ 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 // LL: It's because the ruler only Invalidate()s when the new value is different
// than the current value. // than the current value.
mRuler->SetFlip(GetHeight() > 75 ? true : true); mRuler->SetFlip(GetHeight() > 75 ? true : true);
mRuler->Draw(dc, GetEnvelope(), GetRangeLower(), GetRangeUpper()); mRuler->Draw(dc, this);
int *heights = new int[mid.width]; int *heights = new int[mid.width];
double *envValues = new double[mid.width]; double *envValues = new double[mid.width];

View File

@ -57,6 +57,9 @@ class TimeTrack: public Track {
// Access the track's speed envelope // Access the track's speed envelope
Envelope *GetEnvelope() { return mEnvelope; } Envelope *GetEnvelope() { return mEnvelope; }
//Compute the integral warp factor between two non-warped time points
double ComputeWarpFactor(double t0, double t1);
// Get/Set the speed-warping range, as percentage of original speed (e.g. 90%-110%) // Get/Set the speed-warping range, as percentage of original speed (e.g. 90%-110%)

View File

@ -72,6 +72,7 @@
#include "../WaveTrack.h" #include "../WaveTrack.h"
#include "../widgets/Warning.h" #include "../widgets/Warning.h"
#include "../AColor.h" #include "../AColor.h"
#include "../TimeTrack.h"
// Callback to display format options // Callback to display format options
static void ExportCallback(void *cbdata, int index) static void ExportCallback(void *cbdata, int index)
@ -264,6 +265,28 @@ int ExportPlugin::DoExport(AudacityProject *project,
return false; return false;
} }
//Create a mixer by computing the time warp factor
Mixer* ExportPlugin::CreateMixer(int numInputTracks, WaveTrack **inputTracks,
TimeTrack *timeTrack,
double startTime, double stopTime,
int numOutChannels, int outBufferSize, bool outInterleaved,
double outRate, sampleFormat outFormat,
bool highQuality, MixerSpec *mixerSpec)
{
double warpedStopTime;
double warpFactor = 1.0;
if(timeTrack)
warpFactor = timeTrack->ComputeWarpFactor(startTime, stopTime);
warpedStopTime = warpFactor >= 1.0 ? stopTime : (startTime + ((stopTime - startTime) / warpFactor));
printf("warpfactor %f, stoptime %f, warpstoptime %f\n",warpFactor, stopTime, warpedStopTime);
return new Mixer(numInputTracks, inputTracks,
timeTrack,
startTime, warpedStopTime,
numOutChannels, outBufferSize, outInterleaved,
outRate, outFormat,
highQuality, mixerSpec);
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Export // Export
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -16,6 +16,7 @@
#include <wx/filename.h> #include <wx/filename.h>
#include <wx/panel.h> #include <wx/panel.h>
#include "../Tags.h" #include "../Tags.h"
#include "../SampleFormat.h"
class wxMemoryDC; class wxMemoryDC;
class wxStaticText; class wxStaticText;
@ -25,6 +26,8 @@ class WaveTrack;
class TrackList; class TrackList;
class MixerSpec; class MixerSpec;
class FileDialog; class FileDialog;
class TimeTrack;
class Mixer;
class FormatInfo class FormatInfo
{ {
@ -114,8 +117,15 @@ public:
MixerSpec *mixerSpec, MixerSpec *mixerSpec,
int subformat); int subformat);
private: protected:
Mixer* CreateMixer(int numInputTracks, WaveTrack **inputTracks,
TimeTrack *timeTrack,
double startTime, double stopTime,
int numOutChannels, int outBufferSize, bool outInterleaved,
double outRate, sampleFormat outFormat,
bool highQuality = true, MixerSpec *mixerSpec = NULL);
private:
FormatInfoArray mFormatInfos; FormatInfoArray mFormatInfos;
}; };

View File

@ -338,7 +338,7 @@ int ExportCL::Export(AudacityProject *project,
WaveTrack **waveTracks; WaveTrack **waveTracks;
TrackList *tracks = project->GetTracks(); TrackList *tracks = project->GetTracks();
tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks); tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
Mixer *mixer = new Mixer(numWaveTracks, Mixer *mixer = CreateMixer(numWaveTracks,
waveTracks, waveTracks,
tracks->GetTimeTrack(), tracks->GetTimeTrack(),
t0, t0,

View File

@ -729,7 +729,7 @@ int ExportFFmpeg::Export(AudacityProject *project,
int numWaveTracks; int numWaveTracks;
WaveTrack **waveTracks; WaveTrack **waveTracks;
tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks); tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
Mixer *mixer = new Mixer(numWaveTracks, waveTracks, Mixer *mixer = CreateMixer(numWaveTracks, waveTracks,
tracks->GetTimeTrack(), tracks->GetTimeTrack(),
t0, t1, t0, t1,
channels, pcmBufferSize, true, channels, pcmBufferSize, true,

View File

@ -306,7 +306,7 @@ int ExportFLAC::Export(AudacityProject *project,
int numWaveTracks; int numWaveTracks;
WaveTrack **waveTracks; WaveTrack **waveTracks;
tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks); tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
Mixer *mixer = new Mixer(numWaveTracks, waveTracks, Mixer *mixer = CreateMixer(numWaveTracks, waveTracks,
tracks->GetTimeTrack(), tracks->GetTimeTrack(),
t0, t1, t0, t1,
numChannels, SAMPLES_PER_RUN, false, numChannels, SAMPLES_PER_RUN, false,

View File

@ -261,7 +261,7 @@ int ExportMP2::Export(AudacityProject *project,
int numWaveTracks; int numWaveTracks;
WaveTrack **waveTracks; WaveTrack **waveTracks;
tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks); tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
Mixer *mixer = new Mixer(numWaveTracks, waveTracks, Mixer *mixer = CreateMixer(numWaveTracks, waveTracks,
tracks->GetTimeTrack(), tracks->GetTimeTrack(),
t0, t1, t0, t1,
stereo? 2: 1, pcmBufferSize, true, stereo? 2: 1, pcmBufferSize, true,

View File

@ -1639,7 +1639,7 @@ int ExportMP3::Export(AudacityProject *project,
int numWaveTracks; int numWaveTracks;
WaveTrack **waveTracks; WaveTrack **waveTracks;
tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks); tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
Mixer *mixer = new Mixer(numWaveTracks, waveTracks, Mixer *mixer = CreateMixer(numWaveTracks, waveTracks,
tracks->GetTimeTrack(), tracks->GetTimeTrack(),
t0, t1, t0, t1,
channels, inSamples, true, channels, inSamples, true,

View File

@ -244,7 +244,7 @@ int ExportOGG::Export(AudacityProject *project,
int numWaveTracks; int numWaveTracks;
WaveTrack **waveTracks; WaveTrack **waveTracks;
tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks); tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
Mixer *mixer = new Mixer(numWaveTracks, waveTracks, Mixer *mixer = CreateMixer(numWaveTracks, waveTracks,
tracks->GetTimeTrack(), tracks->GetTimeTrack(),
t0, t1, t0, t1,
numChannels, SAMPLES_PER_RUN, false, numChannels, SAMPLES_PER_RUN, false,

View File

@ -517,7 +517,7 @@ int ExportPCM::Export(AudacityProject *project,
int numWaveTracks; int numWaveTracks;
WaveTrack **waveTracks; WaveTrack **waveTracks;
tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks); tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
Mixer *mixer = new Mixer(numWaveTracks, waveTracks, Mixer *mixer = CreateMixer(numWaveTracks, waveTracks,
tracks->GetTimeTrack(), tracks->GetTimeTrack(),
t0, t1, t0, t1,
info.channels, maxBlockLen, true, info.channels, maxBlockLen, true,

View File

@ -69,6 +69,7 @@ array of Ruler::Label.
#include "../Theme.h" #include "../Theme.h"
#include "../AllThemeResources.h" #include "../AllThemeResources.h"
#include "../Experimental.h" #include "../Experimental.h"
#include "../TimeTrack.h"
#define max(a,b) ( (a<b)?b:a ) #define max(a,b) ( (a<b)?b:a )
@ -905,10 +906,10 @@ void Ruler::TickCustom(int labelIdx, bool major, bool minor)
void Ruler::Update() void Ruler::Update()
{ {
Update(NULL, 0, 0); Update(NULL);
} }
void Ruler::Update( Envelope *speedEnv, long minSpeed, long maxSpeed ) void Ruler::Update(TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, long maxSpeed )
{ {
// This gets called when something has been changed // This gets called when something has been changed
// (i.e. we've been invalidated). Recompute all // (i.e. we've been invalidated). Recompute all
@ -1050,19 +1051,14 @@ void Ruler::Update( Envelope *speedEnv, long minSpeed, long maxSpeed )
i = -1; i = -1;
while(i <= mLength) { while(i <= mLength) {
double warpfactor; double warpfactor;
if( d>0 && speedEnv != NULL ) { if( d>0 && timetrack != NULL )
warpfactor = speedEnv->Average( lastD, d ); warpfactor = timetrack->ComputeWarpFactor( lastD, d );
// Now we re-scale so that 0.5 is normal speed and
// 0 and 1.0 are min% and max% of normal speed
warpfactor = (maxSpeed * (1 - warpfactor) +
warpfactor * minSpeed) / 100.0;
}
else else
warpfactor = 1.0; warpfactor = 1.0;
i++; i++;
lastD = d; lastD = d;
d += UPP*warpfactor; d += UPP/warpfactor;
if ((int)floor(sg * d / mMajor) > majorInt) { if ((int)floor(sg * d / mMajor) > majorInt) {
majorInt = (int)floor(sg * d / mMajor); majorInt = (int)floor(sg * d / mMajor);
@ -1077,19 +1073,14 @@ void Ruler::Update( Envelope *speedEnv, long minSpeed, long maxSpeed )
i = -1; i = -1;
while(i <= mLength) { while(i <= mLength) {
double warpfactor; double warpfactor;
if( d>0 && speedEnv != NULL ) { if( d>0 && timetrack != NULL )
warpfactor = speedEnv->Average( lastD, d ); warpfactor = timetrack->ComputeWarpFactor( lastD, d );
// Now we re-scale so that 0.5 is normal speed and
// 0 and 1.0 are min% and max% of normal speed
warpfactor = (maxSpeed * (1 - warpfactor) +
warpfactor * minSpeed) / 100.0;
}
else else
warpfactor = 1.0; warpfactor = 1.0;
i++; i++;
lastD = d; lastD = d;
d += UPP*warpfactor; d += UPP/warpfactor;
if ((int)floor(sg * d / mMinor) > minorInt) { if ((int)floor(sg * d / mMinor) > minorInt) {
minorInt = (int)floor(sg * d / mMinor); minorInt = (int)floor(sg * d / mMinor);
@ -1217,17 +1208,17 @@ void Ruler::Update( Envelope *speedEnv, long minSpeed, long maxSpeed )
void Ruler::Draw(wxDC& dc) void Ruler::Draw(wxDC& dc)
{ {
Draw( dc, NULL, 0, 0); Draw( dc, NULL);
} }
void Ruler::Draw(wxDC& dc, Envelope *speedEnv, long minSpeed, long maxSpeed) void Ruler::Draw(wxDC& dc, TimeTrack* timetrack)
{ {
mDC = &dc; mDC = &dc;
if( mLength <=0 ) if( mLength <=0 )
return; return;
if (!mValid) if (!mValid)
Update( speedEnv, minSpeed, maxSpeed ); Update(timetrack);
#ifdef EXPERIMENTAL_THEMING #ifdef EXPERIMENTAL_THEMING
mDC->SetPen(mPen); mDC->SetPen(mPen);
@ -1462,7 +1453,7 @@ void Ruler::GetMaxSize(wxCoord *width, wxCoord *height)
wxBitmap tmpBM(1, 1); wxBitmap tmpBM(1, 1);
tmpDC.SelectObject(tmpBM); tmpDC.SelectObject(tmpBM);
mDC = &tmpDC; mDC = &tmpDC;
Update( NULL, 0, 0 ); Update( NULL);
} }
if (width) if (width)

View File

@ -21,6 +21,7 @@
struct ViewInfo; struct ViewInfo;
class AudacityProject; class AudacityProject;
class TimeTrack;
class AUDACITY_DLL_API Ruler { class AUDACITY_DLL_API Ruler {
public: public:
@ -115,7 +116,7 @@ class AUDACITY_DLL_API Ruler {
// Note that it will not erase for you... // Note that it will not erase for you...
void Draw(wxDC& dc); void Draw(wxDC& dc);
void Draw(wxDC& dc, Envelope *speedEnv, long minSpeed, long maxSpeed); void Draw(wxDC& dc, TimeTrack* timetrack);
// If length <> 0, draws lines perpendiculars to ruler corresponding // If length <> 0, draws lines perpendiculars to ruler corresponding
// to selected ticks (major, minor, or both), in an adjacent window. // to selected ticks (major, minor, or both), in an adjacent window.
// You may need to use the offsets if you are using part of the dc for rulers, borders etc. // You may need to use the offsets if you are using part of the dc for rulers, borders etc.
@ -128,7 +129,7 @@ class AUDACITY_DLL_API Ruler {
private: private:
void Invalidate(); void Invalidate();
void Update(); void Update();
void Update(Envelope *speedEnv, long minSpeed, long maxSpeed); void Update(TimeTrack* timetrack);
void FindTickSizes(); void FindTickSizes();
void FindLinearTickSizes(double UPP); void FindLinearTickSizes(double UPP);
wxString LabelString(double d, bool major); wxString LabelString(double d, bool major);