Audacity 3.2.0
Public Member Functions | Static Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
ProjectAudioManager Class Referencefinal

#include <ProjectAudioManager.h>

Inheritance diagram for ProjectAudioManager:
[legend]
Collaboration diagram for ProjectAudioManager:
[legend]

Public Member Functions

 ProjectAudioManager (AudacityProject &project)
 
 ProjectAudioManager (const ProjectAudioManager &)=delete
 
ProjectAudioManageroperator= (const ProjectAudioManager &)=delete
 
 ~ProjectAudioManager () override
 
bool IsTimerRecordCancelled ()
 
void SetTimerRecordCancelled ()
 
void ResetTimerRecordCancelled ()
 
bool Paused () const
 
bool Playing () const
 
bool Recording () const
 
bool Stopping () const
 
bool Appending () const
 
bool Looping () const
 
bool Cutting () const
 
bool CanStopAudioStream () const
 
void OnRecord (bool altAppearance)
 
bool DoRecord (AudacityProject &project, const TransportSequences &transportSequences, double t0, double t1, bool altAppearance, const AudioIOStartStreamOptions &options)
 
int PlayPlayRegion (const SelectedRegion &selectedRegion, const AudioIOStartStreamOptions &options, PlayMode playMode, bool backwards=false)
 
void PlayCurrentRegion (bool newDefault=false, bool cutpreview=false)
 
void OnPause ()
 
void Stop (bool stopStream=true)
 
void StopIfPaused ()
 
bool DoPlayStopSelect (bool click, bool shift)
 
void DoPlayStopSelect ()
 
PlayMode GetLastPlayMode () const
 
- Public Member Functions inherited from ClientData::Base
virtual ~Base ()
 
- Public Member Functions inherited from AudioIOListener
 AudioIOListener ()
 
virtual ~AudioIOListener ()
 
virtual void OnAudioIORate (int rate)=0
 
virtual void OnAudioIOStartRecording ()=0
 
virtual void OnAudioIOStopRecording ()=0
 
virtual void OnAudioIONewBlocks ()=0
 
virtual void OnCommitRecording ()=0
 
virtual void OnSoundActivationThreshold ()=0
 
- Public Member Functions inherited from Observer::Publisher< RecordingDropoutEvent >
 Publisher (ExceptionPolicy *pPolicy=nullptr, Alloc a={})
 Constructor supporting type-erased custom allocation/deletion. More...
 
 Publisher (Publisher &&)=default
 
Publisheroperator= (Publisher &&)=default
 
Subscription Subscribe (Callback callback)
 Connect a callback to the Publisher; later-connected are called earlier. More...
 
Subscription Subscribe (Object &obj, Return(Object::*callback)(Args...))
 Overload of Subscribe takes an object and pointer-to-member-function. More...
 

Static Public Member Functions

static ProjectAudioManagerGet (AudacityProject &project)
 
static const ProjectAudioManagerGet (const AudacityProject &project)
 
static WritableSampleTrackArray ChooseExistingRecordingTracks (AudacityProject &proj, bool selectedOnly, double targetRate=RATE_NOT_SELECTED)
 Find suitable tracks to record into, or return an empty array. More...
 
static bool UseDuplex ()
 

Private Member Functions

void TogglePaused ()
 
void SetPausedOff ()
 
void SetAppending (bool value)
 
void SetLooping (bool value)
 
void SetCutting (bool value)
 
void SetStopping (bool value)
 
void CancelRecording ()
 
void OnAudioIORate (int rate) override
 
void OnAudioIOStartRecording () override
 
void OnAudioIOStopRecording () override
 
void OnAudioIONewBlocks () override
 
void OnCommitRecording () override
 
void OnSoundActivationThreshold () override
 
void OnCheckpointFailure (ProjectFileIOMessage)
 

Static Private Member Functions

static std::pair< TranslatableStrings, unsigned > StatusWidthFunction (const AudacityProject &project, StatusBarField field)
 

Private Attributes

Observer::Subscription mCheckpointFailureSubscription
 
AudacityProjectmProject
 
PlayMode mLastPlayMode { PlayMode::normalPlay }
 
bool mTimerRecordCanceled { false }
 
std::atomic< int > mPaused { 0 }
 
bool mAppending { false }
 
bool mLooping { false }
 
bool mCutting { false }
 
bool mStopping { false }
 
int mDisplayedRate { 0 }
 

Additional Inherited Members

- Public Types inherited from Observer::Publisher< RecordingDropoutEvent >
using message_type = RecordingDropoutEvent
 
using CallbackReturn = std::conditional_t< true, void, bool >
 
using Callback = std::function< CallbackReturn(const RecordingDropoutEvent &) >
 Type of functions that can be connected to the Publisher. More...
 
- Static Public Attributes inherited from Observer::Publisher< RecordingDropoutEvent >
static constexpr bool notifies_all
 
- Protected Member Functions inherited from Observer::Publisher< RecordingDropoutEvent >
CallbackReturn Publish (const RecordingDropoutEvent &message)
 Send a message to connected callbacks. More...
 

Detailed Description

Definition at line 60 of file ProjectAudioManager.h.

Constructor & Destructor Documentation

◆ ProjectAudioManager() [1/2]

ProjectAudioManager::ProjectAudioManager ( AudacityProject project)
explicit

Definition at line 69 of file ProjectAudioManager.cpp.

70 : mProject{ project }
71{
73 registerStatusWidthFunction{ StatusWidthFunction };
76}
const auto project
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
AudacityProject & mProject
static std::pair< TranslatableStrings, unsigned > StatusWidthFunction(const AudacityProject &project, StatusBarField field)
void OnCheckpointFailure(ProjectFileIOMessage)
Observer::Subscription mCheckpointFailureSubscription
static ProjectFileIO & Get(AudacityProject &project)

References ProjectFileIO::Get(), mCheckpointFailureSubscription, OnCheckpointFailure(), project, StatusWidthFunction(), and Observer::Publisher< Message, NotifyAll >::Subscribe().

Here is the call graph for this function:

◆ ProjectAudioManager() [2/2]

ProjectAudioManager::ProjectAudioManager ( const ProjectAudioManager )
delete

◆ ~ProjectAudioManager()

ProjectAudioManager::~ProjectAudioManager ( )
overridedefault

Member Function Documentation

◆ Appending()

bool ProjectAudioManager::Appending ( ) const
inline

Definition at line 97 of file ProjectAudioManager.h.

97{ return mAppending; }

◆ CancelRecording()

void ProjectAudioManager::CancelRecording ( )
private

Definition at line 1065 of file ProjectAudioManager.cpp.

1066{
1067 const auto project = &mProject;
1069}
static PendingTracks & Get(AudacityProject &project)
void ClearPendingTracks(std::vector< std::shared_ptr< Track > > *pAdded=nullptr)
Forget pending track additions and changes;.

References PendingTracks::ClearPendingTracks(), PendingTracks::Get(), and project.

Here is the call graph for this function:

◆ CanStopAudioStream()

bool ProjectAudioManager::CanStopAudioStream ( ) const

Definition at line 1186 of file ProjectAudioManager.cpp.

1187{
1188 auto gAudioIO = AudioIO::Get();
1189 return (!gAudioIO->IsStreamActive() ||
1190 gAudioIO->IsMonitoring() ||
1191 gAudioIO->GetOwningProject().get() == &mProject );
1192}
static AudioIO * Get()
Definition: AudioIO.cpp:126

References AudioIO::Get().

Here is the call graph for this function:

◆ ChooseExistingRecordingTracks()

WritableSampleTrackArray ProjectAudioManager::ChooseExistingRecordingTracks ( AudacityProject proj,
bool  selectedOnly,
double  targetRate = RATE_NOT_SELECTED 
)
static

Find suitable tracks to record into, or return an empty array.

Definition at line 561 of file ProjectAudioManager.cpp.

563{
564 auto p = &proj;
565 size_t recordingChannels = std::max(0, AudioIORecordChannels.Read());
566 bool strictRules = (recordingChannels <= 2);
567
568 // Iterate over all wave tracks, or over selected wave tracks only.
569 // If target rate was specified, ignore all tracks with other rates.
570 //
571 // In the usual cases of one or two recording channels, seek a first-fit
572 // unbroken sub-sequence for which the total number of channels matches the
573 // required number exactly. Never drop inputs or fill only some channels
574 // of a track.
575 //
576 // In case of more than two recording channels, choose tracks only among the
577 // selected. Simply take the earliest wave tracks, until the number of
578 // channels is enough. If there are fewer channels than inputs, but at least
579 // one channel, then some of the input channels will be dropped.
580 //
581 // Resulting tracks may be non-consecutive within the list of all tracks
582 // (there may be non-wave tracks between, or non-selected tracks when
583 // considering selected tracks only.)
584
585 if (!strictRules && !selectedOnly)
586 return {};
587
588 auto &trackList = TrackList::Get(*p);
589 WritableSampleTrackArray candidates;
590 std::vector<unsigned> channelCounts;
591 size_t totalChannels = 0;
592 const auto range = trackList.Any<WaveTrack>();
593 for (auto candidate : selectedOnly ? range + &Track::IsSelected : range) {
594 if (targetRate != RATE_NOT_SELECTED && candidate->GetRate() != targetRate)
595 continue;
596
597 // count channels in this track
598 const auto nChannels = candidate->NChannels();
599 if (strictRules && nChannels > recordingChannels) {
600 // The recording would under-fill this track's channels
601 // Can't use any partial accumulated results
602 // either. Keep looking.
603 candidates.clear();
604 channelCounts.clear();
605 totalChannels = 0;
606 continue;
607 }
608 else {
609 // Might use this but may have to discard some of the accumulated
610 while(strictRules &&
611 nChannels + totalChannels > recordingChannels) {
612 candidates.erase(candidates.begin());
613 auto nOldChannels = channelCounts[0];
614 assert(nOldChannels > 0);
615 channelCounts.erase(channelCounts.begin());
616 totalChannels -= nOldChannels;
617 }
618 candidates.push_back(candidate->SharedPointer<WaveTrack>());
619 channelCounts.push_back(nChannels);
620 totalChannels += nChannels;
621 if (totalChannels >= recordingChannels)
622 // Done!
623 return candidates;
624 }
625 }
626
627 if (!strictRules && !candidates.empty())
628 // good enough
629 return candidates;
630
631 // If the loop didn't exit early, we could not find enough channels
632 return {};
633}
IntSetting AudioIORecordChannels
std::vector< std::shared_ptr< WritableSampleTrack > > WritableSampleTrackArray
constexpr int RATE_NOT_SELECTED
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:207
bool IsSelected() const
Definition: Track.cpp:258
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:314
A Track that contains audio waveform data.
Definition: WaveTrack.h:203
size_t NChannels() const override
A constant property.
Definition: WaveTrack.cpp:530

References AudioIORecordChannels, TrackList::Get(), Track::IsSelected(), WaveTrack::NChannels(), RATE_NOT_SELECTED, and Setting< T >::Read().

Referenced by anonymous_namespace{TransportMenus.cpp}::OnPunchAndRoll(), and anonymous_namespace{TimerRecordDialog.cpp}::OnTimerRecord().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Cutting()

bool ProjectAudioManager::Cutting ( ) const
inline

Definition at line 100 of file ProjectAudioManager.h.

100{ return mCutting; }

◆ DoPlayStopSelect() [1/2]

void ProjectAudioManager::DoPlayStopSelect ( )

Definition at line 1311 of file ProjectAudioManager.cpp.

1312{
1313 auto gAudioIO = AudioIO::Get();
1314 if (DoPlayStopSelect(false, false))
1315 Stop();
1316 else if (!gAudioIO->IsBusy()) {
1317 //Otherwise, start playing (assuming audio I/O isn't busy)
1318
1319 // Will automatically set mLastPlayMode
1320 PlayCurrentRegion(false);
1321 }
1322}
void Stop(bool stopStream=true)
void PlayCurrentRegion(bool newDefault=false, bool cutpreview=false)

References AudioIO::Get().

Here is the call graph for this function:

◆ DoPlayStopSelect() [2/2]

bool ProjectAudioManager::DoPlayStopSelect ( bool  click,
bool  shift 
)

Definition at line 1255 of file ProjectAudioManager.cpp.

1256{
1257 auto &project = mProject;
1258 auto &scrubber = Scrubber::Get( project );
1260 auto &viewInfo = ViewInfo::Get( project );
1261 auto &selection = viewInfo.selectedRegion;
1262 auto gAudioIO = AudioIO::Get();
1263
1264 //If busy, stop playing, make sure everything is unpaused.
1265 if (scrubber.HasMark() ||
1266 gAudioIO->IsStreamActive(token)) {
1267 // change the selection
1268 auto time = gAudioIO->GetStreamTime();
1269 // Test WasSpeedPlaying(), not IsSpeedPlaying()
1270 // as we could be stopped now. Similarly WasKeyboardScrubbing().
1271 if (click && (scrubber.WasSpeedPlaying() || scrubber.WasKeyboardScrubbing()))
1272 {
1273 ;// don't change the selection.
1274 }
1275 else if (shift && click) {
1276 // Change the region selection, as if by shift-click at the play head
1277 auto t0 = selection.t0(), t1 = selection.t1();
1278 if (time < t0)
1279 // Grow selection
1280 t0 = time;
1281 else if (time > t1)
1282 // Grow selection
1283 t1 = time;
1284 else {
1285 // Shrink selection, changing the nearer boundary
1286 if (fabs(t0 - time) < fabs(t1 - time))
1287 t0 = time;
1288 else
1289 t1 = time;
1290 }
1291 selection.setTimes(t0, t1);
1292 }
1293 else if (click){
1294 // avoid a point at negative time.
1295 time = wxMax( time, 0 );
1296 // Set a point selection, as if by a click at the play head
1297 selection.setTimes(time, time);
1298 } else
1299 // How stop and set cursor always worked
1300 // -- change t0, collapsing to point only if t1 was greater
1301 selection.setT0(time, false);
1302
1303 ProjectHistory::Get( project ).ModifyState(false); // without bWantsAutoSave
1304 return true;
1305 }
1306 return false;
1307}
int GetAudioIOToken() const
static ProjectAudioIO & Get(AudacityProject &project)
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
static Scrubber & Get(AudacityProject &project)
Definition: Scrubbing.cpp:186
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235

References AudioIO::Get(), ProjectAudioIO::Get(), ProjectHistory::Get(), ViewInfo::Get(), Scrubber::Get(), ProjectAudioIO::GetAudioIOToken(), ProjectHistory::ModifyState(), and project.

Referenced by anonymous_namespace{TransportMenus.cpp}::OnPlayStopSelect().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ DoRecord()

bool ProjectAudioManager::DoRecord ( AudacityProject project,
const TransportSequences transportSequences,
double  t0,
double  t1,
bool  altAppearance,
const AudioIOStartStreamOptions options 
)
Parameters
transportSequencesIf captureSequences is empty, then tracks are created

Definition at line 757 of file ProjectAudioManager.cpp.

762{
763 auto &projectAudioManager = *this;
764
765 CommandFlag flags = AlwaysEnabledFlag; // 0 means recalc flags.
766
767 // NB: The call may have the side effect of changing flags.
769 flags,
771
772 if (!allowed)
773 return false;
774 // ...end of code from CommandHandler.
775
776 auto gAudioIO = AudioIO::Get();
777 if (gAudioIO->IsBusy())
778 return false;
779
780 projectAudioManager.SetAppending(!altAppearance);
781
782 bool success = false;
783
784 auto transportSequences = sequences;
785
786 // Will replace any given capture tracks with temporaries
787 transportSequences.captureSequences.clear();
788
789 const auto p = &project;
790 auto &trackList = TrackList::Get(project);
791
792 bool appendRecord = !sequences.captureSequences.empty();
793
794 auto insertEmptyInterval =
795 [&](WaveTrack &track, double t0, bool placeholder) {
796 wxString name;
797 for (auto i = 1; ; ++i) {
798 //i18n-hint a numerical suffix added to distinguish otherwise like-named clips when new record started
799 name = XC("%s.%d", "clip name template")
800 .Format(track.GetName(), i).Translation();
801 if (!track.HasClipNamed(name))
802 break;
803 }
804
805 auto clip = track.CreateClip(t0, name);
806 // So that the empty clip is not skipped for insertion:
807 clip->SetIsPlaceholder(true);
808 track.InsertInterval(clip, true);
809 if (!placeholder)
810 clip->SetIsPlaceholder(false);
811 return clip;
812 };
813
814 auto &pendingTracks = PendingTracks::Get(project);
815
816 {
817 if (appendRecord) {
818 // Append recording:
819 // Pad selected/all wave tracks to make them all the same length
820 for (const auto &sequence : sequences.captureSequences) {
821 WaveTrack *wt{};
822 if (!(wt = dynamic_cast<WaveTrack *>(sequence.get()))) {
823 assert(false);
824 continue;
825 }
826 auto endTime = wt->GetEndTime();
827
828 // If the track was chosen for recording and playback both,
829 // remember the original in preroll tracks, before making the
830 // pending replacement.
831 const auto shared = wt->SharedPointer<WaveTrack>();
832 // prerollSequences should be a subset of playbackSequences.
833 const auto &range = transportSequences.playbackSequences;
834 bool prerollTrack = any_of(range.begin(), range.end(),
835 [&](const auto &pSequence){
836 return shared.get() == pSequence->FindChannelGroup(); });
837 if (prerollTrack)
838 transportSequences.prerollSequences.push_back(shared);
839
840 // A function that copies all the non-sample data between
841 // wave tracks; in case the track recorded to changes scale
842 // type (for instance), during the recording.
843 auto updater = [](Track &d, const Track &s){
844 assert(d.NChannels() == s.NChannels());
845 auto &dst = static_cast<WaveTrack&>(d);
846 auto &src = static_cast<const WaveTrack&>(s);
847 dst.Init(src);
848 };
849
850 // End of current track is before or at recording start time.
851 // Less than or equal, not just less than, to ensure a clip boundary.
852 // when append recording.
853 //const auto pending = static_cast<WaveTrack*>(newTrack);
854 const auto lastClip = wt->GetRightmostClip();
855 // RoundedT0 to have a new clip created when punch-and-roll
856 // recording with the cursor in the second half of the space
857 // between two samples
858 // (https://github.com/audacity/audacity/issues/5113#issuecomment-1705154108)
859 const auto recordingStart =
860 std::round(t0 * wt->GetRate()) / wt->GetRate();
861 const auto recordingStartsBeforeTrackEnd =
862 lastClip && recordingStart < lastClip->GetPlayEndTime();
863 // Recording doesn't start before the beginning of the last clip
864 // - or the check for creating a new clip or not should be more
865 // general than that ...
866 assert(
867 !recordingStartsBeforeTrackEnd ||
868 lastClip->WithinPlayRegion(recordingStart));
870 if (!recordingStartsBeforeTrackEnd ||
871 lastClip->HasPitchOrSpeed())
872 newClip = insertEmptyInterval(*wt, t0, true);
873 // Get a copy of the track to be appended, to be pushed into
874 // undo history only later.
875 const auto pending = static_cast<WaveTrack*>(
876 pendingTracks.RegisterPendingChangedTrack(updater, wt)
877 );
878 // Source clip was marked as placeholder so that it would not be
879 // skipped in clip copying. Un-mark it and its copy now
880 if (newClip)
881 newClip->SetIsPlaceholder(false);
882 if (auto copiedClip = pending->NewestOrNewClip())
883 copiedClip->SetIsPlaceholder(false);
884 transportSequences.captureSequences
885 .push_back(pending->SharedPointer<WaveTrack>());
886 }
887 pendingTracks.UpdatePendingTracks();
888 }
889
890 if (transportSequences.captureSequences.empty()) {
891 // recording to NEW track(s).
892 bool recordingNameCustom, useTrackNumber, useDateStamp, useTimeStamp;
893 wxString defaultTrackName, defaultRecordingTrackName;
894
895 // Count the tracks.
896 auto numTracks = trackList.Any<const WaveTrack>().size();
897
898 auto recordingChannels = std::max(1, AudioIORecordChannels.Read());
899
900 gPrefs->Read(wxT("/GUI/TrackNames/RecordingNameCustom"), &recordingNameCustom, false);
901 gPrefs->Read(wxT("/GUI/TrackNames/TrackNumber"), &useTrackNumber, false);
902 gPrefs->Read(wxT("/GUI/TrackNames/DateStamp"), &useDateStamp, false);
903 gPrefs->Read(wxT("/GUI/TrackNames/TimeStamp"), &useTimeStamp, false);
904 defaultTrackName = trackList.MakeUniqueTrackName(WaveTrack::GetDefaultAudioTrackNamePreference());
905 gPrefs->Read(wxT("/GUI/TrackNames/RecodingTrackName"), &defaultRecordingTrackName, defaultTrackName);
906
907 wxString baseTrackName = recordingNameCustom? defaultRecordingTrackName : defaultTrackName;
908
909 auto newTracks =
910 WaveTrackFactory::Get(*p).CreateMany(recordingChannels);
911 const auto first = *newTracks->begin();
912 int trackCounter = 0;
913 const auto minimizeChannelView = recordingChannels > 2
915 for (auto newTrack : newTracks->Any<WaveTrack>()) {
916 // Quantize bounds to the rate of the new track.
917 if (newTrack == first) {
918 if (t0 < DBL_MAX)
919 t0 = newTrack->SnapToSample(t0);
920 if (t1 < DBL_MAX)
921 t1 = newTrack->SnapToSample(t1);
922 }
923
924 newTrack->MoveTo(t0);
925 wxString nameSuffix = wxString(wxT(""));
926
927 if (useTrackNumber) {
928 nameSuffix += wxString::Format(wxT("%d"), 1 + (int) numTracks + trackCounter++);
929 }
930
931 if (useDateStamp) {
932 if (!nameSuffix.empty()) {
933 nameSuffix += wxT("_");
934 }
935 nameSuffix += wxDateTime::Now().FormatISODate();
936 }
937
938 if (useTimeStamp) {
939 if (!nameSuffix.empty()) {
940 nameSuffix += wxT("_");
941 }
942 nameSuffix += wxDateTime::Now().FormatISOTime();
943 }
944
945 // ISO standard would be nice, but ":" is unsafe for file name.
946 nameSuffix.Replace(wxT(":"), wxT("-"));
947
948 if (baseTrackName.empty())
949 newTrack->SetName(nameSuffix);
950 else if (nameSuffix.empty())
951 newTrack->SetName(baseTrackName);
952 else
953 newTrack->SetName(baseTrackName + wxT("_") + nameSuffix);
954
955 //create a new clip with a proper name before recording is started
956 insertEmptyInterval(*newTrack, t0, false);
957
958 transportSequences.captureSequences.push_back(
959 std::static_pointer_cast<WaveTrack>(newTrack->shared_from_this())
960 );
961
962 for(auto channel : newTrack->Channels())
963 {
964 ChannelView::Get(*channel).SetMinimized(minimizeChannelView);
965 }
966 }
967 pendingTracks.RegisterPendingNewTracks(std::move(*newTracks));
968 // Bug 1548. First of new tracks needs the focus.
969 TrackFocus::Get(project).Set(first);
970 if (!trackList.empty()) {
971 BasicUI::CallAfter([pProject = project.weak_from_this()]{
972 if (!pProject.expired()) {
973 auto &project = *pProject.lock();
974 auto &trackList = TrackList::Get(project);
975 Viewport::Get(project).ShowTrack(**trackList.rbegin());
976 }
977 });
978 }
979 }
980
981 //Automated Input Level Adjustment Initialization
982 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
983 gAudioIO->AILAInitialize();
984 #endif
985
986 int token =
987 gAudioIO->StartStream(transportSequences, t0, t1, t1, options);
988
989 success = (token != 0);
990
991 if (success) {
993 }
994 else {
996
997 // Show error message if stream could not be opened
998 auto msg = XO("Error opening recording device.\nError code: %s")
999 .Format( gAudioIO->LastPaErrorString() );
1000 using namespace BasicUI;
1002 XO("Error"), msg, wxT("Error_opening_sound_device"),
1003 ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
1004 }
1005 }
1006
1007 return success;
1008}
wxT("CloseDown"))
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:34
std::bitset< NCommandFlags > CommandFlag
Definition: CommandFlag.h:30
const ReservedCommandFlag & AudioIONotBusyFlag()
XO("Cut/Copy/Paste")
#define XC(s, c)
Definition: Internat.h:37
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
std::unique_ptr< const BasicUI::WindowPlacement > ProjectFramePlacement(AudacityProject *project)
Make a WindowPlacement object suitable for project (which may be null)
Definition: Project.cpp:129
const ReservedCommandFlag & CanStopAudioStreamFlag()
wxString name
Definition: TagsEditor.cpp:166
static CustomUpdaterValue updater
virtual size_t NChannels() const =0
Report the number of channels.
static ChannelView & Get(Channel &channel)
void SetMinimized(bool minimized)
bool TryToMakeActionAllowed(CommandFlag &flags, CommandFlag flagsRqd)
static CommandManager & Get(AudacityProject &project)
void SetAudioIOToken(int token)
Track * Get()
Definition: TrackFocus.cpp:156
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:110
const wxString & GetName() const
Name is always the same for all channels of a group.
Definition: Track.cpp:64
static BoolSetting TracksFitVerticallyZoomed
Definition: TracksPrefs.h:30
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:3376
TrackListHolder CreateMany(size_t nChannels)
Creates tracks with project's default rate and format and the given number of channels.
Definition: WaveTrack.cpp:423
bool HasClipNamed(const wxString &name) const
Definition: WaveTrack.cpp:728
IntervalHolder CreateClip(double offset=.0, const wxString &name=wxEmptyString, const Interval *pToCopy=nullptr, bool copyCutlines=true)
Definition: WaveTrack.cpp:2961
void InsertInterval(const IntervalHolder &interval, bool newClip, bool allowEmpty=false)
Definition: WaveTrack.cpp:3235
static wxString GetDefaultAudioTrackNamePreference()
Definition: WaveTrack.cpp:373
void Init(const WaveTrack &orig)
Definition: WaveTrack.cpp:553
std::shared_ptr< Interval > IntervalHolder
Definition: WaveTrack.h:209
virtual bool Read(const wxString &key, bool *value) const =0
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:214
void ShowErrorDialog(const WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const ManualPageID &helpPage, const ErrorDialogOptions &options={})
Show an error dialog with a link to the manual for further help.
Definition: BasicUI.h:272
fastfloat_really_inline void round(adjusted_mantissa &am, callback cb) noexcept
Definition: fast_float.h:2512
Options for variations of error dialogs; the default is for modal dialogs.
Definition: BasicUI.h:52
RecordableSequences captureSequences
Definition: AudioIO.h:73
ConstPlayableSequences prerollSequences
Definition: AudioIO.h:78
ConstPlayableSequences playbackSequences
Definition: AudioIO.h:72

References AlwaysEnabledFlag, Track::Any(), AudioIONotBusyFlag(), AudioIORecordChannels, BasicUI::CallAfter(), CanStopAudioStreamFlag(), TransportSequences::captureSequences, WaveTrack::CreateClip(), WaveTrackFactory::CreateMany(), AudioIO::Get(), TrackFocus::Get(), ProjectAudioIO::Get(), CommandManager::Get(), PendingTracks::Get(), TrackList::Get(), WaveTrackFactory::Get(), ChannelView::Get(), WaveTrack::GetDefaultAudioTrackNamePreference(), Track::GetName(), gPrefs, WaveTrack::HasClipNamed(), WaveTrack::Init(), WaveTrack::InsertInterval(), name, ChannelGroup::NChannels(), project, ProjectFramePlacement(), audacity::BasicSettings::Read(), Setting< T >::Read(), fast_float::round(), ProjectAudioIO::SetAudioIOToken(), ChannelView::SetMinimized(), BasicUI::ShowErrorDialog(), size, TracksPrefs::TracksFitVerticallyZoomed, CommandManager::TryToMakeActionAllowed(), updater, wxT(), XC, and XO().

Referenced by anonymous_namespace{TransportMenus.cpp}::OnPunchAndRoll().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Get() [1/2]

ProjectAudioManager & ProjectAudioManager::Get ( AudacityProject project)
static

Definition at line 57 of file ProjectAudioManager.cpp.

58{
59 return project.AttachedObjects::Get< ProjectAudioManager >(
61}
static AudacityProject::AttachedObjects::RegisteredFactory sProjectAudioManagerKey

References project, and sProjectAudioManagerKey.

Referenced by AdornedRulerPanel::ScrubbingHandle::Cancel(), CanStopAudioStreamFlag(), AdornedRulerPanel::ClearPlayRegion(), CloseButtonHandle::CommitChanges(), Scrubber::ContinueScrubbingUI(), CommandDispatch::DoAudacityCommand(), Scrubber::DoKeyboardScrub(), anonymous_namespace{TransportMenus.cpp}::DoMoveToLabel(), Scrubber::DoScrub(), TransportUtilities::DoStopPlaying(), anonymous_namespace{DropoutDetector.cpp}::DropoutSubscription::DropoutSubscription(), ControlToolBar::EnableDisableButtons(), Get(), Scrubber::MarkScrubStart(), Scrubber::MaybeStartScrubbing(), ProjectManager::New(), Scrubber::OnActivateOrDeactivateApp(), ProjectManager::OnCloseWindow(), ControlToolBar::OnFF(), ControlToolBar::OnIdle(), AudacityApp::OnKeyDown(), ControlToolBar::OnKeyEvent(), anonymous_namespace{TransportMenus.cpp}::OnPause(), ControlToolBar::OnPause(), ControlToolBar::OnPlay(), anonymous_namespace{TransportMenus.cpp}::OnPlayStopSelect(), anonymous_namespace{TransportMenus.cpp}::OnPunchAndRoll(), ControlToolBar::OnRecord(), ControlToolBar::OnRewind(), anonymous_namespace{TransportMenus.cpp}::OnStop(), ControlToolBar::OnStop(), MixerBoard::OnTimer(), PlayIndicatorOverlay::OnTimer(), TrackPanel::OnTimer(), anonymous_namespace{TimerRecordDialog.cpp}::OnTimerRecord(), TranscriptionToolBar::PlayAtSpeed(), TransportUtilities::PlayCurrentRegionAndWait(), ControlToolBar::PlayDefault(), TransportUtilities::PlayPlayRegionAndWait(), TransportUtilities::RecordAndWait(), TimerRecordDialog::RunWaitDialog(), Scrubber::StartKeyboardScrubbing(), AdornedRulerPanel::StartQPPlay(), ControlToolBar::StateForStatusBar(), StatusWidthFunction(), anonymous_namespace{DoEffect.cpp}::StopPlaybackCb(), and Scrubber::StopScrubbing().

Here is the caller graph for this function:

◆ Get() [2/2]

const ProjectAudioManager & ProjectAudioManager::Get ( const AudacityProject project)
static

Definition at line 63 of file ProjectAudioManager.cpp.

65{
66 return Get( const_cast< AudacityProject & >( project ) );
67}
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
static ProjectAudioManager & Get(AudacityProject &project)

References Get(), and project.

Here is the call graph for this function:

◆ GetLastPlayMode()

PlayMode ProjectAudioManager::GetLastPlayMode ( ) const
inline

Definition at line 136 of file ProjectAudioManager.h.

136{ return mLastPlayMode; }

Referenced by MixerBoard::OnTimer(), and PlayIndicatorOverlay::OnTimer().

Here is the caller graph for this function:

◆ IsTimerRecordCancelled()

bool ProjectAudioManager::IsTimerRecordCancelled ( )
inline

Definition at line 82 of file ProjectAudioManager.h.

◆ Looping()

bool ProjectAudioManager::Looping ( ) const
inline

Definition at line 99 of file ProjectAudioManager.h.

99{ return mLooping; }

◆ OnAudioIONewBlocks()

void ProjectAudioManager::OnAudioIONewBlocks ( )
overrideprivatevirtual

Implements AudioIOListener.

Definition at line 1126 of file ProjectAudioManager.cpp.

1127{
1128 auto &project = mProject;
1129 auto &projectFileIO = ProjectFileIO::Get( project );
1130
1131 wxTheApp->CallAfter( [&]{ projectFileIO.AutoSave(true); });
1132}

References ProjectFileIO::Get(), and project.

Here is the call graph for this function:

◆ OnAudioIORate()

void ProjectAudioManager::OnAudioIORate ( int  rate)
overrideprivatevirtual

Implements AudioIOListener.

Definition at line 1071 of file ProjectAudioManager.cpp.

1072{
1073 auto &project = mProject;
1074
1075 mDisplayedRate = rate;
1076
1077 auto display = FormatRate( rate );
1078
1080}
static TranslatableString FormatRate(int rate)
StatusBarField RateStatusBarField()
ID of the third field in the status bar. This field is used to display the current rate.
static ProjectStatus & Get(AudacityProject &project)
void Set(const TranslatableString &msg, StatusBarField field=MainStatusBarField())

References FormatRate(), ProjectStatus::Get(), project, RateStatusBarField(), and ProjectStatus::Set().

Here is the call graph for this function:

◆ OnAudioIOStartRecording()

void ProjectAudioManager::OnAudioIOStartRecording ( )
overrideprivatevirtual

Implements AudioIOListener.

Definition at line 1082 of file ProjectAudioManager.cpp.

1083{
1084 // Auto-save was done here before, but it is unnecessary, provided there
1085 // are sufficient autosaves when pushing or modifying undo states.
1086}

◆ OnAudioIOStopRecording()

void ProjectAudioManager::OnAudioIOStopRecording ( )
overrideprivatevirtual

Implements AudioIOListener.

Definition at line 1089 of file ProjectAudioManager.cpp.

1090{
1091 auto &project = mProject;
1092 auto &projectAudioIO = ProjectAudioIO::Get( project );
1093 auto &projectFileIO = ProjectFileIO::Get( project );
1094
1095 // Only push state if we were capturing and not monitoring
1096 if (projectAudioIO.GetAudioIOToken() > 0)
1097 {
1098 auto &history = ProjectHistory::Get( project );
1099
1100 if (IsTimerRecordCancelled()) {
1101 // discard recording
1102 history.RollbackState();
1103 // Reset timer record
1105 }
1106 else {
1107 // Add to history
1108 // We want this to have No-fail-guarantee if we get here from exception
1109 // handling of recording, and that means we rely on the last autosave
1110 // successfully committed to the database, not risking a failure
1111 auto flags = AudioIO::Get()->HasRecordingException()
1114 history.PushState(XO("Recorded Audio"), XO("Record"), flags);
1115
1116 // Now, we may add a label track to give information about
1117 // dropouts. We allow failure of this.
1118 auto gAudioIO = AudioIO::Get();
1119 auto &intervals = gAudioIO->LostCaptureIntervals();
1120 if (intervals.size())
1121 Publish( RecordingDropoutEvent{ intervals } );
1122 }
1123 }
1124}
bool HasRecordingException() const
Definition: AudioIO.h:366
CallbackReturn Publish(const RecordingDropoutEvent &message)
Send a message to connected callbacks.
Definition: Observer.h:207
Notification, after recording has stopped, when dropouts have been detected.

References AudioIO::Get(), ProjectAudioIO::Get(), ProjectFileIO::Get(), ProjectHistory::Get(), AudioIoCallback::HasRecordingException(), NOAUTOSAVE, NONE, project, and XO().

Here is the call graph for this function:

◆ OnCheckpointFailure()

void ProjectAudioManager::OnCheckpointFailure ( ProjectFileIOMessage  message)
private

Definition at line 1159 of file ProjectAudioManager.cpp.

1160{
1162 Stop();
1163}
@ CheckpointFailure
Failure happened in a worker thread.

References CheckpointFailure.

Referenced by ProjectAudioManager().

Here is the caller graph for this function:

◆ OnCommitRecording()

void ProjectAudioManager::OnCommitRecording ( )
overrideprivatevirtual

Implements AudioIOListener.

Definition at line 1134 of file ProjectAudioManager.cpp.

1135{
1136 const auto project = &mProject;
1138}
bool ApplyPendingTracks()
Change the state of the project.

References PendingTracks::ApplyPendingTracks(), PendingTracks::Get(), and project.

Here is the call graph for this function:

◆ OnPause()

void ProjectAudioManager::OnPause ( )

Definition at line 1010 of file ProjectAudioManager.cpp.

1011{
1012 auto &projectAudioManager = *this;
1013 bool canStop = projectAudioManager.CanStopAudioStream();
1014
1015 if ( !canStop ) {
1016 return;
1017 }
1018
1019 bool paused = !projectAudioManager.Paused();
1020 TogglePaused();
1021
1022 auto gAudioIO = AudioIO::Get();
1023
1024 auto project = &mProject;
1025 auto &scrubber = Scrubber::Get( *project );
1026
1027 // Bug 1494 - Pausing a seek or scrub should just STOP as
1028 // it is confusing to be in a paused scrub state.
1029 bool bStopInstead = paused &&
1031 !scrubber.IsSpeedPlaying() &&
1032 !scrubber.IsKeyboardScrubbing();
1033
1034 if (bStopInstead) {
1035 Stop();
1036 return;
1037 }
1038
1040 scrubber.Pause(paused);
1041 else
1042 {
1043 constexpr auto publish = true;
1044 gAudioIO->SetPaused(paused, publish);
1045 }
1046}
static bool IsScrubbing()
Definition: ScrubState.cpp:482

References AudioIO::Get(), Scrubber::Get(), ScrubState::IsScrubbing(), and project.

Referenced by anonymous_namespace{TransportMenus.cpp}::OnPause(), and ControlToolBar::OnPause().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ OnRecord()

void ProjectAudioManager::OnRecord ( bool  altAppearance)
Exception safety guarantee:
Strong – For state of current project's tracks

Definition at line 636 of file ProjectAudioManager.cpp.

637{
638 bool bPreferNewTrack;
639 gPrefs->Read("/GUI/PreferNewTrackRecord", &bPreferNewTrack, false);
640 const bool appendRecord = (altAppearance == bPreferNewTrack);
641
642 // Code from CommandHandler start...
644
645 if (p) {
646 const auto &selectedRegion = ViewInfo::Get( *p ).selectedRegion;
647 double t0 = selectedRegion.t0();
648 double t1 = selectedRegion.t1();
649 // When no time selection, recording duration is 'unlimited'.
650 if (t1 == t0)
651 t1 = DBL_MAX;
652
653 auto options = ProjectAudioIO::GetDefaultOptions(*p);
654 WritableSampleTrackArray existingTracks;
655
656 // Checking the selected tracks: counting them and
657 // making sure they all have the same rate
658 const auto selectedTracks{ GetPropertiesOfSelected(*p) };
659 const int rateOfSelected{ selectedTracks.rateOfSelected };
660 const bool anySelected{ selectedTracks.anySelected };
661 const bool allSameRate{ selectedTracks.allSameRate };
662
663 if (!allSameRate) {
664 AudacityMessageBox(XO("The tracks selected "
665 "for recording must all have the same sampling rate"),
666 XO("Mismatched Sampling Rates"),
667 wxICON_ERROR | wxCENTRE);
668
669 return;
670 }
671
672 if (appendRecord) {
673 // Try to find wave tracks to record into. (If any are selected,
674 // try to choose only from them; else if wave tracks exist, may record into any.)
675 existingTracks = ChooseExistingRecordingTracks(*p, true, rateOfSelected);
676 if (!existingTracks.empty()) {
677 t0 = std::max(t0,
679 .max(&Track::GetEndTime));
680 options.rate = rateOfSelected;
681 }
682 else {
683 if (anySelected && rateOfSelected != options.rate) {
685 "Too few tracks are selected for recording at this sample rate.\n"
686 "(Audacity requires two channels at the same sample rate for\n"
687 "each stereo track)"),
688 XO("Too Few Compatible Tracks Selected"),
689 wxICON_ERROR | wxCENTRE);
690
691 return;
692 }
693
694 existingTracks = ChooseExistingRecordingTracks(*p, false, options.rate);
695 if (!existingTracks.empty())
696 {
697 const auto endTime = accumulate(
698 existingTracks.begin(), existingTracks.end(),
699 std::numeric_limits<double>::lowest(),
700 [](double acc, auto &pTrack) {
701 return std::max(acc, pTrack->GetEndTime());
702 }
703 );
704
705 //If there is a suitable track, then adjust t0 so
706 //that recording not starts before the end of that track
707 t0 = std::max(t0, endTime);
708 }
709 // If suitable tracks still not found, will record into NEW ones,
710 // starting with t0
711 }
712
713 // Whether we decided on NEW tracks or not:
714 if (t1 <= selectedRegion.t0() && selectedRegion.t1() > selectedRegion.t0()) {
715 t1 = selectedRegion.t1(); // record within the selection
716 }
717 else {
718 t1 = DBL_MAX; // record for a long, long time
719 }
720 }
721
722 TransportSequences transportTracks;
723 if (UseDuplex()) {
724 // Remove recording tracks from the list of tracks for duplex ("overdub")
725 // playback.
726 /* TODO: set up stereo tracks if that is how the user has set up
727 * their preferences, and choose sample format based on prefs */
728 transportTracks =
729 MakeTransportTracks(TrackList::Get( *p ), false, true);
730 for (const auto &wt : existingTracks) {
731 auto end = transportTracks.playbackSequences.end();
732 auto it = std::find_if(
733 transportTracks.playbackSequences.begin(), end,
734 [&wt](const auto& playbackSequence) {
735 return playbackSequence->FindChannelGroup() ==
736 wt->FindChannelGroup();
737 });
738 if (it != end)
739 transportTracks.playbackSequences.erase(it);
740 }
741 }
742
743 std::copy(existingTracks.begin(), existingTracks.end(),
744 back_inserter(transportTracks.captureSequences));
745
746 DoRecord(*p, transportTracks, t0, t1, altAppearance, options);
747 }
748}
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
PropertiesOfSelected GetPropertiesOfSelected(const AudacityProject &proj)
TransportSequences MakeTransportTracks(TrackList &trackList, bool selectedOnly, bool nonWaveToo)
double GetEndTime() const
Get the maximum of End() values of intervals, or 0 when none.
Definition: Channel.cpp:61
double t0() const
Definition: ViewInfo.h:35
static AudioIOStartStreamOptions GetDefaultOptions(AudacityProject &project, bool newDefaults=false)
Invoke the global hook, supplying a default argument.
static WritableSampleTrackArray ChooseExistingRecordingTracks(AudacityProject &proj, bool selectedOnly, double targetRate=RATE_NOT_SELECTED)
Find suitable tracks to record into, or return an empty array.
bool DoRecord(AudacityProject &project, const TransportSequences &transportSequences, double t0, double t1, bool altAppearance, const AudioIOStartStreamOptions &options)
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:967
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:216
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
void copy(const T *src, T *dst, int32_t n)
Definition: VectorOps.h:40

References AudacityMessageBox(), TransportSequences::captureSequences, staffpad::vo::copy(), details::end(), ViewInfo::Get(), TrackList::Get(), ProjectAudioIO::GetDefaultOptions(), ChannelGroup::GetEndTime(), GetPropertiesOfSelected(), gPrefs, MakeTransportTracks(), TransportSequences::playbackSequences, PropertiesOfSelected::rateOfSelected, audacity::BasicSettings::Read(), TrackList::Selected(), ViewInfo::selectedRegion, NotifyingSelectedRegion::t0(), and XO().

Referenced by ControlToolBar::OnRecord(), and TimerRecordDialog::RunWaitDialog().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ OnSoundActivationThreshold()

void ProjectAudioManager::OnSoundActivationThreshold ( )
overrideprivatevirtual

Implements AudioIOListener.

Definition at line 1140 of file ProjectAudioManager.cpp.

1141{
1142 auto& project = mProject;
1143 auto gAudioIO = AudioIO::Get();
1144 if (gAudioIO && &project == gAudioIO->GetOwningProject().get())
1145 {
1146 bool canStop = CanStopAudioStream();
1147
1148 gAudioIO->SetPaused(!gAudioIO->IsPaused());
1149
1150 if (canStop)
1151 {
1152 // Instead of calling ::OnPause here, we can simply do the only thing it does (i.e. toggling the pause state),
1153 // because scrubbing can not happen while recording
1154 TogglePaused();
1155 }
1156 }
1157}

References AudioIO::Get(), and project.

Here is the call graph for this function:

◆ operator=()

ProjectAudioManager & ProjectAudioManager::operator= ( const ProjectAudioManager )
delete

◆ Paused()

bool ProjectAudioManager::Paused ( ) const

Definition at line 1059 of file ProjectAudioManager.cpp.

1060{
1061 return mPaused.load(std::memory_order_relaxed) == 1;
1062}
std::atomic< int > mPaused

Referenced by Scrubber::OnActivateOrDeactivateApp().

Here is the caller graph for this function:

◆ PlayCurrentRegion()

void ProjectAudioManager::PlayCurrentRegion ( bool  newDefault = false,
bool  cutpreview = false 
)
Parameters
newDefaultSee ProjectAudioIO::GetDefaultOptions

Definition at line 471 of file ProjectAudioManager.cpp.

473{
474 auto &projectAudioManager = *this;
475 bool canStop = projectAudioManager.CanStopAudioStream();
476
477 if ( !canStop )
478 return;
479
481
482 {
483
484 const auto &playRegion = ViewInfo::Get( *p ).playRegion;
485
486 if (newDefault)
487 cutpreview = false;
488 auto options = ProjectAudioIO::GetDefaultOptions(*p, newDefault);
489 if (cutpreview)
490 options.envelope = nullptr;
491 auto mode =
492 cutpreview ? PlayMode::cutPreviewPlay
493 : newDefault ? PlayMode::loopedPlay
495 PlayPlayRegion(SelectedRegion(playRegion.GetStart(), playRegion.GetEnd()),
496 options,
497 mode);
498 }
499}
@ cutPreviewPlay
int PlayPlayRegion(const SelectedRegion &selectedRegion, const AudioIOStartStreamOptions &options, PlayMode playMode, bool backwards=false)
Defines a selected portion of a project.
PlayRegion playRegion
Definition: ViewInfo.h:217

References cutPreviewPlay, ViewInfo::Get(), ProjectAudioIO::GetDefaultOptions(), loopedPlay, normalPlay, and ViewInfo::playRegion.

Referenced by ControlToolBar::PlayDefault().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Playing()

bool ProjectAudioManager::Playing ( ) const

Definition at line 1165 of file ProjectAudioManager.cpp.

1166{
1167 auto gAudioIO = AudioIO::Get();
1168 return
1169 gAudioIO->IsBusy() &&
1171 // ... and not merely monitoring
1172 !gAudioIO->IsMonitoring() &&
1173 // ... and not punch-and-roll recording
1174 gAudioIO->GetNumCaptureChannels() == 0;
1175}

References AudioIO::Get().

Here is the call graph for this function:

◆ PlayPlayRegion()

int ProjectAudioManager::PlayPlayRegion ( const SelectedRegion selectedRegion,
const AudioIOStartStreamOptions options,
PlayMode  playMode,
bool  backwards = false 
)

Definition at line 293 of file ProjectAudioManager.cpp.

297{
298 auto &projectAudioManager = *this;
299 bool canStop = projectAudioManager.CanStopAudioStream();
300
301 if ( !canStop )
302 return -1;
303
304 auto &pStartTime = options.pStartTime;
305
306 bool nonWaveToo = options.playNonWaveTracks;
307
308 // Uncomment this for laughs!
309 // backwards = true;
310
311 double t0 = selectedRegion.t0();
312 double t1 = selectedRegion.t1();
313 // SelectedRegion guarantees t0 <= t1, so we need another boolean argument
314 // to indicate backwards play.
315 const bool newDefault = (mode == PlayMode::loopedPlay);
316
317 if (backwards)
318 std::swap(t0, t1);
319
320 projectAudioManager.SetLooping( mode == PlayMode::loopedPlay );
321 projectAudioManager.SetCutting( mode == PlayMode::cutPreviewPlay );
322
323 bool success = false;
324
325 auto gAudioIO = AudioIO::Get();
326 if (gAudioIO->IsBusy())
327 return -1;
328
329 const bool cutpreview = mode == PlayMode::cutPreviewPlay;
330 if (cutpreview && t0==t1)
331 return -1; /* msmeyer: makes no sense */
332
334
335 auto &tracks = TrackList::Get(*p);
336
337 mLastPlayMode = mode;
338
339 bool hasaudio;
340 if (nonWaveToo)
341 hasaudio = ! tracks.Any<PlayableTrack>().empty();
342 else
343 hasaudio = ! tracks.Any<WaveTrack>().empty();
344
345 double latestEnd = tracks.GetEndTime();
346
347 if (!hasaudio)
348 return -1; // No need to continue without audio tracks
349
350#if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR)
351 double initSeek = 0.0;
352#endif
353 double loopOffset = 0.0;
354
355 if (t1 == t0) {
356 if (newDefault) {
357 const auto &selectedRegion = ViewInfo::Get( *p ).selectedRegion;
358 // play selection if there is one, otherwise
359 // set start of play region to project start,
360 // and loop the project from current play position.
361
362 if ((t0 > selectedRegion.t0()) && (t0 < selectedRegion.t1())) {
363 t0 = selectedRegion.t0();
364 t1 = selectedRegion.t1();
365 }
366 else {
367 // loop the entire project
368 // Bug2347, loop playback from cursor position instead of project start
369 loopOffset = t0 - tracks.GetStartTime();
370 if (!pStartTime)
371 // TODO move this reassignment elsewhere so we don't need an
372 // ugly mutable member
373 pStartTime.emplace(loopOffset);
374 t0 = tracks.GetStartTime();
375 t1 = tracks.GetEndTime();
376 }
377 } else {
378 // move t0 to valid range
379 if (t0 < 0) {
380 t0 = tracks.GetStartTime();
381 }
382 else if (t0 > tracks.GetEndTime()) {
383 t0 = tracks.GetEndTime();
384 }
385#if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR)
386 else {
387 initSeek = t0; //AC: initSeek is where playback will 'start'
388 if (!pStartTime)
389 pStartTime.emplace(initSeek);
390 t0 = tracks.GetStartTime();
391 }
392#endif
393 }
394 t1 = tracks.GetEndTime();
395 }
396 else {
397 // maybe t1 < t0, with backwards scrubbing for instance
398 if (backwards)
399 std::swap(t0, t1);
400
401 t0 = std::max(0.0, std::min(t0, latestEnd));
402 t1 = std::max(0.0, std::min(t1, latestEnd));
403
404 if (backwards)
405 std::swap(t0, t1);
406 }
407
408 int token = -1;
409
410 if (t1 != t0) {
411 if (cutpreview) {
412 const double tless = std::min(t0, t1);
413 const double tgreater = std::max(t0, t1);
414 double beforeLen, afterLen;
415 gPrefs->Read(wxT("/AudioIO/CutPreviewBeforeLen"), &beforeLen, 2.0);
416 gPrefs->Read(wxT("/AudioIO/CutPreviewAfterLen"), &afterLen, 1.0);
417 double tcp0 = tless-beforeLen;
418 const double diff = tgreater - tless;
419 double tcp1 = tgreater+afterLen;
420 if (backwards)
421 std::swap(tcp0, tcp1);
422 AudioIOStartStreamOptions myOptions = options;
423 myOptions.policyFactory =
424 [tless, diff](auto&) -> std::unique_ptr<PlaybackPolicy> {
425 return std::make_unique<CutPreviewPlaybackPolicy>(tless, diff);
426 };
427 token = gAudioIO->StartStream(
428 MakeTransportTracks(TrackList::Get(*p), false, nonWaveToo),
429 tcp0, tcp1, tcp1, myOptions);
430 }
431 else {
432 double mixerLimit = t1;
433 if (newDefault) {
434 mixerLimit = latestEnd;
435 if (pStartTime && *pStartTime >= t1)
436 t1 = latestEnd;
437 }
438 token = gAudioIO->StartStream(
439 MakeTransportTracks(tracks, false, nonWaveToo),
440 t0, t1, mixerLimit, options);
441 }
442 if (token != 0) {
443 success = true;
445 }
446 else {
447 // Bug1627 (part of it):
448 // infinite error spew when trying to start scrub:
449 // Problem was that the error dialog yields to events,
450 // causing recursion to this function in the scrub timer
451 // handler! Easy fix, just delay the user alert instead.
452 auto &window = GetProjectFrame( mProject );
453 window.CallAfter( [&]{
454 using namespace BasicUI;
455 // Show error message if stream could not be opened
457 XO("Error"),
458 XO("Error opening sound device.\nTry changing the audio host, playback device and the project sample rate."),
459 wxT("Error_opening_sound_device"),
460 ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
461 });
462 }
463 }
464
465 if (!success)
466 return -1;
467
468 return token;
469}
int min(int a, int b)
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
const auto tracks
AudioTrack subclass that can also be audibly replayed by the program.
Definition: PlayableTrack.h:40
double t1() const
double t0() const
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
Definition: NoteTrack.cpp:634
struct holding stream options, including a pointer to the time warp info and AudioIOListener and whet...
Definition: AudioIOBase.h:46
PolicyFactory policyFactory
Definition: AudioIOBase.h:75
std::optional< double > pStartTime
Definition: AudioIOBase.h:60

References cutPreviewPlay, AudioIO::Get(), ProjectAudioIO::Get(), ViewInfo::Get(), TrackList::Get(), GetProjectFrame(), gPrefs, loopedPlay, MakeTransportTracks(), min(), AudioIOStartStreamOptions::playNonWaveTracks, AudioIOStartStreamOptions::policyFactory, ProjectFramePlacement(), AudioIOStartStreamOptions::pStartTime, audacity::BasicSettings::Read(), ViewInfo::selectedRegion, ProjectAudioIO::SetAudioIOToken(), BasicUI::ShowErrorDialog(), anonymous_namespace{NoteTrack.cpp}::swap(), SelectedRegion::t0(), SelectedRegion::t1(), tracks, wxT(), and XO().

Referenced by Scrubber::StartKeyboardScrubbing().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Recording()

bool ProjectAudioManager::Recording ( ) const

Definition at line 1177 of file ProjectAudioManager.cpp.

1178{
1179 auto gAudioIO = AudioIO::Get();
1180 return
1181 gAudioIO->IsBusy() &&
1183 gAudioIO->GetNumCaptureChannels() > 0;
1184}

References AudioIO::Get().

Here is the call graph for this function:

◆ ResetTimerRecordCancelled()

void ProjectAudioManager::ResetTimerRecordCancelled ( )
inline

Definition at line 84 of file ProjectAudioManager.h.

84{ mTimerRecordCanceled = false; }

◆ SetAppending()

void ProjectAudioManager::SetAppending ( bool  value)
inlineprivate

Definition at line 143 of file ProjectAudioManager.h.

143{ mAppending = value; }

◆ SetCutting()

void ProjectAudioManager::SetCutting ( bool  value)
inlineprivate

Definition at line 145 of file ProjectAudioManager.h.

145{ mCutting = value; }

◆ SetLooping()

void ProjectAudioManager::SetLooping ( bool  value)
inlineprivate

Definition at line 144 of file ProjectAudioManager.h.

144{ mLooping = value; }

◆ SetPausedOff()

void ProjectAudioManager::SetPausedOff ( )
private

Definition at line 1054 of file ProjectAudioManager.cpp.

1055{
1056 mPaused.store(0, std::memory_order::memory_order_relaxed);
1057}

◆ SetStopping()

void ProjectAudioManager::SetStopping ( bool  value)
inlineprivate

Definition at line 146 of file ProjectAudioManager.h.

146{ mStopping = value; }

◆ SetTimerRecordCancelled()

void ProjectAudioManager::SetTimerRecordCancelled ( )
inline

Definition at line 83 of file ProjectAudioManager.h.

83{ mTimerRecordCanceled = true; }

Referenced by anonymous_namespace{TimerRecordDialog.cpp}::OnTimerRecord().

Here is the caller graph for this function:

◆ StatusWidthFunction()

auto ProjectAudioManager::StatusWidthFunction ( const AudacityProject project,
StatusBarField  field 
)
staticprivate

Definition at line 90 of file ProjectAudioManager.cpp.

93{
94 if ( field == RateStatusBarField() ) {
95 auto &audioManager = ProjectAudioManager::Get( project );
96 int rate = audioManager.mDisplayedRate;
97 return {
98 { { FormatRate( rate ) } },
99 50
100 };
101 }
102 return {};
103}
#define field(n, t)
Definition: ImportAUP.cpp:165

References field, FormatRate(), Get(), project, and RateStatusBarField().

Referenced by ProjectAudioManager().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Stop()

void ProjectAudioManager::Stop ( bool  stopStream = true)

Definition at line 501 of file ProjectAudioManager.cpp.

502{
504 auto &projectAudioManager = *this;
505 bool canStop = projectAudioManager.CanStopAudioStream();
506
507 if ( !canStop )
508 return;
509
510 if(project) {
511 // Let scrubbing code do some appearance change
512 auto &scrubber = Scrubber::Get( *project );
513 scrubber.StopScrubbing();
514 }
515
516 auto gAudioIO = AudioIO::Get();
517
518 auto cleanup = finally( [&]{
519 projectAudioManager.SetStopping( false );
520 } );
521
522 if (stopStream && gAudioIO->IsBusy()) {
523 // flag that we are stopping
524 projectAudioManager.SetStopping( true );
525 // Allow UI to update for that
526 while( wxTheApp->ProcessIdle() )
527 ;
528 }
529
530 if(stopStream)
531 gAudioIO->StopStream();
532
533 projectAudioManager.SetLooping( false );
534 projectAudioManager.SetCutting( false );
535
536 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
537 gAudioIO->AILADisable();
538 #endif
539
540 projectAudioManager.SetPausedOff();
541 //Make sure you tell gAudioIO to unpause
542 gAudioIO->SetPaused( false );
543
544 // So that we continue monitoring after playing or recording.
545 // also clean the MeterQueues
546 if( project ) {
547 auto &projectAudioIO = ProjectAudioIO::Get( *project );
548 auto meter = projectAudioIO.GetPlaybackMeter();
549 if( meter ) {
550 meter->Clear();
551 }
552
553 meter = projectAudioIO.GetCaptureMeter();
554 if( meter ) {
555 meter->Clear();
556 }
557 }
558}

References AudioIO::Get(), ProjectAudioIO::Get(), Scrubber::Get(), and project.

Referenced by AdornedRulerPanel::ScrubbingHandle::Cancel(), AdornedRulerPanel::ClearPlayRegion(), CommandDispatch::DoAudacityCommand(), Scrubber::DoKeyboardScrub(), Scrubber::OnActivateOrDeactivateApp(), ProjectManager::OnCloseWindow(), AudacityApp::OnKeyDown(), anonymous_namespace{TransportMenus.cpp}::OnStop(), TimerRecordDialog::RunWaitDialog(), and anonymous_namespace{DoEffect.cpp}::StopPlaybackCb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ StopIfPaused()

void ProjectAudioManager::StopIfPaused ( )

Definition at line 1249 of file ProjectAudioManager.cpp.

1250{
1251 if( AudioIOBase::Get()->IsPaused() )
1252 Stop();
1253}
static AudioIOBase * Get()
Definition: AudioIOBase.cpp:94

References AudioIOBase::Get().

Referenced by CloseButtonHandle::CommitChanges(), ControlToolBar::OnFF(), and ControlToolBar::OnRewind().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Stopping()

bool ProjectAudioManager::Stopping ( ) const
inline

Definition at line 94 of file ProjectAudioManager.h.

94{ return mStopping; }

◆ TogglePaused()

void ProjectAudioManager::TogglePaused ( )
private

Definition at line 1049 of file ProjectAudioManager.cpp.

1050{
1051 mPaused.fetch_xor(1, std::memory_order::memory_order_relaxed);
1052}

◆ UseDuplex()

bool ProjectAudioManager::UseDuplex ( )
static

Definition at line 750 of file ProjectAudioManager.cpp.

751{
752 bool duplex;
753 gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex, true);
754 return duplex;
755}

References gPrefs, audacity::BasicSettings::Read(), and wxT().

Referenced by anonymous_namespace{TransportMenus.cpp}::OnPunchAndRoll().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ mAppending

bool ProjectAudioManager::mAppending { false }
private

Definition at line 173 of file ProjectAudioManager.h.

◆ mCheckpointFailureSubscription

Observer::Subscription ProjectAudioManager::mCheckpointFailureSubscription
private

Definition at line 161 of file ProjectAudioManager.h.

Referenced by ProjectAudioManager().

◆ mCutting

bool ProjectAudioManager::mCutting { false }
private

Definition at line 175 of file ProjectAudioManager.h.

◆ mDisplayedRate

int ProjectAudioManager::mDisplayedRate { 0 }
private

Definition at line 178 of file ProjectAudioManager.h.

◆ mLastPlayMode

PlayMode ProjectAudioManager::mLastPlayMode { PlayMode::normalPlay }
private

Definition at line 164 of file ProjectAudioManager.h.

◆ mLooping

bool ProjectAudioManager::mLooping { false }
private

Definition at line 174 of file ProjectAudioManager.h.

◆ mPaused

std::atomic<int> ProjectAudioManager::mPaused { 0 }
private

Definition at line 171 of file ProjectAudioManager.h.

◆ mProject

AudacityProject& ProjectAudioManager::mProject
private

Definition at line 162 of file ProjectAudioManager.h.

◆ mStopping

bool ProjectAudioManager::mStopping { false }
private

Definition at line 176 of file ProjectAudioManager.h.

◆ mTimerRecordCanceled

bool ProjectAudioManager::mTimerRecordCanceled { false }
private

Definition at line 167 of file ProjectAudioManager.h.


The documentation for this class was generated from the following files: