Output text to file

Excellent, so we know this works on Mac and Linux.

Apparently (setdir) on Windows returns a string with "" as separators rather than “/”, so that’s something to watch out for.

What about documenting this?

Unfortunately Gale reports that (get-env “HOME”) does not work on Windows 7 X64.
http://bugzilla.audacityteam.org/show_bug.cgi?id=247

I think on Windows it needs to be (get-env “HOMEPATH”)

A standard Lisp trick is to use AND and OR as conditionals like this:

(let ((home-dir (or (get-env "HOME")
                    (get-env "HOMEPATH")
                    (get-env "UserProfile"))))
  (if home-dir
      (setdir home-dir)
      (error "HOME directory unspecified.")))

Plain english explanation:

If no “HOME” variable exists then get-env returns NIL and the “HOMEPATH” variable is checked. If no “HOMEPATH” variable exists then get-env returns NIL and the “UserProfile” variable is checked. If also no “UserProfile” variable exists, then home-dir is NIL and the if-construct raises an error. As soon as one of the get-env forms returns non-NIL, no further get-env form is evaluated, because Lisp’s “or” function is lazy and aborts the evaluation as soon as a non-NIL result has been found. This way you can easily test as many variables as you want.

On Windows we have to take into account that the path to the HOME directory may be stored in the registry and cannot be accessed by get-env at all.

I often work on Windows from external USB or Firewire drives, where the first thing I do is shadowing the Windows HOME variable by a value that points to a directory on my external drive. I never have met a situation where this didn’t work but I also never have tested if there had been a HOME variable defined by Windows itself before.

Don’t know if this is the best information source ever (there might be better info in the MS knowledge base):
http://en.wikipedia.org/wiki/Home_directory - Wikipedia “Home directory”

Here the probably last gimmick for today, a XLISP function to convert Windows to Unix filenames and vice versa:

(defun filename (string &optional win)
  (let* ((end (length string))
         (separator (if win "\" "/"))
         (separators (list #\ #/))
         (current-char  #Space)
         (previous-char #Space)
         (result ""))
    (dotimes (index end)
      (setq current-char (char string index))
      (if (member current-char separators)
          (unless (member previous-char separators)
            (setq result (strcat result separator)))
          (setq result (strcat result (string current-char))))
      (setq previous-char current-char))
    result))

Here is how it works:

(filename "c:\a\b\c")    => "c:/a/b/c"
(filename "c:/a/b/c" 'win)  => "c:\a\b\c"

The 'win argument can be anything except NIL, so you can also write t [Lisp symbol for “true”] instead of 'win:

(filename "c:/a/b/c" t)  => "c:\a\b\c"

The FILENAME function automatically de-messes filenames as it often happens if file and directory names get concatenated by string functions:

(filename "c:\/a\b//c")       => "c:/a/b/c"
(filename "c:\/a\b//c" 'win)  => "c:\a\b\c"

The FILENAME function can handle any number of backslahes greater than or equal to two, but fails with single backslashes, therefore the Lisp reader would need to be re-programmed [what is possible, but should be avoided]. So the following doesn’t work:

(filename "c:abc")  => c:abc

But “c:abc” in XLISP is an illegal filename anyway, the correct version would be “c:\a\b\c”, what can be handled without problems.

That works on XP-SP3 with the latest nightly build (Oct 18 2010), but it returns

\Documents and Settings<username>

without a drive letter.


Edit: XP version corrected. SP3, not SP2

POL

According to http://en.wikipedia.org/wiki/Home_directory the Windows “UserProfile” variable should work on all Windows Systems from Windows_2000 to Windows_7, so could please all Windows users, who read this, test the following code in the Audacity Nyquist prompt:

(print (get-env "UserProfile"))

The Windows HOMEPATH variable only works together with the Windows HOMEDRIVE variable, which returns the drive letter.

Thanks - edgar

(print (get-env “UserProfile”)) works on XP-SP3

POL

Preface: Thanks to Irish/Dublin for tireless testing…

After reading several hours about Windows %HOME% vs. %UserProfile% variables I got lots of contradictionary information. The average opinion seems to be that “%UserProfile%” means “C:Documents and settings”, while “%HOME%” means “C:Documents and settingsMy documents”. Even the Microsoft knowledge base contradicts itself, depending on the Windows Version. This was the reason why I wrote some additional test code.

Here is some more messy-looking but better-working code producing better results, working on all systems, not only on Windows:

(princ
  (format nil "~a~a~a~a"
    (format nil "HOME=~a~%" (or (get-env "HOME") "[No HOME variable]"))
    (let ((drive (get-env "HOMEDRIVE"))
          (path  (get-env "HOMEPATH")))
      (if (and drive path)
          (format nil "HOMEDRIVE+HOMEPATH=~a~a~%" drive path)
          (format nil "HOMEDRIVE=~a~%HOMEPATH=~a~%"
                      (or drive "[No HOMEDRIVE variable]")
                      (or path  "[No HOMEPATH variable]"))))
    (format nil "UserProfile=~a~%"
                (or (get-env "UserProfile") "[No UserProfile variable]"))
    (format nil "PATH=~a~%" (or (get-env "PATH") "[No PATH variable]"))))

If you copy the code into the Audacity Nyquist prompt text box and click the “OK” button, then the Nyquist code produces an Audacity text box with the following contents:

HOME=<path>
HOMEDRIVE+HOMEPATH=<path>
UserProfile=<path>
PATH=<path>

or if some variables do not exist on your system:

HOMEDRIVE=[No HOMEDRIVE variable]
HOMEPATH=[No HOMEPATH variable]

This will give the chance to compare Mac/Linux/Windows output and choose the best result. If you copy the code into the Nyquist prompt window and press “Debug” instead of “OK”, then you can copy the results with Ctrl+c out of the “Debug” window and paste them with Ctrl+v here into the forum.

The PATH variable is included because there seems to be no reliable way to identify an operation system via environment variables, but every operation system has a PATH variable, where the system’s search path for executable programs is stored. The search path contains system-specific patterns which could be used to identify the operation system.

Examples:

  • Only on Windows, PATH contains drive-letter patterns like “c:”.
  • On Windows, PATH elements are separated by semicolons, on Unix PATH elements are separated by colons.
  • Every operation system has system-specific directory names, e.g. the Unix “/home” directory on the Mac is called “/Users”

Any further ideas welcome.

Here is what the code from above tells me about my old Debian_5 (Lenny) box:

HOME=/home/edgar
HOMEDRIVE=[No HOMEDRIVE variable]
HOMEPATH=[No HOMEPATH variable]
UserProfile=[No UserProfile variable]
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games

P.S.: If you think that the Nyquist output contains “secret” information about your system you are free to delete whatever you want. Nobody may feel forced to participate in this test.

Ubuntu 10.10

HOME=/home/steve
HOMEDRIVE=[No HOMEDRIVE variable]
HOMEPATH=[No HOMEPATH variable]
UserProfile=[No UserProfile variable]
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

Audacity (Windows version) in WINE on Ubuntu 10.10

HOME=[No HOME variable]
HOMEDRIVE+HOMEPATH=C:userssteve
UserProfile=C:userssteve
PATH=C:windowssystem32;C:windows;C:windowssystem32wbem

Windows XP in VirtualBox on Ubuntu 10.10

HOME=[No HOME variable]
HOMEDRIVE+HOMEPATH=C:Documents and SettingsSteve
UserProfile=C:Documents and SettingsSteve
PATH=C:WINDOWSsystem32;C:WINDOWS;C:WINDOWSSystem32Wbem

Mac OS X 10.5 PPC

HOME=/Users/Bill
HOMEDRIVE=[No HOMEDRIVE variable]
HOMEPATH=[No HOMEPATH variable]
UserProfile=[No UserProfile variable]
PATH=/usr/bin:/bin:/usr/sbin:/sbin

– Bill

Sorry, I haven’t been keeping up with the thread, so just got around to trying this. In the terminal window, “env” returns a lot of stuff (some of which I’ve redacted):

MANPATH=/usr/share/man:/usr/local/share/man:/usr/X11/man
TERM_PROGRAM=Apple_Terminal
TERM=xterm-color
SHELL=/bin/bash
TMPDIR=/var/folders/5-/5-ACi0S52RWwp++kNLU2y++++TI/-Tmp-/
TERM_PROGRAM_VERSION=240.2
USER=Bill
COMMAND_MODE=unix2003
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin
PWD=/Users/Bill
LANG=en_CA.UTF-8
SHLVL=1
HOME=/Users/Bill
LOGNAME=Bill

Windows XP Pro - SP3

HOME=[No HOME variable]
HOMEDRIVE+HOMEPATH=C:Documents and Settings<username>
UserProfile=C:Documents and Settings<username>
PATH=C:WINDOWSsystem32;C:WINDOWS;C:WINDOWSSystem32Wbem;C:Program FilesCommon FilesRoxio SharedDLLShared;C:Program FilesWindows Imaging;

POL

@all

I’m just trying to write a Nyquist function to identify the operation system from the informations above, but this may still take some hours. We also would need more tests on Windows_Vista and Windows_7. I really (no joke) know nobody who works with Windoes_Vista or Windows_7.

@billw58

Please excuse the stupid questions, but it’s approx. five years ago that I have worked on a Mac every day. So I’m familiar with “general” things, but have forgotten lots of details.

The “~/Library/Application Support/audacity” directory is where the Audacit “plug-ins” directory etc. is located?

What exactly do you mean with “the directory that Audacity is installed in”? A Mac OS X “program” is a directory called “Audacity.app” with sudirectories, where the Audacity binary (the compiled and executable program code) is stored. Do you mean the directory where the “Audacity.app” directory is located (this is the directory, where e.g. in the Mac Finder the Audacity headphones logo appears) or do you mean the sub-directory inside the “Audacity.app” directory where the executable program is stored.

Maybe it works if you type in a terminal window “which audacity”, here is what happens on Debian:

bash$ which audacity
/usr/local/bin/audacity

I have looked in the Audacity C/C++ code to find information about the operation system and/or the directories, but everything seems to be determined at compile-time in the Makefiles or by built-in C/C++ Compiler constants, so I still have no idea how to determine the operation system or the plug-in directory at Audacity run-time from the informations in the Audacity code.

I would have no problems to ask on the Audacity developer lists (because I’m not a really good C/C++ programmer), but I would need more details what exactly to ask for, so the question is:

What information would you like to have or what is the goal you want to reach?

Thanks to all so far - edgar

“~/Library/Application Support/audacity” is where “audacity.cfg”, “plugins.cfg”, “ffmpeg_presets.xml” and “EQcurves.xml” are located as well as the “AutoSave”, “Chains”, and “presets” directories.

The Audacity application could be anywhere. Many users will just put it in the “Applications” directory. The “Languages”, “Nyquist” and “plug-ins” folders are in the same directory as the Audacity application. I put the Audacity application in a folder inside “Applications”, just to keep everything neat and tidy (.e.g “Audacity 1.3.13”, “Audacity 1.3.12”, etc).

I use the “Portable Settings” folder so that each version of Audacity has its own settings. In this case, everything that would normally go in “~/Library/Application Support/audacity” goes in the “Portable Settings” folder.

Yes, technically “Audacity.app” is a “package” that contains a lot of stuff, including the executable. But unless you right-click on the icon and do “Show Package Contents” you’ll never know this. So, yes, I’m looking for “the directory where the “Audacity.app” directory is located (this is the directory, where e.g. in the Mac Finder the Audacity headphones logo appears)”

Executing “(setdir “.”)” at the Nyqist prompt with my installation of 1.3.13 outputs “/Applications/Audacity 1.3.13”. So this would be a way to get to the Portable Settings folder if it was in use, as well as the “plug-ins” folder, and not coincidentally, “the directory where the “Audacity.app” directory is located”.

My goal is to find the “proper” directory to write stuff from a Nyquist effect, as I assume was the purpose of this thread (?).

So, on Mac, one could get to ~/Library/Application Support/audacity" by running your script, getting the “HOME” env variable value, then concatenating “/Library/Application Support/audacity” with it. In my case “/Users/Bill/Library/Application Support/audacity”. It would be nice to be able to test for the existence of the “Portable Settings” folder, and write to that directory instead of the Library… directory. “(setdir “.”)” will at least get you to the place where the “Portable Settings” folder would be if it existed.

Hope this helps.

– Bill

Yes, at least in the beginning (if I remember right)…

The point is that there are many different opinions what the “proper” directory would be, that’s why I need to find a “general” solution, where everyone can experiment with.

Example:

On Linux, most programs have the habit to create dot-files with configurations stuff in the user’s home directory, so my entire home directory is filled with that junk and I am busy for hours to make the programs write their stuff anywhere else. In other words I will instantly hate every plugin that writes files into my home directory, where I assume that other people hate other things, so there probably will be never a “general” solution that will make all people happy…

Some practical code examples to experiment with (Mac OS X only):

If (setdir “.”) retuns the Audacity directory on your machine, and the “Portable Settings” is a direct subdirectory of the Audacity directory, then a simple solution to check if the “Portable Settings” folder exists would look like this:

(defun cd-to-portable-settings-dir ()
  (let ((portable-dir (strcat (setdir ".") "/Portable Settings")))
    (setdir portable-dir)
    ;; if setdir succeeded, then (setdir ".") returns the portable-dir
    ;; if setdir failed, then (setdir ".") still returns the audacity-dir
    (string= (setdir ".") portable-dir)))

The “cd-to-portable-settings-dir” function returns non-NIL [= true] if the directory has been successfully changed, otherwise it returns NIL [= false], meaning that the “Portable Settings” directory has not been found.

A function to change to the “~/Library/Application Support/audacity” folder wold look very similar:

(defun cd-to-audacity-library-dir ()
  (let ((library-dir (strcat (get-env "HOME")
                             "/Library/Application Support/audacity")))
    (setdir library-dir)
    (string= (setdir ".") library-dir)))

Exactly the same game: The “cd-to-audacity-library-dir” function returns non-NIL [= true] if the directory has been successfully changed, otherwise it returns NIL [= false], meaning that the “~/Library/Application Support/audacity” directory has not been found.

There is no warranty that this will also work on other Macs and it will surely not work at all on Linux or Windows (but I think you know that).

Greetings - edgar

Thanks, Edgar, that was way more than I was expecting.

Back to the “general” case, it seems to me that Nyquist effects could safely write text files to the “Audacity application” directory (e.g. “/Applications” on Mac, or in my case “/Applications/Audacity 1.3.13”) or to the directory that contains the “audacity.cfg” file. Scanning through your examples, it seems you’ve found a way to determine what the OS is. Once you know that, you should be able to get to one of those two directories.

I’m not looking to do this myself anytime soon. It just seems to me that that was what everyone was trying to do :confused:

– Bill

This is unfortunately only true for single-user systems. In a multi-user system only the super-user (the “Administrator” in Windows terminology) has write access in the application directory. Only files in “/Users/” (in other words the user’s HOME directory and its subdirectories) can be written without super-user privileges. It’s of course possible to install Audacity in the user’s HOME directory but this is nearly never the case in professional environments.