uSeq

It’s been a loong while since I last posted and I’ve been getting back into coding and music, the intersection of which got me into EE and CompSci way back in the early 2000s.

Common Lisp was the language of CLM and other software synthesis that attracted me at the time with fantasies of studying at Stanford’s CCRMA lab and the LaBRI Institute.

Nowadays there are new options like Incudine and OpusModus, which continue that direction and give me hope that I can continue to experiment with software based composition.

Lately I’ve been spending my days studying and practicing on an old studio piano as well as building a modest Eurorack DIY modular synth setup.

A kit popped up over at Thonk for a “livecoding” module called “uSeq” by Emute Labs, which is connected to the University of Sussex Experimental Music Lab.  It uses a Lisp dialect (uLisp) as a means to program the module using their own DSL called ModuLisp. There is even a published paper written that discusses livecoding with this tool.

The kit as sold by Thonk

The kit comes with everything you need to assemble the module minus a soldering iron, solder, and about 1/2 an hour of time.  There are two SMD switches, but other than it’s all through hole components.  They have a great build guide here and there is also a prebuilt version if you’d prefer to rack it up and go.

Soldered with Kestler no clean 60/40 solder
Installed and testing the blinkenlights.

The soldering went well and everything fired up on first go.  The 10 LEDs lit up in circling sequence and it showed up as a USB device on my Gentoo Linux host running realtime Linux Kernel 6.6.36. Here is the output of dmesg:

[646594.147296] usb 1-3: new full-speed USB device number 6 using xhci_hcd
[646594.295794] usb 1-3: New USB device found, idVendor=2e8a, idProduct=f00a, bcdDevice= 1.00
[646594.295812] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[646594.295820] usb 1-3: Product: RP2040
[646594.295825] usb 1-3: Manufacturer: Generic
[646594.295830] usb 1-3: SerialNumber: E463B013DB56402B
[646594.332211] cdc_acm 1-3:1.0: ttyACM0: USB ACM device
[646594.332284] usbcore: registered new interface driver cdc_acm
[646594.332291] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters

The bolded text “ttyACM0” is the device name for connecting to this new USB connection via the device file /dev/ttyACM0. The issue is that the permissions on that file did not allow my user to open the device:

elliott@deph ~ $ ls -al /dev/ttyACM0
crw-rw---- 1 root dialout 166, 0 Aug 4 04:22 /dev/ttyACM0

The OS is assigning the Rasberry Pi 2040 chip on uSeq as a communications device (like modems) rather than a USB serial device and so it assigns the “dialout” group and root user. If I’d like to connect to the device, I’ll need to either join that group or change permissions. I decided to change the permissions and the best way to do that is by setting up a udev rule. Here is what I added:

elliott@deph ~ $ cat /etc/udev/rules.d/50-useq.rules
SUBSYSTEMS=="usb"
ATTRS{idVendor}=="2e8a"
ATTRS{idProduct}=="f00a"
GROUP="audio"
MODE="0660"

The idVendor and idProduct were from dmesg output above, but also can be found by doing a lsusb -vvv to see all the details of the device. I have the “audio” group setup, my user configured to use it, and I changed the permissions to “0660” to ensure read/write access to that group as well as the root user. The udev rules were reloaded and the cable replugged back in to complete the permissions adjustment.

elliott@deph ~ $ ls -al /dev/ttyACM0
crw-rw---- 1 root audio 166, 0 Aug 4 04:22 /dev/ttyACM0

Now that we have a device and it’s attached, we can connect to it via a serial console emulator app. Luckily Emacs has built in methods and it was quick to load serial-term mode and connect to the device with an “9600 baud 8N1” connection rate using line-mode.

All this went flawlessly and I was soon issuing ModuLisp commands to the uSeq module to get reoccurring patterns on the analog outputs. Looking at the code it’s apparent that there is a python interface (useqedit) and I believe a SuperCollider interface here. The easiest method of connecting with uSeq is the webbased interface and it works well.

Over the next few weeks I’d like to go over the current state of the development environment, commands, and other aspects about using this module towards doing some livecoded audio.

quicklisp and clsql-fluid

This is a tech post and the intended audience is the few people who will bash their heads against a piece of software until it gets installed. I’ve just gone through one of these “sessions”, so I thought I’d document it here for the next person.

Zach Beane created quicklisp, which is a great way to load up common lisp libraries without a headache.

To give an example of this, to load my favorite web programming framework, all I need to do is type the following: (ql:quickload 'weblocks)

It loads everything I need and I can instantly get started working. Very cool! Now after a bit of programming I find that I’d like to customise the storage layer to use a mysql database, but that’s when it gets hairy…

First of all, weblocks’ clsql interface depends on clsql-fluid, which as a project doesn’t package anything… so this doesn’t give quicklisp an opportunity to distribute it. I guess someone could make a package, but I assume Zach would like to have the project maintainers do this instead of himself.

Secondly quicklisp already had installed the clsql library for me and I couldn’t find a command to remove it. So after looking through the documentation and the source I went and deleted things under my quicklisp directory (and ~/.cache) to remove quicklisp’s version of clsql. A remove command in quicklisp would be a nice touch. It would also be nice to get some like functionality for quicklisp in managing software beyond installing & searching. Maybe Zach already has plans for these for when the code goes out of beta…

Thirdly, I fetched clsql-fluid as described on the website and linked it in and loaded it up… but got errors:

"The name NIL does not designate any package."

What is happening here is that clsql-uffi tests that it’s properly loaded by looking for a defined symbol (atol64) to have an associated function. If that function doesn’t exist then we havn’t loaded the foreign libraries and therefore haven’t successfully loaded. The problem with this is that the clsql-uffi package doesn’t exist yet, so we get the error when the test code tries to (find-package #:clsql-uffi).

Since this test is a predicate of sorts I decided that instead of erroring it should just return nil, so I wrapped those probing statements in an: (ignore-errors ...) statement. Once I’d done this it allowed me to get to the next level of errors :)

Fourthly, the syntax used in the uffi calls seems different than what the uffi installed via quicklisp expects. After getting beyond the “nil package” problem above, I encountered this error:

caught ERROR:
; (in macroexpansion of (UFFI:CONVERT-FROM-FOREIGN-STRING CHAR-PTR
:LOCALE ...))
; (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
; error while parsing arguments to DEFMACRO CONVERT-FROM-FOREIGN-STRING:
; unknown keyword: :LOCALE; expected one of :NULL-TERMINATED-P,
:LENGTH

After looking around a bit I got the tip that cffi-uffi-compat might be more compatible than quicklisp’s version of uffi, so I edited clsq.asd, clsql-mysql.asd, clsql-uffi.asd, and uffi/clsql-uffi-package.lisp and edited them to use the uffi compatibility layer from cffi. After all that was done I did another (ql:quickload 'clsql-mysql) and the clsql-fluid version loaded. whew

I hope this helps others stuck in a similar situation and here is the result of a git diff in the root of the clsql-fluid source:

diff --git a/clsql-mysql.asd b/clsql-mysql.asd
index a176f85..1263457 100644
--- a/clsql-mysql.asd
+++ b/clsql-mysql.asd
@@ -20,8 +20,8 @@
 (in-package #:clsql-mysql-system)
 
 (eval-when (:compile-toplevel :load-toplevel :execute)
-  (unless (find-package 'uffi)
-    (asdf:operate 'asdf:load-op 'uffi)))
+  (unless (find-package 'cffi-uffi-compat)
+    (asdf:operate 'asdf:load-op 'cffi-uffi-compat)))
 
 (defvar *library-file-dir* (append (pathname-directory *load-truename*)
                                   (list "db-mysql")))
@@ -48,8 +48,8 @@
   t)
 
 (defmethod operation-done-p ((o load-op) (c clsql-mysql-source-file))
-  (and (symbol-function (intern (symbol-name '#:mysql-get-client-info)
-                               (find-package '#:mysql)))
+  (and (ignore-errors (symbol-function (intern (symbol-name '#:mysql-get-client-info)
+                                              (find-package '#:mysql))))
        t)) 
 
 (defmethod perform ((o compile-op) (c clsql-mysql-source-file))
@@ -80,7 +80,7 @@
   :description "Common Lisp SQL MySQL Driver"
   :long-description "cl-sql-mysql package provides a database driver to the MySQL database system."
 
-  :depends-on (uffi clsql clsql-uffi)
+  :depends-on (cffi-uffi-compat clsql clsql-uffi)
   :components
diff --git a/clsql-mysql.asd b/clsql-mysql.asd
index a176f85..1263457 100644
--- a/clsql-mysql.asd
+++ b/clsql-mysql.asd
@@ -20,8 +20,8 @@
 (in-package #:clsql-mysql-system)
 
 (eval-when (:compile-toplevel :load-toplevel :execute)
-  (unless (find-package 'uffi)
-    (asdf:operate 'asdf:load-op 'uffi)))
+  (unless (find-package 'cffi-uffi-compat)
+    (asdf:operate 'asdf:load-op 'cffi-uffi-compat)))
 
 (defvar *library-file-dir* (append (pathname-directory *load-truename*)
                                   (list "db-mysql")))
@@ -48,8 +48,8 @@
   t)
 
 (defmethod operation-done-p ((o load-op) (c clsql-mysql-source-file))
-  (and (symbol-function (intern (symbol-name '#:mysql-get-client-info)
-                               (find-package '#:mysql)))
+  (and (ignore-errors (symbol-function (intern (symbol-name '#:mysql-get-client-info)
+                                              (find-package '#:mysql))))
        t)) 
 
 (defmethod perform ((o compile-op) (c clsql-mysql-source-file))
@@ -80,7 +80,7 @@
   :description "Common Lisp SQL MySQL Driver"
   :long-description "cl-sql-mysql package provides a database driver to the MySQL database system."
 
-  :depends-on (uffi clsql clsql-uffi)
+  :depends-on (cffi-uffi-compat clsql clsql-uffi)
   :components
   ((:module :db-mysql
            :components
diff --git a/clsql-uffi.asd b/clsql-uffi.asd
index e5a75f6..e78f09e 100644
--- a/clsql-uffi.asd
+++ b/clsql-uffi.asd
@@ -50,8 +50,8 @@
   nil) ;;; library will be loaded by a loader file
 
 (defmethod operation-done-p ((o load-op) (c clsql-uffi-source-file))
-  (and (symbol-function (intern (symbol-name '#:atol64)
-                               (find-package '#:clsql-uffi)))
+  (and (ignore-errors (symbol-function (intern (symbol-name '#:atol64)
+                                              (find-package '#:clsql-uffi))))
        t))
 
 (defmethod perform ((o compile-op) (c clsql-uffi-source-file))
@@ -79,7 +79,7 @@
   :description "Common UFFI Helper functions for Common Lisp SQL Interface Library"
   :long-description "cl-sql-uffi package provides common helper functions using the UFFI for the CLSQL package."
 
-  :depends-on (uffi clsql)
+  :depends-on (cffi-uffi-compat clsql)
 
   :components
   ((:module :uffi
diff --git a/clsql.asd b/clsql.asd
index 35e172a..51da309 100644
--- a/clsql.asd
+++ b/clsql.asd
@@ -26,8 +26,8 @@
 
 ;; need to load uffi for below perform :after method
 (eval-when (:compile-toplevel :load-toplevel :execute)
-  (unless (find-package 'uffi)
-    (asdf:operate 'asdf:load-op 'uffi)))
+  (unless (find-package 'cffi-uffi-compat)
+    (asdf:operate 'asdf:load-op 'cffi-uffi-compat)))
 
 (defsystem clsql
     :name "CLSQL"
diff --git a/uffi/clsql-uffi-package.lisp b/uffi/clsql-uffi-package.lisp
index be5abf5..153ca1f 100644
--- a/uffi/clsql-uffi-package.lisp
+++ b/uffi/clsql-uffi-package.lisp
@@ -19,7 +19,7 @@
 (in-package #:cl-user)
 
 (defpackage #:clsql-uffi
-  (:use #:cl #:uffi)
+  (:use #:cl #:cffi-uffi-compat)
   (:export
    #:find-and-load-foreign-library
    #:canonicalize-type-list

Franz mentioned on Dr Dobbs site

A lot of people ask about my day job at Franz and I usually have a rehearsed answer that goes something like this:

We work on a version of a programming language called Common Lisp and we have built tools on top of it. One of these tools is a database useful for studying complex data sets.

It would be cool to say something like “twitter” or “vimeo” and have instant recognition of my area of work, but with Franz you get a puzzled look and usually 10 minutes of back and forth to properly describe what we do.

With that confusion in mind I jumped to read this Dr. Dobbs interview with our CEO, Jans. I think to the technical people out there, some of this will make sense:

Dr. Dobbs interview with Jans Aasman of Franz Inc

Updating the Canon 5d MII firmware under linux

I just grabbed the 2.0.4 version of the Canon 5d Mark II firmware and these are the steps it took to install it using GNU/Linux.

  1. Fetch the Mac OS X dmg version of the firmware
  2. Install dmg2img
  3. Convert the DMG to an IMG file
    dmg2img eos5d2204.dmg
  4. mount it temporarily
    mount -t hfs -o loop eos5d2204.dmg /mnt/tmp
  5. insert a CF card and note where it’s mounted
  6. Copy it to the card:
    cp /mnt/tmp/5d200204.fir /path/to/CF/card

See linux is easy ;)

Actually, would it be a pain for Canon to just release the firmware in a zip file? I’d think that would work for everybody, but I’m guessing that they are relying on a possible built in checksumming in a DMG and their exe files? I’m not sure about the checksum, but that would make sense.

For those curious, here is the sha256 checksum of the 5d200204.fir file the above process created:

424b1990b52af12748f9675c2085e58949ac3fc682b1e61717c2218f89cdd149  5d200204.fir

The new firmware adds a bunch more features to the video feature set of the camera, including various frame rate options. For more info see canon’s site.

Encoding 5d mII video

The 5d mark II shoots rather high quality videos. Using ffmpeg it’s possible to view the specifics of the original file during encoding. For my example file I’ve been seeing the following:

  Duration: 00:02:24.50, start: 0.000000, bitrate: 41087 kb/s
    Stream #0.0(eng): Video: h264, yuv420p, 1920x1088, 39674 kb/s, 30 fps, 30 tbr, 3k tbn, 6k tbc
    Stream #0.1(eng): Audio: pcm_s16le, 44100 Hz, 2 channels, s16, 1411 kb/s

This shows the two parts of the file’s stream (#0.0 and #0.1) are divided between video (#0.0) and audio (#0.1). The video part is encoded using the h264 codec, which is a nice high quality / highly compressed video codec with a bit rate of 39,674Kb/s, so close to 40Mb/s. The audio is also a fairly high quality capture, using the uncompressed, 16bit (bit depth), little-endian, PCM format at a fairly high rate of 1,411Kb/s.

Recently I wanted to post up some videos I took of Niilo Smeds playing and the above clip is 2:24 seconds worth of video, which consumes 708Mb (yes ~one CD-R worth of data). This makes uploading to a free Vimeo account rather difficult due to the 500Mb per week limit.

I’ve turned to recoding the videos to a lower bit rate so that I can post and have the knowledge that I still have the original 1080p version to play with more later.

I found that mp4 was one of the few container formats that I could easily convert to from videos using the older firmware (that I’m currently upgrading). The older firmware captured at exactly 30 frames per second (not 29.97/sec), which seems to cause havoc for other container formats (like mpeg), but mp4 seems to be quite happy. I’m interested to see if the newer firmware, which allows some choice in frame rate will allow for converting to other containers or if the problem is actually localized to the open source libraries that are used for conversion.

For audio I would have liked to use the original audio (I am recording a guitar player after all) and there is the -acodec copy option to ffmpeg, but again the mp4 container format didn’t like the raw pcm audio. Instead I chose MP2, which didn’t have as much sound degradation as MP3.

After much playing with options my simple script to encode videos from the 5dMII for Vimeo is as follows:

#!/bin/bash

# Copyright Elliott Johnson 2010
# Distributed under the GPL-3.0
#    http://www.gnu.org/licenses/gpl.html

# For encoding video from my 5D into a high quality,
# small file format suitable for vimeo.

THREADS=7 # tune this to your number of execution units - 1

function help() {
  echo "$0: infilename outfilename"
}

INPUTFILE=$1
OUTPUTFILE=$2

ffmpeg -i $INPUTFILE \
       -b 14515.5kb \
       -s 960x544 \
       -r 30 \
       -threads $THREADS \
       -acodec mp2 \
       -ab 256kb \
       -ac 2 \
       $OUTPUTFILE

The joys of pdf conversion

As part of the oacdp I convert a sections of manuals into pdfs.  I’ve been using imagemagick for a while to batch convert. To take any number of images and convert them to a single pdf it’s a simple one line command:

convert *.png -density 100% some.pdf

An annoying feature of imagemagick is that it pulls all the images (in the above case the png files) into memory, converts them in memory to a 16bit (per color channel) representation and then when it’s all assembled writes the content out to disk. Normally this isn’t too bad since I’ve got 6Gigs of memory and 12Gigs of swap and if it takes 3Gigs to process one document I can deal with it.

In working on a type1 manual, the 8th section is 317 images I found it impossible to deal with. I enlarged the amount of swap space, but the load on my system would rise above 15 and eventually the process or my machine would crash.

Andrew Whitlock, who was the previous maintainer of the oacdp confirmed that this happened to him in the past and that he had swapped over to a windows machine to use some application with a reasonable algorithm to convert to PDF. I on the other hand don’t have a windows install, so I began researching online.

Firstly in digging around I found an imagemagick based project called graphicsmagick that is written specifically for multi-core machines like I have. I tried this out, but it uses similar algorithms as imagemagick for processing PDF’s, so really wasn’t an answer, but was an improvement in processing times… it basically made things crash faster.

A little more searching revealed this thread, which describes converting each image to individual pdf’s and then assembling them using pdfjoin of the like. pdfjoin is fast, only taking a handful of seconds to process all 317 pages using pdflatex. The results are what I’d expect imagemagick could do.

It would be nice if imagemagick would get their pdf processing up to snuff, but at least for now I have a work around. Hopefully this can help some other people convering pdf’s using command line tools like imagemagick/graphicsmagick/pdfjoin.

Akismet

After having this blog up for a month or two it’s been around long enough for bots to locate the comment sections.  When I get legitimate comments I get a notification on my phone, so it’s been pretty noisy with spam emails.  Funny thing that while watching the President on TV being spammed during a town hall by some wing nut I happened to get three in a row.  It’s interesting the similarity of the tactics of spammers and the ultra-right extremists.  BTW – Did you know that the President is a Kenyan and needs your help in depositing $1billion into your bank account?

I noticed that Akismet, one of WordPress’ default plugins was designed to control spam.  Fully setting it up involved signing up for a wordpress account and copy and pasting in the API identifier that is associated with my account.  Pretty easy.  Since last night it’s already classified about 10 bogus comments and saved me from being bothered.  Well worth the 20 seconds of setup time.

Thanks Akismet and WordPress devs!