Rekadohttps://elephly.net/feeds/tags/hacking.xmlTag: hacking2023-09-24T23:33:34ZUndocumented Wavedrum modeshttps://elephly.net/posts/2022-01-24-wavedrum-modes.htmlRicardo Wurmusrekado+web@elephly.net2022-01-24T00:00:00Z<p>The manual mentions two special modes that can be entered by holding
down buttons while powering on: hold down <code>Write</code> while powering on
and you can reset to factory settings; hold down <code>Mode</code> while powering
on and you can double the output volume.</p><p>The manual does <em>not</em> mention these additional modes:</p><h2>Information modes</h2><p>These modes only provide version information before booting up
normally.</p><ul><li><p><strong>Hold button 1.</strong> The display shows <code>SyS</code>, followed by the version.
In my case that's <code>2.02</code>. It then proceeds to boot up.</p></li><li><p><strong>Hold button 2.</strong> The display shows <code>Sub</code>, followed by the version.
In my case that's <code>1.10</code>. It then proceeds to boot up.</p></li><li><p><strong>Hold button 3.</strong> The display shows <code>dat</code>, followed by the version.
In my case that's <code>2.02</code>. It then proceeds to boot up.</p></li><li><p><strong>Hold button 4.</strong> The display briefly shows <code>InF</code>, and then cycles
through the version information that can be obtained with the
previous three modes.</p></li></ul><h2>Update modes</h2><p>These modes allow changing the firmware.</p><ul><li><p>Hold <strong>Write</strong> and <strong>button 1</strong>. The display blinks <code>SyS</code>. Upon
pushing <em>Write</em> it displays <code>Lod</code> followed by a blinking <code>End</code>,
presumably loading firmware. (From where?) It is possible to push
the buttons <em>1</em>, <em>2</em>, <em>3</em>, or <em>4</em> to switch between <code>SyS</code>, <code>Sub</code>,
<code>dSP</code>, and <code>S_d</code>, respectively. But the <em>Write</em> button only has an
effect when <code>SyS</code> (button 1) is selected.</p></li><li><p>Hold <strong>Write</strong> and <strong>button 2</strong>; the display blinks <code>Sub</code>. This is like the
previous mode, except that <code>Sub</code> is selected.</p></li><li><p>Hold <strong>Write</strong> and <strong>button 3</strong>; the display blinks <code>dSP</code>. This is like the
previous modes, except that <code>dSP</code> is selected.</p></li><li><p>Hold <strong>Write</strong> and <strong>button 4</strong>; the display blinks <code>S_d</code>. This is like the
previous modes, except that <code>S_d</code> is selected.</p></li></ul><p>Finally, there's the well-known mode to reset to factory settings by
holding <strong>Write</strong> and <strong>Mode</strong> while powering on.</p><h2>Test modes</h2><ul><li><p>Hold <strong>button 1</strong> and <strong>button 3</strong>; the display briefly shows <code>SLF</code>,
probably for "self test". It then shows <code>SyS</code>, followed by the
version number and then lights up all LEDs. Pushing <em>Mode</em> then
lights up only the LED above the <em>Write</em> button. Hitting <em>Write</em>
advances the LED to the next button, and so on.</p><p>When the display is tested, hit <em>Mode</em> to get to test the
<em>Value</em> knob; hit <em>Mode</em> again to test the <em>Value</em> knob's range from 0 to 99; hit it yet again to test
the range from 0 to 7. That's all that can be tested here.</p></li><li><p>Hold <strong>button 1</strong> and <strong>button 4</strong>; the display shows <code>Aud.</code>. It
then lights up LED 1 and displays <code>A.In</code>, presumably to test audio
input. Selecting <em>button 2</em> it shows <code>OFF</code> and the output goes
silent. Selecting <em>button 3</em> shows <code>Pie.</code>; the signal of the piezo
sensors is passed straight to the output. Selecting <em>button 4</em>
shows <code>ALG.</code> and you can hear the sounds produced by a simple test
algorithm when you play the head and rim.</p></li><li><p>Hold <strong>button 2</strong> and <strong>button 4</strong>; the display shows <code>CAL.</code>,
probably meaning "Calibration". It lights up LED 1 and displays the
current value of the pressure sensor. When you select <em>button 2</em>
and strike the head, the display shows the corresponding velocity.
When you select <em>button 3</em> and strike the rim, the display shows the
corresponding velocity. Hold down <em>button 3</em> and you see what seems
to be an amplification factor. By default this shows <code>0.75</code>. This
can be adjusted with the <em>Value</em> knob in the range from <code>0.00</code> all
the way to <code>4.00</code>. There does not seem to be a way to save changes.</p><p>Selecting <em>button 4</em> the display shows where and how strongly the
drum is hit.</p></li><li><p>Hold down <strong>buttons 1, 2, 3, and 4</strong>, and also hold <strong>Mode</strong>; the
display briefly shows <code>deb</code>, which I assume means "debug". It then
seems to boot up normally, but upon completion will have entered an
absolutely bizarre mode where the <em>buttons 1 and 2</em> are used to go
down or up in a list of presets from <code>01</code> to <code>26</code>; similarly,
<em>buttons 3 and 4</em> are used for selecting one of 26 presets, probably
for the rim sounds.</p><p>The value dial goes from <code>050</code> to <code>500</code>, but I don't know what value it
controls. <em>Mode</em> and <em>button 1</em> start a constant fast
automatic trigger of the head. Hitting the combo again stops the
automatic trigger.</p><p><em>Mode</em> and either <em>button 2</em> or <em>button 3</em> seems to mute the audio.
<em>Mode</em> and <em>button 4</em> mutes all generated sounds and passes the
unprocessed sound of the piezo sensors through.</p><p>I'm not sure what the <em>Write</em> button does; pushing it multiple times
seems to cycle between four different values, but it is not clear
what they are. When holding <em>Mode</em>, pushing <em>Write</em>
twice selects the next reverb, cycling from <code>r00</code> to <code>r10</code>.</p></li></ul><p>Read <a href="/tags/wavedrum.html">more posts about the Wavedrum here</a>.</p>Disassembling the Wavedrum firmwarehttps://elephly.net/posts/2014-09-18-wavedrum-firmware-disassembler.htmlRicardo Wurmusrekado+web@elephly.net2014-09-18T00:00:00Z<p>The Wavedrum’s processing unit is an ADSP-21375 by Analog Devices,
a member of the SHARC processor family. The firmware of the
Wavedrum, which is stored on a micro SD-card and, more
importantly, on the flash memory chip is loaded into the processor
during the boot process.</p><p><a href="2013-12-09-wavedrum-connectors.html">Last time</a> I
confirmed by tracing the connections of the two boot pins that the
processor is wired to boot from EPROM/Flash (<code>BOOT_CFG1-0 =
10</code>). I’m too lazy to try to verify that the firmware on the
micro SD-card is identical to the contents of the flash memory, so
I’ll just assume that this is the case.</p><p>When the processor is initially powered on, the internal memory is
in an undefined state. According to the <a href="http://www.analog.com/static/imported-files/processor_manuals/ADSP-21367_hwr_rev2-1.pdf">ADSP hardware reference</a> (section 17-7 <em>Processor
Booting</em>), the processor core is put into <code>IDLE</code> mode
while loading the boot kernel from an external source (in our case
this is the flash memory) into the internal memory at address
0x90000 (<code>IVT_START_ADDR</code>), and finally executes the boot
kernel code when a peripheral interrupt signals that the kernel
has been loaded. Then the application code is loaded from the
memory and finally the application’s Interrupt Vector Table (IVT)
is loaded. The boot kernel is 256 48-bit words long, as is the
IVT. The application code is of arbitrary length.</p><h2>Word packing</h2><p>The boot kernel is exactly 256 48-bit words long (shorter kernels
are padded with NOPs), but the words are not transferred as 48-bit
words. The boot kernel is transferred from the external memory as
a stream of 384 “packed” 32-bit words (see table 17-6 in the
hardware reference). To understand packing we have to know that
conceptionally the internal memory consists of many rows of four
columns, each of which is 16 bit wide. Accessing 48-bit words is
often referred to as 3-column access in the reference, whereas
accessing 32-bit words is called 2-column access. All of the
SHARC instructions are 48 bit wide. This means that any 32-bit
wide package never contains the full instruction. Dependent on
the order of the packages, the 48-bit words can be reconstructed
from a stream of 32-bit words.</p><p>Here’s the original explanation in the hardware reference on page
17-27:</p><blockquote><p>During the boot process, word packing (for example 8
to 32-bit) is performed over the SPI. In other words,
the kernel is not loaded directly with 256 x 48-bit
words, instead it is loaded with 384 x 32-bit ‘packed
words’ (2-column access). The same physical memory for
instruction boot is loaded via DMA in normal word (NW)
2 column. However, after booting the same physical
memory region is fetched by the sequencer in NW
3-column. For example the loader kernel itself has a
NW 2 columns count of 256 x 3/2 = 384 words but the
kernel is executed with 256 instruction fetches.</p></blockquote><p>When booting from external memory the bus width is set to 8 bits.
According to the <a href="http://www.analog.com/static/imported-files/processor_manuals/ADSP-21367_hwr_rev2-1.pdf">ADSP hardware reference</a> (section “External Port Booting”), the
processor reads a stream of 8-bit words from the data port and
packs four of them into 32-bit words (LSB first) before storing
them into the internal memory.</p><p>Figure 17-5 in the hardware reference visualises this process
rather nicely. It shows how streams of different word sizes end
up being stored in the internal memory.</p><img class="full stretch" src="/images/posts/2014/wavedrum-word-packing.png" alt="word packing" /><p>Once I understood that words are transferred from the memory in
8-bit chuncks with the LSB first, writing a disassembler that
would translate the binary boot kernel into assembly code was no
longer very challenging.</p><h2>A free disassembler for ADSP-213xx</h2><p>I implemented a simple tool in Haskell that takes a binary
firmware and spits out assembly code for the ADSP. At the moment
it only supports a limited set of instructions, just enough so
that I could translate the boot kernel. The remainder of the
instructions will be implemented later as I happen to encounter
them in the application code.</p><p>It currently only parses the first 256 words of the firmware,
i.e. only the boot kernel. Before I can parse the remainder I
need to figure out the memory layout.</p><p>The code is freely available under the <a href="http://www.gnu.org/licenses/#GPL">GPL</a> and can be <a href="http://git.elephly.net/wavedrum/sharc-disassembler.git">downloaded here</a>. See the included instructions for assistance
in compiling and using the disassembler.</p><h2>Next steps</h2><p>My work isn’t over yet. Next I’ll focus on the following tasks:</p><ul><li>figure out how the boot kernel loads the application code into
the processor</li><li>disassemble (parts of) the application code</li><li>look out for snippets that involve loading code from the
micro-SD card to the flash memory, because that’s our ticket to
upgrade the firmware easily</li></ul><p>If you want to help me, I’d be happy if you could send me a copy
of the Global Edition’s firmware. To do this you only need to
take out the micro SD-card and create a disk image of it. (On
GNU/Linux this can easily be done with <code>dd</code> on the command
line; see <a href="/posts/2013-08-11-hacking-the-wavedrum.html">my first post on hacking the Wavedrum</a> for more detailed
instructions.)</p><p>I would also be very grateful for code reviews and patches.
Translating the various specifications into executable code wasn’t
always easy and I’m sure there are bugs in the code here and
there.</p><p>Read <a href="/tags/wavedrum.html">more posts
about the Wavedrum here</a>.</p>Connectors on the Wavedrum’s circuit boardhttps://elephly.net/posts/2013-12-09-wavedrum-connectors.htmlRicardo Wurmusrekado+web@elephly.net2013-12-09T00:00:00Z<p>On the circuit board of the Wavedrum there are solder holes to
accomodate three large connectors. Since they are so easily
accessible and thus very inviting to anyone interested in
modifying the instrument, I decided to trace each of the pins to
its destination.</p><p>The three connectors are named CN10, CN11, and CN12,
respectively. CN10 is found on the bottom right, CN11 on the
bottom left, and CN12 close to the left edge below the micro SD
card reader.</p><img class="full stretch" src="/images/posts/2013/wavedrum-connectors.jpg" alt="connectors on the mainboard" /><h2>CN10: digital audio interface</h2><p>Most of the ten pins of CN10 are outputs. The first three pins
carry clock signals used by the analogue to digital and digital
to analogue converters on the top-side of the board. Pin four
gives access to the PDN (power down) signal which is used to
disable the converters. The next three pins are connected over
the resistors R85, R84, and R83 to the DSP's pins 145, 144, and
143 (respectively); according to the <a href="http://www.analog.com/static/imported-files/data_sheets/ADSP-21371_21375.pdf">DSP's datasheet</a> these pins are <code>DAI_P8</code> (<code>SFSI</code>), <code>DAI_P10</code>
(<code>SD2B</code>), and <code>DAI_P11</code> (<code>SD3A</code>), and are thus part of the
Digital Audio Interface (DAI). The remaining three pins on CN10
expose the supply voltage, ground, and an alternative positive
voltage (the same as on the plus pole of the silver capacitors
near the right edge of the board). These are the signals left to
right:</p><table><thead><tr class="header"><th align="right"></th><th align="left">direction</th><th align="left">description</th></tr></thead><tbody><tr><td align="right">1</td><td align="left">output</td><td align="left">Master clock</td></tr><tr><td align="right">2</td><td align="left">output</td><td align="left">Audio serial clock</td></tr><tr><td align="right">3</td><td align="left">output</td><td align="left">Left/right clock</td></tr><tr><td align="right">4</td><td align="left">output</td><td align="left"><code>PDN</code> (power down)</td></tr><tr><td align="right">5</td><td align="left">input?</td><td align="left"><code>DAI_P8</code> / <code>SFSI</code></td></tr><tr><td align="right">6</td><td align="left">input?</td><td align="left"><code>DAI_P10</code> / <code>SD2B</code></td></tr><tr><td align="right">7</td><td align="left">input?</td><td align="left"><code>DAI_P11</code> / <code>SD3A</code></td></tr><tr><td align="right">8</td><td align="left">output</td><td align="left"><code>V_A</code>, or <code>V_DD</code></td></tr><tr><td align="right">9</td><td align="left">output</td><td align="left">GND</td></tr><tr><td align="right">10</td><td align="left">output</td><td align="left">alternative positive voltage</td></tr></tbody></table><p>What is this all good for? Well, since all these clocks and
voltages are exported it becomes relatively easy to connect an
external digital to analogue converter (when <code>DAI_P8</code>,
<code>DAI_P10</code>, and <code>DAI_P11</code> are used as outputs), or
an external analogue to digital converter (if the DSP pins are
used as inputs instead). nAs there are protective resistors
between the DSP pins and the connector pins 5–7 I assume that
they are supposed to be used as inputs.</p><h2>CN11: JTAG interface</h2><p>Moving on to the left bottom edge of the board we see a 14-pin
connector with the name CN11. This connector gives access to the
JTAG interface on the DSP, which allows system debugging.
Unfortunately, I don't own a JTAG dongle and the free JTAG
debugger <a href="http://openocd.sourceforge.net">OpenOCD</a> does
not support the SHARC core, so I haven't been able to experiment
with the debugging interface. I'm not sure whether it is
possible to use debugging feature without hardware/software
provided by Analog Devices. Using JTAG it should be possible to
overwrite the flash memory and replace the firmware. This is the
most promising method to upgrade (or downgrade) a Wavedrum.</p><p>The pins on the bottom row are all connected to ground, so the
following table only lists the signal names of the upper row of
the connector in order from left to right:</p><table><thead><tr class="header"><th align="right"></th><th align="left">Signal</th><th align="left">Full name</th></tr></thead><tbody><tr><td align="right">1</td><td align="left"><code><quasiquote>~EMU</quasiquote></code></td><td align="left">Emulation status</td></tr><tr><td align="right">2</td><td align="left"><code><quasiquote>GND</quasiquote></code></td><td align="left">Ground</td></tr><tr><td align="right">3</td><td align="left"><code><quasiquote>TMS</quasiquote></code></td><td align="left">Test mode select</td></tr><tr><td align="right">4</td><td align="left"><code><quasiquote>TCK</quasiquote></code></td><td align="left">Test clock</td></tr><tr><td align="right">5</td><td align="left"><code><quasiquote>~TRST</quasiquote></code></td><td align="left">Test reset</td></tr><tr><td align="right">6</td><td align="left"><code><quasiquote>TDI</quasiquote></code></td><td align="left">Test data input</td></tr><tr><td align="right">7</td><td align="left"><code><quasiquote>TDO</quasiquote></code></td><td align="left">Test data output</td></tr></tbody></table><h2>CN12: two-wire serial interface</h2><p>CN12 exposes the DSP's two-wire interface, a serial interface
compatible with the proprietary I^2C interface. This allows us
to connect a number of external serial devices to the serial bus.
As firmware support is required to communicate with the devices
on the serial bus I don't see how this could be used without a
custom firmware.</p><p>The following table lists the signals from top to bottom:</p><table><thead><tr class="header"><th align="right"></th><th align="left">Signal</th><th align="left">Full name</th></tr></thead><tbody><tr><td align="right">1</td><td align="left"><code><quasiquote>V_D</quasiquote></code></td><td align="left">Positive voltage</td></tr><tr><td align="right">2</td><td align="left"><code><quasiquote>TWI_DATA</quasiquote></code></td><td align="left">Two-wire interface data</td></tr><tr><td align="right">3</td><td align="left"><code><quasiquote>TWI_CLK</quasiquote></code></td><td align="left">Two-wire interface clock</td></tr><tr><td align="right">4</td><td align="left"><code><quasiquote>GND</quasiquote></code></td><td align="left">Ground</td></tr></tbody></table><h2>Bonus: boot mode</h2><p>What led me to tracing the routes of the connectors was my
curiosity about the boot mode. According to the DSP's datasheet,
there are four possible boot modes to select from by playing with
the states of the pins <code>BOOT_CFG1-0</code> (one of these boot
modes is “no boot”). Tracing these two pins from the DSP it
becomes clear that the third boot mode “EPROM/FLASH boot” is
hardwired (<code>BOOT_CFG1-0 = 10</code>). The other two usable
boot modes are SPI master and slave boots.</p><table><thead><tr class="header"><th align="right">BOOT_CFG1-0</th><th align="left">Booting mode</th></tr></thead><tbody><tr><td align="right">00</td><td align="left">SPI Slave Boot</td></tr><tr><td align="right">01</td><td align="left">SPI Master Boot</td></tr><tr><td align="right">10</td><td align="left">EPROM/Flash Boot</td></tr><tr><td align="right">11</td><td align="left">No boot</td></tr></tbody></table><img class="full stretch" src="/images/posts/2013/wavedrum-bootcfg.jpg" alt="boot configuration traces" /><p>As can be seen on the photo, the Wavedrum engineers were kind
enough to leave solder pads connected to boot configuration pins
on the board, allowing us to rewire them as we see fit. To set
<code>BOOT_CFG0</code> the pads for <code>R72</code> have to be
bridged; likewise, to clear <code>BOOT_CFG1</code> only the two pads
of <code>R59</code> have to be bridged.</p><h2>References</h2><ul><li><a href="http://www.analog.com/static/imported-files/data_sheets/ADSP-21371_21375.pdf">ADSP-21371/ADSP-21375 datasheet</a></li><li><a href="http://www.analog.com/static/imported-files/processor_manuals/ADSP-21367_hwr_rev2-1.pdf">ADSP hardware reference</a></li></ul>Firmware comparison between Wavedrums Original, Black and Orientalhttps://elephly.net/posts/2013-10-31-wavedrum-data-comparison.htmlRicardo Wurmusrekado+web@elephly.net2013-10-31T00:00:00Z<p>Since <a href="/posts/2013-08-11-hacking-the-wavedrum.html">my
first post on hacking the Wavedrum</a> two fellow musicians have
sent me copies of the contents of their Wavedrum instruments, so
I now have the data for the original silver issue, the black
re-issue and the Oriental.</p><p>The differences between the data from the silver and the data
from the black Wavedrum are very few. Of the files sent to me
only five differ: <code>USER.BIN</code>, <code>CALIB.BIN</code>, <code>WD2_PROG.BIN</code>, <code>SYSTEM/VERSION.INF</code>, and <code>SYSTEM/WDX_M100.BIN</code>. <code>USER.BIN</code> contains only the
mapping of programmes to slots and banks, which have been altered
by the respective owners of the two instruments, so it can safely
be ignored. Likewise, <code>WD2_PROG.BIN</code> contains custom
user programmes and hence is of no interest.</p><p><code>CALIB.BIN</code> contains as of yet unknown calibration
information, just like the similarly named <code>CALIB.BOR</code> on
my Wavedrum Oriental. The contents of <code>CALIB.BIN</code> from
the original Wavedrum are identical to those of the matching file
on the Oriental. The only difference that the Black has over the
other two is a single digit. This is from the Oriental:</p><pre><code>01 00 00 75 00 00 00 00 02 00 00 00 00 00 00 00</code></pre><p>And this is from the Black:</p><pre><code>01 00 00 75 00 00 00 00 01 00 00 00 00 00 00 00</code></pre><p>Not very exciting.</p><p><code>SYSTEM/VERSION.INF</code> contains the hardware/software
versions. Here are the contents of the Original, followed by the
Black and the Oriental:</p><pre><code>01 20 01 10 01 20 00 00 00 00 00 00 00 00 00 00
01 32 01 10 01 32 00 00 57 44 58 5F 00 00 00 00
02 02 01 10 02 02 00 00 57 44 4f 52 00 00 00 00</code></pre><p>Again, these are in decimal notation and are in this format:
firmware version (two bytes), sub-version (two bytes), data
version (two-bytes), two empty bytes, four bytes for an optional
identifier followed by four empty bytes.</p><table><thead><tr class="header"><th align="right">Type</th><th align="left">Firmware</th><th align="left">Sub-version</th><th align="left">Data version</th><th align="left">Identifier</th></tr></thead><tbody><tr><td align="right">Original</td><td align="left">1.20</td><td align="left">1.10</td><td align="left">1.20</td><td align="left">none</td></tr><tr><td align="right">Black</td><td align="left">1.32</td><td align="left">1.10</td><td align="left">1.32</td><td align="left">WDX_</td></tr><tr><td align="right">Oriental</td><td align="left">2.02</td><td align="left">1.10</td><td align="left">2.02</td><td align="left">WDOR</td></tr></tbody></table><p>Looking at the version numbers above it becomes apparent that the
sounds themselves are not covered by these numbers as the sounds
on the Black are no different from those on the Original, yet the
data version differs.</p><p>The file <code>SYSTEM/WDX_M100.BIN</code> must be the firmware on
both the Original and the Black Wavedrum, serving the same
purpose as <code>SYSTEM/WDORM202.BIN</code> on the Oriental. There
are quite a few changes even between version 1.20 and 1.32, but I
haven’t yet taken the time to analyse them. It is interesting to
note, though, that every firmware file is <em>exactly</em> one
megabyte long, independent of the Wavedrum type. This is due to
padding which in the Original firmware begins at offset 0xC967C,
in the Black firmware at offset 0xC9C68, and in the Oriental
firmware at offset 0xDCB64.</p><p>More to follow.</p><p>Read <a href="/tags/wavedrum.html">more posts about the Wavedrum
here</a>.</p>Hacking the Wavedrumhttps://elephly.net/posts/2013-08-11-hacking-the-wavedrum.htmlRicardo Wurmusrekado+web@elephly.net2013-08-11T00:00:00Z<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><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><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.</p><h2>A look inside the Wavedrum</h2><p>Not really knowing what to look for I opened up the Wavedrum in
the hopes of finding <em>something</em> 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><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.</p><img class="full stretch" src="/images/posts/2013/wavedrum-opened.jpg" alt="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.)</p><warning><strong>Warning:</strong> 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><p>With this warning out of the way, let’s move on.</p><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</em>.</p><img class="full stretch" src="/images/posts/2013/wavedrum-mainboard.jpg" alt="The mainboard of the Wavedrum Oriental" /><h2>The treasure trove</h2><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.</p><div class="figure"><img src="/images/posts/2013/wavedrum-card-tape.jpg" alt="The taped-over SD card" /><p class="caption">The taped-over SD card</p></div><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</code>.) Eventually,
the card was recognised as <code>/dev/sdb1</code>. (<code>/dev/sdb</code> 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</em> 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</em> mount the filesystem and
simply executed the following command:</p><pre><code>dd if=/dev/sdb1 of=wavedrum.img</code></pre><p>This instructs <code>dd</code> to copy all blocks from the input
device file (<code>if</code>, i.e. <code>/dev/sdb1</code>) to the
output file (<code>of</code>) of the name <code>wavedrum.img</code>.
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</code> 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</em> 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><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:</p><pre><code>mkdir wavedrum
mount -o loop,ro wavedrum.img wavedrum/</code></pre><p>Let’s take a look at the files on the card:</p><ul class="tree"><li><span class="NORM">/</span></li><li>├── ( 16) <span class="EXEC">CALIB.BOR</span></li><li>├── ( 16K) <span class="DIR">Factory</span></li><li>│ ├── (192K) <span class="EXEC">F_INFO.BOR</span></li><li>│ ├── ( 57K) <span class="EXEC">F_INST_H.BOR</span></li><li>│ ├── ( 57K) <span class="EXEC">F_INST_R.BOR</span></li><li>│ ├── ( 16K) <span class="EXEC">F_PROG.BOR</span></li><li>│ └── ( 88) <span class="EXEC">F_USER.BOR</span></li><li>├── ( 57K) <span class="EXEC">INST_H.BOR</span></li><li>├── ( 57K) <span class="EXEC">INST_R.BOR</span></li><li>├── ( 16K) <span class="DIR">LOOP</span></li><li>│ ├── (744K) <span class="EXEC">LOOP0001.BIN</span></li><li>│ ├── (402K) <span class="EXEC">LOOP0002.BIN</span></li><li>│ ├── (750K) <span class="EXEC">LOOP0003.BIN</span></li><li>...</li><li>│ ├── (173K) <span class="EXEC">LOOP0138.BIN</span></li><li>│ ├── (173K) <span class="EXEC">LOOP0139.BIN</span></li><li>│ └── (234K) <span class="EXEC">LOOP0140.BIN</span></li><li>├── ( 16K) <span class="EXEC">PRE_PROG.BOR</span></li><li>├── ( 16K) <span class="DIR">SYSTEM</span></li><li>│ ├── ( 16) <span class="EXEC">VERSION.INF</span></li><li>│ ├── (1.0M) <span class="EXEC">WDORM202.BIN</span></li><li>│ └── (8.0K) <span class="EXEC">WDORS110.BIN</span></li><li>├── ( 88) <span class="EXEC">USER.BOR</span></li><li>├── (157M) <span class="EXEC">WD2_DATA.BOR</span></li><li>├── (192K) <span class="EXEC">WD2_INFO.BOR</span></li><li>└── ( 16K) <span class="EXEC">WD2_PROG.BOR</span></li></ul><p>The files in the <code>Factory</code> 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</code>
directory. All initial programmes that come with the Wavedrum
are stored in <code>Factory/F_PROG.BOR</code>; once programmes have
been edited <code>WD2_PROG.BOR</code> in the root directory will
differ from <code>Factory/F_PROG.BOR</code>. (More about the nature
of these differences later.) <code>PRE_PROG.BOR</code> is the same
as <code>Factory/F_PROG.BOR</code> and is probably used to make the
original factory presets available in addition to custom
programmes, starting at position <code>P.00</code>, the programme
slot after <code>149</code>.</p><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</code>.
Initially, <code>USER.BOR</code> in the root directory will be
identical to this file. The format of this file is rather
simple:</p><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</code></pre><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:</p><ul><li>delay pan</li><li>aux input level</li><li>loop phrase select</li><li>loop play mode (off=38)</li><li>head sensor threshold</li><li>head sensor sensitivity</li><li>rim sensor threshold</li><li>rim sensor sensitivity</li><li>pressure sensor threshold</li><li>pressure maximum</li></ul><p>I don’t know yet what purpose <code>F_INST_H.BOR</code> and <code>F_INST_R.BOR</code> 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</code> and <code>INST_R.BOR</code> in the root
directory were still identical to their counterparts in the
<code>Factory</code> directory.</p><p>The <code>CALIB.BOR</code> 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.</p><h2>Audio data</h2><p>All files in the <code>LOOP</code> directory as well as <code>WD2_DATA.BOR</code> 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</code> (part of
the <a href="http://sox.sourceforge.net">SoX</a> applications):</p><pre><code>find LOOP -name "*.BIN" -print |\
xargs -I XXX \
play -t raw -r 48k -b 16 -e signed-integer -c 1 XXX</code></pre><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><p>All loops start with this 44 byte long header:</p><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</code></pre><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><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><p>The raw audio data in <code>WD2_DATA.BOR</code> suffers from the
same problems. Although the data can be interpreted as raw
audio, the sound is distorted and playback is unnaturally fast.</p><h2>System files</h2><p>I don’t know what <code>SYSTEM/WDORS110.BIN</code> 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><p><code>SYSTEM/VERSION.INF</code> is only 16 bytes short and pretty
boring as it contains just what the name implies: version
numbers.</p><pre><code>02 02 01 10 02 02 00 00 57 44 4f 52 00 00 00 00</code></pre><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</code> references the version
number 1.10, while <code>WDORM202.BIN</code> references the firmware
version number 2.02.</p><p><code>SYSTEM/WDORM202.BIN</code> 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</em> how it works. To view the strings with the
<code>strings</code> command, you have to specify the encoding as
32-bit little endian:</p><pre><code>strings --encoding L SYSTEM/WDORM202.BIN</code></pre><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?).</p><h2>The programme format</h2><p>Looking at the hexdump of the file <code>WD2_PROG.BOR</code> 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.</p><img class="full stretch" src="/images/posts/2013/wavedrum-diff.png" alt="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 <a href="https://en.wikipedia.org/wiki/Two%27s_complement">two’s
complement</a> 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><p>I’m currently writing a Haskell library to parse / build
progammes and parameters. The code is available for <a href="https://www.fsf.org/about/what-is-free-software">free</a> <a href="http://git.elephly.net/wavedrum/wavedrum-lib.git">here</a> under
the <a href="https://gnu.org/licenses/gpl.html">GNU GPLv3</a>.</p><p>The parameters are stored in this order:</p><table><thead><tr class="header"><th align="right">identifier</th><th align="left">mode</th><th align="left">target</th><th align="left">name</th></tr></thead><tbody><tr><td align="right">07.1</td><td align="left">Edit 1</td><td align="left">head algorithm</td><td align="left">Pressure curve</td></tr><tr><td align="right">type</td><td align="left">Edit 2</td><td align="left">–</td><td align="left">Pre EQ</td></tr><tr><td align="right">01.1</td><td align="left">Edit 1</td><td align="left">head algorithm</td><td align="left">Tune</td></tr><tr><td align="right">02.1</td><td align="left">Edit 1</td><td align="left">head algorithm</td><td align="left">Decay</td></tr><tr><td align="right">03.1</td><td align="left">Edit 1</td><td align="left">head algorithm</td><td align="left">Level</td></tr><tr><td align="right">04.1</td><td align="left">Edit 1</td><td align="left">head algorithm</td><td align="left">Pan</td></tr><tr><td align="right">05.1</td><td align="left">Edit 1</td><td align="left">head algorithm</td><td align="left">Algorithm select</td></tr><tr><td align="right">hd.1</td><td align="left">Edit 2</td><td align="left">head algorithm</td><td align="left">Algorithm parameter 1</td></tr><tr><td align="right">hd.2</td><td align="left">Edit 2</td><td align="left">head algorithm</td><td align="left">Algorithm parameter 2</td></tr><tr><td align="right">hd.3</td><td align="left">Edit 2</td><td align="left">head algorithm</td><td align="left">Algorithm parameter 3</td></tr><tr><td align="right">hd.4</td><td align="left">Edit 2</td><td align="left">head algorithm</td><td align="left">Algorithm parameter 4</td></tr><tr><td align="right">hd.5</td><td align="left">Edit 2</td><td align="left">head algorithm</td><td align="left">Algorithm parameter 5</td></tr><tr><td align="right">hd.6</td><td align="left">Edit 2</td><td align="left">head algorithm</td><td align="left">Algorithm parameter 6</td></tr><tr><td align="right">hd.7</td><td align="left">Edit 2</td><td align="left">head algorithm</td><td align="left">Algorithm parameter 7</td></tr><tr><td align="right">hd.8</td><td align="left">Edit 2</td><td align="left">head algorithm</td><td align="left">Algorithm parameter 8</td></tr><tr><td align="right">01.3</td><td align="left">Edit 1</td><td align="left">rim algorithm</td><td align="left">Tune</td></tr><tr><td align="right">02.3</td><td align="left">Edit 1</td><td align="left">rim algorithm</td><td align="left">Decay</td></tr><tr><td align="right">03.3</td><td align="left">Edit 1</td><td align="left">rim algorithm</td><td align="left">Level</td></tr><tr><td align="right">04.3</td><td align="left">Edit 1</td><td align="left">rim algorithm</td><td align="left">Pan</td></tr><tr><td align="right">05.3</td><td align="left">Edit 1</td><td align="left">rim algorithm</td><td align="left">Algorithm select</td></tr><tr><td align="right">rm.1</td><td align="left">Edit 2</td><td align="left">rim algorithm</td><td align="left">Algorithm parameter 1</td></tr><tr><td align="right">rm.2</td><td align="left">Edit 2</td><td align="left">rim algorithm</td><td align="left">Algorithm parameter 2</td></tr><tr><td align="right">rm.3</td><td align="left">Edit 2</td><td align="left">rim algorithm</td><td align="left">Algorithm parameter 3</td></tr><tr><td align="right">rm.4</td><td align="left">Edit 2</td><td align="left">rim algorithm</td><td align="left">Algorithm parameter 4</td></tr><tr><td align="right">rm.5</td><td align="left">Edit 2</td><td align="left">rim algorithm</td><td align="left">Algorithm parameter 5</td></tr><tr><td align="right">rm.6</td><td align="left">Edit 2</td><td align="left">rim algorithm</td><td align="left">Algorithm parameter 6</td></tr><tr><td align="right">rm.7</td><td align="left">Edit 2</td><td align="left">rim algorithm</td><td align="left">Algorithm parameter 7</td></tr><tr><td align="right">rm.8</td><td align="left">Edit 2</td><td align="left">rim algorithm</td><td align="left">Algorithm parameter 8</td></tr><tr><td align="right">01.2</td><td align="left">Edit 1</td><td align="left">head PCM instrument</td><td align="left">Tune</td></tr><tr><td align="right">02.2</td><td align="left">Edit 1</td><td align="left">head PCM instrument</td><td align="left">Decay</td></tr><tr><td align="right">03.2</td><td align="left">Edit 1</td><td align="left">head PCM instrument</td><td align="left">Level</td></tr><tr><td align="right">04.2</td><td align="left">Edit 1</td><td align="left">head PCM instrument</td><td align="left">Pan</td></tr><tr><td align="right">05.2</td><td align="left">Edit 1</td><td align="left">head PCM instrument</td><td align="left">PCM instrument select</td></tr><tr><td align="right">06.2</td><td align="left">Edit 1</td><td align="left">head PCM instrument</td><td align="left">Velocity curve</td></tr><tr><td align="right">07.2</td><td align="left">Edit 1</td><td align="left">head PCM instrument</td><td align="left">Pressure curve</td></tr><tr><td align="right">08.2</td><td align="left">Edit 1</td><td align="left">head PCM instrument</td><td align="left">Pressure tune</td></tr><tr><td align="right">09.2</td><td align="left">Edit 1</td><td align="left">head PCM instrument</td><td align="left">Pressure decay</td></tr><tr><td align="right">01.4</td><td align="left">Edit 1</td><td align="left">rim PCM instrument</td><td align="left">Tune</td></tr><tr><td align="right">02.4</td><td align="left">Edit 1</td><td align="left">rim PCM instrument</td><td align="left">Decay</td></tr><tr><td align="right">03.4</td><td align="left">Edit 1</td><td align="left">rim PCM instrument</td><td align="left">Level</td></tr><tr><td align="right">04.4</td><td align="left">Edit 1</td><td align="left">rim PCM instrument</td><td align="left">Pan</td></tr><tr><td align="right">05.4</td><td align="left">Edit 1</td><td align="left">rim PCM instrument</td><td align="left">PCM instrument select</td></tr><tr><td align="right">06.4</td><td align="left">Edit 1</td><td align="left">rim PCM instrument</td><td align="left">Velocity curve</td></tr><tr><td align="right">07.4</td><td align="left">Edit 1</td><td align="left">rim PCM instrument</td><td align="left">Pressure curve</td></tr><tr><td align="right">08.4</td><td align="left">Edit 1</td><td align="left">rim PCM instrument</td><td align="left">Pressure tune</td></tr><tr><td align="right">09.4</td><td align="left">Edit 1</td><td align="left">rim PCM instrument</td><td align="left">Pressure decay</td></tr><tr><td align="right">10.1</td><td align="left">Edit 1</td><td align="left">–</td><td align="left">Reverb type</td></tr><tr><td align="right">10.2</td><td align="left">Edit 1</td><td align="left">–</td><td align="left">Reverb effect level</td></tr><tr><td align="right">10.3</td><td align="left">Edit 1</td><td align="left">–</td><td align="left">Reverb decay time</td></tr><tr><td align="right">10.4</td><td align="left">Edit 1</td><td align="left">–</td><td align="left">Reverb frequency damping</td></tr><tr><td align="right">11.3</td><td align="left">Edit 1</td><td align="left">–</td><td align="left">Delay feedback</td></tr><tr><td align="right">11.2</td><td align="left">Edit 1</td><td align="left">–</td><td align="left">Delay effect level</td></tr><tr><td align="right">11.1</td><td align="left">Edit 1</td><td align="left">–</td><td align="left">Delay time</td></tr><tr><td align="right">11.4</td><td align="left">Edit 1</td><td align="left">–</td><td align="left">Delay frequency damping</td></tr></tbody></table><h2>Thanks</h2><p>The following tools have proven indispensable in the analysis:</p><ul><li><a href="http://www.isthe.com/chongo/tech/comp/calc/">calc</a>, a
calculator for the command line supporting hexadecimal
representations of numbers (both input and output using the
<code>base</code> and <code>base2</code> functions)</li><li><a href="http://www.cjmweb.net/vbindiff/">vbindiff</a>, a tool to
visualise differences between two binary files with a
split-screen hexadecimal display</li><li><a href="https://wiki.gnome.org/Ghex">ghex</a>, a simple
hexadecimal editor supporting pattern search and highlighting</li></ul><h2>Call for help</h2><p>If you own an earlier model of the Wavedrum or the latest
Wavedrum Global Edition, I would be <em>very</em> 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><p>Please send a link to the micro SD card image to <span class="obfuscated">sflbepAfmfqimz/ofu</span>.</p><p>Read <a href="/tags/wavedrum.html">more posts about the Wavedrum
here</a>.</p>