Go Down

Topic: MIDI Library Reading Pitch Bend (Not Send) (Read 5721 times) previous topic - next topic

Cynosure

I am trying to use the Arduino as a midi adapter for a synth, but I have an issue with the pitch bend.

I can get it to read pitch bend and change a value, but it only reads the change in one direction. If I release the bend wheel then my value stays at the raised level. If I raise the bender again, then the value keeps climbing up.

Are there any examples of how to read pitch bend values using the MIDI library and have it reset the value when the bender returns to the middle position?

Also, does anyone happen to have the math required to change pitch bend value to a frequency based on the original note so that the max pitch bend is always raised by just two semitones? That seems to be the standard for pitch benders.

el_supremo

If you slowly return the wheel to its normal position does the program see it sending values?
How do you get the program to reset to the normal value (zero?) once it is high?

I think this is a software problem. Post your code.

Pete
Don't send me technical questions via Private Message.

Cynosure

Here is the code.

http://pastebin.com/uxU7W6C2

I will give an explanation of what I am trying to do.

I use the Tone library to play three different tones.

I am using the MIDI library to read MIDI notes. When a MIDI note is read, the code sets the frequency for the three different tones.

Now I am trying to add in something to read the pitch bend. I want it to work like it usually does on a synth (bends up or down two semitones, returns to 0 when released, if the pitch bend is held then the next note pressed starts the tone with the bent pitch value, if you increase it to full and lower it halfway back down then the frequency of the tones follow it up to two semitones and back down to one semitone).

I was trying to reset it to 0 using the else{bend = 0;} in the HandlePitchBend function.

Next will be reading MIDI clock and sending out ON/OFF pulses.  I hope that is possible too.

Thanks for your help.

el_supremo

I think your problem lies in this piece of code:
Code: [Select]
  if (bend != 0) {
    bendfreq = bend/1000;
  }
  else {
    bendfreq = 0;
  }

if bend is the value from the midi message, it can only be a value from zero to 127. That means that the result of bend/1000 is always zero because it is an integer division.
You really don't need the if statement either. If bend is zero then bend/1000 is also zero. You can replace the whole if statement with:
Code: [Select]
bendfreq = bend/1000;

Pete
Don't send me technical questions via Private Message.

el_supremo

#4
Aug 01, 2012, 04:14 am Last Edit: Aug 01, 2012, 04:18 am by el_supremo Reason: 1
BTW. You would find your code a lot easier to manage (and much smaller) if you used arrays for the frequency values.
Declare these arrays as global and fill in the remaining values:
Code: [Select]
const long f1[128] = {
65, 69 73, ... etc.
};
const int f2_a[128] = {
10, 11, 11, 12, ... etc
};
const int f2_b[128] = {
10, 10, 11 ,11, ... etc.
}
const int f3[128] = {
12, 13 ,14 , 14, ... etc.
}


and then remove the entire switch statement and replace it with this:
Code: [Select]
     freq1 = f1[note];
     if (thirdSwitch == HIGH) {
      freq2 = f2_a[note];
     } else {
       freq2 = f2_b[note];
     }
     freq3 = f3[note];
     if(note == 0)digitalWrite(ledPin,HIGH);


Pete
Don't send me technical questions via Private Message.

Cynosure

Thanks for the advice. That should shorten up my code a lot.

From the MIDI library info I read, it says that the pitch bend values go from -8192 to 8191. I added the divide by 1000 because at first the pitch was bending way too much. 1000 isn't the correct value though. I think I need to do some math the get the correct value based upon the current frequency of tone that is being played.

I will give this stuff a try this week.

Cynosure

Why did you add this to the bottom of the last bit of code?
Code: [Select]
if(note == 0)digitalWrite(ledPin,HIGH);

that pin is being used for an inverted trigger pulse that will trigger an external envelope circuit.

Cynosure

I tried your code changes but the notes no longer work. It looks like it should, but it just doesn't.

Maybe I am missing something.  Here is the code I tried to use:

http://pastebin.com/1xBfSqQ2

el_supremo

Quote
Why did you add this to the bottom of the last bit of code?

That was in "case 0" of your original code so this will only execute the digitalWrite if the note is zero.

I'm looking at the new version to try to find out why it doesn't work.

Pete 
Don't send me technical questions via Private Message.

el_supremo

There was a problem in your original code. From case 96 onwards you set f1 to values which are too large to store in a 16-bit integer. That is why I declared f1 to be "const long" but this might change the behaviour of the program. Try changing the declaration of f1 to be "const int f1"

Pete
Don't send me technical questions via Private Message.

Cynosure

You were correct about the long/int thing.  Changing it to int made the code work.

However, the pitch bend is still behaving the same. It is as though it only registers positive changes above 0 and negative changes below 0. Is midi code not sent as a pitch bender goes back to the middle position? Is this a flaw in the MIDI library or my code?

el_supremo

The MIDI spec on the web says that pitch bend is sent as a 14-bit number (the low order 7 bits of two successive bytes) and the middle of that range (8192) represents the pitch bend in its centred position.
The spec for my synthesizer (SY77) says it only sends a 7-bit number. I haven't got it hooked up right now so I can't test it further.
I'd suggest you write a simple test sketch which just reads pitch bend values and prints them out so that you can see what you're getting.

Quote
You were correct about the long/int thing.  Changing it to int made the code work.

That means that the higher frequencies can't be generated correctly. In your original code, the tones from case 120 and above can't be represented in a 16-bit integer so they will wrap around. The 66976Hz in case 120 will actually generate a tone of 1440Hz.

Pete
Don't send me technical questions via Private Message.

Cynosure

Thanks for all the help with this.  Some really nice folks in a chat room helped me figure it out.

This is the code I needed in the function to handle the bend:

Code: [Select]
  tone1.play(freq1 + bendfreq);
  tone2.play(freq2 + bendfreq);
  tone3.play(freq3 + bendfreq);


I was modifying the frequ variable and adding to them instead of just changing the frequency being played.

el_supremo

That is essentially what you were doing in the original version. But if it's working now, that's excellent  :)

Pete
Don't send me technical questions via Private Message.

sammyg

Pointer; you probably want to multiply your frequencies by the bend amount, not simply add, otherwise you'll end up with varying bend ratios for different notes. (The relationship between pitch and frequency is geometric, e.g. an octave is a doubling / halving)

Go Up