Preliminary function argument list changes and comments, for scrubbing project

In particular, use an options structure for AudioIO::StartStream to simplify
calls

ControlToolBar::PlayPlayRegion also takes that structure as an argument, and a
SelectedRegion instead of two times

And other changes
This commit is contained in:
Paul-Licameli 2015-04-14 14:52:22 -04:00
parent 21fd4ab374
commit 2b85d0edb4
15 changed files with 235 additions and 123 deletions

View File

@ -1148,13 +1148,8 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
#ifdef EXPERIMENTAL_MIDI_OUT
NoteTrackArray midiPlaybackTracks,
#endif
TimeTrack *timeTrack, double sampleRate,
double t0, double t1,
AudioIOListener* listener,
bool playLooped /* = false */,
double cutPreviewGapStart /* = 0.0 */,
double cutPreviewGapLen, /* = 0.0 */
const double * /* pStartTime */ /* = 0 */)
double sampleRate, double t0, double t1,
const AudioIOStartStreamOptions &options)
{
if( IsBusy() )
return 0;
@ -1194,8 +1189,8 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
}
mSilenceLevel = (silenceLevelDB + dBRange)/(double)dBRange; // meter goes -dBRange dB -> 0dB
mTimeTrack = timeTrack;
mListener = listener;
mTimeTrack = options.timeTrack;
mListener = options.listener;
mRate = sampleRate;
mT0 = t0;
mT1 = t1;
@ -1207,9 +1202,9 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
#ifdef EXPERIMENTAL_MIDI_OUT
mMidiPlaybackTracks = midiPlaybackTracks;
#endif
mPlayLooped = playLooped;
mCutPreviewGapStart = cutPreviewGapStart;
mCutPreviewGapLen = cutPreviewGapLen;
mPlayLooped = options.playLooped;
mCutPreviewGapStart = options.cutPreviewGapStart;
mCutPreviewGapLen = options.cutPreviewGapLen;
mPlaybackBuffers = NULL;
mPlaybackMixers = NULL;
mCaptureBuffers = NULL;
@ -1326,13 +1321,17 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
memset(mPlaybackBuffers, 0, sizeof(RingBuffer*)*mPlaybackTracks.GetCount());
memset(mPlaybackMixers, 0, sizeof(Mixer*)*mPlaybackTracks.GetCount());
for( unsigned int i = 0; i < mPlaybackTracks.GetCount(); i++ )
const Mixer::WarpOptions &warpOptions =
Mixer::WarpOptions(mTimeTrack);
for (unsigned int i = 0; i < mPlaybackTracks.GetCount(); i++)
{
mPlaybackBuffers[i] = new RingBuffer(floatSample, playbackBufferSize);
// MB: use normal time for the end time, not warped time!
mPlaybackMixers[i] = new Mixer(1, &mPlaybackTracks[i],
mTimeTrack, mT0, mT1, 1,
warpOptions,
mT0, mT1, 1,
playbackMixBufferSize, false,
mRate, floatSample, false);
mPlaybackMixers[i]->ApplyTrackGains(false);

View File

@ -42,6 +42,7 @@ class Resample;
class TimeTrack;
class AudioThread;
class Meter;
class SelectedRegion;
class TimeTrack;
class wxDialog;
@ -74,6 +75,25 @@ DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_AUDIOIO_PLAYBACK, -1);
DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_AUDIOIO_CAPTURE, -1);
DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_AUDIOIO_MONITOR, -1);
// To avoid growing the argument list of StartStream, add fields here
struct AudioIOStartStreamOptions
{
AudioIOStartStreamOptions()
: timeTrack(NULL)
, listener(NULL)
, playLooped(false)
, cutPreviewGapStart(0.0)
, cutPreviewGapLen(0.0)
{}
TimeTrack *timeTrack;
AudioIOListener* listener;
bool playLooped;
double cutPreviewGapStart;
double cutPreviewGapLen;
};
class AUDACITY_DLL_API AudioIO {
public:
@ -103,15 +123,9 @@ class AUDACITY_DLL_API AudioIO {
#ifdef EXPERIMENTAL_MIDI_OUT
NoteTrackArray midiTracks,
#endif
TimeTrack *timeTrack, double sampleRate,
double t0, double t1,
AudioIOListener* listener,
bool playLooped = false,
double cutPreviewGapStart = 0.0,
double cutPreviewGapLen = 0.0,
// May be other than t0,
// but will be constrained between t0 and t1
const double *pStartTime = 0);
double sampleRate, double t0, double t1,
const AudioIOStartStreamOptions &options =
AudioIOStartStreamOptions());
/** \brief Stop recording, playback or input monitoring.
*
@ -281,9 +295,8 @@ class AUDACITY_DLL_API AudioIO {
*/
static int GetOptimalSupportedSampleRate();
/** \brief The time the stream has been playing for
/** \brief During playback, the (unwarped) track time most recently played
*
* This is given in seconds based on starting at t0
* When playing looped, this will start from t0 again,
* too. So the returned time should be always between
* t0 and t1
@ -375,10 +388,10 @@ private:
#endif
/** \brief Get the number of audio samples free in all of the playback
* buffers.
*
* Returns the smallest of the buffer free space values in the event that
* they are different. */
* buffers.
*
* Returns the smallest of the buffer free space values in the event that
* they are different. */
int GetCommonlyAvailPlayback();
/** \brief Get the number of audio samples ready in all of the recording
@ -535,7 +548,7 @@ private:
Meter *mInputMeter;
Meter *mOutputMeter;
bool mUpdateMeters;
bool mUpdatingMeters;
volatile bool mUpdatingMeters;
#if USE_PORTMIXER
PxMixer *mPortMixer;

View File

@ -2013,7 +2013,8 @@ void AudacityProject::OnPlayOneSecond()
double pos = mTrackPanel->GetMostRecentXPos();
mLastPlayMode = oneSecondPlay;
GetControlToolBar()->PlayPlayRegion(pos - 0.5, pos + 0.5);
GetControlToolBar()->PlayPlayRegion
(SelectedRegion(pos - 0.5, pos + 0.5), GetDefaultPlayOptions());
}
@ -2056,7 +2057,8 @@ void AudacityProject::OnPlayToSelection()
// only when playing a short region, less than or equal to a second.
// mLastPlayMode = ((t1-t0) > 1.0) ? normalPlay : oneSecondPlay;
GetControlToolBar()->PlayPlayRegion(t0, t1);
GetControlToolBar()->PlayPlayRegion
(SelectedRegion(t0, t1), GetDefaultPlayOptions());
}
// The next 4 functions provide a limited version of the
@ -2073,7 +2075,7 @@ void AudacityProject::OnPlayBeforeSelectionStart()
mLastPlayMode = oneSecondPlay; // this disables auto scrolling, as in OnPlayToSelection()
GetControlToolBar()->PlayPlayRegion(t0 - beforeLen, t0);
GetControlToolBar()->PlayPlayRegion(SelectedRegion(t0 - beforeLen, t0), GetDefaultPlayOptions());
}
void AudacityProject::OnPlayAfterSelectionStart()
@ -2089,9 +2091,9 @@ void AudacityProject::OnPlayAfterSelectionStart()
mLastPlayMode = oneSecondPlay; // this disables auto scrolling, as in OnPlayToSelection()
if ( t1 - t0 > 0.0 && t1 - t0 < afterLen )
GetControlToolBar()->PlayPlayRegion(t0, t1);
GetControlToolBar()->PlayPlayRegion(SelectedRegion(t0, t1), GetDefaultPlayOptions());
else
GetControlToolBar()->PlayPlayRegion(t0, t0 + afterLen);
GetControlToolBar()->PlayPlayRegion(SelectedRegion(t0, t0 + afterLen), GetDefaultPlayOptions());
}
void AudacityProject::OnPlayBeforeSelectionEnd()
@ -2107,9 +2109,9 @@ void AudacityProject::OnPlayBeforeSelectionEnd()
mLastPlayMode = oneSecondPlay; // this disables auto scrolling, as in OnPlayToSelection()
if ( t1 - t0 > 0.0 && t1 - t0 < beforeLen )
GetControlToolBar()->PlayPlayRegion(t0, t1);
GetControlToolBar()->PlayPlayRegion(SelectedRegion(t0, t1), GetDefaultPlayOptions());
else
GetControlToolBar()->PlayPlayRegion(t1 - beforeLen, t1);
GetControlToolBar()->PlayPlayRegion(SelectedRegion(t1 - beforeLen, t1), GetDefaultPlayOptions());
}
@ -2124,7 +2126,7 @@ void AudacityProject::OnPlayAfterSelectionEnd()
mLastPlayMode = oneSecondPlay; // this disables auto scrolling, as in OnPlayToSelection()
GetControlToolBar()->PlayPlayRegion(t1, t1 + afterLen);
GetControlToolBar()->PlayPlayRegion(SelectedRegion(t1, t1 + afterLen), GetDefaultPlayOptions());
}
void AudacityProject::OnPlayLooped()

View File

@ -161,7 +161,8 @@ bool MixAndRender(TrackList *tracks, TrackFactory *trackFactory,
endTime = mixEndTime;
}
Mixer *mixer = new Mixer(numWaves, waveArray, tracks->GetTimeTrack(),
Mixer *mixer = new Mixer(numWaves, waveArray,
Mixer::WarpOptions(tracks->GetTimeTrack()),
startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
rate, format);
@ -226,8 +227,28 @@ bool MixAndRender(TrackList *tracks, TrackFactory *trackFactory,
return (updateResult == eProgressSuccess || updateResult == eProgressStopped);
}
Mixer::WarpOptions::WarpOptions(double min, double max)
: timeTrack(0), minSpeed(min), maxSpeed(max)
{
if (minSpeed < 0)
{
wxASSERT(false);
minSpeed = 0;
}
if (maxSpeed < 0)
{
wxASSERT(false);
maxSpeed = 0;
}
if (minSpeed > maxSpeed)
{
wxASSERT(false);
std::swap(minSpeed, maxSpeed);
}
}
Mixer::Mixer(int numInputTracks, WaveTrack **inputTracks,
TimeTrack *timeTrack,
const WarpOptions &warpOptions,
double startTime, double stopTime,
int numOutChannels, int outBufferSize, bool outInterleaved,
double outRate, sampleFormat outFormat,
@ -238,12 +259,15 @@ Mixer::Mixer(int numInputTracks, WaveTrack **inputTracks,
mHighQuality = highQuality;
mNumInputTracks = numInputTracks;
mInputTrack = new WaveTrack*[mNumInputTracks];
// mSamplePos holds for each track the next sample position not
// yet processed.
mSamplePos = new sampleCount[mNumInputTracks];
for(i=0; i<mNumInputTracks; i++) {
mInputTrack[i] = inputTracks[i];
mSamplePos[i] = inputTracks[i]->TimeToLongSamples(startTime);
}
mTimeTrack = timeTrack;
mTimeTrack = warpOptions.timeTrack;
mT0 = startTime;
mT1 = stopTime;
mTime = startTime;
@ -277,23 +301,45 @@ Mixer::Mixer(int numInputTracks, WaveTrack **inputTracks,
}
mFloatBuffer = new float[mInterleavedBufferSize];
// This is the number of samples grabbed in one go from a track
// and placed in a queue, when mixing with resampling.
// (Should we use WaveTrack::GetBestBlockSize instead?)
mQueueMaxLen = 65536;
// But cut the queue into blocks of this finer size
// for variable rate resampling. Each block is resampled at some
// constant rate.
mProcessLen = 1024;
// Position in each queue of the start of the next block to resample.
mQueueStart = new int[mNumInputTracks];
// For each queue, the number of available samples after the queue start.
mQueueLen = new int[mNumInputTracks];
mSampleQueue = new float *[mNumInputTracks];
mResample = new Resample*[mNumInputTracks];
for(i=0; i<mNumInputTracks; i++) {
double factor = (mRate / mInputTrack[i]->GetRate());
if (timeTrack) {
double minFactor, maxFactor;
if (mTimeTrack) {
// variable rate resampling
mResample[i] = new Resample(mHighQuality,
factor / timeTrack->GetRangeUpper(),
factor / timeTrack->GetRangeLower());
} else {
mResample[i] = new Resample(mHighQuality, factor, factor); // constant rate resampling
mbVariableRates = true;
minFactor = factor / mTimeTrack->GetRangeUpper();
maxFactor = factor / mTimeTrack->GetRangeLower();
}
else if (warpOptions.minSpeed > 0.0 && warpOptions.maxSpeed > 0.0) {
// variable rate resampling
mbVariableRates = true;
minFactor = factor / warpOptions.maxSpeed;
maxFactor = factor / warpOptions.minSpeed;
}
else {
// constant rate resampling
mbVariableRates = false;
minFactor = maxFactor = factor;
}
mResample[i] = new Resample(mHighQuality, minFactor, maxFactor);
mSampleQueue[i] = new float[mQueueMaxLen];
mQueueStart[i] = 0;
mQueueLen[i] = 0;
@ -408,6 +454,7 @@ sampleCount Mixer::MixVariableRates(int *channelFlags, WaveTrack *track,
while (out < mMaxOut) {
if (*queueLen < mProcessLen) {
// Shift pending portion to start of the buffer
memmove(queue, &queue[*queueStart], (*queueLen) * sampleSize);
*queueStart = 0;
@ -581,7 +628,7 @@ sampleCount Mixer::Process(sampleCount maxToProcess)
}
}
if (mTimeTrack || track->GetRate() != mRate)
if (mbVariableRates || track->GetRate() != mRate)
out = MixVariableRates(channelFlags, track,
&mSamplePos[i], mSampleQueue[i],
&mQueueStart[i], &mQueueLen[i], mResample[i]);
@ -594,28 +641,27 @@ sampleCount Mixer::Process(sampleCount maxToProcess)
double t = (double)mSamplePos[i] / (double)track->GetRate();
if(t > mTime)
mTime = std::min(t, mT1);
}
if(mInterleaved) {
for(int c=0; c<mNumChannels; c++) {
CopySamples(mTemp[0] + (c * SAMPLE_SIZE(floatSample)),
floatSample,
mBuffer[0] + (c * SAMPLE_SIZE(mFormat)),
mFormat,
maxOut,
mHighQuality,
mNumChannels,
mNumChannels);
floatSample,
mBuffer[0] + (c * SAMPLE_SIZE(mFormat)),
mFormat,
maxOut,
mHighQuality,
mNumChannels,
mNumChannels);
}
}
else {
for(int c=0; c<mNumBuffers; c++) {
CopySamples(mTemp[c],
floatSample,
mBuffer[c],
mFormat,
maxOut,
mHighQuality);
CopySamples(mTemp[c],
floatSample,
mBuffer[c],
mFormat,
maxOut,
mHighQuality);
}
}
// MB: this doesn't take warping into account, replaced with code based on mSamplePos

View File

@ -67,12 +67,29 @@ class AUDACITY_DLL_API MixerSpec
class AUDACITY_DLL_API Mixer {
public:
//
// An argument to Mixer's constructor
class WarpOptions
{
public:
explicit WarpOptions(TimeTrack *t)
: timeTrack(t), minSpeed(0.0), maxSpeed(0.0)
{}
WarpOptions(double min, double max);
private:
friend class Mixer;
TimeTrack *timeTrack;
double minSpeed, maxSpeed;
};
//
// Constructor / Destructor
//
Mixer(int numInputTracks, WaveTrack **inputTracks,
TimeTrack *timeTrack,
const WarpOptions &warpOptions,
double startTime, double stopTime,
int numOutChannels, int outBufferSize, bool outInterleaved,
double outRate, sampleFormat outFormat,
@ -129,6 +146,7 @@ class AUDACITY_DLL_API Mixer {
// Input
int mNumInputTracks;
WaveTrack **mInputTrack;
bool mbVariableRates;
TimeTrack *mTimeTrack;
sampleCount *mSamplePos;
bool mApplyTrackGains;

View File

@ -1037,6 +1037,14 @@ AudacityProject::~AudacityProject()
wxGetApp().GetRecentFiles()->RemoveMenu(mRecentFilesMenu);
}
AudioIOStartStreamOptions AudacityProject::GetDefaultPlayOptions()
{
AudioIOStartStreamOptions options;
options.timeTrack = GetTracks()->GetTimeTrack();
options.listener = this;
return options;
}
void AudacityProject::UpdatePrefsVariables()
{
gPrefs->Read(wxT("/AudioFiles/ShowId3Dialog"), &mShowId3Dialog, true);

View File

@ -82,6 +82,7 @@ class LyricsWindow;
class MixerBoard;
class MixerBoardFrame;
struct AudioIOStartStreamOptions;
AudacityProject *CreateNewAudacityProject();
AUDACITY_DLL_API AudacityProject *GetActiveProject();
@ -135,6 +136,8 @@ class AUDACITY_DLL_API AudacityProject: public wxFrame,
const wxPoint & pos, const wxSize & size);
virtual ~AudacityProject();
AudioIOStartStreamOptions GetDefaultPlayOptions();
TrackList *GetTracks() { return mTracks; }
UndoManager *GetUndoManager() { return &mUndoManager; }

View File

@ -1248,7 +1248,7 @@ bool Sequence::Set(samplePtr buffer, sampleFormat format,
}
bool Sequence::GetWaveDisplay(float *min, float *max, float *rms,int* bl,
int len, sampleCount *where,
int len, const sampleCount *where,
double samplesPerPixel)
{
sampleCount s0 = where[0];

View File

@ -80,7 +80,7 @@ class Sequence: public XMLTagHandler {
sampleCount start, sampleCount len);
bool GetWaveDisplay(float *min, float *max, float *rms,int* bl,
int len, sampleCount *where,
int len, const sampleCount *where,
double samplesPerPixel);
bool Copy(sampleCount s0, sampleCount s1, Sequence **dest);

View File

@ -973,7 +973,7 @@ void TrackPanel::OnTimer()
AudacityProject *p = GetProject();
if ((p->GetAudioIOToken() > 0) &&
gAudioIO->IsStreamActive(p->GetAudioIOToken()))
gAudioIO->IsStreamActive(p->GetAudioIOToken()))
{
// Update lyrics display.
LyricsWindow* pLyricsWindow = p->GetLyricsWindow();
@ -991,11 +991,11 @@ void TrackPanel::OnTimer()
// audacityAudioCallback where it calls gAudioIO->mOutputMeter->UpdateDisplay().
MixerBoard* pMixerBoard = this->GetMixerBoard();
if (pMixerBoard &&
(p->GetAudioIOToken() > 0) &&
gAudioIO->IsStreamActive(p->GetAudioIOToken()))
(p->GetAudioIOToken() > 0) &&
gAudioIO->IsStreamActive(p->GetAudioIOToken()))
{
pMixerBoard->UpdateMeters(gAudioIO->GetStreamTime(),
(p->mLastPlayMode == loopedPlay));
(p->mLastPlayMode == loopedPlay));
}
// Check whether we were playing or recording, but the stream has stopped.
@ -1379,27 +1379,29 @@ void TrackPanel::OnPaint(wxPaintEvent & /* event */)
mRefreshBacking = false;
// Redraw the backing bitmap
DrawTracks( &mBackingDC );
DrawTracks(&mBackingDC);
// Copy it to the display
dc->Blit( 0, 0, mBacking->GetWidth(), mBacking->GetHeight(), &mBackingDC, 0, 0 );
dc->Blit(0, 0, mBacking->GetWidth(), mBacking->GetHeight(), &mBackingDC, 0, 0);
}
else
{
// Copy full, possibly clipped, damage rectange
dc->Blit( box.x, box.y, box.width, box.height, &mBackingDC, box.x, box.y );
dc->Blit(box.x, box.y, box.width, box.height, &mBackingDC, box.x, box.y);
}
// Done with the clipped DC
delete dc;
// Drawing now goes directly to the client area
wxClientDC cdc( this );
wxClientDC cdc(this);
// Update the indicator in case it was damaged if this project is playing
// PRL: mIndicatorShowing never becomes true!
AudacityProject* p = GetProject();
if (!gAudioIO->IsPaused() &&
( mIndicatorShowing || gAudioIO->IsStreamActive(p->GetAudioIOToken())))
(mIndicatorShowing || gAudioIO->IsStreamActive(p->GetAudioIOToken())))
{
// We just want to repair, not update the old, so set the second param to true.
// This is important because this onPaint could be for just some of the tracks.
@ -1407,8 +1409,8 @@ void TrackPanel::OnPaint(wxPaintEvent & /* event */)
}
// Draw the cursor
if( mViewInfo->selectedRegion.isPoint())
DoDrawCursor( cdc );
if (mViewInfo->selectedRegion.isPoint())
DoDrawCursor(cdc);
#if DEBUG_DRAW_TIMING
sw.Pause();
@ -2119,7 +2121,8 @@ void TrackPanel::StartOrJumpPlayback(wxMouseEvent &event)
//the clicked point
ControlToolBar * ctb = p->GetControlToolBar();
//ctb->SetPlay(true);// Not needed as done in PlayPlayRegion
ctb->PlayPlayRegion(clicktime, endtime,false) ;
ctb->PlayPlayRegion
(SelectedRegion(clicktime, endtime), p->GetDefaultPlayOptions());
}
else
{
@ -2130,7 +2133,7 @@ void TrackPanel::StartOrJumpPlayback(wxMouseEvent &event)
//require a new method in ControlToolBar: SetPause();
ControlToolBar * ctb = p->GetControlToolBar();
ctb->StopPlaying();
ctb->PlayPlayRegion(clicktime,endtime,false) ;
ctb->PlayPlayRegion(SelectedRegion(clicktime, endtime), p->GetDefaultPlayOptions());
}
}
}

View File

@ -2265,7 +2265,7 @@ void Effect::Preview(bool dryOnly)
#ifdef EXPERIMENTAL_MIDI_OUT
empty,
#endif
NULL, rate, t0, t1, NULL);
rate, t0, t1);
if (token) {
int previewing = eProgressSuccess;
@ -2959,7 +2959,9 @@ void EffectUIHost::OnPlay(wxCommandEvent & WXUNUSED(evt))
mPlayPos = mRegion.t1();
}
mProject->GetControlToolBar()->PlayPlayRegion(mPlayPos, mRegion.t1());
mProject->GetControlToolBar()->PlayPlayRegion
(SelectedRegion(mPlayPos, mRegion.t1()),
mProject->GetDefaultPlayOptions());
}
}

View File

@ -277,7 +277,7 @@ Mixer* ExportPlugin::CreateMixer(int numInputTracks, WaveTrack **inputTracks,
{
// MB: the stop time should not be warped, this was a bug.
return new Mixer(numInputTracks, inputTracks,
timeTrack,
Mixer::WarpOptions(timeTrack),
startTime, stopTime,
numOutChannels, outBufferSize, outInterleaved,
outRate, outFormat,

View File

@ -467,34 +467,42 @@ bool ControlToolBar::IsRecordDown()
{
return mRecord->IsDown();
}
void ControlToolBar::PlayPlayRegion(double t0, double t1,
bool looped /* = false */,
bool cutpreview /* = false */,
TimeTrack *timetrack /* = NULL */,
const double *pStartTime /* = NULL */)
int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion,
const AudioIOStartStreamOptions &options,
bool cutpreview, /* = false */
bool backwards /* = false */)
{
double t0 = selectedRegion.t0();
double t1 = selectedRegion.t1();
// SelectedRegion guarantees t0 <= t1, so we need another boolean argument
// to indicate backwards play.
const bool looped = options.playLooped;
wxASSERT(! backwards);
SetPlay(true, looped, cutpreview);
if (gAudioIO->IsBusy()) {
SetPlay(false);
return;
return -1;
}
if (cutpreview && t0==t1) {
SetPlay(false);
return; /* msmeyer: makes no sense */
return -1; /* msmeyer: makes no sense */
}
AudacityProject *p = GetActiveProject();
if (!p) {
SetPlay(false);
return; // Should never happen, but...
return -1; // Should never happen, but...
}
TrackList *t = p->GetTracks();
if (!t) {
mPlay->PopUp();
return; // Should never happen, but...
return -1; // Should never happen, but...
}
bool hasaudio = false;
@ -512,7 +520,7 @@ void ControlToolBar::PlayPlayRegion(double t0, double t1,
if (!hasaudio) {
SetPlay(false);
return; // No need to continue without audio tracks
return -1; // No need to continue without audio tracks
}
double maxofmins,minofmaxs;
@ -565,7 +573,7 @@ void ControlToolBar::PlayPlayRegion(double t0, double t1,
// we test if the intersection has no volume
if (minofmaxs <= maxofmins) {
// no volume; play nothing
return;
return -1;
}
else {
t0 = maxofmins;
@ -573,14 +581,15 @@ void ControlToolBar::PlayPlayRegion(double t0, double t1,
}
}
// Can't play before 0...either shifted or latencey corrected tracks
if (t0 < 0.0) {
// Can't play before 0...either shifted or latency corrected tracks
if (t0 < 0.0)
t0 = 0.0;
}
if (t1 < 0.0)
t1 = 0.0;
int token = -1;
bool success = false;
if (t1 > t0) {
int token;
if (cutpreview) {
double beforeLen, afterLen;
gPrefs->Read(wxT("/AudioIO/CutPreviewBeforeLen"), &beforeLen, 2.0);
@ -590,36 +599,37 @@ void ControlToolBar::PlayPlayRegion(double t0, double t1,
SetupCutPreviewTracks(tcp0, t0, t1, tcp1);
if (mCutPreviewTracks)
{
AudioIOStartStreamOptions myOptions = options;
myOptions.cutPreviewGapStart = t0;
myOptions.cutPreviewGapLen = t1 - t0;
token = gAudioIO->StartStream(
mCutPreviewTracks->GetWaveTrackArray(false),
WaveTrackArray(),
#ifdef EXPERIMENTAL_MIDI_OUT
NoteTrackArray(),
#endif
timetrack, p->GetRate(), tcp0, tcp1, p, false,
t0, t1-t0,
pStartTime);
p->GetRate(), tcp0, tcp1, myOptions);
} else
{
// Cannot create cut preview tracks, clean up and exit
SetPlay(false);
SetStop(false);
SetRecord(false);
return;
return -1;
}
} else {
// Lifted the following into AudacityProject::GetDefaultPlayOptions()
/*
if (!timetrack) {
timetrack = t->GetTimeTrack();
}
*/
token = gAudioIO->StartStream(t->GetWaveTrackArray(false),
WaveTrackArray(),
#ifdef EXPERIMENTAL_MIDI_OUT
t->GetNoteTrackArray(false),
#endif
timetrack,
p->GetRate(), t0, t1, p, looped,
0, 0,
pStartTime);
p->GetRate(), t0, t1, options);
}
if (token != 0) {
success = true;
@ -648,7 +658,10 @@ void ControlToolBar::PlayPlayRegion(double t0, double t1,
SetPlay(false);
SetStop(false);
SetRecord(false);
return -1;
}
return token;
}
void ControlToolBar::PlayCurrentRegion(bool looped /* = false */,
@ -666,9 +679,12 @@ void ControlToolBar::PlayCurrentRegion(bool looped /* = false */,
double playRegionStart, playRegionEnd;
p->GetPlayRegion(&playRegionStart, &playRegionEnd);
PlayPlayRegion(playRegionStart,
playRegionEnd,
looped, cutpreview);
AudioIOStartStreamOptions options(p->GetDefaultPlayOptions());
options.playLooped = looped;
if (cutpreview)
options.timeTrack = NULL;
PlayPlayRegion(SelectedRegion(playRegionStart, playRegionEnd),
options, cutpreview);
}
}
@ -898,14 +914,14 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
#ifdef AUTOMATED_INPUT_LEVEL_ADJUSTMENT
gAudioIO->AILAInitialize();
#endif
AudioIOStartStreamOptions options(p->GetDefaultPlayOptions());
int token = gAudioIO->StartStream(playbackTracks,
newRecordingTracks,
#ifdef EXPERIMENTAL_MIDI_OUT
midiTracks,
#endif
t->GetTimeTrack(),
p->GetRate(), t0, t1, p);
p->GetRate(), t0, t1, options);
bool success = (token != 0);

View File

@ -30,6 +30,9 @@ class AudacityProject;
class TrackList;
class TimeTrack;
struct AudioIOStartStreamOptions;
class SelectedRegion;
// In the GUI, ControlToolBar appears as the "Transport Toolbar". "Control Toolbar" is historic.
class ControlToolBar:public ToolBar {
@ -64,13 +67,10 @@ class ControlToolBar:public ToolBar {
// play from current cursor.
void PlayCurrentRegion(bool looped = false, bool cutpreview = false);
// Play the region [t0,t1]
void PlayPlayRegion(double t0, double t1,
bool looped = false,
bool cutpreview = false,
TimeTrack *timetrack = NULL,
// May be other than t0,
// but will be constrained between t0 and t1
const double *pStartTime = NULL);
// Return the Audio IO token or -1 for failure
int PlayPlayRegion(const SelectedRegion &selectedRegion,
const AudioIOStartStreamOptions &options,
bool cutpreview = false, bool backwards = false);
void PlayDefault();
// Stop playing

View File

@ -439,11 +439,13 @@ void TranscriptionToolBar::PlayAtSpeed(bool looped, bool cutPreview)
#ifdef EXPERIMENTAL_MIDI_OUT
gAudioIO->SetMidiPlaySpeed(mPlaySpeed);
#endif
p->GetControlToolBar()->PlayPlayRegion(playRegionStart,
playRegionEnd,
looped,
cutPreview,
mTimeTrack);
AudioIOStartStreamOptions options(p->GetDefaultPlayOptions());
options.playLooped = looped;
options.timeTrack = mTimeTrack;
p->GetControlToolBar()->PlayPlayRegion
(SelectedRegion(playRegionStart, playRegionEnd),
options,
cutPreview);
}
}