Digital harmonica

Status
Not open for further replies.

RICHIE888

Member
Hi , i'm struggling a bit trying to get the Teensy 3.2 to trigger a sensor. I'm using an optical slotted sensor H22A1. This operates by blocking the slot, it switches the on state to an off. The other sensor in use is a pressure sensor, this part works fine with the code listed below. The optical sensor is giving me grief. I have recently swapped over from using the arduino to the Teensy. I managed to get this working using the Arduino.

The idea is to use the pressure sensor to deliver the expression values, then this will be used alongside the optical sensor which will trigger midi notes on or off.
I'm new to the coding and what I have here is bits and pieces from other examples. Can anyone see where i'm going wrong. Cheers

The outlook is to have twenty optical sensors available to play alike the harmonica. Any help will be welcome.:confused:

(some of this code is taken from Gordophone website regards his breath instrument........Cheers for that)
#define EXPRESSION_CONTROLLER 11
#define MIDI_CHANNEL 1
// Send continuous controller message no more than
// every CC_INTERVAL milliseconds

#define CC_INTERVAL 20

// Only send CC data if the pressure sensor reading
// a value larger than this.

#define BREATH_THRESHOLD 110

// The last time we sent a CC value

unsigned long ccSendTime = 0L;

// The value read from the sensor

int sensorValue;

// The CC value we will send

int ccVal;
// The last CC value we sent

int lastCcVal = 0;

int buttonPin = 7; // Slot sensor input


boolean currentState = LOW;//stroage for current button state
boolean lastState = LOW;//storage for last button state


void setup() {

pinMode( 7,INPUT_PULLUP);// set the pin as INPUT /// also tried putting this to six in case 0 was one and six was seven input


// Nothing to initialize for this sketch
}

void loop() {

if (millis() - ccSendTime > CC_INTERVAL) { // Only read the sensor if enough time has passed

sensorValue = analogRead(A0); // read the input on analog pin 0
if (sensorValue > BREATH_THRESHOLD)
{
// Map the value, which may range from BREATH_THRESHOLD
// to 1023, to a value in the range 0 to 127, which is
// the valid range for a MIDI continuous controller
ccVal = lastCcVal = map(sensorValue, BREATH_THRESHOLD, 1023, 0, 127);
// And send the value as a MIDI CC message
usbMIDI.sendControlChange(EXPRESSION_CONTROLLER, ccVal, MIDI_CHANNEL);
ccSendTime = millis();
delay(2);
}
else if (lastCcVal > 0)
{
// The pressure has just dropped below the threshold, so
// send a CC value of zero
usbMIDI.sendControlChange(EXPRESSION_CONTROLLER, 0, MIDI_CHANNEL);
ccSendTime = millis();
lastCcVal = 0;
delay(2);


currentState = digitalRead(buttonPin);
if (currentState == HIGH && lastState == LOW){//if button has just been pressed
usbMIDI.sendNoteOn(60, ccVal, MIDI_CHANNEL);//turn note 60 on with 127 velocity // I used ccVal as the velocity to register the values from the press sensor

delay(2);//crude form of button debouncing
} else if(currentState == LOW && lastState == HIGH){
usbMIDI.sendNoteOff(60, ccVal, MIDI_CHANNEL);//turn note 60 off
delay(2);//crude form of button debouncing
}
lastState = currentState;
//Serial.println(val);
}

}
}
 
Does the digital signal from the sensor bounce? If so.. why not use the BOUNCE object library?

You don't really say what the 'trouble' is.


...In future could you use the CODE tags ('Go Advanced' option)? It's much easier to read as it mono-spaced and it retains space-indents.
 
Last edited:
Hi Oddson thanks for the response, i'm not sure what you mean re Code Tags ( never used this before) . As regards the Harmonica I haven't used the bounce option as I thought that was in relation to a pressed state of a button. The optical slotted sensor only needs something to enter the slot this breaks the beam and it turns the state from on to off. The problem I am having is trying to get a midi message sent when the optical sensor becomes triggered. I think it is the way I have written the code. Is there specific code I need to use which differs from code used in Arduino, ive seen that the USBMidi code is used to replace midi commands ive used previously in Arduino.

When I put something in the gap of the slotted sensor it should trigger for a midi note to play, when I remove the item from the sensor it should stop the midi note. That's all i'm looking to achieve at this time. Cheers.
 
Code tags are available from the 'go advanced' features - next to the quote bubble with a # sign on it...

Since I'm not at my Arduino/Teensy IDE machine I took your loop() function and recreated the indenting so I could read the logic...

Looks like you are only firing your digital stuff in the an 'else if' section that will only run ONCE when the analog threshold value is no longer met.
Code:
void loop() {
	if (millis() - ccSendTime > CC_INTERVAL) {
		sensorValue = analogRead(A0); 
		if (sensorValue > BREATH_THRESHOLD) {
			ccVal = lastCcVal = map(sensorValue, BREATH_THRESHOLD, 1023, 0, 127);
			usbMIDI.sendControlChange(EXPRESSION_CONTROLLER, ccVal, MIDI_CHANNEL);
			ccSendTime = millis();
			delay(2);
		} else if (lastCcVal > 0) {
			usbMIDI.sendControlChange(EXPRESSION_CONTROLLER, 0, MIDI_CHANNEL);
			ccSendTime = millis();
			lastCcVal = 0;
			delay(2);
[COLOR="#FF0000"]			currentState = digitalRead(buttonPin);
			if (currentState == HIGH && lastState == LOW){
				usbMIDI.sendNoteOn(60, ccVal, MIDI_CHANNEL);
				delay(2);
			} else if(currentState == LOW && lastState == HIGH	{
				usbMIDI.sendNoteOff(60, ccVal, MIDI_CHANNEL);
				delay(2);
			}
                        lastState = currentState; [/COLOR]
		}
	} 
}

You would have to move the code to the outermost section of the loop -- two levels out from where it is now...

Then I would think you want to test whether the breath controller is over it's threshold and make that part of the logic on whether to send the note-on or not.

I think you want that test IN PLACE OF the lastState==LOW condition since the sensor might be on before the threshold is reached (you don't want to make the note-on conditional on the switch just having changed like you do for a keyboard; but I understand you want to get it working like a regular key-switch first).

You may find the sensor isn't as bounce free as you think... and you may want a better analog taming routine as reading voltage signals always contains some noise.

Good luck.
 
Last edited:
Thanks for that insight , really appreciate the help, I rejigged some of the code and trialled the midi notes on their own, and then the pressure sensor. (i'm using two optical sensors and the pressure sensor now). Managed to get it working but like you said ive got some noise coming through on one of the sensors. Well im guessing its noise because when I trigger one of the optical sensors, it is silent until I blow through the pressure sensor, the volume adjusts as required. The other optical sensor has a slight volume on it before I begin blowing the pressure sensor. I'll take your advice though and trial it. Next stage is to add more sensors on it.

:) Cheers for taking the time
 
Well im guessing its noise because when I trigger one of the optical sensors, it is silent until I blow through the pressure sensor
Isn't that what it's supposed to do?


If you want to post your current code (in [CODE] [/CODE] tags!) I'd be happy to have a look.

That doesn't sound like noise (on the analog) or bounce (on the digital sensor).
 
Last edited:
Code:
#define MIDI_CHANNEL 1
#define EXPRESSION_CONTROLLER 11
#define CC_INTERVAL 20// Send continuous controller message no more than every CC_INTERVAL milliseconds
#define BREATH_THRESHOLD 110// Only send CC data if the pressure sensor reading a value larger than this.

unsigned long ccSendTime = 0L;  // The last time we sent a CC value
int sensorValue; // The value read from the pressure sensor
int ccVal; // The CC value we will send
int lastCcVal = 0; // The last CC value we sent


int buttonPin = 23; // Slot sensor input
int buttonPina = 22; // 

boolean currentState = LOW;//stroage for current button state
boolean lastState = LOW;//storage for last button state
boolean currentState1 = LOW;//stroage for current button state
boolean lastState1 = LOW;

void setup()

{
pinMode(22,INPUT_PULLUP);
pinMode(23,INPUT_PULLUP);// set the pin as INPUT
  // Nothing to initialize for this sketch
}

void loop () {

   if (millis() - ccSendTime > CC_INTERVAL) { // Only read the sensor if enough time has passed
   
        sensorValue = analogRead(A0);  // read the input on analog pin 0
        if (sensorValue > BREATH_THRESHOLD) 
        {
      // Map the value, which may range from BREATH_THRESHOLD
      // to 1023, to a value in the range 0 to 127, which is
      // the valid range for a MIDI continuous controller
       ccVal = lastCcVal = map(sensorValue, BREATH_THRESHOLD, 1023, 0, 127);
      // And send the value as a MIDI CC message
       usbMIDI.sendControlChange(EXPRESSION_CONTROLLER, ccVal, MIDI_CHANNEL);
       ccSendTime = millis();
       delay(2);
        } 
      else if (lastCcVal > 0) 
       {
      // The pressure has just dropped below the threshold, so
      // send a CC value of zero
      usbMIDI.sendControlChange(EXPRESSION_CONTROLLER, 0, MIDI_CHANNEL);
      ccSendTime = millis();
      lastCcVal = 0;
      delay(2); }

 currentState = digitalRead(buttonPin);
  if (currentState == HIGH && lastState == LOW)
  {   //if button has just been pressed
   usbMIDI.sendNoteOn(60, ccVal, MIDI_CHANNEL);//turn note 60 on with 127 velocity
  }
  
   else if(currentState == LOW && lastState == HIGH){
    usbMIDI.sendNoteOff(60, 0 , MIDI_CHANNEL);//turn note 60 off
    delay(2);//crude form of button debouncing
  }
  lastState = currentState; 

 currentState1 = digitalRead(buttonPina);
  if (currentState1 == HIGH && lastState1 == LOW)
  {   //if button has just been pressed
   usbMIDI.sendNoteOn(66, ccVal, MIDI_CHANNEL);//turn note 60 on with 127 velocity
  }
  
  else if(currentState1 == LOW && lastState1 == HIGH){
    usbMIDI.sendNoteOff(66, 0 , MIDI_CHANNEL);//turn note 60 off
    delay(2);//crude form of button debouncing
  }
  lastState1 = currentState1; 
}
   }
 
R.E. Isn't that what it's supposed to do?

Yes it is, the midi note will be triggered and is silent until the pressure sensor values change it. One optical sensor trigger seems to work that way, the other has a low level of volume.

Thanks for looking Oddson
 
...the midi note will be triggered and is silent until the pressure sensor values change it. One optical sensor trigger seems to work that way, the other has a low level of volume.
If the note messages are just gates then wouldn't you just send a constant for the velocity (127 or 99?? -- really anything other than zero).

You have all your code nested inside what is basically a 20-ms delay (as well as several in-line delays) ...I don't know that this is 'breaking' anything but it's not really efficient.

I suspected it was essential to make the analog play nice... but I don't think it's your friend on the digital part.

But the thing is what you are actually building is a standard MIDI controller for one potentiometer (or any voltage source) and N 'switches' (in your case digital sensors).

If the CC message is controlling the volume then the only thing that's different than stock is mapping inputs below some threshold to zero.

I recently made an example sketch posted here: https://forum.pjrc.com/threads/42479-simple-midi-contoller?p=136016&viewfull=1#post136016

I plan on building a step by step tutorial so the arrays and trickier bits are introduced slowly... but I've not started yet.

If your keen on building your own bit by bit you could have a look at post 7 from the same thread where I discover how to use the excellent ResponsiveAnalogRead library that will produce a MIDI friendly CC data stream. There are other techniques too (search 'hysterisis' and/or 'dead-band' for more info).

...gotta run... I'll have a closer look tonight.
 
// If the note messages are just gates then wouldn't you just send a constant for the velocity (127 or 99?? -- really anything other than zero).

The thinking was to control the midi note using the values form the pressure sensor, As I blow forward it will (somehow) force a capsule to trigger the optical sensor presenting the note on. The pressure sensor (hopefully) will act as my breath expression. I believe if I sent a constant value the volume will remain the same throughout. The idea is to make it change as in various breath expressions, that way you can perform a quiet or a loud note.

//You have all your code nested inside what is basically a 20-ms delay (as well as several in-line delays) ...I don't know that this is 'breaking' anything but it's not really efficient.


As you can see my coding skills are rank but I try lol.......Parts of the code have been taken from other authors, if I can make it work its a bonus. However your guidance is noted cheers.

Ill get a look into they links you've sent see if I can sharpen things up a bit.

Cheers appreciate much a gratas
 
I believe if I sent a constant value the volume will remain the same throughout.
I think we may be talking at cross purposes... please make sure to discuss the MIDI parameters: CC and velocity; neither of which are 'volume' unless you use them as such. I have no clue about the sounds you are making... so let's talk MIDI only as much as possible :)

If you are tracking volume solely by current pressure level then you don't need a variable velocity value to be sent with the note-on.

(It will normally but just above the threshold anyway unless the note on is triggered by the mechanical action but the velocity is read from the ccVal after a little time has passed --which is similar to what you do when 'debouncing' anyway so there may be a solution here if velocity is important). But I don't think you NEED it to start and for now it's a complication you can avoid (it would really only come in handy if you're changing the way the sound evolves based on how fast the note was blown at the outset..)

If you have not yet got the mechanism to block the light-sensor than the timings you get from manually blocking while blowing the breath-sensor will be unlike the real behaviour... it may be you've let up on the breath a bit by the time you trigger the second sensor and so its sounding at a lower volume (if you have your sound generator set to play proportionally to velocity).

But again... we should be talking strictly of MIDI messages...
 
Yea some chewy stuff to think about there for me.... So regards this

//(It will normally but just above the threshold anyway unless the note on is triggered by the mechanical action but the velocity is read from the ccVal after a little time has passed --which is similar to what you do when 'debouncing' anyway so there may be a solution here if velocity is important).

One of the objectives for the project is to attempt a similar playing style as of a harmonica. I have the twenty notes pre recorded and this plays back in Kontact or pro tools. Triggering the sensors will put the note on and maintain the note play until I release a breath, this gives note duration. The pressure sensor is required to present midi values to provide expression control change (not velocity my mistake earlier).

I'm aware that there will be a slight delay upon the midi note being played and the analogue values converting to a midi representation (from the pressure sensor). Also whilst doing it manually will be inaccurate (gotta start somewhere though eh lol).


But i'll play around and see how it goes, cheers for the insight really appreciate that. Ill give a message upon the next movement.
 
So is the physical hardware settled?

I wonder if reeds fashioned from piezo discs or sheet could give you note-by-note signals?

Not pitch... the position would do that, but an envelop follower could track as a proxy for intensity/loudness... so the notes getting most the air could sound louder than its neighbors.
 
Last edited:
Yea that would be interesting, not sure how you would go about it . Times running out for this project though needs to be surrendered in two weeks so I can only work with what I have. Ill continue to work with it as its something id like to complete. I saw a chap use the reeds and plate on the harmonica wired up in such a way to turn use a capacitance type effect. He removed the reeds done something to them and put them back on. He was then able to connect this up to play out of a speaker...here its here

http://www.instructables.com/id/Electric-Wurlitzharmonica/

Bit rough but love the effort. Is this similar to what the idea you were thinking ?

I'm wondering if you're clued up with using one of the touch pins to control a pitch movement. I was thinking if that touch control could be attached to a spot on the harmonica, I could activate a slight pitch bend to replicate a bent note. I'm aware that midi has a message for pitch control for MSB and LSB. But you'd only need a slight pitch bend probably not the full response as such on a keyboard. Any idea how that could be done. I had a look at that code you had wrote for the various analogue and digital pins, bouncing and read h files, awesome that's going to come in handy if you don't mind me applying it to use.
 
Status
Not open for further replies.
Back
Top