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 1057 of file ProjectAudioManager.cpp.

1058{
1059 const auto project = &mProject;
1061}
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 1178 of file ProjectAudioManager.cpp.

1179{
1180 auto gAudioIO = AudioIO::Get();
1181 return (!gAudioIO->IsStreamActive() ||
1182 gAudioIO->IsMonitoring() ||
1183 gAudioIO->GetOwningProject().get() == &mProject );
1184}
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:532

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 1303 of file ProjectAudioManager.cpp.

1304{
1305 auto gAudioIO = AudioIO::Get();
1306 if (DoPlayStopSelect(false, false))
1307 Stop();
1308 else if (!gAudioIO->IsBusy()) {
1309 //Otherwise, start playing (assuming audio I/O isn't busy)
1310
1311 // Will automatically set mLastPlayMode
1312 PlayCurrentRegion(false);
1313 }
1314}
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 1247 of file ProjectAudioManager.cpp.

1248{
1249 auto &project = mProject;
1250 auto &scrubber = Scrubber::Get( project );
1252 auto &viewInfo = ViewInfo::Get( project );
1253 auto &selection = viewInfo.selectedRegion;
1254 auto gAudioIO = AudioIO::Get();
1255
1256 //If busy, stop playing, make sure everything is unpaused.
1257 if (scrubber.HasMark() ||
1258 gAudioIO->IsStreamActive(token)) {
1259 // change the selection
1260 auto time = gAudioIO->GetStreamTime();
1261 // Test WasSpeedPlaying(), not IsSpeedPlaying()
1262 // as we could be stopped now. Similarly WasKeyboardScrubbing().
1263 if (click && (scrubber.WasSpeedPlaying() || scrubber.WasKeyboardScrubbing()))
1264 {
1265 ;// don't change the selection.
1266 }
1267 else if (shift && click) {
1268 // Change the region selection, as if by shift-click at the play head
1269 auto t0 = selection.t0(), t1 = selection.t1();
1270 if (time < t0)
1271 // Grow selection
1272 t0 = time;
1273 else if (time > t1)
1274 // Grow selection
1275 t1 = time;
1276 else {
1277 // Shrink selection, changing the nearer boundary
1278 if (fabs(t0 - time) < fabs(t1 - time))
1279 t0 = time;
1280 else
1281 t1 = time;
1282 }
1283 selection.setTimes(t0, t1);
1284 }
1285 else if (click){
1286 // avoid a point at negative time.
1287 time = wxMax( time, 0 );
1288 // Set a point selection, as if by a click at the play head
1289 selection.setTimes(time, time);
1290 } else
1291 // How stop and set cursor always worked
1292 // -- change t0, collapsing to point only if t1 was greater
1293 selection.setT0(time, false);
1294
1295 ProjectHistory::Get( project ).ModifyState(false); // without bWantsAutoSave
1296 return true;
1297 }
1298 return false;
1299}
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 Viewport::Get(project).ShowTrack(**trackList.rbegin());
972 }
973
974 //Automated Input Level Adjustment Initialization
975 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
976 gAudioIO->AILAInitialize();
977 #endif
978
979 int token =
980 gAudioIO->StartStream(transportSequences, t0, t1, t1, options);
981
982 success = (token != 0);
983
984 if (success) {
986 }
987 else {
989
990 // Show error message if stream could not be opened
991 auto msg = XO("Error opening recording device.\nError code: %s")
992 .Format( gAudioIO->LastPaErrorString() );
993 using namespace BasicUI;
995 XO("Error"), msg, wxT("Error_opening_sound_device"),
996 ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
997 }
998 }
999
1000 return success;
1001}
wxT("CloseDown"))
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:34
std::bitset< NCommandFlags > CommandFlag
Definition: CommandFlag.h:30
const ReservedCommandFlag & AudioIONotBusyFlag()
const TranslatableString name
Definition: Distortion.cpp:76
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()
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
void ShowTrack(const Track &track)
Definition: Viewport.cpp:456
static Viewport & Get(AudacityProject &project)
Definition: Viewport.cpp:33
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:3349
TrackListHolder CreateMany(size_t nChannels)
Creates tracks with project's default rate and format and the given number of channels.
Definition: WaveTrack.cpp:425
bool HasClipNamed(const wxString &name) const
Definition: WaveTrack.cpp:711
IntervalHolder CreateClip(double offset=.0, const wxString &name=wxEmptyString, const Interval *pToCopy=nullptr, bool copyCutlines=true)
Definition: WaveTrack.cpp:2934
void InsertInterval(const IntervalHolder &interval, bool newClip, bool allowEmpty=false)
Definition: WaveTrack.cpp:3208
static wxString GetDefaultAudioTrackNamePreference()
Definition: WaveTrack.cpp:375
void Init(const WaveTrack &orig)
Definition: WaveTrack.cpp:555
std::shared_ptr< Interval > IntervalHolder
Definition: WaveTrack.h:209
virtual bool Read(const wxString &key, bool *value) const =0
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:264
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:71
ConstPlayableSequences prerollSequences
Definition: AudioIO.h:76
ConstPlayableSequences playbackSequences
Definition: AudioIO.h:70

References AlwaysEnabledFlag, Track::Any(), AudioIONotBusyFlag(), AudioIORecordChannels, CanStopAudioStreamFlag(), TransportSequences::captureSequences, WaveTrack::CreateClip(), WaveTrackFactory::CreateMany(), AudioIO::Get(), TrackFocus::Get(), ProjectAudioIO::Get(), CommandManager::Get(), PendingTracks::Get(), TrackList::Get(), Viewport::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(), Viewport::ShowTrack(), 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(), EffectUI::DoEffect(), 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(), 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 1118 of file ProjectAudioManager.cpp.

1119{
1120 auto &project = mProject;
1121 auto &projectFileIO = ProjectFileIO::Get( project );
1122
1123 wxTheApp->CallAfter( [&]{ projectFileIO.AutoSave(true); });
1124}

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 1063 of file ProjectAudioManager.cpp.

1064{
1065 auto &project = mProject;
1066
1067 mDisplayedRate = rate;
1068
1069 auto display = FormatRate( rate );
1070
1072}
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 1074 of file ProjectAudioManager.cpp.

1075{
1076 // Auto-save was done here before, but it is unnecessary, provided there
1077 // are sufficient autosaves when pushing or modifying undo states.
1078}

◆ OnAudioIOStopRecording()

void ProjectAudioManager::OnAudioIOStopRecording ( )
overrideprivatevirtual

Implements AudioIOListener.

Definition at line 1081 of file ProjectAudioManager.cpp.

1082{
1083 auto &project = mProject;
1084 auto &projectAudioIO = ProjectAudioIO::Get( project );
1085 auto &projectFileIO = ProjectFileIO::Get( project );
1086
1087 // Only push state if we were capturing and not monitoring
1088 if (projectAudioIO.GetAudioIOToken() > 0)
1089 {
1090 auto &history = ProjectHistory::Get( project );
1091
1092 if (IsTimerRecordCancelled()) {
1093 // discard recording
1094 history.RollbackState();
1095 // Reset timer record
1097 }
1098 else {
1099 // Add to history
1100 // We want this to have No-fail-guarantee if we get here from exception
1101 // handling of recording, and that means we rely on the last autosave
1102 // successfully committed to the database, not risking a failure
1103 auto flags = AudioIO::Get()->HasRecordingException()
1106 history.PushState(XO("Recorded Audio"), XO("Record"), flags);
1107
1108 // Now, we may add a label track to give information about
1109 // dropouts. We allow failure of this.
1110 auto gAudioIO = AudioIO::Get();
1111 auto &intervals = gAudioIO->LostCaptureIntervals();
1112 if (intervals.size())
1113 Publish( RecordingDropoutEvent{ intervals } );
1114 }
1115 }
1116}
bool HasRecordingException() const
Definition: AudioIO.h:374
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 1151 of file ProjectAudioManager.cpp.

1152{
1154 Stop();
1155}
@ 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 1126 of file ProjectAudioManager.cpp.

1127{
1128 const auto project = &mProject;
1130}
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 1003 of file ProjectAudioManager.cpp.

1004{
1005 auto &projectAudioManager = *this;
1006 bool canStop = projectAudioManager.CanStopAudioStream();
1007
1008 if ( !canStop ) {
1009 return;
1010 }
1011
1012 bool paused = !projectAudioManager.Paused();
1013 TogglePaused();
1014
1015 auto gAudioIO = AudioIO::Get();
1016
1017 auto project = &mProject;
1018 auto &scrubber = Scrubber::Get( *project );
1019
1020 // Bug 1494 - Pausing a seek or scrub should just STOP as
1021 // it is confusing to be in a paused scrub state.
1022 bool bStopInstead = paused &&
1024 !scrubber.IsSpeedPlaying() &&
1025 !scrubber.IsKeyboardScrubbing();
1026
1027 if (bStopInstead) {
1028 Stop();
1029 return;
1030 }
1031
1033 scrubber.Pause(paused);
1034 else
1035 {
1036 gAudioIO->SetPaused(paused);
1037 }
1038}
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:215
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 1132 of file ProjectAudioManager.cpp.

1133{
1134 auto& project = mProject;
1135 auto gAudioIO = AudioIO::Get();
1136 if (gAudioIO && &project == gAudioIO->GetOwningProject().get())
1137 {
1138 bool canStop = CanStopAudioStream();
1139
1140 gAudioIO->SetPaused(!gAudioIO->IsPaused());
1141
1142 if (canStop)
1143 {
1144 // Instead of calling ::OnPause here, we can simply do the only thing it does (i.e. toggling the pause state),
1145 // because scrubbing can not happen while recording
1146 TogglePaused();
1147 }
1148 }
1149}

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 1051 of file ProjectAudioManager.cpp.

1052{
1053 return mPaused.load(std::memory_order_relaxed) == 1;
1054}
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:216

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 1157 of file ProjectAudioManager.cpp.

1158{
1159 auto gAudioIO = AudioIO::Get();
1160 return
1161 gAudioIO->IsBusy() &&
1163 // ... and not merely monitoring
1164 !gAudioIO->IsMonitoring() &&
1165 // ... and not punch-and-roll recording
1166 gAudioIO->GetNumCaptureChannels() == 0;
1167}

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:628
struct holding stream options, including a pointer to the time warp info and AudioIOListener and whet...
Definition: AudioIOBase.h:44
PolicyFactory policyFactory
Definition: AudioIOBase.h:73
std::optional< double > pStartTime
Definition: AudioIOBase.h:58

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 1169 of file ProjectAudioManager.cpp.

1170{
1171 auto gAudioIO = AudioIO::Get();
1172 return
1173 gAudioIO->IsBusy() &&
1175 gAudioIO->GetNumCaptureChannels() > 0;
1176}

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 1046 of file ProjectAudioManager.cpp.

1047{
1048 mPaused.store(0, std::memory_order::memory_order_relaxed);
1049}

◆ 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(), EffectUI::DoEffect(), Scrubber::DoKeyboardScrub(), Scrubber::OnActivateOrDeactivateApp(), ProjectManager::OnCloseWindow(), AudacityApp::OnKeyDown(), anonymous_namespace{TransportMenus.cpp}::OnStop(), and TimerRecordDialog::RunWaitDialog().

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

◆ StopIfPaused()

void ProjectAudioManager::StopIfPaused ( )

Definition at line 1241 of file ProjectAudioManager.cpp.

1242{
1243 if( AudioIOBase::Get()->IsPaused() )
1244 Stop();
1245}
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 1041 of file ProjectAudioManager.cpp.

1042{
1043 mPaused.fetch_xor(1, std::memory_order::memory_order_relaxed);
1044}

◆ 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: