E-drum Project Files

On this page you can find file downloads related to my 3D printed E-drums and related virtual reality projects. For build information and useful notes about the electrical and software implementation of this project, please check my blog posts under the E-drums category.

STL files for 3D printing

6″ Drum Shell and Rim

The 6″ drum shell is modified from a set published by RyoKosaka on Thingiverse under the Creative Commons Attribution-ShareAlike licence. In accordance with that licence my modifications and my sensor mount design are licenced similarly.

6″ Drum body with mounting holes for a side mounted Cliff jack and sensor pack mounted to the cross-bar
6″ Drum rim

Drum Clamps

Click to download STL file for 3D printing

Sensor Mounts

The first mount (EVA 12mm x 3 layers) is recommended. The 12mm EVA is this product, available from Bunnings.

Sensor mount for 6″ drum 12mm EVA (3 layers)
Sensor mount for 6″ drum 12mm EVA (2 layers)
Sensor mount for 6″ drum 10mm Polyethelyne (3 layers)
Side sensor mount

Electronics Sleds

These sleds hold many types of Arduino (they were tested with Mega and Leonardo). It has room for two different types of DC-DC voltage converter (the LM2596 with LED display and the compact XL6009E1), the OpAmp buffer module described in my blog, and 12 Cliff jacks. These sleds include the Arduino Mega Case R2 from icare as part of the design.

A mounting sled for the project electronics. The slots on the side are for Velcro loops

A taller sled for Cliff jacks with long legs

A lead guide to keep your cable runs tidy

Manufacturing Aids

A full 2 octave drumset needs 96 foam disks (3 per cone and 1 underneath the sensor on each drum). Here are some simple 3D printed tools to make bulk cone assembly a little easier. Instructions can be found in my post ‘3D Printed E-Drum and sensor system‘ and additional notes in ‘Troubles with Triggers’.

Cutting jig for firm foams only. Attach two of the 37mm wheels with M3 bolts – one for cutting flat discs and one for cutting stacks for cones
37mm wheel for cutting foam on the jig
Sample sensor cone to check measurements
This punch can be used to quickly mark a whole foam sheet for cutting with 37mm discs

MAX Patches

My drums are designed to compliment an identical Tonnetz arrangement in Virtual Reality, made in the Patchworld modular instrument environment. This is a modification of the freely available OSC Bridge that allows Patchworld to send and receive MIDI continuous controllers over ethernet. I have modified this patch to replace two channels of controllers with MIDI note information.

Patchworld MIDI bridge

Modified Patchworld Bridge with two channels of MIDI notes replacing controllers

Copy the text below and select ‘New from Clipboard’ in MAX

<pre><code>
----------begin_max5_patcher----------
3890.3oc6cksaiajE8Y6uBAMupHT6KyascmMfzSBldlAMPOAFxRztYhLkgDk
QmIH+6SsPIwkRjEkHEkkoShbLIUUEu08bpSscq+75qFd+huFrZ3f+9fOO3pq
9yqu5JykzW3pj+9pgOM4qSmOYk4wFNcwSOEDEObj8dwAeM1b8+wh3fA+qfUa
uyyKCVodvIwgKhtaYvzXatfIhwfQCfXzX5nAL9XJW8OTHThQXNVcG08G7qII
R3LShu39e6avjMobz5mBilGDaJPPGYW5qqd3Eqi27zfMO8j3oeIL5wTELHfi
GK.69AJPiFPYHcwkSFKH.NGfHDpTfExMETc58WWes9iQGoI7Giddc7f2GDqK
SdYEkhZZDg.PqaEoi4xT+PUkPJh23Vw6WGGqJjUXmnTi2FDn+ERLlPgHkuGA
vPXBm35Zasa2OOL52mtX9hk1DCLVxoPAS.PR0KgfORcINWxnXFfKwLBWpuDA
C.DU0.hCnbDTk8tqLjzsk9IKm7jpde4cAQStedPZibspmt+wLkWHQBfRUgSP
vPro7hR82Hcci5RDUAUHPXJRRfnrk2r07v5VySjRikmr4ysIrMUi+imCre+g
2OI5wgYtcXTPlWGAVhfTlfg3p5LcQW.JbI1tWEHmQy91rZxKAytaRb7xPk+S
vt+uUIdZItZYrjWk55WML3qZi+pDC+v3uD7jsTNdd3KA2sZ8xGlLM3t6ebn8
an7n2jjY7m7MUM+u2sJXtxRqts86mOoyaspWhqYfL+8cgQuDrbUv1z+5c+pU
fmhyY3o7hBdBQrd3YO7rBMHZEbCt81AgUAcoHivHq5HSq6n8fiDhCRxwCKhh
WE9+LtePc1TWkHPjC8bblgvAQKTh04WjBlaJ2uSgxUzWC93jnUC9Pvrv0OM7
.rxZWtwyBmLeiE3kIK2lGau4mgfesBqMiZs11OMEdLKUgexyOGnHohlFj1Dt
0wIwhXd0S+gypKPYzdaR5IJu8WBhBBlMOvurvYkuMYd3QsYvujwOEpnR7KPb
XQhPH.OVpHcYJ1W.FhHRjSCcAZwgiFL7g4KlDO7.Xwb95WJ4PApEmUD0KIx3
lTuu5KSluNXwCE+h67cluH5ws972Fub9f2+Y3F+8LO4SKlo92zstl41q9xhk
w4RIWIylJGWow5nv3Uw+QRS3GOMpu.bXk.7DIPmB.N5RGfqrh8.7NDfeaiAv
u80B.GUE.mxjmL.N6BGfC43d.dWBvuow.327ZAfiqDfiDmL.N+RGfin8.7tD
f+tFCf+ttFfWq4IfPNCGHRl3hadBJNOa1QBtefH6mmfRlmfyR3IBHt3lnfd7
YO9z4DEjVc7poSh9o6muSpvtoQ3ipaM3gEK+uQ+7GucvMKCm8XvfeQ6rMXVv
KgJMvIeC6a65HyWC6hEn5mHkuqcz8oigLhxcRgsEREcfx4QZFdMBaOsvJO9o
n.d.SQAPnJo69gSP5ojCpWTGJm9Bk3VaJJxRBqJk1Zw8UoeSbzmqbDMkXCUA
nXcA1bGLZLGqoujLhhFiScUwPqwjQjiyjk4GCmIKEgBgC8sGP6kjdwxYAKyj
ofQo9HcBmqvAL7b.ok2iY9BVl7DldwHWz99PnuUptpCm4aC5gESWupNEaGNs
D6TngDBG8FSpccUeBR+CkWRey10+3jJwMTiIEMtotZa6Z5xnjkogN8kvY+4P
arnfizgzQuLuB0KAN3bNWcZ89xt7JZ79XFn7WSpyW7vC5tjqSrecTE8FME8z
95RphNKEB3v6tplYqrNqhN9FS0sO5kfWBNYgwvUhUwHAfikJpBnP4ZSIIML.
gLk1LlhSkvX3c7m4FSoRf2oWYfBXiqhUWPxAm8ifDZeDdFnOw.z2wZpUKVFk
3FsBaGLggKClEobiGtexM9lAdhqRcHFPjZCNFNlYXxP.DiR4ZpNH.jz9FHig
2jQ+Pv7mGV1vQo+OSqrmNAsSUhGVtX9NEnM4fLkql1uu7QNnspZa8Ssugs0d
6OKqRmBjXGBQvXpoEXayYlEs5lQxcOigKIkrLceER65mBYw8RCyAK7T6AV5.
rNe5rr89McGGIRqPCX5lY8SHfjCyztKQnWPY3BlQYAyXyNBsoe+Z7lsBiBi0
SNf0UwY6UIORw5zJZUKuCpyV0HiANuan0ev8cqSqdUWT1TOAOUyFitGeUMYK
vcq9LaKkLxd5ZGukWv6T6heSVTMrsfA.G3BbuBRtOL4qetxIkBa62qvziK6n
mAo4ZwpgGZlzZJvrFm5y+IQhp5moo2ljwXNlq5WsdnAo5tV4vRzrbRs670jk
TB.ZJZoLtTtEYC.GOkyGBiNJdFZqKfPUB8.aY8h5LrE+L.aAXiwZ4x3MSTK5
xBbkRc+QCtR6S8lFboXYPd1vEi0QfKbGBtzDK8MbU2FtP8XKKICxyFt5LrE4
L.a02vUsZ3pGbkvx.8rgKhri.WfNDbAIh9FtpcCWvdrkkjA5YCWcF1BdFfs5
a3pVMb0CtrrL90pEF0MHKTGNVFRpYc622nUcZzpGTkpDVQyUcEnBP6dPUeqU
0o0p2Lnpp2uUrpiHB1EuGFz962JH5BOlHfPIKDURxR9Vxz6jMY+9s5Dseq9g
lYyV8CuR1MkbOCGBmHzM7Be6Txk8n6tDc+8MC596ekftEdFKDNQn6K9vchBH
aVxpIKCOJoGceJQ2eWyft+tWInaomABgSD5FeYitEvdvcWBt+1lAb+scM3de
w6w+Sv7ESCi+iAnJP0ZmNyt2CR34Wh21UR.ZuCDEraB.jDHbLkjKJhn2J4BB
By4IfGlRLLCeRBGjkF6zQ+MuqAbrWELqpg8WCf5lZ.DBOFI8oFfC6zZfsv.n
2UBPbcgA3toRPU57DFHHcOL.5MLPxJfBfkWAP5jJ.A4LCDTicOEsJwdHoUrm
0z2ASxg3fmjivGiVndQlGN82a1opm.vEAbDHYLNUENEguvlJj1XyQQO9nPUQ
u8tsGV9A7X9B7vjtA3AAme.O06RQl1df2g.7XuUAdbeAdIwmkSOvCc9A7.H3
dZw6hdx+aCfG+sJvS3KvyF3E5.fG4rC3Iv38zfWOtql3NwkGtyzwZGnt+czS
Sdt582JQjZ0VCoE7exYXFNYc7hm15KO7SCcbjJwNvv40AFPX1UjxWnZqUosd
X3KLVK5UAWdEnNLnaGHjOUdriIWHypX39IOiFXLbafEyD4OpL3h0VgLq5GTZ
b7NdP4fNEbELGqWnq5S5JfO4QbqJGFqchXUlLokCYUkxj7g28KdviXikUktq
MRp7TomKVC9ok0vI2v7I2GLuETXz.hucctK5jyYOF+7l9dVmVm0on2TaFv8T
OMTWGp9MxCtqLn51g4Zm2VmvaYYmQdp.xFgOZHEP3KbEPT8J2rWATuBnbXrK
XEPHOU.UZjBpbEPjdEPkMgaLPuBndEPMqBHza.EPPOU.wXMnBHvEtBHrdAbz
q.pWATNL1ErBHnmJfJMjSUtBHXuBn5dlV2q.pWAzwn.Bd4q.xO4O1H3PyH+g
Kurk+HwLGq1XWwAhd0OW9pet3k93mtmRCALkp6gK508Tx5eQvcrz58LnyzK6
oW1iCYOWBZd73Dz.AEiSibjDyolV9cTSomsFbbKe1ZPrBuHM9Yqw91BReLHZ
1fDO3J2lylBmcqCx4ksyi3czFfDPJd7RBwNNE0g1cO7oYmGU8VLm3YveJY+p
0p6vb5E9FLGAcbJNAYzwhzACQ8HGzuCyakcX96alcX96ekD9HndF5mNIXa5E
dnggg5w1cI191lAae6qDrM1y.+zo.aS3W3XaH1g3tdr8ICaeSyfsu4UB1F4Y
Xe5jfsIW1XaEJtGZ2gP620LP62ctFzmt8KShhBl62AirnvXBUZXtgy5pw5.6
0oQrnSCwMY5pVkQ3FtLewmfJKNOwHmQAZKDmWLB2Pvcu4+VeM+pdOUOyO8LJ
Ja417S6dy+MUY9wlYOwTXKZ9Kg4gcNEesba9kcu4+c9Z9QhZZ9QmOQWK2V+t
M5l8OClFnDB46zKfsZ6LdLRYoF9tZ1Ev7hq4LDVzwSufeQaBjmQahN5zcl9Z
Irl46ZLrOXS3z66sVPdA6IrqiNaZYuVBpY8vtCA1geqB6fdB65nSVS5qkPZ1
k+4YVa.6fuQgc9g45niGP+N3D59nYVOj6.fbWT3sfYUMP0Hq6.AMFIxLhEvj
arGHPYH.PCh.tedXzuGGZssP.ft45OlcYDOJ0G4lWpTHnMo5hnLeadJl.fTL
ZyJ.O+jSUD2wA1SO.L0wwJhcPSHkgzBiRgwV7vCYJVaohrKCcyBPOWAs3Ufs
wx57YkCdkS4gwdwKrNXcDY7S6Hw6jQfAS3iY4mmP8fAWnVzwxSsMF+Es8V8k
KZ+wXLvuYaRhcbzVnK6fxZYTtaY0qW281Ua+NmNkmsCjP5JP4ASEb+hkyBLE
D31Zv8xCXd1LkbTl8D.VWLoE25.xr6vfQoO2Yyyh.Su4NP7Qddo79FU5XRJw
wDhc3XRgtFYP6XJippkbMGyn7aGir9vK0Mo1fjF+h9EavOV0V7AhcSYvDkQY
rCObRoLHTomTF1CD9SNkw9LxL2jCIAC31kc.i5YGZP1ABV5M6.7rkcHY5bpg
pBHjVSYEfyGYE5BOP4LfUdERlfSAhtWVAk5qrBkUuSzUzybz55Jf50TRdOyy
YcE+jl1vSYEN3LXkNYvP44itBmbFRz4mtBGrCP.r8oGJ+DEnmdnIDVb1RO77
DOVBlIj.E7NQvhadWJXOdYLP6tMckzhlchvnM.JLrUT5AsU2u+wGBmW20c70
oGN1hQnknGsnKDGr0CKmqLQf4DhDJw..faf0.NjIQB.B.UHjDWYNfvQpGkRE
jBQ1fEZggIENE3pkbP9FiCh8StkxBJ1CaiD0ftAaGg2gKClEopGFVxboY8AT
FblxfBXTEE.EwE5MbdxYEs9WsrCR93Tvp0KeXxzfzgnfi20oPLdPQ0BS2Jgo
EAT5PxADUtqCVlx2w7TC0au+U1rbiqjwra11+YbnVsX8xoaHzzNABthKaWlM
KXUbXz157OuatgFruQf06bh4QNom42iOmPdjSZRviOm.97NIZfbhI7HmLGIQ
odpcZBNp7FA7KyAtybvQk44embm4RZa7hm+UZO4sr571hSm77yuDrbCCjIaU
T7+lktPLx7mgQ1+jY9ykAuDt44MyT5vIKUzowJtz0Ks7seMYU9a3mVFsNLIu
M7VCMMenEmr54I12MSqLW+WW++M317aD
-----------end_max5_patcher-----------
</code></pre>

Virtuoso Midi Bridge

When experimenting with the Virtuoso VR instrument I discovered that thier MIDI bridge application did not run on my Mac. I made a simple bridge in MAX that connects their Harp and Rimba instruments to Ableton. Tilt is only available for the Rimba, as the Virtuoso harp instrument does not send tilt information.

Copy the text below and select ‘New from Clipboard’ in MAX

<pre><code>
----------begin_max5_patcher----------
2051.3oc6b01aaaCD9y1+JDz9ZZ.eQTjZeqX6Cq.qCCcXEEHnnP1lwQsxRFx
zYoqX+2GeSxxNRVzNxNxsAnPNllRG4Cum6NdGU+13Q9Sxefux26m8twaznuM
dzHcSpFFY+9H+EwOLMMdkta9SyWrfmI7ux7aB9CBc6+EW3IRREdEwYy4k+bZ
RFeZ95LceP1FWVvWIeDwhj7rOUvmJLxmPhtFbkGDRTeDAzegcMv6i16KYlVR
4S97qfgP+FdZpeGZaek3qob8MTvmkwkC+xaHVL8tjr40Dc.AokFPOBHL0UTT
MQmsdQRVJWrptDjMluVT1JP03+Mdr5xUNBloI2yuV9XT8x9PuOtHKdgYf+13
GtA9Q+NfMHTO1QZ.KHP+ERyvFFsADJjRQvK9DOKdhAnJmWlIk3qK4FI36ekm
+so4wRI9wNP83oB4bZx7o4o4ElaGbMEABiXWI+KXHEgU+AfA.v.4Hs1.sgEF
nZZQTytf1ldNrzTp3sJ9d9rOEKDEISVK3a9qU10H6hTCSiQ090Q97GTy+U14
tuuoc45t81uONcMO+1Geiaf8jrDQRbpcZBplOM0oGuFsUuRyyl2rNyVcagT0
S+H.JnrgeOel7e5mRS+7p6xKDaDSRVSxnTooog4Z4johTRJgrwa9nmIOIYtS
d.rtIOPL7hk8.QeGyd.W2erm5JM+PydhenCpS.g3reGoO8KLpSjz8+K9cNL+
NuPapMB6h13jGGH6Rk17hCGmc37CCsQuWwFHM+c1h3k2fcMVMRaVj2AQ1hIg
.GMSxARzZQ9hpV8+f+IJbNPTXc1kYixcyt1L71c.Vs68pVF9LQtbHZWc9fZ4
4C9MxE2hksiFVyTsmJMSKj8QzPmXdzae8e5NKB2l+G0S2t7Hef9MwkfmRtTe
yYBnGiGoJlQML3hhaH6MTg3xOQNvP1R24zvO1fjOKri5zytBN63bwPt7cwDI
CK8EOLGqGlu6cu3H84o3aI7xw2Bivdw0hStVtv8qzVMuda7RSMullmIJxSW8
TJ6E1kxdAH8YYufPlYCEm8Be0Fh95oS4KEdu8M+5a7ldWbVFOsQaNaAv38Cv
RGypoEUekni9M.zL9x5U3kvLBNvVWyvGszdhPWQ974o7NLVS0iJpwzUX40FQ
k8ZSFzlM4jLGx+zAgmjPCdR0poAkWOD3DNvUVwDpqJqznd0VP.PKSFZPpshA
tqtBGFpqPLMzfnmY80YpDU1gSG.ciBl4vOntVMxVk7ul.tJy9X0NefOFviNN
6C6jg5LNeVJuVnYl7TT+RUe02p7Atbsn9X5fW0D2kL8K5FT9o2jq0Vx9lsVw
l.8BokWG.qmA1Ux9Y8j7iw5IB87rd19QnJalWZ9z3Tu2z0VsBQXs4Dc3hl3L
ZKnQVPu5mvDMEw7Ajd1bSzFp89jBw57U4du+cdhbs23NvNY3tpndwlU+v8gc
ggcgcM.QgAZEbLjUKYROmPz6RVLItCPAg0CyWYOLY5UWLtksgPppK4sxc9TZ
bQ6g6fQKI+SKYbPqh9LCW+VbQWIJDtAqhB1OTE1ePUohUPaB9DATRyypc+6T
HEVyCfRqSMeRpXGkGFURGlDmMu63ztMuXQrdfEdL13.T8bIhVyq5VSFWph8o
BnsGVUm.5.z.GnM9fO6.caT+emeqvKV5FtHY9clCzraqFVmIz8l8l.Vu5IFX
79GEU+Dk7b5mQuS3eYO6Dt194rYK0rWdJdu3FtWgMbn1keDVKTF8bgZpSMDu
vQbAoSLWWr6dhbKGlIKLo2EF1qPsgPDgQGB8V1T0vo2X7SVKTkdvoffvFkxv
xqMA9niaSRaC7SRSx9haaQZmpVHiAPF6c.EPXLDlnqZAhFP.QL.NBAITSSXB
Jprqg6TQi9wFjIiLQFiO.P0GOyYkKKWv8xu81tyHGxoLxETWENpEch909NxX
aBaBFYflQNbP2YjCOTxHGxTgCrI8pmuLx4joejIOgNY5GSNww0cXkQxZemMP
hh6OTb+epK3lEVKBDxdq6V.reI1F5hsxelBwLXh.AYyljKpgACJ0PjcKQCE0
v2ySymlH9Zm7dl6JhriHeTPaJnr5aO+4i5.1mfz1h66S.0mrTVjIxFHc.tMA
n87Y4BIMZfuKAlYiXAl3aF9aR.55VDh.m2sHzK0XOh9cd77PSkSLwyGh2W77
gzd0fRHZ.GNO04n4CICin4s1MFlAy+J2sOGBGPAQQsGLfKpP4sG6TmBfpWyk
HCAGtAxSbOShAfAjJHy3z4RKLdakScQIDeLQwSs6t4bGDuSwDQLAKCa6jNs0
+0szCQE0G5YQl3MMT3yn6C9+HggGokAocchOLlWLEK27Z11FctR85z6D1lwb
RTTKCqsPQzoFEAcAhA0.Q7dsIROefHjETCDaXXcdAQXHqKXD5LLFdFgQbzfB
FiPcY0j4NLBNe3n0v34FFWF6P5f1btaTQppd2EnvVPL7Q3jEyLu5Rg1yhDq5
iCxM6A+96LY9sIooG3auy35uDOO5UST5uzrhinaNGjsUEwvcJf3NEOb27Lju
LunDMkOknZq15doeAX14+V4znsp8sUAVkutXZopbY7AdaD1L9JQRV0Z2MUd3
p0m7hY7h1iuoWkLsYICO8RVYBnIQiOChtYIidZRVc3j5TzpCirpSOREKd4x6
4EkrBsTj1S9rQ4lc0XSNBMeUmtRoku6SJ6u1rkebgz.fPx9WWXLN9Pn4LUnY
SEYqSrqsZVlu1Vk58Na0xXyTQaRa7+M9+AfvvnMN
-----------end_max5_patcher-----------
</code></pre>

Arduino Code

Below is code for my Arduino Leonardo (or clone) to process 12 piezo inputs into MIDI. Use one Leonardo for the upper octave and another for the lower.

/*
  * 24_channel_tonnetz_drum_array.ino
  *  Cloud Unknowing 2024
  *  Extensively Modified for Leonardo running MIDIUSB
  *  Functions from demo code:
  *     Created: 4/6/2015 10:47:08 AM
  *     Author: gurbrinder grewal
  *     Modified by Arduino LLC (2015)
  * Parts of body logic:
  *     Xylophone
  *     from Jenna deBoisblanc and Spiekenzie Labs initial code
 */ 

#include "MIDIUSB.h"

//*******************************************************************************************************************
// User settable variables
//*******************************************************************************************************************
int Cyc = 10;      // Note length, set all at once. This is very short, intended for instruments without sustain
int CutF = 90;     // Minimum hit value, set all 90 fot lower 100 for upper

int pinRead;

// char pinAssignments[16] ={'A0','A1','A2','A3','A4','A5','A6','A7','A8','A9','A10','A11','A12','A13','A14','A15'};

// Notemap using the below values:
//      Pin                    1    2    3    4    5   6    7   8   9   10  11   12
//
//      Order of pins on the LEONARDO
//                             1    2    3    4    5   6    7   9  10   11  12   8
//
//      Note (tonnetz)        C#0, G#0, D#0, A#0,  F0, C0,  G0, D0, A0, E0, B0, F#0 (1st Octave)
//                             49   56   51   58   53  48   55  50  57  52  59   54
//      For LEONARDO           49   56   51   58   53  48   55  57  52  59  54   50
//      My module              56   49   48   53   58  51   54  55  59  57  50   55
//
//      Note (tonnetz)        C#1, G#1, D#1, A#1,  F1, C1,  G1, D1, A1, E1, B1, F#1 (2nd Octave)
//                             61   68   63   70   65  60   67  62  69   64  71  66
//      For LEONARDO           61   68   63   70   65  60   67  69  64   71  66  62
//      My module.             60   65   70   63   68  61   66  71  64   69  62  67


// byte PadNote[16] = {49,56,51,58,53,48,55,50,57,52,59,54};         // MIDI notes Lower Octave linear
// byte PadNote[16] = {56,49,48,53,58,51,54,59,57,52,50,55};         // MIDI notes Lower Octave My setup


// byte PadNote[16] = {61,68,63,70,65,60,67,62,69,64,59,66};         // MIDI notes Higher Octave
byte PadNote[16] = {60,65,70,63,68,61,66,71,64,69,62,67};         // MIDI notes Higher Octave My setup

// Minimum Analog value to cause a drum hit, Change individual values if any pads are giving you trouble
int PadCutOff[16] = {CutF,CutF,CutF,CutF,CutF,CutF,CutF,CutF,CutF,CutF,CutF,CutF,CutF,CutF,CutF,CutF};           

// Note length, change individual values for splits, etc.
int MaxPlayTime[16] = {Cyc,Cyc,Cyc,Cyc,Cyc,Cyc,Cyc,Cyc,Cyc,Cyc,Cyc,Cyc,Cyc,Cyc,Cyc,Cyc};  // Cycles before note off (also before a 2nd hit is allowed)

int midichannel = 0;                              // MIDI channel from 0 to 15 (+1 in "real world")
boolean VelocityFlag  = true;                     // Velocity ON (true) or OFF (false)

//*******************************************************************************************************************
// Internal Use Variables - these structures have 16 elements for code reuse with the Mega
//*******************************************************************************************************************
boolean activePad[16] = {                   
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};         // Array of flags of pad currently playing
int PinPlayTime[16] = {
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};         // Counter since pad started to play
byte status1;

int pin = 0;     
int hitavg = 0;

// First parameter is the event type (0x09 = note on, 0x08 = note off).
// Second parameter is note-on/note-off, combined with the channel.
// Channel can be anything between 0-15. Typically reported to the user as 1-16.
// Third parameter is the note number (48 = middle C).
// Fourth parameter is the velocity (64 = normal, 127 = fastest).

void noteOn(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
  MidiUSB.sendMIDI(noteOn);
}

void noteOff(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
  MidiUSB.sendMIDI(noteOff);
}

void setup() {
  Serial.begin(115200);
}

//*******************************************************************************************************************
// Main Program
//*******************************************************************************************************************

void loop() 
{
  for(int pin=0; pin < 12; pin++)                          // 12 inputs for Leonardo, 16 for Mega.
  {
    MidiUSB.read(); //this is undocumented magic that stops the Leonardo from freezing.
    hitavg = analogRead(pin); 
    // Serial.println(hitavg);   //debug breadcrumb

    // read the input pin
    if((hitavg > PadCutOff[pin]))
    {
      if((activePad[pin] == false)) //this blocks new hits from being processed if one is already active on the pin. Make this always true if noteoff is disabled
      {
        if(VelocityFlag == true)
        {
          // This was: I took it out to save cycles. Put it back in again for more accurate velocity scaling for pads with altered sensitivity
          // hitavg = 127 / ((1023 - PadCutOff[pin]) / (hitavg - PadCutOff[pin]));
          hitavg = (hitavg / 8) -1 ;
        }
        else
        {
          hitavg = 127;
        }
        //MIDI_TX(144,PadNote[pin],hitavg); //note on // Placeholder for use with another library
        noteOn(midichannel,PadNote[pin], hitavg);  
        MidiUSB.flush();
        PinPlayTime[pin] = 0;
        activePad[pin] = true;
      }
      else
      {
        PinPlayTime[pin] = PinPlayTime[pin] + 1;
      }
    }
    else if((activePad[pin] == true))
    {
      PinPlayTime[pin] = PinPlayTime[pin] + 1;
      if(PinPlayTime[pin] > MaxPlayTime[pin])
      {
        activePad[pin] = false;
        //MIDI_TX(144,PadNote[pin],0);        // Placeholder for use with another library
        noteOn(midichannel,PadNote[pin],0);   
        // Note off. Not always needed and not always helpful for percussion. Some instruments won't work without it though
        // You can leave this whole section out for faster polling/processing. Ableton instruments don't seem to mind, just set sustain to 0 and turn up release.
        MidiUSB.flush();
      }
    }
  } 
}