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 :)