diff --git a/Makefile.am b/Makefile.am
index 60d7d17f2fb4745e230be9e80f04b4bae6bcac76..531f471e2b1e6aa7c741fc62a4b15c8b05163468 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,10 +13,10 @@ libengine_la_LIBADD = $(SNDFILE_LIBS) $(SAMPLERATE_LIBS)
 
 noinst_PROGRAMS = load-drumkit verify-voice
 
-load_drumkit_SOURCES = engine/load-drumkit.c
+load_drumkit_SOURCES = aux/load-drumkit.c
 load_drumkit_LDADD = libengine.la
 
-verify_voice_SOURCES = engine/verify-voice.c
+verify_voice_SOURCES = aux/verify-voice.c
 verify_voice_LDADD = libengine.la
 
 if LV2
diff --git a/engine/load-drumkit.c b/aux/load-drumkit.c
similarity index 100%
rename from engine/load-drumkit.c
rename to aux/load-drumkit.c
diff --git a/aux/sfz2hy.py b/aux/sfz2hy.py
new file mode 100755
index 0000000000000000000000000000000000000000..9f688645ad7622f92bf5175b701e96ee8e8e7c67
--- /dev/null
+++ b/aux/sfz2hy.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+#
+# Convert (some) SFZ metadata files to Hydrogen drumkit files.
+#
+
+import re
+import os
+import sys
+
+_keys = ['a', 'a#', 'b', 'c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#']
+_keys_to_note = dict((v, k) for k, v in enumerate(_keys))
+_key_rx = re.compile(r'^([abcdefg]#?)(\d+)$')
+
+
+def key_to_note(key):
+    m = _key_rx.match(key)
+    base_note = _keys_to_note[m.group(1)]
+    octave = int(m.group(2))
+    return 21 + octave * 12 + base_note
+
+
+def get_key(region):
+    if 'pitch_keycenter' in region:
+        return region['pitch_keycenter']
+    return region['lokey']
+
+
+def common_root(names):
+    root = names[0]
+    for n in names[1:]:
+        for i in xrange(min(len(root), len(n))):
+            if root[i] != n[i]:
+                root = root[:i]
+                break
+    return root.rstrip('-_+=(). ')
+
+
+def read_sfz(filename):
+    regions = []
+    with open(filename) as fd:
+        in_region = False
+        region = {}
+        for line in fd:
+            line = line.strip()
+            if not line:
+                continue
+            if line.startswith('<region>'):
+                if region:
+                    regions.append(region)
+                region = {'lovel': 0, 'hivel': 127}
+                in_region = True
+            elif line.startswith('<'):
+                in_region = False
+            elif in_region:
+                key, value = line.split('=', 1)
+                try:
+                    value = int(value)
+                except ValueError:
+                    pass
+                region[key] = value
+    return regions
+
+
+def to_xml(instruments):
+    print '''<?xml version="1.0" encoding="UTF-8"?>
+<drumkit_info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.hydrogen-music.org/drumkit">
+ <name>Drumkit</name>
+ <componentList>
+  <drumkitComponent>
+   <id>0</id>
+   <name>Main</name>
+   <volume>1</volume>
+  </drumkitComponent>
+ </componentList>
+ <instrumentList>'''
+    for id, ins in enumerate(instruments):
+        print '''  <instrument>
+   <id>%(id)d</id>
+   <name>%(name)s</name>
+   <isMuted>false</isMuted>
+   <pan_L>1</pan_L>
+   <pan_R>1</pan_R>
+   <randomPitchFactor>0</randomPitchFactor>
+   <gain>1</gain>
+   <volume>1</volume>
+   <applyVelocity>true</applyVelocity>
+   <filterActive>false</filterActive>
+   <filterCutoff>1</filterCutoff>
+   <filterResonance>0</filterResonance>
+   <Attack>0</Attack>
+   <Decay>0</Decay>
+   <Sustain>1</Sustain>
+   <Release>1000</Release>
+   <muteGroup>%(mute_group)d</muteGroup>
+   <midiOutChannel>-1</midiOutChannel>
+   <midiOutNote>%(note)d</midiOutNote>
+   <isStopNote>false</isStopNote>
+   <sampleSelectionAlgo>VELOCITY</sampleSelectionAlgo>
+   <isHihat>-1</isHihat>
+   <lower_cc>0</lower_cc>
+   <higher_cc>127</higher_cc>
+   <FX1Level>0</FX1Level>
+   <FX2Level>0</FX2Level>
+   <FX3Level>0</FX3Level>
+   <FX4Level>0</FX4Level>
+   <instrumentComponent>
+    <componentId>0</componentId>
+    <gain>1</gain>''' % {'id': id, 'name': ins['name'], 'note': ins['note'], 'mute_group': ins['mute_group']}
+        for l in ins['layers']:
+            print '''    <layer>
+     <filename>%s</filename>
+     <min>%g</min>
+     <max>%g</max>
+     <gain>1</gain>
+     <pitch>0</pitch>
+    </layer>''' % (l['sample'], l.get('lovel', 0) / 127.0, l.get('hivel', 127) / 127.0)
+        print '''   </instrumentComponent>
+  </instrument>'''
+    print ''' </instrumentList>
+</drumkit_info>'''
+
+
+def convert(filename):
+    dir = os.path.dirname(filename)
+    regions = read_sfz(filename)
+    # Regroup by pitch_keycenter
+    by_pitch = {}
+    for r in regions:
+        by_pitch.setdefault(get_key(r), []).append(r)
+    instruments = []
+    for key, rlist in by_pitch.iteritems():
+        note = key_to_note(key)
+        rlist.sort(key=lambda x: x['lovel'])
+        instrument_name = common_root([
+            os.path.splitext(x['sample'])[0] for x in rlist])
+        if not instrument_name:
+            instrument_name = 'instrument_%s' + key
+        instruments.append({
+            'note': note,
+            'name': instrument_name,
+            'layers': rlist,
+            'mute_group': rlist[0].get('group', -1),
+        })
+        print >>sys.stderr, 'note %d: %s' % (note, instrument_name)
+        for r in rlist:
+            print >>sys.stderr, '  + [%d, %d] %s' % (
+                int(r['lovel']), int(r['hivel']),
+                os.path.join(dir, r['sample']))      
+    to_xml(instruments)
+
+
+if __name__ == '__main__':
+    if len(sys.argv) < 2:
+        sys.exit(2)
+    convert(sys.argv[1])
diff --git a/engine/verify-voice.c b/aux/verify-voice.c
similarity index 100%
rename from engine/verify-voice.c
rename to aux/verify-voice.c