mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-03 17:19:43 +02:00
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:
parent
21fd4ab374
commit
2b85d0edb4
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
94
src/Mix.cpp
94
src/Mix.cpp
@ -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
|
||||
|
22
src/Mix.h
22
src/Mix.h
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user