Importing Libraries

Although Beat Link Trigger includes many useful libraries for things like working with MIDI and Open Sound Control, there are going to be situations where you would like to use something that isn’t already built in. To support that, there is now a mechanism that lets you dynamically load any Java (or Clojure, or other JVM language) library that you have locally on your machine (in the form of a Jar file or directory of classes), or that exists in a Maven repository on the Internet.

You need to be connected to the Internet the first time you try to load a library from a repository, but from then on it will be in your local Maven cache, so you will be able to access it even when offline.

For example, suppose you are building an integration where you want to be able to write out JSON files. BLT doesn’t include that ability out of the box, but there is a nice Clojure library, data.json, that offers it. Looking at the project page, we can see that it has a Leiningen dependency “coordinate” of [org.clojure/data.json "2.4.0"]. Leiningen is a very common tool for managing library dependencies in Clojure projects, and that format is what the BLT library loader uses as well. To make this library available, add this to the Shared Functions:

(add-library '[org.clojure/data.json "2.4.0"])
(require '[ :as json])

(The Leiningen coordinate needs to be preceded by a single quote mark for Clojure to parse it properly.) Assuming you are connected to the Internet, the first line will download the data.json library, and any libraries that it needs for its own use, and add them to the class path so your expressions can access them.

The second line loads the main namespace of the data.json library, and aliases it under the name json to make it more convenient for your expressions to call its functions.

At this point, your expressions can do things like:

(json/write-str {:a 1 :b 2})

Which returns a string holding the JSON representation of the Clojure map. See the library’s API documentation for more details.

If you want to add multiple libraries, you can call call add-library multiple times, or in a slightly more compact and efficient variation, call add-libraries instead and pass a vector of all the coordinates (put another set of square brackets around them), like so:

(add-libraries '[[org.clojure/data.json "2.4.0"]
                 [incanter "1.9.3"]])
(require '[ :as json])
(require '[incanter.core :as incanter])

Notice that you still need individual require statements for all the Clojure libraries you want to actually load and/or give short aliases to. Java libraries don’t need require statements but you might want to import some of their classes to save typing.

Adding libraries like this, while very powerful, is also fraught with peril. Beyond vetting that the library seems to be well-written and safe, and that your network connection is good the first time you try it, there are a number of scenarios in which add-library will not work, or will not work as you’d expect, because of the nature of JVM classloaders. If any of the jars you add provide conflicting versions of an existing Beat Link Trigger dependency, this will lead to very bad results. So when this works, it can let you add new features quickly, but if it doesn’t, ask for help from the Zulip chat community to see if there might be another library that would work better, or if the functionality you need can be safely incorporated in a future release.

If you need to load a dependency from a repository other than Clojars or Maven Central, you can tell add-library where to look by merging the description of your repository with the default repositories, like this:

(add-library '[com.mycompany/cool "0.0.1"]
             :repositories (merge default-repositories
                                  {"my repo name" ""}))

Of course you would replace the example repository name and URL with the actual name and URL of the repository you want to add.

Local Libraries

If you have a library already downloaded as a standalone Jar file (or directory hierarchy of class files and resources), you can use it by adding it to the Beat Link Trigger class path, like in this example:

(extend-classpath "/Users/james/git/wayang/wayang-0.1.7.jar")
In addition to the caveats described above about adding libraries in general, the low-level extend-classpath function doesn’t give you any feedback if the path you entered for the file or directory is incorrect; you will simply not find the library classes you were hoping would be available when your code tries to use them.