July 18, 2009
In which I reverse-engineer the HammerHead HUB file format.
Back in the day I used to use a freeware Windows drum machine called HammerHead. It was pretty simple but more or less did the trick.

It came with some built-in drum sounds. You could also load custom sounds, but the support for this was limited. Sounds could only be loaded from special files called HUBs (for HammerHead User Bank). Each HUB stored 6 sounds. You could only load 1 HUB at a time, so if you wanted mix and match sounds from different HUBs you were out of luck.

While going through some old files I stumbled onto my old collection of HUBs. Although I hadn’t used them or HammerHead in years, I decided to see if I could reverse-engineer the file format to extract the sounds into individual wave files. This would let me use the liberated sounds in modern programs like Logic or GarageBand.
I was successful, and the end result is a (very short) Ruby program called Clawhammer. I’m not sure how many other people will have a use for it, but I am documenting it here for the historical record.
At the command line, run clawhammer.rb and specify the path to the HUB file as an argument.
ruby clawhammer.rb mybank.hub
Afterward, 6 new wave files will be created in the current working directory, one for each sound in the HUB. For example, running the command above would result in the following 6 files being created:
mybank-1.wav
mybank-2.wav
mybank-3.wav
mybank-4.wav
mybank-5.wav
mybank-6.wav
Clawhammer uses the WaveFile gem to create the output wave files. Therefore, you will need to have the gem installed on your machine. To do so, run the following command:
sudo gem install wavefile
I used the following tools to figure it out:
Educated guesses based on my knowledge of the Wave file format.
A utility program for creating custom HUBs that comes with HammerHead. This allowed me to make guesses about the format and then test them out using custom HUBs. For example, I guessed that the size of each sound was stored somewhere in each file. Using the tool, I could create a custom HUB where each sound had a known size, such as 10,000 bytes. I could then search the resulting file for the number 10,000, which would likely indicate the location (and presence) of the size field.
A utility program I wrote called FileInspector. It is essentially a command-line hex viewer, but has better support for viewing data in numeric formats than other hex viewers I’ve seen. I wouldn’t be surprised if there are other tools out there that do the same thing, but I couldn’t find them on the web so I just wrote it myself. Perhaps one day I will blog about it.
Going back to our example of the size field - although I figured it was stored in the file somewhere, I didn’t know the numerical format. It could be 2 bytes or 4 bytes long, be signed or unsigned, etc. FileInspector let me view the file data in different numerical formats side-by-side, allowing me to test guesses more quickly.
Good old trial-and-error.
And now for the results! The file format is very simple. The data for each sound consists of a 36 byte header, followed by the sound’s raw sample data. 6 pairs of header/sample data are stored sequentially.
| Header for Sound #1 |
| Sound #1 Sample Data |
| Header for Sound #2 |
| Sound #2 Sample Data |
| … |
| Header for Sound #6 |
| Sound #6 Sample Data |
Each 36 byte header has the following format:
| Bytes | Description | Data Format |
|---|---|---|
| 0: | Length of the HUB title, in bytes. | Integer. Signed or unsigned doesn’t matter, since the maximum valid value is 30. |
| 1-30: | HUB title. If length is less than 30 characters, the extra bytes will be garbage. The title will be identical for each header. | 1-byte ASCII characters |
| 31-34: | Length of the sound’s sample data, in bytes. | Unsigned, little-endian |
| 35: | Flag for whether sample should be stretched to fill a full measure when played in HammerHead. (For example, a drum loop). Ignored by Clawhammer. | 0x01 for true, 0x00 for false |
The header is followed by the raw sample data. The length of the sample data (in bytes) is specified by the size field of the header (bytes 31-34). The next header will start immediately after the sample data.
All sounds are assumed by HammerHead to be 16-bit, mono, with a sample rate of 44,100Hz. Therefore, the normal wave file header is not stored for each sound - only the raw sample data.