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

69 : mProject{ project }
70{
72 registerStatusWidthFunction{ StatusWidthFunction };
75}
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 98 of file ProjectAudioManager.h.

98{ return mAppending; }

◆ CancelRecording()

void ProjectAudioManager::CancelRecording ( )
private

Definition at line 1056 of file ProjectAudioManager.cpp.

1057{
1058 const auto project = &mProject;
1059 TrackList::Get( *project ).ClearPendingTracks();
1060}
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:347
void ClearPendingTracks(ListOfTracks *pAdded=nullptr)
Definition: Track.cpp:1050

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

Here is the call graph for this function:

◆ CanStopAudioStream()

bool ProjectAudioManager::CanStopAudioStream ( ) const

Definition at line 1177 of file ProjectAudioManager.cpp.

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

Definition at line 565 of file ProjectAudioManager.cpp.

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

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

Referenced by 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 101 of file ProjectAudioManager.h.

101{ return mCutting; }

◆ DoPlayStopSelect() [1/2]

void ProjectAudioManager::DoPlayStopSelect ( )

Definition at line 1302 of file ProjectAudioManager.cpp.

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

1247{
1248 auto &project = mProject;
1249 auto &scrubber = Scrubber::Get( project );
1251 auto &viewInfo = ViewInfo::Get( project );
1252 auto &selection = viewInfo.selectedRegion;
1253 auto gAudioIO = AudioIO::Get();
1254
1255 //If busy, stop playing, make sure everything is unpaused.
1256 if (scrubber.HasMark() ||
1257 gAudioIO->IsStreamActive(token)) {
1258 // change the selection
1259 auto time = gAudioIO->GetStreamTime();
1260 // Test WasSpeedPlaying(), not IsSpeedPlaying()
1261 // as we could be stopped now. Similarly WasKeyboardScrubbing().
1262 if (click && (scrubber.WasSpeedPlaying() || scrubber.WasKeyboardScrubbing()))
1263 {
1264 ;// don't change the selection.
1265 }
1266 else if (shift && click) {
1267 // Change the region selection, as if by shift-click at the play head
1268 auto t0 = selection.t0(), t1 = selection.t1();
1269 if (time < t0)
1270 // Grow selection
1271 t0 = time;
1272 else if (time > t1)
1273 // Grow selection
1274 t1 = time;
1275 else {
1276 // Shrink selection, changing the nearer boundary
1277 if (fabs(t0 - time) < fabs(t1 - time))
1278 t0 = time;
1279 else
1280 t1 = time;
1281 }
1282 selection.setTimes(t0, t1);
1283 }
1284 else if (click){
1285 // avoid a point at negative time.
1286 time = wxMax( time, 0 );
1287 // Set a point selection, as if by a click at the play head
1288 selection.setTimes(time, time);
1289 } else
1290 // How stop and set cursor always worked
1291 // -- change t0, collapsing to point only if t1 was greater
1292 selection.setT0(time, false);
1293
1294 ProjectHistory::Get( project ).ModifyState(false); // without bWantsAutoSave
1295 return true;
1296 }
1297 return false;
1298}
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:188
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 768 of file ProjectAudioManager.cpp.

773{
774 auto &projectAudioManager = *this;
775
776 CommandFlag flags = AlwaysEnabledFlag; // 0 means recalc flags.
777
778 // NB: The call may have the side effect of changing flags.
780 flags,
782
783 if (!allowed)
784 return false;
785 // ...end of code from CommandHandler.
786
787 auto gAudioIO = AudioIO::Get();
788 if (gAudioIO->IsBusy())
789 return false;
790
791 projectAudioManager.SetAppending(!altAppearance);
792
793 bool success = false;
794
795 auto transportSequences = sequences;
796
797 // Will replace any given capture tracks with temporaries
798 transportSequences.captureSequences.clear();
799
800 const auto p = &project;
801 auto &trackList = TrackList::Get(project);
802
803 bool appendRecord = !sequences.captureSequences.empty();
804
805 auto makeNewClipName = [&](WaveTrack* track) {
806 for (auto i = 1; ; ++i) {
807 //i18n-hint a numerical suffix added to distinguish otherwise like-named clips when new record started
808 auto name = XC("%s #%d", "clip name template")
809 .Format(track->GetName(), i).Translation();
810 if (track->FindClipByName(name) == nullptr)
811 return name;
812 }
813 };
814
815 {
816 if (appendRecord) {
817 // Append recording:
818 // Pad selected/all wave tracks to make them all the same length
819 for (const auto &sequence : sequences.captureSequences) {
820 WaveTrack *wt{};
821 if (!(wt = dynamic_cast<WaveTrack *>(sequence.get()))) {
822 assert(false);
823 continue;
824 }
825 if (!wt->IsLeader())
826 continue;
827 auto endTime = wt->GetEndTime();
828
829 // If the track was chosen for recording and playback both,
830 // remember the original in preroll tracks, before making the
831 // pending replacement.
832 const auto shared = wt->SharedPointer<WaveTrack>();
833 // playbackSequences contains only leaders; prerollSequences should
834 // be a subset of it. Non-leader might not be found, but that is
835 // all right.
836 const auto &range = transportSequences.playbackSequences;
837 bool prerollTrack = any_of(range.begin(), range.end(),
838 [&](const auto &pSequence){
839 return shared.get() == pSequence->FindChannelGroup(); });
840 if (prerollTrack)
841 transportSequences.prerollSequences.push_back(shared);
842
843 // A function that copies all the non-sample data between
844 // wave tracks; in case the track recorded to changes scale
845 // type (for instance), during the recording.
846 auto updater = [](Track &d, const Track &s){
847 assert(d.IsLeader());
848 assert(s.IsLeader());
849 assert(d.NChannels() == s.NChannels());
850 auto &dst = static_cast<WaveTrack&>(d);
851 auto &src = static_cast<const WaveTrack&>(s);
852 dst.Reinit(src);
853 };
854
855 // Get a copy of the track to be appended, to be pushed into
856 // undo history only later.
857 const auto pending = static_cast<WaveTrack*>(
858 trackList.RegisterPendingChangedTrack(updater, wt)
859 );
860 // End of current track is before or at recording start time.
861 // Less than or equal, not just less than, to ensure a clip boundary.
862 // when append recording.
863 //const auto pending = static_cast<WaveTrack*>(newTrack);
864 const auto lastClip = pending->GetRightmostClip();
865 // RoundedT0 to have a new clip created when punch-and-roll
866 // recording with the cursor in the second half of the space
867 // between two samples
868 // (https://github.com/audacity/audacity/issues/5113#issuecomment-1705154108)
869 const auto recordingStart =
870 std::round(t0 * pending->GetRate()) / pending->GetRate();
871 const auto recordingStartsBeforeTrackEnd =
872 lastClip && recordingStart < lastClip->GetPlayEndTime();
873 // Recording doesn't start before the beginning of the last clip
874 // - or the check for creating a new clip or not should be more
875 // general than that ...
876 assert(
877 !recordingStartsBeforeTrackEnd ||
878 lastClip->WithinPlayRegion(recordingStart));
879 if (!recordingStartsBeforeTrackEnd ||
880 !lastClip->StretchRatioEquals(1))
881 pending->CreateWideClip(t0, makeNewClipName(pending));
882 transportSequences.captureSequences
883 .push_back(pending->SharedPointer<WaveTrack>());
884 }
885 trackList.UpdatePendingTracks();
886 }
887
888 if (transportSequences.captureSequences.empty()) {
889 // recording to NEW track(s).
890 bool recordingNameCustom, useTrackNumber, useDateStamp, useTimeStamp;
891 wxString defaultTrackName, defaultRecordingTrackName;
892
893 // Count the tracks.
894 auto numTracks = trackList.Any<const WaveTrack>().size();
895
896 auto recordingChannels = std::max(1, AudioIORecordChannels.Read());
897
898 gPrefs->Read(wxT("/GUI/TrackNames/RecordingNameCustom"), &recordingNameCustom, false);
899 gPrefs->Read(wxT("/GUI/TrackNames/TrackNumber"), &useTrackNumber, false);
900 gPrefs->Read(wxT("/GUI/TrackNames/DateStamp"), &useDateStamp, false);
901 gPrefs->Read(wxT("/GUI/TrackNames/TimeStamp"), &useTimeStamp, false);
902 defaultTrackName = trackList.MakeUniqueTrackName(WaveTrack::GetDefaultAudioTrackNamePreference());
903 gPrefs->Read(wxT("/GUI/TrackNames/RecodingTrackName"), &defaultRecordingTrackName, defaultTrackName);
904
905 wxString baseTrackName = recordingNameCustom? defaultRecordingTrackName : defaultTrackName;
906
907 auto newTracks = WaveTrackFactory::Get(*p).Create(recordingChannels);
908 const auto first = *newTracks->begin();
909 int trackCounter = 0;
910 const auto minimizeChannelView = recordingChannels > 2;
911 for (auto newTrack : newTracks->Any<WaveTrack>()) {
912 // Quantize bounds to the rate of the new track.
913 if (newTrack == first) {
914 if (t0 < DBL_MAX)
915 t0 = newTrack->SnapToSample(t0);
916 if (t1 < DBL_MAX)
917 t1 = newTrack->SnapToSample(t1);
918 }
919
920 newTrack->MoveTo(t0);
921 wxString nameSuffix = wxString(wxT(""));
922
923 if (useTrackNumber) {
924 nameSuffix += wxString::Format(wxT("%d"), 1 + (int) numTracks + trackCounter++);
925 }
926
927 if (useDateStamp) {
928 if (!nameSuffix.empty()) {
929 nameSuffix += wxT("_");
930 }
931 nameSuffix += wxDateTime::Now().FormatISODate();
932 }
933
934 if (useTimeStamp) {
935 if (!nameSuffix.empty()) {
936 nameSuffix += wxT("_");
937 }
938 nameSuffix += wxDateTime::Now().FormatISOTime();
939 }
940
941 // ISO standard would be nice, but ":" is unsafe for file name.
942 nameSuffix.Replace(wxT(":"), wxT("-"));
943
944 if (baseTrackName.empty())
945 newTrack->SetName(nameSuffix);
946 else if (nameSuffix.empty())
947 newTrack->SetName(baseTrackName);
948 else
949 newTrack->SetName(baseTrackName + wxT("_") + nameSuffix);
950
951 //create a new clip with a proper name before recording is started
952 newTrack->CreateWideClip(t0, makeNewClipName(newTrack));
953
954 transportSequences.captureSequences.push_back(
955 std::static_pointer_cast<WaveTrack>(newTrack->shared_from_this())
956 );
957
958 for(auto channel : newTrack->Channels())
959 {
960 ChannelView::Get(*channel).SetMinimized(minimizeChannelView);
961 }
962 }
963 trackList.RegisterPendingNewTracks(std::move(*newTracks));
964 // Bug 1548. First of new tracks needs the focus.
965 TrackFocus::Get(project).Set(first);
966 if (!trackList.empty())
967 Viewport::Get(project).ShowTrack(**trackList.rbegin());
968 }
969
970 //Automated Input Level Adjustment Initialization
971 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
972 gAudioIO->AILAInitialize();
973 #endif
974
975 int token =
976 gAudioIO->StartStream(transportSequences, t0, t1, t1, options);
977
978 success = (token != 0);
979
980 if (success) {
982 }
983 else {
985
986 // Show error message if stream could not be opened
987 auto msg = XO("Error opening recording device.\nError code: %s")
988 .Format( gAudioIO->LastPaErrorString() );
989 using namespace BasicUI;
991 XO("Error"), msg, wxT("Error_opening_sound_device"),
992 ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
993 }
994 }
995
996 return success;
997}
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:122
bool IsLeader() const override
Definition: Track.cpp:291
void ShowTrack(const Track &track)
Definition: Viewport.cpp:478
static Viewport & Get(AudacityProject &project)
Definition: Viewport.cpp:32
std::shared_ptr< WaveTrack > Create()
Creates an unnamed empty WaveTrack with default sample format and default rate.
Definition: WaveTrack.cpp:726
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:4476
void Reinit(const WaveTrack &orig)
Definition: WaveTrack.cpp:829
static wxString GetDefaultAudioTrackNamePreference()
Definition: WaveTrack.cpp:708
const WaveClip * GetRightmostClip() const
Definition: WaveTrack.cpp:3003
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:262
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, AudioIONotBusyFlag(), AudioIORecordChannels, CanStopAudioStreamFlag(), TransportSequences::captureSequences, WaveTrackFactory::Create(), AudioIO::Get(), TrackFocus::Get(), ProjectAudioIO::Get(), CommandManager::Get(), TrackList::Get(), Viewport::Get(), WaveTrackFactory::Get(), ChannelView::Get(), WaveTrack::GetDefaultAudioTrackNamePreference(), WaveTrack::GetRightmostClip(), gPrefs, Track::IsLeader(), name, ChannelGroup::NChannels(), project, ProjectFramePlacement(), audacity::BasicSettings::Read(), Setting< T >::Read(), WaveTrack::Reinit(), fast_float::round(), ProjectAudioIO::SetAudioIOToken(), ChannelView::SetMinimized(), BasicUI::ShowErrorDialog(), Viewport::ShowTrack(), size, CommandManager::TryToMakeActionAllowed(), updater, wxT(), XC, and XO().

Here is the call graph for this function:

◆ Get() [1/2]

ProjectAudioManager & ProjectAudioManager::Get ( AudacityProject project)
static

Definition at line 56 of file ProjectAudioManager.cpp.

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

References project, and sProjectAudioManagerKey.

Referenced by AdornedRulerPanel::ScrubbingHandle::Cancel(), CanStopAudioStreamFlag(), AdornedRulerPanel::ClearPlayRegion(), CloseButtonHandle::CommitChanges(), CommandDispatch::DoAudacityCommand(), EffectUI::DoEffect(), anonymous_namespace{TransportMenus.cpp}::DoMoveToLabel(), TransportUtilities::DoStopPlaying(), anonymous_namespace{DropoutDetector.cpp}::DropoutSubscription::DropoutSubscription(), ControlToolBar::EnableDisableButtons(), Get(), Scrubber::MarkScrubStart(), ProjectManager::New(), ProjectManager::OnCloseWindow(), ControlToolBar::OnFF(), ControlToolBar::OnIdle(), AudacityApp::OnKeyDown(), ControlToolBar::OnKeyEvent(), anonymous_namespace{TransportMenus.cpp}::OnPause(), ControlToolBar::OnPause(), ControlToolBar::OnPlay(), anonymous_namespace{TransportMenus.cpp}::OnPlayStopSelect(), 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(), AdornedRulerPanel::StartQPPlay(), ControlToolBar::StateForStatusBar(), and StatusWidthFunction().

Here is the caller graph for this function:

◆ Get() [2/2]

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

Definition at line 62 of file ProjectAudioManager.cpp.

64{
65 return Get( const_cast< AudacityProject & >( project ) );
66}
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 137 of file ProjectAudioManager.h.

137{ 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 83 of file ProjectAudioManager.h.

◆ Looping()

bool ProjectAudioManager::Looping ( ) const
inline

Definition at line 100 of file ProjectAudioManager.h.

100{ return mLooping; }

◆ OnAudioIONewBlocks()

void ProjectAudioManager::OnAudioIONewBlocks ( )
overrideprivatevirtual

Implements AudioIOListener.

Definition at line 1117 of file ProjectAudioManager.cpp.

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

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

1063{
1064 auto &project = mProject;
1065
1066 mDisplayedRate = rate;
1067
1068 auto display = FormatRate( rate );
1069
1071}
static TranslatableString FormatRate(int rate)
@ rateStatusBarField
Definition: ProjectStatus.h:27
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 1073 of file ProjectAudioManager.cpp.

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

◆ OnAudioIOStopRecording()

void ProjectAudioManager::OnAudioIOStopRecording ( )
overrideprivatevirtual

Implements AudioIOListener.

Definition at line 1080 of file ProjectAudioManager.cpp.

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

1151{
1153 Stop();
1154}
@ 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 1125 of file ProjectAudioManager.cpp.

1126{
1127 const auto project = &mProject;
1128 TrackList::Get( *project ).ApplyPendingTracks();
1129}
bool ApplyPendingTracks()
Definition: Track.cpp:1092

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

Here is the call graph for this function:

◆ OnPause()

void ProjectAudioManager::OnPause ( )

Definition at line 999 of file ProjectAudioManager.cpp.

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

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

References AudacityMessageBox(), TransportSequences::captureSequences, staffpad::vo::copy(), PackedArray::end(), ViewInfo::Get(), TrackList::Get(), ProjectAudioIO::GetDefaultOptions(), ChannelGroup::GetEndTime(), GetPropertiesOfSelected(), gPrefs, MakeTransportTracks(), TransportSequences::playbackSequences, RATE_NOT_SELECTED, 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 1131 of file ProjectAudioManager.cpp.

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

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

1051{
1052 return mPaused.load(std::memory_order_relaxed) == 1;
1053}
std::atomic< int > mPaused

◆ PlayCurrentRegion()

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

Definition at line 470 of file ProjectAudioManager.cpp.

472{
473 auto &projectAudioManager = *this;
474 bool canStop = projectAudioManager.CanStopAudioStream();
475
476 if ( !canStop )
477 return;
478
480
481 {
482
483 const auto &playRegion = ViewInfo::Get( *p ).playRegion;
484
485 if (newDefault)
486 cutpreview = false;
487 auto options = ProjectAudioIO::GetDefaultOptions(*p, newDefault);
488 if (cutpreview)
489 options.envelope = nullptr;
490 auto mode =
491 cutpreview ? PlayMode::cutPreviewPlay
492 : newDefault ? PlayMode::loopedPlay
494 PlayPlayRegion(SelectedRegion(playRegion.GetStart(), playRegion.GetEnd()),
495 options,
496 mode);
497 }
498}
@ 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 1156 of file ProjectAudioManager.cpp.

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

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

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

Here is the call graph for this function:

◆ Recording()

bool ProjectAudioManager::Recording ( ) const

Definition at line 1168 of file ProjectAudioManager.cpp.

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

References AudioIO::Get().

Here is the call graph for this function:

◆ ResetTimerRecordCancelled()

void ProjectAudioManager::ResetTimerRecordCancelled ( )
inline

Definition at line 85 of file ProjectAudioManager.h.

85{ mTimerRecordCanceled = false; }

◆ SetAppending()

void ProjectAudioManager::SetAppending ( bool  value)
inlineprivate

Definition at line 144 of file ProjectAudioManager.h.

144{ mAppending = value; }

◆ SetCutting()

void ProjectAudioManager::SetCutting ( bool  value)
inlineprivate

Definition at line 146 of file ProjectAudioManager.h.

146{ mCutting = value; }

◆ SetLooping()

void ProjectAudioManager::SetLooping ( bool  value)
inlineprivate

Definition at line 145 of file ProjectAudioManager.h.

145{ mLooping = value; }

◆ SetPausedOff()

void ProjectAudioManager::SetPausedOff ( )
private

Definition at line 1045 of file ProjectAudioManager.cpp.

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

◆ SetStopping()

void ProjectAudioManager::SetStopping ( bool  value)
inlineprivate

Definition at line 147 of file ProjectAudioManager.h.

147{ mStopping = value; }

◆ SetTimerRecordCancelled()

void ProjectAudioManager::SetTimerRecordCancelled ( )
inline

Definition at line 84 of file ProjectAudioManager.h.

84{ 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 89 of file ProjectAudioManager.cpp.

92{
93 if ( field == rateStatusBarField ) {
94 auto &audioManager = ProjectAudioManager::Get( project );
95 int rate = audioManager.mDisplayedRate;
96 return {
97 { { FormatRate( rate ) } },
98 50
99 };
100 }
101 return {};
102}
#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 500 of file ProjectAudioManager.cpp.

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

References ToolBar::EnableDisableButtons(), AudioIO::Get(), ProjectAudioIO::Get(), ToolManager::Get(), Scrubber::Get(), ToolManager::GetToolBar(), project, and wxT().

Referenced by AdornedRulerPanel::ScrubbingHandle::Cancel(), AdornedRulerPanel::ClearPlayRegion(), CommandDispatch::DoAudacityCommand(), EffectUI::DoEffect(), 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 1240 of file ProjectAudioManager.cpp.

1241{
1242 if( AudioIOBase::Get()->IsPaused() )
1243 Stop();
1244}
static AudioIOBase * Get()
Definition: AudioIOBase.cpp:93

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 95 of file ProjectAudioManager.h.

95{ return mStopping; }

◆ TogglePaused()

void ProjectAudioManager::TogglePaused ( )
private

Definition at line 1040 of file ProjectAudioManager.cpp.

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

◆ UseDuplex()

bool ProjectAudioManager::UseDuplex ( )
static

Definition at line 755 of file ProjectAudioManager.cpp.

756{
757 bool duplex;
758 gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex,
759#ifdef EXPERIMENTAL_DA
760 false
761#else
762 true
763#endif
764 );
765 return duplex;
766}

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

Here is the call graph for this function:

Member Data Documentation

◆ mAppending

bool ProjectAudioManager::mAppending { false }
private

Definition at line 174 of file ProjectAudioManager.h.

◆ mCheckpointFailureSubscription

Observer::Subscription ProjectAudioManager::mCheckpointFailureSubscription
private

Definition at line 162 of file ProjectAudioManager.h.

Referenced by ProjectAudioManager().

◆ mCutting

bool ProjectAudioManager::mCutting { false }
private

Definition at line 176 of file ProjectAudioManager.h.

◆ mDisplayedRate

int ProjectAudioManager::mDisplayedRate { 0 }
private

Definition at line 179 of file ProjectAudioManager.h.

◆ mLastPlayMode

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

Definition at line 165 of file ProjectAudioManager.h.

◆ mLooping

bool ProjectAudioManager::mLooping { false }
private

Definition at line 175 of file ProjectAudioManager.h.

◆ mPaused

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

Definition at line 172 of file ProjectAudioManager.h.

◆ mProject

AudacityProject& ProjectAudioManager::mProject
private

Definition at line 163 of file ProjectAudioManager.h.

◆ mStopping

bool ProjectAudioManager::mStopping { false }
private

Definition at line 177 of file ProjectAudioManager.h.

◆ mTimerRecordCanceled

bool ProjectAudioManager::mTimerRecordCanceled { false }
private

Definition at line 168 of file ProjectAudioManager.h.


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