1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-02 17:09:26 +02:00

Don't pass whole TimeTrack to Ruler or Mixer...

... they need only the information in a (Bounded)Envelope.
This commit is contained in:
Paul Licameli 2019-06-06 09:21:01 -04:00
parent 5ae606cf53
commit 46bf5a82fc
17 changed files with 142 additions and 123 deletions

View File

@ -1626,7 +1626,7 @@ void AdornedRulerPanel::StartQPPlay(bool looped, bool cutPreview)
if (!cutPreview) if (!cutPreview)
options.pStartTime = &oldStart; options.pStartTime = &oldStart;
else else
options.timeTrack = NULL; options.envelope = nullptr;
auto mode = auto mode =
cutPreview ? PlayMode::cutPreviewPlay cutPreview ? PlayMode::cutPreviewPlay

View File

@ -409,7 +409,7 @@ callbacks for these events.
\class AudioIOStartStreamOptions \class AudioIOStartStreamOptions
\brief struct holding stream options, including a pointer to the \brief struct holding stream options, including a pointer to the
TimeTrack and AudioIOListener and whether the playback is looped. time warp info and AudioIOListener and whether the playback is looped.
*//*******************************************************************/ *//*******************************************************************/
@ -458,7 +458,7 @@ TimeTrack and AudioIOListener and whether the playback is looped.
#include "Prefs.h" #include "Prefs.h"
#include "Project.h" #include "Project.h"
#include "ProjectWindow.h" #include "ProjectWindow.h"
#include "TimeTrack.h" #include "Envelope.h"
#include "WaveTrack.h" #include "WaveTrack.h"
#include "AutoRecovery.h" #include "AutoRecovery.h"
@ -2143,7 +2143,7 @@ bool AudioIO::AllocateBuffers(
ScrubbingOptions::MaxAllowedScrubSpeed()) ScrubbingOptions::MaxAllowedScrubSpeed())
: :
#endif #endif
Mixer::WarpOptions(mPlaybackSchedule.mTimeTrack); Mixer::WarpOptions(mPlaybackSchedule.mEnvelope);
mPlaybackQueueMinimum = mPlaybackSamplesToCopy; mPlaybackQueueMinimum = mPlaybackSamplesToCopy;
if (scrubbing) if (scrubbing)
@ -2806,9 +2806,9 @@ void AudioIO::PlaybackSchedule::Init(
// the existing audio. (Unless we figured out the inverse warp of the // the existing audio. (Unless we figured out the inverse warp of the
// captured samples in real time.) // captured samples in real time.)
// So just quietly ignore the time track. // So just quietly ignore the time track.
mTimeTrack = nullptr; mEnvelope = nullptr;
else else
mTimeTrack = options.timeTrack; mEnvelope = options.envelope;
mT0 = t0; mT0 = t0;
if (pRecordingSchedule) if (pRecordingSchedule)
@ -2838,7 +2838,7 @@ void AudioIO::PlaybackSchedule::Init(
const auto &scrubOptions = *options.pScrubbingOptions; const auto &scrubOptions = *options.pScrubbingOptions;
if (pRecordingSchedule || if (pRecordingSchedule ||
Looping() || Looping() ||
mTimeTrack != NULL || mEnvelope ||
scrubOptions.maxSpeed < ScrubbingOptions::MinAllowedScrubSpeed()) { scrubOptions.maxSpeed < ScrubbingOptions::MinAllowedScrubSpeed()) {
wxASSERT(false); wxASSERT(false);
scrubbing = false; scrubbing = false;
@ -4173,7 +4173,7 @@ static Alg_update gAllNotesOff; // special event for loop ending
double AudioIO::UncorrectedMidiEventTime() double AudioIO::UncorrectedMidiEventTime()
{ {
double time; double time;
if (mPlaybackSchedule.mTimeTrack) if (mPlaybackSchedule.mEnvelope)
time = time =
mPlaybackSchedule.RealDuration(mNextEventTime - MidiLoopOffset()) mPlaybackSchedule.RealDuration(mNextEventTime - MidiLoopOffset())
+ mPlaybackSchedule.mT0 + (mMidiLoopPasses * + mPlaybackSchedule.mT0 + (mMidiLoopPasses *
@ -5633,6 +5633,35 @@ bool AudioIO::PlaybackSchedule::Overruns( double trackTime ) const
return (ReversedTime() ? trackTime <= mT1 : trackTime >= mT1); return (ReversedTime() ? trackTime <= mT1 : trackTime >= mT1);
} }
namespace
{
/** @brief Compute the duration (in seconds at playback) of the specified region of the track.
*
* Takes a region of the time track (specified by the unwarped time points in the project), and
* calculates how long it will actually take to play this region back, taking the time track's
* warping effects into account.
* @param t0 unwarped time to start calculation from
* @param t1 unwarped time to stop calculation at
* @return the warped duration in seconds
*/
double ComputeWarpedLength(const Envelope &env, double t0, double t1)
{
return env.IntegralOfInverse(t0, t1);
}
/** @brief Compute how much unwarped time must have elapsed if length seconds of warped time has
* elapsed
*
* @param t0 The unwarped time (seconds from project start) at which to start
* @param length How many seconds of warped time went past.
* @return The end point (in seconds from project start) as unwarped time
*/
double SolveWarpedLength(const Envelope &env, double t0, double length)
{
return env.SolveIntegralOfInverse(t0, length);
}
}
double AudioIO::PlaybackSchedule::AdvancedTrackTime( double AudioIO::PlaybackSchedule::AdvancedTrackTime(
double time, double realElapsed, double speed ) const double time, double realElapsed, double speed ) const
{ {
@ -5643,7 +5672,7 @@ double AudioIO::PlaybackSchedule::AdvancedTrackTime(
if ( fabs(mT0 - mT1) < 1e-9 ) if ( fabs(mT0 - mT1) < 1e-9 )
return mT0; return mT0;
if (mTimeTrack) { if (mEnvelope) {
wxASSERT( speed == 1.0 ); wxASSERT( speed == 1.0 );
double total=0.0; double total=0.0;
@ -5654,7 +5683,7 @@ double AudioIO::PlaybackSchedule::AdvancedTrackTime(
// Avoid SolveWarpedLength // Avoid SolveWarpedLength
time = mT1; time = mT1;
else else
time = mTimeTrack->SolveWarpedLength(time, realElapsed); time = SolveWarpedLength(*mEnvelope, time, realElapsed);
if (!Looping() || !Overruns( time )) if (!Looping() || !Overruns( time ))
break; break;
@ -5666,7 +5695,7 @@ double AudioIO::PlaybackSchedule::AdvancedTrackTime(
// Avoid integrating again // Avoid integrating again
delta = total; delta = total;
else { else {
delta = mTimeTrack->ComputeWarpedLength(oldTime, mT1); delta = ComputeWarpedLength(*mEnvelope, oldTime, mT1);
if (oldTime == mT0) if (oldTime == mT0)
foundTotal = true, total = delta; foundTotal = true, total = delta;
} }
@ -5762,8 +5791,8 @@ double AudioIO::TimeQueue::Consumer( size_t nSamples, double rate )
double AudioIO::PlaybackSchedule::TrackDuration(double realElapsed) const double AudioIO::PlaybackSchedule::TrackDuration(double realElapsed) const
{ {
if (mTimeTrack) if (mEnvelope)
return mTimeTrack->SolveWarpedLength(mT0, realElapsed); return SolveWarpedLength(*mEnvelope, mT0, realElapsed);
else else
return realElapsed; return realElapsed;
} }
@ -5771,8 +5800,8 @@ double AudioIO::PlaybackSchedule::TrackDuration(double realElapsed) const
double AudioIO::PlaybackSchedule::RealDuration(double trackTime1) const double AudioIO::PlaybackSchedule::RealDuration(double trackTime1) const
{ {
double duration; double duration;
if (mTimeTrack) if (mEnvelope)
duration = mTimeTrack->ComputeWarpedLength(mT0, trackTime1); duration = ComputeWarpedLength(*mEnvelope, mT0, trackTime1);
else else
duration = trackTime1 - mT0; duration = trackTime1 - mT0;
return fabs(duration); return fabs(duration);

View File

@ -57,7 +57,7 @@ class AudioIO;
class RingBuffer; class RingBuffer;
class Mixer; class Mixer;
class Resample; class Resample;
class TimeTrack; class BoundedEnvelope;
class AudioThread; class AudioThread;
class MeterPanel; class MeterPanel;
class SelectedRegion; class SelectedRegion;
@ -118,7 +118,7 @@ struct AudioIOStartStreamOptions
explicit explicit
AudioIOStartStreamOptions(AudacityProject *pProject_, double rate_) AudioIOStartStreamOptions(AudacityProject *pProject_, double rate_)
: pProject{ pProject_ } : pProject{ pProject_ }
, timeTrack(NULL) , envelope(nullptr)
, listener(NULL) , listener(NULL)
, rate(rate_) , rate(rate_)
, playLooped(false) , playLooped(false)
@ -130,7 +130,7 @@ struct AudioIOStartStreamOptions
AudacityProject *pProject{}; AudacityProject *pProject{};
MeterPanel *captureMeter{}, *playbackMeter{}; MeterPanel *captureMeter{}, *playbackMeter{};
TimeTrack *timeTrack; BoundedEnvelope *envelope; // for time warping
AudioIOListener* listener; AudioIOListener* listener;
double rate; double rate;
bool playLooped; bool playLooped;
@ -668,7 +668,7 @@ protected:
// with ComputeWarpedLength, it is now possible the calculate the warped length with 100% accuracy // with ComputeWarpedLength, it is now possible the calculate the warped length with 100% accuracy
// (ignoring accumulated rounding errors during playback) which fixes the 'missing sound at the end' bug // (ignoring accumulated rounding errors during playback) which fixes the 'missing sound at the end' bug
const TimeTrack *mTimeTrack; const BoundedEnvelope *mEnvelope;
volatile enum { volatile enum {
PLAY_STRAIGHT, PLAY_STRAIGHT,

View File

@ -31,6 +31,7 @@
#include <wx/timer.h> #include <wx/timer.h>
#include <wx/intl.h> #include <wx/intl.h>
#include "Envelope.h"
#include "WaveTrack.h" #include "WaveTrack.h"
#include "Prefs.h" #include "Prefs.h"
#include "Resample.h" #include "Resample.h"
@ -143,10 +144,11 @@ void MixAndRender(TrackList *tracks, TrackFactory *trackFactory,
endTime = mixEndTime; endTime = mixEndTime;
} }
auto timeTrack = tracks->GetTimeTrack();
Mixer mixer(waveArray, Mixer mixer(waveArray,
// Throw to abort mix-and-render if read fails: // Throw to abort mix-and-render if read fails:
true, true,
Mixer::WarpOptions(tracks->GetTimeTrack()), Mixer::WarpOptions(timeTrack ? timeTrack->GetEnvelope() : nullptr),
startTime, endTime, mono ? 1 : 2, maxBlockLen, false, startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
rate, format); rate, format);
@ -204,7 +206,7 @@ void MixAndRender(TrackList *tracks, TrackFactory *trackFactory,
} }
Mixer::WarpOptions::WarpOptions(double min, double max) Mixer::WarpOptions::WarpOptions(double min, double max)
: timeTrack(0), minSpeed(min), maxSpeed(max) : minSpeed(min), maxSpeed(max)
{ {
if (minSpeed < 0) if (minSpeed < 0)
{ {
@ -253,7 +255,7 @@ Mixer::Mixer(const WaveTrackConstArray &inputTracks,
mInputTrack[i].SetTrack(inputTracks[i]); mInputTrack[i].SetTrack(inputTracks[i]);
mSamplePos[i] = inputTracks[i]->TimeToLongSamples(startTime); mSamplePos[i] = inputTracks[i]->TimeToLongSamples(startTime);
} }
mTimeTrack = warpOptions.timeTrack; mEnvelope = warpOptions.envelope;
mT0 = startTime; mT0 = startTime;
mT1 = stopTime; mT1 = stopTime;
mTime = startTime; mTime = startTime;
@ -301,11 +303,11 @@ Mixer::Mixer(const WaveTrackConstArray &inputTracks,
mMaxFactor.resize(mNumInputTracks); mMaxFactor.resize(mNumInputTracks);
for (size_t i = 0; i<mNumInputTracks; i++) { for (size_t i = 0; i<mNumInputTracks; i++) {
double factor = (mRate / mInputTrack[i].GetTrack()->GetRate()); double factor = (mRate / mInputTrack[i].GetTrack()->GetRate());
if (mTimeTrack) { if (mEnvelope) {
// variable rate resampling // variable rate resampling
mbVariableRates = true; mbVariableRates = true;
mMinFactor[i] = factor / mTimeTrack->GetRangeUpper(); mMinFactor[i] = factor / mEnvelope->GetRangeUpper();
mMaxFactor[i] = factor / mTimeTrack->GetRangeLower(); mMaxFactor[i] = factor / mEnvelope->GetRangeLower();
} }
else if (warpOptions.minSpeed > 0.0 && warpOptions.maxSpeed > 0.0) { else if (warpOptions.minSpeed > 0.0 && warpOptions.maxSpeed > 0.0) {
// variable rate resampling // variable rate resampling
@ -380,6 +382,26 @@ void MixBuffers(unsigned numChannels, int *channelFlags, float *gains,
} }
} }
namespace {
//Note: The meaning of this function has changed (December 2012)
//Previously this function did something that was close to the opposite (but not entirely accurate).
/** @brief Compute the integral warp factor between two non-warped time points
*
* Calculate the relative length increase of the chosen segment from the original sound.
* So if this time track has a low value (i.e. makes the sound slower), the NEW warped
* sound will be *longer* than the original sound, so the return value of this function
* is larger.
* @param t0 The starting time to calculate from
* @param t1 The ending time to calculate to
* @return The relative length increase of the chosen segment from the original sound.
*/
double ComputeWarpFactor(const Envelope &env, double t0, double t1)
{
return env.AverageOfInverse(t0, t1);
}
}
size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache, size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache,
sampleCount *pos, float *queue, sampleCount *pos, float *queue,
int *queueStart, int *queueLen, int *queueStart, int *queueLen,
@ -474,7 +496,7 @@ size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache,
} }
double factor = initialWarp; double factor = initialWarp;
if (mTimeTrack) if (mEnvelope)
{ {
//TODO-MB: The end time is wrong when the resampler doesn't use all input samples, //TODO-MB: The end time is wrong when the resampler doesn't use all input samples,
// as a result of this the warp factor may be slightly wrong, so AudioIO will stop too soon // as a result of this the warp factor may be slightly wrong, so AudioIO will stop too soon
@ -482,11 +504,11 @@ size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache,
// without changing the way the resampler works, because the number of input samples that will be used // without changing the way the resampler works, because the number of input samples that will be used
// is unpredictable. Maybe it can be compensated later though. // is unpredictable. Maybe it can be compensated later though.
if (backwards) if (backwards)
factor *= mTimeTrack->ComputeWarpFactor factor *= ComputeWarpFactor( *mEnvelope,
(t - (double)thisProcessLen / trackRate + tstep, t + tstep); t - (double)thisProcessLen / trackRate + tstep, t + tstep);
else else
factor *= mTimeTrack->ComputeWarpFactor factor *= ComputeWarpFactor( *mEnvelope,
(t, t + (double)thisProcessLen / trackRate); t, t + (double)thisProcessLen / trackRate);
} }
auto results = pResample->Process(factor, auto results = pResample->Process(factor,

View File

@ -25,7 +25,7 @@
class Resample; class Resample;
class DirManager; class DirManager;
class TimeTrack; class BoundedEnvelope;
class TrackFactory; class TrackFactory;
class TrackList; class TrackList;
class WaveTrack; class WaveTrack;
@ -83,15 +83,15 @@ class AUDACITY_DLL_API Mixer {
class WarpOptions class WarpOptions
{ {
public: public:
explicit WarpOptions(const TimeTrack *t) explicit WarpOptions(const BoundedEnvelope *e)
: timeTrack(t), minSpeed(0.0), maxSpeed(0.0) : envelope(e), minSpeed(0.0), maxSpeed(0.0)
{} {}
WarpOptions(double min, double max); WarpOptions(double min, double max);
private: private:
friend class Mixer; friend class Mixer;
const TimeTrack *timeTrack; const BoundedEnvelope *envelope = nullptr;
double minSpeed, maxSpeed; double minSpeed, maxSpeed;
}; };
@ -164,7 +164,7 @@ class AUDACITY_DLL_API Mixer {
size_t mNumInputTracks; size_t mNumInputTracks;
ArrayOf<WaveTrackCache> mInputTrack; ArrayOf<WaveTrackCache> mInputTrack;
bool mbVariableRates; bool mbVariableRates;
const TimeTrack *mTimeTrack; const BoundedEnvelope *mEnvelope;
ArrayOf<sampleCount> mSamplePos; ArrayOf<sampleCount> mSamplePos;
bool mApplyTrackGains; bool mApplyTrackGains;
Doubles mEnvValues; Doubles mEnvValues;

View File

@ -24,6 +24,7 @@ Paul Licameli split from ProjectManager.cpp
#include "ProjectHistory.h" #include "ProjectHistory.h"
#include "ProjectSettings.h" #include "ProjectSettings.h"
#include "ProjectWindow.h" #include "ProjectWindow.h"
#include "TimeTrack.h"
#include "toolbars/ControlToolBar.h" #include "toolbars/ControlToolBar.h"
#include "widgets/ErrorDialog.h" #include "widgets/ErrorDialog.h"
#include "widgets/Warning.h" #include "widgets/Warning.h"
@ -174,7 +175,8 @@ DefaultPlayOptions( AudacityProject &project )
ProjectSettings::Get( project ).GetRate() }; ProjectSettings::Get( project ).GetRate() };
options.captureMeter = projectAudioIO.GetCaptureMeter(); options.captureMeter = projectAudioIO.GetCaptureMeter();
options.playbackMeter = projectAudioIO.GetPlaybackMeter(); options.playbackMeter = projectAudioIO.GetPlaybackMeter();
options.timeTrack = TrackList::Get( project ).GetTimeTrack(); auto timeTrack = TrackList::Get( project ).GetTimeTrack();
options.envelope = timeTrack ? timeTrack->GetEnvelope() : nullptr;
options.listener = &ProjectAudioManager::Get( project ); options.listener = &ProjectAudioManager::Get( project );
return options; return options;
} }
@ -191,7 +193,8 @@ DefaultSpeedPlayOptions( AudacityProject &project )
AudioIOStartStreamOptions options{ &project, PlayAtSpeedRate }; AudioIOStartStreamOptions options{ &project, PlayAtSpeedRate };
options.captureMeter = projectAudioIO.GetCaptureMeter(); options.captureMeter = projectAudioIO.GetCaptureMeter();
options.playbackMeter = projectAudioIO.GetPlaybackMeter(); options.playbackMeter = projectAudioIO.GetPlaybackMeter();
options.timeTrack = TrackList::Get( project ).GetTimeTrack(); auto timeTrack = TrackList::Get( project ).GetTimeTrack();
options.envelope = timeTrack ? timeTrack->GetEnvelope() : nullptr;
options.listener = &ProjectAudioManager::Get( project ); options.listener = &ProjectAudioManager::Get( project );
return options; return options;
} }

View File

@ -58,11 +58,12 @@ TimeTrack::TimeTrack(const std::shared_ptr<DirManager> &projDirManager, const Zo
{ {
mHeight = 100; mHeight = 100;
mEnvelope = std::make_unique<BoundedEnvelope>(true, TIMETRACK_MIN, TIMETRACK_MAX, 1.0);
SetRangeLower( 0.9 ); SetRangeLower( 0.9 );
SetRangeUpper( 1.1 ); SetRangeUpper( 1.1 );
mDisplayLog = false; mDisplayLog = false;
mEnvelope = std::make_unique<BoundedEnvelope>(true, TIMETRACK_MIN, TIMETRACK_MAX, 1.0);
mEnvelope->SetTrackLen(DBL_MAX); mEnvelope->SetTrackLen(DBL_MAX);
mEnvelope->SetOffset(0); mEnvelope->SetOffset(0);
@ -88,6 +89,10 @@ TimeTrack::TimeTrack(const TimeTrack &orig, double *pT0, double *pT1)
} }
else else
mEnvelope = std::make_unique<BoundedEnvelope>( *orig.mEnvelope ); mEnvelope = std::make_unique<BoundedEnvelope>( *orig.mEnvelope );
SetRangeLower(orig.GetRangeLower());
SetRangeUpper(orig.GetRangeUpper());
mEnvelope->SetTrackLen( len ); mEnvelope->SetTrackLen( len );
mEnvelope->SetOffset(0); mEnvelope->SetOffset(0);
@ -104,8 +109,6 @@ void TimeTrack::Init(const TimeTrack &orig)
Track::Init(orig); Track::Init(orig);
SetDefaultName(orig.GetDefaultName()); SetDefaultName(orig.GetDefaultName());
SetName(orig.GetName()); SetName(orig.GetName());
SetRangeLower(orig.GetRangeLower());
SetRangeUpper(orig.GetRangeUpper());
SetDisplayLog(orig.GetDisplayLog()); SetDisplayLog(orig.GetDisplayLog());
} }
@ -188,22 +191,6 @@ void TimeTrack::SetInterpolateLog(bool interpolateLog) {
mEnvelope->SetExponential(interpolateLog); mEnvelope->SetExponential(interpolateLog);
} }
//Compute the (average) warp factor between two non-warped time points
double TimeTrack::ComputeWarpFactor(double t0, double t1) const
{
return GetEnvelope()->AverageOfInverse(t0, t1);
}
double TimeTrack::ComputeWarpedLength(double t0, double t1) const
{
return GetEnvelope()->IntegralOfInverse(t0, t1);
}
double TimeTrack::SolveWarpedLength(double t0, double length) const
{
return GetEnvelope()->SolveIntegralOfInverse(t0, length);
}
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"))) {
@ -335,7 +322,7 @@ void TimeTrack::Draw
// than the current value. // than the current value.
mRuler->SetFlip(GetHeight() > 75 ? true : true); // MB: so why don't we just call Invalidate()? :) mRuler->SetFlip(GetHeight() > 75 ? true : true); // MB: so why don't we just call Invalidate()? :)
mRuler->SetTickColour( theTheme.Colour( clrTrackPanelText )); mRuler->SetTickColour( theTheme.Colour( clrTrackPanelText ));
mRuler->Draw(dc, this); mRuler->Draw(dc, GetEnvelope());
Doubles envValues{ size_t(mid.width) }; Doubles envValues{ size_t(mid.width) };
EnvelopeEditor::GetValues( *GetEnvelope(), EnvelopeEditor::GetValues( *GetEnvelope(),

View File

@ -83,38 +83,6 @@ class TimeTrack final : public Track {
BoundedEnvelope *GetEnvelope() { return mEnvelope.get(); } BoundedEnvelope *GetEnvelope() { return mEnvelope.get(); }
const BoundedEnvelope *GetEnvelope() const { return mEnvelope.get(); } const BoundedEnvelope *GetEnvelope() const { return mEnvelope.get(); }
//Note: The meaning of this function has changed (December 2012)
//Previously this function did something that was close to the opposite (but not entirely accurate).
/** @brief Compute the integral warp factor between two non-warped time points
*
* Calculate the relative length increase of the chosen segment from the original sound.
* So if this time track has a low value (i.e. makes the sound slower), the NEW warped
* sound will be *longer* than the original sound, so the return value of this function
* is larger.
* @param t0 The starting time to calculate from
* @param t1 The ending time to calculate to
* @return The relative length increase of the chosen segment from the original sound.
*/
double ComputeWarpFactor(double t0, double t1) const;
/** @brief Compute the duration (in seconds at playback) of the specified region of the track.
*
* Takes a region of the time track (specified by the unwarped time points in the project), and
* calculates how long it will actually take to play this region back, taking the time track's
* warping effects into account.
* @param t0 unwarped time to start calculation from
* @param t1 unwarped time to stop calculation at
* @return the warped duration in seconds
*/
double ComputeWarpedLength(double t0, double t1) const;
/** @brief Compute how much unwarped time must have elapsed if length seconds of warped time has
* elapsed
*
* @param t0 The unwarped time (seconds from project start) at which to start
* @param length How many seconds of warped time went past.
* @return The end point (in seconds from project start) as unwarped time
*/
double SolveWarpedLength(double t0, double length) const;
// 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%)
double GetRangeLower() const; double GetRangeLower() const;

View File

@ -68,6 +68,7 @@
#include "../ProjectSettings.h" #include "../ProjectSettings.h"
#include "../ProjectWindow.h" #include "../ProjectWindow.h"
#include "../ShuttleGui.h" #include "../ShuttleGui.h"
#include "../TimeTrack.h"
#include "../WaveTrack.h" #include "../WaveTrack.h"
#include "../widgets/AudacityMessageBox.h" #include "../widgets/AudacityMessageBox.h"
#include "../widgets/Warning.h" #include "../widgets/Warning.h"
@ -250,11 +251,12 @@ std::unique_ptr<Mixer> ExportPlugin::CreateMixer(const TrackList &tracks,
const WaveTrackConstArray inputTracks = const WaveTrackConstArray inputTracks =
tracks.GetWaveTrackConstArray(selectionOnly, false); tracks.GetWaveTrackConstArray(selectionOnly, false);
const TimeTrack *timeTrack = tracks.GetTimeTrack(); const TimeTrack *timeTrack = tracks.GetTimeTrack();
auto envelope = timeTrack ? timeTrack->GetEnvelope() : nullptr;
// MB: the stop time should not be warped, this was a bug. // MB: the stop time should not be warped, this was a bug.
return std::make_unique<Mixer>(inputTracks, return std::make_unique<Mixer>(inputTracks,
// Throw, to stop exporting, if read fails: // Throw, to stop exporting, if read fails:
true, true,
Mixer::WarpOptions(timeTrack), Mixer::WarpOptions(envelope),
startTime, stopTime, startTime, stopTime,
numOutChannels, outBufferSize, outInterleaved, numOutChannels, outBufferSize, outInterleaved,
outRate, outFormat, outRate, outFormat,

View File

@ -29,7 +29,6 @@ class Tags;
class TrackList; class TrackList;
class MixerSpec; class MixerSpec;
class ProgressDialog; class ProgressDialog;
class TimeTrack;
class Mixer; class Mixer;
using WaveTrackConstArray = std::vector < std::shared_ptr < const WaveTrack > >; using WaveTrackConstArray = std::vector < std::shared_ptr < const WaveTrack > >;
enum class ProgressResult : unsigned; enum class ProgressResult : unsigned;

View File

@ -713,12 +713,6 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion,
return -1; return -1;
} }
else { else {
// Lifted the following into AudacityProject::GetDefaultPlayOptions()
/*
if (!timetrack) {
timetrack = t->GetTimeTrack();
}
*/
token = gAudioIO->StartStream( token = gAudioIO->StartStream(
GetAllPlaybackTracks( tracks, false, useMidi ), GetAllPlaybackTracks( tracks, false, useMidi ),
t0, t1, options); t0, t1, options);
@ -775,7 +769,7 @@ void ControlToolBar::PlayCurrentRegion(bool looped /* = false */,
auto options = DefaultPlayOptions( *p ); auto options = DefaultPlayOptions( *p );
options.playLooped = looped; options.playLooped = looped;
if (cutpreview) if (cutpreview)
options.timeTrack = NULL; options.envelope = nullptr;
auto mode = auto mode =
cutpreview ? PlayMode::cutPreviewPlay cutpreview ? PlayMode::cutPreviewPlay
: options.playLooped ? PlayMode::loopedPlay : options.playLooped ? PlayMode::loopedPlay

View File

@ -28,7 +28,6 @@ class wxStatusBar;
class AButton; class AButton;
class AudacityProject; class AudacityProject;
class TrackList; class TrackList;
class TimeTrack;
struct AudioIOStartStreamOptions; struct AudioIOStartStreamOptions;
class SelectedRegion; class SelectedRegion;

View File

@ -40,7 +40,7 @@
#include "../KeyboardCapture.h" #include "../KeyboardCapture.h"
#include "../Project.h" #include "../Project.h"
#include "../ProjectAudioManager.h" #include "../ProjectAudioManager.h"
#include "../TimeTrack.h" #include "../Envelope.h"
#include "../ViewInfo.h" #include "../ViewInfo.h"
#include "../WaveTrack.h" #include "../WaveTrack.h"
#include "../widgets/AButton.h" #include "../widgets/AButton.h"
@ -443,6 +443,11 @@ void TranscriptionToolBar::GetSamples(
*slen = ss1 - ss0; *slen = ss1 - ss0;
} }
// PRL: duplicating constants from TimeTrack.cpp
//TODO-MB: are these sensible values?
#define TIMETRACK_MIN 0.01
#define TIMETRACK_MAX 10.0
// Come here from button clicks, or commands // Come here from button clicks, or commands
void TranscriptionToolBar::PlayAtSpeed(bool looped, bool cutPreview) void TranscriptionToolBar::PlayAtSpeed(bool looped, bool cutPreview)
{ {
@ -464,17 +469,16 @@ void TranscriptionToolBar::PlayAtSpeed(bool looped, bool cutPreview)
bFixedSpeedPlay = bFixedSpeedPlay || looped || cutPreview; bFixedSpeedPlay = bFixedSpeedPlay || looped || cutPreview;
if (bFixedSpeedPlay) if (bFixedSpeedPlay)
{ {
// Create a TimeTrack if we haven't done so already // Create a BoundedEnvelope if we haven't done so already
if (!mTimeTrack) { if (!mEnvelope) {
mTimeTrack = TrackFactory::Get( *p ).NewTimeTrack(); mEnvelope =
if (!mTimeTrack) { std::make_unique<BoundedEnvelope>(
return; true, TIMETRACK_MIN, TIMETRACK_MAX, 1.0);
}
} }
// Set the speed range // Set the speed range
//mTimeTrack->SetRangeUpper((double)mPlaySpeed / 100.0); //mTimeTrack->SetRangeUpper((double)mPlaySpeed / 100.0);
//mTimeTrack->SetRangeLower((double)mPlaySpeed / 100.0); //mTimeTrack->SetRangeLower((double)mPlaySpeed / 100.0);
mTimeTrack->GetEnvelope()->Flatten((double)mPlaySpeed / 100.0); mEnvelope->Flatten((double)mPlaySpeed / 100.0);
} }
// Pop up the button // Pop up the button
@ -498,7 +502,7 @@ void TranscriptionToolBar::PlayAtSpeed(bool looped, bool cutPreview)
auto options = DefaultPlayOptions( *p ); auto options = DefaultPlayOptions( *p );
options.playLooped = looped; options.playLooped = looped;
// No need to set cutPreview options. // No need to set cutPreview options.
options.timeTrack = mTimeTrack.get(); options.envelope = mEnvelope.get();
auto mode = auto mode =
cutPreview ? PlayMode::cutPreviewPlay cutPreview ? PlayMode::cutPreviewPlay
: options.playLooped ? PlayMode::loopedPlay : options.playLooped ? PlayMode::loopedPlay

View File

@ -29,7 +29,7 @@ class wxKeyEvent;
class AButton; class AButton;
class ASlider; class ASlider;
class AudacityProject; class AudacityProject;
class TimeTrack; class BoundedEnvelope;
class WaveTrack; class WaveTrack;
#ifdef EXPERIMENTAL_VOICE_DETECTION #ifdef EXPERIMENTAL_VOICE_DETECTION
@ -152,7 +152,7 @@ class TranscriptionToolBar final : public ToolBar {
int mBackgroundWidth; int mBackgroundWidth;
int mBackgroundHeight; int mBackgroundHeight;
std::shared_ptr<TimeTrack> mTimeTrack; std::shared_ptr<BoundedEnvelope> mEnvelope;
public: public:

View File

@ -387,7 +387,7 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx)
auto options = auto options =
DefaultPlayOptions( *mProject ); DefaultPlayOptions( *mProject );
options.pScrubbingOptions = &mOptions; options.pScrubbingOptions = &mOptions;
options.timeTrack = NULL; options.envelope = nullptr;
mOptions.delay = (ScrubPollInterval_ms / 1000.0); mOptions.delay = (ScrubPollInterval_ms / 1000.0);
mOptions.isPlayingAtSpeed = false; mOptions.isPlayingAtSpeed = false;
mOptions.minSpeed = 0.0; mOptions.minSpeed = 0.0;
@ -487,7 +487,7 @@ bool Scrubber::StartSpeedPlay(double speed, double time0, double time1)
auto options = DefaultSpeedPlayOptions( *mProject ); auto options = DefaultSpeedPlayOptions( *mProject );
options.pScrubbingOptions = &mOptions; options.pScrubbingOptions = &mOptions;
options.timeTrack = NULL; options.envelope = nullptr;
mOptions.delay = (ScrubPollInterval_ms / 1000.0); mOptions.delay = (ScrubPollInterval_ms / 1000.0);
mOptions.minSpeed = speed -0.01; mOptions.minSpeed = speed -0.01;
mOptions.maxSpeed = speed +0.01; mOptions.maxSpeed = speed +0.01;

View File

@ -64,8 +64,8 @@ array of Ruler::Label.
#include "../AColor.h" #include "../AColor.h"
#include "../AllThemeResources.h" #include "../AllThemeResources.h"
#include "../Envelope.h"
#include "../NumberScale.h" #include "../NumberScale.h"
#include "../TimeTrack.h"
#include "../ViewInfo.h" #include "../ViewInfo.h"
using std::min; using std::min;
@ -954,7 +954,19 @@ void Ruler::Update()
Update(NULL); Update(NULL);
} }
void Ruler::Update(const TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, long maxSpeed ) namespace {
double ComputeWarpedLength(const Envelope &env, double t0, double t1)
{
return env.IntegralOfInverse(t0, t1);
}
double SolveWarpedLength(const Envelope &env, double t0, double length)
{
return env.SolveIntegralOfInverse(t0, length);
}
}
void Ruler::Update(const Envelope* envelope)// Envelope *speedEnv, long minSpeed, long maxSpeed )
{ {
const ZoomInfo *zoomInfo = NULL; const ZoomInfo *zoomInfo = NULL;
if (!mLog && mOrientation == wxHORIZONTAL) if (!mLog && mOrientation == wxHORIZONTAL)
@ -1115,8 +1127,8 @@ void Ruler::Update(const TimeTrack* timetrack)// Envelope *speedEnv, long minSpe
} }
else else
d = mMin - UPP / 2; d = mMin - UPP / 2;
if (timetrack) if (envelope)
warpedD = timetrack->ComputeWarpedLength(0.0, d); warpedD = ComputeWarpedLength(*envelope, 0.0, d);
else else
warpedD = d; warpedD = d;
// using ints doesn't work, as // using ints doesn't work, as
@ -1133,8 +1145,8 @@ void Ruler::Update(const TimeTrack* timetrack)// Envelope *speedEnv, long minSpe
} }
else else
nextD = d + UPP; nextD = d + UPP;
if (timetrack) if (envelope)
warpedD += timetrack->ComputeWarpedLength(d, nextD); warpedD += ComputeWarpedLength(*envelope, d, nextD);
else else
warpedD = nextD; warpedD = nextD;
d = nextD; d = nextD;
@ -1290,14 +1302,14 @@ void Ruler::Draw(wxDC& dc)
Draw( dc, NULL); Draw( dc, NULL);
} }
void Ruler::Draw(wxDC& dc, const TimeTrack* timetrack) void Ruler::Draw(wxDC& dc, const Envelope* envelope)
{ {
mDC = &dc; mDC = &dc;
if( mLength <=0 ) if( mLength <=0 )
return; return;
if (!mValid) if (!mValid)
Update(timetrack); Update(envelope);
mDC->SetTextForeground( mTickColour ); mDC->SetTextForeground( mTickColour );
#ifdef EXPERIMENTAL_THEMING #ifdef EXPERIMENTAL_THEMING

View File

@ -21,7 +21,7 @@ class wxDC;
class wxFont; class wxFont;
class NumberScale; class NumberScale;
class TimeTrack; class Envelope;
class ZoomInfo; class ZoomInfo;
class AUDACITY_DLL_API Ruler { class AUDACITY_DLL_API Ruler {
@ -136,7 +136,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, const TimeTrack* timetrack); void Draw(wxDC& dc, const Envelope* envelope);
// 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.
@ -151,7 +151,7 @@ class AUDACITY_DLL_API Ruler {
private: private:
void Update(); void Update();
void Update(const TimeTrack* timetrack); void Update(const Envelope* envelope);
void FindTickSizes(); void FindTickSizes();
void FindLinearTickSizes(double UPP); void FindLinearTickSizes(double UPP);
wxString LabelString(double d, bool major); wxString LabelString(double d, bool major);