// blog

Stanton QuickGrid (Part 1)

Posted 2020-10-27. Permalink. Tagged 2010s, freebsd, linux, music, screenshot, scs4dj, software.

Screenshot of the Stanton QuickGrid 1.20.2 graphical frontend

Intro & Problem

Stanton QuickGrid is an audio file analysis program for Mac OS X and Windows distributed with the Stanton SCS.4DJ. It creates metadata files that contain things like the waveform graphic and beat grid indicators for use with the SCS.4DJ device. It's a program in two parts: djanalyze.exe which does the work of generating metadata for one audio file, and the graphical frontend (pictured above) which automates the process for many audio files. QuickGrid performs a similar function to, say, Rekordbox's analysis and export to USB.

It works in two stages. First you "analyze tracks" which creates and stores analysis metadata files for audio in a location you specify. Then you "prepare USB device" which crawls a USB drive looking for audio and copies over the relevant analysis metadata files, and also creates a file called hashes.dat on the USB drive which the SCS.4DJ reads to discover new data.

I have a problem with QuickGrid: I don't run either OS X or Windows. So I worked out what the graphical frontend is doing and how to drive djanalyze.exe using Wine. Then I wrote a shell script to automate the process. Some notes on what I found:


Let's take a look at djanalyze.exe's help output:

$ wine "C:\Program Files\Stanton\djanalyze.exe" "--help"

usage: djanalyze audioFileName rootFolder songId
       djanalyze --version
       djanalyze --error-code
       djanalyze --help

example: djanalyze "e:\audio.mp3" "e:" "FE66E7B1E7D1C4B8AAA2FD5BB8B71A39"

audioFileName is the full path to one audio file. rootFolder is the path where you want djanalyze to write its metadata files. songId is the md5 hash of the audio file, and will be used as the filename of the resulting metadata files. All paths are in DOS format. Wine provides a Z:\ drive that maps to the Unix root directory, so we can access any path we want that way. It's easy to get the md5 hash of a file when running any modern Unix-like operating system; I used FreeBSD's md5(1).

File Structure

Another piece of the puzzle is the file structure the SCS.4DJ expects on USB drives:

$ ls /USB_Drive
$ ls /USB_Drive/SCS.4DJ_Database
$ ls /USB_Drive/SCS.4DJ_Database/analysis
... 256 two-character directories, 00 thru ff, named for the first
... two hex digits of the MD5 hash of the audio file the analysis
... files within relate to.

SCS.4DJ_Database is what we're interested in. hashes.dat is found here, as well as Stanton_DJ_DB.db (an SQLite database we won't be getting into today). SCS.4DJ_Database/analysis is where the device looks for metadata files (in subdirectories named after the first two characters of the md5 hash of the audio file).

djanalyze.exe will create some of this tree itself, however for me it creates a directory called SCS.8DJ_Database rather than the expected SCS.4DJ_Database, something to remember when we script this process. (Perhaps it's creating .8 instead of .4 because it couldn't find an existing .4 directory?)


hashes.dat is a plaintext file that the SCS.4DJ device reads when a USB drive is inserted into the device. It contains data on new tracks that the device should import. The first line of hashes.dat must be "Hash Helper v1". Subsequent lines each represent one audio file and are split into five tab-separated fields; here's the field order and contents:

  1. Filename (no escape characters, regular Unix path, from the USB drive root).
  2. MD5 Hash of file at Filename.
  3. st_atime (time when Filename was last accessed).
  4. st_size (Filename's size in bytes).
  5. 0 (the character "0"; I don't know what this field is used for).

st_atime and st_size can both be easily retrieved in a shell script using for example FreeBSD's stat(1).

Script Outline & Closing

I wrote a script that copies both the audio files and metadata files to the USB drive at the same time instead of duplicating QuickGrid's two-stage approach. (My script "adds" music to a USB drive with the necessary additional files; you use it instead of your file manager to copy music over).

The order of operations is, roughly: call djanalyze.exe to generate metadata files in a temporary location for audio file X, then copy audio file X to the USB drive, then move the new metadata files to the USB drive, then add an entry to hashes.dat describing the new audio file (creating hashes.dat if necessary).

The information above should be enough for a savvy reader to script their own replacement for QuickGrid, I hope. I have another post on this topic in the works, Stanton QuickGrid (Part 2), where I'll show and explain a simplified version of my own script.

Mednafen 1.22.2's Joystick Detection and FreeBSD 12

Posted 2020-01-07. Permalink. Tagged freebsd, hardware, photo, software, video games.

Photo of a gamepad next to the game Wipeout XL

A few days ago I bought a Logitech F310 gamepad at my local thrift store. FreeBSD detected it immediately and created the appropriate uhid entry in /dev. SDL2 also saw the gamepad, which I was able to verify with Joytran. The Mednafen game console emulator did not see the device, however. Here's why:

Mednafen 1.22.2 supports three different joystick backends: Linux event devices (evdev), SDL2, and MS Windows DirectInput / XInput devices. The backend is selected when the autoconf ./configure script is run, and then that backend selection is compiled into the Mednafen binary (see the ifdef statement at line 178 in src/drivers/Joystick.cpp).

Mednafen's autoconf script selects the evdev backend if it finds the file linux/joystick.h in the header search path. The FreeBSD port devel/evdev-proto installs that joystick.h header file. So, if you have evdev-proto installed (it's required by x11-toolkits/qt5-gui) and then compile emulators/mednafen it will use evdev and not SDL2 for its joystick support.

I worked around this by commenting out parts of src/drivers/Joystick.cpp (again around line 178) to force Mednafen to use SDL2 for joysticks. I should probably post on FreeBSD's bug tracker; could submit a patch too, it's simple enough.

This whole situation is definitely a corner case. The joystick backend selection in Mednafen could be better, but I'm also doing something a little unusual here.

Posting because this took me hours to figure out, and so I'll remember next time I encounter this problem.