void ControlToolBar::PlayPlayRegion(double t0, double t1, bool looped /* = false */, bool cutpreview /* = false */, TimeTrack *timetrack /* = NULL */, const double *pStartTime /* = NULL */) { SetPlay(true, looped, cutpreview); if (gAudioIO->IsBusy()) { SetPlay(false); return; } if (cutpreview && t0==t1) { SetPlay(false); return; /* msmeyer: makes no sense */ } AudacityProject *p = GetActiveProject(); if (!p) { SetPlay(false); return; // Should never happen, but... } TrackList *t = p->GetTracks(); if (!t) { mPlay->PopUp(); return; // Should never happen, but... } bool hasaudio = false; TrackListIterator iter(t); for (Track *trk = iter.First(); trk; trk = iter.Next()) { if (trk->GetKind() == Track::Wave #ifdef EXPERIMENTAL_MIDI_OUT || trk->GetKind() == Track::Note #endif ) { hasaudio = true; break; } } if (!hasaudio) { SetPlay(false); return; // No need to continue without audio tracks } double maxofmins,minofmaxs; #if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR) double init_seek = 0.0; #endif // JS: clarified how the final play region is computed; if (t1 == t0) { // msmeyer: When playing looped, we play the whole file, if // no range is selected. Otherwise, we play from t0 to end if (looped) { // msmeyer: always play from start t0 = t->GetStartTime(); } else { // move t0 to valid range if (t0 < 0) { t0 = t->GetStartTime(); } else if (t0 > t->GetEndTime()) { t0 = t->GetEndTime(); } #if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR) else { init_seek = t0; //AC: init_seek is where playback will 'start' t0 = t->GetStartTime(); } #endif } // always play to end t1 = t->GetEndTime(); } else { // always t0 < t1 right? // the set intersection between the play region and the // valid range maximum of lower bounds if (t0 < t->GetStartTime()) maxofmins = t->GetStartTime(); else maxofmins = t0; // minimum of upper bounds if (t1 > t->GetEndTime()) minofmaxs = t->GetEndTime(); else minofmaxs = t1; // we test if the intersection has no volume if (minofmaxs <= maxofmins) { // no volume; play nothing return; } else { t0 = maxofmins; t1 = minofmaxs; } } // Can't play before 0...either shifted or latencey corrected tracks if (t0 < 0.0) { t0 = 0.0; } bool success = false; if (t1 > t0) { int token; if (cutpreview) { double beforeLen, afterLen; gPrefs->Read(wxT("/AudioIO/CutPreviewBeforeLen"), &beforeLen, 2.0); gPrefs->Read(wxT("/AudioIO/CutPreviewAfterLen"), &afterLen, 1.0); double tcp0 = t0-beforeLen; double tcp1 = (t1+afterLen) - (t1-t0); SetupCutPreviewTracks(tcp0, t0, t1, tcp1); if (mCutPreviewTracks) { token = gAudioIO->StartStream( mCutPreviewTracks->GetWaveTrackArray(false), WaveTrackArray(), #ifdef EXPERIMENTAL_MIDI_OUT NoteTrackArray(), #endif timetrack, p->GetRate(), tcp0, tcp1, p, false, t0, t1-t0, pStartTime); } else { // Cannot create cut preview tracks, clean up and exit SetPlay(false); SetStop(false); SetRecord(false); return; } } else { 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); } if (token != 0) { success = true; p->SetAudioIOToken(token); mBusyProject = p; #if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR) //AC: If init_seek was set, now's the time to make it happen. gAudioIO->SeekStream(init_seek); #endif } else { // msmeyer: Show error message if stream could not be opened wxMessageBox( #if wxCHECK_VERSION(3,0,0) _("Error while opening sound device. " "Please check the playback device settings and the project sample rate."), #else _("Error while opening sound device. " wxT("Please check the playback device settings and the project sample rate.")), #endif _("Error"), wxOK | wxICON_EXCLAMATION, this); } } if (!success) { SetPlay(false); SetStop(false); SetRecord(false); } }
int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, const AudioIOStartStreamOptions &options, PlayMode mode, PlayAppearance appearance, /* = PlayOption::Straight */ bool backwards, /* = false */ bool playWhiteSpace /* = false */) { if (!CanStopAudioStream()) return -1; // Uncomment this for laughs! // backwards = true; 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; if (backwards) std::swap(t0, t1); SetPlay(true, appearance); if (gAudioIO->IsBusy()) { SetPlay(false); return -1; } const bool cutpreview = appearance == PlayAppearance::CutPreview; if (cutpreview && t0==t1) { SetPlay(false); return -1; /* msmeyer: makes no sense */ } AudacityProject *p = GetActiveProject(); if (!p) { SetPlay(false); return -1; // Should never happen, but... } TrackList *t = p->GetTracks(); if (!t) { mPlay->PopUp(); return -1; // Should never happen, but... } p->mLastPlayMode = mode; bool hasaudio = false; TrackListIterator iter(t); for (Track *trk = iter.First(); trk; trk = iter.Next()) { if (trk->GetKind() == Track::Wave #ifdef EXPERIMENTAL_MIDI_OUT || trk->GetKind() == Track::Note #endif ) { hasaudio = true; break; } } double latestEnd = (playWhiteSpace)? t1 : t->GetEndTime(); if (!hasaudio) { SetPlay(false); return -1; // No need to continue without audio tracks } #if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR) double init_seek = 0.0; #endif if (t1 == t0) { if (looped) { // play selection if there is one, otherwise // set start of play region to project start, // and loop the project from current play position. if ((t0 > p->GetSel0()) && (t0 < p->GetSel1())) { t0 = p->GetSel0(); t1 = p->GetSel1(); } else { // loop the entire project t0 = t->GetStartTime(); t1 = t->GetEndTime(); } } else { // move t0 to valid range if (t0 < 0) { t0 = t->GetStartTime(); } else if (t0 > t->GetEndTime()) { t0 = t->GetEndTime(); } #if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR) else { init_seek = t0; //AC: init_seek is where playback will 'start' t0 = t->GetStartTime(); } #endif } t1 = t->GetEndTime(); } else { // maybe t1 < t0, with backwards scrubbing for instance if (backwards) std::swap(t0, t1); t0 = std::max(0.0, std::min(t0, latestEnd)); t1 = std::max(0.0, std::min(t1, latestEnd)); if (backwards) std::swap(t0, t1); } int token = -1; bool success = false; if (t1 != t0) { if (cutpreview) { const double tless = std::min(t0, t1); const double tgreater = std::max(t0, t1); double beforeLen, afterLen; gPrefs->Read(wxT("/AudioIO/CutPreviewBeforeLen"), &beforeLen, 2.0); gPrefs->Read(wxT("/AudioIO/CutPreviewAfterLen"), &afterLen, 1.0); double tcp0 = tless-beforeLen; double diff = tgreater - tless; double tcp1 = (tgreater+afterLen) - diff; SetupCutPreviewTracks(tcp0, tless, tgreater, tcp1); if (backwards) std::swap(tcp0, 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 tcp0, tcp1, myOptions); } else { // Cannot create cut preview tracks, clean up and exit SetPlay(false); SetStop(false); SetRecord(false); 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 t0, t1, options); } if (token != 0) { success = true; p->SetAudioIOToken(token); mBusyProject = p; #if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR) //AC: If init_seek was set, now's the time to make it happen. gAudioIO->SeekStream(init_seek); #endif } else { // msmeyer: Show error message if stream could not be opened wxMessageBox( _("Error while opening sound device. " "Please check the playback device settings and the project sample rate."), _("Error"), wxOK | wxICON_EXCLAMATION, this); } } if (!success) { SetPlay(false); SetStop(false); SetRecord(false); return -1; } // Let other UI update appearance if (p) p->GetRulerPanel()->HideQuickPlayIndicator(); return token; }