Go Down

Topic: Capacitive sensing for a paper piano (Read 677 times) previous topic - next topic

jaggions

Aug 01, 2015, 03:16 pm Last Edit: Aug 01, 2015, 03:17 pm by jaggions
Hi. I'm trying to create a MIDI keyboard from a conductive ink drawing on a piece of paper. I have a problem with capacitive sensing: here is the code I wrote until now (it is limited to the first note of the piano, F1).

Code: [Select]
#include <CapacitiveSensor.h>
#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>

MIDI_CREATE_DEFAULT_INSTANCE();
CapacitiveSensor  F1 = CapacitiveSensor(2,3);

void setup() {
  F1.set_CS_AutocaL_Millis(0xFFFFFFFF);
  MIDI.begin(1);
  Serial.begin(115200);
}

void loop() {
 long start = millis();
 long F1button =  F1.capacitiveSensor(30);
  if (F1button > 1000) {
    MIDI.sendNoteOn(29, 80, 1);
 }
}


The code actually works: if I touch pin 3 on the Arduino, the MIDI software plays the F1 note on the piano. However since the code runs as a loop, if I hold the pin, the note keeps replaying from the beginning until I stop touching the pin. I have attached a small audio file to help you understand this.

I'd need some way to make the Arduino ignore a key if it's already pressed and - possibly - also a way to stop playing the note as soon as the finger is lifted from the button. So that if I touch pin 3, F1 starts playing once until I stop touching pin 3.

Thank you very much for your help.

DrDiettrich

You have to remember the button state, so that you can detect state changes. You also have remember the time of the sound activation, so that you can find out when to stop the sound.

From a state machine view you have 3 states: not_pressed, sound_started, sound_timeout.
When you write down these states as a diagram, add arcs for each condition where the current state should change. I.e. if not_pressed, and the button is pressed, switch to sound_started and start the sound at the same time, and remember the start time. If sound_started, and the button is not pressed any more, switch back to not_pressed and turn off the sound. If sound_started and the current time exceeds the start time by the maximum sound length, switch to sound_timeout state and turn off the sound. If sound_timeout and the button is released, switch to not_pressed.

If you add more buttons, replicating above code for each button is not a good idea. Then you have to remember which button was pressed, and add transitions (arcs) for the case that a different button is pressed.

jaggions

You have to remember the button state, so that you can detect state changes. You also have remember the time of the sound activation, so that you can find out when to stop the sound.

From a state machine view you have 3 states: not_pressed, sound_started, sound_timeout.
When you write down these states as a diagram, add arcs for each condition where the current state should change. I.e. if not_pressed, and the button is pressed, switch to sound_started and start the sound at the same time, and remember the start time. If sound_started, and the button is not pressed any more, switch back to not_pressed and turn off the sound. If sound_started and the current time exceeds the start time by the maximum sound length, switch to sound_timeout state and turn off the sound. If sound_timeout and the button is released, switch to not_pressed.

If you add more buttons, replicating above code for each button is not a good idea. Then you have to remember which button was pressed, and add transitions (arcs) for the case that a different button is pressed.
I understand what you're saying, but I really don't know where to start. Could you write me some example code so that I know how to do that? That would be really appreciated. Thank you so much.

Grumpy_Mike

Quote
Could you write me some example code so that I know how to do that?
Arduino IDE, then
File -> examples -> 02 Digital -> StateChangeDetection

You already have an example

DrDiettrich

I prefer an enum for the states, then a
Code: [Select]

  switch (State) {
    case not_pressed: ...
    ...
  }
to do what's necessary for the current state.

Go Up