Audacity 3.2.0
BatchCommands.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 MacroCommands.cpp
6
7 Dominic Mazzoni
8 James Crook
9
10********************************************************************//*******************************************************************/
17
18#define wxLOG_COMPONENT "MacroCommands"
19
20
21#include "BatchCommands.h"
22
23#include <wx/defs.h>
24#include <wx/datetime.h>
25#include <wx/dir.h>
26#include <wx/log.h>
27#include <wx/textfile.h>
28#include <wx/time.h>
29
30#include "Project.h"
31#include "ProjectHistory.h"
32#include "ProjectSettings.h"
33#include "ProjectWindow.h"
36#include "effects/EffectUI.h"
37#include "FileNames.h"
38#include "Menus.h"
39#include "PluginManager.h"
40#include "Prefs.h"
41#include "SelectFile.h"
42#include "SelectUtilities.h"
43#include "SettingsVisitor.h"
44#include "Track.h"
45#include "UndoManager.h"
46
47#include "AllThemeResources.h"
48
49#include "AudacityMessageBox.h"
50
53
55: mProject{ project }
56{
57 ResetMacro();
58
59 auto names = GetNames();
60 auto defaults = GetNamesOfDefaultMacros();
61
62 for( size_t i = 0;i<defaults.size();i++){
63 wxString name = defaults[i];
64 if ( ! make_iterator_range( names ).contains(name) ) {
68 }
69 }
70}
71
72static const auto MP3Conversion = XO("MP3 Conversion");
73static const auto FadeEnds = XO("Fade Ends");
74
76{
77 return {
78 MP3Conversion.Translation() ,
79 FadeEnds.Translation() ,
80 };
81}
82
83void MacroCommands::RestoreMacro(const wxString & name)
84{
85// TIDY-ME: Effects change their name with localisation.
86// Commands (at least currently) don't. Messy.
87 ResetMacro();
88 if (name == MP3Conversion.Translation() ){
89 AddToMacro( wxT("Normalize") );
90 AddToMacro( wxT("ExportMP3") );
91 } else if (name == FadeEnds.Translation() ){
92 AddToMacro( wxT("Select"), wxT("Start=\"0\" End=\"1\"") );
93 AddToMacro( wxT("FadeIn") );
94 AddToMacro( wxT("Select"), wxT("Start=\"0\" End=\"1\" RelativeTo=\"ProjectEnd\"") );
95 AddToMacro( wxT("FadeOut") );
96 AddToMacro( wxT("Select"), wxT("Start=\"0\" End=\"0\"") );
97 }
98}
99
101{
102 if (index < 0 || index >= (int)mCommandMacro.size()) {
103 return wxT("");
104 }
105
106 return mCommandMacro[index];
107}
108
109wxString MacroCommands::GetParams(int index)
110{
111 if (index < 0 || index >= (int)mParamsMacro.size()) {
112 return wxT("");
113 }
114
115 return mParamsMacro[index];
116}
117
119{
120 return (int)mCommandMacro.size();
121}
122
123wxString MacroCommands::ReadMacro(const wxString & macro, wxWindow *parent)
124{
125 // Clear any previous macro
126 ResetMacro();
127
128 // Build the filename
129 wxFileName name(FileNames::MacroDir(), macro, wxT("txt"));
130
131 // But, ask the user for the real name if we're importing
132 if (parent) {
133 FilePath fn = SelectFile(FileNames::Operation::_None,
134 XO("Import Macro"),
135 wxEmptyString,
136 name.GetName(),
137 wxT("txt"),
139 wxFD_OPEN | wxRESIZE_BORDER,
140 parent);
141
142 // User canceled...
143 if (fn.empty()) {
144 return wxEmptyString;
145 }
146
147 wxFileName check(fn);
148 check.SetPath(name.GetPath());
149 if (check.FileExists())
150 {
151 int id = AudacityMessageBox(
152 XO("Macro %s already exists. Would you like to replace it?").Format(check.GetName()),
153 XO("Import Macro"),
154 wxYES_NO);
155 if (id == wxNO) {
156 return wxEmptyString;
157 }
158 }
159
160 name.Assign(fn);
161 }
162
163 // Set the file name
164 wxTextFile tf(name.GetFullPath());
165
166 // Open and check
167 tf.Open();
168 if (!tf.IsOpened()) {
169 // wxTextFile will display any errors
170 return wxEmptyString;
171 }
172
173 // Load commands from the file
174 int lines = tf.GetLineCount();
175 if (lines > 0) {
176 for (int i = 0; i < lines; i++) {
177
178 // Find the command name terminator...ignore line if not found
179 int splitAt = tf[i].Find(wxT(':'));
180 if (splitAt < 0) {
181 continue;
182 }
183
184 // Parse and clean
185 wxString cmd = tf[i].Left(splitAt).Strip(wxString::both);
186 wxString parm = tf[i].Mid(splitAt + 1).Strip(wxString::trailing);
187
188 // Add to lists
189 mCommandMacro.push_back(cmd);
190 mParamsMacro.push_back(parm);
191 }
192 }
193
194 // Done with the file
195 tf.Close();
196
197 // Write to macro directory if importing
198 if (parent) {
199 return WriteMacro(name.GetName());
200 }
201
202 return name.GetName();
203}
204
205wxString MacroCommands::WriteMacro(const wxString & macro, wxWindow *parent)
206{
207 // Build the default filename
208 wxFileName name(FileNames::MacroDir(), macro, wxT("txt"));
209
210 // But, ask the user for the real name if we're exporting
211 if (parent) {
212 FilePath fn = SelectFile(FileNames::Operation::_None,
213 XO("Export Macro"),
214 wxEmptyString,
215 name.GetName(),
216 wxT("txt"),
218 wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
219 parent);
220
221 // User canceled...
222 if (fn.empty()) {
223 return wxEmptyString;
224 }
225
226 name.Assign(fn);
227 }
228
229 // Set the file name
230 wxTextFile tf(name.GetFullPath());
231
232 // Create the file (Create() doesn't leave the file open)
233 if (!tf.Exists()) {
234 tf.Create();
235 }
236
237 // Open it
238 tf.Open();
239
240 if (!tf.IsOpened()) {
241 // wxTextFile will display any errors
242 return wxEmptyString;
243 }
244
245 // Start with a clean slate
246 tf.Clear();
247
248 // Copy over the commands
249 int lines = mCommandMacro.size();
250 for (int i = 0; i < lines; i++) {
251 // using GET to serialize macro definition to a text file
252 tf.AddLine(mCommandMacro[i].GET() + wxT(":") + mParamsMacro[ i ]);
253 }
254
255 // Write the macro
256 tf.Write();
257
258 // Done with the file
259 tf.Close();
260
261 return name.GetName();
262}
263
264bool MacroCommands::AddMacro(const wxString & macro)
265{
266 // Build the filename
267 wxFileName name(FileNames::MacroDir(), macro, wxT("txt"));
268
269 // Set the file name
270 wxTextFile tf(name.GetFullPath());
271
272 // Create it..Create will display errors
273 return tf.Create();
274}
275
276bool MacroCommands::DeleteMacro(const wxString & macro)
277{
278 // Build the filename
279 wxFileName name(FileNames::MacroDir(), macro, wxT("txt"));
280
281 // Delete it...wxRemoveFile will display errors
282 auto result = wxRemoveFile(name.GetFullPath());
283
284 // Delete any legacy chain that it shadowed
285 auto oldPath = wxFileName{ FileNames::LegacyChainDir(), macro, wxT("txt") };
286 wxRemoveFile(oldPath.GetFullPath()); // Don't care about this return value
287
288 return result;
289}
290
291bool MacroCommands::RenameMacro(const wxString & oldmacro, const wxString & newmacro)
292{
293 // Build the filenames
294 wxFileName oname(FileNames::MacroDir(), oldmacro, wxT("txt"));
295 wxFileName nname(FileNames::MacroDir(), newmacro, wxT("txt"));
296
297 // Rename it...wxRenameFile will display errors
298 return wxRenameFile(oname.GetFullPath(), nname.GetFullPath());
299}
300
301// Gets all commands that are valid for this mode.
303{
304 if (!project)
305 return;
306
307 Entries commands;
308
311 {
312 for (auto &plug
314 auto command = em.GetCommandIdentifier(plug.GetID());
315 if (!command.empty())
316 commands.push_back( {
317 { command, plug.GetSymbol().Msgid() },
318 plug.GetPluginType() == PluginTypeEffect ?
319 XO("Effect") : XO("Menu Command (With Parameters)")
320 } );
321 }
322 }
323
325 TranslatableStrings mLabels;
326 CommandIDs mNames;
327 std::vector<bool> vExcludeFromMacros;
328 mLabels.clear();
329 mNames.clear();
330 manager.GetAllCommandLabels(mLabels, vExcludeFromMacros, true);
331 manager.GetAllCommandNames(mNames, true);
332
333 const bool english = wxGetLocale()->GetCanonicalName().StartsWith(wxT("en"));
334
335 for(size_t i=0; i<mNames.size(); i++) {
336 if( !vExcludeFromMacros[i] ){
337 auto label = mLabels[i];
338 label.Strip();
339 bool suffix;
340 if (!english)
341 suffix = false;
342 else {
343 // We'll disambiguate if the squashed name is short and shorter than the internal name.
344 // Otherwise not.
345 // This means we won't have repetitive items like "Cut (Cut)"
346 // But we will show important disambiguation like "All (SelectAll)" and "By Date (SortByDate)"
347 // Disambiguation is no longer essential as the details box will show it.
348 // PRL: I think this reasoning applies only when locale is English.
349 // For other locales, show the (CamelCaseCodeName) always. Or, never?
350 wxString squashed = label.Translation();
351 squashed.Replace( " ", "" );
352
353 // uh oh, using GET for dubious comparison of (lengths of)
354 // user-visible name and internal CommandID!
355 // and doing this only for English locale!
356 suffix = squashed.length() < wxMin( 18, mNames[i].GET().length());
357 }
358
359 if( suffix )
360 // uh oh, using GET to expose CommandID to the user, as a
361 // disambiguating suffix on a name, but this is only ever done if
362 // the locale is English!
363 // PRL: In case this logic does get fixed for other locales,
364 // localize even this punctuation format. I'm told Chinese actually
365 // prefers slightly different parenthesis characters
366 label.Join( XO("(%s)").Format( mNames[i].GET() ), wxT(" ") );
367
368 // Bug 2294. The Close command pulls the rug out from under
369 // batch processing, because it destroys the project.
370 // So it is UNSAFE for scripting, and therefore excluded from
371 // the catalog.
372 if (mNames[i] == "Close")
373 continue;
374
375 commands.push_back(
376 {
377 {
378 mNames[i], // Internal name.
379 label // User readable name
380 },
381 XO("Menu Command (No Parameters)")
382 }
383 );
384 }
385 }
386
387 // Sort commands by their user-visible names.
388 // PRL: What exactly should happen if first members of pairs are not unique?
389 // I'm not sure, but at least I can sort stably for a better defined result.
390 auto less =
391 [](const Entry &a, const Entry &b)
392 { return a.name.StrippedTranslation() <
393 b.name.StrippedTranslation(); };
394 std::stable_sort(commands.begin(), commands.end(), less);
395
396 // Now uniquify by friendly name
397 auto equal =
398 [](const Entry &a, const Entry &b)
399 { return a.name.StrippedTranslation() ==
400 b.name.StrippedTranslation(); };
401 std::unique_copy(
402 commands.begin(), commands.end(), std::back_inserter(mCommands), equal);
403}
404
405// binary search
407 -> Entries::const_iterator
408{
409 const auto less = [](const Entry &entryA, const Entry &entryB)
410 { return entryA.name.StrippedTranslation() <
411 entryB.name.StrippedTranslation(); };
412 auto range = std::equal_range(
413 begin(), end(), Entry{ { {}, friendlyName }, {} }, less
414 );
415 if (range.first != range.second) {
416 wxASSERT_MSG( range.first + 1 == range.second,
417 "Non-unique user-visible command name" );
418 return range.first;
419 }
420 else
421 return end();
422}
423
424// linear search
425auto MacroCommandsCatalog::ByCommandId( const CommandID &commandId ) const
426 -> Entries::const_iterator
427{
428 // Maybe this too should have a uniqueness check?
429 return std::find_if( begin(), end(),
430 [&](const Entry &entry)
431 { return entry.name.Internal() == commandId; });
432}
433
435{
436 const PluginID & ID =
438 if (ID.empty())
439 {
440 return wxEmptyString; // effect not found.
441 }
442
444}
445
447 const CommandID & command, const wxString & params, wxWindow &parent)
448{
449 const PluginID & ID =
451 if (ID.empty())
452 return wxEmptyString; // effect not found
453
454 wxString res = params;
455 auto cleanup = EffectManager::Get().SetBatchProcessing(ID);
456 if (EffectManager::Get().SetEffectParameters(ID, params))
457 if (EffectManager::Get().PromptUser(ID, EffectUI::DialogFactory, parent))
459 return res;
460}
461
462wxString MacroCommands::PromptForPresetFor(const CommandID & command, const wxString & params, wxWindow *parent)
463{
464 const PluginID & ID =
466 if (ID.empty())
467 {
468 return wxEmptyString; // effect not found.
469 }
470
471 wxString preset = EffectManager::Get().GetPreset(ID, params, parent);
472
473 // Preset will be empty if the user cancelled the dialog, so return the original
474 // parameter value.
475 if (preset.empty())
476 {
477 return params;
478 }
479
480 return preset;
481}
482
484 const PluginID & ID, const TranslatableString &friendlyCommand,
485 const CommandID & command, const wxString & params,
486 const CommandContext & Context)
487{
488 static_cast<void>(command);//compiler food.
489
490 //Possibly end processing here, if in batch-debug
491 if( ReportAndSkip(friendlyCommand, params))
492 return true;
493
495 if (!plug)
496 return false;
497
499
500 // IF nothing selected, THEN select everything depending
501 // on preferences setting.
502 // (most effects require that you have something selected).
504 {
506 {
508 // i18n-hint: %s will be replaced by the name of an action, such as "Remove Tracks".
509 XO("\"%s\" requires one or more tracks to be selected.").Format(friendlyCommand));
510 return false;
511 }
512 }
513
514 bool res = false;
515
516 auto cleanup = EffectManager::Get().SetBatchProcessing(ID);
517
518 // transfer the parameters to the effect...
519 if (EffectManager::Get().SetEffectParameters(ID, params))
520 {
522 // and apply the effect...
524 Context,
528 else
529 // and apply the effect...
530 res = EffectUI::DoEffect(ID,
531 Context,
535 }
536
537 return res;
538}
539
541 const CommandID & command, const wxString & params,
542 CommandContext const * pContext)
543{
544 // Test for an effect.
545 const PluginID & ID =
547 if (!ID.empty())
548 {
549 if( pContext )
550 return ApplyEffectCommand(
551 ID, friendlyCommand, command, params, *pContext);
552 const CommandContext context( mProject );
553 return ApplyEffectCommand(
554 ID, friendlyCommand, command, params, context);
555 }
556
559 if( pContext ){
561 manager, command, *pContext, AlwaysEnabledFlag, true ) )
562 return true;
563 pContext->Status( wxString::Format(
564 _("Your batch command of %s was not recognized."), friendlyCommand.Translation() ));
565 return false;
566 }
567 else
568 {
569 const CommandContext context( mProject );
571 manager, command, context, AlwaysEnabledFlag, true ) )
572 return true;
573 }
574
576 XO("Your batch command of %s was not recognized.")
577 .Format( friendlyCommand ) );
578
579 return false;
580}
581
583 const TranslatableString &friendlyCommand,
584 const CommandID & command, const wxString &params,
585 CommandContext const * pContext)
586{
589 // Recalc flags and enable items that may have become enabled.
590 MenuManager::Get(*project).UpdateMenus(false);
591 // enter batch mode...
592 project->mBatchMode++;
593 auto cleanup = finally( [&] {
594 // exit batch mode...
595 project->mBatchMode--;
596 } );
597
598 return ApplyCommand( friendlyCommand, command, params, pContext );
599}
600
601static int MacroReentryCount = 0;
602// ApplyMacro returns true on success, false otherwise.
603// Any error reporting to the user in setting up the macro
604// has already been done.
606 const MacroCommandsCatalog &catalog, const wxString & filename)
607{
608 // Check for reentrant ApplyMacro commands.
609 // We'll allow 1 level of reentry, but not more.
610 // And we treat ignoring deeper levels as a success.
611 if (MacroReentryCount > 1) {
612 return true;
613 }
614
615 // Restore the reentry counter (to zero) when we exit.
616 auto cleanup1 = valueRestorer(MacroReentryCount);
618
619 AudacityProject *proj = &mProject;
620 bool res = false;
621
622 // Only perform this group on initial entry. They should not be done
623 // while recursing.
624 if (MacroReentryCount == 1) {
625 mFileName = filename;
626
627 TranslatableString longDesc, shortDesc;
628 wxString name = gPrefs->Read(wxT("/Batch/ActiveMacro"), wxEmptyString);
629 if (name.empty()) {
630 /* i18n-hint: active verb in past tense */
631 longDesc = XO("Applied Macro");
632 shortDesc = XO("Apply Macro");
633 }
634 else {
635 /* i18n-hint: active verb in past tense */
636 longDesc = XO("Applied Macro '%s'").Format(name);
637 shortDesc = XO("Apply '%s'").Format(name);
638 }
639
640 // Save the project state before making any changes. It will be rolled
641 // back if an error occurs.
642 // It also causes any calls to ModifyState (such as by simple
643 // view-changing commands) to append changes to this state, not to the
644 // previous state in history. See Bug 2076
645 if (proj) {
646 ProjectHistory::Get(*proj).PushState(longDesc, shortDesc);
647 }
648 }
649
650 // Upon exit of the top level apply, roll back the state if an error occurs.
651 auto cleanup2 = finally([&, macroReentryCount = MacroReentryCount] {
652 if (macroReentryCount == 1 && !res && proj) {
653 // Be sure that exceptions do not escape this destructor
654 GuardedCall([&]{
655 // Macro failed or was cancelled; revert to the previous state
656 auto &history = ProjectHistory::Get(*proj);
657 history.RollbackState();
658 // The added undo state is now vacuous. Remove it (Bug 2759)
659 auto &undoManager = UndoManager::Get(*proj);
660 undoManager.Undo(
661 [&]( const UndoStackElem &elem ){
662 history.PopState( elem.state ); } );
663 undoManager.AbandonRedo();
664 });
665 }
666 });
667
668 mAbort = false;
669
670 // Is tracing enabled?
671 bool trace;
672 gPrefs->Read(wxT("/EnableMacroTracing"), &trace, false);
673
674 // If so, then block most other messages while running the macro
675 wxLogLevel prevLevel = wxLog::GetComponentLevel("");
676 if (trace) {
677 wxLog::SetComponentLevel("", wxLOG_FatalError);
678 wxLog::SetComponentLevel(wxLOG_COMPONENT, wxLOG_Info);
679 }
680
681 size_t i = 0;
682 for (; i < mCommandMacro.size(); i++) {
683 const auto &command = mCommandMacro[i];
684 auto iter = catalog.ByCommandId(command);
685 const auto friendly = (iter == catalog.end())
686 ?
687 // uh oh, using GET to expose an internal name to the user!
688 // in default of any better friendly name
689 Verbatim( command.GET() )
690 : iter->name.Msgid().Stripped();
691
692 wxTimeSpan before;
693 if (trace) {
694 before = wxTimeSpan(0, 0, 0, wxGetUTCTimeMillis());
695 }
696
697 bool success = ApplyCommandInBatchMode(friendly, command, mParamsMacro[i]);
698
699 if (trace) {
700 auto after = wxTimeSpan(0, 0, 0, wxGetUTCTimeMillis());
701 wxLogMessage(wxT("Macro line #%ld took %s : %s:%s"),
702 i + 1,
703 (after - before).Format(wxT("%H:%M:%S.%l")),
704 command.GET(),
705 mParamsMacro[i]);
706 }
707
708 if (!success || mAbort)
709 break;
710 }
711
712 // Restore message level
713 if (trace) {
714 wxLog::SetComponentLevel("", prevLevel);
715 }
716
717 res = (i == mCommandMacro.size());
718 if (!res)
719 return false;
720
721 if (MacroReentryCount == 1) {
722 mFileName.Empty();
723
724 if (proj)
725 ProjectHistory::Get(*proj).ModifyState(true);
726 }
727
728 return true;
729}
730
731// AbortBatch() allows a premature terminatation of a batch.
733{
734 mAbort = true;
735}
736
737void MacroCommands::AddToMacro(const CommandID &command, int before)
738{
739 AddToMacro(command, GetCurrentParamsFor(command), before);
740}
741
742void MacroCommands::AddToMacro(const CommandID &command, const wxString &params, int before)
743{
744 if (before == -1) {
745 before = (int)mCommandMacro.size();
746 }
747
748 mCommandMacro.insert(mCommandMacro.begin() + before, command);
749 mParamsMacro.insert(mParamsMacro.begin() + before, params);
750}
751
753{
754 if (index < 0 || index >= (int)mCommandMacro.size()) {
755 return;
756 }
757
758 mCommandMacro.erase( mCommandMacro.begin() + index );
759 mParamsMacro.erase( mParamsMacro.begin() + index );
760}
761
763{
764 mCommandMacro.clear();
765 mParamsMacro.clear();
766}
767
768// ReportAndSkip() is a diagnostic function that avoids actually
769// applying the requested effect if in batch-debug mode.
771 const TranslatableString & friendlyCommand, const wxString & params)
772{
773 int bDebug;
774 gPrefs->Read(wxT("/Batch/Debug"), &bDebug, 0);
775 if( bDebug == 0 )
776 return false;
777
778 //TODO: Add a cancel button to these, and add the logic so that we can abort.
779 if( !params.empty() )
780 {
782 XO("Apply %s with parameter(s)\n\n%s")
783 .Format( friendlyCommand, params ),
784 XO("Test Mode"));
785 }
786 else
787 {
789 XO("Apply %s").Format( friendlyCommand ),
790 XO("Test Mode"));
791 }
792 return true;
793}
794
796{
797 static bool done = false;
798 if (!done) {
799 // Check once per session at most
800
801 // Copy chain files from the old Chains into the new Macros directory,
802 // but only if like-named files are not already present in Macros.
803
804 // Leave the old copies in place, in case a user wants to go back to
805 // an old Audacity version. They will have their old chains intact, but
806 // won't have any edits they made to the copy that now lives in Macros
807 // which old Audacity will not read.
808
809 const auto oldDir = FileNames::LegacyChainDir();
810 FilePaths files;
811 wxDir::GetAllFiles(oldDir, &files, wxT("*.txt"), wxDIR_FILES);
812
813 // add a dummy path component to be overwritten by SetFullName
814 wxFileName newDir{ FileNames::MacroDir(), wxT("x") };
815
816 for (const auto &file : files) {
817 auto name = wxFileName{file}.GetFullName();
818 newDir.SetFullName(name);
819 const auto newPath = newDir.GetFullPath();
820 if (!wxFileExists(newPath))
821 FileNames::DoCopyFile(file, newPath);
822 }
823 done = true;
824 }
825 // To do: use std::once
826}
827
829{
831
832 wxArrayString names;
833 FilePaths files;
834 wxDir::GetAllFiles(FileNames::MacroDir(), &files, wxT("*.txt"), wxDIR_FILES);
835 size_t i;
836
837 wxFileName ff;
838 for (i = 0; i < files.size(); i++) {
839 ff = (files[i]);
840 names.push_back(ff.GetName());
841 }
842
843 std::sort( names.begin(), names.end() );
844
845 return names;
846}
847
848bool MacroCommands::IsFixed(const wxString & name)
849{
850 auto defaults = GetNamesOfDefaultMacros();
851 if( make_iterator_range( defaults ).contains( name ) )
852 return true;
853 return false;
854}
855
856void MacroCommands::Split(const wxString & str, wxString & command, wxString & param)
857{
858 int splitAt;
859
860 command.Empty();
861 param.Empty();
862
863 if (str.empty()) {
864 return;
865 }
866
867 splitAt = str.Find(wxT(':'));
868 if (splitAt < 0) {
869 return;
870 }
871
872 command = str.Mid(0, splitAt);
873 param = str.Mid(splitAt + 1);
874
875 return;
876}
877
878wxString MacroCommands::Join(const wxString & command, const wxString & param)
879{
880 return command + wxT(": ") + param;
881}
wxT("CloseDown"))
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), F3 delayedHandler=DefaultDelayedHandlerAction) noexcept(noexcept(handler(std::declval< AudacityException * >())) &&noexcept(handler(nullptr)) &&noexcept(std::function< void(AudacityException *)>{std::move(delayedHandler)}))
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
static const auto MP3Conversion
static const auto FadeEnds
#define wxLOG_COMPONENT
static int MacroReentryCount
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:34
#define str(a)
EffectDistortionSettings params
Definition: Distortion.cpp:77
const TranslatableString name
Definition: Distortion.cpp:76
wxString PluginID
Definition: EffectManager.h:30
XO("Cut/Copy/Paste")
std::vector< CommandID > CommandIDs
Definition: Identifier.h:233
#define _(s)
Definition: Internat.h:73
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
Definition: MemoryX.h:251
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:448
@ PluginTypeAudacityCommand
@ PluginTypeEffect
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
wxString FilePath
Definition: Project.h:21
static ProjectFileIORegistry::AttributeWriterEntry entry
static const AttachedProjectObjects::RegisteredFactory manager
EffectReverbSettings preset
Definition: Reverb.cpp:44
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)
Definition: SelectFile.cpp:17
TranslatableString label
Definition: TagsEditor.cpp:165
static TranslatableStrings names
Definition: TagsEditor.cpp:153
const auto project
declares abstract base class Track, TrackList, and iterators over TrackList
static Settings & settings()
Definition: TrackInfo.cpp:83
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::vector< TranslatableString > TranslatableStrings
static const auto fn
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
virtual void Status(const wxString &message, bool bFlush=false) const
static CommandManager & Get(AudacityProject &project)
const wxString StrippedTranslation() const
EffectManager is the class that handles effects and effect categories.
Definition: EffectManager.h:48
CommandID GetCommandIdentifier(const PluginID &ID)
BatchProcessingScope SetBatchProcessing(const PluginID &ID)
Begin a scope that ends when the returned object is destroyed.
static EffectManager & Get()
wxString GetPreset(const PluginID &ID, const wxString &params, wxWindow *parent)
wxString GetEffectParameters(const PluginID &ID)
const PluginID & GetEffectByIdentifier(const CommandID &strTarget)
FILES_API const FileType TextFiles
Definition: FileNames.h:73
Abstract base class used in importing a file.
Entries::const_iterator ByCommandId(const CommandID &commandId) const
Entries::const_iterator end() const
Definition: BatchCommands.h:49
std::vector< Entry > Entries
Definition: BatchCommands.h:36
MacroCommandsCatalog(const AudacityProject *project)
Entries::const_iterator ByFriendlyName(const TranslatableString &friendlyName) const
static wxArrayStringEx GetNamesOfDefaultMacros()
static wxString PromptForPresetFor(const CommandID &command, const wxString &params, wxWindow *parent)
bool IsFixed(const wxString &name)
CommandIDs mCommandMacro
void AddToMacro(const CommandID &command, int before=-1)
bool ApplyEffectCommand(const PluginID &ID, const TranslatableString &friendlyCommand, const CommandID &command, const wxString &params, const CommandContext &Context)
wxString mFileName
bool ApplyCommand(const TranslatableString &friendlyCommand, const CommandID &command, const wxString &params, CommandContext const *pContext=NULL)
wxString GetParams(int index)
void DeleteFromMacro(int index)
wxArrayString mParamsMacro
wxString Join(const wxString &command, const wxString &param)
static wxString GetCurrentParamsFor(const CommandID &command)
static void MigrateLegacyChains()
bool RenameMacro(const wxString &oldmacro, const wxString &newmacro)
CommandID GetCommand(int index)
static wxArrayString GetNames()
bool DeleteMacro(const wxString &name)
bool ReportAndSkip(const TranslatableString &friendlyCommand, const wxString &params)
void Split(const wxString &str, wxString &command, wxString &param)
wxString WriteMacro(const wxString &macro, wxWindow *parent=nullptr)
bool ApplyMacro(const MacroCommandsCatalog &catalog, const wxString &filename={})
static wxString PromptForParamsFor(const CommandID &command, const wxString &params, wxWindow &parent)
bool AddMacro(const wxString &macro)
MacroCommands(AudacityProject &project)
wxString ReadMacro(const wxString &macro, wxWindow *parent=nullptr)
void RestoreMacro(const wxString &name)
AudacityProject & mProject
bool ApplyCommandInBatchMode(const TranslatableString &friendlyCommand, const CommandID &command, const wxString &params, CommandContext const *pContext=NULL)
static MenuManager & Get(AudacityProject &project)
Definition: Menus.cpp:69
void UpdateMenus(bool checkActive=true)
Definition: Menus.cpp:570
PluginType GetPluginType() const
PluginManager maintains a list of all plug ins. That covers modules, effects, generators,...
Definition: PluginManager.h:51
Range PluginsOfType(int type)
const PluginDescriptor * GetPlugin(const PluginID &ID) const
static PluginManager & Get()
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
static ProjectSettings & Get(AudacityProject &project)
Holds a msgid for the translation catalog; may also bind format arguments.
TranslatableString & Strip(unsigned options=MenuCodes) &
TranslatableString & Join(TranslatableString arg, const wxString &separator={}) &
Append another translatable string.
wxString Translation() const
TranslatableString Stripped(unsigned options=MenuCodes) const
non-mutating, constructs another TranslatableString object
static UndoManager & Get(AudacityProject &project)
Definition: UndoManager.cpp:71
virtual bool Read(const wxString &key, bool *value) const =0
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
AUDACITY_DLL_API bool DoAudacityCommand(const PluginID &ID, const CommandContext &context, unsigned flags)
AUDACITY_DLL_API bool HandleTextualCommand(CommandManager &commandManager, const CommandID &Str, const CommandContext &context, CommandFlag flags, bool alwaysEnabled)
AUDACITY_DLL_API bool DoEffect(const PluginID &ID, const CommandContext &context, unsigned flags)
'Repeat Last Effect'.
Definition: EffectUI.cpp:1144
AUDACITY_DLL_API DialogFactoryResults DialogFactory(wxWindow &parent, EffectBase &host, EffectUIServices &client, EffectSettingsAccess &access)
Definition: EffectUI.cpp:1105
FILES_API FilePath MacroDir()
FILES_API bool DoCopyFile(const FilePath &file1, const FilePath &file2, bool overwrite=true)
FILES_API FilePath LegacyChainDir()
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
bool SelectAllIfNoneAndAllowed(AudacityProject &project)
Definition: BatchCommands.h:32
ComponentInterfaceSymbol name
Definition: BatchCommands.h:33
Holds one item with description and time range for the UndoManager.
Definition: UndoManager.h:117
UndoState state
Definition: UndoManager.h:128