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
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
|
(post
:title "Hacking the Wavedrum"
:date (string->date* "2013-08-11 00:00")
:tags '("DIY"
"planet-fsfe-en"
"electronics"
"music"
"hacking"
"wavedrum")
(p [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.])
(p [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.])
(p [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.])
(h2 [A look inside the Wavedrum])
(p [Not really knowing what to look for I opened up the Wavedrum in
the hopes of finding ,(em [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.])
(p [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.])
(wide-img "2013/wavedrum-opened.jpg"
"After removing the rim and the drum head")
(p [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.)])
(list 'warning [,(strong [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.])
(p [With this warning out of the way, let’s move on.])
(p [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 ,(em [in situ]).])
(wide-img "2013/wavedrum-mainboard.jpg"
"The mainboard of the Wavedrum Oriental")
(h2 [The treasure trove])
(p [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.])
(figure "2013/wavedrum-card-tape.jpg" "The taped-over SD card")
(p [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 ,(code [dmesg]).) Eventually,
the card was recognised as ,(code [/dev/sdb1]). (,(code
[/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 ,(em
[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 ,(em [did not]) mount the filesystem and
simply executed the following command:])
(pre (code [dd if=/dev/sdb1 of=wavedrum.img]))
(p [This instructs ,(code [dd]) to copy all blocks from the input
device file (,(code [if]), i.e. ,(code [/dev/sdb1])) to the
output file (,(code [of])) of the name ,(code [wavedrum.img]).
Dependent on the number of disks on your system, the input device
file may have a different name. Check the output of ,(code
[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 ,(em [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).])
(p [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:])
(pre (code [mkdir wavedrum
mount -o loop,ro wavedrum.img wavedrum/]))
(p [Let’s take a look at the files on the card:])
'(ul (@ (class "tree"))
(li (span (@ (class "NORM")) "/" ))
(li "├── ( 16) " (span (@ (class "EXEC")) "CALIB.BOR"))
(li "├── ( 16K) " (span (@ (class "DIR")) "Factory"))
(li "│ ├── (192K) " (span (@ (class "EXEC")) "F_INFO.BOR"))
(li "│ ├── ( 57K) " (span (@ (class "EXEC")) "F_INST_H.BOR"))
(li "│ ├── ( 57K) " (span (@ (class "EXEC")) "F_INST_R.BOR"))
(li "│ ├── ( 16K) " (span (@ (class "EXEC")) "F_PROG.BOR"))
(li "│ └── ( 88) " (span (@ (class "EXEC")) "F_USER.BOR"))
(li "├── ( 57K) " (span (@ (class "EXEC")) "INST_H.BOR"))
(li "├── ( 57K) " (span (@ (class "EXEC")) "INST_R.BOR"))
(li "├── ( 16K) " (span (@ (class "DIR")) "LOOP"))
(li "│ ├── (744K) " (span (@ (class "EXEC")) "LOOP0001.BIN"))
(li "│ ├── (402K) " (span (@ (class "EXEC")) "LOOP0002.BIN"))
(li "│ ├── (750K) " (span (@ (class "EXEC")) "LOOP0003.BIN"))
(li "...")
(li "│ ├── (173K) " (span (@ (class "EXEC")) "LOOP0138.BIN"))
(li "│ ├── (173K) " (span (@ (class "EXEC")) "LOOP0139.BIN"))
(li "│ └── (234K) " (span (@ (class "EXEC")) "LOOP0140.BIN"))
(li "├── ( 16K) " (span (@ (class "EXEC")) "PRE_PROG.BOR"))
(li "├── ( 16K) " (span (@ (class "DIR")) "SYSTEM"))
(li "│ ├── ( 16) " (span (@ (class "EXEC")) "VERSION.INF"))
(li "│ ├── (1.0M) " (span (@ (class "EXEC")) "WDORM202.BIN"))
(li "│ └── (8.0K) " (span (@ (class "EXEC")) "WDORS110.BIN"))
(li "├── ( 88) " (span (@ (class "EXEC")) "USER.BOR"))
(li "├── (157M) " (span (@ (class "EXEC")) "WD2_DATA.BOR"))
(li "├── (192K) " (span (@ (class "EXEC")) "WD2_INFO.BOR"))
(li "└── ( 16K) " (span (@ (class "EXEC")) "WD2_PROG.BOR")))
(p [The files in the ,(code [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 ,(code [Factory])
directory. All initial programmes that come with the Wavedrum
are stored in ,(code [Factory/F_PROG.BOR]); once programmes have
been edited ,(code [WD2_PROG.BOR]) in the root directory will
differ from ,(code [Factory/F_PROG.BOR]). (More about the nature
of these differences later.) ,(code [PRE_PROG.BOR]) is the same
as ,(code [Factory/F_PROG.BOR]) and is probably used to make the
original factory presets available in addition to custom
programmes, starting at position ,(code [P.00]), the programme
slot after ,(code [149]).])
(p [The initial mapping of presets to any of the 12 slots (3 banks
with 4 slots each) is stored in ,(code [Factory/F_USER.BOR]).
Initially, ,(code [USER.BOR]) in the root directory will be
identical to this file. The format of this file is rather
simple:])
(pre (code [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]))
(p [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:])
(ul
(li [delay pan])
(li [aux input level])
(li [loop phrase select])
(li [loop play mode (off=38)])
(li [head sensor threshold])
(li [head sensor sensitivity])
(li [rim sensor threshold])
(li [rim sensor sensitivity])
(li [pressure sensor threshold])
(li [pressure maximum]))
(p [I don’t know yet what purpose ,(code [F_INST_H.BOR]) and ,(code
[F_INST_R.BOR]) serve, 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,
,(code [INST_H.BOR]) and ,(code [INST_R.BOR]) in the root
directory were still identical to their counterparts in the
,(code [Factory]) directory.])
(p [The ,(code [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.])
(h2 [Audio data])
(p [All files in the ,(code [LOOP]) directory as well as ,(code
[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 ,(code [play]) (part of
the ,(ref "http://sox.sourceforge.net" "SoX") applications):])
(pre (code [find LOOP -name "*.BIN" -print |\\
xargs -I XXX \\
play -t raw -r 48k -b 16 -e signed-integer -c 1 XXX]))
(p [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.])
(p [All loops start with this 44 byte long header:])
(pre (code [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]))
(p [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.])
(p [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.])
(p [The raw audio data in ,(code [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.])
(h2 [System files])
(p [I don’t know what ,(code [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.])
(p [,(code [SYSTEM/VERSION.INF]) is only 16 bytes short and pretty
boring as it contains just what the name implies: version
numbers.])
(pre (code [02 02 01 10 02 02 00 00 57 44 4f 52 00 00 00 00]))
(p [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 ,(code [WDORS110.BIN]) references the version
number 1.10, while ,(code [WDORM202.BIN]) references the firmware
version number 2.02.])
(p [,(code [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 ,(em
[understanding]) how it works. To view the strings with the
,(code [strings]) command, you have to specify the encoding as
32-bit little endian:])
(pre (code [strings --encoding L SYSTEM/WDORM202.BIN]))
(p [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?).])
(h2 [The programme format])
(p [Looking at the hexdump of the file ,(code [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.])
(wide-img "2013/wavedrum-diff.png"
"Analysing the programme format by changing values and looking at the differences")
(p [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 ,(ref
"https://en.wikipedia.org/wiki/Two%27s_complement" "two’s
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.])
(p [I’m currently writing a Haskell library to parse / build
progammes and parameters. The code is available for ,(ref
"https://www.fsf.org/about/what-is-free-software" "free") ,(ref
"http://git.elephly.net/wavedrum/wavedrum-lib.git" "here") under
the ,(ref "https://gnu.org/licenses/gpl.html" "GNU GPLv3").])
(p [The parameters are stored in this order:])
(table :align '("right")
:headers '("identifier" "mode" "target" "name")
:rows
'(("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")))
(h2 [Thanks])
(p [The following tools have proven indispensable in the analysis:])
(ul
(li [,(ref "http://www.isthe.com/chongo/tech/comp/calc/" "calc"), a
calculator for the command line supporting hexadecimal
representations of numbers (both input and output using the
,(code [base]) and ,(code [base2]) functions)])
(li [,(ref "http://www.cjmweb.net/vbindiff/" "vbindiff"), a tool to
visualise differences between two binary files with a
split-screen hexadecimal display])
(li [,(ref "https://wiki.gnome.org/Ghex" "ghex"), a simple
hexadecimal editor supporting pattern search and highlighting]))
(h2 [Call for help])
(p [If you own an earlier model of the Wavedrum or the latest
Wavedrum Global Edition, I would be ,(em [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).])
(p [Please send a link to the micro SD card image to ,(email
"rekado@elephly.net").])
(p [Read ,(ref "/tags/wavedrum.html" "more posts about the Wavedrum
here").]))
|