Unattended command line processing

General discussion about writing or understanding source code in audio software that does not fit in the other specific Programming and Development boards.

If you require help using Audacity, or think you have found a "bug", please post on the forum board relevant to your operating system.
Windows
Mac OS X
GNU/Linux and Unix-like

Unattended command line processing

Permanent link to this post Posted by Edgar » Fri Aug 20, 2010 7:51 pm

In another thread (http://forum.audacityteam.org/viewtopic.php?f=15&t=37601) we talked about this and I started a new thread to present a "proof of concept".

changes for unattended CLI operation
for unattended operation I think On Demand should (must?) be off

usage:
Audacity.exe -dounattended song.mp3

example:
create a "working" directory somewhere (here I am working in D:\MP3s\converted)
open a CLI and cd to the "working" directory--this is the directory in which the file will be saved
run Audacity from the CLI with the -dounattended switch -- only submit a single file to convert
D:\MP3s\converted>"D:\audio\Audacity\Audacity.exe" -dounattended D:\MP3s\song.mp3

result:
D:\MP3s\converted\song.m4a is created with the user's default M4A options

notes:
the new file gets the old file's name with the extension changed to reflect the conversion
the complete path to Audacity must be specified as you do not want to be writing into your application directory
the fully qualified filename (complete with path and extension) must be used in the song name
without the -dounattended switch Audacity behaves as normal (except it will not nag to save an empty project)

to perform many of these conversions overnight create a script--either save it as a batch file and execute it or paste from a text editor into a CLI (I have tried pasting into a Win7 CommandLine and it does not work--using a batch file launches cmd.exe sequentially and works):

D:\MP3s\converted>"D:\audio\Audacity\Audacity.exe" -dounattended D:\MP3s\song1.mp3
D:\MP3s\converted>"D:\audio\Audacity\Audacity.exe" -dounattended D:\MP3s\song2.mp3
D:\MP3s\converted>"D:\audio\Audacity\Audacity.exe" -dounattended D:\MP3s\song3.mp3
------------------------------------------------------------------------------------------------------------
code changes are surrounded by pairs of comments with my initials:
//efm5
changed code
//efm5

below are all the changes with a few lines of context
line numbers below are approximations, correct to the SVN as of 20Aug2010
some of the reasoning is commented in the code,
some is described here


AudacityApp.h line #218:

Code: Select all
 public:
    DECLARE_EVENT_TABLE()
//efm5
// store the current working directory as it exists when Audacity is launched
//(it gets hijacked somewhere -- see Project.cpp line #758
private:
   wxString mCLIpath;
   void SetCLIpath(const wxString & CLIpath) {mCLIpath = CLIpath;};
public:
   const wxString & GetCLIpath() const {return mCLIpath;};
//efm5
};

extern AudacityApp & wxGetApp();


AudacityApp.cpp line #873:
Code: Select all
bool AudacityApp::OnInit()
{
//efm5
   SetCLIpath(wxGetCwd());
//efm5
#if defined(__WXGTK__)


project.h line #552
Code: Select all
 public:
    DECLARE_EVENT_TABLE()
//efm5
public:
   bool bStorageDirectorySet;//could use Get/Set() pair here
   void UnattendedCLIAction();
//efm5
};


Project.cpp line #719:
Code: Select all
AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id,
[...]
     mMenuClose(false),
     //efm5
     bDoUnattended(false)
     //efm5
{ //this is line #759
//efm5
   //note -- uncomment this to see that cwd has been hijacked by the time we get here as opposed to the real cwd from the cli (see AudacityApp.cpp line #875)
   //wxMessageBox(wxGetCwd());
   //AudacityApp & theApp = wxGetApp();
   //wxMessageBox(theApp.GetCLIpath());
//efm5


the next turns off "save project" if it has no tracks and
also if it is running unattended
Project.cpp line #1862:

Code: Select all
   if (event.CanVeto() && (mEmptyCanBeDirty || bHasTracks)) {
      if (mUndoManager.UnsavedChanges()) {
         //efm5
         if (!bDoUnattended) {
            wxString Message = _("Save changes before closing?");
            if( bHasTracks )
            {
               int result = wxMessageBox( Message,
                                         _("Save changes?"),
                                         wxYES_NO | wxCANCEL | wxICON_QUESTION,
                                         this);

               if (result == wxCANCEL || (result == wxYES && !Save()))
               {
                  event.Veto();
                  return;
               }
            }
         }//efm5
      }
   }
   
   ModuleManager::Dispatch(ProjectClosing);


this next adds a new commandline switch to Audacity: -dounattended
it tells Audacity to excercise the new function for unattended operation

AudacityApp.cpp line #1189

Code: Select all
        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
         if (!handled && !wxString(wxT("-dounattended")).CmpNoCase(argv[option])) {
            if (!project)
               project = CreateNewAudacityProject();
            project->bDoUnattended = true;
            handled = true;
         }
         //efm5

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

         if (!handled)
         {
            if (!project)
            {
               // Create new window for project
               project = CreateNewAudacityProject();
            }
            //efm5
            wxString tempFN(GetCLIpath());
            tempFN.Append(wxT("\\"));//must escape NEWLINE to compile
            tempFN.Append(argv[option]);
            project->OpenFile(tempFN);
            if (project->bDoUnattended)
            {
               wxSetWorkingDirectory(GetCLIpath());
               project->UnattendedCLIAction();
            }
            //efm5
            project = NULL; // don't reuse this project for other file
         }
      }                         // for option...


at this point we have a file opened in a project
the next step is to force the project to process (Export) the loaded file
I am going to import an MP3 file and Export it as an M4A
the export will be at my prefered Quality and will be stored in the CWD

Menus.h line# 180:

Code: Select all
void OnExport();
//efm5
void OnExport(const wxString & FormatType, const wxString & FileName);
//efm5
void OnExportSelection();


Menus.cpp line# 2944
Code: Select all
void AudacityProject::OnExport()
{
   Exporter e;

   e.Process(this, false, 0.0, mTracks->GetEndTime());
}

//efm5
void AudacityProject::OnExport(const wxString & FormatType, const wxString & FileName)
{
   Exporter e;
   e.Process(this, 2, FormatType, FileName, false, 0.0, mTracks->GetEndTime());
}
//efm5

void AudacityProject::OnExportSelection()


Project.h line# 552
Code: Select all
public:
   DECLARE_EVENT_TABLE()
//efm5
public:
   bool bDoUnattended;//could use Get/Set() pair here
   void UnattendedCLIAction();
//efm5
};

#endif


here is where we create our workflow
in this case I am exporting the file which was opened because it was passed as a CLI argument
I then tell Audacity to quit

Project.cpp line# 4551 (at end of file)

Code: Select all

void AudacityProject::UnattendedCLIAction()
{
   wxFileName fileName(GetFileName());
   wxString tempName(fileName.GetName());
   tempName.Append(wxT(".m4a"));
   OnExport(wxT("M4A"), tempName);
   OnExit();
}
Last edited by Edgar on Wed Feb 22, 2012 8:49 pm, edited 1 time in total.
-Edgar
compiling Audacity daily
64-bit Windows 7
Edgar
 
Posts: 1104
Joined: Thu Sep 03, 2009 9:13 pm

Re: Unattended command line processing

Permanent link to this post Posted by Edgar » Mon Aug 23, 2010 5:47 pm

Not having any comments, it appears there is little interest in unattended CLI processing at this time. Still, someone in the future might find this of interest so I will add this update.

The next step in this process is to make Audacity "invisible"; I want it to start with no GUI (no Project window) and never show a Progress Dialog. Here are the code changes (again, line numbers are only approximations as the SVN might have changed, I include a line or two before and after for context and wrap the affected code in
//efm5 start new
//efm5 end new
(note I have added start/end to the pair and "new" for this update):

Project.cpp line #504:
Code: Select all
  ModuleManager::Dispatch(ProjectInitialized);
   //efm5 start new
   AudacityApp & theApp = wxGetApp();
   bool dontShowIt = wxGetApp().GetDoUnattended();
   if (!dontShowIt)
      p->Show(true);
   else
      p->Show(false);
   //efm5 end
   return p;


ProgressDialog.cpp line #1195
Code: Select all
ProgressDialog::Show(bool show)
{
   if (!show)
   {
   [...]
   }

   //efm5 start new
   bool dontShowIt = wxGetApp().GetDoUnattended();
   return wxDialog::Show(!dontShowIt);
   //efm5 end new
}


I also found that in creating batch files I would occasionally have a typo in the file name resulting in a "failure to open..." MessageBox. These required human intervention so I also changed that:

Project.cpp line #2285 (note--2 affected sections):
Code: Select all
   wxString firstLine = wxT("AudacityProject");
   if (!::wxFileExists(fileName)) {
      //efm5 start new
      wxString outputMsg (_("Could not open file: ") + fileName);
      bool doingUnattended = wxGetApp().GetDoUnattended();
      if (!doingUnattended)
         wxMessageBox(outputMsg.c_str(),
                      _("Error opening file"),
                      wxOK | wxCENTRE, this);
      else {
         wcout << outputMsg.mb_str() << endl;
         wxGetApp().SetFileNameError(true);
      //efm5 end new
      }
      return;
   }

   wxFFile *ff = new wxFFile(fileName, wxT("rb"));
   if (!ff->IsOpened()) {
      //efm5 start new
      wxString outputMsg (_("Could not open file: ") + fileName);
      bool doingUnattended = wxGetApp().GetDoUnattended();
      if (!doingUnattended)
         wxMessageBox(outputMsg.c_str(),
                      _("Error opening file"),
                      wxOK | wxCENTRE, this);
      else {
         wcout << outputMsg.mb_str() << endl;
         wxGetApp().SetFileNameError(true);
      //efm5 end new
      }
   }
   char buf[16];


A typical batch file script might look something like:

Code: Select all
cd "D:\audio\KCEA\23Aug2010"
"D:\audio\Audacity\SVN\win\Unicode Release\Audacity.exe" -dounattended "D:\audio\KCEA\23Aug2010\Mon Aug 23 0928 2010.mp3" > errors.txt
"D:\audio\Audacity\SVN\win\Unicode Release\Audacity.exe" -dounattended "D:\audio\KCEA\23Aug2010\bogus name.mp3" >> errors.txt
"D:\audio\Audacity\SVN\win\Unicode Release\Audacity.exe" -dounattended "D:\audio\KCEA\23Aug2010\Mon Aug 23 0007 2010.mp3" >> errors.txt


which results in a file "errors.txt" containing:
Could not open file: D:\audio\KCEA\23Aug2010\bogus name.mp3
and in an empty saved file with no name as the result of trying to process no data. The next step is to add a check to eliminate this empty file when there is no data to process. Note in the above code that I am now setting a variable in the case of file errors and here is the code which supports this:

AudacityApp.h line #219:

Code: Select all
    DECLARE_EVENT_TABLE()
//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;
   void SetCLIpath(const wxString & CLIpath) {mCLIpath = CLIpath;};
   bool mbDoUnattended;
   bool mbFileNameError;
public:
   const wxString & GetCLIpath() const {return mCLIpath;};
   bool GetDoUnattended() const {return mbDoUnattended;};
   bool GetFileNameError() const {return mbFileNameError;};
   void SetFileNameError(bool error) {mbFileNameError = error;};
//efm5 end new
};

extern AudacityApp & wxGetApp();
-Edgar
compiling Audacity daily
64-bit Windows 7
Edgar
 
Posts: 1104
Joined: Thu Sep 03, 2009 9:13 pm

Re: Unattended command line processing

Permanent link to this post Posted by steve » Mon Aug 23, 2010 6:24 pm

Edgar wrote:Not having any comments, it appears there is little interest in unattended CLI processing at this time.

It's not a commonly sought feature, but it does come up from time to time, and for the people that are looking for this it is often of great importance.

If you have time it might be useful (primarily for the forum "elves") if you could post a short, non-technical summary so that we can direct people to this thread when it's appropriate. Is this topic specific to Windows, or would it perhaps be better on the "General Audio Programming" board?
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)
steve
Senior Forum Staff
 
Posts: 32946
Joined: Sat Dec 01, 2007 11:43 am

Re: Unattended command line processing

Permanent link to this post Posted by Edgar » Tue Aug 24, 2010 6:45 am

stevethefiddle wrote:
Edgar wrote:Not having any comments, it appears there is little interest in unattended CLI processing at this time.

It's not a commonly sought feature, but it does come up from time to time, and for the people that are looking for this it is often of great importance.

If you have time it might be useful (primarily for the forum "elves") if you could post a short, non-technical summary so that we can direct people to this thread when it's appropriate. Is this topic specific to Windows, or would it perhaps be better on the "General Audio Programming" board?


I think that everything I have done would work on Mac and Linux but I can only test Win7. Feel free to move it to where ever you deem appropriate (but kindly PM or email me if you do so so that I may monitor the thread).

short non-technical summary
Detailed specific steps for adding the needed code to Audacity's source which will allow Audacity to do unattended batch file processing as a background (non-GUI) process. Included is an example of converting many MP3 files into M4A files. Pretty much any series of menu commands can be coded; Nyquist effects would need to have the defaults changed/hard-coded to the user's choices; Audacity Preferences need to be established in advance. The ability to compile Audacity is required but I am willing to help out with that part.

Feel free to make the above summary a separate post with appropriate links, if desired.
-Edgar
compiling Audacity daily
64-bit Windows 7
Edgar
 
Posts: 1104
Joined: Thu Sep 03, 2009 9:13 pm

Re: Unattended command line processing

Permanent link to this post Posted by caseyd » Mon Feb 14, 2011 10:37 pm

Can you post the compiled version with the added command line processing feature?
caseyd
 
Posts: 2
Joined: Mon Feb 14, 2011 9:49 pm

Re: Unattended command line processing

Permanent link to this post Posted by Edgar » Mon Feb 14, 2011 11:49 pm

caseyd wrote:Can you post the compiled version with the added command line processing feature?


http://home.wavecable.com/~edgarmusgrove/index.html#UnattendedAudacity

This is not really intended for the user who is unfamiliar with the Audacity source code and C++ programming! When you run this app from the CLI there will be NO GUI you will have to watch for the command prompt to return to know it is finished. It is really intended for unattended batch processing (I set it running in a batch process with hundreds of file when I go to bed and all is finished in the AM).

If you have a specific need to perform the same effect on large numbers of files, give me some details and I will craft a specific version specifically for you (I will need to know EXACTLY which effects are in your Audacity executable directory's Plug-ins folder.
Edgar
 
Posts: 1104
Joined: Thu Sep 03, 2009 9:13 pm

Re: Unattended command line processing

Permanent link to this post Posted by Edgar » Thu Apr 21, 2011 5:23 am

I recently ported my changes to Linux (should now work on both Windows & Linux--I have no way to test on Mac) and moved up to revision 11014.

I zipped up the affected source files:
UnA2Linux.zip
(151.39 KiB) Downloaded 115 times


I changed the command line switches for clarity and added some new abilities:
-doTo3
-doTo4
-doSilenceProject
-doAmplify

if you call
audacity -doTo3 project.aup
(with the file names fully qualified) the project will open and the audio will be exported as an MP3 (-doTo4 exports as M4A).

[-ed] here are the folder locations for the files in the zip:
\src\AudacityApp.cpp
\src\AudacityApp.h
\src\Menus.cpp
\src\Menus.h
\src\Project.cpp
\src\Project.h
\src\effects\Amplify.cpp
\src\effects\Silence.h
\src\effects\nyquist\Nyquist.cpp
\src\widgets\ProgressDialog.cpp
\lib-src\libnyquist\nyquist\xlisp\xlread.c
Edgar
 
Posts: 1104
Joined: Thu Sep 03, 2009 9:13 pm

Re: Unattended command line processing

Permanent link to this post Posted by Edgar » Thu Apr 21, 2011 5:06 pm

I have posted new executables to play with (windows & Linux):
http://home.wavecable.com/~edgarmusgrove/#CompiledUnattendedAudacity
Edgar
 
Posts: 1104
Joined: Thu Sep 03, 2009 9:13 pm

Re: Unattended command line processing

Permanent link to this post Posted by sgparry » Sat Apr 30, 2011 11:22 pm

Not meaning to dismiss this whole command line processing idea, is it not possible to do all this unattended processing using mod-pipe-script? It is even possible (though tortuous) to drive audacity, via mod-pipe-script, from a Windows batch file rather than a perl script. Mod-pipe-script even works in 1.3.13 Beta without hacking the source and recompiling !!!
sgparry
 
Posts: 1
Joined: Sat Apr 30, 2011 11:14 pm

Re: Unattended command line processing

Permanent link to this post Posted by Edgar » Sun May 01, 2011 1:33 am

sgparry wrote:is it not possible to do all this unattended processing using mod-pipe-script?


In this thread on the audacity-users listserv (Feb 2010) http://audacity.238276.n2.nabble.com/mod-script-pipe-module-and-noise-reduction-td4596332.html Gale says:
Gale wrote:As far as I know, effects cannot be controlled by scripts yet.


On this page of the Audacity Manual http://manual.audacityteam.org/index.php?title=Scripting it says:
How to get started with scripting

Audacity 2.0 can only be used with scripting if you compile a separate plug-in module from SVN called mod-script-pipe. You'll also need the scripting language Perl to try out the examples. We may provide an already compiled mod-script-pipe some time after releasing Audacity 2.0. If you just want to use scripting but don't want to do the developer steps then you will need to wait for that to be released.

This document refers to the versions of Audacity and mod-script-pipe in SVN as of December 12th 2009. Our intention is to keep this document as up-to-date as possible on the wiki so that it continues to apply to latest builds of Audacity from SVN head.

Building
Ensure you have the latest SVN HEAD version of Audacity built and working. The scripting module, "mod-script-pipe" is in SVN (under lib-src), but is not built automatically.

In MSVC, right-click the mod-script-pipe project and select Build. If all goes to plan, the DLL will be placed in the "modules" directory.
Under GCC, move into the lib-src/mod-script-pipe directory and type "make". This will build the module and copy the ".so" to the modules directory.

[ToDo] Mac instructions here


Note there is no Mac support documentation and one must still do all the stuff of compiling Audacity then mod-script-pipe to try it.

From what I can tell, Dan Horgan is the author but I don't see any developer support for mod-script-pipe here on the forum.


@sgparry -- do you understand mod-script-pipe well enough to start a new thread and give the forum members a little tutorial and some support?
Edgar
 
Posts: 1104
Joined: Thu Sep 03, 2009 9:13 pm


Return to General Audio Programming



Who is online

Users browsing this forum: No registered users and 0 guests