summaryrefslogtreecommitdiff
path: root/posts/2013-08-11-hacking-the-wavedrum.markdown
blob: a44c2bb32d96f7fe73930ef60b218a61fa9fe56e (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
---
title: Hacking the Wavedrum
tags: DIY,electronics,music,hacking,wavedrum
---

The Wavedrum Oriental is a wonderful electronic instrument.  Unlike an
electronic drum set or drum machines with touch sensitive pads, this
drum synthesizer's sensors don't merely trigger samples.  The sensors
rather behave like microphones or the pickup in an electric guitar;
the signals of the four sensors---one sensor for the drum head, one
sensor on the left and another on the right of the metal rim, and a
pressure sensor in the centre of the drum---are used to control drum
synthesizer algorithms whose output can be mixed with PCM samples.  As
a result, the instrument feels a lot like a real drum, a feat that
cannot easily be achieved with devices that use simple
velocity-sensitive sample triggers.

For all its magic, the Wavedrum also has a number of flaws.  Most
prominently, all editing is done through five buttons and an endless
rotary encoder.  What parameters can be selected by the buttons and
thus manipulated by the encoder depends entirely on context; one
button is used to jump to the next parameter page; simultaneously
pressing a pair of buttons switches between the two edit modes (why
two?), "global" mode and "live" mode; as one navigates through this
confusing environment, a three-character seven-segment display
conjures up magic strings that occasionally resemble abbreviations of
what appear to be parameter names.  Without a copy of the manual lying
next to the device, any attempt at deciphering the cryptic
three-character hints is doomed to fail.

Another painful flaw is the lack of connectivity.  There is no way to
export these precious custom programmes that were edited with so much
difficulty.  There is no way to back up the programmes, nor can one
share programmes with another Wavedrum.  When the device dies, all
custom patches go down with it.  Or so it seemed.


# A look inside the Wavedrum

Not really knowing what to look for I opened up the Wavedrum in the
hopes of finding *something* that would allow me to extend the feature
set of the instrument.  I first took off the control panel.  Only
three screws have to be loosened to lift the front panel and look
underneath.  The PCB, however, does not offer much of interest.

Much more interesting is the main board which is located right
underneath the drum head.  Removing the rim and the drum head
apparently is a permitted activity which does not void the
warranty---the manual includes instructions on how to change the drum
head.

<img class="full stretch" src="/images/posts/2013/wavedrum-opened.jpg" alt="After removing the rim and the drum head" />

Once the rim and drum head are out of the way, one can already
see much of the main board, but access is denied by a transparent
plastic disk.  In my instrument the plastic disk was only screwed to
two posts although there are holes for seven screws.  The heads of the
two screws are covered with adhesive pads that can easily be removed
to undo the screws.  (Don't worry, the glue on the pads is strong
enough to put them back on when you're done.)

<warning>
**Warning:** if you are following these instructions, at this point, I
  believe, you might be voiding your warranty.  If you're careful and
  you don't tell anyone, nobody should ever notice.  Note that I
  cannot be made responsible for any damage to your device that may
  result from following these instructions.
</warning>

With this warning out of the way, let's move on.

The main board is very tidy making it easy to understand what's going
on.  The densely packed section on the right appears to be power
supply and rim sensor amplification logic.  On the left you can see
two medium-sized chips, a bulky capacitor and something covered with a
black, textured tape.  The two chips are RAM (ESMT) and flash memory
(cFeon), respectively.  The big capacitor buffers the power for the
two memory chips and the massive DSP on the back of the board.  The
back side of the board is rather boring as it really only holds the
DSP chip (ADSP-21375 by Analog Devices).  The board has a somewhat
unusually great number of test pads (most of which are connected to
ground, used for automated testing) and quite a few connector pads,
possibly allowing a hardware debugger to be connected to debug the
DSP's firmware *in situ*.

<img class="full stretch" src="/images/posts/2013/wavedrum-mainboard.jpg" alt="The mainboard of the Wavedrum Oriental" />


# The treasure trove

What is underneath that black tape on the front, though?  This is
where things get really interesting (well, to people like me, at
least).  As I carefully removed the tape I was pleasently surprised to
see a micro SD card reader underneath.  The card is locked to the
reading interface to make sure it stays in place during operation.
Unlock it by shifting the metal brace to the right whereupon it can be
lifted.

![The taped-over SD card](/images/posts/2013/wavedrum-card-tape.jpg)

The 2GB micro SD card is a standard card formatted with a FAT32
filesystem, making it possible to read it out with a standard card
reader.  My netbook has a built-in SD card reader only, so I first
needed to buy an adapter to connect the micro SD card.  This reader is
a little weird.  It seems that the adapter must be in the reader slot
on boot or the micro SD card won't be recognised.  (If you're unsure
whether the card is recognised by your system check the output of
`dmesg`.)  Eventually, the card was recognised as `/dev/sdb1`.
(`/dev/sdb` is the SD card reader device itself.)  As this is my only
Wavedrum and I intend to use it for years to come I decided to be
especially careful this time and only operate on a *copy* of the card.
The Wavedrum's card reader is perfectly capable of reading 8GB micro
SD HC cards, so if you want to play with the data on the card I
recommend mirroring the original card image onto whatever micro SD
card you have at your disposal and play with that instead of the
original card.  To create a block level copy of the card I *did not*
mount the filesystem and simply executed the following command:

    dd if=/dev/sdb1 of=wavedrum.img

This instructs `dd` to copy all blocks from the input device file
(`if`, i.e. `/dev/sdb1`) to the output file (`of`) of the name
`wavedrum.img`.  Dependent on the number of disks on your system, the
input device file may have a different name.  Check the output of
`dmesg | tail` as you connect the card reader to see which device node
is created for the micro SD card. Note that this blindly copies
*everything* on the micro SD card, not just files that are available
through the FAT32 filesystem.  Hence, the size of the image is quite a
bit larger than the sum of all files on the mounted image (502,145,536
bytes vs 234,479,878 bytes).

Before continuing, please put the micro SD card back into the
Wavedrum's card reader and lock it to prevent it from being damaged
(things can get messy, you know).  Going forward, we only need to
mount the image to access the data stored on the card.  Run the following as
root to mount the card image as a read-only filesystem:

    mkdir wavedrum
    mount -o loop,ro wavedrum.img wavedrum/

Let's take a look at the files on the card:

<ul class="tree">
<li><b class="NORM">/</b></li>
<li>├── [&nbsp;&nbsp;16]&nbsp;&nbsp;<b class="EXEC">CALIB.BOR</b></li>
<li>├── [&nbsp;16K]&nbsp;&nbsp;<b class="DIR">Factory</b></li>
<li>│   ├── [192K]&nbsp;&nbsp;<b class="EXEC">F_INFO.BOR</b></li>
<li>│   ├── [&nbsp;57K]&nbsp;&nbsp;<b class="EXEC">F_INST_H.BOR</b></li>
<li>│   ├── [&nbsp;57K]&nbsp;&nbsp;<b class="EXEC">F_INST_R.BOR</b></li>
<li>│   ├── [&nbsp;16K]&nbsp;&nbsp;<b class="EXEC">F_PROG.BOR</b></li>
<li>│   └── [&nbsp;&nbsp;88]&nbsp;&nbsp;<b class="EXEC">F_USER.BOR</b></li>
<li>├── [&nbsp;57K]&nbsp;&nbsp;<b class="EXEC">INST_H.BOR</b></li>
<li>├── [&nbsp;57K]&nbsp;&nbsp;<b class="EXEC">INST_R.BOR</b></li>
<li>├── [&nbsp;16K]&nbsp;&nbsp;<b class="DIR">LOOP</b></li>
<li>│   ├── [744K]&nbsp;&nbsp;<b class="EXEC">LOOP0001.BIN</b></li>
<li>│   ├── [402K]&nbsp;&nbsp;<b class="EXEC">LOOP0002.BIN</b></li>
<li>│   ├── [750K]&nbsp;&nbsp;<b class="EXEC">LOOP0003.BIN</b></li>
<li>&#x22ee;</li>
<li>│   ├── [173K]&nbsp;&nbsp;<b class="EXEC">LOOP0138.BIN</b></li>
<li>│   ├── [173K]&nbsp;&nbsp;<b class="EXEC">LOOP0139.BIN</b></li>
<li>│   └── [234K]&nbsp;&nbsp;<b class="EXEC">LOOP0140.BIN</b></li>
<li>├── [&nbsp;16K]&nbsp;&nbsp;<b class="EXEC">PRE_PROG.BOR</b></li>
<li>├── [&nbsp;16K]&nbsp;&nbsp;<b class="DIR">SYSTEM</b></li>
<li>│   ├── [&nbsp;&nbsp;16]&nbsp;&nbsp;<b class="EXEC">VERSION.INF</b></li>
<li>│   ├── [1.0M]&nbsp;&nbsp;<b class="EXEC">WDORM202.BIN</b></li>
<li>│   └── [8.0K]&nbsp;&nbsp;<b class="EXEC">WDORS110.BIN</b></li>
<li>├── [&nbsp;&nbsp;88]&nbsp;&nbsp;<b class="EXEC">USER.BOR</b></li>
<li>├── [157M]&nbsp;&nbsp;<b class="EXEC">WD2_DATA.BOR</b></li>
<li>├── [192K]&nbsp;&nbsp;<b class="EXEC">WD2_INFO.BOR</b></li>
<li>└── [&nbsp;16K]&nbsp;&nbsp;<b class="EXEC">WD2_PROG.BOR</b></li>
</ul>

The files in the `Factory` directory contain initialisation data.
When a factory reset is performed, the customised versions of these
files in the root directory are overwritten with the versions
contained in the `Factory` directory.  All initial programmes that
come with the Wavedrum are stored in `Factory/F_PROG.BOR`; once
programmes have been edited `WD2_PROG.BOR` in the root directory will
differ from `Factory/F_PROG.BOR`.  (More about the nature of these
differences later.)  `PRE_PROG.BOR` is the same as
`Factory/F_PROG.BOR` and is probably used to make the original factory
presets available in addition to custom programmes, starting at
position `P.00`, the programme slot after `149`.

The initial mapping of presets to any of the 12 slots (3 banks with 4
slots each) is stored in `Factory/F_USER.BOR`.  Initially, `USER.BOR`
in the root directory will be identical to this file.  The format of
this file is rather simple:

    00000000 |  00 00 00 64 00 00 00 67  00 00 00 7b 00 00 00 6c
    00000010 |  00 00 00 65 00 00 00 68  00 00 00 71 00 00 00 7a
    00000020 |  00 00 00 84 00 00 00 8c  00 00 00 8b 00 00 00 95
    00000030 |  00 00 00 00 00 00 00 00  00 00 00 75 00 00 00 26
    00000040 |  00 00 00 07 00 00 00 14  00 00 00 07 00 00 00 14
    00000050 |  00 00 00 05 00 00 00 64

Every 8 digit block (4 byte) is used for one slot.  We can see that
the first slot in bank A is set to programme 100 (0x64 hex), the
second to programme 103 (0x67 hex) and so on.  As the Wavedrum only
allows for 12 slots to store programme identifiers, only the first 48
bytes are used for programmes.  The remaining 40 bytes (starting at
0x30) are used for global parameters that can be adjusted in "global"
editing mode.  The global parameters are stored in this order:

  - delay pan
  - aux input level
  - loop phrase select
  - loop play mode (off=38)
  - head sensor threshold
  - head sensor sensitivity
  - rim sensor threshold
  - rim sensor sensitivity
  - pressure sensor threshold
  - pressure maximum

I don't know yet what purpose `F_INST_H.BOR` and `F_INST_R.BOR`
fulfil, but it is clear that the former relates to settings for the
drum head while the latter contains similar settings for the rim.
Even after editing a few programmes, `INST_H.BOR` and `INST_R.BOR` in
the root directory were still identical to their counterparts in the
`Factory` directory.

The `CALIB.BOR` appears to contain calibration information for the
head and rim sensors.  This is different from the calibration
performed by adjusting the four global paramaters for sensor threshold
and sensitivity.  I have not been able to edit these settings through
the Wavedrum so far, so these probably are factory settings.


## Audio data

All files in the `LOOP` directory as well as `WD2_DATA.BOR` contain
raw audio data.  Unfortunately, I haven't quite figured out the format
yet, but you can listen to the clearly recognisable loop patterns with
`play` (part of the [SoX](http://sox.sourceforge.net) applications):

    find LOOP -name "*.BIN" -print |\
      xargs -I XXX \
      play -t raw -r 48k -b 16 -e signed-integer -c 1 XXX

Obviously, this isn't quite correct.  I'm interpreting every 16 bits
as a sample in signed integer format, but the sound is distorted and
far from the realistic instrument sound when playing back the loops
through the Wavedrum.

All loops start with this 44 byte long header:

    04 dc 10 d3 uU vV 5W 95  01 d4 00 d0 30 f8 22 b5
    46 95 56 95 57 95 57 95  d6 2e 56 95 56 e2 57 95
    54 95 46 95 32 f4 22 f4  xX yY 5W 95

With a few exceptions (namely 0009, 0025, 0027, 0030, 0033, 0036,
0049, 0054, 0064, 0082, 0091, 0103, 0104, 0107, 0108, 0127, 0128,
0129, 0130, 0131, 0132, 0135), vV equals yY in most loops. It seems
that loops with the same number of bytes have the exact same numbers
for uU, vV, W, xX, and yY.  This is especially apparent in the
loops 0127 to 0132 (inclusive), which are all 192,010 bytes long and
all have the values 54:7b:54 for uU:vV:5W and 88:78:54 for xX:yY:5W.

Clearly, more work is required to figure out the complete format of
these loop files.  Once this is understood we could use custom loops
with the Wavedrum.

The raw audio data in `WD2_DATA.BOR` suffers from the same problems.
Although the data can be interpreted as raw audio, the sound is
distorted and playback is unnaturally fast.


## System files

I don't know what `SYSTEM/WDORS110.BIN` is used for.  The only useful
string contained in the file is "BOOTABLE".  Your guess is as good as
mine as to what it does.

`SYSTEM/VERSION.INF` is only 16 bytes short and pretty boring as it
contains just what the name implies: version numbers.

    02 02 01 10 02 02 00 00  57 44 4f 52 00 00 00 00

This string of numbers is interpreted as follows: firmware version
2.02, sub-version 1.10, data version 2.02 (followed by two empty
bytes); 57 44 4f 52 (hex for "WDOR") stands for "Wavedrum Oriental"
(followed by four empty bytes).  You can have the Wavedrum display all
its version numbers by pressing the button labelled "Global" when
powering on the device. Note that the file name `WDORS110.BIN`
references the version number 1.10, while `WDORM202.BIN` references
the firmware version number 2.02.

`SYSTEM/WDORM202.BIN` contains the firmware of the Wavedrum Oriental.
There are many interesting strings and binary patterns in the file,
but I'm still a long way from *understanding* how it works.  To view
the strings with the `strings` command, you have to specify the
encoding as 32-bit little endian:

    strings --encoding L SYSTEM/WDORM202.BIN

Some of the strings embedded in the firmware are file names, some of
which are not available on the micro SD card.  This includes the
following files: SYS00000.BIN, SYS00100.BIN, SYSTEM/WDORS100.BIN,
SYSTEM/WDX_M100.BIN, SYSTEM/WDX_S100.BIN, and SUBXXXXX.BIN (a
pattern?).


# The programme format

Looking at the hexdump of the file `WD2_PROG.BOR` which holds all custom
presets, I couldn't find any obvious patterns in the file, so I
resorted to editing a single programme, setting particular consecutive
parameters to easily recognisable sequences of values (such as 100,
99, 98, and 97 for hd1, hd2, hd3, and hd4) and locating the changes in
the hexdump.

<img class="full stretch" src="/images/posts/2013/wavedrum-diff.png" alt="Analysing the programme format by changing values and looking at the differences" />

This procedure has allowed me to figure out in what order the
parameters are stored in the file.  Each programme is exactly 54
16-bit words long; each parameter takes up exactly 16 bits.  Negative
values are stored in [two's
complement](https://en.wikipedia.org/wiki/Two%27s_complement) format
(e.g. negative six is stored as 0xFFFA).  The file is exactly 16200
bytes long which is just enough to hold 150 custom programmes, each
taking up 108 bytes.

I'm currently writing a Haskell library to parse / build progammes and
parameters.  The code is available for
[free](https://www.fsf.org/about/what-is-free-software) [on
gitorious](https://gitorious.org/wavedrum/wavedrum-lib) under the [GNU
GPLv3](https://gnu.org/licenses/gpl.html).

The parameters are stored in this order:

|identifier |  mode  | target              | name                         |
|----------:|--------|:--------------------|:-----------------------------|
|07.1       | Edit 1 | head algorithm      | Pressure curve               |
|type       | Edit 2 | --                  | Pre EQ                       |
|01.1       | Edit 1 | head algorithm      | Tune                         |
|02.1       | Edit 1 | head algorithm      | Decay                        |
|03.1       | Edit 1 | head algorithm      | Level                        |
|04.1       | Edit 1 | head algorithm      | Pan                          |
|05.1       | Edit 1 | head algorithm      | Algorithm select             |
|hd.1       | Edit 2 | head algorithm      | Algorithm parameter 1        |
|hd.2       | Edit 2 | head algorithm      | Algorithm parameter 2        |
|hd.3       | Edit 2 | head algorithm      | Algorithm parameter 3        |
|hd.4       | Edit 2 | head algorithm      | Algorithm parameter 4        |
|hd.5       | Edit 2 | head algorithm      | Algorithm parameter 5        |
|hd.6       | Edit 2 | head algorithm      | Algorithm parameter 6        |
|hd.7       | Edit 2 | head algorithm      | Algorithm parameter 7        |
|hd.8       | Edit 2 | head algorithm      | Algorithm parameter 8        |
|01.3       | Edit 1 | rim algorithm       | Tune                         |
|02.3       | Edit 1 | rim algorithm       | Decay                        |
|03.3       | Edit 1 | rim algorithm       | Level                        |
|04.3       | Edit 1 | rim algorithm       | Pan                          |
|05.3       | Edit 1 | rim algorithm       | Algorithm select             |
|rm.1       | Edit 2 | rim algorithm       | Algorithm parameter 1        |
|rm.2       | Edit 2 | rim algorithm       | Algorithm parameter 2        |
|rm.3       | Edit 2 | rim algorithm       | Algorithm parameter 3        |
|rm.4       | Edit 2 | rim algorithm       | Algorithm parameter 4        |
|rm.5       | Edit 2 | rim algorithm       | Algorithm parameter 5        |
|rm.6       | Edit 2 | rim algorithm       | Algorithm parameter 6        |
|rm.7       | Edit 2 | rim algorithm       | Algorithm parameter 7        |
|rm.8       | Edit 2 | rim algorithm       | Algorithm parameter 8        |
|01.2       | Edit 1 | head PCM instrument | Tune                         |
|02.2       | Edit 1 | head PCM instrument | Decay                        |
|03.2       | Edit 1 | head PCM instrument | Level                        |
|04.2       | Edit 1 | head PCM instrument | Pan                          |
|05.2       | Edit 1 | head PCM instrument | PCM instrument select        |
|06.2       | Edit 1 | head PCM instrument | Velocity curve               |
|07.2       | Edit 1 | head PCM instrument | Pressure curve               |
|08.2       | Edit 1 | head PCM instrument | Pressure tune                |
|09.2       | Edit 1 | head PCM instrument | Pressure decay               |
|01.4       | Edit 1 | rim PCM instrument  | Tune                         |
|02.4       | Edit 1 | rim PCM instrument  | Decay                        |
|03.4       | Edit 1 | rim PCM instrument  | Level                        |
|04.4       | Edit 1 | rim PCM instrument  | Pan                          |
|05.4       | Edit 1 | rim PCM instrument  | PCM instrument select        |
|06.4       | Edit 1 | rim PCM instrument  | Velocity curve               |
|07.4       | Edit 1 | rim PCM instrument  | Pressure curve               |
|08.4       | Edit 1 | rim PCM instrument  | Pressure tune                |
|09.4       | Edit 1 | rim PCM instrument  | Pressure decay               |
|10.1       | Edit 1 | --                  | Reverb type                  |
|10.2       | Edit 1 | --                  | Reverb effect level          |
|10.3       | Edit 1 | --                  | Reverb decay time            |
|10.4       | Edit 1 | --                  | Reverb frequency damping     |
|11.3       | Edit 1 | --                  | Delay feedback               |
|11.2       | Edit 1 | --                  | Delay effect level           |
|11.1       | Edit 1 | --                  | Delay time                   |
|11.4       | Edit 1 | --                  | Delay frequency damping      |


# Thanks

The following tools have proven indispensable in the analysis:

- [`calc`](http://www.isthe.com/chongo/tech/comp/calc/), a calculator
  for the command line supporting hexadecimal representations of
  numbers (both input and output using the `base` and `base2`
  functions)

- [`vbindiff`](http://www.cjmweb.net/vbindiff/), a tool to visualise
  differences between two binary files with a split-screen hexadecimal
  display

- [`ghex`](https://wiki.gnome.org/Ghex), a simple hexadecimal editor
  supporting pattern search and highlighting


# Call for help

If you own an earlier model of the Wavedrum or the latest Wavedrum
Global Edition, I would be *very* happy if you could send me a
block-level copy of the SD card (see above for instructions).  This
would allow me to understand the firmware better and maybe even make
it possible to upgrade an older Wavedrum to the latest version (taking
into account possible hardware differences, such as differing memory
size).

Please send a link to the micro SD card image to
<span class="obfuscated">sflbep,xbwfesvnAfmfqimz/ofu</span>.

Read [more posts about the Wavedrum here](http://elephly.net/tags/wavedrum.html).