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]);
220 this->PopulateOrExchange(
S);
224 m_pTimeTextCtrl_Duration->SetFocus();
225 m_pTimeTextCtrl_Duration->SetFieldFocus(3);
235 wxDateTime dateTime_UNow = wxDateTime::UNow();
248 long hr = (long)(dTime / 3600.0);
249 long min = (long)((dTime - (hr * 3600.0)) / 60.0);
250 long sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
257 wxTimerEvent dummyTimerEvent;
258 this->
OnTimer(dummyTimerEvent);
274 long days = (long)(dTime / (24.0 * 3600.0));
276 dTime -= (double)days * 24.0 * 3600.0;
282 wxDateEvent dummyDateEvent;
290 long hr = (long)(dTime / 3600.0);
291 long min = (long)((dTime - (hr * 3600.0)) / 60.0);
292 long sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
316 long days = (long)(dTime / (24.0 * 3600.0));
318 dTime -= (double)days * 24.0 * 3600.0;
324 wxDateEvent dummyDateEvent;
331 long hr = (long)(dTime / 3600.0);
332 long min = (long)((dTime - (hr * 3600.0)) / 60.0);
333 long sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
344 wxString fName =
SelectFile(FileNames::Operation::Export,
345 XO(
"Save Timer Recording As"),
350 wxFD_SAVE | wxRESIZE_BORDER,
358 if (wxFileExists(fName) && (projectFileIO.GetFileName() != fName)) {
361 XO(
"The selected file name could not be used\nfor Timer Recording because it \
362would overwrite another project.\nPlease try again and select an original name."),
363 XO(
"Error Saving Timer Recording Project"),
389 if(exportDialog.ShowModal() != wxID_OK)
414 if (!m_TimeSpan_Duration.IsPositive())
417 XO(
"Duration is zero. Nothing will be recorded."),
418 XO(
"Error in Duration"),
419 wxICON_EXCLAMATION | wxOK);
428 XO(
"Automatic Save path is invalid."),
429 XO(
"Error in Automatic Save"),
430 wxICON_EXCLAMATION | wxOK);
437 XO(
"Automatic Export path is invalid."),
438 XO(
"Error in Automatic Export"),
439 wxICON_EXCLAMATION | wxOK);
454 int iMinsLeft = projectManager.GetEstimatedRecordingMinsLeftOnDisk();
460 if (iMinsRecording >= iMinsLeft) {
463 auto sRemainingTime = projectManager.GetHoursMinsString(iMinsLeft);
464 auto sPlannedTime = projectManager.GetHoursMinsString(iMinsRecording);
468"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")
469 .Format( sPlannedTime, sRemainingTime );
474 XO(
"Timer Recording Disk Space Warning"),
475 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
476 if (dlgMessage.ShowModal() != wxID_YES ) {
483 this->EndModal(wxID_OK);
486 gPrefs->
Write(
wxT(
"/TimerRecord/LastDuration"), duration.ToLong());
527 gAudioIO->DelayActions(
true);
529 auto cleanup =
finally([gAudioIO]{ gAudioIO->DelayActions(
false); });
540 bool bIsRecording =
true;
548 XO(
"Recording start:") ,
550 XO(
"Recording end:") ,
552 XO(
"Automatic Save enabled:") ,
553 XO(
"Automatic Export enabled:") ,
554 XO(
"Action after Timer Recording:") ,
569 XO(
"Audacity Timer Record Progress"),
575 wxTimerEvent dummyTimerEvent;
576 this->
OnTimer(dummyTimerEvent);
581 using namespace std::chrono;
610 bool bSaveOK =
false;
611 bool bExportOK =
false;
613 int iOverriddenAction = iPostRecordAction;
614 bool bErrorOverride =
false;
622 bSaveOK = projectFileManager.Save();
638 const auto t0 = std::max(.0,
tracks.GetStartTime());
640 auto [exportPlugin, formatIndex] =
643 if(exportPlugin !=
nullptr)
671 if (bErrorOverride || bWasStopped) {
678 auto sMessage = (bWasStopped ?
XO(
"Timer Recording stopped.") :
679 XO(
"Timer Recording completed."));
683 sMessage =
XO(
"%s\n\nRecording saved: %s").Format(
686 sMessage =
XO(
"%s\n\nError saving recording.").Format( sMessage );
691 sMessage =
XO(
"%s\n\nRecording exported: %s").Format(
694 sMessage =
XO(
"%s\n\nError exporting recording.").Format( sMessage );
698 if (bErrorOverride) {
700 if ((iOverriddenAction != iPostRecordAction) &&
703 sMessage =
XO(
"%s\n\n'%s' has been canceled due to the error(s) noted above.").Format(
712 wxICON_EXCLAMATION | wxOK);
716 sMessage =
XO(
"%s\n\n'%s' has been canceled as the recording was stopped.").Format(
723 XO(
"Timer Recording"),
724 wxICON_INFORMATION | wxOK);
754 return iPostRecordAction;
759#if defined(__WXMSW__)
771 const wxDateTime::Tm tm(dt.GetTm());
776 st.wYear = (WXWORD)tm.year;
777 st.wMonth = (WXWORD)(tm.mon - wxDateTime::Jan + 1);
779 st.wDayOfWeek = st.wMinute = st.wSecond = st.wMilliseconds = 0;
781 len = ::GetDateFormat(LOCALE_USER_DEFAULT,
788 len = ::GetDateFormat(LOCALE_USER_DEFAULT,
792 wxStringBuffer(s, len),
795 s +=
wxT(
" ") + dt.FormatTime();
802wxPrintf(
wxT(
"%s\n"), dt.Format());
803 return Verbatim( dt.FormatDate() +
wxT(
" ") + dt.FormatTime() );
807 wxWindow *wParent,
const int iID,
819 bool bAutoSave =
gPrefs->
ReadBool(
"/TimerRecord/AutoSave",
false);
820 bool bAutoExport =
gPrefs->
ReadBool(
"/TimerRecord/AutoExport",
false);
821 int iPostTimerRecordAction =
gPrefs->
ReadLong(
"/TimerRecord/PostAction", 0);
826 auto strFormat =
XO(
"099 h 060 m 060 s");
828 auto strFormat1 =
XO(
"099 days 024 h 060 m 060 s");
830 S.StartMultiColumn(2, wxCENTER);
832 S.StartVerticalLay(
true);
840 S.StartStatic(
XO(
"Start Date and Time"),
true);
843 safenew wxDatePickerCtrl(
S.GetParent(),
848#if wxUSE_ACCESSIBILITY
851 S.Name(
XO(
"Start Date"))
859 .CustomFormat(strFormat)
861 S.Name(
XO(
"Start Time"))
866 S.StartStatic(
XO(
"End Date and Time"),
true);
869 safenew wxDatePickerCtrl(
S.GetParent(),
877#if wxUSE_ACCESSIBILITY
880 S.Name(
XO(
"End Date"))
888 .CustomFormat(strFormat)
890 S.Name(
XO(
"End Time"))
895 S.StartStatic(
XO(
"Duration"),
true);
902 .CustomFormat(strFormat1)
912 S.Name(
XO(
"Duration"))
919 S.StartVerticalLay(
true);
921 S.StartStatic(
XO(
"Automatic Save"),
true);
926 S.StartMultiColumn(3, wxEXPAND);
930 if (!sSaveValue.empty()) {
932 sInitialValue =
XO(
"Current Project");
934 S.AddPrompt(
XXO(
"Save Project As:"));
937 XO(
"Save Project As:"), sInitialValue);
946 S.StartStatic(
XO(
"Automatic Export"),
true);
949 S.StartMultiColumn(3, wxEXPAND);
951 S.AddPrompt(
XXO(
"Export Project As:"));
954 XO(
"Export Project As:"), {});
964 S.StartStatic(
XO(
"Options"),
true);
967 S.StartMultiColumn(1, wxEXPAND);
969 S.SetStretchyCol( 0 );
973 XO(
"Exit Audacity") ,
975 XO(
"Restart system") ,
976 XO(
"Shutdown system") ,
979 iPostTimerRecordAction
996 SetMinSize(GetSize());
1012 hr = (long)(dTime / 3600.0);
1013 min = (long)((dTime - (hr * 3600.0)) / 60.0);
1014 sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
1021 hr = (long)(dTime / 3600.0);
1022 min = (long)((dTime - (hr * 3600.0)) / 60.0);
1023 sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
1040 gPrefs->
Write(
"/TimerRecord/PostAction", iPostRecordAction);
1080 XO(
"Waiting to start recording at:") ,
1081 XO(
"Recording duration:") ,
1082 XO(
"Scheduled to stop at:") ,
1084 XO(
"Automatic Save enabled:") ,
1085 XO(
"Automatic Export enabled:") ,
1086 XO(
"Action after Timer Recording:") ,
1099 wxDateTime startWait_DateTime = wxDateTime::UNow();
1102 XO(
"Audacity Timer Record - Waiting for Start"),
1107 XO(
"Recording will commence in:"));
1110 bool bIsRecording =
false;
1114 using namespace std::chrono;
1118 return updateResult;
1124 ->GetString(iActionIndex) );
1129 auto sCountdownLabel =
XO(
"%s in:").Format( sAction );
1134 XO(
"Timer Recording completed.") ,
1136 XO(
"Recording Saved:") ,
1137 XO(
"Recording Exported:") ,
1138 XO(
"Action after Timer Recording:") ,
1150 wxDateTime dtNow = wxDateTime::UNow();
1151 wxTimeSpan tsWait = wxTimeSpan(0, 1, 0, 0);
1152 wxDateTime dtActionTime = dtNow.Add(tsWait);
1155 XO(
"Audacity Timer Record - Waiting"),
1161 bool bIsTime =
false;
1165 using namespace std::chrono;
1167 bIsTime = (dtActionTime <= wxDateTime::UNow());
1169 return iUpdateResult;
1196"Timer Recording cannot be used with more than one open project.\n\nPlease close any additional projects and try again."),
1197 XO(
"Timer Recording"),
1198 wxICON_INFORMATION | wxOK);
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)
IntSetting AudioIORecordChannels
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
constexpr auto kTimerInterval
@ ID_AUTOEXPORTPATH_BUTTON
static double wxDateTime_to_AudacityTime(wxDateTime &dateTime)
TimerRecordCompletedActions
@ POST_TIMER_RECORD_CLOSE
@ POST_TIMER_RECORD_CANCEL
@ POST_TIMER_RECORD_CANCEL_WAIT
@ POST_TIMER_RECORD_NOTHING
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)
Find suitable tracks to record into, or return an empty array.
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.
IMPORT_EXPORT_API 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