30#include <wx/wxcrtvararg.h>
32#include <wx/calctrl.h>
33#include <wx/checkbox.h>
37#include <wx/datectrl.h>
38#include <wx/datetime.h>
68#if wxUSE_ACCESSIBILITY
102 return (dateTime.GetHour() * 3600.0) + (dateTime.GetMinute() * 60.0) + dateTime.GetSecond();
118#if wxUSE_ACCESSIBILITY
123 DatePickerCtrlAx(wxDatePickerCtrl * ctrl) :
WindowAccessible(ctrl), mCtrl(ctrl) {};
125 virtual ~ DatePickerCtrlAx() {};
128 wxAccStatus GetState(
int childId,
long *state)
override;
131 wxDatePickerCtrl *mCtrl;
135wxAccStatus DatePickerCtrlAx::GetState(
int WXUNUSED(childId),
long *state)
137 *state = wxACC_STATE_SYSTEM_FOCUSABLE;
171 wxDefaultSize, wxCAPTION)
176 m_DateTime_Start = wxDateTime::UNow();
178 gPrefs->
Read(
wxT(
"/TimerRecord/LastDuration"), &seconds, 3600L);
179 m_TimeSpan_Duration = wxTimeSpan::Seconds(seconds);
180 m_DateTime_End = m_DateTime_Start + m_TimeSpan_Duration;
182 m_pDatePickerCtrl_Start = NULL;
183 m_pTimeTextCtrl_Start = NULL;
185 m_pDatePickerCtrl_End = NULL;
186 m_pTimeTextCtrl_End = NULL;
188 m_pTimeTextCtrl_Duration = NULL;
191 m_bProjectAlreadySaved = bAlreadySaved;
195 if(exportPath.empty())
197 m_fnAutoExportFile.SetPath(exportPath);
199 m_fnAutoExportFile.SetName(mProject.GetProjectName());
200 if(m_fnAutoExportFile.GetName().IsEmpty())
201 m_fnAutoExportFile.SetName(
_(
"untitled"));
204 if(!m_sAutoExportFormat.empty())
206 auto [plugin, formatIndex]
209 if(plugin !=
nullptr)
211 const auto formatInfo = plugin->GetFormatInfo(formatIndex);
212 m_fnAutoExportFile.SetExt(formatInfo.extensions[0]);
219 this->PopulateOrExchange(
S);
223 m_pTimeTextCtrl_Duration->SetFocus();
224 m_pTimeTextCtrl_Duration->SetFieldFocus(3);
234 wxDateTime dateTime_UNow = wxDateTime::UNow();
247 long hr = (long)(dTime / 3600.0);
248 long min = (long)((dTime - (hr * 3600.0)) / 60.0);
249 long sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
256 wxTimerEvent dummyTimerEvent;
257 this->
OnTimer(dummyTimerEvent);
273 long days = (long)(dTime / (24.0 * 3600.0));
275 dTime -= (double)days * 24.0 * 3600.0;
281 wxDateEvent dummyDateEvent;
289 long hr = (long)(dTime / 3600.0);
290 long min = (long)((dTime - (hr * 3600.0)) / 60.0);
291 long sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
315 long days = (long)(dTime / (24.0 * 3600.0));
317 dTime -= (double)days * 24.0 * 3600.0;
323 wxDateEvent dummyDateEvent;
330 long hr = (long)(dTime / 3600.0);
331 long min = (long)((dTime - (hr * 3600.0)) / 60.0);
332 long sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
343 wxString fName =
SelectFile(FileNames::Operation::Export,
344 XO(
"Save Timer Recording As"),
349 wxFD_SAVE | wxRESIZE_BORDER,
357 if (wxFileExists(fName) && (projectFileIO.GetFileName() != fName)) {
360 XO(
"The selected file name could not be used\nfor Timer Recording because it \
361would overwrite another project.\nPlease try again and select an original name."),
362 XO(
"Error Saving Timer Recording Project"),
388 if(exportDialog.ShowModal() != wxID_OK)
413 if (!m_TimeSpan_Duration.IsPositive())
416 XO(
"Duration is zero. Nothing will be recorded."),
417 XO(
"Error in Duration"),
418 wxICON_EXCLAMATION | wxOK);
427 XO(
"Automatic Save path is invalid."),
428 XO(
"Error in Automatic Save"),
429 wxICON_EXCLAMATION | wxOK);
436 XO(
"Automatic Export path is invalid."),
437 XO(
"Error in Automatic Export"),
438 wxICON_EXCLAMATION | wxOK);
453 int iMinsLeft = projectManager.GetEstimatedRecordingMinsLeftOnDisk();
459 if (iMinsRecording >= iMinsLeft) {
462 auto sRemainingTime = projectManager.GetHoursMinsString(iMinsLeft);
463 auto sPlannedTime = projectManager.GetHoursMinsString(iMinsRecording);
467"You may not have enough free disk space to complete this Timer Recording, based on your current settings.\n\nDo you wish to continue?\n\nPlanned recording duration: %s\nRecording time remaining on disk: %s")
468 .Format( sPlannedTime, sRemainingTime );
473 XO(
"Timer Recording Disk Space Warning"),
474 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
475 if (dlgMessage.ShowModal() != wxID_YES ) {
482 this->EndModal(wxID_OK);
485 gPrefs->
Write(
wxT(
"/TimerRecord/LastDuration"), duration.ToLong());
526 gAudioIO->DelayActions(
true);
528 auto cleanup =
finally([gAudioIO]{ gAudioIO->DelayActions(
false); });
539 bool bIsRecording =
true;
547 XO(
"Recording start:") ,
549 XO(
"Recording end:") ,
551 XO(
"Automatic Save enabled:") ,
552 XO(
"Automatic Export enabled:") ,
553 XO(
"Action after Timer Recording:") ,
568 XO(
"Audacity Timer Record Progress"),
574 wxTimerEvent dummyTimerEvent;
575 this->
OnTimer(dummyTimerEvent);
580 using namespace std::chrono;
609 bool bSaveOK =
false;
610 bool bExportOK =
false;
612 int iOverriddenAction = iPostRecordAction;
613 bool bErrorOverride =
false;
621 bSaveOK = projectFileManager.Save();
637 const auto t0 = std::max(.0,
tracks.GetStartTime());
639 auto [exportPlugin, formatIndex] =
642 if(exportPlugin !=
nullptr)
670 if (bErrorOverride || bWasStopped) {
677 auto sMessage = (bWasStopped ?
XO(
"Timer Recording stopped.") :
678 XO(
"Timer Recording completed."));
682 sMessage =
XO(
"%s\n\nRecording saved: %s").Format(
685 sMessage =
XO(
"%s\n\nError saving recording.").Format( sMessage );
690 sMessage =
XO(
"%s\n\nRecording exported: %s").Format(
693 sMessage =
XO(
"%s\n\nError exporting recording.").Format( sMessage );
697 if (bErrorOverride) {
699 if ((iOverriddenAction != iPostRecordAction) &&
702 sMessage =
XO(
"%s\n\n'%s' has been canceled due to the error(s) noted above.").Format(
711 wxICON_EXCLAMATION | wxOK);
715 sMessage =
XO(
"%s\n\n'%s' has been canceled as the recording was stopped.").Format(
722 XO(
"Timer Recording"),
723 wxICON_INFORMATION | wxOK);
753 return iPostRecordAction;
758#if defined(__WXMSW__)
770 const wxDateTime::Tm tm(dt.GetTm());
775 st.wYear = (WXWORD)tm.year;
776 st.wMonth = (WXWORD)(tm.mon - wxDateTime::Jan + 1);
778 st.wDayOfWeek = st.wMinute = st.wSecond = st.wMilliseconds = 0;
780 len = ::GetDateFormat(LOCALE_USER_DEFAULT,
787 len = ::GetDateFormat(LOCALE_USER_DEFAULT,
791 wxStringBuffer(s, len),
794 s +=
wxT(
" ") + dt.FormatTime();
801wxPrintf(
wxT(
"%s\n"), dt.Format());
802 return Verbatim( dt.FormatDate() +
wxT(
" ") + dt.FormatTime() );
806 wxWindow *wParent,
const int iID,
818 bool bAutoSave =
gPrefs->
ReadBool(
"/TimerRecord/AutoSave",
false);
819 bool bAutoExport =
gPrefs->
ReadBool(
"/TimerRecord/AutoExport",
false);
820 int iPostTimerRecordAction =
gPrefs->
ReadLong(
"/TimerRecord/PostAction", 0);
825 auto strFormat =
XO(
"099 h 060 m 060 s");
827 auto strFormat1 =
XO(
"099 days 024 h 060 m 060 s");
829 S.StartMultiColumn(2, wxCENTER);
831 S.StartVerticalLay(
true);
839 S.StartStatic(
XO(
"Start Date and Time"),
true);
842 safenew wxDatePickerCtrl(
S.GetParent(),
847#if wxUSE_ACCESSIBILITY
850 S.Name(
XO(
"Start Date"))
858 .CustomFormat(strFormat)
860 S.Name(
XO(
"Start Time"))
865 S.StartStatic(
XO(
"End Date and Time"),
true);
868 safenew wxDatePickerCtrl(
S.GetParent(),
876#if wxUSE_ACCESSIBILITY
879 S.Name(
XO(
"End Date"))
887 .CustomFormat(strFormat)
889 S.Name(
XO(
"End Time"))
894 S.StartStatic(
XO(
"Duration"),
true);
901 .CustomFormat(strFormat1)
911 S.Name(
XO(
"Duration"))
918 S.StartVerticalLay(
true);
920 S.StartStatic(
XO(
"Automatic Save"),
true);
925 S.StartMultiColumn(3, wxEXPAND);
929 if (!sSaveValue.empty()) {
931 sInitialValue =
XO(
"Current Project");
933 S.AddPrompt(
XXO(
"Save Project As:"));
936 XO(
"Save Project As:"), sInitialValue);
945 S.StartStatic(
XO(
"Automatic Export"),
true);
948 S.StartMultiColumn(3, wxEXPAND);
950 S.AddPrompt(
XXO(
"Export Project As:"));
953 XO(
"Export Project As:"), {});
963 S.StartStatic(
XO(
"Options"),
true);
966 S.StartMultiColumn(1, wxEXPAND);
968 S.SetStretchyCol( 0 );
972 XO(
"Exit Audacity") ,
974 XO(
"Restart system") ,
975 XO(
"Shutdown system") ,
978 iPostTimerRecordAction
995 SetMinSize(GetSize());
1011 hr = (long)(dTime / 3600.0);
1012 min = (long)((dTime - (hr * 3600.0)) / 60.0);
1013 sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
1020 hr = (long)(dTime / 3600.0);
1021 min = (long)((dTime - (hr * 3600.0)) / 60.0);
1022 sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
1039 gPrefs->
Write(
"/TimerRecord/PostAction", iPostRecordAction);
1079 XO(
"Waiting to start recording at:") ,
1080 XO(
"Recording duration:") ,
1081 XO(
"Scheduled to stop at:") ,
1083 XO(
"Automatic Save enabled:") ,
1084 XO(
"Automatic Export enabled:") ,
1085 XO(
"Action after Timer Recording:") ,
1098 wxDateTime startWait_DateTime = wxDateTime::UNow();
1101 XO(
"Audacity Timer Record - Waiting for Start"),
1106 XO(
"Recording will commence in:"));
1109 bool bIsRecording =
false;
1113 using namespace std::chrono;
1117 return updateResult;
1123 ->GetString(iActionIndex) );
1128 auto sCountdownLabel =
XO(
"%s in:").Format( sAction );
1133 XO(
"Timer Recording completed.") ,
1135 XO(
"Recording Saved:") ,
1136 XO(
"Recording Exported:") ,
1137 XO(
"Action after Timer Recording:") ,
1149 wxDateTime dtNow = wxDateTime::UNow();
1150 wxTimeSpan tsWait = wxTimeSpan(0, 1, 0, 0);
1151 wxDateTime dtActionTime = dtNow.Add(tsWait);
1154 XO(
"Audacity Timer Record - Waiting"),
1160 bool bIsTime =
false;
1164 using namespace std::chrono;
1166 bIsTime = (dtActionTime <= wxDateTime::UNow());
1168 return iUpdateResult;
1195"Timer Recording cannot be used with more than one open project.\n\nPlease close any additional projects and try again."),
1196 XO(
"Timer Recording"),
1197 wxICON_INFORMATION | wxOK);
1205 if ((undoManager.UnsavedChanges()) &&
1209"Timer Recording cannot be used while you have unsaved changes.\n\nPlease save or close this project and try again."),
1210 XO(
"Timer Recording"),
1211 wxICON_INFORMATION | wxOK);
1221 const bool anySelected{ selectedTracks.anySelected };
1222 const bool allSameRate{ selectedTracks.allSameRate };
1226 "for recording must all have the same sampling rate"),
1227 XO(
"Mismatched Sampling Rates"),
1228 wxICON_ERROR | wxCENTRE);
1234 const auto existingTracks =
1237 if (existingTracks.empty()) {
1238 if (anySelected && rateOfSelected !=
1241 "Too few tracks are selected for recording at this sample rate.\n"
1242 "(Audacity requires two channels at the same sample rate for\n"
1243 "each stereo track)"),
1244 XO(
"Too Few Compatible Tracks Selected"),
1245 wxICON_ERROR | wxCENTRE);
1260 &window,
project, bProjectSaved);
1261 int modalResult = dialog.ShowModal();
1262 if (modalResult == wxID_CANCEL)
1272 bool bPreferNewTrack;
1273 gPrefs->
Read(
"/GUI/PreferNewTrackRecord",&bPreferNewTrack,
false);
1274 if (bPreferNewTrack) {
1275 window.Rewind(
false);
1277 window.SkipEnd(
false);
1282 switch (iTimerRecordingOutcome) {
1300 wxTheApp->CallAfter( []{
1302 wxCommandEvent evt{ wxEVT_MENU, wxID_EXIT };
1303 wxTheApp->AddPendingEvent( evt );
1309 case POST_TIMER_RECORD_RESTART:
1312 system(
"shutdown /r /f /t 30");
1314 case POST_TIMER_RECORD_SHUTDOWN:
1317 system(
"shutdown /s /f /t 30");
1330 {
wxT(
"Transport/Basic/Record"),
1331 { OrderingHint::After,
wxT(
"Record2ndChoice") } }
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
const ReservedCommandFlag & AudioIONotBusyFlag()
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
void ShowExportErrorDialog(const TranslatableString &message, const TranslatableString &caption, bool allowReporting)
XXO("&Cut/Copy/Paste Toolbar")
const NumericConverterType & NumericConverterType_TIME()
audacity::BasicSettings * gPrefs
const ReservedCommandFlag & CanStopAudioStreamFlag()
PropertiesOfSelected GetPropertiesOfSelected(const AudacityProject &proj)
an object holding per-project preferred sample rate
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 ...
accessors for certain important windows associated with each project
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
const int kSlowTimerInterval
@ ID_AUTOEXPORTPATH_BUTTON
constexpr auto kTimerInterval
static double wxDateTime_to_AudacityTime(wxDateTime &dateTime)
@ POST_TIMER_RECORD_CLOSE
@ POST_TIMER_RECORD_CANCEL
@ POST_TIMER_RECORD_CANCEL_WAIT
@ POST_TIMER_RECORD_NOTHING
TimerRecordCompletedActions
declares abstract base class Track, TrackList, and iterators over TrackList
static Settings & settings()
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Wrap wxMessageDialog so that caption IS translatable.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
std::tuple< ExportPlugin *, int > FindFormat(const wxString &format, bool compareWithCase=false) const
Returns first pair of [exportPlugin, formatIndex], such that: exportPlugin->GetFormatInfo(formatIndex...
static ExportPluginRegistry & Get()
ExportTaskBuilder & SetPlugin(const ExportPlugin *plugin, int format=0) noexcept
ExportTaskBuilder & SetParameters(ExportProcessor::Parameters parameters) noexcept
ExportTaskBuilder & SetNumChannels(unsigned numChannels) noexcept
ExportTaskBuilder & SetSampleRate(double sampleRate) noexcept
ExportTaskBuilder & SetFileName(const wxFileName &filename)
ExportTaskBuilder & SetRange(double t0, double t1, bool selectedOnly=false) noexcept
static TrackIterRange< const WaveTrack > FindExportWaveTracks(const TrackList &tracks, bool selectedOnly)
FILES_API const FileType AudacityProjects
static FormatterContext EmptyContext()
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
void SetValue(double newValue)
std::vector< MessageColumn > MessageTable
void Stop(bool stopStream=true)
static WritableSampleTrackArray ChooseExistingRecordingTracks(AudacityProject &proj, bool selectedOnly, double targetRate=RATE_NOT_SELECTED)
static ProjectAudioManager & Get(AudacityProject &project)
void SetTimerRecordCancelled()
void OnRecord(bool altAppearance)
static ProjectFileIO & Get(AudacityProject &project)
const FilePath & GetFileName() const
static ProjectFileManager & Get(AudacityProject &project)
static ProjectHistory & Get(AudacityProject &project)
static ProjectManager & Get(AudacityProject &project)
void SetSkipSavePrompt(bool bSkip)
static ProjectRate & Get(AudacityProject &project)
static ProjectSettings & Get(AudacityProject &project)
Generates classes whose instances register items at construction.
bool Write(const T &value)
Write value to config and return true if successful.
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined */
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Specialization of Setting for strings.
ProgressResult UpdateProgress()
Dialog for Timer Record, i.e., timed or long recording.
void OnAutoSaveCheckBox_Change(wxCommandEvent &event)
wxDatePickerCtrl * m_pDatePickerCtrl_Start
NumericTextCtrl * m_pTimeTextCtrl_Duration
wxDateTime m_DateTime_End
void OnHelpButtonClick(wxCommandEvent &event)
void OnTimeText_Duration(wxCommandEvent &event)
NumericTextCtrl * m_pTimeTextCtrl_End
AudacityProject & mProject
wxString m_sAutoExportFormat
TranslatableString GetDisplayDate(wxDateTime &dt)
wxButton * m_pTimerSavePathButtonCtrl
void EnableDisableAutoControls(bool bEnable, int iControlGoup)
wxCheckBox * m_pTimerAutoSaveCheckBoxCtrl
int ExecutePostRecordActions(bool bWasStopped)
void OnOK(wxCommandEvent &event)
void PopulateOrExchange(ShuttleGui &S)
NumericTextCtrl * m_pTimeTextCtrl_Start
wxTextCtrlWrapper * m_pTimerExportPathTextCtrl
int m_iAutoExportSampleRate
wxDateTime m_DateTime_Start
bool m_bAutoExportEnabled
void OnAutoExportPathButton_Click(wxCommandEvent &event)
bool m_bProjectAlreadySaved
void OnAutoExportCheckBox_Change(wxCommandEvent &event)
void UpdateTextBoxControls()
bool TransferDataFromWindow() override
wxChoice * m_pTimerAfterCompleteChoiceCtrl
wxFileName m_fnAutoSaveFile
void OnDatePicker_End(wxDateEvent &event)
ProgressResult WaitForStart()
wxTextCtrlWrapper * NewPathControl(wxWindow *wParent, const int iID, const TranslatableString &sCaption, const TranslatableString &sValue)
wxCheckBox * m_pTimerAutoExportCheckBoxCtrl
wxFileName m_fnAutoExportFile
void OnTimeText_Start(wxCommandEvent &event)
wxTimeSpan m_TimeSpan_Duration
wxDatePickerCtrl * m_pDatePickerCtrl_End
void OnAutoSavePathButton_Click(wxCommandEvent &event)
wxTextCtrlWrapper * m_pTimerSavePathTextCtrl
ExportProcessor::Parameters m_AutoExportParameters
void OnTimeText_End(wxCommandEvent &event)
wxButton * m_pTimerExportPathButtonCtrl
void OnTimer(wxTimerEvent &event)
int RunWaitDialog()
Runs the wait for start dialog. Returns false if the user clicks stop.
void OnDatePicker_Start(wxDateEvent &event)
int m_iAutoExportChannels
ProgressResult PreActionDelay(int iActionIndex, TimerRecordCompletedActions eCompletedActions)
void Bind(wxFileName &filename, wxString &format, int &sampleRate, int &channels, ExportProcessor::Parameters ¶mters)
static TrackList & Get(AudacityProject &project)
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
static UndoManager & Get(AudacityProject &project)
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
virtual bool Flush() noexcept=0
virtual bool Write(const wxString &key, bool value)=0
long ReadLong(const wxString &key, long defaultValue) const
bool ReadBool(const wxString &key, bool defaultValue) const
virtual bool Read(const wxString &key, bool *value) const =0
void SetReadOnly(bool readonly=true)
std::unique_ptr< WindowPlacement > FindFocus()
Find the window that is accepting keyboard input, if any.
ExportResult Show(ExportTask exportTask)
void ExceptionWrappedCall(Callable callable)
FILES_API FilePath FindDefaultPath(Operation op)
double GetRate(const Track &track)
void OnTimerRecord(const CommandContext &context)
StringSetting DefaultExportAudioPath
StringSetting DefaultExportAudioFormat