Ultra noob seeking some MIDI coding help.

Status
Not open for further replies.

MrRoper

Member
Hi everybody! My name is Dan and I've been gifted a pair of Teensy LC boards from a friend. I have a big old midi controller that I use with Ableton, it feels amazing to play but has no pitch or mod wheels, so I thought I'd get the teensy to do this over USB to my DAW. I've got the mod wheel working from running the AnalogControlChange example but now I've tried to add pitchbend I'm running into trouble. I found an answer from the forums about pitchbend code so I've kinda just tried to add that to the existing analogcc one.

void setup() {
}
void loop() {
usbMIDI.sendControlChange(1, analogRead(0)>>3, 1);
delay(10);
usbMIDI.sendPitchBend(1, analogRead(1)bendVal<<7,1);

while (usbMIDI.read()) ; // read and discard any incoming MIDI messages
}

But I'm getting this come up when I try to Verify it

Arduino: 1.8.1 (Mac OS X), TD: 1.35, Board: "Teensy LC, MIDI, 48 MHz, Smallest Code, US English"

AnalogControlChange: In function 'void loop()':
AnalogControlChange:6: error: expected ')' before 'bendVal'
usbMIDI.sendPitchBend(1, analogRead(1)bendVal<<7,1);
^
AnalogControlChange:6: error: no matching function for call to 'usb_midi_class::sendPitchBend(int, int, int)'
usbMIDI.sendPitchBend(1, analogRead(1)bendVal<<7,1);
^
/Users/danknight/Downloads/AnalogControlChange/AnalogControlChange.ino:6:54: note: candidate is:
In file included from /Users/danknight/Desktop/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/WProgram.h:29:0,
from /Users/danknight/Desktop/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/Arduino.h:1,
from /var/folders/ly/hkddh0q537x3s38w6q4mg81h0000gn/T/arduino_build_215963/sketch/AnalogControlChange.ino.cpp:1:
/Users/danknight/Desktop/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/usb_midi.h:121:14: note: void usb_midi_class::sendPitchBend(uint32_t, uint32_t)
void sendPitchBend(uint32_t value, uint32_t channel) __attribute__((always_inline)) {
^
/Users/danknight/Desktop/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/usb_midi.h:121:14: note: candidate expects 2 arguments, 3 provided
expected ')' before 'bendVal'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.


I'd imagine this must be one of the simplest things you can do with a Teensy but I have zero experience in the code. I just want the modwheel on pin A0 and the pitchbend on pin A1. Can anyone help me here and/or direct me to some cool learning resources? I'd love to put the second Teensy board to good use!

I also have a question with regards to the voltage tolerance of the pins on the LC. Just to be sure I have my pots outer pins connected between 3V and G and the wiper going to its respective analog pin?

Thanks so much in advance!

Dan
 
Last edited:
Code:
usbMIDI.sendPitchBend(1, analogRead(1)bendVal<<7,1);

Remove "bendval".
I'm not sure that "<<7" is correct. A pitchBend is 14 bits and analogRead will give 10 bits so I would have thought it should be <<4 so that it doesn't overflow.

Pete
 
Hi Pete, thanks for the advice! I tried to remove bendval and change the 7 to 4 but it's still not verifying .

Code now is:
void setup() {
}
void loop() {
usbMIDI.sendControlChange(1, analogRead(0)>>3, 1);
delay(10);
usbMIDI.sendPitchBend(1, analogRead(1)<<4,1);

while (usbMIDI.read()) ; // read and discard any incoming MIDI messages
}

and the error message I'm getting is:

Arduino: 1.8.1 (Mac OS X), TD: 1.35, Board: "Teensy LC, MIDI, 48 MHz, Smallest Code, US English"

AnalogControlChange: In function 'void loop()':
AnalogControlChange:6: error: no matching function for call to 'usb_midi_class::sendPitchBend(int, int, int)'
usbMIDI.sendPitchBend(1, analogRead(1)<<4,1);
^
/Users/danknight/Downloads/AnalogControlChange/AnalogControlChange.ino:6:47: note: candidate is:
In file included from /Users/danknight/Desktop/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/WProgram.h:29:0,
from /Users/danknight/Desktop/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/Arduino.h:1,
from /var/folders/ly/hkddh0q537x3s38w6q4mg81h0000gn/T/arduino_build_215963/sketch/AnalogControlChange.ino.cpp:1:
/Users/danknight/Desktop/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/usb_midi.h:121:14: note: void usb_midi_class::sendPitchBend(uint32_t, uint32_t)
void sendPitchBend(uint32_t value, uint32_t channel) __attribute__((always_inline)) {
^
/Users/danknight/Desktop/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/usb_midi.h:121:14: note: candidate expects 2 arguments, 3 provided
no matching function for call to 'usb_midi_class::sendPitchBend(int, int, int)'

Very confused as to what's causing this, however given my total lack of knowledge in this, most things are confusing me!
 
@mrRoper. I haven't used pitch end message myself, but here is what I think is wrong. You are passing 3 parameters to the sendpitchbend function. That is what you would expect if you were looking at the docs for the standard (non-USB) midi driver library. I think that this library has issues, because the pitchbend command is 3 bytes- 1st is pitchbend command itself with the channel encoded into it. The second and third bytes are the 14-bit pitchbend value itself. But the docs say that you should send channel,note and velocity for this pitchbend command, so something is odd there.
But, you are using the USBmidi library. For that, the pitchbend function expects only 2 parameters: a 16 bit integer value for the pitchbend amount, and the channel. So, if you scale your 10-bit analog read value out to 14 bits ( using >>4) and send that as the first parameter, I think your compile error should disappear, and it should run properly.
That said, I've used USB midi lib myself several times successfully, but have not needed the pitchbend function, so I can't guarantee this.
Good luck!
 
@mrRoper: Quick correction- the >>4 should be <<4 (like you have). I was typing faster than I was thinking!
 
sendPitchBend only has two arguments. It also appears, from info right at the end of this thread, that <<7 is correct. Try:
Code:
usbMIDI.sendPitchBend(1, analogRead(1)<<7);

Pete
 
3.3 v (labled 3v on Teensy) is correct for the hot-side of the pots and then the analog ground (AGND) for the ground side. They will work on the regular ground but there should be less noise on the AGND.

There are only two parameters for .sendPitchBend -- 14 bits of data as a value (the combined 7-bit D1 and D2 values of most MIDI messages) and the channel.

'bendVal' is nothing in this sketch... I assume you were just trying anything...

If you have a 10-bit value that you need to pad to 14 bits I believe this is the code fragment (assuming you are reading analog pin A1):

usbMIDI.sendPitchBend(analogRead(1)<<4,1);

This should shift the bits to their 14-bit position (should zero the bottom four bits)...

Even if this works you would need to deal with jittery signals... there is a library routine that does this ResponsiveAnalogRead.

(I see others have answered while I pondered.)
 
Last edited:
It may be that the user who reported that <<7 worked had wired the pot so that it produced at most 7 bits of input, so the <<7 was required. If you are generating the full 10bits in the ADC, then <<4 is more appropriate.

Pete
 
sendPitchBend only has two arguments. It also appears, from info right at the end of this thread, that <<7 is correct. Try:
Code:
usbMIDI.sendPitchBend(1, analogRead(1)<<7);

Pete
only two parameters... but value is first...

the 7-bit shift was specific to the example... the person had a 7-bit to 14-bit shift in that case...
 
Thank you all so much for your help! I got it working using oddson's suggestion of

usbMIDI.sendPitchBend(analogRead(1)<<4,1);

It's now working perfectly and I'm gonna start building a box for it.
I'm away from my computer now but I can post the working code for this tomorrow if anyone's interested.

Thank you all again! Anyone have any links to good learning resources for coding?
 
Anyone have any links to good learning resources for coding?

The Harvard University or the Massachusetts Institute of Technology?

Besides of studying computer science, there is the Arduino reference and there are the code examples which come with the Arduino IDE and the Teensyduino plugin.
Going through that line by line until you understand what each of it does, from simple blink things up to complex libraries will teach you a lot. Then, there is still the 1000+ pages reference manual for each Teensy which gives detailed information about the inner hardware and how to configure and use it.
 
Hi everybody! Hope you're all well!

I've been busy making myself a little box for this pitch/ mod wheel project and I'm nearly there but I just have a few questions about pitch bend ranges and the like.

I have a second Novation 25 note midi controller that has a pitch and mod joystick and I've noticed that the pitch bend range on that is 6 semitones whereas on my box with the current code it is only a tone/ 2 semitones. My question is whether there is something in the code I can adjust to give me control of the range or is it possibly a wrong value pot? It should be fine as I'm using the whole wheels assembly from a trashed Kurzweil PC88 keyboard and I've tested the pots to be working. I'm having a similar issue with the mod wheel as well, where if I assign it to control something in ableton the mod wheel only affects half of the sweep range available.

Also the mod wheel on most controller keyboards I've played (and my Novation) is automatically assigned to a vibrato (on most patches) and I was wondering again, if I can edit the code to give me this functionality?

Thanks for everbodys help so far, think this is close to being perfect!

Here is the code in its current state if it helps!

void setup() {
}
void loop() {
usbMIDI.sendControlChange(1, analogRead(0)>>3, 1);
delay(10);
usbMIDI.sendPitchBend(analogRead(1)<<4,1);


while (usbMIDI.read()) ; // read and discard any incoming MIDI messages
}

Cheers!

Dan
 
The MIDI specifications say clearly that the pitch bend sends a value between 0 and 16383 (decimal), where 8192 is the center position, and that the sensitivity (how many semitones will be deviated) is a function of the receiver. Thus, there are synths who respect the unofficial standard of +/- 2 semitones, others will have their own sensitivity. Many software solutions allow to configure it by a specific control change message.
https://www.midi.org/specifications/item/table-3-control-change-messages-data-bytes-2
 
Thanks so much for the reply on this (and apologies for my late response!). So if I understand you correctly here then I can use one of the RPN messages to change the amount of pitch bend? for example if I want 6 semi tones I would use (according to the table)

101 0
100 0
6 6
38 0

Please bare with this stupid question, but would I need to add this to the code in Teensyduino or would I use something like midi-ox to send it?
 
First, you should make sure that your receiving midi device accepts that pitch bend range change. This could be tested manually with midi-ox. Once you are sure that the commands work as expected, you may integrate the (known working) commands into your code.
 
Hi everyone, getting a little further ahead in my project and have been trying to work on the code with a friend. I finally have the mod wheel going into analog in 0 tracking perfectly but I'm still having getting the pitch bend to scale properly.

Here is my code as it stands:

void setup() {
usbMIDI.sendControlChange(1, analogRead(0)>>3, 1);
usbMIDI.sendPitchBend(analogRead(1)<<4,1);

}

//these variable store the last value sent
//they are initialized with impossible values so the first send occurs.
// byte for mod wheel since it is ranged 0..127 which is less than 8 bits
// unsigned int for pitchbend since it is a 14 bit value.
byte sent_value_cc1 = 128;
unsigned int sent_value_pb = 65000;



void loop()
{
//read in the value for the analog pin

unsigned int temp = analogRead(0);
temp -= 320;
temp /= 3;
byte new_value_cc1 = temp;






//compare the value against the last sent value
if ( new_value_cc1 != sent_value_cc1)
{
//send the new value to the midi port
usbMIDI.sendControlChange(1, new_value_cc1 , 1);
//save the new value
sent_value_cc1 = new_value_cc1;
//allow time for the hardware to send
delay(10);
}

unsigned int new_value_pb = analogRead(1)<<4;
if ( new_value_pb != sent_value_pb )
{
usbMIDI.sendPitchBend(new_value_pb ,1);
sent_value_pb= new_value_pb ;
delay(10);
}
while (usbMIDI.read()) ; // read and discard any incoming MIDI messages
}

The problems im having are getting the pitch bend to scale properly so it does +/- 2 semi tones. I now understand that altering pitch bend sensitivity is done on the receiving unit but at the moment i'm barely even getting a semi tone pb. I ran a serial monitor code on it and the pots travel is between 320 and 700 with 510 in the centre (same as the mod wheel) but I don't understand where to adjust my code to get this working.

I also have and issue when trying to assign something in ableton to the mod wheel where the pitchbend will always send a message after I move the mod wheel which makes ableton think I want to assign to the pitchbend wheel. I need to click the midi assign button off real quickly to get it to assign to mod wheel.

Anyone able to help me here?

Thanks

Dan
 
First of all, you'll have to scale the values obtained from your pitch bend pot in a way that your code sends really the full pitch bend range (0 to 16383) to the receiving unit. Only in a second step, when you are sure that the full pitch bend range is transmitted, you might play with the receiving device's pitch bend sensitivity.

That's a little calculus exercise: The pot gives you a value of 510 +/-190 (from 320 to 700) which has to be remapped into 8192 +/- 8191 (from 1 to 16383)
Step 1 read the pot: int16_t pval=analogRead(1)-510; //will read values from -190 to +190 into pval
Step 2 scale the range: pval = pval * 43.11f // now, pval contains values from -8191 to +8191
Step 3 set the midpoint: pval = pval + 8192 // finally pval contains values from 1 to 16383
Step 4 check if this is different from the previous value: if(pval != oldval)
Step 5 send it to the midi device: usbMIDI.sendPitchBend(pval ,1);
Step 6 update oldval: oldval = pval;

Ready :)
 
Thanks so much for the reply Theremin! The way you've broken that down for me really helps me to start to understand whats happening per line. I've tried adding it to my existing code but I'm getting an error message again.

Heres the code now:

void setup() {
usbMIDI.sendControlChange(1, analogRead(0)>>3, 1);
usbMIDI.sendPitchBend(analogRead(1)<<4,1);

}

//these variable store the last value sent
//they are initialized with impossible values so the first send occurs.
// byte for mod wheel since it is ranged 0..127 which is less than 8 bits
// unsigned int for pitchbend since it is a 14 bit value.
byte sent_value_cc1 = 128;
unsigned int sent_value_pb = 65000;



void loop()
{
//read in the value for the analog pin

unsigned int temp = analogRead(0);
temp -= 320;
temp /= 3;
byte new_value_cc1 = temp;

int16_t pval=analogRead(1)-510; //will read values from -190 to +190 into pval
pval = pval * 43.11f ; // now, pval contains values from -8191 to +8191
pval = pval + 8192 ;// finally pval contains values from 1 to 16383
if(pval != oldval);
usbMIDI.sendPitchBend(pval ,1);
oldval = pval;


//compare the value against the last sent value
if ( new_value_cc1 != sent_value_cc1)
{
//send the new value to the midi port
usbMIDI.sendControlChange(1, new_value_cc1 , 1);
//save the new value
sent_value_cc1 = new_value_cc1;
//allow time for the hardware to send
delay(10);
}

unsigned int new_value_pb = analogRead(1)<<4;
if ( new_value_pb != sent_value_pb )
{
usbMIDI.sendPitchBend(new_value_pb ,1);
sent_value_pb= new_value_pb ;
delay(10);
}
while (usbMIDI.read()) ; // read and discard any incoming MIDI messages
}

And here's the error Im getting.

Arduino: 1.8.1 (Windows 7), TD: 1.35, Board: "Teensy LC, MIDI, 48 MHz, Smallest Code, US English"

Kurzweil_mod_working_pb_not_scaled_always_transmit: In function 'void loop()':
Kurzweil_mod_working_pb_not_scaled_always_transmit:28: error: 'oldval' was not declared in this scope
if(pval != oldval);

^

Kurzweil_mod_working_pb_not_scaled_always_transmit:30: error: 'oldval' was not declared in this scope
oldval = pval;

^

'oldval' was not declared in this scope

Thanks again for your continued assistance in getting this working mate, it's so appreciated and if youre ever in London the beers are on me!

Dan
 
Naturally, you get still errors because you added well the pitch bend code in setup, but you are still keeping the old stuff in the loop:

Remove from the loop
Code:
unsigned int new_value_pb = analogRead(1)<<4; 
if ( new_value_pb != sent_value_pb ) 
{ 
usbMIDI.sendPitchBend(new_value_pb ,1); 
sent_value_pb= new_value_pb ; 
delay(10); 
}

and since oldval has to keep its value during repeated loop() calls, it has to be declared globally, that means outside and before setup() and loop(). Thus, you have to add the line
Code:
int16_t oldval;
before setup().
 
You want him to remove the send from the loop but leave it in setup???

the new pitch bend send is already in the loop (above the old code which should be removed) or I'm perhaps blind:
Code:
void loop() 
{ 
//read in the value for the analog pin 

unsigned int temp = analogRead(0); 
temp -= 320; 
temp /= 3; 
byte new_value_cc1 = temp;

int16_t pval=analogRead(1)-510; //will read values from -190 to +190 into pval
pval = pval * 43.11f ; // now, pval contains values from -8191 to +8191
pval = pval + 8192 ;// finally pval contains values from 1 to 16383
if(pval != oldval);
usbMIDI.sendPitchBend(pval ,1);
oldval = pval;
 
The map() function does basically the same as my suggested code which I wrote line by line for pedagogic reasons. One is neither quicker or more precise than the other. The map() function risks even to be slower because it will execute at least one division...

Removing the actual send function calls from setup doesn't hurt, that's true, these are pointless.
 
Thank you all so much guys, it worked by following theremins suggestion, but I've got the arduino page open so will definitely read up on that. Getting a bit of glitch on both the wheels but I'll try and add the responsive analog read library to the code and see if it helps.

Should I be using the aref pin as the 0v of the pots? I'm currently using the G (opposite 5v) for both my pots.

Thanks again, what a helpful forum!

Dan
 
Status
Not open for further replies.
Back
Top