Expand Audacity

Hello!

I need a tool for cutting wav-files, which will be invoked from another application. I tried to adapt Audacity.
I already followed the steps in the Simplifying Audacity thread to change the surface a little.
Now there remain some todos on my list. I think they would imply some programming, so I already downloaded the source code and compiled Audacity with Visual Studio 2008. Unfortunately I never did much on C and C++ and it has been a while since I got in touch with this language.
I would appreciate if you could give me some hints, how to solve these problems:

My Audacity should be able to open a specific file (that works for me with the command line: audacity.exe input.wav) and
[] save it automatically on program exit
[
] under a given path. (It would be nice, if I could expand the command line control, so that I could call Audacity like this: audacity.exe -input input.wav -output edited_input.wav OR audacity.exe edited_input.wav input.wav)
Further I need to call Audacity only with a path for saving a new recording (e.g. audacity.exe -record new_record.wav).

Other improvements, that aren’t that important would be:
[*] - create button for directely show a spectrogram and saving the file

So, would this be much work?
Where could I start? I actually couldn’t find the main()-function.
Which are the necessary files to look at?

I am really looking forward to your help!

Best regards,
KB

Apart from the final point (show spectrum), it would be much easier to use Sox than Audacity for your tasks. Sox is designed specifically to be run from the command line.

Look at this post which describes in detail how to modify the source to do similar things to those you require:

Thank you for that hint! With your thread I managed to open a file in Audacity by invoking it with audacity -input C:example.wav.

At the moment I am struggeling on these things:

1.) To get an edited wave file saved under a predefined path. The path should be made available for the program with the command line like this: audacity.exe -output C:outputdirectorycut_example.wav.

On program quit the wave-file should be saved automatically.
Where do I have to implement this functionality? Is it in the function “void AudacityProject::OnCloseWindow(wxCloseEvent & event)” in Project.cpp?
And how could I save/ export the project as wave-file?

2.) Where is it implemented, that Audacity normalizes an opened wave file? It would be interesting for me to add a stereo2mono-functionality as well.

Just to make my aim clearer: I don’t want to do things unattended. A wave file should be opened in Audacity for a user to edit it (cut noise from speech and do some other things).

Many thanks in advance for your help!

Q1-- obviously, add the -output switch and fully qualifiedPathfilename.wav handler/storage as I did the other switches–you will probably want to have path/filename contain no spaces due to the dificulty of parsing the command line. Next, OnCloseWindow may be the best place (but you will need to experiment). Just make sure that the Project’s data is still intact. The code to Export a file looks like:

         wxString tempName("fully qualified path and file name from switch");
         tempName.Append(wxT(".wav"));//may not be needed if you passed it in the switch
         OnExport(wxT("WAV"), tempName);

Q2-- look at this code from Project.cpp:

bool AudacityProject::Import(wxString fileName, WaveTrackArray* pTrackArray /*= NULL*/)
{
   [...]
   int mode = gPrefs->Read(wxT("/AudioFiles/NormalizeOnLoad"), 0L);
   if (mode == 1) {
      //TODO: All we want is a SelectAll()
      SelectNone();
      SelectAllIfNone();
      OnEffect(ALL_EFFECTS | CONFIGURED_EFFECT,
               EffectManager::Get().GetEffectByIdentifier(wxT("Normalize")));
   }

I think this function will be called during the CLI Import of your WAV–put a break on that "int mode = " line and see–if so just change the code by removing the “int mode” declaration, assignment & test --or just turn NormalizeOnLoad on in the CFG file via Prefs:
norm.png

Thank you very much for your help! I used your uploaded files as basic.

For the “-input” switch (opening a given file) and the “-output” switch (saving project under a given filename) I am using this code:

I inserted this code in Audacity.cpp:

         //mytry start
         if (!handled && !wxString(wxT("-input")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            wxString tempFilename(GetCLIpath());
            tempFilename.Append(wxT("\"));//must escape NEWLINE to compile
            tempFilename.Append(argv[option+1]);
            handled = true;
         }
         if (!handled && !wxString(wxT("-output")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            wxString tempFilename(GetCLIpath());
            tempFilename.Append(wxT("\"));//must escape NEWLINE to compile
            tempFilename.Append(argv[option+1]);
            mSaveAsFileName = tempFilename;
            //mSaveAsFileName = argv[option+1];
            mbSaveAsSet = true;
            handled = true;
         }
         //mytry end

         if (argv[option][0] == wxT('-') && !handled) {
            wxPrintf(_("Unknown command line option: %sn"), argv[option]);
            exit(0);
         }

         if (!handled)
         {
            if (!project)
            {
               // Create new window for project
               project = CreateNewAudacityProject();
            }
            //efm5 start
            wxString tempFN(GetCLIpath());
            tempFN.Append(wxT("\"));//must escape NEWLINE to compile
            tempFN.Append(argv[option]);
            project->OpenFile(tempFN);
            if (mbDoUnattended) {
               wxSetWorkingDirectory(GetCLIpath());
               project->UnattendedCLIAction();
            }

And in void AudacityProject::OnCloseWindow(wxCloseEvent & event) in Project.cpp I added:

   // We may not bother to prompt the user to save, if the 
   // project is now empty.
   //efm5 start
   //if (event.CanVeto() && (mEmptyCanBeDirty || bHasTracks)) {
   //   if (mUndoManager.UnsavedChanges()) {
   //      wxString Message = _("Save changes before closing?");
   //      if( !bHasTracks )
   //      { 
   //       Message += _("nIf saved, the project will have no tracks.nnTo save any previously open tracks:nCancel, Edit > Undo until all tracksnare open, then File > Save Project.");
   //      }
   //      int result = wxMessageBox( Message,
   //                                _("Save changes?"),
   //                                wxYES_NO | wxCANCEL | wxICON_QUESTION,
   //                                this);

   //      if (result == wxCANCEL || (result == wxYES && !Save())) {
   //         event.Veto();
   //         return;
   //      }
   //   }
   //}
   //efm5 end
   //mytry start
   bool bSaveFile = wxGetApp().GetSaveAsSet();
   if (bSaveFile && (!mEmptyCanBeDirty || bHasTracks))
   {
	   wxFileName tempFileName(wxGetApp().GetSaveAsFileName());
	   wxString tempName(tempFileName.GetName());
	   tempName.Append(wxT(".wav"));//may not be needed if passed in the switch
	   OnExport(wxT("WAV"), tempName);
   }
   //mytry end

But I still have a problem: if called with -input and -output my Audacity tries to open the input and the output filename.The output filename doesn’t exit yet, and and error appears.
Maybe I am too tired to see the solution. Could you give me another hint?

If the following is not enough to get you going, post the entire content of the OnInit function you are having trouble with, but…

you must force the Import() (opening) of -input using code like:
tempFilename.Append(argv[option+1]);
project->OpenFile(tempFilename);//add this line

but remember, the CLI must be CDed to the folder in which the -input file resides and you must NOT have any path info in argv[option] (or you may modify the code so it does not look in the current directory and pass a fully qualified path/filename.ext as -input. This should suppress trying to open a second (-output) file but you might need to get trick by not having a space between -output and filename then parsing the arg to get the real filename.

Note–since you have:
tempName.Append(wxT(“.wav”));//may not be needed if passed in the switch
make sure that -output is a a string which DOES NOT end in .wav (or an dot extension for that matter) this also should suppress automatic opening of the arg.

Also, remember, since this is DOS CLI stuff you do not want any spaces (or any other non-standard characters) in your paths and file names!

I think you are real close, so keep trying and don’t hesitate to ask for help!

Thank you, Edgar!
Your help keeps me going!

On more thing to clarify: my Audacity should get a full qualified path with the input and the output argument, e.g.: “C:UsersmeDesktopAudacity.exe” -input “C:UsersmeMusicinputsinput.wav” -output “C:UsersmeMusicoutputsoutput.wav”.
Do you think, that would be possible? Without having the CLI CDed to the folder in which the -input file resides, seems to work, when opening/ importing a wave-file.
Can’t I use paths with spaces if I put them into apostrophes (“”)?

I tried the whole day to get my Audacity running. But with few success.
Now it doesn’t try to open the given output-path anymore, but it doesn’t save the edited wave-file OnCloseWindow anymore, though I didn’t change anything on it at OnCloseWindow.

This is my OnInit-function now (I commented out the if (!handled) branch):

bool AudacityApp::OnInit()
{
//efm5 start new
   SetCLIpath(wxGetCwd());
   mbDoUnattended = false;
   mbDoTo4 = false;
   mbSilenceProject = false;
   mbAmplify = false;
   mbDoPrompt = false;
   mbFileNameError = false;
   mbNeedToSave = true;
   mbSaveAsSet = false; //mytry
//efm5 end new
   m_aliasMissingWarningShouldShow = true;
   m_LastMissingBlockFile = NULL;

#if defined(__WXGTK__)
   // Workaround for bug 154 -- initialize to false
   inKbdHandler = false;
#endif

#if defined(__WXMAC__)
   // Disable window animation
   wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, 1 );
#endif

//MERGE:
//Everything now uses Audacity name for preferences.
//(Audacity and CleanSpeech the same program and use
//the same preferences file).
//
// LL: Moved here from InitPreferences() to ensure VST effect
//     discovery writes configuration to the correct directory
//     on OSX with case-sensitive file systems.
#ifdef AUDACITY_NAME
   wxString appName = wxT(AUDACITY_NAME);
   wxString vendorName = wxT(AUDACITY_NAME);
#else
   wxString vendorName = wxT("Audacity");
   wxString appName = wxT("Audacity");
#endif

   wxTheApp->SetVendorName(vendorName);
   wxTheApp->SetAppName(appName);

#ifdef USE_VST // if no VST support, answer is always no
   // Have we been started to check a plugin?
   if (argc == 3 && wxStrcmp(argv[1], VSTCMDKEY) == 0) {
      wxHandleFatalExceptions();

      VSTEffect::Check(argv[2]);
      return false;
   }
#endif

   #ifndef __WXMAC__
      mLogger = new wxLogWindow(NULL, wxT("Audacity Log"), false, false);
      mLogger->SetActiveTarget(mLogger);
      mLogger->EnableLogging(true);
      mLogger->SetLogLevel(wxLOG_Max);
   #endif

   // Unused strings that we want to be translated, even though
   // we're not using them yet...
   wxString future1 = _("Master Gain Control");
   wxString future2 = _("Input Meter");
   wxString future3 = _("Output Meter");

   ::wxInitAllImageHandlers();

   wxFileSystem::AddHandler(new wxZipFSHandler);

   InitPreferences();

   #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__)
      this->AssociateFileTypes(); 
   #endif

   // TODO - read the number of files to store in history from preferences
   mRecentFiles = new FileHistory(ID_RECENT_LAST - ID_RECENT_FIRST + 1, ID_RECENT_CLEAR);
   mRecentFiles->Load(*gPrefs, wxT("RecentFiles"));

   //
   // Paths: set search path and temp dir path
   //

   wxString home = wxGetHomeDir();
   mAppHomeDir = home;
   theTheme.EnsureInitialised();

   // AColor depends on theTheme.
   AColor::Init(); 

   /* On Unix systems, the default temp dir is in /tmp. */
   /* Search path (for plug-ins, translations etc) is (in this order):
      * The AUDACITY_PATH environment variable
      * The current directory
      * The user's .audacity-files directory in their home directory
      * The "share" and "share/doc" directories in their install path */
   #ifdef __WXGTK__
   defaultTempDir.Printf(wxT("/tmp/audacity-%s"), wxGetUserId().c_str());
   
   wxString pathVar = wxGetenv(wxT("AUDACITY_PATH"));
   if (pathVar != wxT(""))
      AddMultiPathsToPathList(pathVar, audacityPathList);
   AddUniquePathToPathList(::wxGetCwd(), audacityPathList);
   AddUniquePathToPathList(wxString::Format(wxT("%s/.audacity-files"),
                                            home.c_str()),
                           audacityPathList);
   #ifdef AUDACITY_NAME
      AddUniquePathToPathList(wxString::Format(wxT("%s/share/%s"),
                                               wxT(INSTALL_PREFIX), wxT(AUDACITY_NAME)),
                              audacityPathList);
      AddUniquePathToPathList(wxString::Format(wxT("%s/share/doc/%s"),
                                               wxT(INSTALL_PREFIX), wxT(AUDACITY_NAME)),
                              audacityPathList);
   #else //AUDACITY_NAME
      AddUniquePathToPathList(wxString::Format(wxT("%s/share/audacity"),
                                               wxT(INSTALL_PREFIX)),
                              audacityPathList);
      AddUniquePathToPathList(wxString::Format(wxT("%s/share/doc/audacity"),
                                               wxT(INSTALL_PREFIX)),
                              audacityPathList);
   #endif //AUDACITY_NAME

   AddUniquePathToPathList(wxString::Format(wxT("%s/share/locale"),
                                            wxT(INSTALL_PREFIX)),
                           audacityPathList);

   #endif //__WXGTK__

   wxFileName tmpFile;
   tmpFile.AssignTempFileName(wxT("nn"));
   wxString tmpDirLoc = tmpFile.GetPath(wxPATH_GET_VOLUME);
   ::wxRemoveFile(tmpFile.GetFullPath());

   // On Mac and Windows systems, use the directory which contains Audacity.
   #ifdef __WXMSW__
   // On Windows, the path to the Audacity program is in argv[0]
   wxString progPath = wxPathOnly(argv[0]);
   AddUniquePathToPathList(progPath, audacityPathList);
   AddUniquePathToPathList(progPath+wxT("\Languages"), audacityPathList);
   
   defaultTempDir.Printf(wxT("%s\audacity_temp"), 
                         tmpDirLoc.c_str());
   #endif //__WXWSW__

   #ifdef __WXMAC__
   // On Mac OS X, the path to the Audacity program is in argv[0]
   wxString progPath = wxPathOnly(argv[0]);

   AddUniquePathToPathList(progPath, audacityPathList);
   // If Audacity is a "bundle" package, then the root directory is
   // the great-great-grandparent of the directory containing the executable.
   AddUniquePathToPathList(progPath+wxT("/../../../"), audacityPathList);

   AddUniquePathToPathList(progPath+wxT("/Languages"), audacityPathList);
   AddUniquePathToPathList(progPath+wxT("/../../../Languages"), audacityPathList);
   defaultTempDir.Printf(wxT("%s/audacity-%s"), 
                         tmpDirLoc.c_str(),
                         wxGetUserId().c_str());
   #endif //__WXMAC__

   // BG: Create a temporary window to set as the top window
   wxFrame *temporarywindow = new wxFrame(NULL, -1, wxT("temporarytopwindow"));
   SetTopWindow(temporarywindow);

   // Initialize the ModuleManager
   ModuleManager::Initialize();

   // Initialize the CommandHandler
   InitCommandHandler();

   // load audacity plug-in modules
   LoadModules(*mCmdHandler);

   // Locale
   // wxWidgets 2.3 has a much nicer wxLocale API.  We can make this code much
   // better once we move to wx 2.3/2.4.

   wxString lang = gPrefs->Read(wxT("/Locale/Language"), wxT(""));

   if (lang == wxT(""))
      lang = GetSystemLanguageCode();

#ifdef NOT_RQD
//TIDY-ME: (CleanSpeech) Language prompt??
// The prompt for language only happens ONCE on a system.
// I don't think we should disable it JKC
   wxString lang = gPrefs->Read(wxT("/Locale/Language"), "en");  //lda

// Pop up a dialog the first time the program is run
//lda   if (lang == "")
//lda      lang = ChooseLanguage(NULL);
#endif

   mLocale = NULL;
   InitLang( lang );

   // Init DirManager, which initializes the temp directory
   // If this fails, we must exit the program.

   if (!InitTempDir()) {
      FinishPreferences();
      return false;
   }

   // More initialization
   InitCleanSpeech();

   InitDitherers();
   InitAudioIO();

   LoadEffects();


#ifdef __WXMAC__

   // On the Mac, users don't expect a program to quit when you close the last window.
   // Create a menubar that will show when all project windows are closed.

   wxMenu *fileMenu = new wxMenu();
   wxMenu *recentMenu = new wxMenu();
   fileMenu->Append(wxID_NEW, wxString(_("&New")) + wxT("tCtrl+N"));
   fileMenu->Append(wxID_OPEN, wxString(_("&Open...")) + wxT("tCtrl+O"));
   fileMenu->AppendSubMenu(recentMenu, _("Open &Recent..."));
   fileMenu->Append(wxID_ABOUT, _("&About Audacity..."));
   fileMenu->Append(wxID_PREFERENCES, wxString(_("&Preferences...")) + wxT("tCtrl+,"));

   wxMenuBar *menuBar = new wxMenuBar();
   menuBar->Append(fileMenu, wxT("&File"));

   wxMenuBar::MacSetCommonMenuBar(menuBar);

   mRecentFiles->UseMenu(recentMenu);
   mRecentFiles->AddFilesToMenu(recentMenu);

   // This invisibale frame will be the "root" of all other frames and will
   // become the active frame when no projects are open.
   gParentFrame = new wxFrame(NULL, -1, wxEmptyString, wxPoint(0, 0), wxSize(0, 0), 0);

#endif //__WXMAC__

   SetExitOnFrameDelete(true);
   //efm5 start
#if !defined(__CYGWIN__)//might work on Cygwin
   if (argc > 1) {
      if (!wxString(wxT("-doTo4")).CmpNoCase(argv[1])) {
         mbDoUnattended = true;
         mbDoTo4 = true;
      }
      if (!wxString(wxT("-doTo3")).CmpNoCase(argv[1])) {
         mbDoUnattended = true;
         mbDoTo3 = true;
      }
      else if (!wxString(wxT("-doSilenceProject")).CmpNoCase(argv[1])) {
         mbDoUnattended = true;
         mbSilenceProject = true;
      }
      else if (!wxString(wxT("-doAmplify")).CmpNoCase(argv[1])) {
         mbDoUnattended = true;
         mbAmplify = true;
      }
   }
#endif
   //efm5 end

   AudacityProject *project = CreateNewAudacityProject();
   mCmdHandler->SetProject(project);

   wxWindow * pWnd = MakeHijackPanel() ;
   if( pWnd )
   {
      project->Show( false );
      SetTopWindow(pWnd);
      pWnd->Show( true );
   }

   delete temporarywindow;
   
   if( project->mShowSplashScreen )
      project->OnHelpWelcome();

   // JKC 10-Sep-2007: Enable monitoring from the start.
   // (recommended by lprod.org).
   // Monitoring stops again after any 
   // PLAY or RECORD completes.  
   // So we also call StartMonitoring when STOP is called.
   project->MayStartMonitoring();

   #ifdef __WXMAC__
      mLogger = new wxLogWindow(NULL, wxT("Audacity Log"), false, false);
      mLogger->SetActiveTarget(mLogger);
      mLogger->EnableLogging(true);
      mLogger->SetLogLevel(wxLOG_Max);
   #endif

   #ifdef USE_FFMPEG
   FFmpegStartup();
   #endif

   #ifdef USE_GSTREAMER
   GStreamerStartup();
   #endif

   mImporter = new Importer;

   //
   // Auto-recovery
   //
   bool didRecoverAnything = false;
   if (!ShowAutoRecoveryDialogIfNeeded(&project, &didRecoverAnything))
   {
      // Important: Prevent deleting any temporary files!
      DirManager::SetDontDeleteTempFiles();
      QuitAudacity(true);
   }

   //
   // Command-line parsing, but only if we didn't recover
   //

#if !defined(__CYGWIN__)

   // Parse command-line arguments
   if (argc > 1 && !didRecoverAnything) {
      for (int option = 1; option < argc; option++) {
         if (!argv[option])
            continue;
         bool handled = false;

         if (!wxString(wxT("-help")).CmpNoCase(argv[option])) {
            PrintCommandLineHelp(); // print the help message out
            exit(0);
         }

         if (option < argc - 1 &&
             argv[option + 1] &&
             !wxString(wxT("-blocksize")).CmpNoCase(argv[option])) {
            long theBlockSize;
            if (wxString(argv[option + 1]).ToLong(&theBlockSize)) {
               if (theBlockSize >= 256 && theBlockSize < 100000000) {
                  wxFprintf(stderr, _("Using block size of %ldn"),
                          theBlockSize);
                  Sequence::SetMaxDiskBlockSize(theBlockSize);
               }
            }
            option++;
            handled = true;
         }

         if (!handled && !wxString(wxT("-test")).CmpNoCase(argv[option])) {
            RunBenchmark(NULL);
            exit(0);
         }

         if (!handled && !wxString(wxT("-version")).CmpNoCase(argv[option])) {
            wxPrintf(wxT("Audacity v%s (%s)n"),
                     AUDACITY_VERSION_STRING,
                     (wxUSE_UNICODE ? wxT("Unicode") : wxT("ANSI")));
            exit(0);
         }

        //efm5 start
         if (!handled && !wxString(wxT("-doTo3")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            handled = true;
         }
         if (!handled && !wxString(wxT("-doTo4")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            handled = true;
         }
         if (!handled && !wxString(wxT("-doSilenceProject")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            wxString tempFilename(GetCLIpath());
            tempFilename.Append(wxT("\"));//must escape NEWLINE to compile
            tempFilename.Append(argv[option+1]);
            mUnattendedProjectName = tempFilename;
            handled = true;
         }
         if (!handled && !wxString(wxT("-doAmplify")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            wxString tempFilename(GetCLIpath());
            tempFilename.Append(wxT("\"));//must escape NEWLINE to compile
            tempFilename.Append(argv[option+1]);
            mUnattendedProjectName = tempFilename;
            handled = true;
         }
         //efm5 end
		 //mytry start
         if (!handled && !wxString(wxT("-input")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            wxFileName fn(argv[option+1]);
            fn.MakeAbsolute();
            project->OpenFile(fn.GetFullPath());
			//wxString tempFilename(GetCLIpath());
            //tempFilename.Append(wxT("\"));//must escape NEWLINE to compile
            //tempFilename.Append(argv[option+1]);
			//project->OpenFile(tempFilename);
            handled = true;
         }
		 if (!handled && !wxString(wxT("-output")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            wxString tempFilename(GetCLIpath());
            tempFilename.Append(wxT("\"));//must escape NEWLINE to compile
            tempFilename.Append(argv[option+1]);
			mSaveAsFileName = tempFilename;
			//mSaveAsFileName = argv[option+1];
			//mSaveAsFileName.MakeAbsolute();
			mbSaveAsSet = true;
            handled = true;
         }
		 //mytry end

         if (argv[option][0] == wxT('-') && !handled) {
            wxPrintf(_("Unknown command line option: %sn"), argv[option]);
            exit(0);
         }

		 /*//mytry start
         if (!handled)
         {
            if (!project)
            {
               // Create new window for project
               project = CreateNewAudacityProject();
            }
            //efm5 start
			wxString tempFN(GetCLIpath());
            tempFN.Append(wxT("\"));//must escape NEWLINE to compile
            tempFN.Append(argv[option]);
            project->OpenFile(tempFN);
            if (mbDoUnattended) {
               wxSetWorkingDirectory(GetCLIpath());
               project->UnattendedCLIAction();
            }

            // Always open files with an absolute path
            //wxFileName fn(argv[option]);
            //fn.MakeAbsolute();
            //project->OpenFile(fn.GetFullPath());
            //efm5 end
            project = NULL; // don't reuse this project for other file
         }
		 *///mytry end
      }                         // for option...
   }                            // if (argc>1)

#else //__CYGWIN__
   
   // Cygwin command line parser (by Dave Fancella)
   if (argc > 1 && !didRecoverAnything) {
      int optionstart = 1;
      bool startAtOffset = false;
      
      // Scan command line arguments looking for trouble
      for (int option = 1; option < argc; option++) {
         if (!argv[option])
            continue;
         // Check to see if argv[0] is copied across other arguments.
         // This is the reason Cygwin gets its own command line parser.
         if (wxString(argv[option]).Lower().Contains(wxString(wxT("audacity.exe")))) {
            startAtOffset = true;
            optionstart = option + 1;
         }
      }
      
      for (int option = optionstart; option < argc; option++) {
         if (!argv[option])
            continue;
         bool handled = false;
         bool openThisFile = false;
         wxString fileToOpen;
         
         if (!wxString(wxT("-help")).CmpNoCase(argv[option])) {
            PrintCommandLineHelp(); // print the help message out
            exit(0);
         }

         if (option < argc - 1 &&
             argv[option + 1] &&
             !wxString(wxT("-blocksize")).CmpNoCase(argv[option])) {
            long theBlockSize;
            if (wxString(argv[option + 1]).ToLong(&theBlockSize)) {
               if (theBlockSize >= 256 && theBlockSize < 100000000) {
                  wxFprintf(stderr, _("Using block size of %ldn"),
                          theBlockSize);
                  Sequence::SetMaxDiskBlockSize(theBlockSize);
               }
            }
            option++;
            handled = true;
         }

         if (!handled && !wxString(wxT("-test")).CmpNoCase(argv[option])) {
            RunBenchmark(NULL);
            exit(0);
         }

         if (argv[option][0] == wxT('-') && !handled) {
            wxPrintf(_("Unknown command line option: %sn"), argv[option]);
            exit(0);
         }
         
         if(handled)
            fileToOpen.Clear();
         
         if (!handled)
            fileToOpen = fileToOpen + wxT(" ") + argv[option];
         if(wxString(argv[option]).Lower().Contains(wxT(".aup")))
            openThisFile = true;
         if(openThisFile) {
            openThisFile = false;
            if (!project)
            {
               // Create new window for project
               project = CreateNewAudacityProject();
            }
            project->OpenFile(fileToOpen);
            project = NULL; // don't reuse this project for other file
         }

      }                         // for option...
   }                            // if (argc>1)

#endif // __CYGWIN__ (Cygwin command-line parser)

   gInited = true;
   
   ModuleManager::Dispatch(AppInitialized);

   mWindowRectAlreadySaved = FALSE;

   wxLog::FlushActive(); // Make sure all log messages are written.

   mTimer = new wxTimer(this, kAudacityAppTimerID);
   mTimer->Start(200);
   return TRUE;
}

I’ll have to rest something to get my mind clearer.
I would be very happy if you could help me on this.

Having the whole function helps me a lot! I see a couple of problems.

First, try moving the -input switch arg after the -output code (so that mSaveAsFileName is initialized before the project is opened); then :

         if (!handled && !wxString(wxT("-input")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            wxFileName fn(argv[option+1]);
            fn.MakeAbsolute();
            project->OpenFile(fn.GetFullPath());
         //wxString tempFilename(GetCLIpath());
            //tempFilename.Append(wxT("\"));//must escape NEWLINE to compile
            //tempFilename.Append(argv[option+1]);
         //project->OpenFile(tempFilename);
            handled = true;
         }

IMVHO, the statement:
fn.MakeAbsolute();
should not be needed (it resolves to Normalize())–and you should not be using “…”, “.” or any path variables (for sanity’s sake).
so, stick the input file as the last arg on the CLI:
audacity.exe -output “try with spaces” -input “fully-qualified input file”


the other option is to uncomment my final (!handled) section and get rid of your -input switch completely and put the input file as the last arg. In that case you would need to move your code from the -input switch replacing my code.

Next, you still need to work on the -output code; you have:

       if (!handled && !wxString(wxT("-output")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            wxString tempFilename(GetCLIpath());
            tempFilename.Append(wxT("\"));//must escape NEWLINE to compile
            tempFilename.Append(argv[option+1]);
         mSaveAsFileName = tempFilename;
         //mSaveAsFileName = argv[option+1];
         //mSaveAsFileName.MakeAbsolute();
         mbSaveAsSet = true;
            handled = true;
         }

what you want looks more like:

       if (!handled && !wxString(wxT("-output")).CmpNoCase(argv[option])) {
         wxString tempFilename(argv[option+1]);
         mSaveAsFileName = tempFilename;
         mbSaveAsSet = true;
         handled = true;
      }

there may quicker ways to handle assigning the string argv[option+1] to mSaveAsFileName, you seem to have tried:
mSaveAsFileName = argv[option+1];
which might work fine.

After this, if you still have problems, I will need to see the new code in OnInit–just paste it in again. I will also need to see the entire function where you handle -output–paste into code block as before.

Thank you so much Edgar!! :smiley:
It really seems to work now as I wanted: C:>“C:UsersmeDesktopaudacity-src - unA2LinuxwinReleaseAudacity.exe” -output “C:UsersmeDesktopoutputedited_1.wav” -input “C:UsersmeDesktopintput with spaces1.wav”

For the sake of completeness the code (based on Edgar’s UnA2Linux-files, my improvements marked with //mytry):

  • My OnInit()-function in AudacityApp.cpp:
bool AudacityApp::OnInit()
{
//efm5 start new
   SetCLIpath(wxGetCwd());
   mbDoUnattended = false;
   mbDoTo4 = false;
   mbSilenceProject = false;
   mbAmplify = false;
   mbDoPrompt = false;
   mbFileNameError = false;
   mbNeedToSave = true;
   mbSaveAsSet = false; //mytry
//efm5 end new
   m_aliasMissingWarningShouldShow = true;
   m_LastMissingBlockFile = NULL;

#if defined(__WXGTK__)
   // Workaround for bug 154 -- initialize to false
   inKbdHandler = false;
#endif

#if defined(__WXMAC__)
   // Disable window animation
   wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, 1 );
#endif

//MERGE:
//Everything now uses Audacity name for preferences.
//(Audacity and CleanSpeech the same program and use
//the same preferences file).
//
// LL: Moved here from InitPreferences() to ensure VST effect
//     discovery writes configuration to the correct directory
//     on OSX with case-sensitive file systems.
#ifdef AUDACITY_NAME
   wxString appName = wxT(AUDACITY_NAME);
   wxString vendorName = wxT(AUDACITY_NAME);
#else
   wxString vendorName = wxT("Audacity");
   wxString appName = wxT("Audacity");
#endif

   wxTheApp->SetVendorName(vendorName);
   wxTheApp->SetAppName(appName);

#ifdef USE_VST // if no VST support, answer is always no
   // Have we been started to check a plugin?
   if (argc == 3 && wxStrcmp(argv[1], VSTCMDKEY) == 0) {
      wxHandleFatalExceptions();

      VSTEffect::Check(argv[2]);
      return false;
   }
#endif

   #ifndef __WXMAC__
      mLogger = new wxLogWindow(NULL, wxT("Audacity Log"), false, false);
      mLogger->SetActiveTarget(mLogger);
      mLogger->EnableLogging(true);
      mLogger->SetLogLevel(wxLOG_Max);
   #endif

   // Unused strings that we want to be translated, even though
   // we're not using them yet...
   wxString future1 = _("Master Gain Control");
   wxString future2 = _("Input Meter");
   wxString future3 = _("Output Meter");

   ::wxInitAllImageHandlers();

   wxFileSystem::AddHandler(new wxZipFSHandler);

   InitPreferences();

   #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__)
      this->AssociateFileTypes(); 
   #endif

   // TODO - read the number of files to store in history from preferences
   mRecentFiles = new FileHistory(ID_RECENT_LAST - ID_RECENT_FIRST + 1, ID_RECENT_CLEAR);
   mRecentFiles->Load(*gPrefs, wxT("RecentFiles"));

   //
   // Paths: set search path and temp dir path
   //

   wxString home = wxGetHomeDir();
   mAppHomeDir = home;
   theTheme.EnsureInitialised();

   // AColor depends on theTheme.
   AColor::Init(); 

   /* On Unix systems, the default temp dir is in /tmp. */
   /* Search path (for plug-ins, translations etc) is (in this order):
      * The AUDACITY_PATH environment variable
      * The current directory
      * The user's .audacity-files directory in their home directory
      * The "share" and "share/doc" directories in their install path */
   #ifdef __WXGTK__
   defaultTempDir.Printf(wxT("/tmp/audacity-%s"), wxGetUserId().c_str());
   
   wxString pathVar = wxGetenv(wxT("AUDACITY_PATH"));
   if (pathVar != wxT(""))
      AddMultiPathsToPathList(pathVar, audacityPathList);
   AddUniquePathToPathList(::wxGetCwd(), audacityPathList);
   AddUniquePathToPathList(wxString::Format(wxT("%s/.audacity-files"),
                                            home.c_str()),
                           audacityPathList);
   #ifdef AUDACITY_NAME
      AddUniquePathToPathList(wxString::Format(wxT("%s/share/%s"),
                                               wxT(INSTALL_PREFIX), wxT(AUDACITY_NAME)),
                              audacityPathList);
      AddUniquePathToPathList(wxString::Format(wxT("%s/share/doc/%s"),
                                               wxT(INSTALL_PREFIX), wxT(AUDACITY_NAME)),
                              audacityPathList);
   #else //AUDACITY_NAME
      AddUniquePathToPathList(wxString::Format(wxT("%s/share/audacity"),
                                               wxT(INSTALL_PREFIX)),
                              audacityPathList);
      AddUniquePathToPathList(wxString::Format(wxT("%s/share/doc/audacity"),
                                               wxT(INSTALL_PREFIX)),
                              audacityPathList);
   #endif //AUDACITY_NAME

   AddUniquePathToPathList(wxString::Format(wxT("%s/share/locale"),
                                            wxT(INSTALL_PREFIX)),
                           audacityPathList);

   #endif //__WXGTK__

   wxFileName tmpFile;
   tmpFile.AssignTempFileName(wxT("nn"));
   wxString tmpDirLoc = tmpFile.GetPath(wxPATH_GET_VOLUME);
   ::wxRemoveFile(tmpFile.GetFullPath());

   // On Mac and Windows systems, use the directory which contains Audacity.
   #ifdef __WXMSW__
   // On Windows, the path to the Audacity program is in argv[0]
   wxString progPath = wxPathOnly(argv[0]);
   AddUniquePathToPathList(progPath, audacityPathList);
   AddUniquePathToPathList(progPath+wxT("\Languages"), audacityPathList);
   
   defaultTempDir.Printf(wxT("%s\audacity_temp"), 
                         tmpDirLoc.c_str());
   #endif //__WXWSW__

   #ifdef __WXMAC__
   // On Mac OS X, the path to the Audacity program is in argv[0]
   wxString progPath = wxPathOnly(argv[0]);

   AddUniquePathToPathList(progPath, audacityPathList);
   // If Audacity is a "bundle" package, then the root directory is
   // the great-great-grandparent of the directory containing the executable.
   AddUniquePathToPathList(progPath+wxT("/../../../"), audacityPathList);

   AddUniquePathToPathList(progPath+wxT("/Languages"), audacityPathList);
   AddUniquePathToPathList(progPath+wxT("/../../../Languages"), audacityPathList);
   defaultTempDir.Printf(wxT("%s/audacity-%s"), 
                         tmpDirLoc.c_str(),
                         wxGetUserId().c_str());
   #endif //__WXMAC__

   // BG: Create a temporary window to set as the top window
   wxFrame *temporarywindow = new wxFrame(NULL, -1, wxT("temporarytopwindow"));
   SetTopWindow(temporarywindow);

   // Initialize the ModuleManager
   ModuleManager::Initialize();

   // Initialize the CommandHandler
   InitCommandHandler();

   // load audacity plug-in modules
   LoadModules(*mCmdHandler);

   // Locale
   // wxWidgets 2.3 has a much nicer wxLocale API.  We can make this code much
   // better once we move to wx 2.3/2.4.

   wxString lang = gPrefs->Read(wxT("/Locale/Language"), wxT(""));

   if (lang == wxT(""))
      lang = GetSystemLanguageCode();

#ifdef NOT_RQD
//TIDY-ME: (CleanSpeech) Language prompt??
// The prompt for language only happens ONCE on a system.
// I don't think we should disable it JKC
   wxString lang = gPrefs->Read(wxT("/Locale/Language"), "en");  //lda

// Pop up a dialog the first time the program is run
//lda   if (lang == "")
//lda      lang = ChooseLanguage(NULL);
#endif

   mLocale = NULL;
   InitLang( lang );

   // Init DirManager, which initializes the temp directory
   // If this fails, we must exit the program.

   if (!InitTempDir()) {
      FinishPreferences();
      return false;
   }

   // More initialization
   InitCleanSpeech();

   InitDitherers();
   InitAudioIO();

   LoadEffects();


#ifdef __WXMAC__

   // On the Mac, users don't expect a program to quit when you close the last window.
   // Create a menubar that will show when all project windows are closed.

   wxMenu *fileMenu = new wxMenu();
   wxMenu *recentMenu = new wxMenu();
   fileMenu->Append(wxID_NEW, wxString(_("&New")) + wxT("tCtrl+N"));
   fileMenu->Append(wxID_OPEN, wxString(_("&Open...")) + wxT("tCtrl+O"));
   fileMenu->AppendSubMenu(recentMenu, _("Open &Recent..."));
   fileMenu->Append(wxID_ABOUT, _("&About Audacity..."));
   fileMenu->Append(wxID_PREFERENCES, wxString(_("&Preferences...")) + wxT("tCtrl+,"));

   wxMenuBar *menuBar = new wxMenuBar();
   menuBar->Append(fileMenu, wxT("&File"));

   wxMenuBar::MacSetCommonMenuBar(menuBar);

   mRecentFiles->UseMenu(recentMenu);
   mRecentFiles->AddFilesToMenu(recentMenu);

   // This invisibale frame will be the "root" of all other frames and will
   // become the active frame when no projects are open.
   gParentFrame = new wxFrame(NULL, -1, wxEmptyString, wxPoint(0, 0), wxSize(0, 0), 0);

#endif //__WXMAC__

   SetExitOnFrameDelete(true);
   //efm5 start
#if !defined(__CYGWIN__)//might work on Cygwin
   if (argc > 1) {
      if (!wxString(wxT("-doTo4")).CmpNoCase(argv[1])) {
         mbDoUnattended = true;
         mbDoTo4 = true;
      }
      if (!wxString(wxT("-doTo3")).CmpNoCase(argv[1])) {
         mbDoUnattended = true;
         mbDoTo3 = true;
      }
      else if (!wxString(wxT("-doSilenceProject")).CmpNoCase(argv[1])) {
         mbDoUnattended = true;
         mbSilenceProject = true;
      }
      else if (!wxString(wxT("-doAmplify")).CmpNoCase(argv[1])) {
         mbDoUnattended = true;
         mbAmplify = true;
      }
   }
#endif
   //efm5 end

   AudacityProject *project = CreateNewAudacityProject();
   mCmdHandler->SetProject(project);

   wxWindow * pWnd = MakeHijackPanel() ;
   if( pWnd )
   {
      project->Show( false );
      SetTopWindow(pWnd);
      pWnd->Show( true );
   }

   delete temporarywindow;
   
   if( project->mShowSplashScreen )
      project->OnHelpWelcome();

   // JKC 10-Sep-2007: Enable monitoring from the start.
   // (recommended by lprod.org).
   // Monitoring stops again after any 
   // PLAY or RECORD completes.  
   // So we also call StartMonitoring when STOP is called.
   project->MayStartMonitoring();

   #ifdef __WXMAC__
      mLogger = new wxLogWindow(NULL, wxT("Audacity Log"), false, false);
      mLogger->SetActiveTarget(mLogger);
      mLogger->EnableLogging(true);
      mLogger->SetLogLevel(wxLOG_Max);
   #endif

   #ifdef USE_FFMPEG
   FFmpegStartup();
   #endif

   #ifdef USE_GSTREAMER
   GStreamerStartup();
   #endif

   mImporter = new Importer;

   //
   // Auto-recovery
   //
   bool didRecoverAnything = false;
   if (!ShowAutoRecoveryDialogIfNeeded(&project, &didRecoverAnything))
   {
      // Important: Prevent deleting any temporary files!
      DirManager::SetDontDeleteTempFiles();
      QuitAudacity(true);
   }

   //
   // Command-line parsing, but only if we didn't recover
   //

#if !defined(__CYGWIN__)

   // Parse command-line arguments
   if (argc > 1 && !didRecoverAnything) {
      for (int option = 1; option < argc; option++) {
         if (!argv[option])
            continue;
         bool handled = false;

         if (!wxString(wxT("-help")).CmpNoCase(argv[option])) {
            PrintCommandLineHelp(); // print the help message out
            exit(0);
         }

         if (option < argc - 1 &&
             argv[option + 1] &&
             !wxString(wxT("-blocksize")).CmpNoCase(argv[option])) {
            long theBlockSize;
            if (wxString(argv[option + 1]).ToLong(&theBlockSize)) {
               if (theBlockSize >= 256 && theBlockSize < 100000000) {
                  wxFprintf(stderr, _("Using block size of %ldn"),
                          theBlockSize);
                  Sequence::SetMaxDiskBlockSize(theBlockSize);
               }
            }
            option++;
            handled = true;
         }

         if (!handled && !wxString(wxT("-test")).CmpNoCase(argv[option])) {
            RunBenchmark(NULL);
            exit(0);
         }

         if (!handled && !wxString(wxT("-version")).CmpNoCase(argv[option])) {
            wxPrintf(wxT("Audacity v%s (%s)n"),
                     AUDACITY_VERSION_STRING,
                     (wxUSE_UNICODE ? wxT("Unicode") : wxT("ANSI")));
            exit(0);
         }

        //efm5 start
         if (!handled && !wxString(wxT("-doTo3")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            handled = true;
         }
         if (!handled && !wxString(wxT("-doTo4")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            handled = true;
         }
         if (!handled && !wxString(wxT("-doSilenceProject")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            wxString tempFilename(GetCLIpath());
            tempFilename.Append(wxT("\"));//must escape NEWLINE to compile
            tempFilename.Append(argv[option+1]);
            mUnattendedProjectName = tempFilename;
            handled = true;
         }
         if (!handled && !wxString(wxT("-doAmplify")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            wxString tempFilename(GetCLIpath());
            tempFilename.Append(wxT("\"));//must escape NEWLINE to compile
            tempFilename.Append(argv[option+1]);
            mUnattendedProjectName = tempFilename;
            handled = true;
         }
         //efm5 end
	 //mytry start
         if (!handled && !wxString(wxT("-output")).CmpNoCase(argv[option])) {
            mSaveAsFileName = argv[option+1];
            mbSaveAsSet = true;
            handled = true;
         }
         if (!handled && !wxString(wxT("-input")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            wxFileName fn(argv[option+1]);
            project->OpenFile(fn.GetFullPath());
            handled = true;
         }
		 //mytry end

         if (argv[option][0] == wxT('-') && !handled) {
            wxPrintf(_("Unknown command line option: %sn"), argv[option]);
            exit(0);
         }

		 /*//mytry start
         if (!handled)
         {
            if (!project)
            {
               // Create new window for project
               project = CreateNewAudacityProject();
            }
            //efm5 start
			wxString tempFN(GetCLIpath());
            tempFN.Append(wxT("\"));//must escape NEWLINE to compile
            tempFN.Append(argv[option]);
            project->OpenFile(tempFN);
            if (mbDoUnattended) {
               wxSetWorkingDirectory(GetCLIpath());
               project->UnattendedCLIAction();
            }

            // Always open files with an absolute path
            //wxFileName fn(argv[option]);
            //fn.MakeAbsolute();
            //project->OpenFile(fn.GetFullPath());
            //efm5 end
            project = NULL; // don't reuse this project for other file
         }
		 *///mytry end
      }                         // for option...
   }                            // if (argc>1)

#else //__CYGWIN__
   
   // Cygwin command line parser (by Dave Fancella)
   if (argc > 1 && !didRecoverAnything) {
      int optionstart = 1;
      bool startAtOffset = false;
      
      // Scan command line arguments looking for trouble
      for (int option = 1; option < argc; option++) {
         if (!argv[option])
            continue;
         // Check to see if argv[0] is copied across other arguments.
         // This is the reason Cygwin gets its own command line parser.
         if (wxString(argv[option]).Lower().Contains(wxString(wxT("audacity.exe")))) {
            startAtOffset = true;
            optionstart = option + 1;
         }
      }
      
      for (int option = optionstart; option < argc; option++) {
         if (!argv[option])
            continue;
         bool handled = false;
         bool openThisFile = false;
         wxString fileToOpen;
         
         if (!wxString(wxT("-help")).CmpNoCase(argv[option])) {
            PrintCommandLineHelp(); // print the help message out
            exit(0);
         }

         if (option < argc - 1 &&
             argv[option + 1] &&
             !wxString(wxT("-blocksize")).CmpNoCase(argv[option])) {
            long theBlockSize;
            if (wxString(argv[option + 1]).ToLong(&theBlockSize)) {
               if (theBlockSize >= 256 && theBlockSize < 100000000) {
                  wxFprintf(stderr, _("Using block size of %ldn"),
                          theBlockSize);
                  Sequence::SetMaxDiskBlockSize(theBlockSize);
               }
            }
            option++;
            handled = true;
         }

         if (!handled && !wxString(wxT("-test")).CmpNoCase(argv[option])) {
            RunBenchmark(NULL);
            exit(0);
         }

         if (argv[option][0] == wxT('-') && !handled) {
            wxPrintf(_("Unknown command line option: %sn"), argv[option]);
            exit(0);
         }
         
         if(handled)
            fileToOpen.Clear();
         
         if (!handled)
            fileToOpen = fileToOpen + wxT(" ") + argv[option];
         if(wxString(argv[option]).Lower().Contains(wxT(".aup")))
            openThisFile = true;
         if(openThisFile) {
            openThisFile = false;
            if (!project)
            {
               // Create new window for project
               project = CreateNewAudacityProject();
            }
            project->OpenFile(fileToOpen);
            project = NULL; // don't reuse this project for other file
         }

      }                         // for option...
   }                            // if (argc>1)

#endif // __CYGWIN__ (Cygwin command-line parser)

   gInited = true;
   
   ModuleManager::Dispatch(AppInitialized);

   mWindowRectAlreadySaved = FALSE;

   wxLog::FlushActive(); // Make sure all log messages are written.

   mTimer = new wxTimer(this, kAudacityAppTimerID);
   mTimer->Start(200);
   return TRUE;
}
  • My OnCloseWindow file-saving (after Edgar’s efm paragraph):
   //efm5 start
   //if (event.CanVeto() && (mEmptyCanBeDirty || bHasTracks)) {
   //   if (mUndoManager.UnsavedChanges()) {
   //      wxString Message = _("Save changes before closing?");
   //      if( !bHasTracks )
   //      { 
   //       Message += _("nIf saved, the project will have no tracks.nnTo save any previously open tracks:nCancel, Edit > Undo until all tracksnare open, then File > Save Project.");
   //      }
   //      int result = wxMessageBox( Message,
   //                                _("Save changes?"),
   //                                wxYES_NO | wxCANCEL | wxICON_QUESTION,
   //                                this);

   //      if (result == wxCANCEL || (result == wxYES && !Save())) {
   //         event.Veto();
   //         return;
   //      }
   //   }
   //}
   //efm5 end
   //mytry start
   bool bSaveFile = wxGetApp().GetSaveAsSet();
   if (bSaveFile && (!mEmptyCanBeDirty || bHasTracks))
   {
	   wxFileName tempFileName(wxGetApp().GetSaveAsFileName());
	   wxString tempName(tempFileName.GetFullPath());
	   OnExport(wxT("WAV"), tempName);
   }
   //mytry end
  • And of course the declarations in AudacityApp.h:
//efm5 start new
// store the current working directory as it exists when Audacity is launched
//(it gets hijacked somewhere -- see Project.cpp line #758
private:
   wxString mCLIpath;
   wxFileName mUnattendedProjectName;
   wxFileName mSaveAsFileName; //mytry
   void SetCLIpath(const wxString & CLIpath) {mCLIpath = CLIpath;};
   bool mbNeedToSave;
   bool mbDoUnattended;
   bool mbDoTo4;
   bool mbDoTo3;
   bool mbSilenceProject;
   bool mbAmplify;
   bool mbDoPrompt;
   bool mbFileNameError;
   bool mbSaveAsSet; //mytry
public:
   const wxString & GetCLIpath() const {return mCLIpath;};
   const wxFileName & GetUnattendedProjectName() const {return mUnattendedProjectName;};
   const wxFileName & GetSaveAsFileName() const {return mSaveAsFileName;}; //mytry
   bool GetDoUnattended() const {return mbDoUnattended;};
   bool GetDoTo4() const {return mbDoTo4;};
   bool GetDoTo3() const {return mbDoTo3;};
   bool GetDoSilenceProject() const {return mbSilenceProject;};
   bool GetDoAmplifyProject() const {return mbAmplify;};
   bool GetDoPrompt() const {return mbDoPrompt;};
   bool GetFileNameError() const {return mbFileNameError;};
   void SetFileNameError(bool pError) {mbFileNameError = pError;};
   void SetNeedToSave(bool pNeedToSave) {mbNeedToSave = pNeedToSave;};
   bool GetNeedToSave() const {return mbNeedToSave;};
   bool GetSaveAsSet() const {return mbSaveAsSet;}; //mytry
//efm5 end new
};

Another little adaption which I made was:

  • I’d like to save wav-files only as mono, so I changed line 3116 in Menus.cpp:
//efm5 start
void AudacityProject::OnExport(const wxString & FormatType, const wxString & FileName)
{
   Exporter e;
   //this version of Exporter::Process bypasses the Save dialog
   e.Process(this, 1, FormatType, FileName, false, 0.0, mTracks->GetEndTime()); //mytry: changed 2nd argument (number of channels) from 2 to 1
}
//efm5 end

EDIT:
One more thing came to my mind: maybe it would be a good idea to parse the CLI-input (argv[option+1]) through the wxT-function in case somebody wants a unicode compatible solution.

mSaveAsFileName = wxT(argv[option+1]);

and

wxFileName fn(wxT(argv[option+1]));

Well done!

There is one “bug” I see in my Audacity version: If I open Audacity twice and a second Audycity (and third and so on…) instance should open with parameters, it fails:

It seems as if Audacity tries to open the file “-saveAs”, which is my renamed “-output” flag.

I don’t see, why a second instance of Audacity does this. Any hints?

It may be an OS or shell/CLI problem. I get something similar if I create something like this in a text file:
audacity.exe -doSomething file1.wav
audacity.exe -doSomething file2.wav
audacity.exe -doSomething file3.wav

then select all and copy then paste from the clipboard into a CLI (on Win7 using the built-in shell). However, if I save the text file with a .bat extension (instead of .txt) and execute the resulting file as a batch process it works as planned. The difference is that pasting text into the CLI from the clipboard runs all the commands simultaneously while running as a batch processes the commands on-at-a-time.

If that does not get you going, create and send me a patch (or just send me the changed files) and I will install the code here and see what I can do. I will PM you right now with my @dress so you may send me code which might not be attachable here.

Oh, and as to your point about using wxT(), have you tried it? My personal choice is to use very plain names which would not require this but seeing your pic with (what looks like) German I understand your thought!

To avoid the bug I now just commented out the “DDE connection to an already active Audacity” (ca. line 1683 to line 1700 in AudacityApp.cpp):

	  /* //mytry start
      wxClient client;
      wxConnectionBase *conn;

      // We try up to 10 times since there's a small window
      // where the DDE server may not have been fully initialized
      // yet.
      for (int i = 0; i < 10; i++) {
         conn = client.MakeConnection(wxEmptyString,
                                      IPC_APPL,
                                      IPC_TOPIC);
         if (conn) {
            if (conn->Execute(argv[1])) {
               // Command was successfully queued so exit quietly
               delete mChecker;
               return false;
            }
         }
         wxMilliSleep(100);
      }
	  */ //mytry end

This is a dangerous solution as most of Audacity’s code is NOT re-entrant–it is just not designed for multiple simultaneous instances.



Sorry, I chose the wrong english word: I meant “commented out the DDE connection” (it was “uncommented” before). So my Audacity is now less able to be opened more than once.
Trying to open Audacity twice now, gets me a message box with an error and no second project.
This was the quickest solution I could find.

I was aware of the (un)comment “typo” but my concern remains about commenting out those lines. There are serious but subtle problems when multiple copies of Audacity run at the same time.

There is a race condition bug in the code you comment out, reported here:
http://bugzilla.audacityteam.org/show_bug.cgi?id=219
which can lead to multiple copies of Audacity running at the same time. There is a thread (on -devel I think–the Audacity mailing list) with some discussion with pictures of TaskManager showing two Audacity running.

Thank you, Edgar. I’ll keep that in mind and perhaps I’ll try to fix this later.

Meanwhile I found another bug:
If the -saveAs and -open parameters are the same (which means that the opened file is saved under its own name), the replaced file seems to be empty.

Surprisingly I can avoid emptyness of the saved file by normalizing on load.

For that, I built in another CLI switch. It has to be called after -saveAs and -open:

if (!handled && !wxString(wxT("-normalize")).CmpNoCase(argv[option])) {
    if (!project)
       project = CreateNewAudacityProject();
    project->SelectNone();
    project->SelectAllIfNone();
    project->OnEffect(ALL_EFFECTS | CONFIGURED_EFFECT,
              EffectManager::Get().GetEffectByIdentifier(wxT("Normalize")));
    handled = true;
}

Any idea?

I thought that problem had been addressed/fixed a couple of months ago. Are you working with a recent SVN HEAD? If not, You should go ahead and grab the most recent and port your changes. I just tested it here on SVN HEAD (but not via your CLI code) and do not experience this. If the problem persists for you let me know and I will try to test it here.

Thanks for pointing out GetEffectByIdentifier! I have been using a hard-coded numeric ID which could change if the Plug-ins folder’s content changed. This may help me with some fine tuning I am currently doing on my “Personal Audacity”.

No, I wasn’t working with a recent SVN HEAD, but with the Audacity 1.3 release, I think. I’ll try porting our changes next week and report my result.

Nice to hear, that I could contribute at last. :smiley: