tag:blogger.com,1999:blog-26714394181880485502024-03-14T00:04:52.083-07:00GordophoneWires, sensors, code, MIDI -> new instruments.
<p>
My blog about experimenting with Arduino, MIDI, synthesizers, sonification, and other music distractions.</p>Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.comBlogger44125tag:blogger.com,1999:blog-2671439418188048550.post-85293450711312563942021-03-08T15:44:00.011-08:002021-05-27T19:28:03.877-07:00Sonifying Air Traffic<p>A while ago I got a <a href="https://flightaware.com/adsb/prostick/">Flightaware Pro Stick Plus</a> - a neat little software-defined radio that lets my little Raspberry Pi Zero decode <a href="https://www.faa.gov/nextgen/programs/adsb/">ADSB</a> transmissions from aircraft. These transmissions broadcast the location and altitude of each aircraft, in addition to other data.</p><p>So, I thought, why not turn those transmissions into music?</p><p>Code (evolving work, is a bit messy): <a href="https://github.com/ggood/adsbTheremin">https://github.com/ggood/adsbTheremin</a><p>General idea: python code reads the stream of aircraft position reports and creates a map of where the aircraft are and their distance/altitude relative to my location. Then map this information to <a href="https://en.wikipedia.org/wiki/MIDI" target="_blank">MIDI</a> note on/off events and send this information to <a href="https://www.ableton.com/en/" target="_blank">Ableton Live</a> running on my Mac.</p><p>Listen to the long notes - lower pitches are aircraft at low altitudes, higher pitches are aircraft at higher altitudes. At about 2:50 you can hear the general aviation aircraft doing touch-and-goes at the Palo Alto Airport (low tones), while the commercial airliners pass overhead, with much higher pitches.</p><p>There is a lot of arpeggiation (jumping-around notes) to keep things interesting, but the long notes you hear represent the position and altitude of the aircraft.</p><p><br /></p>
<iframe allow="autoplay" frameborder="no" height="300" scrolling="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/986828497&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true" width="100%"></iframe><div style="color: #cccccc; font-family: Interstate, "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Garuda, Verdana, Tahoma, sans-serif; font-size: 10px; font-weight: 100; line-break: anywhere; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; word-break: normal;"><a href="https://soundcloud.com/gordongood" style="color: #cccccc; text-decoration: none;" target="_blank" title="Gordon Good">Gordon Good</a> ยท <a href="https://soundcloud.com/gordongood/airplanes-feb-15-2021" style="color: #cccccc; text-decoration: none;" target="_blank" title="Airplanes Feb 15 2021">Airplanes Feb 15 2021</a></div>Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com0tag:blogger.com,1999:blog-2671439418188048550.post-7194426897419210152016-07-08T23:32:00.001-07:002021-03-08T16:20:42.487-08:00My King VOX Ampliphonic Octavoice IIIn a discussion thread on my original wind controller post, I got a question from <a href="https://www.blogger.com/profile/09749402000641517245" rel="nofollow" style="background-color: #f6f6f6; color: #9e5205; font-family: "Trebuchet MS", Trebuchet, Verdana, sans-serif; font-size: 14.3px; font-weight: bold;">DBaylies</a> about how to sample a brass instrument's sound at the mouthpiece. That reminded me that I had an old "octave divider" effects box that <a href="https://www.dso.org/about-the-dso/our-orchestra/brass/trumpet/kevin-good">my brother Kevin </a>had handed down to me at some point.<br />
<br />
The octave divider, which was part of the Vox guitar amplifier line manufactured by the Thomas organ company, allowed a trumpet player to lower the pitch of his/her instrument by one or two octaves. It was called the Octavoice, and you can read more about it here:<br />
<a href="https://www.blogger.com/goog_1543164201"><br /></a>
<a href="http://www.voxshowroom.com/us/amp/octavoice.html">http://www.voxshowroom.com/us/amp/octavoice.html</a><br />
<br />
To use the Octavoice, the trumpet player drilled a hole in the mouthpiece, and screwed in an adapter that allowed the Octavoice's transducer fitting to be attached to the mouthpiece. Since I'm a trombonist, this picture shows the fitting on a trombone mouthpiece.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-efeBGxShAts/V4CXW2aduwI/AAAAAAAANhM/3I1XSWo6gksyEOlrfe6B3aRMpo457PIvgCLcB/s1600/IMG_5883.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://1.bp.blogspot.com/-efeBGxShAts/V4CXW2aduwI/AAAAAAAANhM/3I1XSWo6gksyEOlrfe6B3aRMpo457PIvgCLcB/s320/IMG_5883.JPG" width="240" /></a></div>
<image></image><br />
<br />
And when the transducer is attached to the mouthpiece, it looks like this.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-8z3-GWPHg5w/V4CXnXJSlSI/AAAAAAAANhQ/1NmtNmp0aJwSab42rtqldxPcdTz6VmHXACKgB/s1600/IMG_5884.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://4.bp.blogspot.com/-8z3-GWPHg5w/V4CXnXJSlSI/AAAAAAAANhQ/1NmtNmp0aJwSab42rtqldxPcdTz6VmHXACKgB/s320/IMG_5884.JPG" width="240" /></a></div>
<br />
<image></image><br />
<br />
This device was produced in the late 1960s or early 1970s, so there is no digital signal processing going on. Inside the box are a bunch of transistors, resistors, capacitors, and inductors - not even any IC op amds. I'm a little stymied on how this box could produce an octave shift down, but I am a computer engineer, not an electrical engineer. Here are some photos of the inside of the box.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-xSYbSL2zqx4/V4CXns0WAaI/AAAAAAAANhY/x4Ji0JKmXYAzrhmdtd0jlpicckyd9AA5ACKgB/s1600/IMG_5886.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://4.bp.blogspot.com/-xSYbSL2zqx4/V4CXns0WAaI/AAAAAAAANhY/x4Ji0JKmXYAzrhmdtd0jlpicckyd9AA5ACKgB/s320/IMG_5886.JPG" width="240" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-6zMjfeLSikI/V4CXpMKJu5I/AAAAAAAANhc/E_f-XszDqqcmnW9RparTKTZ201y2Ua-dACKgB/s1600/IMG_5887.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://1.bp.blogspot.com/-6zMjfeLSikI/V4CXpMKJu5I/AAAAAAAANhc/E_f-XszDqqcmnW9RparTKTZ201y2Ua-dACKgB/s320/IMG_5887.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-Us4nMx9H10s/V4CXqH878vI/AAAAAAAANhg/51qhYweIMwMZIz7J5akjyy4L8Owc039cACKgB/s1600/IMG_5888.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://4.bp.blogspot.com/-Us4nMx9H10s/V4CXqH878vI/AAAAAAAANhg/51qhYweIMwMZIz7J5akjyy4L8Owc039cACKgB/s320/IMG_5888.JPG" width="320" /></a></div>
<br />
<br />
<br />
Whether or not I understand how it works, it does work. I used it to record the "tuba" track for an entry in the contest to be the song on the flexi-disc included with the Billy And The Boingers Bootleg collection of Bloom County comics by Berkeley Breathed. We didn't win, since we weren't so heavy metal, but I still do sort of like the song we made.<br />
<br />
So, for DBaylies: if anyone can offer suggestions on how to build something similar to how build a mouthpiece-attached transducer, post here. The goal is to get an audio signal into the input of an analog-digital converter for processing in the digital domain.<br />
<br />Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com4tag:blogger.com,1999:blog-2671439418188048550.post-5897306332833472152016-04-21T23:38:00.001-07:002016-04-21T23:47:00.203-07:00Building a Woodwind Controller Using the MPR121 Touch Sensor<h2>
</h2>
The Akai EWI uses a set of touch-sensitive metal keys:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-tgII62L9Yn8/VxhUXIXZtBI/AAAAAAAANZk/3EHnscgt9nIu1XwRjPW48oiuRgG1KVXvgCLcB/s1600/ewi_close.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="https://1.bp.blogspot.com/-tgII62L9Yn8/VxhUXIXZtBI/AAAAAAAANZk/3EHnscgt9nIu1XwRjPW48oiuRgG1KVXvgCLcB/s640/ewi_close.jpg" width="640" /></a></div>
<br />
A key is actuated simply by touching it. The instrument detects the change in capacitance that results when your body touches the key. For more information on how this works, see https://en.wikipedia.org/wiki/Capacitive_sensing. And for some videos of people playing the EWI, look on YouTube. I especially like this one of the late Michael Brecker: https://www.youtube.com/watch?v=tPUBp9uTLIw<br />
<br />
<h2>
Can I Do This? </h2>
<br />
Is there a way to inexpensively build this into our own wind controllers? The answer is definitely yes.<br />
<br />
NXP Semiconductors manufactures a very low-cost chip, the MPR121 ($1.95 in single quantities), that provides 12 separate touch inputs.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-5ndOdqgX_0w/VxhXhRXXRtI/AAAAAAAANZo/gfruQdHUefAdSCGVYEnby2gsEOJ9hRVjACLcB/s1600/mpr121.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://2.bp.blogspot.com/-5ndOdqgX_0w/VxhXhRXXRtI/AAAAAAAANZo/gfruQdHUefAdSCGVYEnby2gsEOJ9hRVjACLcB/s200/mpr121.jpg" width="200" /></a></div>
and Adafruit Industries has a <a href="https://www.adafruit.com/products/1982" target="_blank">nice breakout board</a> that breaks out the tiny pins on the chip, and has some support circuitry that allows use with either 3.3v or 5v controllers.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://cdn-shop.adafruit.com/970x728/1982-00.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="150" src="https://cdn-shop.adafruit.com/970x728/1982-00.jpg" width="200" /></a></div>
<br />
Sparkfun also has <a href="https://www.sparkfun.com/products/9695" target="_blank">a breakout board for the MPR121</a>. It doesn't include the level shifters to allow 3.3/5v operation, but is less expensive.<br />
<br />
I won't write a tutorial on how to wire up the sensor and use it, since <a href="https://learn.adafruit.com/adafruit-mpr121-12-key-capacitive-touch-sensor-breakout-tutorial" target="_blank">the Adafruit tutorial</a> does a great job of that. Instead, I'll show how we can incorporate it into a woodwind-style controller.<br />
<br />
One thing that may occur to you is that there are only 12 inputs, but typical woodwinds have more than 12 keys. Is there a way to use more than one touch sensor chip in an instrument? Yes, there is. The MPR121 is an I2C device, which means you can attach more than one to the same two-wire communication bus, as long as they have different addresses. Both the Adafruit and Sparkfun breakouts include a way to set the address (up to 4 different addresses can be set), so it is possible to do touch-sensing on up to 48 keys. That should be enough.<br />
<br />
<h2>
Modifying get_note() For Touch Sensing </h2>
In my post, <a href="http://gordophone.blogspot.com/2016/02/note-selection-basics.html" target="_blank">Note Selection Basics</a>, I define a function named get_note() that read the switches that simulated our "trumpet valves" and returns the MIDI note to play. Let's replace that with a new function that can read the MPR121 and detect which of the 12 inputs is being touched.<br />
<br />
First, a little background. Adafruit provides a library for the MPR121 that makes configuring and reading it very simple. To initialize the chip:<br />
<br />
touchSensor.begin(0x5A);<br />
<br />
(0x5A is the default I2C address of the Adafruit breakout)<br />
<br />
Then, to read all of the pins:<br />
<br />
uint16_t touchValue = touchSensor.touched();<br />
<br />
This will return a 16 bit value where each of the lower 12 bits is a 1 if the key is touched, and a 0 if it is not. Which bit corresponds to which key depends on how I wired the brass washers to the touch sensor input pins. In my case, the octave keys are mapped to bits 0 and 1, and then the rest of the keys are:<br />
<br />
LH index finger: bit 2<br />
LH ring finger: bit 3<br />
LH middle finger: bit 4<br />
(bit 5 not used - it's an extra key on my instrument not currently used)<br />
RH index finger: bit 6<br />
RH ring finger: bit 7<br />
RH middle finger: bit 8<br />
RH pinkie: bit 9<br />
(bits 10, 11 not used)<br />
<br />
<h3>
Table Lookup for Note Mapping</h3>
As I mentioned in the Note Selection Basics post, a C language case statement will start to get pretty ugly for an instrument with all these keys, so let's look into a table lookup approach. We'll build a table that has, in one column, the expected bit values read from the touched() function of the MPR121, and in the next column, the MIDI note to send.<br />
<br />
In C, we can define a structure that holds one row of that table like this:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">struct fmap_entry {<br /> uint16_t keys;<br /> uint8_t midi_note;<br />};</span><br />
<br />
This is a chunk of memory that can hold a 16-bit value (named "keys", which will hold a bitmap of key values), and an 8-bit MIDI note value.<br />
<br />
Next, we'll build an array of these:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">#define FMAP_SIZE 33</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">struct fmap_entry fmap[FMAP_SIZE];</span><br />
<br />
This defines an array (or table, if you prefer) of 33 rows of the structure we define above.<br />
<br />
To map from a fingering to a MIDI note, we start at the beginning of this table and check to see if the fingering we just read from the sensors matches the value in the "keys" field. If it does, we've found the MIDI note and we're done. Otherwise, we skip to the next entry, and so on. In programming, this is called a linear search.<br />
<br />
We actually need to initialize the "fmap" array with all of the key and note values. That's very verbose, so I'll omit it here and will just include it with the full code.<br />
<br />
So here's the revised get_note() function. Since my instrument has an extra key I'm not using, there's a little code (in blue) that makes sure that even if the player touches that unused key, it won't change the value we read, so we don't need to have entries in the table for when that key is touched/not touched.<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">int get_note() {<br /> // This routine reads the touch-sensitive keys of the instrument and<br /> // maps the value read to a MIDI note. We use a lookup table that maps<br /> // valid combinations of keys to a note. If the lookup fails, this<br /> // routine returns -1 to indicate that the fingering was not valid.<br /> int ret = -1; // Sentinel for unknown fingering<br /> uint16_t touchValue = touchSensor.touched();</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"><br /><span style="color: blue;"> // Since we're not using the 4th finger of the left hand, mask off that key<br /> touchValue = touchValue & 0b1111111111011111;</span><br /><br /> <span style="color: red;">for (uint8_t i = 0; i < FMAP_SIZE; i++) {<br /> if (touchValue == fmap[i].keys) {<br /> ret = fmap[i].midi_note;</span></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: red;"> break;<br /> }<br /> }</span><br /> return ret;<br />}</span></span><br />
<br />
The for loop (in red) is where we do the linear search. We look at each keys value, and when we find a match, we stop looking and return the corresponding MIDI note.<br />
<br />
If we don't find a match, then the player has their fingers in a non-supported position, and our function returns -1, which means to take no action. In other words, we ignore the glitch. That's not the only thing we could do. If, for example, we wanted to try to mimic how a real instrument behaves, we might send a pitch bend message to indicate that the pitch should be a little sharp or flat relative to the normal fingering. There are a lot of possibilities.<br />
<br />
Ok, now that we've had a look at some code, is it possible to build something?<br />
<br />
<h2>
A Test Platform </h2>
I've built a very hacky prototype woodwind-style controller as a platform to test these ideas. The body of the instrument is a 14" length of PVC plumbing pipe, 2" or so in diameter. I was going for roughly the dimensions of an alto recorder, but chose a thicker tube to make running wires inside a little easier.<br />
<br />
To make the touch-sensitive keys, I soldered lengths of wire to ten brass washers:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-W3WQm46liyU/VxmvweAFK0I/AAAAAAAANaE/A5uhUPjaR5YWAuXV0BT4CnzcHnbsSdyOQCLcB/s1600/Washer.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://4.bp.blogspot.com/-W3WQm46liyU/VxmvweAFK0I/AAAAAAAANaE/A5uhUPjaR5YWAuXV0BT4CnzcHnbsSdyOQCLcB/s320/Washer.jpg" width="320" /></a></div>
<br />
<br />
Then I drilled holes in the tube, ran the wires from the outside to the inside, and hot-glued the washers to the outside of the tube, about where my fingers would fall. I didn't arrange the keys to resemble any particular instrument, although they're somewhat like a recorder layout (albeit with one extra key for the left hand, oops). The Frankenstein-like contraption looks like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-Uld2PNEeJRc/Vxmw1zbAAlI/AAAAAAAANac/ZUPNTHF3UZ8ZfFWs1YOzTgJS_p4t_Ve8wCKgB/s1600/Top.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="https://3.bp.blogspot.com/-Uld2PNEeJRc/Vxmw1zbAAlI/AAAAAAAANac/ZUPNTHF3UZ8ZfFWs1YOzTgJS_p4t_Ve8wCKgB/s640/Top.jpg" width="640" /></a></div>
<br />
The white mouthpiece protruding from the top is something I made to use with my Blowchucks Controller for the Electro-Music Festival in 2014. It connects to a tube that runs down the length of the instrument and connects to the Freescale pressure sensor I've been using in all of my wind controller projects. <br />
<br />
On the back, I added two octave keys, and strapped all of the electronics near the base. This means I only have a USB cable running from the instrument to my laptop.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-KhaGSkE-xpA/Vxmw3U5zBII/AAAAAAAANag/k0JCe2alixYpxDkoR2YQT_ubDBYSb-aSgCLcB/s1600/Back.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="https://3.bp.blogspot.com/-KhaGSkE-xpA/Vxmw3U5zBII/AAAAAAAANag/k0JCe2alixYpxDkoR2YQT_ubDBYSb-aSgCLcB/s640/Back.jpg" width="640" /></a></div>
In this close up of the electronics, you can see the MPR121 touch sensor breakout on the left. The green and white wires that attach to that board are the wires coming from the brass washers. The board to the right has the Teensy microcontroller mounted on the right, the the pressure sensor on the left. You can also see the power and ground (red/black) wires going to the touch sensor, as well as the two wires (yellow/white) that connect the touch sensor to the I2C bus on the microcontroller.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-4RBVOdolnDA/Vxmw42MieVI/AAAAAAAANak/wcMCiZ_Zcusx7ZJD0tYh_NCFEZSzF7GRACLcB/s1600/Electronics.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="https://3.bp.blogspot.com/-4RBVOdolnDA/Vxmw42MieVI/AAAAAAAANak/wcMCiZ_Zcusx7ZJD0tYh_NCFEZSzF7GRACLcB/s640/Electronics.jpg" width="640" /></a></div>
<br />
I'll do a proper video later, but for now, here's a quick audio demo of the instrument running the code below. You'll hear some glitches as I'm not a woodwind player and have a hard time getting multiple fingers to touch keys at exactly the same time. We can de-glitch that stuff in code, and I'll work on that for a future post.<br />
<br />
<br />
<iframe frameborder="no" height="166" scrolling="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/260307476&color=ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false" width="100%"></iframe>
<br />
<br />
The full code is posted below, and is also available at <a href="https://github.com/ggood/NoteSelectionTutorialRecorder">https://github.com/ggood/NoteSelectionTutorialRecorder</a><br />
<br />
<br />
<script src="https://gist.github.com/ggood/0b04d55cf21c6c93f6698942d82a73c3.js"></script>
Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com13tag:blogger.com,1999:blog-2671439418188048550.post-69864744616167070192016-04-20T00:06:00.001-07:002016-04-20T00:13:21.850-07:00Note Selection - How fast do we need to be?<h4>
A Different Approach</h4>
As you probably noticed, I was lucky enough to have <a href="http://gordophone.blogspot.com/2016/04/guest-post-alternative-way-of-note.html" target="_blank">a guest post from Johan Berglund</a>, who showed how to use a simple algorithm that reads all of the switches (keys) of the electronic woodwind, and adds or subtracts semitones from the "center" MIDI note that the instrument produces with no keys pressed.<br />
<br />
After reading Johan's post, I thought some of you might be interested in
how important it is to have a fast algorithm for map key events to MIDI
note on/note off events. For the impatient: it doesn't matter very
much. <br />
<h4>
Johan's Algorithm</h4>
With no keys pressed, Johan's instrument will play a MIDI note 61, which is a C#4 (one half-step above middle C on a piano). Pressing the left-hand index finger switch will lower the pitch by 2 semitones, which means his instrument will produce a MIDI note 59, or a B3 (one half-step below middle C). When more than one key is pressed, all that's needed is to sum all of the effects of each key, although though there are a few exceptions where several keys interact, so some logical AND and NOT operations are needed.<br />
<h4>
My Lookup Table Approach </h4>
By contrast, my approach uses a lookup table. I scan all of the switches, and put the value of each switch (on/off) into a bit array. So if only the left-hand index finger of Johan's instrument is pressed, my bit value would look like 00100000 00000000. If all of the 14 keys in Johan's instrument are pressed, the bit value would look like 00111111 11111111. The leftmost 2 bits are always zero because we're putting these 14 key switch values into a 16-bit number, so 2 bits are always zero.<br />
<br />
I maintain a table that has two columns: a fingering bitmask value, and a MIDI note, like this:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">Bitmask MIDI note</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">...</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">00100000 00000000 59</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">...</span><br />
<br />
To figure out which note our instrument should be playing, we read all of the switches and pack them into a bitmask, then start at the beginning of this table and compare the current switch on/off values with the bitmask in the table. When we find a match, we know which MIDI note to produce.<br />
<br />
Now, if we naively create a table that has every possible combination of those 14 switches, we'll end up with a table with 2^14 slots, or 16,384 slots. Since the bitmask is 2 bytes (16 bits) and the MIDI note is 1 byte (8 bits), my table will occupy at least 3 * 16,384 = 49,152 byes, or 48 kbytes. That's way more RAM memory than the Arduino Uno has (2 kbytes), so we need to be smarter here.<br />
<br />
One trick is to realize that not all fingering combinations need to be considered valid. For example, no saxophone player will use a fingering that includes the ring finger of the left hand and the pinky of the right hand (unless they're doing some sort of weird extended technique). So we can get rid of the majority of the entries in our table because they'll never be used. So, really, we only need as many entries in the table as there are notes that our instrument can produce, plus any alternate fingerings (two ways of playing the same note). Since Johan's instrument produces all 12 semitones of the chromatic scale across two octaves, if we conservatively allow for 3 alternate fingerings for each of those 24 notes, we only need 72 table entries for a total size of 216 bytes. That's more like it!<br />
<h4>
Let's Race! </h4>
Now that we have a compact way to represent all the fingering-to-MIDI note mappings, let's think for a bit about efficiency. In a drag race to convert a fingering to a MIDI note, will Johan's code or my code be faster?<br />
<br />
(Caveat: it's been a long time since I took my computer architecture class, so I may bork some of this!)<br />
<br />
The Atmel AVR chip in the Arduino Uno has the following timing characteristics, according to https://en.wikipedia.org/wiki/Atmel_AVR_instruction_set:<br />
<br />
<ul>
<li>Arithmetic operations take one clock cycle, except for multiplication, which takes two cycles</li>
<li>Reading data from memory takes two clock cycles</li>
</ul>
Armed with this knowledge we can get a rough idea of how many clock cycles each method takes:<br />
<br />
Johan's statement:<br />
<br />
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
</div>
<span style="font-family: "courier new" , "courier" , monospace;">fingeredNote=startNote-2*LH1-(LHb && !(LH1 && LH2))-LH2-(LH2
&& LH1)-2*LH3+LHp1-LHp2+(RHs && !LHp1)-RH1-(RH1
&& LH3)-RH2-2*RH3+RHp1-RHp2-2*RHp3+12*OCTup </span><br />
<br />
I count:<br />
<ul>
<li>22 memory accesses (44 clock cycles)</li>
<li>5 multiplications (10 clock cycles)</li>
<li>22 arithmetic or logical operations (22 clock cycles)</li>
</ul>
So Johan's code should take about <b>76 clock cycles</b><br />
<br />
My code's performance will depend on which fingering is selected. If we get lucky and the fingering the player is using is the first entry in our lookup table, we'll only need to do one comparison. If we're unlucky, we'll need to look through all of the table. Let's consider the worst case, because no musician wants their instrument to slow down when she plays certain notes.<br />
<br />
So let's assume we have to look through all 72 entries. Each table lookup involves:<br />
<ul>
<li>2 memory accesses, to bring the two bytes of the mask into registers (4 clock cycles total)</li>
<li>2 clock cycles to compare those byes</li>
</ul>
And finally, when we have a hit, there's a memory access to retrieve the MIDI note (2 clock cycles) and one to store it (2 cycles).<br />
<br />
So, worst case, the table lookup is 72 * (2 + 2) + (2 + 2) = <b>292 clock cycles</b><br />
<h4>
Checkered flag to Johan!</h4>
So, clearly, Johan's code is more efficient. But how much does it really matter? Let's look at the clock frequency of the ATMega328 chip found in the Arduino Uno - 16 Mhz.<br />
<br />
That means that each clock cycle takes 1 / (16 * 10^6) seconds, or about .1 microseconds. Both of our algorithms will execute in less than 3 microseconds (0.000003 seconds), which is really really fast, compared to <a href="http://cogsci.stackexchange.com/questions/1664/what-is-the-threshold-where-actions-are-perceived-as-instant" target="_blank">the 0.1 second delay that a human can perceive</a>. <br />
<h4>
Understandability Wins</h4>
The take-away here is to realize that, in many or most cases where you're reading a sensor in your electronic musical instrument project, and then doing some computation, <i><b>you will almost never need to worry about the efficiency of your algorithm*. Use the algorithm that is the simplest to implement, and that makes sense to you. </b></i><br />
<i><b><br /></b></i>
Hope this was helpful! In my next post I'll show how to use a <a href="https://www.adafruit.com/products/1982" target="_blank">cool capacitive touch sensor you can buy for $8</a> to make an instrument like the Akai EWI.<br />
<br />
- Gordon<i><b><br /></b></i><br />
<br />
<br />
*Computer science nerds: Yes, I'm intentionally omitting algorithms that have quadratic behavior here. On microcontrollers, even if the algorithm is quadratic, it's hard to make <i>n</i> very big, given typical microcontroller memory sizes.<br />
Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com2tag:blogger.com,1999:blog-2671439418188048550.post-70334664524674086522016-04-15T23:26:00.001-07:002016-04-25T11:26:22.709-07:00Guest Post: Alternative way of note selection (Johan Berglund)<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<span style="-webkit-padding-start: 0px;">One of the best things about the internet, is the way it brings all of us around the world together. Today, I'd like to bring your a guest post from Johan, with some insights on mapping key fingerings (via switches) to MIDI notes. </span></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<span style="-webkit-padding-start: 0px;">The interesting thing to think about is - how efficient is the code that maps the fingered notes to a MIDI note value. Is it more efficient to take a value and do a bunch of additions/subtractions (Johan's code), or to do a linear search on an array (my code)? Is there a better way? Share your ideas!</span></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<span style="-webkit-padding-start: 0px;">Thank you, Johan, for sharing your work!</span></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<span style="-webkit-padding-start: 0px;">-Gordon</span></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<span style="-webkit-padding-start: 0px;">=============</span></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<span style="-webkit-padding-start: 0px;"> </span><b id="yui_3_16_0_ym19_1_1460786835581_3031" style="-webkit-padding-start: 0px;"> </b></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3032" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<b id="yui_3_16_0_ym19_1_1460786835581_3031" style="-webkit-padding-start: 0px;">Alternative way of note selection</b></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3045" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
guest post by Johan Berglund</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3044" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3066" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
My idea for a DIY wind controller was to build it small and light with cheap components, an Arduino Pro Mini, a DIN 5 MIDI output and the keys and fingering based on the Akai EWI. Going through the fingering chart in the EWI manual, I discovered that some of the fingerings that I use weren't even listed. How many unlisted fingerings could there be? When playing the EWI it seemed there was more of a logical pattern to the workings of each key than what could be expected if it was looking up combinations in a list. Looking for answers I found the blog of Bret Pimentel, and his post on flexible EWI fingerings.</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3371" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3067" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<a href="http://bretpimentel.com/flexible-ewi-fingerings/" id="yui_3_16_0_ym19_1_1460786835581_3373" rel="nofollow" shape="rect" style="-webkit-padding-start: 0px; background: transparent; color: #196ad4; margin: 0px; outline: none; padding: 0px; text-decoration: underline;" target="_blank">http://bretpimentel.com/flexible-ewi-fingerings/</a></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3374" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3068" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
He had it all figured out. Each key changes the note value a certain number of semitones up or down, some of them with conditions. Let's list them here as variable declarations for our Arduino sketch:</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3069" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3070" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Key variables, TRUE (1) for pressed, FALSE (0) for not pressed</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3071" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LH1; // Left Hand key 1 (pitch change -2)</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3072" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LHb; // Left Hand bis key (pitch change -1 unless both LH1 and LH2 are pressed)</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3073" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LH2; // Left Hand key 2 (with LH1 also pressed pitch change is -2, otherwise -1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LH3; // Left Hand key 3 (pitch change -2)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LHp1; // Left Hand pinky key 1 (pitch change +1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LHp2; // Left Hand pinky key 2 (pitch change -1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RHs; // Right Hand side key (pitch change -2 unless LHp1 is pressed)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RH1; // Right Hand key 1 (with LH3 also pressed pitch change is -2, otherwise -1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RH2; // Right Hand key 2 (pitch change -1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RH3; // Right Hand key 3 (pitch change -2)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RHp1; // Right Hand pinky key 1 (pitch change +1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RHp2; // Right Hand pinky key 2 (pitch change -1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RHp3; // Right Hand pinky key 3 (pitch change -2)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte OCTup; // Octave switch key (pitch change +12)<span style="-webkit-padding-start: 0px; font-family: "helvetica";"> </span></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Ok, so we have straightforward rules for how the note number should change when the keys are pressed. With no keys pressed, it should send a C#, so lets put that in there.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte startNote=61; // set startNote to C# (change this value in steps of 12 to start in other octaves)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
And also a variable for the calculated result.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
int fingeredNote; // note calculated from fingering (switches)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
To get the keys pressed into their dedicated variables we need to read them from the Arduino pins. In the setup part of our sketch, we set their input pins as digital inputs with pullups. That makes them active low. (To use this with other Arduinos or a Teensy, just change the input pins accordingly. Just make sure you have enough digital pins for the project.)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(2, INPUT_PULLUP); // Set inputs with pull-up</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(3, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(4, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(5, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(6, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(7, INPUT_PULLUP); </div>
<div id="yui_3_16_0_ym19_1_1460786835581_3043" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(8, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(9, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(10, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(11, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(12, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(14, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(15, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(16, INPUT_PULLUP);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Reading them will give us a HIGH (1) for the keys that are not pressed and a LOW (0) for the keys that are pressed. To get the value TRUE (1) into our variables for the LOW (0) inputs, and FALSE (0) for the HIGH (1) inputs, we just invert the value with the logical operator NOT. A logical NOT in C is simply a '!' in front of the value that is inverted, like this.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
void readSwitches(){ </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Read switches and put inverted value in variables</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
LH1=!digitalRead(2);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
LHb=!digitalRead(3);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
LH2=!digitalRead(4);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
LH3=!digitalRead(5);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
LHp1=!digitalRead(6);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
LHp2=!digitalRead(7);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RHs=!digitalRead(8);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RH1=!digitalRead(9);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RH2=!digitalRead(10);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RH3=!digitalRead(11);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RHp1=!digitalRead(12);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RHp2=!digitalRead(14);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RHp3=!digitalRead(15);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
OCTup=!digitalRead(16);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3042" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Now we will have every variable for a pressed key set to a numerical '1' and the variables for keys not pressed to a numerical '0'. Here comes the tricky bit. We want to combine math and logic to get our fingeredNote right. We begin with our startNote.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
fingeredNote=startNote;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Then we take the keys from the top down. First we have LH1. It changes the pitch with -2 semitones, so let's subtract two times the value of LH1 from the startNote.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
fingeredNote=startNote-2*LH1;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Next up is the bis key, LHb, and already it gets more tricky. In our notes we stated it should do "<span style="-webkit-padding-start: 0px; font-family: "courier";">pitch change -1 unless both LH1 and LH2 are pressed".</span><span class="Apple-converted-space"> </span>How do we do that in C? Another logical operator, AND (&&), will help us do this. AND will make the condition true only if both operands are true, otherwise it's false. So, we subtract 1 (TRUE) only if LHb is pressed AND NOT (LH1 AND LH2). Let's add it to our calculation.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
fingeredNote=startNote-2*LH1-(LHb && !(LH1 && LH2));</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Ok, now we know how to do this, so the next one will be easy. If LH2 is pressed, subtract 1, and if both LH2 AND LH1 are pressed, subtract another 1.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
fingeredNote=startNote-2*LH1-(LHb && !(LH1 && LH2))-LH2-(LH2 && LH1);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
The following three keys are simple, just add or subtract each key multiplied with the number of semitones.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
fingeredNote=startNote-2*LH1-(LHb && !(LH1 && LH2))-LH2-(LH2 && LH1)-2*LH3+LHp1-LHp2;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Next is the right hand side key, RHs. It should subtract two semitones unless LHp1 is pressed. Not too hard now that we know how to use ! and &&.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
fingeredNote=startNote-2*LH1-(LHb && !(LH1 && LH2))-LH2-(LH2 && LH1)-2*LH3+LHp1-LHp2+(RHs && !LHp1);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Not many special cases left now. Just this last one. RH1 should subtract one semitone, but if LH3 is also pressed it should subtract two semitones.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
fingeredNote=startNote-2*LH1-(LHb && !(LH1 && LH2))-LH2-(LH2 && LH1)-2*LH3+LHp1-LHp2+(RHs && !LHp1)-RH1-(RH1 && LH3);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
After that it's easy as pie. Again just add or subtract each key multiplied with the number of semitones.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
fingeredNote=startNote-2*LH1-(LHb && !(LH1 && LH2))-LH2-(LH2 && LH1)-2*LH3+LHp1-LHp2+(RHs && !LHp1)-RH1-(RH1 && LH3)-RH2-2*RH3+RHp1-RHp2-2*RHp3+12*OCTup;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Done! We now have one single line of code that deals with all possible fingerings, just like that.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
In the context of my MiniWI Arduino sketch it looks like this (I'm removing the fancy stuff like the joysticks for octaves, modulation and pitch bend for now):</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
/*</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
NAME: MiniWI Lite Ver.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
WRITTEN BY: JOHAN BERGLUND</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
CREDITS: State machine from the Gordophone blog by GORDON GOOD</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
DATE: 2016-04-13</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
FILE SAVED AS: MiniWI.ino</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
FOR: Arduino Pro Mini, ATmega328</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
CLOCK: 16.00 MHz CRYSTAL </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
PROGRAMME FUNCTION: Wind Controller with EWI style key setup, Freescale MPX5010GP breath sensor </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
and output to 5-pin DIN MIDI </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
HARDWARE NOTES:</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* For the MIDI connection, attach a MIDI out Female 180 Degree 5-Pin DIN socket to Arduino.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* Socket is seen from solder tags at rear.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* DIN-5 pinout is: _______ </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* pin 2 - GND / \</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* pin 4 - 220 ohm resistor to +5V | 1 3 | MIDI jack</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* pin 5 - Arduino Pin 1 (TX) via a 220 ohm resistor | 4 5 |</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* all other pins - unconnected \___2___/</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
*</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* The Freescale MPX5010GP pressure sensor output (V OUT) is connected to Arduino pin A3.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* Sensor pinout</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* 1: V OUT (pin with indent)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* 2: GND</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* 3: VCC (to 5V) </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* 4: n/c</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* 5: n/c</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* 6: n/c</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* All key switches connect Ardino digital inputs (with internal pullups) to GND</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
* </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
*/</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
//_______________________________________________________________________________________________ DECLARATIONS</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
#define ON_Thr 40 // Set threshold level before switching ON</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
#define ON_Delay 20 // Set Delay after ON threshold before velocity is checked (wait for tounging peak)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
#define breath_max 300 // Blowing as hard as you can</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
#define modsLo_Thr 411 // Low threshold for mod stick center</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
#define modsHi_Thr 611 // High threshold for mod stick center</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
#define octsLo_Thr 311 // Low threshold for octave stick center</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
#define octsHi_Thr 711 // High threshold for octave stick center</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// The three states of our state machine</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3034" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// No note is sounding</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
#define NOTE_OFF 1</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// We've observed a transition from below to above the</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// threshold value. We wait a while to see how fast the</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// breath velocity is increasing</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
#define RISE_WAIT 2</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// A note is sounding</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
#define NOTE_ON 3</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Send CC data no more than every CC_INTERVAL</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// milliseconds</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
#define CC_INTERVAL 40 </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
//variables setup</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
int state; // The state of the state machine</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
unsigned long ccSendTime = 0L; // The last time we sent CC values</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
unsigned long breath_on_time = 0L; // Time when breath sensor value went over the ON threshold</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
int initial_breath_value; // The breath value at the time we observed the transition</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3041" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
long lastDebounceTime = 0; // The last time the fingering was changed</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
long debounceDelay = 30; // The debounce time; increase if the output flickers</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
int lastFingering = 0; // Keep the last fingering value for debouncing</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte MIDIchannel=0; // MIDI channel 1</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
int breathLevel;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
int pressureSensor; // pressure data from breath sensor, for midi breath cc and breath threshold checks</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte velocity; // remapped midi velocity from breath sensor</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
int fingeredNote; // note calculated from fingering (switches) and octave joystick position</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte activeNote; // note playing</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte startNote=61; // set startNote to C# (change this value in steps of 12 to start in other octaves)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte midistatus=0;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte x;</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3035" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LedPin = 13; // select the pin for the LED</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Key variables, TRUE (1) for pressed, FALSE (0) for not pressed</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LH1; // Left Hand key 1 (pitch change -2)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LHb; // Left Hand bis key (pitch change -1 unless both LH1 and LH2 are pressed)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LH2; // Left Hand key 2 (with LH1 also pressed pitch change is -2, otherwise -1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LH3; // Left Hand key 3 (pitch change -2)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LHp1; // Left Hand pinky key 1 (pitch change +1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte LHp2; // Left Hand pinky key 2 (pitch change -1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RHs; // Right Hand side key (pitch change -2 unless LHp1 is pressed)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RH1; // Right Hand key 1 (with LH3 also pressed pitch change is -2, otherwise -1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RH2; // Right Hand key 2 (pitch change -1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RH3; // Right Hand key 3 (pitch change -2)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RHp1; // Right Hand pinky key 1 (pitch change +1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RHp2; // Right Hand pinky key 2 (pitch change -1)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte RHp3; // Right Hand pinky key 3 (pitch change -2)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
byte OCTup; // Octave switch key (pitch change +12)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
//_______________________________________________________________________________________________ SETUP</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
void setup() {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(2, INPUT_PULLUP); // Set inputs with pull-up</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(3, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(4, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(5, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(6, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(7, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(8, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(9, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(10, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(11, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(12, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(14, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(15, INPUT_PULLUP); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(16, INPUT_PULLUP);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; display: block; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; padding: 0px; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
state = NOTE_OFF; // initialize state machine</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; display: block; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; padding: 0px; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pinMode(LedPin,OUTPUT); // declare the LED's pin as output</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
for (x=1; x<=4; x++){ // Do the flashy-flashy to say we are up and running</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
digitalWrite( LedPin, HIGH );</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
delay(300);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
digitalWrite( LedPin, LOW );</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
delay(300);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Serial.begin(31250); // start serial with midi baudrate 31250</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Serial.flush();</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
//_______________________________________________________________________________________________ MAIN LOOP</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
void loop() {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; display: block; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; padding: 0px; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
pressureSensor = analogRead(A3); // Get the pressure sensor reading from analog pin A3</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
if (state == NOTE_OFF) {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
if (pressureSensor > ON_Thr) {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Value has risen above threshold. Move to the ON_Delay</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// state. Record time and initial breath value.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
breath_on_time = millis();</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
initial_breath_value = pressureSensor;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
state = RISE_WAIT; // Go to next state</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
} else if (state == RISE_WAIT) {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
if (pressureSensor > ON_Thr) {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Has enough time passed for us to collect our second</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// sample?</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
if (millis() - breath_on_time > ON_Delay) {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Yes, so calculate MIDI note and velocity, then send a note on event</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
readSwitches();</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; display: block; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; padding: 0px; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
//calculate midi note number from pressed keys and octave shifts</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
fingeredNote=startNote-2*LH1-(LHb && !(LH1 && LH2))-LH2-(LH2 && LH1)-2*LH3+LHp1-LHp2+(RHs && !LHp1)-RH1-(RH1 && LH3)-RH2-2*RH3+RHp1-RHp2-2*RHp3+12*OCTup;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// We should be at tonguing peak, so set velocity based on current pressureSensor value </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// If initial value is greater than value after delay, go with initial value, constrain input to keep mapped output within 7 to 127</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3036" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
velocity = map(constrain(max(pressureSensor,initial_breath_value),ON_Thr,breath_max),ON_Thr,breath_max,7,127);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
midiSend((0x90 | MIDIchannel), fingeredNote, velocity); // send Note On message for new note</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
activeNote=fingeredNote;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
state = NOTE_ON;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
} else {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Value fell below threshold before ON_Delay passed. Return to</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// NOTE_OFF state (e.g. we're ignoring a short blip of breath)</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
state = NOTE_OFF;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
} else if (state == NOTE_ON) {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
if (pressureSensor < ON_Thr) {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Value has fallen below threshold - turn the note off</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
midiSend((0x80 | MIDIchannel), activeNote, velocity); // send Note Off message </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
state = NOTE_OFF;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
} else {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Is it time to send more CC data?</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
if (millis() - ccSendTime > CC_INTERVAL) {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// deal with Breath</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
breath();</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
ccSendTime = millis();</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
readSwitches(); </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
//calculate midi note number from pressed keys</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
fingeredNote=startNote-2*LH1-(LHb && !(LH1 && LH2))-LH2-(LH2 && LH1)-2*LH3+LHp1-LHp2+(RHs && !LHp1)-RH1-(RH1 && LH3)-RH2-2*RH3+RHp1-RHp2-2*RHp3+12*OCTup;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
if (fingeredNote != lastFingering){ //</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// reset the debouncing timer</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
lastDebounceTime = millis();</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
if ((millis() - lastDebounceTime) > debounceDelay) {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// whatever the reading is at, it's been there for longer</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// than the debounce delay, so take it as the actual current state</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
if (fingeredNote != activeNote) {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Player has moved to a new fingering while still blowing.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Send a note off for the current note and a note on for</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// the new note.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
midiSend((0x80 | MIDIchannel), activeNote, velocity); // send Note Off message</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
activeNote=fingeredNote;</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
midiSend((0x90 | MIDIchannel), activeNote, velocity); // send Note On message</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
lastFingering=fingeredNote; </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
//_______________________________________________________________________________________________ FUNCTIONS</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Send a three byte midi message </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
void midiSend(byte midistatus, byte data1, byte data2) {</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
digitalWrite(LedPin,HIGH); // indicate we're sending MIDI data</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Serial.write(midistatus);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Serial.write(data1);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
Serial.write(data2);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
digitalWrite(LedPin,LOW); // indicate we're sending MIDI data</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
//***********************************************************</div>
<div id="yui_3_16_0_ym19_1_1460786835581_3037" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
void breath(){</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
breathLevel = analogRead(A3); // read voltage on analog pin A3</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
breathLevel = map(constrain(breathLevel,ON_Thr,breath_max),ON_Thr,breath_max,0,127);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
midiSend((0xB0 | MIDIchannel), 2, breathLevel);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
//***********************************************************</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
void readSwitches(){ </div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
// Read switches and put inverted value in variables</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
LH1=!digitalRead(2);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
LHb=!digitalRead(3);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
LH2=!digitalRead(4);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
LH3=!digitalRead(5);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
LHp1=!digitalRead(6);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
LHp2=!digitalRead(7);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RHs=!digitalRead(8);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RH1=!digitalRead(9);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RH2=!digitalRead(10);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RH3=!digitalRead(11);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RHp1=!digitalRead(12);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RHp2=!digitalRead(14);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
RHp3=!digitalRead(15);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
OCTup=!digitalRead(16);</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
}</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: Courier; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<b style="-webkit-padding-start: 0px;">Supplementary studies</b></div>
<div class="yiv4447599323yqt9153602403" id="yiv4447599323yqtfd89687" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<div style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px; min-height: 14px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px;">
If you prefer brass valve instruments over woodwind, you can do the exact same thing but with the AKAI/Steiner EVI fingerings, only it's easier because there are no conditional value changes for any keys. Resources needed to do that are found here:</div>
<div style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px; min-height: 14px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px;">
<a href="http://www.patchmanmusic.com/NyleMIDIEVI.html" rel="nofollow" shape="rect" style="-webkit-padding-start: 0px; background: transparent; color: #196ad4; margin: 0px; outline: none; padding: 0px; text-decoration: underline;" target="_blank">http://www.patchmanmusic.com/NyleMIDIEVI.html</a></div>
<div style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px; min-height: 14px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px;">
Direct links to the EVI 1000 fingering charts including the value changes for each key are here:</div>
<div style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px; min-height: 14px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px;">
<a href="http://www.patchmanmusic.com/Steiner_Photos/EVI1000FingeringChartA.jpg" rel="nofollow" shape="rect" style="-webkit-padding-start: 0px; background: transparent; color: #196ad4; margin: 0px; outline: none; padding: 0px; text-decoration: underline;" target="_blank">http://www.patchmanmusic.com/Steiner_Photos/EVI1000FingeringChartA.jpg</a></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3039" style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px;">
<a href="http://www.patchmanmusic.com/Steiner_Photos/EVI1000FingeringChartB.jpg" id="yui_3_16_0_ym19_1_1460786835581_3038" rel="nofollow" shape="rect" style="-webkit-padding-start: 0px; background: transparent; color: #196ad4; margin: 0px; outline: none; padding: 0px; text-decoration: underline;" target="_blank">http://www.patchmanmusic.com/Steiner_Photos/EVI1000FingeringChartB.jpg</a></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3040" style="-webkit-padding-start: 0px; display: block; font-size: 12px; margin: 0px; min-height: 14px; padding: 0px;">
</div>
<div style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px;">
There's also info on the EVI fingering mode in the reference manual for the EWI4000s:</div>
<div style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px; min-height: 14px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px;">
<a href="http://www.akaipro.com/product/ewi4000s#downloads" rel="nofollow" shape="rect" style="-webkit-padding-start: 0px; background: transparent; color: #196ad4; margin: 0px; outline: none; padding: 0px; text-decoration: underline;" target="_blank">http://www.akaipro.com/product/ewi4000s#downloads</a></div>
<div style="-webkit-padding-start: 0px; font-size: 12px; margin: 0px;">
<a href="http://www.patchmanmusic.com/manuals/EWI4000s_v24_Manual.pdf" rel="nofollow" shape="rect" style="-webkit-padding-start: 0px; background: transparent; color: #196ad4; margin: 0px; outline: none; padding: 0px; text-decoration: underline;" target="_blank">http://www.patchmanmusic.com/manuals/EWI4000s_v24_Manual.pdf</a></div>
</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
The code for my MiniWI project in its complete (and now and then updated) form is available at Github.</div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; min-height: 14px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br clear="none" style="-webkit-padding-start: 0px;" /></div>
<div style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<a href="https://github.com/Trasselfrisyr" rel="nofollow" shape="rect" style="-webkit-padding-start: 0px; background: transparent; color: #196ad4; margin: 0px; outline: none; padding: 0px; text-decoration: underline;" target="_blank">https://github.com/Trasselfrisyr</a></div>
<div id="yui_3_16_0_ym19_1_1460786835581_3378" style="-webkit-padding-start: 0px; -webkit-text-stroke-width: 0px; background-color: white; color: black; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<a href="https://github.com/Trasselfrisyr/MiniWI/blob/master/MiniWI.ino" id="yui_3_16_0_ym19_1_1460786835581_3377" rel="nofollow" shape="rect" style="-webkit-padding-start: 0px; background: transparent; color: #196ad4; margin: 0px; outline: none; padding: 0px; text-decoration: underline;" target="_blank">https://github.com/Trasselfrisyr/MiniWI/blob/master/MiniWI.ino</a></div>
Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com5tag:blogger.com,1999:blog-2671439418188048550.post-31184582464330822112016-02-25T22:38:00.000-08:002016-02-25T22:46:41.388-08:00<h2>
Shout-Outs</h2>
Here are some links to some great wind controller projects, found by<a href="https://www.youtube.com/watch?v=JataQs4R5Bc" target="_blank"> Onyx Ashanti</a>:<br />
<br />
<a href="https://youtu.be/2iWSM3rVC2w" target="_blank">Open Horn MIDI System (OHMS)</a><br />
<br />
<a href="https://youtu.be/-A0cIdHsIeo" target="_blank">Gwen's MIDI Controller</a><br />
<br />
<br />Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com2tag:blogger.com,1999:blog-2671439418188048550.post-26161722047118938162016-02-25T20:27:00.003-08:002016-02-25T22:27:43.619-08:00Note Selection Basics<div>
<br />
In my previous posts, I've focused on detecting note-on and note-off transitions from the breath controller, and on mapping the breath intensity to a MIDI continuous controller to control expressive parameters. But the circuits and code have never been able to play more than one note. In this post, I'll discuss how to read a set of finger inputs, like the keys on a woodwind instrument, or the valves of a trumpet.</div>
<div>
<br /></div>
<div>
To keep things simple, I'll start with 3 finger inputs, like found on a trumpet. For a B-flat trumpet, the 3 fingers can be used to play 7 different notes:<br />
<div>
<br /></div>
<div>
<br /></div>
<table style="-evernote-table: true; border-collapse: collapse; margin-left: 0px; table-layout: fixed; width: 100%;"><tbody>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
<b>Index</b></div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
<b>Middle</b></div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
<b>Ring</b></div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
<b>Note Produced</b></div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
B-flat</div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
A</div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
A-flat</div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
G</div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
G-flat</div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
F</div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
E</div>
</td></tr>
</tbody></table>
<div>
<br /></div>
</div>
<table style="-evernote-table: true; border-collapse: collapse; margin-left: 0px; table-layout: fixed; width: 100%;"><tbody>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"></td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><br /></td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><br /></td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><br /></td></tr>
</tbody></table>
<div>
Readers familiar with binary numbers may be saying, "wait, with 3 binary digits, you should be able to produce 2^3, or 8 distinct finger combinations." And you would be right, except that the fingering combination [Index=up, Middle=Up, Ring=Down] produces an "in-between-pitch" note in the lower registers of the trumpet, and is not used.<br />
<br />
<h2>
A Real Instrument </h2>
</div>
<div>
<br /></div>
<div>
For those of you unfamiliar with how a trumpet works, most have 3 piston valves which re-route the flow of air through the instrument to change the effective length, and therefore the resonant frequency, of the instrument.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://upload.wikimedia.org/wikipedia/commons/9/9d/Trumpet_1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="106" src="https://upload.wikimedia.org/wikipedia/commons/9/9d/Trumpet_1.jpg" width="320" /></a></div>
(Photo: Wikimedia Commons: https://upload.wikimedia.org/wikipedia/commons/9/9d/Trumpet_1.jpg)<br />
<br />
A natural way to simulate the operation of a piston valve like this is to use a momentary switch, so let's wire something up. I've used <a href="https://www.sparkfun.com/products/9190" target="_blank">a small tactile switch like the following</a>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://upload.wikimedia.org/wikipedia/commons/3/35/BUTA-06-X-STAN-01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="https://upload.wikimedia.org/wikipedia/commons/3/35/BUTA-06-X-STAN-01.jpg" width="320" /></a></div>
(Photo: Wikimedia Commons: https://upload.wikimedia.org/wikipedia/commons/3/35/BUTA-06-X-STAN-01.jpg)<br />
<br />
These tactile switches are widely used in consumer electronics, and are very inexpensive.e.g. $0.20 each. They are available from all the major parts suppliers. <br />
<br />
I've wired up three of these on a breadboard, spaced approximately finger-width apart:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-1m6vv0WK6mw/VZYaJ3xJvDI/AAAAAAAABno/zkqQsV_XCv8/s1600/FullSizeRender.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="https://4.bp.blogspot.com/-1m6vv0WK6mw/VZYaJ3xJvDI/AAAAAAAABno/zkqQsV_XCv8/s640/FullSizeRender.jpg" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<span id="goog_784088183"></span><span id="goog_784088184"></span></div>
<br />
Now, to be clear, no actual trumpet player would find this thing pleasant to play, as the "feel" of the tactile switches is very different from the feel of an actual piston valve. But it will let us start to experiment with how we can simulate real-world musical instrument properties like trumpet valves and woodwind keys.<br />
<br />
To connect these switches to your microcontroller, first figure out which pins are connected when the switch is pressed. If you are using the tactile switches like I am, there are 4 pins on each one, arranged in two pairs. If you find that the switch appears to be always pressed, you may need pull the switch out of the breadboard, rotate it 90 degrees, and re-insert it.<br />
<br />
Once the switches are attached to the breadboard, connect one side of each switch to a common wire (this will attach to the ground on your microcontroller). The other side of each switch should be brought out on a separate wire. In total, there will be 4 connections to the microcontroller, like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-amuDi_PK_aQ/VZYd0t_ZrmI/AAAAAAAABn4/Rc3k_gXhzso/s1600/FullSizeRender%25281%2529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="https://3.bp.blogspot.com/-amuDi_PK_aQ/VZYd0t_ZrmI/AAAAAAAABn4/Rc3k_gXhzso/s640/FullSizeRender%25281%2529.jpg" width="640" /></a></div>
<br />
Once you have these wired up, attach Common to the Ground (GND) pin on your microcontroller, and the Index, Middle, and Ring (finger) switch wires to three digital input pins. I've attached mine to digital inputs 2, 3, and 4 on my Teensy microcontroller. If you have yours attached to different input pins, you'll need to modify the code examples below accordingly.<br />
<br />
One thing to be aware of is that we're pulling the digital inputs low when the buttons are pressed. So the "valve" will read HIGH when the button is not pressed and LOW when pressed.<br />
<h2>
Mapping Inputs to MIDI Notes</h2>
Now that we have our "trumpet valves" plugged into our microcontroller, how do we get it to send different MIDI notes to our synthesizers according to which switches are pressed?<br />
<br />
One approach might be to use a bunch of if/then statements to decide which note to select. It might look like:<br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">if (switch one pressed) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> if (switch two pressed) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> if (switch three pressed) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> send E</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> } else {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> send G</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> } else {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> // switch two is NOT pressed </span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> if (switch three pressed) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> send F</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> } else {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> send A-flat</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">etc etc</span><br />
<br />
As you can see, this is pretty hard to read, and it's pretty easy to make a mistake. Plus, imagine how horrifying this code would be if you were trying to build a woodwind controller, which could have as many as 14 or 15 switches.<br />
<br />
A better approach is to use binary numbers to map any combination of the switch on/off states to a number. For our trumpet, we only need 3 bits, so all the possible key combinations, and the corresponding MIDI note, can be represented in a new column in our fingering table<br />
<br />
<table style="-evernote-table: true; border-collapse: collapse; margin-left: 0px; table-layout: fixed; width: 100%;"><tbody>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
<b>Index</b></div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
<b>Middle</b></div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
<b>Ring</b></div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
<b>Note Produced</b></div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
<b>Binary (Decimal) Value</b></div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
B-flat</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
000 (0)</div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
A</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
010 (2)</div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
A-flat</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
011 (3)</div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
G</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
001 (1)</div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
G-flat</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
100 (4)</div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Up</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
F</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
101 (5)</div>
</td></tr>
<tr><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 25%;"><div>
Down</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
E</div>
</td><td style="border-color: rgb(219,219,219); border-style: solid; border-width: 1px; margin: 0px; padding: 10px; width: 12.5%;"><div>
111 (7)</div>
</td></tr>
</tbody></table>
<div>
<div>
<br /></div>
<div>
Now that ugly code for deciding which note to play can be replaced with:</div>
<div>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">if (value = 0) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> send B-flat</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">} else if (value == 2) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> send A</span><br />
<div>
<span style="font-family: "courier new" , "courier" , monospace;">} else if (value == 3) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> send A-flat</span></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">} else if (value == 1) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> send G</span></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">} else if (value == 4) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> send G-flat</span></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">} else if (value == 5) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> send F</span></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">} else if (alue == 7) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> send E</span></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">} </span></div>
</div>
</div>
<div>
We'll actually use a C-language case statement in the sample code, and we'll express the numbers in binary instead of decimal, like this:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">switch (value) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> case 0:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> send B-flat;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> break;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> case 2:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> send A;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> break</span><br />
<br />
and so on.<br />
<br />
So let's go ahead and write the sketch for our trumpet. To do that, we'll replace the get_note() function with a new one:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>int get_note() {</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // This routine reads the three buttons that are our "trumpet</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // valves", and returns a MIDI note.</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> int value = (digitalRead(2) << 2) +</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> (digitalRead(3) << 1) +</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> digitalRead(4);</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // Since the digital input pins are pulled low when the</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // button is pressed, the "all valves open" value will</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // be 111 (binary) or 7 (decimal). Full table:</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // v1 v2 v3 note value (decimal)</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // open open open C 7</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // open closed open B 5</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // closed open open B-flat/A-sharp 3</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // closed closed open A 1</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // open closed closed A-flat/G-sharp 4</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // closed open closed G 2</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // closed closed closed G-flat/F-sharp 0</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // open open close not used 6</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // </b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b>#define BASE 60 // The base MIDI note value</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> switch (value) {</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> case 7:</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> return BASE;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> break;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> case 5:</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> return BASE - 1;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> break;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> case 3:</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> return BASE - 2;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> break;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> case 1:</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> return BASE - 3;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> break;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> case 4:</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> return BASE - 4;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> break;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> case 2:</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> return BASE - 5;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> break;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> case 0:</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> return BASE - 6;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> break;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> default:</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // If invalid fingering, ignore and return the</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // currently sounding note. </b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> return noteSounding;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> }</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>}</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b><br /></b></span><span style="font-family: inherit;">What's going on here?</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b>int value = (digitalRead(2) << 2) +</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> (digitalRead(3) << 1) +</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> digitalRead(4);</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span>
<span style="font-family: inherit;">Here, we're reading the values of the three buttons into a single integer value, using bit shift operators. Let's break it down:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">First, we declare a variable named "value". For all practical purposes, that starts off as zero, and in binary that is:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">00000000</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">which is 8 bits of binary zeros. </span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">(Yes, nerds, it's actually a 32-bit signed integer, but that's not important to this discussion)</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">When we do digitalRead(2) << 2</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">we're saying "read digital input two and shift the whole value to the left two bits. So if we read 00000001, we'd shift that two bits to the left, so we end up with:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">00000100</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Then we read digital input three. Suppose we also read a HIGH, and shift left one bit, that ends up being:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">00000010</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Finally we read input 4, but don't shift it at all. So if we get a HIGH on pins 4, we have:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">00000001</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Now, we add the following three binary numbers:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">00000100</span><br />
<span style="font-family: inherit;">00000010</span><br />
<span style="font-family: inherit;">00000001</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">and we get:</span><br />
<br />
<span style="font-family: inherit;">00000111</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">So that means the three digital I/O pin we're using are giving the value 1. As I mentioned before, we're taking the digital I/O pins low with button presses, so this binary value 00000111 means no buttons are pressed.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">In order to make pulling I/O pins low to detect button pressed, we also need to add pullups to the digitnal I/O pins. The Teensy has support for that built-in (otherwise we'd need to attach some resistors between the digital pin and the power rail). We'll add the following code (in blue) to the setup() function:</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>void setup() {</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> state = NOTE_OFF; // initialize state machine</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> pinMode(2, INPUT_PULLUP);</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> pinMode(3, INPUT_PULLUP);</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> pinMode(4, INPUT_PULLUP);</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>}</b></span><br />
<br />
We'll also need to change the main loop a little bit to handle the situation where the player chooses a new fingering but keeps blowing. In that case we need to turn off the old note and turn on the new one. So we'll add the following code in the block where we're handing the case where a note is on (new code in blue):<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>void loop() {</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> // read the input on analog pin 0</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> sensorValue = analogRead(A0);</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> if (state == NOTE_OFF) {</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> if (sensorValue > NOTE_ON_THRESHOLD) {</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> // Value has risen above threshold. Move to the RISE_TIME</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> // state. Record time and initial breath value.</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> breath_on_time = millis();</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> initial_breath_value = sensorValue;</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> state = RISE_WAIT; // Go to next state</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> }</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> } else if (state == RISE_WAIT) {</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> if (sensorValue > NOTE_ON_THRESHOLD) {</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> // Has enough time passed for us to collect our second</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> // sample?</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> if (millis() - breath_on_time > RISE_TIME) {</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> // Yes, so calculate MIDI note and velocity, then send a note on event</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> noteSounding = get_note();</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> int velocity = get_velocity(initial_breath_value, sensorValue, RISE_TIME);</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> usbMIDI.sendNoteOn(noteSounding, velocity, MIDI_CHANNEL);</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> state = NOTE_ON;</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> }</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> } else {</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> // Value fell below threshold before RISE_TIME passed. Return to</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> // NOTE_OFF state (e.g. we're ignoring a short blip of breath)</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> state = NOTE_OFF;</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> }</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> } else if (state == NOTE_ON) {</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> if (sensorValue < NOTE_ON_THRESHOLD) {</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> // Value has fallen below threshold - turn the note off</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> usbMIDI.sendNoteOff(noteSounding, 100, MIDI_CHANNEL); </b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> state = NOTE_OFF;</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> } else {</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> // Is it time to send more aftertouch data?</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> if (millis() - atSendTime > AT_INTERVAL) {</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> // Map the sensor value to the aftertouch range 0-127</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> atVal = map(sensorValue, NOTE_ON_THRESHOLD, 1023, 0, 127);</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> usbMIDI.sendAfterTouch(atVal, MIDI_CHANNEL);</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> atSendTime = millis();</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> }</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> }</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> <span style="color: blue;">int newNote = get_note();</span></b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> if (newNote != noteSounding) {</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // Player has moved to a new fingering while still blowing.</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // Send a note off for the current node and a note on for</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> // the new note.</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> usbMIDI.sendNoteOff(noteSounding, 100, MIDI_CHANNEL);</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> noteSounding = newNote;</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> int velocity = get_velocity(initial_breath_value, sensorValue, RISE_TIME);</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> usbMIDI.sendNoteOn(noteSounding, velocity, MIDI_CHANNEL);</b></span><br />
<span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b> }</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> }</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>}</b></span><br />
<br />
<div class="separator" style="clear: both; text-align: left;">
Here's a short video of the sketch in action:</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/GdlDZ4oYR18/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/GdlDZ4oYR18?feature=player_embedded" width="320"></iframe></div>
<br />
<br />
Here's the entire sketch, available at https://github.com/ggood/NoteSelectionTutorial<br />
<br />
<br /></div>
</div>
</div>
</div>
</div>
</div>
<script src="http://gist-it.appspot.com/http://github.com/ggood/NoteSelectionTutorial/blob/master/NoteSelectionTutorial.ino"></script>
Thanks for reading. If there's anything you would like me to address in future posts, leave a comment. Next up: how to play more than the seven notes this instrument is capable of playing.Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com10tag:blogger.com,1999:blog-2671439418188048550.post-38700074363455118802014-11-01T12:19:00.004-07:002014-11-01T12:19:56.268-07:00Ah, memoriesI believe this was the Prism Quartet's first recording.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-JLD2ky0SW-4/VFUyQa1I4YI/AAAAAAAABk8/2gQmRHXLV1w/s1600/photo.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-JLD2ky0SW-4/VFUyQa1I4YI/AAAAAAAABk8/2gQmRHXLV1w/s1600/photo.JPG" height="640" width="478" /></a></div>
<br />Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com0tag:blogger.com,1999:blog-2671439418188048550.post-59232718774438098942014-01-01T17:46:00.001-08:002014-01-01T17:46:43.108-08:00Not music related, but...I know it's been a long while since I posted here. I've been pretty busy with other things, but here's some stuff I did today.<br />
<br />
Back in August, I thought it would be good to introduce my eight-year-old daughter to kit-building and soldering, so I ordered the <a href="https://www.sparkfun.com/products/retired/9565" target="_blank">It's a Through-Hole Christmas, Charlie Brown!</a> christmas ornament kit from <a href="https://www.sparkfun.com/" target="_blank">Sparkfun</a>. It's an easy-to-build kit using LEDs, a resistor, and a pre-programmed ATTiny85 microcontroller (unfortunately, Sparkfun no longer makes it).<br />
<br />
Construction of the kit went well, my daughter got an intro to soldering, and when we powered up the ornament for the first time, it lit up! And different lights faded in and out! My daughter and I exchanged high fives.<br />
<br />
And then I noticed that after the initial light fade in-out sequence, the ornament seemed to freeze up. After a little googling, it looks like there is a bug in the firmware that Sparkfun shipped on the ATTiny85 chip.<br />
<br />
With most vendors, I would be mightily peeved that I was sent something that didn't work as advertised, except:<br />
<ul>
<li>I'd already gotten a great deal of value from building the kit with my daughter,<br /><br />and<br /></li>
<li>Everything about this kit - schematics, PCB layouts, code, is freely available on github<br /><br />oh, and<br /> </li>
<li>I love Sparkfun </li>
</ul>
So, I went digging, and, if you've got an Arduino laying around, it's really easy to use it to reprogram the ATTiny85. First, a little background on the chip.<br />
<h4>
The ATTiny85</h4>
For those so don't know what an ATTiny85 is, <a href="http://www.atmel.com/devices/attiny85.aspx" target="_blank">quoting from the Atmel website</a>:<br />
<br />
<blockquote>
<span style="font-family: inherit;">The high-performance, low-power Atmel 8-bit AVR RISC-based
microcontroller combines 8KB ISP flash memory, 512B EEPROM, 512-Byte
SRAM, 6 general purpose I/O lines, 32 general purpose working registers,
one 8-bit timer/counter with compare modes, one 8-bit high speed
timer/counter, USI, internal and external Interrupts, 4-channel 10-bit
A/D converter, programmable watchdog timer with internal oscillator,
three software selectable power saving modes, and debugWIRE for on-chip
debugging. The device achieves a throughput of 20 MIPS at 20 MHz and
operates between 2.7-5.5 volts. </span></blockquote>
<br />
If you're familiar with Arduinos, this chip uses the same instruction set as the processor in the Arduino family, but has half the EEPROM, a quarter of the RAM, and far fewer I/O lines. The chip costs $1.32 in single quantities (<a href="http://www.digikey.com/product-detail/en/ATTINY85-20PU/ATTINY85-20PU-ND/735469?WT.mc_id=IQ_7595_G_pla735469&wt.srch=1&wt.medium=cpc" target="_blank">Digi-Key price</a>), and is made in through-hole versions like the one shown below, so it's a great thing to use in projects where you want to embed a cheap but capable CPU. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-NQaIsDKm3dc/UsRFgTU7TjI/AAAAAAAABjE/Qlg-Z_ahsaI/s1600/PDIP-8_4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="http://3.bp.blogspot.com/-NQaIsDKm3dc/UsRFgTU7TjI/AAAAAAAABjE/Qlg-Z_ahsaI/s200/PDIP-8_4.jpg" width="200" /></a></div>
<br />
<h4>
Reprogramming the ATTiny85</h4>
With a full-featured Arduino board, you can upload new code to the processor (usually an Atmel 328) via a USB port implemented on the Arduino board. With the bare ATTiny85 chip, there's no USB support, so we need to upload the code using a special protocol that allows you to read and write the flash memory on the chip using one of the 8 pins.<br />
<br />
If you're doing this a lot,<a href="https://www.sparkfun.com/products/11460" target="_blank"> there's a nice kit from Sparkfun </a>that allows you to plug the chip into a socket and use the Arduino IDE to directly upload sketches to the chip. Or, you can use an Arduino and a couple of extra parts to accomplish this.<br />
<br />
There are a lot of good tutorials on the web like <a href="http://www.instructables.com/id/How-to-program-attiny-using-arduino-uno/">http://www.instructables.com/id/How-to-program-attiny-using-arduino-uno/</a> that show you how to wire up an Arduino as an ISP (in-circuit programmer) that can program the ATTiny85. I followed that tutorial, and here's the result:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-WJJfOIZ-uLQ/UsRJPl6kaDI/AAAAAAAABjQ/i59hqx7khVk/s1600/photo(1).JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="478" src="http://4.bp.blogspot.com/-WJJfOIZ-uLQ/UsRJPl6kaDI/AAAAAAAABjQ/i59hqx7khVk/s640/photo(1).JPG" width="640" /></a></div>
<br />
The Arduino Uno I used as a programmer is at the top of the photo. The breadboard to the left is where the ATTiny85 is plugged in to be programmed. <br />
<br />
Being the nerd I am, I wanted to be able to pull the ATTiny85 chip out of its programmer and test it with the least hassle. So the larger breadboard to the right is a copy of the Sparkfun ornament circuit. After uploading new code to the chip, I just unplug it from the programming breadboard on the left and plug it into the test breadboard on the right.<br />
<br />
<h4>
Results</h4>
<br />
Here's the new code (that I wrote) running on the ornament. In the future, I'll sit down with my daughter and let her tweak a couple of the timing parameters, or maybe add back the fade in-out, implemented with PWM, and see what she picks up about coding.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dzITb-4Q7qQMXFCsHmYpSBjkfPE5jRXt_nth3tRjUGsGAf--DpR8J3-Vn1WoM8Fq57ijrT653mXu9hbIHeVJg' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
<br />
<br />
<br />Happy New Year!<br />
<br />
<br />
<br />Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com1tag:blogger.com,1999:blog-2671439418188048550.post-70964994144380284152013-04-25T23:26:00.000-07:002013-04-27T22:21:41.633-07:00<h2>
The BlowChucks Wind Instrument Controller</h2>
<h3>
My latest musical instrument contraption</h3>
<h3>
</h3>
<h2>
<iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/oLzV1U1DPCI" width="560"></iframe>
</h2>
<h2>
Introduction</h2>
<br />
Over the past couple of years I've been experimenting with electronic wind instruments that mimic the way that a trombone player interacts with his/her instrument. The two instruments I made, the <a href="http://gordophone.blogspot.com/2010/06/updated-trombone-controller.html" target="_blank">Gordophone</a> and the <a href="http://gordophone.blogspot.com/2011/02/3-d-trombone-photos-and-ideas.html" target="_blank">3d Trombone</a>, were interesting and fun to build, but there are a couple of problems I haven't been able to solve, and until I solve those problems, the instruments aren't as playable as I want them to be. Because of that, I've gotten kind of stuck and didn't do much music hacking for a while.<br />
<br />
To get unstuck, I decided to write<a href="http://gordophone.blogspot.com/2013/01/a-series-basics-of-diy-wind-controllers.html" target="_blank"> a series of posts describing things I've learned while I was building those controllers</a>, which I am still working on. In that series, I've tried to be as hands-on as possible, publishing diagrams that describe the physical construction, wiring, and source code.<br />
<br />
Along the way, I wondered if there was a way to make a wind controller that was more accessible and easier to play than the instruments I'd been designing.<br />
<br />
<h2>
Aha! </h2>
<h2>
</h2>
Coincidentally, my wife and I finally broke down and bought a Wii system for our kids, which came with the standard <a href="http://en.wikipedia.org/wiki/Wii_Remote" target="_blank">WiiMote</a> and <a href="http://en.wikipedia.org/wiki/Wii_Remote#Nunchuk" target="_blank">Nunchuck</a> accessory. The first time I used the Nunchuck, I thought "wow, this would be a pretty cool controller to use for an electronic instrument." After I did a little web research, I discovered that it has:<br />
<ul>
<li>2 momentary pushbuttons</li>
<li>a joystick</li>
<li>a 3-axis accelerometer</li>
</ul>
On top of that, I discovered that it uses a standard <a href="http://en.wikipedia.org/wiki/I%C2%B2C" target="_blank">i2c</a> interface, that libraries existed to make it work with Arduino, and that <a href="http://todbot.com/blog/2008/02/18/wiichuck-wii-nunchuck-adapter-available/" target="_blank">you can even use one without hacking off the connector</a>. Many thanks to <span class="coMULTI"><a href="http://growdown.blogspot.com/" target="_blank">Tim Hirzel</a> and </span><a href="http://todbot.com/blog/" target="_blank">Tod E. Kurt</a>, for the WiiChuck library, and another thanks to Tod for the <a href="https://www.sparkfun.com/products/9281" target="_blank">WiiChuck Adapter)</a>.<br />
<br />
I'm a big fan of <a href="http://onyx-ashanti.com/" target="_blank">Onyx Ashanti's work</a>, and I've always been impressed with <a href="http://www.ted.com/talks/onyx_ashanti_this_is_beatjazz.html" target="_blank">how his beatjazz controller frees up his hands to move around independently</a>. This lead me to think about using two Nunchucks in a single instrument, in addition to the pressure sensor.<br />
<br />
<h2>
Breadboard Layout</h2>
<h2>
</h2>
The instrument is really simple - only 4 parts are needed. A Freescale pressure sensor (the one I <a href="http://gordophone.blogspot.com/2013/01/breath-sensing-101.html" target="_blank">discussed in a previous post</a>), the two nunchucks, and a <a href="http://www.pjrc.com/store/teensy3.html" target="_blank">Teensy 3.0 microcontroller</a>. If you've read my previous posts, you'll note that I'm now using the Teensy 3.0 instead of the Teensy 2.0. I'll discuss why I made that change in the section "Challenges" later in this post.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-csNKAowyV2U/UWrarK_WhNI/AAAAAAAABg4/Z06lP3IWriI/s1600/BlowChucks_bb.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="http://2.bp.blogspot.com/-csNKAowyV2U/UWrarK_WhNI/AAAAAAAABg4/Z06lP3IWriI/s640/BlowChucks_bb.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
The wiring is pretty simple:<br />
<br />
The pressure sensor gets a reference voltage on pin 2, ground on pin 3, and the output connects to pin 4. The output voltage varies between 0 and the reference voltage depending on the breath pressure (so this part should work fine on either 3.3 or 5 volt controllers, and that's been my experience).<br />
<br />
The pressure sensor output goes to the Teensy analog pin 0, which is read to determine how hard the performer is blowing.<br />
<br />
Each Nunchuck gets a connection to ground and power, and a distinct i2c bus connection to the Teensy.<br />
<br />
<h2>
Challenges</h2>
<h2>
</h2>
I began work on this project by using a Teensy 2.0 controller (which is awesomely cool because it has USB-MIDI support built in) and one Nunchuck. I was able to build an instrument that can <a href="http://gordophone.blogspot.com/2013/02/wii-nunchuck-and-ableton-live-scene.html" target="_blank">manage Ableton Live scenes (previous/next, launch), using one Nunchuck</a>.<br />
<br />
While working on the next iteration of the controller I ran into one serious roadblock. The nunchuck is designed to plug into the WiiMote game controller's single accessory port. The nunchuck wasn't designed in a way that allows two of them to be hooked up at the same time. This is because each device on an i2c bus needs to have a separate identifier, but all nunchucks have the same i2c id.<br />
<br />
To solve this problem, I switched to the Teensy 3.0, which has two sets of i2c pins. Although it looks like the ARM Cortex M3 that the Teensy 3.0 is based on has two separate i2c buses, there is only one i2c block on the chip. Still, with a bit of creative programming, you can make things work by configuring one set of i2c pins, polling one nunchuck, then configuring the other set of pins and polling the other nunchuck. Thanks to Brian in the <a href="http://forum.pjrc.com/threads/21680-New-I2C-library-for-Teensy3?highlight=i2c+library" target="_blank">PJRC forum</a> for his new i2c library and also for the help in figuring out how to make both i2c "buses" work.<br />
<br />
Another option would have been to stick with the Teensy 2.0 and use something like a 4053-series analog multiplexer to let the Teensy talk to both nunchucks. At some point I'll adapt this instrument so it can work with a plain Arduino, and I'll include the multiplexer in that design.<br />
<br />
<h2>
How It Works</h2>
First, an explanatory video:<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/j1emiN2XLCU" width="560"></iframe>
<br />
<br />
The code, which is <a href="https://github.com/ggood/BlowChucks/tree/harm_den_roll" target="_blank">available on github</a>, works as follows:<br />
<br />
Each time through the loop() method, we do the following<br />
<ul>
<li>Poll each nunchuck and record the joystick position, button state, and the current pitch (up/down) and roll (side-to-side) position.</li>
<li>Record the current analog value read from the breath sensor</li>
</ul>
If the breath value has increased above a threshold value, we send one or more MIDI note on events to turn on notes, and if the value has fallen below threshold, we turn off all notes that are currently playing. This allows the player to articulate notes just like on a wind instrument.<br />
<br />
If notes are currently sounding, we also send new MIDI continuous controller values for breath controller and also send updated aftertouch values. We send both because some synthesizer patches respond to breath controller input, while others, such as the Korg M1 software synth I use in the video, only respond to aftertouch values.<br />
<br />
When it's time to send note on messages, we first calculate a "base" note (not a "bass" note), by looking at the "compass position" of the right joystick, and map those positions to the notes of a pentatonic scale:<br />
<br />
Center: C6<br />
North: D6<br />
Northeast: F6<br />
East: G6<br />
Southeast: A6<br />
South: C7<br />
Southwest: D7<br />
West: F7<br />
Northwest: G7<br />
<br />
The left joystick can be used to transpose the base note by an octave up or down by moving it in the X axis. If pushed to the left, the base note is transposed down an octave, by subtracting 12 from the base MIDI note value. If pushed to the right, the base note is transposed up an octave by adding 12 to the base MIDI note value (centered leaves the base note as is).<br />
<br />
Once the base note has been calculated, a harmonization of the base note is created. There are several different harmonization algorithms, which can be cycled through by using the buttons on the left joystick. In the code, we use a function pointer to select which harmonization function gets called for note on events.<br />
<br />
There are several parallel harmonization algorithms, as well as two that create slash chord voicings by choosing a bass note randomly from one of several choices.<br />
<br />
Then, we decide how many notes of the harmonization to turn on by examining the roll value of the left nunchuck. When rolled all the way to the left, only the base note sounds. Rolling the nunchuck to the right enables more and more of the notes of the harmonization.<br />
<br />
One final thing we do on each loop is look for button presses on the right nunchuck, and map those to MIDI note on messages on a second MIDI channel. If the upper button is pressed, we send MIDI note on and note off messages for MIDI note C0. If the lower button is pressed, we do the same, but with note C#0, and if both buttons are pressed and released, we send a MIDI D0 note on/off pair. This is intended for use with Ableton live to navigate up and down the list of scenes with the up and down buttons, and to launch the currently selected scene by pressing both buttons.<br />
<br />
<h2>
The Sounds</h2>
The sounds that you're hearing from the Blowchucks controller are coming from a <a href="http://www.korg.com/Legacym1" target="_blank">Korg M1 Legacy software synthesizer</a>, running inside Ableton Live 8 on my MacBook. The patches were programmed by Matt Traum of <a href="https://www.patchmanmusic.com/" target="_blank">Patchman Music</a>, and were developed from the ground up to work well with wind-based controllers like the Blowchucks, or commercially available wind controllers.<br />
<br />
<h2>
Summary</h2>
The Blowchucks controller is a fun instrument to play, especially when it is driving synthesizer patches that are breath-friendly. It should be really simple to build for about $70, and I hope that people reading this post will build the controller and dream up all sorts of crazy new ways to play it!<br />
<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<br />Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com4tag:blogger.com,1999:blog-2671439418188048550.post-46402656810989005402013-02-24T07:50:00.002-08:002013-02-27T00:49:22.676-08:00Wii Nunchuck and Ableton Live Scene ControlI've been playing around with some cheap knock-off Wii Nunchuck controllers I got from eBay. I wrote some code that allows the Nunchuck to be used for scene navigation and launch in Ableton Live.<br />
<br />
Scene up/down is controlled by the two buttons, and to launch the currently selected scene, shake the controller.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dwQNRvUCvgaQftkHd8p1-bl5lCV3UXC2YzIe8VjfgFW5ECMEN1-gBZdshMEh61hNX8mBHR5_-iKGzlE3UNMsw' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
The joystick is not used at this time. This will eventually be part of a more complicated controller, probably using two Nunchucks and a breath controller.<br />
<br />
There's nothing too fancy going on here. Each button press sends a different MIDI note on/off pair on MIDI channel two, and a sudden change in the accelerometer readings sends another MIDI note on/off pair. Ableton's MIDI map mode makes it very easy to assign those messages to the scene controls.<br />
<br />
Here's the code (requires a PJRC Teensy Microcontroller).<br />
<br />
<pre>#include <span style="color: #006699;">"Wire.h"</span>
#include <span style="color: #006699;">"WiiChuck.h"</span>
<span style="color: #7e7e7e;">// The MIDI channel we use for Ableton Live control</span>
#define SCENE_MGMT_MIDI_CHANNEL 2
<span style="color: #7e7e7e;">// The MIDI note for Live scene launch</span>
#define SCENE_LAUNCH_MIDI_NOTE 0
<span style="color: #7e7e7e;">// The MIDI note for the Live previous scene action</span>
#define SCENE_PREV_MIDI_NOTE 1
<span style="color: #7e7e7e;">// The MIDI note for the Live next scene action</span>
#define SCENE_NEXT_MIDI_NOTE 2
<span style="color: #7e7e7e;">// Suppress multiple scene lanches if < 100 ms apart</span>
#define SCENE_LAUNCH_DELAY 100
<span style="color: #7e7e7e;">// We need a change in Z-axis acceleration larger</span>
<span style="color: #7e7e7e;">// than this to launch the selected scene. You should</span>
<span style="color: #7e7e7e;">// adjust this value to fine-tune how hard you have</span>
<span style="color: #7e7e7e;">// to jerk the nunchuck to launch a scene.</span>
#define Z_AXIS_ACCEL_THRESHOLD 500
WiiChuck chuck = WiiChuck(); <span style="color: #7e7e7e;">// The nunchuck controller</span>
<span style="color: #cc6600;">int</span> xVal, yVal, zVal, zSum, zAvg;
<span style="color: #cc6600;">int</span> zValues[10] = {0};
<span style="color: #cc6600;">byte</span> note;
<span style="color: #cc6600;">boolean</span> cButton, zButton;
<span style="color: #cc6600;">int</span> i;
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> sceneChangeTime;
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>setup</b></span>() {
<span style="color: #7e7e7e;">// Initialize the nunchuck-related things</span>
cButton = zButton = <span style="color: #cc6600;">false</span>;
chuck.<span style="color: #cc6600;">begin</span>();
}
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>loop</b></span>() {
<span style="color: #7e7e7e;">// Process nunchuck data</span>
chuck.<span style="color: #cc6600;">update</span>();
<span style="color: #cc6600;">delay</span>(1);
<span style="color: #7e7e7e;">// Deal with accelerometer. Compute the average accelerometer</span>
<span style="color: #7e7e7e;">// value over the last 10 samples. I've unfortunately forgotten</span>
<span style="color: #7e7e7e;">// what internet reference lead me to using smoothed values</span>
<span style="color: #7e7e7e;">// for this - apologies.</span>
zVal = chuck.readAccelZ();
zSum -= zValues[i];
zSum += zVal;
zValues[i] = zVal;
i = (i + 1) % 10;
zAvg = zSum / 10;
<span style="color: #7e7e7e;">// If the average value is above some configured threshold, treat</span>
<span style="color: #7e7e7e;">// the gesture as a scene launch</span>
<span style="color: #cc6600;">if</span> (zAvg > Z_AXIS_ACCEL_THRESHOLD) {
<span style="color: #cc6600;">if</span> (<span style="color: #cc6600;">millis</span>() - sceneChangeTime > SCENE_LAUNCH_DELAY) {
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOn</span>(SCENE_LAUNCH_MIDI_NOTE, 100, SCENE_MGMT_MIDI_CHANNEL);
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOff</span>(SCENE_LAUNCH_MIDI_NOTE, 100, SCENE_MGMT_MIDI_CHANNEL);
sceneChangeTime = <span style="color: #cc6600;">millis</span>();
}
}
<span style="color: #cc6600;">if</span> (chuck.cPressed()) {
<span style="color: #cc6600;">if</span> (!cButton) {
<span style="color: #7e7e7e;">// Rising edge - launch current scene</span>
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOn</span>(SCENE_PREV_MIDI_NOTE, 100, SCENE_MGMT_MIDI_CHANNEL);
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOff</span>(SCENE_PREV_MIDI_NOTE, 100, SCENE_MGMT_MIDI_CHANNEL);
cButton = <span style="color: #cc6600;">true</span>;
}
} <span style="color: #cc6600;">else</span> {
cButton = <span style="color: #cc6600;">false</span>;
}
<span style="color: #cc6600;">if</span> (chuck.zPressed()) {
<span style="color: #cc6600;">if</span> (!zButton) {
<span style="color: #7e7e7e;">// Rising edge - select the next scene</span>
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOn</span>(SCENE_NEXT_MIDI_NOTE, 100, SCENE_MGMT_MIDI_CHANNEL);
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOff</span>(SCENE_NEXT_MIDI_NOTE, 100, SCENE_MGMT_MIDI_CHANNEL);
zButton = <span style="color: #cc6600;">true</span>;
}
} <span style="color: #cc6600;">else</span> {
zButton = <span style="color: #cc6600;">false</span>;
}
}
</pre>
<br />
To set up Ableton Live, you need to enter MIDI mode (Command-M on a Mac), select the control to configure, then either press one of the buttons on the nunchuck or shake it, depending on which scene control you are configuring).<br />
<br />
Depending on which Wii Nunchuck you have (knockoff or genuine Nintendo), you may need a different initialization sequence. Here's the WiiChuck.h I cobbled together from various internet sources (but most of the work comes from <a href="http://www.growdown.com/" target="_blank">Tim Hirzel</a> and <a href="http://todbot.com/blog/" target="_blank">Tod E. Kurt</a> of <a href="http://thingm.com/" target="_blank">ThingM</a>):<br />
<br />
<br />
<pre><span style="color: #7e7e7e;">/*</span>
<span style="color: #7e7e7e;"> * Nunchuck -- Use a Wii Nunchuck</span>
<span style="color: #7e7e7e;"> * Tim Hirzel http://www.growdown.com</span>
<span style="color: #7e7e7e;"> * </span>
<span style="color: #7e7e7e;"> notes on Wii Nunchuck Behavior.</span>
<span style="color: #7e7e7e;"> This library provides an improved derivation of rotation angles from the nunchuck accelerometer data.</span>
<span style="color: #7e7e7e;"> The biggest different over existing libraries (that I know of ) is the full 360 degrees of Roll data</span>
<span style="color: #7e7e7e;"> from teh combination of the x and z axis accelerometer data using the math library atan2. </span>
<span style="color: #7e7e7e;"> It is accurate with 360 degrees of roll (rotation around axis coming out of the c button, the front of the wii),</span>
<span style="color: #7e7e7e;"> and about 180 degrees of pitch (rotation about the axis coming out of the side of the wii). (read more below)</span>
<span style="color: #7e7e7e;"> In terms of mapping the wii position to angles, its important to note that while the Nunchuck</span>
<span style="color: #7e7e7e;"> sense Pitch, and Roll, it does not sense Yaw, or the compass direction. This creates an important</span>
<span style="color: #7e7e7e;"> disparity where the nunchuck only works within one hemisphere. At a result, when the pitch values are </span>
<span style="color: #7e7e7e;"> less than about 10, and greater than about 170, the Roll data gets very unstable. essentially, the roll</span>
<span style="color: #7e7e7e;"> data flips over 180 degrees very quickly. To understand this property better, rotate the wii around the</span>
<span style="color: #7e7e7e;"> axis of the joystick. You see the sensor data stays constant (with noise). Because of this, it cant know</span>
<span style="color: #7e7e7e;"> the difference between arriving upside via 180 degree Roll, or 180 degree pitch. It just assumes its always</span>
<span style="color: #7e7e7e;"> 180 roll.</span>
<span style="color: #7e7e7e;"> * </span>
<span style="color: #7e7e7e;"> * This file is an adaptation of the code by these authors:</span>
<span style="color: #7e7e7e;"> * Tod E. Kurt, http://todbot.com/blog/</span>
<span style="color: #7e7e7e;"> *</span>
<span style="color: #7e7e7e;"> * The Wii Nunchuck reading code is taken from Windmeadow Labs</span>
<span style="color: #7e7e7e;"> * http://www.windmeadow.com/node/42</span>
<span style="color: #7e7e7e;"> * </span>
<span style="color: #7e7e7e;"> * Conversion to Arduino 1.0 by Danjovic</span>
<span style="color: #7e7e7e;"> * http://hotbit.blogspot.com </span>
<span style="color: #7e7e7e;"> * </span>
<span style="color: #7e7e7e;"> */</span>
#ifndef WiiChuck_h
#define WiiChuck_h
#include <span style="color: #006699;">"Arduino.h"</span>
#include <<span style="color: #cc6600;">Wire</span>.h>
#include <math.h>
<span style="color: #7e7e7e;">// these may need to be adjusted for each nunchuck for calibration</span>
#define ZEROX 510
#define ZEROY 490
#define ZEROZ 460
#define RADIUS 210 <span style="color: #7e7e7e;">// probably pretty universal</span>
#define DEFAULT_ZERO_JOY_X 124
#define DEFAULT_ZERO_JOY_Y 132
<span style="color: #cc6600;">class</span> WiiChuck {
<span style="color: #cc6600;">private</span>:
<span style="color: #cc6600;">uint8_t</span> cnt;
<span style="color: #cc6600;">uint8_t</span> <span style="color: #cc6600;">status</span>[6]; <span style="color: #7e7e7e;">// array to store wiichuck output</span>
<span style="color: #cc6600;">uint8_t</span> averageCounter;
<span style="color: #7e7e7e;">//int accelArray[3][AVERAGE_N]; // X,Y,Z</span>
<span style="color: #cc6600;">int</span> i;
<span style="color: #cc6600;">int</span> total;
<span style="color: #cc6600;">uint8_t</span> zeroJoyX; <span style="color: #7e7e7e;">// these are about where mine are</span>
<span style="color: #cc6600;">uint8_t</span> zeroJoyY; <span style="color: #7e7e7e;">// use calibrateJoy when the stick is at zero to correct</span>
<span style="color: #cc6600;">int</span> lastJoyX;
<span style="color: #cc6600;">int</span> lastJoyY;
<span style="color: #cc6600;">int</span> angles[3];
bool lastZ, lastC;
<span style="color: #cc6600;">public</span>:
<span style="color: #cc6600;">uint8_t</span> joyX;
<span style="color: #cc6600;">uint8_t</span> joyY;
bool buttonZ;
bool buttonC;
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;">begin</span>()
{
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">begin</span>();
cnt = 0;
averageCounter = 0;
<span style="color: #7e7e7e;">// instead of the common 0x40 -> 0x00 initialization, we</span>
<span style="color: #7e7e7e;">// use 0xF0 -> 0x55 followed by 0xFB -> 0x00.</span>
<span style="color: #7e7e7e;">// this lets us use 3rd party nunchucks (like cheap $4 ebay ones)</span>
<span style="color: #7e7e7e;">// while still letting us use official oness.</span>
<span style="color: #7e7e7e;">// only side effect is that we no longer need to decode bytes in _nunchuk_decode_byte</span>
<span style="color: #7e7e7e;">// see http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1264805255</span>
<span style="color: #7e7e7e;">// </span>
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(0x52); <span style="color: #7e7e7e;">// device address</span>
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span>(0xF0);
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span>(0x55);
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();
<span style="color: #cc6600;">delay</span>(1);
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(0x52);
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span>(0xFB);
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span>((<span style="color: #cc6600;">uint8_t</span>)0x00);
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();
<span style="color: #cc6600;">update</span>();
<span style="color: #cc6600;">for</span> (i = 0; i<3;i++) {
angles[i] = 0;
}
zeroJoyX = DEFAULT_ZERO_JOY_X;
zeroJoyY = DEFAULT_ZERO_JOY_Y;
}
<span style="color: #cc6600;">void</span> calibrateJoy() {
zeroJoyX = joyX;
zeroJoyY = joyY;
}
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;">update</span>() {
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">requestFrom</span> (0x52, 6); <span style="color: #7e7e7e;">// request data from nunchuck</span>
<span style="color: #cc6600;">while</span> (<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">available</span> ()) {
<span style="color: #7e7e7e;">// receive byte as an integer</span>
<span style="color: #cc6600;">status</span>[cnt] = _nunchuk_decode_byte (<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">read</span>()); <span style="color: #7e7e7e;">//</span>
cnt++;
}
<span style="color: #cc6600;">if</span> (cnt > 5) {
lastZ = buttonZ;
lastC = buttonC;
lastJoyX = readJoyX();
lastJoyY = readJoyY();
<span style="color: #7e7e7e;">//averageCounter ++;</span>
<span style="color: #7e7e7e;">//if (averageCounter >= AVERAGE_N)</span>
<span style="color: #7e7e7e;">// averageCounter = 0;</span>
cnt = 0;
joyX = (<span style="color: #cc6600;">status</span>[0]);
joyY = (<span style="color: #cc6600;">status</span>[1]);
<span style="color: #cc6600;">for</span> (i = 0; i < 3; i++)
<span style="color: #7e7e7e;">//accelArray[i][averageCounter] = ((int)status[i+2] << 2) + ((status[5] & (B00000011 << ((i+1)*2) ) >> ((i+1)*2))); </span>
angles[i] = (<span style="color: #cc6600;">status</span>[i+2] << 2) + ((<span style="color: #cc6600;">status</span>[5] & (B00000011 << ((i+1)*2) ) >> ((i+1)*2)));
<span style="color: #7e7e7e;">//accelYArray[averageCounter] = ((int)status[3] << 2) + ((status[5] & B00110000) >> 4); </span>
<span style="color: #7e7e7e;">//accelZArray[averageCounter] = ((int)status[4] << 2) + ((status[5] & B11000000) >> 6); </span>
buttonZ = !( <span style="color: #cc6600;">status</span>[5] & B00000001);
buttonC = !((<span style="color: #cc6600;">status</span>[5] & B00000010) >> 1);
_send_zero(); <span style="color: #7e7e7e;">// send the request for next bytes</span>
}
}
<span style="color: #7e7e7e;">// UNCOMMENT FOR DEBUGGING</span>
<span style="color: #7e7e7e;">//byte * getStatus() {</span>
<span style="color: #7e7e7e;">// return status;</span>
<span style="color: #7e7e7e;">//}</span>
<span style="color: #cc6600;">float</span> readAccelX() {
<span style="color: #7e7e7e;">// total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT;</span>
<span style="color: #cc6600;">return</span> (<span style="color: #cc6600;">float</span>)angles[0] - ZEROX;
}
<span style="color: #cc6600;">float</span> readAccelY() {
<span style="color: #7e7e7e;">// total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT;</span>
<span style="color: #cc6600;">return</span> (<span style="color: #cc6600;">float</span>)angles[1] - ZEROY;
}
<span style="color: #cc6600;">float</span> readAccelZ() {
<span style="color: #7e7e7e;">// total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT;</span>
<span style="color: #cc6600;">return</span> (<span style="color: #cc6600;">float</span>)angles[2] - ZEROZ;
}
bool zPressed() {
<span style="color: #cc6600;">return</span> (buttonZ && ! lastZ);
}
bool cPressed() {
<span style="color: #cc6600;">return</span> (buttonC && ! lastC);
}
<span style="color: #7e7e7e;">// for using the joystick like a directional button</span>
bool rightJoy(<span style="color: #cc6600;">int</span> thresh=60) {
<span style="color: #cc6600;">return</span> (readJoyX() > thresh and lastJoyX <= thresh);
}
<span style="color: #7e7e7e;">// for using the joystick like a directional button</span>
bool leftJoy(<span style="color: #cc6600;">int</span> thresh=60) {
<span style="color: #cc6600;">return</span> (readJoyX() < -thresh and lastJoyX >= -thresh);
}
<span style="color: #cc6600;">int</span> readJoyX() {
<span style="color: #cc6600;">return</span> (<span style="color: #cc6600;">int</span>) joyX - zeroJoyX;
}
<span style="color: #cc6600;">int</span> readJoyY() {
<span style="color: #cc6600;">return</span> (<span style="color: #cc6600;">int</span>)joyY - zeroJoyY;
}
<span style="color: #7e7e7e;">// R, the radius, generally hovers around 210 (at least it does with mine)</span>
<span style="color: #7e7e7e;">// int R() {</span>
<span style="color: #7e7e7e;">// return sqrt(readAccelX() * readAccelX() +readAccelY() * readAccelY() + readAccelZ() * readAccelZ()); </span>
<span style="color: #7e7e7e;">// }</span>
<span style="color: #7e7e7e;">// returns roll degrees</span>
<span style="color: #cc6600;">int</span> readRoll() {
<span style="color: #cc6600;">return</span> (<span style="color: #cc6600;">int</span>)(<span style="color: #cc6600;">atan2</span>(readAccelX(),readAccelZ())/ M_PI * 180.0);
}
<span style="color: #7e7e7e;">// returns pitch in degrees</span>
<span style="color: #cc6600;">int</span> readPitch() {
<span style="color: #cc6600;">return</span> (<span style="color: #cc6600;">int</span>) (<span style="color: #cc6600;">acos</span>(readAccelY()/RADIUS)/ M_PI * 180.0); <span style="color: #7e7e7e;">// optionally swap 'RADIUS' for 'R()'</span>
}
<span style="color: #cc6600;">private</span>:
<span style="color: #cc6600;">uint8_t</span> _nunchuk_decode_byte (<span style="color: #cc6600;">uint8_t</span> x)
{
<span style="color: #7e7e7e;">//decode is only necessary with certain initializations </span>
<span style="color: #7e7e7e;">//x = (x ^ 0x17) + 0x17;</span>
<span style="color: #cc6600;">return</span> x;
}
<span style="color: #cc6600;">void</span> _send_zero()
{
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span> (0x52); <span style="color: #7e7e7e;">// transmit to device 0x52</span>
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span> ((<span style="color: #cc6600;">uint8_t</span>)0x00); <span style="color: #7e7e7e;">// sends one byte</span>
<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span> (); <span style="color: #7e7e7e;">// stop transmitting</span>
}
};
#endif
</pre>
<br />Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com2tag:blogger.com,1999:blog-2671439418188048550.post-62327727168482033032013-01-27T08:05:00.000-08:002016-02-24T21:54:09.904-08:00Expression, Part 2 (MIDI Aftertouch)<br />
In my <a href="http://gordophone.blogspot.com/2013/01/expression-part-1-midi-note-on-velocity.html" target="_blank">previous post</a> I showed how to map the breath pressure measured at the time a note commences to MIDI note on velocity. This allows a wind controller to play synth patches that mimic percussive or plucked instruments in a fairly natural way - the harder you blow, the harder the attack sounds (assuming that the synthesizer patch is responsive to note on velocity).<br />
<br />
Another expression parameter present in the MIDI spec is <a href="http://www.sweetwater.com/expert-center/glossary/t--Aftertouch" target="_blank">aftertouch, sometimes referred to as pressure</a>. After pressing a key down, a player can "lean on" the note and the keyboard will send additional MIDI messages that tell a synthesizer how hard the key is being pressed. Synth patches that respond to aftertouch will often alter a filter frequency as the pressure on the key increases (usually brightening the sound), or apply more vibrato to the note, but that's just one of many possible things that can be altered in real time.<br />
<br />
There are actually two types of aftertouch - monophonic aftertouch, sometimes called channel pressure, and polyphonic aftertouch. With monophonic aftertouch, the keyboard only sends one value for aftertouch, no matter how many keys are being held down. With polyphonic aftertouch, the keyboard sends one aftertouch value for each key being pressed. Since a wind instrument is inherently a monophonic (one note at a time) instrument, we'll only worry about monophonic aftertouch in this post.<br />
<br />
This sketch builds on the sketch in the MIDI note on velocity sketch (and uses <a href="http://gordophone.blogspot.com/2013/01/breath-sensing-101.html" target="_blank">the same circuit built in this post</a>), and brings back a couple of the concepts from the <a href="http://gordophone.blogspot.com/2013/01/building-breath-controller.html" target="_blank">breath controller post</a>. Notice how we keep track of the last time we sent an aftertouch value, and only send a new value if a specific amount of time has passed, to avoid sending unnecessary MIDI data.<br />
<br />
I've highlighted in yellow the additions the sketch from the previous post (so anything not in yellow is unchanged). There really isn't a lot of new code, mostly because we only need to worry about sending aftertouch values when we know a note is on.<br />
<br />
<br />
<pre>#define MIDI_CHANNEL 1
<span style="color: #7e7e7e;">// The threshold level for sending a note on event. If the</span>
<span style="color: #7e7e7e;">// sensor is producing a level above this, we should be sounding</span>
<span style="color: #7e7e7e;">// a note.</span>
#define NOTE_ON_THRESHOLD 80
<span style="color: #7e7e7e;">// The maximum raw pressure value you can generate by</span>
<span style="color: #7e7e7e;">// blowing into the tube.</span>
#define MAX_PRESSURE 500
<span style="color: #7e7e7e;">// The three states of our state machine</span>
<span style="color: #7e7e7e;">// No note is sounding</span>
#define NOTE_OFF 1
<span style="color: #7e7e7e;">// We've observed a transition from below to above the</span>
<span style="color: #7e7e7e;">// threshold value. We wait a while to see how fast the</span>
<span style="color: #7e7e7e;">// breath velocity is increasing</span>
#define RISE_WAIT 2
<span style="color: #7e7e7e;">// A note is sounding</span>
#define NOTE_ON 3
<span style="background-color: yellow;"><span style="color: #7e7e7e;">// Send aftertouch data no more than every AT_INTERVAL</span>
<span style="color: #7e7e7e;">// milliseconds</span>
#define AT_INTERVAL 70</span> </pre>
<pre>// We wait for 10 milliseconds of continuous breath</pre>
<pre>// pressure above NOTE+ON_THRESHOLD before we turn on</pre>
<pre>// the note, to de-glitch</pre>
<pre>#define RISE_TIME 10 </pre>
<pre><span style="color: #7e7e7e;">// The five notes, from which we choose one at random</span>
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">int</span> notes[5] = {60, 62, 65, 67, 69};
<span style="color: #7e7e7e;">// We keep track of which note is sounding, so we know</span>
<span style="color: #7e7e7e;">// which note to turn off when breath stops.</span>
<span style="color: #cc6600;">int</span> noteSounding;
<span style="color: #7e7e7e;">// The value read from the sensor</span>
<span style="color: #cc6600;">int</span> sensorValue;
<span style="color: #7e7e7e;">// The state of our state machine</span>
<span style="color: #cc6600;">int</span> state;
<span style="color: #7e7e7e;">// The time that we noticed the breath off -> on transition</span>
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> breath_on_time = 0L;
<span style="color: #7e7e7e;">// The breath value at the time we observed the transition</span>
<span style="color: #cc6600;">int</span> initial_breath_value;
<span style="background-color: yellow;"><span style="color: #7e7e7e;">// The aftertouch value we will send</span>
<span style="color: #cc6600;">int</span> atVal;
<span style="color: #7e7e7e;">// The last time we sent an aftertouch value</span>
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> atSendTime = 0L;</span>
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>setup</b></span>() {
state = NOTE_OFF; <span style="color: #7e7e7e;">// initialize state machine</span>
}
<span style="color: #cc6600;">int</span> get_note() {
<span style="color: #cc6600;">return</span> notes[<span style="color: #cc6600;">random</span>(0,4)];
}
<span style="color: #cc6600;">int</span> get_velocity(<span style="color: #cc6600;">int</span> initial, <span style="color: #cc6600;">int</span> final, <span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> time_delta) {
<span style="color: #cc6600;">return</span> <span style="color: #cc6600;">map</span>(final, NOTE_ON_THRESHOLD, MAX_PRESSURE, 0, 127);
}
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>loop</b></span>() {
<span style="color: #7e7e7e;">// read the input on analog pin 0</span>
sensorValue = <span style="color: #cc6600;">analogRead</span>(A0);
<span style="color: #cc6600;">if</span> (state == NOTE_OFF) {
<span style="color: #cc6600;">if</span> (sensorValue > NOTE_ON_THRESHOLD) {
<span style="color: #7e7e7e;">// Value has risen above threshold. Move to the RISE_TIME</span>
<span style="color: #7e7e7e;">// state. Record time and initial breath value.</span>
breath_on_time = <span style="color: #cc6600;">millis</span>();
initial_breath_value = sensorValue;
state = RISE_WAIT; <span style="color: #7e7e7e;">// Go to next state</span>
}
} <span style="color: #cc6600;">else</span> <span style="color: #cc6600;">if</span> (state == RISE_WAIT) {
<span style="color: #cc6600;">if</span> (sensorValue > NOTE_ON_THRESHOLD) {
<span style="color: #7e7e7e;">// Has enough time passed for us to collect our second</span>
<span style="color: #7e7e7e;">// sample?</span>
<span style="color: #cc6600;">if</span> (<span style="color: #cc6600;">millis</span>() - breath_on_time > RISE_TIME) {
<span style="color: #7e7e7e;">// Yes, so calculate MIDI note and velocity, then send a note on event</span>
noteSounding = get_note();
<span style="color: #cc6600;">int</span> velocity = get_velocity(initial_breath_value, sensorValue, RISE_TIME);
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOn</span>(noteSounding, velocity, MIDI_CHANNEL);
state = NOTE_ON;
}
} <span style="color: #cc6600;">else</span> {
<span style="color: #7e7e7e;">// Value fell below threshold before RISE_TIME passed. Return to</span>
<span style="color: #7e7e7e;">// NOTE_OFF state (e.g. we're ignoring a short blip of breath)</span>
state = NOTE_OFF;
}
} <span style="color: #cc6600;">else</span> <span style="color: #cc6600;">if</span> (state == NOTE_ON) {
<span style="color: #cc6600;">if</span> (sensorValue < NOTE_ON_THRESHOLD) {
<span style="color: #7e7e7e;">// Value has fallen below threshold - turn the note off</span>
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOff</span>(noteSounding, 100, MIDI_CHANNEL);
state = NOTE_OFF;
<span style="background-color: yellow;"> } <span style="color: #cc6600;">else</span> {
<span style="color: #7e7e7e;">// Is it time to send more aftertouch data?</span>
<span style="color: #cc6600;">if</span> (<span style="color: #cc6600;">millis</span>() - atSendTime > AT_INTERVAL) {
<span style="color: #7e7e7e;">// Map the sensor value to the aftertouch range 0-127</span>
atVal = <span style="color: #cc6600;">map</span>(sensorValue, NOTE_ON_THRESHOLD, 1023, 0, 127);
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendAfterTouch</span>(atVal, MIDI_CHANNEL);
atSendTime = <span style="color: #cc6600;">millis</span>();
}
}</span>
}
}
</pre>
<br />
Here are a couple of recordings I made. In the first, I play some long notes that have a hard initial attack, then I immediately back off the breath, and blow harder and harder until I release the note (a <i>fp</i> plus a crescendo for you musicians).<br />
<br />
In this first example, the synth is not responding to aftertouch, so you just hear a static note.<br />
<br />
<iframe frameborder="no" height="166" scrolling="no" src="http://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F76239577&auto_play=false&show_artwork=false&color=ff1500" width="100%"></iframe>
In the second example, I've modified the synth patch to apply vibrato to the patch, and the amount of vibrato depends on the aftertouch value.<br />
<br />
<iframe frameborder="no" height="166" scrolling="no" src="http://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F76239626&auto_play=false&show_artwork=false&color=ff1500" width="100%"></iframe>Are you able to hear the vibrato (wavering sound) at the end of the notes?<br />
<br />
<h4>
What's Next</h4>
<br />
With the ability to add expressiveness via MIDI note velocity and aftertouch, we can make some pretty interesting sounds, but we're still mimicking a keyboard instrument. To realize the full potential of an electronic wind instrument, we're going to need to get synthesizers to respond to us in a way that makes sense for the way that a wind instrument works. <br />
<br />
While I am by no means an expert in synth programming, I'll share what I know, and maybe we can come up with some interesting sounds.Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com18tag:blogger.com,1999:blog-2671439418188048550.post-60845680420545950272013-01-21T10:45:00.000-08:002013-01-23T23:25:27.774-08:00Expression, part 1 (MIDI Note On Velocity)In our previous Arduino sketches, we created musical instruments that were very limited in terms of expression. In this post, I'll discuss two ways that we can give the instrument more expressive capabilities that utilize the performer's breath - mapping breath articulation to MIDI note on velocity, and mapping breath values to MIDI aftertouch after the initial attack.<br />
<br />
These two techniques are useful if you are trying to play an existing synthesizer patch that is not specifically designed for wind control. They still leave a lot to be desired if you want to create an instrument that plays like an acoustic wind instrument, but I'll cover that topic in a later post.<br />
<br />
<h3>
An Inventory Of Expression Parameters</h3>
<br />
Before I go much further, let's take a moment to understand the various ways the the MIDI spec conveys expressive data, and how that MIDI data relates to a breath sensor.<br />
<br />
<h4>
Note On Velocity</h4>
<br />
With a velocity-sensitive keyboard, the MIDI note on velocity describes how hard the key on the keyboard was pressed (strictly speaking, it's the speed with which the finger moves the piano key through its range of motion - that's why it's called "velocity" and not "force"). For percussive instruments like drums or keyboards, it usually controls the overall volume of the ADSR envelope. Note on values range from 0 to 127, with 0 representing the lightest possible touch, and 127 representing the maximum force. <br />
<br />
For a wind controller, it's not so clear. When a wind player articulates a note, the note starts from zero breath and increases at some rate controlled by the player. In the case where the player is using a hard articulation (that is, one with a fast rise time), it may make sense to try to map the rise time of the sensor to a note on velocity. This can be helpful if you are trying to play a patch that behaves like a percussive or plucked instrument. We'll implement this in the first sketch in this series, and see how it works out. As a hint, it's kind of a dead-end if we really want to build an instrument that responds like a real-world wind instrument, but the concepts here are generally useful, plus if you really do want to play a piano or drum patch, it'll help you play that patch with more expression.<br />
<br />
There is also a corresponding note off velocity. I don't think this is widely used in synth patches, but it would control the duration of the R phase of the ADSR envelope. We won't implement it in our instrument's code, to keep things simple. <br />
<br />
<h4>
Aftertouch</h4>
<br />
In addition to detecting how hard a key was initially pressed, many MIDI keyboards can detect how hard a key is being pressed while it it being held down and transmit that data via MIDI aftertouch messages. With many synth patches, pressing harder on the key will engage a vibrato effect like the modulation wheel.<br />
<br />
With our wind controller, It's pretty simple to send aftertouch data that corresponds to the breath values. So, if a patch is configured to respond to aftertouch, we should be able to make it respond to how hard we blow after starting the note. We'll implement that in our sketch and see how it affects a few different synthesizer patches.<br />
<br />
<h4>
Continuous Controllers</h4>
<br />
We saw how continuous controllers work in a previous post. They are MIDI messages that aren't associated with any particular note. There are many different continuous controllers defined (<a href="http://www.nortonmusic.com/midi_cc.html" target="_blank">here's a complete list</a>). Some synthesizers, and especially software-based synthesizers, allow you to route any continuous controller to any synthesizer parameter. When we get to the post about designing synth patches for wind control, we'll see how powerful this capability is.<br />
<br />
<h3>
Mapping Breath to Note On Velocity</h3>
<br />
Here's a sketch that will allow you to play MIDI patches that respond to note on velocity. Most piano, drum, and guitar patches will probably respond to note on velocity information.<br />
<br />
The basic approach is to take the reading from the breath sensor at the time the note begins, and map that to a value in the range 0 to 127 (the minimum and maximum allowable MIDI note on velocity values), and send that with the note on event. We can use the Arduino map() method to do that math, like we did in our continuous controller sketch.<br />
<br />
The only slightly tricky thing is that, when the breath starts, it takes a few milliseconds to build to its final value, so if we use the first value we read, it won't be as "loud" as the player intended. To get around that, we actually wait a little while after we see the breath go above the note on threshold value, and then re-sample the pressure sensor. The second sample is the one we map to the velocity.<br />
<br />
The other concept in this sketch that you may not be familiar with it the use of a very simple <a href="http://en.wikipedia.org/wiki/Finite-state_machine" target="_blank">finite state machine</a>. While it may sound complicated, it's actually pretty simple. At any time, the sketch is in one of three states:<br />
<br />
<ul>
<li>Note Off State - no note is sounding</li>
<li>Rise Time State - the performer has started to blow into the sensor, and we're waiting a bit for the pressure to rise to its final value</li>
<li>Note On State -<span style="font-family: Times,"Times New Roman",serif;"> a note is soundin</span>g </li>
</ul>
For each state in a finite state machine, you also have to know what actions will move you from that state to some other state. One way to do that is via a table:<br />
<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;">Current State Input Next State</span><br />
<span style="font-family: "Courier New", Courier, monospace;">====================================================== </span><br />
<span style="font-family: "Courier New", Courier, monospace;">NOTE_OFF Breath value goes above RISE_TIME</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> NOTE_ON_THRESHOLD </span><br />
<br />
<span style="font-family: "Courier New", Courier, monospace;">RISE_TIME RISE_TIME milliseconds NOTE_ON</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> have elapsed</span><br />
<br />
<span style="font-family: "Courier New", Courier, monospace;">RISE_TIME </span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;">Breath value goes below NOTE_OFF</span></span><br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;"> NOTE_ON_THRESHOLD </span></span><br />
<br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;">NOTE_ON </span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;">Breath value goes below NOTE_OFF</span></span><span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;"> </span></span></span></span><br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;"> NOTE_ON_THRESHOLD</span></span></span></span><br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: "Courier New", Courier, monospace;"> </span></span> </span></span><br />
<br />
<span style="font-family: Times,"Times New Roman",serif;"><span style="font-family: Georgia,"Times New Roman",serif;"><span style="font-size: small;">Another way to visualize a state machine is with a state graph. The states are shown as ovals, and the transitions between states are the edges (curved arrows) in the graph. Note that two of the states have transitions that point to themselves (I didn't include those in the table above). That's perfectly ok and shows that some inputs might not cause a transition out of the current state. Click the diagram to see a larger version if it's hard to read.</span></span></span><br />
<span style="font-family: Times,"Times New Roman",serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-d91bM-hWOGw/UP2GSYYoU6I/AAAAAAAABgM/LwS3t-hCytw/s1600/FSM.tif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="494" src="http://4.bp.blogspot.com/-d91bM-hWOGw/UP2GSYYoU6I/AAAAAAAABgM/LwS3t-hCytw/s640/FSM.tif" width="640" /></a></div>
<span style="font-family: Times,"Times New Roman",serif;"><br /></span>
<br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: Times,"Times New Roman",serif;"><span style="font-family: "Courier New", Courier, monospace;">H</span>ere's the sketch: </span> </span><br />
<br />
<pre>#define MIDI_CHANNEL 1
<span style="color: #7e7e7e;">// The threshold level for sending a note on event. If the</span>
<span style="color: #7e7e7e;">// sensor is producing a level above this, we should be sounding</span>
<span style="color: #7e7e7e;">// a note.</span>
#define NOTE_ON_THRESHOLD 80
<span style="color: #7e7e7e;">// The maximum raw pressure value you can generate by</span>
<span style="color: #7e7e7e;">// blowing into the tube.</span>
#define MAX_PRESSURE 500
<span style="color: #7e7e7e;">// The three states of our state machine</span>
<span style="color: #7e7e7e;">// No note is sounding</span>
#define NOTE_OFF 1
<span style="color: #7e7e7e;">// We've observed a transition from below to above the</span>
<span style="color: #7e7e7e;">// threshold value. We wait a while to see how fast the</span>
<span style="color: #7e7e7e;">// breath velocity is increasing</span>
#define RISE_TIME 10
<span style="color: #7e7e7e;">// A note is sounding</span>
#define NOTE_ON 3
<span style="color: #7e7e7e;">// The five notes, from which we choose one at random</span>
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">int</span> notes[5] = {60, 62, 65, 67, 69};
<span style="color: #7e7e7e;">// We keep track of which note is sounding, so we know</span>
<span style="color: #7e7e7e;">// which note to turn off when breath stops.</span>
<span style="color: #cc6600;">int</span> noteSounding;
<span style="color: #7e7e7e;">// The value read from the sensor</span>
<span style="color: #cc6600;">int</span> sensorValue;
<span style="color: #7e7e7e;">// The state of our state machine</span>
<span style="color: #cc6600;">int</span> state;
<span style="color: #7e7e7e;">// The time that we noticed the breath off -> on transition</span>
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> breath_on_time = 0L;
<span style="color: #7e7e7e;">// The breath value at the time we observed the transition</span>
<span style="color: #cc6600;">int</span> initial_breath_value;
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>setup</b></span>() {
state = NOTE_OFF; <span style="color: #7e7e7e;">// initialize state machine</span>
}
<span style="color: #cc6600;">int</span> get_note() {
<span style="color: #cc6600;">return</span> notes[<span style="color: #cc6600;">random</span>(0,4)];
}
<span style="color: #cc6600;">int</span> get_velocity(<span style="color: #cc6600;">int</span> initial, <span style="color: #cc6600;">int</span> final, <span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> time_delta) {
<span style="color: #cc6600;">return</span> <span style="color: #cc6600;">map</span>(final, NOTE_ON_THRESHOLD, MAX_PRESSURE, 0, 127);
}
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>loop</b></span>() {
<span style="color: #7e7e7e;">// read the input on analog pin 0</span>
sensorValue = <span style="color: #cc6600;">analogRead</span>(A0);
<span style="color: #cc6600;">if</span> (state == NOTE_OFF) {
<span style="color: #cc6600;">if</span> (sensorValue > NOTE_ON_THRESHOLD) {
<span style="color: #7e7e7e;">// Value has risen above threshold. Move to the RISE_TIME</span>
<span style="color: #7e7e7e;">// state. Record time and initial breath value.</span>
breath_on_time = <span style="color: #cc6600;">millis</span>();
initial_breath_value = sensorValue;
state = RISE_TIME; <span style="color: #7e7e7e;">// Go to next state</span>
}
} <span style="color: #cc6600;">else</span> <span style="color: #cc6600;">if</span> (state == RISE_TIME) {
<span style="color: #cc6600;">if</span> (sensorValue > NOTE_ON_THRESHOLD) {
<span style="color: #7e7e7e;">// Has enough time passed for us to collect our second</span>
<span style="color: #7e7e7e;">// sample?</span>
<span style="color: #cc6600;">if</span> (<span style="color: #cc6600;">millis</span>() - breath_on_time > RISE_TIME) {
<span style="color: #7e7e7e;">// Yes, so calculate MIDI note and velocity, then send a note on event</span>
noteSounding = get_note();
<span style="color: #cc6600;">int</span> velocity = get_velocity(initial_breath_value, sensorValue, RISE_TIME);
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOn</span>(noteSounding, velocity, MIDI_CHANNEL);
state = NOTE_ON;
}
} <span style="color: #cc6600;">else</span> {
<span style="color: #7e7e7e;">// Value fell below threshold before RISE_TIME passed. Return to</span>
<span style="color: #7e7e7e;">// NOTE_OFF state (e.g. we're ignoring a short blip of breath)</span>
state = NOTE_OFF;
}
} <span style="color: #cc6600;">else</span> <span style="color: #cc6600;">if</span> (state == NOTE_ON) {
<span style="color: #cc6600;">if</span> (sensorValue < NOTE_ON_THRESHOLD) {
<span style="color: #7e7e7e;">// Value has fallen below threshold - turn the note off</span>
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOff</span>(noteSounding, 100, MIDI_CHANNEL);
state = NOTE_OFF;
}
}
}
</pre>
<br />
<br />
<br />
Here's how it sounds. I play four notes quietly, four notes loud, four more notes quietly, and then do four notes of increasing volume (a crescendo, in musical terms), and eight notes of decreasing volume (a diminuendo). The sketch is randomly picking which notes to play, but the attack velocity of each note is under my control.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-W9THpU5eu5g/UP1_0tty6QI/AAAAAAAABf8/ZA2XxqyYdIE/s1600/score.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="78" src="http://2.bp.blogspot.com/-W9THpU5eu5g/UP1_0tty6QI/AAAAAAAABf8/ZA2XxqyYdIE/s640/score.tiff" width="640" /></a></div>
<br />
<iframe frameborder="no" height="166" scrolling="no" src="http://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F75852887&auto_play=false&show_artwork=false&color=ff1500" width="100%"></iframe>
<br />
<br />
Looking at the MIDI data, it looks like the values are ranging from a low of about 4 to a maximum of about 100, so I could alter the MAX_PRESSURE value in the sketch to fix that. But you get the idea.<br />
<br />
Here's another rhythmic motif in 9/8 that I played on a different wind controller, a Yamaha WX-7, that also maps breath to note on velocity. Because of this mapping, I'm able to accent the 1st, 4th, 6th, and 8th notes of each group of nine, resulting in a <a href="http://en.wikipedia.org/wiki/Music_of_Battlestar_Galactica_%28reimagining%29#Number_Six.27s_theme" target="_blank">3 + 2 + 2 + 2 pattern</a>.<br />
<br />
<iframe frameborder="no" height="166" scrolling="no" src="http://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F75940127&auto_play=false&show_artwork=false&color=ff1500" width="100%"></iframe>
<br />
In part two, I'll add MIDI aftertouch to this sketch.<br />
<br />
<br />
<br />
<br />Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com5tag:blogger.com,1999:blog-2671439418188048550.post-7647484575082820142013-01-18T23:32:00.000-08:002013-01-19T23:08:40.334-08:00Breath and Note On/Off TransitionsIf we're going to build a MIDI wind instrument controller, it's going to need to send MIDI note on and off messages - it's just part of the MIDI spec. But the tricky part is knowing when your breath is producing enough pressure to justify sending the MIDI note on message.<br />
<br />
An approach that makes sense for our project is to choose some value a little above the "idle" value that the pressure sensor reads (that is, when you're not blowing into it). My sensor produces values of about 65 when I'm not blowing into it, and a threshold value of 100 seems to work well. In the Arduino sketches in this post, you may need to change the threshold value to something appropriate for the way your air tubing is set up, as well as your playing style. To adjust that threshold, look for the line:<br />
<br />
<pre>#define NOTE_ON_THRESHOLD 100
</pre>
<br />
And experiment with different values until you find something that works. Don't forget to recompile and upload the sketch after you make changes.<br />
<br />
<h2>
One Note </h2>
<br />
The following sketch reads the pressure sensor and sends a MIDI Note On event for middle C (the C about in the middle of the piano keyboard) when it detects that the pressure is above the threshold value. It sends a MIDI Note Off event when the pressure is below the threshold value. It also keeps track of whether a note is sounding or not, so it knows if a Note On/Off message needs to be sent (if the note is already on, we don't need, or want, to send another Note On message).<br />
<br />
<pre>#define MIDI_CHANNEL 1
<span style="color: #7e7e7e;">// For this sketch, we only can play one note</span>
#define MIDI_NOTE 60 <span style="color: #7e7e7e;">// Middle C (C4)</span>
<span style="color: #7e7e7e;">// The threshold level for sending a note on event. If the</span>
<span style="color: #7e7e7e;">// sensor is producing a level above this, we are in note on</span>
<span style="color: #7e7e7e;">// state, otherwise note off</span>
#define NOTE_ON_THRESHOLD 100
<span style="color: #7e7e7e;">// We keep track of whether a note is sounding or not,</span>
<span style="color: #7e7e7e;">// so we know whether to send a note on or off event.</span>
<span style="color: #cc6600;">boolean</span> noteSounding = <span style="color: #cc6600;">false</span>;
<span style="color: #7e7e7e;">// The value read from the sensor</span>
<span style="color: #cc6600;">int</span> sensorValue;
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>setup</b></span>() {
<span style="color: #7e7e7e;">// Nothing to initialize for this sketch</span>
}
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>loop</b></span>() {
<span style="color: #7e7e7e;">// read the input on analog pin 0</span>
sensorValue = <span style="color: #cc6600;">analogRead</span>(A0);
<span style="color: #7e7e7e;">// Send the appropriate MIDI note on or off message</span>
<span style="color: #cc6600;">if</span> (sensorValue > NOTE_ON_THRESHOLD) {
<span style="color: #cc6600;">if</span> (noteSounding) {
<span style="color: #7e7e7e;">// Nothing to do - note is already on</span>
} <span style="color: #cc6600;">else</span> {
<span style="color: #7e7e7e;">// Value has risen above threshold - turn the note on</span>
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOn</span>(MIDI_NOTE, 100, MIDI_CHANNEL);
noteSounding = <span style="color: #cc6600;">true</span>;
}
} <span style="color: #cc6600;">else</span> {
<span style="color: #cc6600;">if</span> (noteSounding) {
<span style="color: #7e7e7e;">// Value has fallen below threshold - turn the note off</span>
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOff</span>(MIDI_NOTE, 100, MIDI_CHANNEL);
noteSounding = <span style="color: #cc6600;">false</span>;
} <span style="color: #cc6600;">else</span> {
<span style="color: #7e7e7e;">// Nothing to do - note is already off</span>
}
}
<span style="color: #7e7e7e;">// Delay a bit to avoid glitches (very short notes that</span>
<span style="color: #7e7e7e;">// sound because the breath falls below the threshold</span>
<span style="color: #7e7e7e;">// value, then goes back above it). Adding 20</span>
<span style="color: #7e7e7e;">// milleseconds of delay reduces the responsiveness</span>
<span style="color: #7e7e7e;">// of the instrument, and we'll discuss better ways</span>
<span style="color: #7e7e7e;">// of handling this in later posts. For now, this is</span>
<span style="color: #7e7e7e;">// good enough.</span>
<span style="color: #cc6600;">delay</span>(20);
}
</pre>
Here's how the sketch sounds when playing the Grand Piano patch from GarageBand.<br />
<br />
Four long notes:<br />
<br />
<iframe frameborder="no" height="166" scrolling="no" src="http://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F75273892&auto_play=false&show_artwork=false&color=ff1500" width="100%"></iframe>
A synth pad, long notes:<br />
<br />
<iframe frameborder="no" height="166" scrolling="no" src="http://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F75274432&auto_play=false&show_artwork=false&color=ff1500" width="100%"></iframe>
And to test the responsiveness, here I'm playing faster and faster notes (using a technique called <a href="http://en.wikipedia.org/wiki/Tonguing" target="_blank">double-tonguing</a> and then <a href="http://en.wikipedia.org/wiki/Flutter-tonguing" target="_blank">flutter-tonguing</a>). It keeps up pretty well:<br />
<br />
<iframe frameborder="no" height="166" scrolling="no" src="http://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F75276559&auto_play=false&show_artwork=false&color=ff1500" width="100%"></iframe>
<br />
Ok, great. We can send MIDI Note On/Off messages. But this is pretty boring, only playing one note. We'll be talking about how to select notes based on fingerings in later posts, but let's at least make our sketch choose a couple of different notes at random.<br />
<br />
Here's a modification to the previous sketch. Instead of always sending a middle C for the note, whenever a Note On event is to be sent, it randomly chooses one of 5 notes from a <a href="http://en.wikipedia.org/wiki/Pentatonic_scale" target="_blank">pentatonic scale</a> by using <a href="http://arduino.cc/en/Reference/random" target="_blank">the random() method from the Arduino library</a>. Look at the get_note() method - that's where we pick the random note to play. The Arduino library's random() method picks a number from 0 through 4 for us, and we use that to select one of the MIDI notes 60 (middle C), 62 (D), 65 (F), 67 (G), or 69 (A).<br />
<br />
<pre>#define MIDI_CHANNEL 1
<span style="color: #7e7e7e;">// The threshold level for sending a note on event. If the</span>
<span style="color: #7e7e7e;">// sensor is producing a level above this, we are in note on</span>
<span style="color: #7e7e7e;">// state, otherwise note off</span>
#define NOTE_ON_THRESHOLD 80
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">int</span> notes[5] = {60, 62, 65, 67, 69};
<span style="color: #7e7e7e;">// We keep track of which note is sounding. The value</span>
<span style="color: #7e7e7e;">// -1 means no note is sounding.</span>
<span style="color: #cc6600;">int</span> noteSounding = -1;
<span style="color: #7e7e7e;">// The value read from the sensor</span>
<span style="color: #cc6600;">int</span> sensorValue;
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>setup</b></span>() {
<span style="color: #7e7e7e;">// Nothing to initialize for this sketch</span>
}
<span style="color: #cc6600;">int</span> get_note() {
<span style="color: #cc6600;">return</span> notes[<span style="color: #cc6600;">random</span>(0,4)];
}
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>loop</b></span>() {
<span style="color: #7e7e7e;">// read the input on analog pin 0</span>
sensorValue = <span style="color: #cc6600;">analogRead</span>(A0);
<span style="color: #7e7e7e;">// Send the appropriate MIDI note on or off message</span>
<span style="color: #cc6600;">if</span> (sensorValue > NOTE_ON_THRESHOLD) {
<span style="color: #cc6600;">if</span> (noteSounding != -1) {
<span style="color: #7e7e7e;">// Nothing to do - note is already on</span>
} <span style="color: #cc6600;">else</span> {
<span style="color: #7e7e7e;">// Value has risen above threshold - turn the note on</span>
noteSounding = get_note();
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOn</span>(noteSounding, 100, MIDI_CHANNEL);
}
} <span style="color: #cc6600;">else</span> {
<span style="color: #cc6600;">if</span> (noteSounding != -1) {
<span style="color: #7e7e7e;">// Value has fallen below threshold - turn the note off</span>
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendNoteOff</span>(noteSounding, 100, MIDI_CHANNEL);
noteSounding = -1;
} <span style="color: #cc6600;">else</span> {
<span style="color: #7e7e7e;">// Nothing to do - note is already off</span>
}
}
<span style="color: #7e7e7e;">// Delay a bit to avoid glitches (very short notes that</span>
<span style="color: #7e7e7e;">// sound because the breath falls below the threshold</span>
<span style="color: #7e7e7e;">// value, then goes back above it). Adding 20</span>
<span style="color: #7e7e7e;">// milleseconds of delay reduces the responsiveness</span>
<span style="color: #7e7e7e;">// of the instrument, and we'll discuss better ways</span>
<span style="color: #7e7e7e;">// of handling this in later posts. For now, this is</span>
<span style="color: #7e7e7e;">// good enough.</span>
<span style="color: #cc6600;">delay</span>(20);
}
</pre>
<br />
Here's how it sounds. I'm playing a <a href="http://en.wikipedia.org/wiki/Syncopation" target="_blank">syncopated</a> rhythm, using the GarageBand Grand Piano patch. Notice how the note pitches change randomly:<br />
<br />
<iframe frameborder="no" height="166" scrolling="no" src="http://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F75546543&auto_play=false&show_artwork=false&color=ff1500" width="100%"></iframe>
Here I'm playing the new sketch and using the "Kotu Chords" patch from GarageBand's Synth Textures collection, but playing the same rhythm. This patch <a href="http://en.wikipedia.org/wiki/Harmonization" target="_blank">harmonizes</a> the input notes, so even though the get_note() method only produces one randomly selected note, once I feed that note into the synthesizer, I get about 4 notes out.<br />
<br />
<iframe frameborder="no" height="166" scrolling="no" src="http://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F75545119&auto_play=false&show_artwork=false&color=ff1500" width="100%"></iframe> <br />
A cool aspect of this sketch is that, since we're using the random() method from the Arduino library to choose which note to play, two performances of the same piece on this instrument are likely to be very different. And by combining our pretty simple breath based controller with some interesting patches from GarageBand, we're able to make some interesting sounds. Try playing around with different patches in GarageBand, or if you're using a different audio environment and/or OS, experiment with what you have. Upload your creations and share links to them here.<br />
<br />
<h2>
Next</h2>
While these sketches can produce some interesting sounds, they are pretty much devoid of expression. All the notes are exactly the same volume, and we have no control over how the note evolves over time. In my next post, I'll talk about how to create an instrument that is much more responsive to the nuances of breath control.Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com2tag:blogger.com,1999:blog-2671439418188048550.post-7028633990646376662013-01-15T20:28:00.002-08:002016-02-25T21:57:38.797-08:00Building a Breath Controller<br />
In this project, I'll build on <a href="http://gordophone.blogspot.com/2013/01/breath-sensing-101.html" target="_blank">my previous post </a>on reading breath pressure into an Arduino or Arduino clone. We'll use the same circuit from that post, and write some new code that maps the sensor values we read to a MIDI continuous controller (which I'll refer to as a CC from here on out). That CC data will, in turn, control a parameter of a software synthesizer.<br />
<br />
<h2>
What's a MIDI CC?</h2>
<br />
MIDI continuous controllers are a standard way for performers to modify the sound produced by the synthesizers they are playing. The "continuous" part of the name means that the values sent on the MIDI bus control some parameter with a range. If you've played a MIDI keyboard that has a modulation wheel:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://dt7v1i9vyp3mf.cloudfront.net/styles/news_large/s3/imagelibrary/S/Strings3_12.jpg?itok=XiggPQvP" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://dt7v1i9vyp3mf.cloudfront.net/styles/news_large/s3/imagelibrary/S/Strings3_12.jpg?itok=XiggPQvP" height="213" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<br />
you know that the more you turn the "mod wheel", the more vibrato you hear, at least with most common synth patches. In the following example, I play a chord, and turn the modulation wheel from zero to full on, then back to zero.<br />
<br />
<iframe frameborder="no" height="166" scrolling="no" src="http://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F74987099&auto_play=false&show_artwork=false&color=ff1500" width="100%"></iframe>
If you dig into the MIDI spec, you'll discover that the mod wheel is only one of many continuous controllers defined. Each one has a unique number assigned to it, and some have a name, like "Modulation Wheel" or "Pan". The controller name describes what type of control is typically going to generate that data. On a traditional MIDI keyboard, if you move the mod wheel, you'll generate Continuous Controller 1 data. <br />
<br />
If you think about it, there are many real-life things that naturally can be expressed as a continuous controller: How far you have twisted a knob. How far to the left or right your are tilting your hand. How far apart your hands are. Or how hard you are blowing air. All of these things can be mapped to some number that ranges from some minimum value to some maximum value (provided you can measure them and translate them to MIDI). <br />
<br />
The MIDI spec states that continuous controller values vary from a minimum value of zero to a maximum value of 127. This means CC values have 7 bit resolution, which, for some applications, is not acceptable - the results sound odd. I'll talk about those later, but for many of the common synthesizer parameters that are controller by CCs, 7 bits is fine.<br />
<br />
<h2>
</h2>
<h2>
How the Pressure Sensor Works</h2>
<br />
Before we get into wiring up and coding the project, let's dive into how the Freescale pressure sensor works. It relies on something called the <a href="http://en.wikipedia.org/wiki/Piezoresistive_effect" target="_blank">Piezoresistive Effect</a>.<br />
<br />
There are some materials that exhibit the property that, as you press on them, the resistance through the material changes. The Freescale sensor has a small piece of this type of material inside, and when the pressure inside the case of the sensor increases, the resistance through this material changes. The sensor also has circuitry to amplify the signal and make it work consistently even if the temperature varies.<br />
<br />
Advances in chip fabrication techniques have allowed manufacturers to make these type of sensors in very small packages. By contrast, the Yamaha WX-7, a 1980s-era wind instrument controller, has a breath sensor that is much larger than the Freescale sensor used in this project. Although I don't know how the WX-7's pressure sensor works, I suspect it's based on the same principle.<br />
<br />
<h2>
Mapping Sensor Values</h2>
We'll now build on the circuit in my previous post and generate MIDI continuous controller data based on how hard a performer is blowing into the breath sensor. <br />
<br />
Remember that our Arduino's analog inputs convert the values they read into a value that varies between 0 and 1023. But the MIDI spec wants you to provide values between 0 and 127. What to do?<br />
<br />
Well, the math is pretty simple. Just divide the value read from the input by 1024, and multiply it by 128. But the arduino library has <a href="http://arduino.cc/en/Reference/map" target="_blank">a nice convenience function named map()</a> that does exactly this. For example:<br />
<br />
<pre> <span style="color: #cc6600;">int</span> sensorValue1 = <span style="color: #cc6600;">analogRead</span>(A0);
<span style="color: #cc6600;">int</span> ccVal = <span style="color: #cc6600;">map</span>(sensorValue1, 0, 1023, 0, 127);
</pre>
The code snippet above will linearly map values in the range 0-1023 to values in the range 0-127.<br />
<br />
<h2>
Generating MIDI CC Values</h2>
The PJRC USB MIDI support makes sending MIDI data over USB just ridiculously simple. From the <a href="http://www.pjrc.com/teensy/td_midi.html" target="_blank">PJRC USB MIDI reference</a>:<br />
<br />
<pre><span style="color: #cc6600;">usbMIDI</span>.<span style="color: #cc6600;">sendControlChange</span>(control, value, channel)</pre>
<br />
Where "control" is the MIDI controller to change, "value" is the mapped sensor value, and "channel" is the MIDI channel on which to send the data. Although we haven't talked about MIDI channels yet, for these exercises we'll send the data on MIDI channel 1 and then make sure that our MIDI synthesizers are either set up to listen on channel 1 or are set to "omni" mode, in which they respond to MIDI data on any MIDI channel.<br />
<br />
<h2>
Our First, and Imperfect, Sketch</h2>
<pre>#define MOD_WHEEL_CONTROLLER 1
#define MIDI_CHANNEL 1
<span style="color: #7e7e7e;">// The value read from the sensor</span>
<span style="color: #cc6600;">int</span> sensorValue;
<span style="color: #7e7e7e;">// The CC value we will send</span>
<span style="color: #cc6600;">int</span> ccVal;
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>setup</b></span>() {
<span style="color: #7e7e7e;">// Nothing to initialize for this sketch</span>
}
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>loop</b></span>() {
<span style="color: #7e7e7e;">// read the input on analog pin 0</span>
sensorValue = <span style="color: #cc6600;">analogRead</span>(A0);
<span style="color: #7e7e7e;">// Map the value, which may range from 0 to 1023,</span>
<span style="color: #7e7e7e;">// to a value in the range 0 to 127, which is</span>
<span style="color: #7e7e7e;">// the valid range for a MIDI continuous controller</span>
ccVal = <span style="color: #cc6600;">map</span>(sensorValue, 0, 1023, 0, 127);
<span style="color: #7e7e7e;">// And send the value as a MIDI CC message</span>
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendControlChange</span>(MOD_WHEEL_CONTROLLER, ccVal, MIDI_CHANNEL);
}
</pre>
To load this sketch, first go to the "Tools" menu and choose "USB Type" and select "MIDI". Then click on the upload button.<br />
<br />
Once you've loaded the sketch, you'll need to load a software synthesizer host on your Mac/PC/Linux box. While I can't cover every possibility in this post, I'll cover the basic steps for running Garage Band on a Mac and getting mod wheel output from our circuit. <br />
<br />
<ol>
<li>Start Garage Band.</li>
<li>If a project opens automatically, choose Close from the File menu and choose New Project...</li>
<li>Select the Keyboard Collection template and give the project a name in the dialog that appears.</li>
<li> In the list of instruments that appears, click on Solo Star - it's an interesting-sounding synth that responds to mod wheel input.</li>
<li>Select Musical Typing from the Window menu. A window appears where you can click on a virtual MIDI keyboard.</li>
<li>If your Teensy controller isn't plugged in, plug it in now. When you plug in a MIDI-USB device, GarageBand should pop up a window informing you that the number of MIDI inputs has changed.</li>
<li>Click and hold down the mouse button on a note in the Musical Typing window. In the sound sample below, I clicked and held the "F" key.</li>
<li>You should be hearing a synthesizer playing a note now. Keep holding the mouse button and blow into the tube connected to your pressure sensor. Start blowing gently, blow harder and harder, then gradually blow less and less.</li>
<li>You should hear something about like this</li>
</ol>
<br />
<iframe frameborder="no" height="166" scrolling="no" src="http://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F74998322&auto_play=false&show_artwork=false&color=ff1500" width="100%"></iframe>And if you double-click the segment you just recorded, and select "Modulation" from the "View" menu, you can see a graph of the values the Teensy sent.<br />
<br />
Pretty cool, huh? Actually, no, there are two serious problems with my sketch.<br />
<br />
<h2>
Shut Up, Already!</h2>
Notice that we send a MIDI CC value every time the the loop() method is called. This means that you're spamming the MIDI instruments as fast as your microcontroller can make it through its loop() method. This is not good because (a) the MIDI bus has a finite bandwidth, and (b) you can overload software synthesizers with this data, as they try to adjust internal parameters in real time.<br />
<br />
There are two approaches I can think of to address this problem:<br />
<ol>
<li>Only send a new CC value if a certain amount of time has passed, e.g. 20 milliseconds, or</li>
<li>Only send a new CC value if the new value is different from the previously sent value to be interesting to the synthesizer.</li>
</ol>
The first method is really easy to implement. Here's a sketch that will only send CC values every 20 milliseconds.<br />
<br />
<pre>#define MOD_WHEEL_CONTROLLER 1
#define MIDI_CHANNEL 1
<span style="color: #7e7e7e;">// Send continuous controller message no more than</span>
<span style="color: #7e7e7e;">// every CC_INTERVAL milliseconds</span>
#define CC_INTERVAL 20
<span style="color: #7e7e7e;">// The last time we sent a CC value</span>
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> ccSendTime = 0L;
<span style="color: #7e7e7e;">// The value read from the sensor</span>
<span style="color: #cc6600;">int</span> sensorValue;
<span style="color: #7e7e7e;">// The CC value we will send</span>
<span style="color: #cc6600;">int</span> ccVal;
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>setup</b></span>() {
<span style="color: #7e7e7e;">// Nothing to initialize for this sketch</span>
}
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>loop</b></span>() {
<span style="color: #7e7e7e;">// read the input on analog pin 0</span>
sensorValue = <span style="color: #cc6600;">analogRead</span>(A0);
<span style="color: #7e7e7e;">// Map the value, which may range from 0 to 1023,</span>
<span style="color: #7e7e7e;">// to a value in the range 0 to 127, which is</span>
<span style="color: #7e7e7e;">// the valid range for a MIDI continuous controller</span>
ccVal = <span style="color: #cc6600;">map</span>(sensorValue, 0, 1023, 0, 127);
<span style="color: #7e7e7e;">// And send the value as a MIDI CC message</span>
<span style="color: #cc6600;">if</span> (<span style="color: #cc6600;">millis</span>() - ccSendTime > CC_INTERVAL) {
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendControlChange</span>(MOD_WHEEL_CONTROLLER, ccVal, MIDI_CHANNEL);
ccSendTime = <span style="color: #cc6600;">millis</span>();
}
}
</pre>
<h2>
Don't Send Useless Data</h2>
The other problem is that, even when you aren't blowing into the tube, it's sending data to the MIDI instruments. If no air is going through the tube, then why send any data at all?<br />
<br />
This is pretty easy to fix. Recall that, even when no air was being blown through the tube, it produced a voltage that the analog-to-digital converter on the Arduino interpreted as about 64. So, if the value we read from the input port is less than about 70, let's just not send anything at all. Problem solved.<br />
<br />
One subtle issue is that when the pressure falls below the threshold value, we need to send a zero value. Otherwise, when you stop blowing, the controller would remain at the last value we sent, rather than zero. We handle this in the last else clause.<br />
<br />
<pre>#define MOD_WHEEL_CONTROLLER 1
#define MIDI_CHANNEL 1
<span style="color: #7e7e7e;">// Send continuous controller message no more than</span>
<span style="color: #7e7e7e;">// every CC_INTERVAL milliseconds</span>
#define CC_INTERVAL 20
<span style="color: #7e7e7e;">// Only send CC data if the pressure sensor reading</span>
<span style="color: #7e7e7e;">// a value larger than this.</span>
#define BREATH_THRESHOLD 70
<span style="color: #7e7e7e;">// The last time we sent a CC value</span>
<span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> ccSendTime = 0L;
<span style="color: #7e7e7e;">// The value read from the sensor</span>
<span style="color: #cc6600;">int</span> sensorValue;
<span style="color: #7e7e7e;">// The CC value we will send</span>
<span style="color: #cc6600;">int</span> ccVal;
<span style="color: #7e7e7e;">// The last CC value we sent</span>
<span style="color: #cc6600;">int</span> lastCcVal = 0;
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>setup</b></span>() {
<span style="color: #7e7e7e;">// Nothing to initialize for this sketch</span>
}
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>loop</b></span>() {
<span style="color: #7e7e7e;">// Only read the sensor if enough time has passed</span>
<span style="color: #cc6600;">if</span> (<span style="color: #cc6600;">millis</span>() - ccSendTime > CC_INTERVAL) {
<span style="color: #7e7e7e;">// read the input on analog pin 0</span>
sensorValue = <span style="color: #cc6600;">analogRead</span>(A0);
<span style="color: #cc6600;">if</span> (sensorValue > BREATH_THRESHOLD) {
<span style="color: #7e7e7e;">// Map the value, which may range from BREATH_THRESHOLD</span>
<span style="color: #7e7e7e;">// to 1023, to a value in the range 0 to 127, which is</span>
<span style="color: #7e7e7e;">// the valid range for a MIDI continuous controller</span>
ccVal = lastCcVal = <span style="color: #cc6600;">map</span>(sensorValue, BREATH_THRESHOLD, 1023, 0, 127);
<span style="color: #7e7e7e;">// And send the value as a MIDI CC message</span>
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendControlChange</span>(MOD_WHEEL_CONTROLLER, ccVal, MIDI_CHANNEL);
ccSendTime = <span style="color: #cc6600;">millis</span>();
}
<span style="color: #cc6600;">else</span> <span style="color: #cc6600;">if</span> (lastCcVal > 0) {
<span style="color: #7e7e7e;">// The pressure has just dropped below the threshold, so</span>
<span style="color: #7e7e7e;">// send a CC value of zero</span>
<span style="color: #cc6600;"><b>usbMIDI</b></span>.<span style="color: #cc6600;">sendControlChange</span>(MOD_WHEEL_CONTROLLER, 0, MIDI_CHANNEL);
ccSendTime = <span style="color: #cc6600;">millis</span>();
lastCcVal = 0;
}
}
}
</pre>
<br />
Another thing you can do with this code is convert it to a MIDI Breath Controller and do cool stuff like in this video:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /><iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/9pEAf9sMb8k/0.jpg" src="https://www.youtube.com/embed/9pEAf9sMb8k?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<br />
<br />
You can build that For about $36.<br />
<br />
<h2>
Next </h2>
<br />
In the next post, I'll show how to use the pressure sensor to manage MIDI Note On and Note Off events, which will allow us to articulate like a woodwind or brass player does.<br />
<br />
<br />
<br />
<br />Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com29tag:blogger.com,1999:blog-2671439418188048550.post-35080394419536571752013-01-13T11:24:00.004-08:002013-01-16T21:26:30.006-08:00Breath Sensing 101In this post, I'll discuss very basic breath sensing. We'll use a Freescale pressure sensor to detect how hard a player is blowing into a tube, and we'll print out the values being read. In later posts, I'll show how to convert those raw sensor values into MIDI continuous controller messages that we can use for expressive control of a MIDI synthesizer.<br />
<br />
What you'll need:<br />
<ul>
<li>A microcontroller. In my examples, I will use the <a href="http://www.pjrc.com/teensy/" target="_blank">Teensy 2.0 microcontroller from PJRC</a>. You can use any Arduino-compatible microcontroller for these examples, but once we start using MIDI, it will be a lot easier if you have the Teensy, as it has MIDI-over-USB support built in. This means that you can plug the Teensy into your computer's USB port and directly drive a software synthesizer. I have a Mac so I'll use Garage Band for the demos, but, you can use any instrument "host" that allows you to run Apple or VST instruments. Hosts are available for Macs, PCs, and Linux.<br />By the way, I recommend ordering the Teensy with pins pre-soldered, so that you can easily plug it into a breadboard while prototyping.</li>
<li>A USB cable for the microcontroller.</li>
<li>A <a href="http://www.freescale.com/files/sensors/doc/data_sheet/MPXV4006.pdf">Freescale MPXV4006GP</a> (pdf spec sheet). You can order one from Mouser Electronics (<a href="http://www.mouser.com/ProductDetail/Freescale-Semiconductor/MPXV4006GP/?qs=%2fha2pyFadujQ12PNU2Hbe1ZcDacrC%2fGsaykvyfNsgvpYcRBHeuFTxchvaor%2frlHo" target="_blank">direct link</a>). They are about $13.00 in single quantities.</li>
<li>A suitable breadboard and jumper kit for connecting the components together. <a href="http://www.makershed.com/" target="_blank">Maker Shed</a> is a great place to get things like this, and also has a bundle of a <a href="http://www.makershed.com/product_p/msbun21.htm" target="_blank">breadboard and a jumper kit</a>. For prototyping, I prefer <a href="http://www.makershed.com/product_p/mkseeed3.htm" target="_blank">flexible jumper wires</a>, which Maker Shed also has.</li>
<li>Some heat-shrink tubing, which we'll use to make an initial attachment to the pressure sensor. I would recommend getting an assortment of heat shrink tubing sizes either online or at Radio Shack - you'll use it a lot if you do any serious amount of hacking.</li>
<li>Some 1/4" drip irrigation tubing - a few feet will do. This should be available at any hardware store or garden supply center. We'll slip this tubing over the heat shrink attached to the sensor, and the inside diameter of the irrigation tubing is close enough to the outside diameter of the heat shrink that it makes a decent seal, even without gluing it.</li>
<li>A few pushbutton switches for use in later projects where we'll be simulating woodwind keys and trumpet valves. I like the <a href="https://www.sparkfun.com/products/10302" target="_blank">tactile button assortment </a>available from SparkFun, but any momentary pushbutton switch that can plug directly into the breadboard will work. If you get a "Getting Started with Arduino" kit, available from a number of places, it will probably include something suitable.</li>
<li>Some <a href="https://www.sparkfun.com/products/10527" target="_blank">solderless headers</a>, which we'll use to attach legs to the Freescale sensor. Since the sensor is a surface mount device, it won't directly plug into the breadboard. However, its pins use the same spacing as the holes in the breadboard, so soldering 4 pins on each side of the sensor will allow us to plug it in.</li>
<li>Soldering iron, solder, and some basic soldering skills.</li>
</ul>
Preparing the Pressure Sensor<br />
<br />
As I mentioned, the Freescale pressure sensor is a surface-mount device. Typically, a machine will place the part on a circuit board and use hot air to melt a solder paste that affixes the part directly to metallic pads on the board. This is cheaper to make/assemble than the older "through-hole" type of part, where legs on the part go through the circuit board and are soldered into the hole. It's getting harder and harder to find through-hole versions of components, so some companies like SparkFun provide "break-out" boards, which a small circuit board with the surface-mount component soldered to it, and standard-spaced holes which can be soldered to. For example, look at SparkFun's breakout board for the VS1033D MP3 chip. The chip has 50+ very tiny pins which would be extremely difficult to hand-solder (some people can do it - not me).<br />
<br />
Fortunately, the Freescale sensor we're using is much simpler. In fact, even though there are 8 pins on the device, only three are used (in this drawing, the active pins are the three on the right side - pins 2, 3, and 4.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.mouser.com/images/freescale/lrg/1369-01.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.mouser.com/images/freescale/lrg/1369-01.JPG" /> </a> </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />
What I did was use a <a href="http://www.makershed.com/product_p/mkhh1.htm" target="_blank">Helping Hands</a> to hold the sensor and a set of of the header pins against the sensor legs, after I flattened out the legs so they pointed straight down. I then soldered each of the 4 header pins to the sensor pin it was touching, and repeated it with the 4 pins on the other side. The result looks like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/_c_W4p2Ok5c0/S0WC1dBE0SI/AAAAAAAABPA/1rtmmTtcTEU/s400/L1010126.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="http://1.bp.blogspot.com/_c_W4p2Ok5c0/S0WC1dBE0SI/AAAAAAAABPA/1rtmmTtcTEU/s640/L1010126.JPG" width="640" /></a></div>
<br />
<br />
Try to work fast so you don't overheat the sensor electronics.<br />
<br />
In that photo you can also see how I attached some heat-shrink tubing (the red tube) to the input port of the sensor, and then slipped some irrigation tubing over that (the black tubing). Use a lighter to heat the heat shrink tubing where it mates with the sensor's input tube so it makes a tight seal.<br />
<br />
Now we're ready to hook things up on a breadboard (click to view a larger version):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-1Olv14gy5HI/UPMFKlHhOOI/AAAAAAAABe4/SLVQeNYCpu8/s1600/Pressure+Sensor+and+Teensy_bb.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="222" src="http://3.bp.blogspot.com/-1Olv14gy5HI/UPMFKlHhOOI/AAAAAAAABe4/SLVQeNYCpu8/s640/Pressure+Sensor+and+Teensy_bb.png" width="640" /></a></div>
This shows a Teensy 2.0, so if you're using some other microcontroller, hook up pin 4 of the sensor to Analog input zero.<br />
<br />
A schematic of this circuit is:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-1mRb9XbzTVI/UPMF59k7GrI/AAAAAAAABfI/zdHcs2_CyTg/s1600/Pressure+Sensor+and+Teensy_schem.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="496" src="http://3.bp.blogspot.com/-1mRb9XbzTVI/UPMF59k7GrI/AAAAAAAABfI/zdHcs2_CyTg/s640/Pressure+Sensor+and+Teensy_schem.png" width="640" /></a></div>
<br />
Once that's all wired up, attach the USB cable to the controller and hook it up to your PC. Start the Arduino development environment (if you're using a Teensy, you'll also want to install PJRC's <a href="http://www.pjrc.com/teensy/teensyduino.html" target="_blank">Teensyduino</a> add-on which makes it possible to use the Teensy just like any other Arduino device from within the dev enviroment. Here is a simple sketch that will just print out the values being read from the sensor:<br />
<pre><span style="color: #7e7e7e;">// the setup routine runs once when you press reset:</span>
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>setup</b></span>() {
<span style="color: #7e7e7e;">// initialize serial communication at 9600 bits per second:</span>
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">begin</span>(9600);
}
<span style="color: #7e7e7e;">// the loop routine runs over and over again forever:</span>
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><b>loop</b></span>() {
<span style="color: #7e7e7e;">// read the input on analog pin 0</span>
<span style="color: #cc6600;">int</span> sensorValue1 = <span style="color: #cc6600;">analogRead</span>(A0);
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">print</span>(sensorValue1);
<span style="color: #cc6600;"><b>Serial</b></span>.<span style="color: #cc6600;">println</span>();
<span style="color: #cc6600;">delay</span>(100); <span style="color: #7e7e7e;">// delay 100 milliseconds (1/10 of a second)</span>
}
</pre>
If using a Teensy, make sure the "USB Type" option in the "Tools" menu is set to "Serial". Choose the correct board type and serial port from the Tools menu, then upload the sketch to the board.<br />
<br />
To see the values being read, choose "Serial Monitor" from the "Tools" menu and set the baud rate to 9600. You should see a series of values being printed. Without blowing the tube, I see values of about 64, which probably corresponds to ambient air pressure. Blowing into the tube, you should be able to max out the sensor, meaning it will produce a reading of close to 1023 (the maximum value that the 10-bit analog-to-digital converter on the Arduino will produce).<br />
<br />
In the next post, I'll describe how to map these raw values to MIDI continuous controller data, and how to use that to control MIDI synthesizers.<br />
<br />Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com1tag:blogger.com,1999:blog-2671439418188048550.post-84749393803220465702013-01-13T11:24:00.003-08:002024-01-04T00:31:05.327-08:00A Series: Basics of DIY Wind ControllersOver the past few years I've spent some time thinking about and designing wind instrument controllers. I thought a good way to give something back would be to produce a series of blog posts describing what I've learned while tinkering with my projects.<br />
<br />
As it turns out, I'm not a very skilled craftsman, so most of my projects end up looking like something Homer Simpson would have created. But I think I've learned a few things about building the electronics and writing code. So, in this series of posts, I'm going to concentrate on sharing some basic building blocks and core concepts, like the following:<br />
<ul>
<li>Why electronic wind instruments are hard</li>
<li>Breath Sensing 101</li>
<li>Mapping analog readings to MIDI continuous controller values</li>
<li>MIDI note selection methods</li>
<li>Using sensors to alter performance data in real time</li>
<li>And more, as I think of them </li>
</ul>
<br />
Since I've been using Arduino and Teensy microcontrollers to do my experiments, I'm going to focus on those, so the code examples will target those platforms. <br />
<br />
If you are a performer who uses an EWI, EVI, or WX-series controller, there won't be a lot of practical advice for you here, but the circuits and code may help you understand what's going on inside your instrument. Also, the posts on building synth patches that work well with wind controllers will certainly be applicable to your live rigs. So, please - read on!<br />
<br />
So, onto post number one:<br />
<br />
<h2>
Why Electronic Wind Instruments are Hard</h2>
First of all, if you're not familiar with what an electronic wind instrument is, I'll define the term.<br />
<br />
<i>An electronic wind instrument is a musical instrument that employs electronics to produce the instrument's sound, and is articulated by blowing into the instrument.</i><br />
<br />
There are a number of commercially available electronic wind instruments. The most common instruments are the <a href="http://en.wikipedia.org/wiki/EWI" target="_blank">EWI</a> series from Akai, and the <a href="http://usa.yamaha.com/products/music-production/midi-controllers/wx5/" target="_blank">WX-5 from Yamaha</a>. Both are woodwind-style controllers - that is, they are fingered in a way that is easily learned by someone who knows how to play the saxophone, clarinet, or flute. The Akai instruments also support a mode that is more natural for trumpet players to use.<br />
<br />
The Akai instruments are the latest in a long line of wind controllers that started with Nyle Steiner's work in the 1970s. For more information on this history of the Steinerphone/EWI, see the <a href="http://www.patchmanmusic.com/NyleSteinerHomepage.html" target="_blank">Nyle Steiner home page</a>. For more links to learn about wind controllers, check out the <a href="http://www.patchmanmusic.com/WindControllerLinks.html" target="_blank">Wind Controller links page</a> from <a href="http://www.patchmanmusic.com/index.html" target="_blank">Patchman Music</a>. These two paragraphs don't come close to describing the history of wind controllers, but the links page on the Patchman site is an excellent resource to learn more.<br />
<br />
(Aside: Nyle Steiner also <a href="http://sparkbangbuzz.com/" target="_blank">invents lots of other crazy stuff</a>. And he's a <a href="http://km6i.blogspot.com/" target="_blank">ham like me</a>.) <br />
<br />
<h3>
ADSR</h3>
<br />
The majority of electronic instruments you can buy are really good at emulating instruments that can be modeled with the <a href="http://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope" target="_blank">ADSR model (Attack, Decay, Sustain, Release)</a>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://en.wikipedia.org/wiki/File:ADSR_parameter.svg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="174" src="http://upload.wikimedia.org/wikipedia/commons/e/ea/ADSR_parameter.svg" width="320" /></a></div>
<br />
This model describes how a sound evolves over time. For example, when you hit a key on a piano, there is an initial <span style="color: #274e13;">attack <i>A</i></span>, when the piano's hammer hits the string. After the initial strike of the hammer (the attack phase of ADSR), the string starts vibrating, and the vibration starts to lose energy. In most cases, the majority of the string's vibrational energy dissipates quickly (<span style="color: #e69138;">the D - decay phase</span>), but then the string continues to vibrate at a lower volume, fading out gradually (<span style="color: #3d85c6;">the S - sustain phase</span>). When the key is released, the piano's felt damper touches the string, stopping the vibrations (<span style="color: purple;">the R - release phase</span>). Most synthesizer patches have a fixed ADSR envelope, a "recipe" for the sound as it progresses through time. For a plucked or struck instrument, the performer has some control over the duration of these phases, and can also exert some control over the initial input, e.g. how hard the string is plucked or how hard the drum head is struck.<br />
<br />
ADSR works really well for modeling instruments that are plucked or
struck, which includes most of the staple instruments of popular music
like:<br />
<ul>
<li>Guitar</li>
<li>Bass</li>
<li>Drums</li>
<li>Piano and other keyboards</li>
</ul>
Wind instruments, on the other hand, don't follow this model at all. The sound is produced by a column of air emanating from the performer's lungs, which in turn causes something to vibrate - a single reed (clarinet/saxophone), two reeds (oboe/bassoon), lips (trumpet/horn/trombone/tuba), or the air column itself (flute/recorder). Articulation (the starting and stopping of sound) is generally accomplished by interrupting the stream of air using the tongue. The ADSR model simply doesn't reflect the way wind instruments work. It also doesn't model the way that bowed instruments like the violin make sound either.<br />
<br />
Due to the popularity of the instruments that ADSR models well, manufacturers of electronic musical instruments have generally not found other types of instruments to be commercially viable. Yamaha and Akai have a series of wind controllers that emulate woodwind instruments, and some smaller companies produce small quantities of instruments that emulate other types of instruments, including trumpets and violins, but for the most part, wind players have not been invited to the electronic music party until they learn to play a different instrument.<br />
<br />
For this reason, even if you have a wind instrument controller like one from Yamaha or Akai, you're faced with the difficult task of finding synthesizer patches that work well with your controller. If you *want* to sound like a Fender Rhodes electric piano, no problem, but if you want to make that Rhodes fade in from nothing, swell up, and fade out, sorry, you're out of luck. The ADSR envelope of the Rhodes patch you have models the characteristics of the real Fender instrument.<br />
<br />
I'll cover this topic in more detail in a later post, but the important thing to remember is that if you want to play your wind instrument controller in an idiomatic way, you're going to have to either go find some patches specifically designed for wind controllers, or build your own.<br />
<br />
I should also mention that my work has focused on building instruments that send MIDI data, but an equally valid approach is to build instruments that send raw sensor data to a device that makes the sound itself, rather than relying on a MIDI synthesizer to make the sound. The original Steiner EWI and Akai variants had a dedicated synthesizer that directly read the instrument's sensors. Another option is to feed all the sensor outputs to a computer. The computer, in turn, uses a sound system like pd or Max to realize the sound. There are a number of artists using that approach, but one of the most exciting, in my opinion, is <a href="http://onyx-ashanti.com/" target="_blank">Onyx Ashanti, who is really pushing the envelope on the form factor for wind controllers</a>. He started with a Yamaha wind controller, deconstructed the functionality it provided, scratched some personal itches he had with performing live, and arrived at the Beatjazz Controller. I encourage you to follow his work.<br />
<br />
<h2>
What's Next</h2>
<br />
In the next post, I'll select an inexpensive sensor that you can use to sense breath pressure in a wind controller. We'll cover how to connect it to an Arduino or Teensy controller, and how to connect tubes to the sensor so you can blow into it and measure the breath intensity.<br />
<br />Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com14tag:blogger.com,1999:blog-2671439418188048550.post-9060626566710172422012-07-04T00:23:00.001-07:002012-07-04T00:39:37.476-07:00After a long hiatus, I'm back!(In which I give a big shout-out to PJRC, designers of the Teensy)<br />
<br />
I got inspired to do more work on my <a href="http://gordophone.blogspot.com/2010/06/updated-trombone-controller.html">Gordophone project</a> when I saw that the <a href="http://www.pjrc.com/teensy/">Teensy 2.0</a> had native support for USB MIDI. If you're unfamiliar with Teensy, it's a dynamite little ATMega-based microcontroller that is extremely compatible with Arduino, but also allows you to turn it into a USB device.<br />
<br />
I've always been bummed out that, in order for my instruments to drive software synthesizers on my Mac, my designs needed a MIDI shield bolted to the Arduino, and a MIDI interface connected to the Mac, using those 1980s DIN-5 connectors - very unwieldy.<br />
<br />
There is a standard for transporting MIDI messages over USB, and any modern music device you get these days will allow you to attach it to your computer via USB. So if, say, you go to your local music store and buy a keyboard, it'll have a USB connector. Plug it into your Mac, start up Garage Band, and you can control the softsynths.<br />
<br />
Since Teensy 2.0 has USB-MIDI support built in, this means that the Gordophone can shed all those MIDI cables and interfaces, and work directly over the USB cable that connects the Teensy to the computer.<br />
<br />
Also, Teensy is, well, teensy. It's barely bigger than a U.S. Quarter, yet has all the I/O I need to build the Gordophone, and if I need more I/O pins, I can use the Teensy 2.0 ++ (the big brother to the Teensy, which, while being a larger sibling, is still pretty damn small). I'm hoping to be able to embed the controller directly into the instrument in future designs.<br />
<br />
<a href="http://www.pjrc.com/">PJRC</a> is the company that sells the Teensy. I placed an order with them via the web, received a prompt acknowledgement of my order, and received my order a couple of days later (I'm on the US west coast, so shipping time from Oregon is fast). The Teensy is well-supported with plenty of downloadable sample code.<br />
<br />
My first milestone was to put together a simple instrument - a single button that sends a random MIDI node on event when pressed, and sends a note off event when the button is released. Following the help files on the PJRC website, I had my simple instrument running in less than 30 minutes, and the code worked the first time (that *never* happens at my day gig).<br />
<br />
My next milestone was to port my old Arduino-based Gordophone sketch to the Teensy.<br />
<br />
First, I had to solder up an adapter that would plug into the DB-25 connector on the Gordophone and bring out the individual wires so I could plug them into a breadboard and wire them up to the Teensy:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-8XJhMbGqqpE/T_PplSsRX_I/AAAAAAAABdo/bKQrvDzpOpA/s1600/1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://4.bp.blogspot.com/-8XJhMbGqqpE/T_PplSsRX_I/AAAAAAAABdo/bKQrvDzpOpA/s320/1.jpg" width="239" /></a></div>
<br />
And then it was a matter of digging up my project docs to remember which of the Gordophone sensors were connected to which input pins on the Arduino. The pins on the Teensy are different, but PJRC thoughtfully provides a reference card that maps the Arduino pin numbers to the Teensy pin numbers. Looking at that, I was able to patch the DB-25 to the Teensy:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-_giRdB-bzSs/T_PqeZM_7BI/AAAAAAAABdw/uwh04ncKBoU/s1600/2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://4.bp.blogspot.com/-_giRdB-bzSs/T_PqeZM_7BI/AAAAAAAABdw/uwh04ncKBoU/s320/2.jpg" width="239" /></a></div>
<br />
Also, I should mention, PJRC has done a fabulous job of integrating the Teensy into the Arduino IDE, via the <a href="http://www.pjrc.com/teensy/td_serial.html">Teensyduino</a> package. Apart from requiring that you press the Teensy's reset button once, the developer experience is exactly the same as using an Arduino.<br />
<br />
Since I have been inactive for a while, getting things running on the Teensy also required porting some code to Arduino 1.0, which required a few code changes since I developed everything on Arduino-22, but within 2 hours, I had everything working.<br />
<br />
Kudos to Paul and Robin at PJRC for making such an excellent controller and providing such top-notch support for it. Thank you!<br />
<br />Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com0tag:blogger.com,1999:blog-2671439418188048550.post-53722021977969211582011-04-06T23:20:00.000-07:002011-04-07T00:19:00.657-07:003D Trombone ImprovementsOver the last few days I've made a couple of improvements to the 3D Trombone firmware that improve its playability and get me a little closer to having a playable instrument to demo. My goal is to have something to take to Maker Faire Bay Area in May.<br /><br /><span style="font-weight: bold;">Improvement 1: Flip-Flopping the Overtone Selector</span><br /><br />If you recall, the 3D Trombone has a controller operated with the right hand that selects the "overtone" played by the instrument. All that really means is that, depending on which buttons are pressed, a different note is played when the player blows into the instrument, and the series of notes are the same as you would hear if an acoustic trombone player was playing the overtone series.<br /><br />In musical notation, that's:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-t4i8EFLHsck/TZ1bIC6XU2I/AAAAAAAABb0/RezgmsGP-jg/s1600/trb.JPG"><img style="cursor: pointer; width: 400px; height: 299px;" src="http://3.bp.blogspot.com/-t4i8EFLHsck/TZ1bIC6XU2I/AAAAAAAABb0/RezgmsGP-jg/s400/trb.JPG" alt="" id="BLOGGER_PHOTO_ID_5592726506042774370" border="0" /></a><br /><br />Since I don't have a way of enulating the "overblowing" behavior that I can get on an acoustic trombone, I built a controller that lets the player press buttons to select the "overtone" played. It looks like this:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-13clWaPcb30/TZ1bkk_0GGI/AAAAAAAABb8/Wcj520d_-8Y/s1600/3drh.JPG"><img style="cursor: pointer; width: 299px; height: 400px;" src="http://2.bp.blogspot.com/-13clWaPcb30/TZ1bkk_0GGI/AAAAAAAABb8/Wcj520d_-8Y/s400/3drh.JPG" alt="" id="BLOGGER_PHOTO_ID_5592726996228773986" border="0" /></a><br /><br />In my original firmware, I'd mapped the overtones as follows:<br /><br />All switches open: Fundamental<br />Switch 4 pressed: overtone 1<br />Switches 3 and 4 pressed: overtone 2<br />Switches 2, 3 and 4 pressed: overtone 3<br />Switches 1, 2, 3 and 4 pressed: overtone 4<br />Switches 1, 2 and 3 pressed: overtone 5<br />Switches 1 and 2 pressed: overtone 6<br />Switch 1 pressed: overtone 7<br /><br />I found this incredibly difficult to play. I often would unintentionally play a lower note when I intended to play a higher note, or vice-versa. At first I attributed this to being completely unfamiliar with the concept of using my fingers to select pitches, as opposed to using my embouchure.<br /><br />But after playing "3d air trombone" for a while today, I wondered if some of my difficulties were due to the particular way I'd mapped the keys. So tonight I rewrote the firmware and turned the finger assignments completely upside down. And, lo and behold, it works a lot better. For some reason, it feels much more like the concepts of "up" and "down" make sense now.<br /><br />To experience this, hold your right hand sideways in front of you, with your palm facing you. If you curl your fingers toward your palm, starting first with your pinky and ending with your index finger, that's the new motion I implemented, and it feels like "up" to me. <span style="font-weight: bold; font-style: italic;">I had it backwards before!</span><br /><br /><span style="font-weight: bold;">Improvement 2: Enabling Scene Selection in Ableton Live</span><br /><br />Since I want to be able to take this setup and perform live at Maker Faire, I've been trying to build a live performance setup (by the way, I won't have a set location - I'm just hoping to find an electrical outlet somewhere and have an impromptu concert). Although I have mostly been using Apple Logic, I did get a Lite version of Ableton Live with one of the MIDI interfaces I bought, and I was able to upgrade to the Lite version of Live 8 for free.<br /><br />I've always had a bit of a hard time getting my head around how Live works, but I think I'm starting to get it, and after spending some more time with the tutorials, I can see using it for my performances. Live has a concept of "scenes" that typically map to some musical structure. For example, the scenes might the intro, verse, chorus, break, and outro (for a traditional song form). For a dj, the scenes might be a collection of samples and beats that s/he selects in some sequence.<br /><br />People who use Live seriously often have a dedicated hardware controller with big, lighted buttons that are easy to see in a dark environment and are easy to hit reliably in a performance. I really don't want to have to haul something like that around. So I decided to build in the ability to do scene selection with the 3d Trombone.<br /><br />To accomplish that, I added an additional button, operated by the thumb. In the photo, it's labeled "Meta":<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-yG6TpYA0Y0w/TZ1ima70SjI/AAAAAAAABcE/muadrwW8x_4/s1600/3drh.JPG"><img style="cursor: pointer; width: 299px; height: 400px;" src="http://1.bp.blogspot.com/-yG6TpYA0Y0w/TZ1ima70SjI/AAAAAAAABcE/muadrwW8x_4/s400/3drh.JPG" alt="" id="BLOGGER_PHOTO_ID_5592734724468787762" border="0" /></a><br /><br />To select a scene in Live, you:<br /><br />Stop playing any notes (that is, stop blowing)<br />Press button 1, 2, 3, or 4 to select a scene<br />Press and release the Meta button<br /><br />When the firmware detects that the meta button was released, it reads the values of the other 4 buttons and sends a MIDI Note On event on an alternate MIDI channel. You can then use Live's MIDI mapping mode to assign that to one of the scene selection buttons in your Live set.<br /><br />Being the geek I am, I was unhappy with only being able to select one of 4 scenes, so I wrote the firmware so that it reads the 4 switches as a 4-bit binary number and sends that as the MIDI note on. So, if you are able to do binary in your head, you can select up to 16 scenes (if you don't want to do that, you can still just use the 4 notes produced by pressing the 4 switches individually).<br /><br /><span style="font-weight: bold;">Next</span><br /><br />Now that I seem to have something that's somewhat playable, the next step is to put together a few Live sets that have some backing material that I can use to show off the 3D Trombone. Unfortunately, it doesn't appear that the Apple Logic Softsynths are available from within Live, so I'll probably need to find an AU or VST synth plugin that is flexible enough to be controlled by my instrument. Most of the really high-end softsynths (things from Native Instruments, Omnisphere, etc) all have very sophisticated MIDI controller routing capabilities, so one of those is probably in my future. If anyone has suggestions for a specific synth they have gotten working well with a wind controller (e.g. a Yamaha WX series, or an Akai EWI), let me know.<br /><br />Thanks for reading...<br /><br />-GordonGordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com0tag:blogger.com,1999:blog-2671439418188048550.post-4227083541185255582011-03-05T10:29:00.000-08:002011-03-05T10:46:36.330-08:00Analog MultiplexingThe Arduino has 6 analog I/O pins. For one project I'm considering, I actually will need 7 analog I/O pins, so I went looking for an analog multiplexer chip that would allow me to have more analog I/O. I found the CD74HC4067, a 16-channel analog multiplexer that will fill the bill.<br /><br />You can think of the chip like a 16-position switch. There are 4 input pins that select which one of the 16 pins to connect to the common pin. If you write a binary 0000 to the input pins, the common pin is connected to input/output pin 0. If you write a binary 0001, the common pin is connected to input/output pin 1. And so on.<br /><br />To try this chip out, I built the circuit shown below. Two 10 k potentiometers are wired up as a voltage divider to provide a voltage from 0-5 volts that I can measure. The common pin of the multiplexer chip goes to the Arduino's analog input, and the wipers of the pots go to input/output pins 0 and 1 of the multiplexer chip.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-7qjfzCrlUYY/TXKChTEpDXI/AAAAAAAABbU/9pun8e8s5EA/s1600/4067.jpg"><img style="cursor: pointer; width: 249px; height: 400px;" src="http://3.bp.blogspot.com/-7qjfzCrlUYY/TXKChTEpDXI/AAAAAAAABbU/9pun8e8s5EA/s400/4067.jpg" alt="" id="BLOGGER_PHOTO_ID_5580666396832501106" border="0" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-LJOyrdC65X0/TXKDWjhH36I/AAAAAAAABbc/4yZYB_bVUec/s1600/IMG_0418.JPG"><img style="cursor: pointer; width: 299px; height: 400px;" src="http://2.bp.blogspot.com/-LJOyrdC65X0/TXKDWjhH36I/AAAAAAAABbc/4yZYB_bVUec/s400/IMG_0418.JPG" alt="" id="BLOGGER_PHOTO_ID_5580667311779995554" border="0" /></a><br /><br />To be sure I was programming the chip correctly, I also hooked the wipers of the pots to Arduino analog pins 1 and 2. If I've got things working properly, then I should see that same value coming from the mux chip as I see on the Arduino analog input.<br /><br />Finally, I wrote a little sketch that selects one of the mux inputs, and then prints the values from analogRead() on pin 0 (connected to the MUX) and pins 1 and 2 (connected to the potentiometers). Running the sketch, when I turn the potentiometer selected by the mux, I see it value change, and it matches the value directly read by the Arduino. Unit testing hardware FTW!<br /><br /><pre><br />/**<br />74HC4067 Test<br /><br />The 74HC4067 chip is an analog multiplexer. It has 4 control pins where you write<br />a value (0-15) that selects which of the 16 analog inputs/outputs to/from the chip<br />are hooked up to the common input/outout. This is useful if you need to read or<br />write an analog voltage to more than the 6 pins available on the Arduino.<br /><br />*/<br /><br />int mpin = 1;<br /><br />void setup() {<br /> Serial.begin(9600);<br /> pinMode(2, OUTPUT);<br /> pinMode(3, OUTPUT);<br /> pinMode(4, OUTPUT);<br /> pinMode(5, OUTPUT);<br />}<br /><br />/*<br />Choose the input pin selected by the 74HC4067 chip<br />*/<br />void selectInputPin(int pin) {<br /> if (0 == pin) {<br /> digitalWrite(2, 0);<br /> } else if (1 == pin) {<br /> digitalWrite(2, 1);<br /> }<br /> digitalWrite(3, 0);<br /> digitalWrite(4, 0);<br /> digitalWrite(5, 0);<br />}<br /> <br /><br />void loop() {<br /> Serial.print("Loop begin: select multiplexer pin ");<br /> selectInputPin(mpin);<br /> Serial.print(mpin);<br /> Serial.println();<br /> Serial.print("0: ");<br /> Serial.print(analogRead(0));<br /> Serial.print(" 1: ");<br /> Serial.print(analogRead(1));<br /> Serial.print(" 2: ");<br /> Serial.print(analogRead(2));<br /> Serial.println();<br /> delay(1000);<br />}<br /></pre>Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com0tag:blogger.com,1999:blog-2671439418188048550.post-46182507248425546362011-02-22T23:03:00.000-08:002011-02-23T12:28:11.753-08:003-D Trombone Photos and IdeasI've finally gotten back to working on my 3-D Trombone concept. It's been a while - work has gotten pretty crazy lately, but I've just gotta get back to this to exercise my creative outlets.<br /><br />Here are a few photos of the electronics:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-5Moa7CWeIcY/TWSyG-5wMgI/AAAAAAAABZ8/YhOOehJfRAQ/s1600/IMG_0390.jpg"><img style="cursor: pointer; width: 299px; height: 400px;" src="http://2.bp.blogspot.com/-5Moa7CWeIcY/TWSyG-5wMgI/AAAAAAAABZ8/YhOOehJfRAQ/s400/IMG_0390.jpg" alt="" id="BLOGGER_PHOTO_ID_5576778071625708034" border="0" /></a><br /><br />The large black unit in the center is the 3-position joystick I liberated from a <a href="http://en.wikipedia.org/wiki/Gametrak">Gametrak</a> controller. You can see the joystick in the upper right. The circuit board in the upper left is just a wiring junction I built to make the electrical connections more secure. All the potentiometer connections and the power supply line come in/out on the ribbon cable you see (IDC connecors FTW!).<br /><br />Here's another view where you can see some of the mechanics of the Game Trak controller. It's pretty simple, really - a gear system drives a potentiometer. The large enclosure houses a large coil spring that provides the return force for the z-axis.<br /><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-A_wa786P8Xc/TWSzwYAO2vI/AAAAAAAABaE/JBUkSHRFH_c/s1600/IMG_0379.jpg"><img style="cursor: pointer; width: 400px; height: 299px;" src="http://2.bp.blogspot.com/-A_wa786P8Xc/TWSzwYAO2vI/AAAAAAAABaE/JBUkSHRFH_c/s400/IMG_0379.jpg" alt="" id="BLOGGER_PHOTO_ID_5576779882250033906" border="0" /></a><br /><br />There is also a breath sensor based on the same Freescale chip I used in my previous controller, built into a small project box and attached to the gametrak controller box:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-o5W1fOOcGb4/TWS11TaQ_rI/AAAAAAAABaU/kEMqaXg9aMs/s1600/IMG_0376.jpg"><img style="cursor: pointer; width: 299px; height: 400px;" src="http://4.bp.blogspot.com/-o5W1fOOcGb4/TWS11TaQ_rI/AAAAAAAABaU/kEMqaXg9aMs/s400/IMG_0376.jpg" alt="" id="BLOGGER_PHOTO_ID_5576782165939650226" border="0" /></a><br /><br />I also have a controller that the player holds in the right hand. It consists of 5 monentary pushbutton switches used to select the overtone played. Here's a view of it:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-Wx7Hryx3SAA/TWS0jkj1S0I/AAAAAAAABaM/-ofmNjHL7c0/s1600/IMG_0372.jpg"><img style="cursor: pointer; width: 299px; height: 400px;" src="http://2.bp.blogspot.com/-Wx7Hryx3SAA/TWS0jkj1S0I/AAAAAAAABaM/-ofmNjHL7c0/s400/IMG_0372.jpg" alt="" id="BLOGGER_PHOTO_ID_5576780761793907522" border="0" /></a><br /><br /><br />The right hand controller and gametrak box connects to the same Arduino + MIDI Shield box I built for my other instrument (the new box is plug-compatible with the old one). Here's a view from the outside:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-cFB65JCfqu4/TWS2j0G5c1I/AAAAAAAABac/HAH6-_bFgxs/s1600/IMG_0383.JPG"><img style="cursor: pointer; width: 400px; height: 299px;" src="http://3.bp.blogspot.com/-cFB65JCfqu4/TWS2j0G5c1I/AAAAAAAABac/HAH6-_bFgxs/s400/IMG_0383.JPG" alt="" id="BLOGGER_PHOTO_ID_5576782964990767954" border="0" /></a><br /><br />The controller electronics attach via the DB-25 connector. The switch on the top is used to select "load" mode, where the Arduino is able to download code from the IDE, and "run" mode where the serial pins are connected to the MIDI shield, which you can see in this photo of the inside:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-MqJUDiTBwvM/TWS3USMKsLI/AAAAAAAABak/QgFlEfRoG68/s1600/IMG_0386.JPG"><img style="cursor: pointer; width: 400px; height: 299px;" src="http://2.bp.blogspot.com/-MqJUDiTBwvM/TWS3USMKsLI/AAAAAAAABak/QgFlEfRoG68/s400/IMG_0386.JPG" alt="" id="BLOGGER_PHOTO_ID_5576783797699653810" border="0" /></a><br /><br />Visible at the upper-left is the MIDI out port.<br /><br /><span style="font-weight: bold;">Ideas</span><br /><br />I had an email conversation with <a href="http://onyx-ashanti.ning.com/">Onyx Ashanti</a> about the cool work he's doing on his <a href="http://onyx-ashanti.ning.com/profiles/blog/list">Tron Beatjazz Controller</a>. Onyx has some big goals for his work, and some of them could benefit my design, especially the hand-controllers he's working on - they'll have keys for each finger to operate, as well as an accelerometer. I think he's also incorporating some <a href="http://thingm.com/">ThingM</a> <a href="http://thingm.com/products/blinkm-maxm.html">MaxM</a> LEDs, which is very cool. ThingM's founder, <a href="http://orangecone.com/">Mike Kuniavsky</a>, is a friend of mine and a former coworker at the University of Michigan.<br /><br />The night after I had the email conversation, I had a dream that I was playing live at some sort of a club. I had an instrument sort of like my 3-D Trombone, but instead of the overtone controller, in my right hand I held a microphone, and to control the overtones, I moved my right hand up and down in the vertical axis. In my dream, I found it very natural, and was able to play melodies about as easily as on my trombone. I'm still not sure why I was holding a microphone in my dream.<br /><br />I suspect this idea had been hanging around in my brain for a while, and my conversation with Onyx brought it to the front.<br /><br /><span style="font-weight: bold;">Naive Implementation</span><br /><br />I took that idea and modified my 3-D Trombone Arduino sketch to read the Y-axis position of the gametrak controller and map the value, in a linear fashion, to an overtone.<br /><br />In a nutshell, the result was unplayable. The problem is that, in order to maintain the "slide" position, the amount of "string" deployed out the gametrak controller has to be constant. So, in order to move up and down the harmonic series without changing slide position, you need to move your arm in an constant-radius arc, which is already pretty hard. But to make matters worse, the radius of the arc depends on which position you're in. So if you're in seventh position, the arc is several feet long, but if you're in first position, the arc is only one or two inches long. It produced some fun random effects flying up and down the harmonic series will glissando-ing in and out, but that would get old quick. Here's a picture of what I mean:<br /><br /><a href="http://2.bp.blogspot.com/-yyDLu2kRJJI/TWVto30b5-I/AAAAAAAABbM/-kcnQx-KDpk/s1600/photo%25283%2529.JPG"><img style="cursor: pointer; width: 299px; height: 400px;" src="http://2.bp.blogspot.com/-yyDLu2kRJJI/TWVto30b5-I/AAAAAAAABbM/-kcnQx-KDpk/s400/photo%25283%2529.JPG" alt="" id="BLOGGER_PHOTO_ID_5576984262514304994" border="0" /></a><br /><br />I have another idea about how to make this idea (vertical motion selects overtones, horizontal motion selects pitch) - a simple mapping of overtone to vertical position, pitch to horizontal position. Basically, a grid like this:<br /><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-JWeVw1shGss/TWTCLf12v0I/AAAAAAAABas/PHZecx2Db9k/s1600/grid.jpg"><img style="cursor: pointer; width: 400px; height: 299px;" src="http://2.bp.blogspot.com/-JWeVw1shGss/TWTCLf12v0I/AAAAAAAABas/PHZecx2Db9k/s400/grid.jpg" alt="" id="BLOGGER_PHOTO_ID_5576795741373251394" border="0" /></a><br /><br />The X axis is the slide position - a trombone has seven of them, and the Y axis is the overtone. A good trombone player can play about 10 overtones, which corresponds to a range of about 3 octaves plus a few extra notes. So where a person playing an acoustic trombone would keep the slide in first position and move up and down the harmonic series with his/her embouchure, the player of the 3-D trombone would trade in the embouchure for up and down motion.<br /><br />For those of you who may play trombone, here's how a B-flat major scale would look:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-RXWIzqOU0jg/TWTD1-QsJFI/AAAAAAAABa8/fbZmnB-YJws/s1600/path.jpg"><img style="cursor: pointer; width: 400px; height: 299px;" src="http://2.bp.blogspot.com/-RXWIzqOU0jg/TWTD1-QsJFI/AAAAAAAABa8/fbZmnB-YJws/s400/path.jpg" alt="" id="BLOGGER_PHOTO_ID_5576797570604999762" border="0" /></a><br /><br /><span style="font-weight: bold;">Implementation:</span><br /><br />It turns out that it will be very hard to implement this "grid" idea using my current setup. The reason is that, due to the arrangement of the gametrak controller and the player (s/he holds it near the face), and the travel limits of the gametrak unit's joystick axes (about 90 degrees), it's not possible to cover the whole range of motion that might be interesting to a trombone player. So... back to the drawing board.<br /><br />A more promising arrangement would be to use the Gametrak as it was intended to be used; base unit sitting on the floor. I'll investigate that and post on it in the future.Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com0tag:blogger.com,1999:blog-2671439418188048550.post-48081544094902636232010-09-30T15:47:00.000-07:002011-02-20T08:59:19.258-08:00HP Creative CampWelcome, HP Creative Camp participants who have found your way here. And thank you for all the positive feedback I got at camp, and in email afterwards. If you want to follow my music/microcontroller experiments add this bookmark:<br /><br /><a href="http://gordophone.blogspot.com/">http://gordophone.blogspot.com/</a><br /><br />I had the distinct pleasure of participating in HP Software's Creative Camp (modeled on <a href="http://en.wikipedia.org/wiki/Foo_Camp">Foo Camp</a>) in Sep. 2010 at the <a href="http://www.stanfordsierra.com/">Stanford Sierra Conference Center</a>. I gave a hastily prepared talk on the work I've been doing with microcontrollers and music, gave a demo of my recently completed <a href="http://gordophone.blogspot.com/2010/08/3-d-trombone.html">3-dimensional trombone</a>, and some weird stuff I've been doing around sonification (sorry, no public posts about that yet). I also "performed" at the big party event, making some sounds with my iPhone+<a href="http://hexler.net/software/touchosc">TouchOSC </a>and <a href="http://www.osculator.net/">OSCUlator</a>+<a href="http://www.apple.com/logicstudio/">Logic</a>, accompanied by other Creative Camp musicians. It was a blast. A <a href="http://www.youtube.com/watch?v=PxSfPrMRrEk">video summary</a> of the event was made, and I'm at 4:51.<br /><br />Oh, and the Silent Disco (everyone puts on wireless headphones) put on by DJ <a href="http://www.motionpotion.com/">Motion Potion</a> was pretty damn cool! Robbie gave a presentation earlier in the the day (also hastily prepared. according to Robbie, but way, *way* better than mine) about DJ technology and history. As a traditionally trained musician, I've always found DJ culture puzzling, but the way he framed the whole presentation around passion really spoke to me. Thanks, Robbie.<br /><br />P.S. I looked over the comments from the camp, and someone commented that my session caused them to "rocket into ideation mode". That's exactly what happened to me when <a href="http://gordophone.blogspot.com/2010/07/week-of-good-ccrma.html">I attended the New Music Controllers</a> Workshop at Stanford, and if I managed to trigger that in someone else's mind, that's pretty great. Thanks for sharing that!Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com0tag:blogger.com,1999:blog-2671439418188048550.post-74583638800037951152010-08-31T23:17:00.000-07:002010-09-03T16:18:51.031-07:00The 3-D TromboneWhen I was at the<a href="http://gordophone.blogspot.com/2010/07/week-of-good-ccrma.html"> New Music Controllers workshop at CCRMA</a> this summer, after I'd demoed my trombone controller and mentioned that I was interested in using a retractable string for a slide (based on a suggestion from Chris Graham), a CCRMA grad student named <a href="https://ccrma.stanford.edu/people/michael-berger">Michael Berger</a> clued me into a very cool device - the <a href="http://en.wikipedia.org/wiki/Gametrak">GameTrak Controller</a>.<br /><br />The GameTrak is a pretty amazing little device. Think of a joystick, which can measure X and Y axis movements, then add a retractable cord that protrudes through the handle and can measure Z-axis displacement. There are actually two of these in each GameTrak, and the player wears a pair of gloves that attach to clips on the end of the Z-axis cords. Internally, there are 6 potentiometers that hook to a small board that does all the analog to digital conversion and appears as a USB HID device. Hooking one of these up to, say, Max/MSP or pd is super simple, and here are some cool things that have been done with GameTraks:<br /><br /><a href="http://www.youtube.com/watch?v=HFfR_9Wczjc">Game Trak Theory</a> (A CCRMA performance)<br /><a href="http://www.youtube.com/watch?v=0ifxD-CeXII">Cop de Cap by Experimental Headbang Orchestra</a> (Stanford)<br /><br />Since the Wii pretty much destroyed the GameTrak in the gaming market, they're available very cheaply now - I think I now own 6, and I got them for $20 each.<br /><br />Originally I was only interested in cannibalizing one for the z-axis retractable cord, to use that for the slide of my trombone. But once I got one of the GameTraks open, I thought "why limit the slide to linear motion? Why can't we build a trombone "slide" that operates in 3 dimensions?" And so the 3-D Trombone was born.<br /><br />Opening up the GameTrak is very easy, and the spring/joystick mechanism for one-half of the device can easily be removed with just a small philips screwdriver. I remounted the assembly in a project box, which is a lot larger than I'd like it to be, but it's a prototype.<br /><br />I built another breath controller using garden irrigation tubing and the same <a href="http://gordophone.blogspot.com/2010/01/we-have-winner.html">Freescale Pressure Sensor</a> I used for the Gordophone. For overtone selection, I epoxied some momentary switches into piece of PVC tubing (in the Gordophone, these switches are in the joystick handle that is used to move the slide).<br /><br />After wiring everything up, I made two changes to the Arduino sketch that does the sensor reading and MIDI event generation:<br /><br />- Rescaled the "slide" motion limits, since the GameTra can measure about 6 feet of z-axis motion, but a trombone slide is only a couple of feet.<br />- Coded things so that the X and Y axis controllers produce MIDI continuous controller data on controllers number 16 and 17.<br /><br />Finally, I put together a patch and an effect in Logic, as follows:<br /><br />- A simple sine wave instrument using the ES2 synth. The breath controller is mapped to the oscillator amplitude.<br />- The EVOC 20 TrackOscillator Filter. I used Logic's "Learn" mode to set things up so that the slide's X axis motion controls the Formant Shift, and the Y axis motion controls the LFO intensity. I set the LFO frequency at 100 Hz so it really distorts the sound (I really lean into that distortion at around 0:52 and 1:02).<br /><br />I made the X and Y axis controls very non-subtle, so I could tell when they were working. This video shows the whole thing in action.<br /><br /><br /><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dxg3-vj55c_Fk5kSxv50tLG7JGWu8MI4fbeTz5SnL9ZZG5PuRmIzIFj8ymsOXfSByYD_Al0l_B0XjO39w8EsA' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br /><br />One thing that's very tricky is maintaining a constant slide position on the Z-axis while moving around the X and Y axes. While playing a traditional trombone, one can move around, but the player's body position relative the the instrument remains constant. With the 3-D Trombone, all that changes, and it (so far) seems like a radically different experience. More exprimentation is due.Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com1tag:blogger.com,1999:blog-2671439418188048550.post-63401270842286132882010-07-04T10:11:00.000-07:002010-08-03T15:17:42.026-07:00A week of good CCRMA<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_c_W4p2Ok5c0/TC_9jy6xguI/AAAAAAAABVA/BfVVblR8xL0/s1600/L1010341.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_c_W4p2Ok5c0/TC_9jy6xguI/AAAAAAAABVA/BfVVblR8xL0/s400/L1010341.jpg" alt="" id="BLOGGER_PHOTO_ID_5489885262193459938" border="0" /></a><br /><br /><span style="font-style: italic;">The Knoll - CCRMA Home</span><br /><br />This past week I cashed in some vacation time and attended the 5-day <a href="https://ccrma.stanford.edu/workshops/new-music-controllers-nmc">New Music Controllers Workshop</a>, led by <a href="https://ccrma.stanford.edu/%7Eeberdahl/">Edgar Berdahl</a> and <a href="http://www-cdr.stanford.edu/%7Ewendyju/">Wendy Ju</a>, at Stanford's <a href="https://ccrma.stanford.edu/">Center for Computer Research in Music and Acoustics</a> (CCRMA, pronounced "karma"). It was a great experience, with terrific guest lecturers and a fun group of participants.<br /><br />(Update 7/22/10: Video<span style="text-decoration: underline;"></span> of <a href="https://ccrma.stanford.edu/courses/250a/workshop2010/index.html">all the workshop demos</a> is now online on the CCRMA website.)<br /><br />The workshop is a one-week version of the same material covered in the <a href="https://ccrma.stanford.edu/courses/250a/">Physical Interaction Design for Music</a> course offered at Stanford (Ed and Wendy teach that course as well). Topics covered in the course include the <a href="https://ccrma.stanford.edu/wiki/Interaction_Design_Framework">Verplankian Physical Interaction Design Framework</a>, basic electronics, the <a href="http://arduino.cc/">Arduino</a>, using <a href="http://cycling74.com/products/maxmspjitter/">Max/MSP</a> and <a href="http://puredata.info/">pd</a>, and using sensors to interact with the real world.<br /><br />The guest lectures were one of the high points of the workshop. We heard from <a href="http://www.billverplank.com/professional.html">Bill Verplank</a> (Interaction Design), <a href="http://www.create.ucsb.edu/%7Edano/">Dan Overholt</a> (Music Interface Technology Design Space), Alexandros Kontogeorgakopoulos (Cardiff School of Art and Design - Haptic Digital Audio Effects), and <a href="https://ccrma.stanford.edu/%7Ege/">Ge Wang</a> (<a href="http://chuck.cs.princeton.edu/">Chuck programming language</a>, <a href="http://www.smule.com/">Smule</a>). I particularly enjoyed seeing all the cool projects that Dan Overholt did, including <a href="http://www.create.ucsb.edu/%7Edano/violin/">Overtone Violin</a>, <a href="http://www.create.ucsb.edu/%7Edano/sphere/">Sphere Spatializer</a>, and his <a href="http://overtone-labs.ning.com/">Overtone Labs</a> work. And if you've never seen Ge Wang talk, you really, really should. He blew me away with his geek chops, his musician chops, and his business chops -- all in one hour.<br /><br />I also really enjoyed meeting all the other participants. We were all over the range in terms of experience with music performance, synthesis, hardware, software... but everyone chipped in to help each other fill in their knowledge gaps.<br /><br />Here are some photos and videos of the workshop:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_c_W4p2Ok5c0/TC_-QQ3Mu8I/AAAAAAAABVI/gEju_bNUwgA/s1600/L1010349.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_c_W4p2Ok5c0/TC_-QQ3Mu8I/AAAAAAAABVI/gEju_bNUwgA/s400/L1010349.jpg" alt="" id="BLOGGER_PHOTO_ID_5489886026145774530" border="0" /></a><br /><br /><span style="font-style: italic;">Ian's Thumb Piano (force sensitive resistors, an acceleromoter, and some Max/MSP code)</span><br /><br />Ian is also no stranger to geeking out with electronics and music. Here he is with his Guitamoton (built previously):<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_c_W4p2Ok5c0/TC__QZWcWqI/AAAAAAAABVQ/qfG5HiSz0Qw/s1600/L1010365.jpg"><img style="cursor: pointer; width: 300px; height: 400px;" src="http://3.bp.blogspot.com/_c_W4p2Ok5c0/TC__QZWcWqI/AAAAAAAABVQ/qfG5HiSz0Qw/s400/L1010365.jpg" alt="" id="BLOGGER_PHOTO_ID_5489887127935933090" border="0" /></a><br /><br />and a video of it in action:<br /><br /><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dwyWvS0PDGDeX3458-FF7B2jf7h3v4mb3CmqCc4niXfdkl7FrfW0nImuwvy-4-nAnNBUc9QdtT4fxilZYwTMQ' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br /><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_c_W4p2Ok5c0/TDADbqXn76I/AAAAAAAABVY/nuwM2Gg4EsM/s1600/L1010346.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_c_W4p2Ok5c0/TDADbqXn76I/AAAAAAAABVY/nuwM2Gg4EsM/s400/L1010346.jpg" alt="" id="BLOGGER_PHOTO_ID_5489891719529361314" border="0" /></a><br /><br /><span style="font-style: italic;">A sensor glove from Jenifer (Masters student in Intermedia Music Technology at the University of Oregon)</span><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TDAEGYkR4qI/AAAAAAAABVg/nNduvStnTNc/s1600/L1010354.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TDAEGYkR4qI/AAAAAAAABVg/nNduvStnTNc/s400/L1010354.jpg" alt="" id="BLOGGER_PHOTO_ID_5489892453484978850" border="0" /></a><br /><br /><span style="font-style: italic;">Jeremy and Chekad testing their "conductor" device that allows the player to change the tempo of a performance by conducting. They had about two days to build it, and it actually worked!</span><br /><br />For the final demo/concert in the CCRMA Stage, we had a great audience of CCRMA faculty and students, including <a href="http://en.wikipedia.org/wiki/John_Chowning">John Chowning</a> (!).<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TDAE5XJNwHI/AAAAAAAABVo/3qcxvEfQgiQ/s1600/L1010372.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TDAE5XJNwHI/AAAAAAAABVo/3qcxvEfQgiQ/s400/L1010372.jpg" alt="" id="BLOGGER_PHOTO_ID_5489893329276354674" border="0" /></a><br /><br />Between sessions, I wandered around the CCRMA building. Man, that place is one big house full of cool toys:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_c_W4p2Ok5c0/TDAF-zw6h8I/AAAAAAAABVw/ml0bLd-IJVY/s1600/L1010359.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_c_W4p2Ok5c0/TDAF-zw6h8I/AAAAAAAABVw/ml0bLd-IJVY/s400/L1010359.jpg" alt="" id="BLOGGER_PHOTO_ID_5489894522370033602" border="0" /></a><br /><span style="font-style: italic;">The door to the Max Lab, named after </span><a style="font-style: italic;" href="http://en.wikipedia.org/wiki/Max_Mathews">Max Matthews</a><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TDAGyAwWkTI/AAAAAAAABV4/SySW_6NQtUs/s1600/L1010360.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TDAGyAwWkTI/AAAAAAAABV4/SySW_6NQtUs/s400/L1010360.jpg" alt="" id="BLOGGER_PHOTO_ID_5489895402030666034" border="0" /></a><br /><br /><span style="font-style: italic;">Inside the lab - a music/hardware/software hacker's paradise. And we had full access to it for the week.</span><br /><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TDAHSMGS56I/AAAAAAAABWA/Rmxh5EFlCks/s1600/L1010362.jpg"><img style="cursor: pointer; width: 300px; height: 400px;" src="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TDAHSMGS56I/AAAAAAAABWA/Rmxh5EFlCks/s400/L1010362.jpg" alt="" id="BLOGGER_PHOTO_ID_5489895954831304610" border="0" /></a><br /><br /><span style="font-style: italic;">Yes, there's one whole bin just for accelerometers.</span><br /><br />On the CCRMA ground floor there's a museum of sorts. Check this stuff out:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TDAIG_WTd0I/AAAAAAAABWI/jshnk61dqdU/s1600/L1010335.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TDAIG_WTd0I/AAAAAAAABWI/jshnk61dqdU/s400/L1010335.jpg" alt="" id="BLOGGER_PHOTO_ID_5489896861941856066" border="0" /></a><br /><br /><span style="font-style: italic;">A NeXT cube. Man, I used to support those things at U of M. The optical drive qualified as a percussion instrument.</span><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_c_W4p2Ok5c0/TDAIfcM3teI/AAAAAAAABWQ/UXRNVGh3mcI/s1600/L1010338.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_c_W4p2Ok5c0/TDAIfcM3teI/AAAAAAAABWQ/UXRNVGh3mcI/s400/L1010338.jpg" alt="" id="BLOGGER_PHOTO_ID_5489897282003776994" border="0" /></a><br /><span style="font-style: italic;">A </span><a style="font-style: italic;" href="http://en.wikipedia.org/wiki/DX-7">Yamaha DX-7</a><span style="font-style: italic;">, the first commercially successful digital synthesizer. The FM synthesis patent that Stanford licensed to Yamaha was at one point the most lucrative patent held by the University.</span><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_c_W4p2Ok5c0/TDAJxhdLMoI/AAAAAAAABWY/JD-ozfSeTAo/s1600/L1010336.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_c_W4p2Ok5c0/TDAJxhdLMoI/AAAAAAAABWY/JD-ozfSeTAo/s400/L1010336.jpg" alt="" id="BLOGGER_PHOTO_ID_5489898692163613314" border="0" /></a><br /><br /><span style="font-style: italic;">An early prototype FM synthesizer from Yamaha? Check out the console:</span><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_c_W4p2Ok5c0/TDAKQG_4ANI/AAAAAAAABWg/uYo-_ZIZ-XI/s1600/L1010337.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_c_W4p2Ok5c0/TDAKQG_4ANI/AAAAAAAABWg/uYo-_ZIZ-XI/s400/L1010337.jpg" alt="" id="BLOGGER_PHOTO_ID_5489899217637343442" border="0" /></a><br /><br /><span style="font-style: italic;">Notice how there are actually four separate monitors.</span><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_c_W4p2Ok5c0/TDAKxBSkF2I/AAAAAAAABWo/SiTVddjbM78/s1600/L1010364.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_c_W4p2Ok5c0/TDAKxBSkF2I/AAAAAAAABWo/SiTVddjbM78/s400/L1010364.jpg" alt="" id="BLOGGER_PHOTO_ID_5489899783040800610" border="0" /></a><br /><br /><span style="font-style: italic;">Interesting aural possibilities...</span><br /><br />And, in the 2nd floor common area:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TDALUDBK3UI/AAAAAAAABWw/dKZH4O7toDk/s1600/L1010355.jpg"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TDALUDBK3UI/AAAAAAAABWw/dKZH4O7toDk/s400/L1010355.jpg" alt="" id="BLOGGER_PHOTO_ID_5489900384800136514" border="0" /></a><br /><br /><span style="font-style: italic;">When reading Computer Music Journal, it's best to have an ample supply of Tabasco on hand.</span><br /><br />After the demo/performance, some beer was consumed, and then Chekad pulled out his violin. I had no idea he was such an accomplished violinist, both in western styles and in the styles of his native Iran. He jammed with Dan Overholt, and then with Alexandros, who managed despite lacking a piano bench:<br /><br /><br /><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dwTcx4RPfxn1qK1Tx2LWzViIVWfaAD9V_Y2H03C-g89J6CRX3G5cPAJepzNocC5z_bZ1WvZVAzCB_98DtFPiA' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br /><br /><br /><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dxhaaqS0XyYZDVNIoR9zdnQaQgELWoslA2tC1zMAUXHpugwT-ti9K4it3ZKUsNiV5z00JWYihduuObf8_XU4A' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br /><br />A nice end to the week.<br /><br />-GordonGordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com1tag:blogger.com,1999:blog-2671439418188048550.post-43070526379595458352010-06-04T00:16:00.000-07:002010-06-08T21:49:31.914-07:00Updated Trombone ControllerOver the past month or two, I've been slowly working on a refinement to the trombone controller, and I've finally got something that's physically stable and reasonably playable. Here's an update:<br /><br />First, here's a photo of the prototype:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_c_W4p2Ok5c0/TAio00ZEOVI/AAAAAAAABUg/x3RqpbeJies/s1600/Gordo_Over.jpg"><img style="cursor: pointer; width: 400px; height: 211px;" src="http://2.bp.blogspot.com/_c_W4p2Ok5c0/TAio00ZEOVI/AAAAAAAABUg/x3RqpbeJies/s400/Gordo_Over.jpg" alt="" id="BLOGGER_PHOTO_ID_5478814572066650450" border="0" /></a><br /><br />If the wooden handle (used to hold the instrument) looks like an axe handle to you... you'd be right. I'm still working on how the performer's left hand is involved, but for the time being, I've relegated it to a supporting role.<br /><br />The major change between this prototype and the previous prototypes is the slide. The new prototype is essentially a copy of one half of <a href="http://digitalmediaphd.wordpress.com/2010/03/24/the-double-slide-controller-by-tomas-henriques/">Thomas Henriques Double Slide Controller</a>. The basic construction is pretty simple, and involves:<br /><br /><ul><li>A piece of 1/8" x 1 1/2" x 36" aluminum stock (Home Depot) - the substrate for the "trombone slide"</li><li>A 24" x 2" piece of plexiglass (<a href="http://www.tapplastics.com/">Tap Plastics</a> - a 15 minute walk from my house) - the bearing surfaces of the "slide"</li><li>A 5" x 3" piece of plexiglass, that holds:</li><li>Two 3/4" x 2 3/4" blocks of teflon, which I shaped with a router, and ride along the long plexiglass piece. These are equivalent to the outer parts of the "slide"</li><li>A repurposed joystick controller, which the player holds in his/her right hand. The controller handle is used to move the "slide", but also has 5 buttons that control overtone selection and a slide quantization mode (I'll explain that later). The buttons were epoxied into holes drilled into the joystick handle.</li><li>A project box that contains a Freescale pressure sensor, and all the wiring interconnects.</li><li>A "mouthpiece" that allows the performer to blow into the pressure sensor.</li></ul>To set the stage, here's a little video that shows how the instrument is held, and how the slide moves:<br /><br /><br /><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dx7W359Vlh8AVu7HRfk0W_AF3jxhD1kqPlZDSMduRtseVEa9dcySeatNkxo45YXD0Ba4TXhnSyTmBXMWeN6hw' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br /><br /><span style="font-weight: bold;">Sensors</span><br /><br />There are three types of sensors on the instrument:<br /><br /><span style="font-weight: bold; font-style: italic;">Breath</span> is detected via a Freescale pressure sensor. In the photo below, the mouthpiece (the clear plastic vinyl tubing that the player blows into) is connected to a box with some 1/4" tubing. The box contains the pressure sensor, along with the other wiring interconnects. At the top of the mouthpiece, there is a "T" connector that allows half of the airflow to exit (so the player feels like s/he is blowing through the instrument) and the rest goes to the pressure sensor. The Arduino code reads the sensor and produces MIDI Breath Controller data.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TAnXq0pOQUI/AAAAAAAABUo/bMS2Uo5gFU8/s1600/L1010317.JPG"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_c_W4p2Ok5c0/TAnXq0pOQUI/AAAAAAAABUo/bMS2Uo5gFU8/s400/L1010317.JPG" alt="" id="BLOGGER_PHOTO_ID_5479147552358940994" border="0" /></a><br /><br /><br /><span style="font-weight: bold; font-style: italic;">Slide Position</span> is detected with a SpectraSymbol 500mm SoftPot linear potentiometer. The SoftPot is adhered to the aluminum stock using the adhesive backing provided with the SoftPot. The aluminum stock is screwed to a slightly wider piece of plexiglass. A mechanism slides along the edges of the plexiglass. The bearing surfaces are made of teflon block. I cut a groove in two pieces of the block using a router, and these grooves line up with and ride along the plexiglass, as shown below.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_c_W4p2Ok5c0/TAnZE9SDCRI/AAAAAAAABUw/GTQ_HuTKkJk/s1600/L1010313.JPG"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_c_W4p2Ok5c0/TAnZE9SDCRI/AAAAAAAABUw/GTQ_HuTKkJk/s400/L1010313.JPG" alt="" id="BLOGGER_PHOTO_ID_5479149100865882386" border="0" /></a><br /><br />In the middle of the clear block, you can see what appears to be a setscrew. This is actually a stylus that is manufactured by SpectraSymbol. You can't see it in the photo, but the end of the screw is a small nylon stylus that rides on a small spring that provides a constant force. This makes the pressure on the SoftPot very consistent, which means the slide behavior is very predictable.<br /><br />The Arduino code reads the slide position and computes the appropriate pitch bend to send. My most recent firmware also includes a mode where the slide positions are quantized - in effect, the slide "clicks into position" automatically. Although a glissando isn't possible with this setup, the instrument's notes are always in tune. The slide quantization mode can be toggled on and off using the thumb of the right hand (there was a spare button on the joystick handle that was perfect for that).<br /><br />A future enhancement I'm considering is providing an LED on the instrument that lights up when the player has the slide in one of the seven positions (well, actually, within a certain range of the dead-on position). Trombonists are used to reaching out to touch the bell to gauge where 3rd position is; this LED would do the same thing, but for all seven positions.<br /><br /><span style="font-weight: bold; font-style: italic;">Overtone Selection</span> is accomplished via a set of four switches on the handle that the player uses to move the slide. Here's a picture of the handle:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_c_W4p2Ok5c0/TAnad0S4GHI/AAAAAAAABU4/_ehgtEJZTSg/s1600/L1010316.JPG"><img style="cursor: pointer; width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_c_W4p2Ok5c0/TAnad0S4GHI/AAAAAAAABU4/_ehgtEJZTSg/s400/L1010316.JPG" alt="" id="BLOGGER_PHOTO_ID_5479150627461798002" border="0" /></a><br /><br />The handle is a repurposed joystick, with some momentary switches epoxied into some (very crudely drilled) holes I made in the handle. The "trigger" button is actuated with the index finger, and the remaining buttons are operated with the second, third, and fourth fingers. By using a simple "chording" method, the player can select any one of eight overtones:<br /><br /><span style="font-family:courier new;">Overtone 0: off off off off</span> <span style="font-family:courier new;"><br />Overtone 1: on off off off</span><br /><span style="font-family:courier new;">Overtone 2: on on off off<br /></span><span style="font-family:courier new;">Overtone 3: on on on off<br /></span><span style="font-family:courier new;">Overtone 4: on on on on<br /></span><span style="font-family:courier new;">Overtone 5: off on on on<br /></span><span style="font-family:courier new;">Overtone 6: </span><span style="font-family:courier new;">off off on on</span><br /><span style="font-family:courier new;">Overtone 7: </span><span style="font-family:courier new;">off off off on</span><span style="font-family:courier new;"></span><br /><br />Now, only 8 overtones is not really enough to make a trombone player feel at home (most accomplished players can produce at least 10), so I need to think about this some more, but 8 overtones does give me enough range to play stuff that's interesting.<br /><br />Here's a short video of me playing a little improvisation on the instrument. I still have some work ahead of me to produce a patch that makes the instrument play well. The patch you're hearing is one I built for the ES2 FM synth that comes with Apple Logic Express.<br /><br /><br /><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dzk2-yO_Q1-mVU6rRZZQaFyK8kZ8VJFMN2-Rug0EyD2Sr8iASdX4l1P73LYmPicLRThlnEM_4NXTUbwGT5uNA' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br /><br /><br />I have to say that, while the instrument is still pretty glitchy, I'm starting to feel like it's possible to be expressive with it. I'm also feeling like the instrument is pretty consistent; it behaves predictably, which allows me to practice a musical passage, get it right, and then to be able to perform it in a repeatable fashion.<br /><br />Finally, as a point of comparison addressing the expressiveness of the instrument, here's an improvisation in the same vein, but on my trombone.<br /><br /><br /><br /><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dwX2tzNvuP9kxfFIbP7dSxnmJAP3YDxJBkhJU7hq3qT3NWBQZ_NP7VyR3Me_hI2SzcT4naUItD7Uj9chaJehg' class='b-hbp-video b-uploaded' frameborder='0'></iframe>Gordon Goodhttp://www.blogger.com/profile/02789377236535400196noreply@blogger.com3