Checking the Audacity version from a Nyquist script

Given that new versions of Audacity support many new features for Nyquist plug-ins that are not supported by old versions of Audacity, it can be useful to include a test in new public plug-ins to ensure that the version of Audacity is recent enough to run the plug-in correctly.

As of Audacity 2.1.0, there is a property list for the variable AUDACITY, which includes the Audacity version. See: https://wiki.audacityteam.org/wiki/Nyquist_Plug-ins_Reference#.2AAUDACITY.2A

Here’s a code snippet for testing that the script is running on a version of Audacity that is the same as, or later than the required version. In this example, the required version is 2.1.1

(defun versioncheck(minversion)
  ;; 'minversion' is the required minimum version as
  ;; a list of three integers.
  ;; Return true if current version >= 'minversion'
  (if (or (not (listp minversion))
          (/= (length minversion) 3))
      nil
      (prog ((v (get '*audacity* 'version)))
        (when (not v)
          (return nil))
        (mapc (lambda (x)
                (when (not (integerp x))
                  (error "list of 3 integers required")))
              minversion)
        (mapc (lambda (required actual)
                (when (> required actual)
                  (return nil))
                (when (< required actual)
                  (return t)))
                minversion v)
        (return t))))

;Test it
(if (versioncheck (list 2 1 1))
    (print "Pass")
    (print "Fail"))

A shorter version of this function, which assumes that the “minversion” argument is properly formatted as (list int int int):

(defun versioncheck (minversion)
  (prog ((v (get '*audacity* 'version)))
    (when (not v)
      (return nil))
    (mapc (lambda (required actual)
            (when (> required actual)
              (return nil))
            (when (< required actual)
              (return t)))
            minversion v)
    (return t)))

How it works:

As you will see, this function is only suitable for plug-ins designed to run on Audacity 2.1.0 or later.

Audacity version numbers use a form of “Semantic versioning”. That is, the version number uses a sequence of three integers (Major.Minor.Revision)
(get 'audacity 'version) returns the Audacity version number as a list of 3 integers: major, minor, revision. This feature was added in Audacity 2.1.0, so for earlier version, it will return NIL.

For brevity, the variable “v” is assigned the value returned by (get 'audacity 'version). This is set at the top of a PROG (program) block, so that we are able to escape out of the block, and thus escape out of the function using RETURN.

Firstly we check that v is not NIL. If it is NIL, versioncheck returns NIL (Fail. The Audacity version is older than 2.1.0)

Then we use MAPC to apply a lambda expression to each successive item in the lists “minversion” and “v”. Ignoring the RETURN statements for a moment, MAPC would attempt to run the lambda with the first term from each list, then the second term from each list, and so on.

A LISP lambda expression is much like a LISP function, except that functions always have a name, and lambdas don’t have a name.
If it were a function, it would look like:

(defun function-name (required actual)
  (when (> required actual)
    (return nil))
  (when (< required actual)
    (return t)))

but as a lambda expression:

(lambda (required actual)
  (when (> required actual)
    (return nil))
  (when (< required actual)
    (return t)))

As MAPC loops through the two lists, each pair of values (“required” and “actual”) are tested:

  • If the required value is greater than the actual value, we bail immediately from versioncheck, returning NIL (False / fail).
  • If the required value is less than the actual value, we bail immediately from versioncheck, returning T (True / pass).
  • If the required value is equal to the actual value, we do nothing, allowing MAPC to move onto the next pair of values.

If MAPC completes the lists, then each item in the “minversion” must be equal to the corresponding item in the “(get 'audacity 'version)” list, so the final line in the PROG block returns T (True / pass), which is the final value returned by versioncheck.