As promised this is the second part of the project "How to turn Toy piano into Midi keyboard" and in this series we are adding velocity sensitivity to the keyboard. In fact as a bonus we will add an aftertouch effect as well.
The most common implementation of Velocity sensing is done by measuring the time it took to press the key - in a way measuring the speed and converting it to a volume. Usually it is done by using two push buttons on each key of the keyboard. Pressing individual key on the keyboard will produce two ON events with some small time difference. The first ON event register when the key is just being pressed and second when the key is completely pressed. Based on the time difference between two events micro-controller calculates how fast the key was pressed. The time difference correspond to volume of the key: long time - soft volume and short time - loud. Read more about it here.
After some consideration I've decided to implement Velocity control slightly different from common approach and used Force Sensitive Resistor (FSR) sensors. This method will measure the actual force that is applied to the key instead of how fast the key is pressed. When the note is pressed Arduino will read analog value from FSR and assign volume to a note. In my view this approach is closer to original piano hammer action design: different force applied to a key triggers the hammer to hit the string with different force producing softer or louder sound.
The FSR I've got was from Interlink 24" long sensor which was perfect for the project. It is available from major shops as SparkFun, LittleBird.
One of the challenge was to find place to install FSR on the keyboard so when the keys are pressed it will just gently touch FSR and apply force that will cover sensing range of FSR. I've tried several locations and the one gave me best results is displayed in the picture below. I've put a leveling foam and double sided tape to raise the FSR bus. Base on the keyboard you are hacking you may be more lucky and it may all fit naturally without need to level it. At the same time look into using less bending materials as it all decreases precision of the end result.
As you can see on the above picture, FSR sensor was cut into 4 pieces to implement separate velocity/aftertouch sensing for 4 channels (see my previous small post on how you can cut FSRs and add connectors). 4 separate channels cover each 8 notes of the keyboard and allow playing different parts of the keyboard simultaneously (two hands) while producing sound of different volume and sensing aftertouch for each channel. Each FSR channel was mapped to a separate MIDI channel. This allows you to set each of the channels to play different instrument or combination of different instruments to have a split keyboard effect e.g. base, drums, lead or base, lead or other combination...
Another challenge I had was black keys had not sufficient length to reach the FSR sensors. I had to extend all black keys and glued a short "leg" to each key so when the key gets pressed it is able to reach FSR and applies similar pressure as white keys. I've glued to the black keys end about 1cm of the hard plastic straw. When you choose straw or any similar material you will need to make sure it is made of hard plastic and does not bend much when you press it. Also remember that you may need to cut the straw later to adjust the length. You could combine it with some sort of silicone glue at the end of straw so it is easier to cut when you tuning the keyboard. White keys already had sufficient length to reach the FSR sensor.
There were minor schematics changes from previous post. Below is updated breadboard diagram. Please note 4 FSR sensors were added at the bottom and connected to 2,3,4,5 Analog inputs:
Modified code to add Velocity sensing and aftertouch is below:
The code is quite similar to what it was before. Several things I'd like to explain.
1) Measuring Velocity sensitivity required to add timing mechanism to allow sufficient time to read the FSR sensor as Note will get pressed first and FSR sensor second. So before we can send the note we need to measure the FSR values. To implement this two arrays were introduced: one remembers the Note that was pressed and acts as a buffer: noteChannelPressed and second remembers the milliseconds when the note was pressed: previousMillisChannel. After a delay of about 1 ms value of FSR is translated to a volume. (currently linear translation is done by simple mapping the range of FSR to MIDI but you can experiment and see what suits most your FSR/location/mechanics, etc). And after that note with volume is sent to Midi. The functions implementing above are getNote() and sendChannelNotes()
2) Aftertouch was implemented (as well) based on FSR readings and handled by sendChannelExpression(). Effect is only kicks in after 1 second which is configured in expressionDelay constant. As aftertouch effect I've used midi modulation command as it is widely supported by all synth. It can be map to any other effect that your synth support.
Pretty simple isn't it? :)
Yeah... FSRs rock!
Concluding the post FSR worked out to be a good way to implement velocity sensing and after touch. The limitation of design is velocity and after touch works base on channel (4 channels, each channel of 8 notes). Thus notes played on the same channel simultaneously will produce similar volume (e.g. chord) - which is fine by the way. And notes played on the same channel at different times will register different volume - which is expected. You need to remember that channel has 8 sequential notes that you unlikely will press at the same time unless you playing a chord or some harmonic melodies of the same volume. 4 channels are spread across keyboard and allow to play compositions with two hands . So one hand can play soft chord and second louder say melody. I'd say most of the compositions (except for some sophisticated pieces) are playable on the keyboard.
And one of the challenges was mechanics of the keyboard. If you able to use any solid materials to strengthen the keyboard / to prevent it from bending you are likely to have more consistent sound across all keys.
Based on results I am quite interested to explore complete analog solution that will utilize FSR sensors for each key... This will reduce requirements to mechanics, allow different velocity per key than channel... So stay tune :)
The most common implementation of Velocity sensing is done by measuring the time it took to press the key - in a way measuring the speed and converting it to a volume. Usually it is done by using two push buttons on each key of the keyboard. Pressing individual key on the keyboard will produce two ON events with some small time difference. The first ON event register when the key is just being pressed and second when the key is completely pressed. Based on the time difference between two events micro-controller calculates how fast the key was pressed. The time difference correspond to volume of the key: long time - soft volume and short time - loud. Read more about it here.
After some consideration I've decided to implement Velocity control slightly different from common approach and used Force Sensitive Resistor (FSR) sensors. This method will measure the actual force that is applied to the key instead of how fast the key is pressed. When the note is pressed Arduino will read analog value from FSR and assign volume to a note. In my view this approach is closer to original piano hammer action design: different force applied to a key triggers the hammer to hit the string with different force producing softer or louder sound.
The FSR I've got was from Interlink 24" long sensor which was perfect for the project. It is available from major shops as SparkFun, LittleBird.
One of the challenge was to find place to install FSR on the keyboard so when the keys are pressed it will just gently touch FSR and apply force that will cover sensing range of FSR. I've tried several locations and the one gave me best results is displayed in the picture below. I've put a leveling foam and double sided tape to raise the FSR bus. Base on the keyboard you are hacking you may be more lucky and it may all fit naturally without need to level it. At the same time look into using less bending materials as it all decreases precision of the end result.
As you can see on the above picture, FSR sensor was cut into 4 pieces to implement separate velocity/aftertouch sensing for 4 channels (see my previous small post on how you can cut FSRs and add connectors). 4 separate channels cover each 8 notes of the keyboard and allow playing different parts of the keyboard simultaneously (two hands) while producing sound of different volume and sensing aftertouch for each channel. Each FSR channel was mapped to a separate MIDI channel. This allows you to set each of the channels to play different instrument or combination of different instruments to have a split keyboard effect e.g. base, drums, lead or base, lead or other combination...
Another challenge I had was black keys had not sufficient length to reach the FSR sensors. I had to extend all black keys and glued a short "leg" to each key so when the key gets pressed it is able to reach FSR and applies similar pressure as white keys. I've glued to the black keys end about 1cm of the hard plastic straw. When you choose straw or any similar material you will need to make sure it is made of hard plastic and does not bend much when you press it. Also remember that you may need to cut the straw later to adjust the length. You could combine it with some sort of silicone glue at the end of straw so it is easier to cut when you tuning the keyboard. White keys already had sufficient length to reach the FSR sensor.
There were minor schematics changes from previous post. Below is updated breadboard diagram. Please note 4 FSR sensors were added at the bottom and connected to 2,3,4,5 Analog inputs:
Modified code to add Velocity sensing and aftertouch is below:
The code is quite similar to what it was before. Several things I'd like to explain.
1) Measuring Velocity sensitivity required to add timing mechanism to allow sufficient time to read the FSR sensor as Note will get pressed first and FSR sensor second. So before we can send the note we need to measure the FSR values. To implement this two arrays were introduced: one remembers the Note that was pressed and acts as a buffer: noteChannelPressed and second remembers the milliseconds when the note was pressed: previousMillisChannel. After a delay of about 1 ms value of FSR is translated to a volume. (currently linear translation is done by simple mapping the range of FSR to MIDI but you can experiment and see what suits most your FSR/location/mechanics, etc). And after that note with volume is sent to Midi. The functions implementing above are getNote() and sendChannelNotes()
2) Aftertouch was implemented (as well) based on FSR readings and handled by sendChannelExpression(). Effect is only kicks in after 1 second which is configured in expressionDelay constant. As aftertouch effect I've used midi modulation command as it is widely supported by all synth. It can be map to any other effect that your synth support.
Pretty simple isn't it? :)
Yeah... FSRs rock!
Concluding the post FSR worked out to be a good way to implement velocity sensing and after touch. The limitation of design is velocity and after touch works base on channel (4 channels, each channel of 8 notes). Thus notes played on the same channel simultaneously will produce similar volume (e.g. chord) - which is fine by the way. And notes played on the same channel at different times will register different volume - which is expected. You need to remember that channel has 8 sequential notes that you unlikely will press at the same time unless you playing a chord or some harmonic melodies of the same volume. 4 channels are spread across keyboard and allow to play compositions with two hands . So one hand can play soft chord and second louder say melody. I'd say most of the compositions (except for some sophisticated pieces) are playable on the keyboard.
And one of the challenges was mechanics of the keyboard. If you able to use any solid materials to strengthen the keyboard / to prevent it from bending you are likely to have more consistent sound across all keys.
Based on results I am quite interested to explore complete analog solution that will utilize FSR sensors for each key... This will reduce requirements to mechanics, allow different velocity per key than channel... So stay tune :)
I think that the biggest challenge will be put one FSR per key with the limited number of analogic inputs. Or do you already have a solution for this?
ReplyDeleteAnd about your function to map the FSR value to the velocity value. Where did you get it? Did it needed any ajustment?
You could use analog multiplexer for this.
DeleteThe FSR value to midi velocity was tuned manually. It could be slightly different from case to case based on the FSR model, and location it is installed in the keyboard.
Instead of FSR wouldn`t be cheaper use piezoelectric sensors (http://goo.gl/04QE0) ?
ReplyDeleteYou can buy 10 piezo sensors for $3 or $4. Only one FSR sensor will cost more than that.
The challenge with piezo sensors is they will all register the knock/press (assuming you spread those across the keyboard) even you press key in specific area of the keyboard. You will have to somehow to isolate this effect.
DeleteAnd second issue is that you can't implement aftertouch as piezo sensor registers the press/knock only at the time of the knock/press and then it drops to 0 even you continue pressing it with same intensity.
is this polyphonic after-touch? (a different after-touch value for each key, so C could have vibrato for instance, while E had none, and G had a different amount than C.)
ReplyDeleteThe after-touch is only polyphonic per "channel". As you see from the post the whole keyboard subdivided into 4 areas that 4 separate FSRs are applied to. Each FSR serves a separate channel.
DeleteIt is not true polyphonic implementation but a concept that can be used to build a complete polyphonic aftertouch implementation (if you find it is necessary). If you want aftertouch per key you could allocate FSR sensor per key and read it via analog multiplexer...
Hi Biga,
ReplyDeleteI am quite new to arduino so here is my question.
I want to do a globe with fsr in every fingertip and depending on the force of the tap control the volume of the sample.
Would it be possible to change this code so I would get this result?
:S I meant Jen Shen
DeleteHi Jen, I am currently working on a design for a custom wiki-hayden hex keyboard to be made from laser cut parts. This work you have here is really intriguing!
ReplyDeleteI was wondering, if I used totally analog keys with an FSR per key, would I be able to read key presses, velocity, and aftertouch, all from the FSR's alone? Do you think this implementation would work well in practice? It seems to me it would be very similar to how a real piano works.
If you are interested, I will send you a copy of my plans when I'm finished.
Hi Jen, the working you are doing is intriguing! It seems polyphonic playing can be solved by adding more channels. But how about capturing repeated notes? I know many piano players can play a single note over a dozen times within a second. Will FSR be sensitive enough to capture that? It's analog after all... Thx!
ReplyDeleteHi Jen,
ReplyDeleteVery interesting! I am now planning to make a digital keyboard using a "real" harpsichord keyboard (i.e., one made by a professional harpsichord builder).
I am looking for an appropriate type of midi sensor system; Perhaps yours would be good for such a purpose? If you think you may be interested in a business collaboration (no need for investment on your part), please contact me:
David Bolton
dboltoncreations AT gmail.com
Have a nice day!
David
This comment has been removed by the author.
ReplyDeleteHey there :)
ReplyDeleteI have a key matrix of 8X5 (4 buses of 8 and 1bus of 4, total of 36 keys), now, do you only have 4 notes polyphonic keyboard or 8?
Do you use the chip to read the values or to send values?
that mean, I can write power only for the 5 busses (because of the diodes), and read from the 8 other pins
Moreover, I'm using teensy 3.1 and that's mean I use 3.3volts and 5volts like the Arduino Uno, so what are the resistor values I need to use for the FSR’s voltage dividers ?
thanks a head and great project :)
Hi Jen,
ReplyDeleteIs it possible to apply this idea on an acoustic piano?
Thanks
It is
DeleteMail me for explanation
Alonstudi@gmail.com
I'm trying to convert a toy piano keyboard but it uses resistors instead of diodes. I've reading about matrix reading but did not find how to read it. I'm very confused.
ReplyDeleteI posted an schematic of toy piano keyboard in:
http://i1250.photobucket.com/albums/hh526/arduinoxino/teclat_imaginarium_zpsryw8t9ac.png
Any suggerence?
Thank you very much!