Ultra noob seeking some MIDI coding help.

Status
Not open for further replies.
...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.
Yeah I was a bit skeptical about ResonsiveAnalogRead() for MIDI projects but it really is pretty good and with Teensy you have so much horsepower to spare it doesn't really matter if it burns a few more cycles than if you'd written your own smoothing/hysteresis code. I still haven't looked under the hood for it's more advanced features but the basic functionality is pretty good for MIDI CC from a voltage divider source.

Your code already is limited to a change in the result before sending MIDI updates but with CC even modest noise from the pot you can still end up toggling at a high rate between adjacent values because the voltage happened to land very near a rounding point in the MIDI mapping. With pitchbend you are bound to have the problem even if you are only updating when it changes mapping... because the mapping has more values than your signal.

I also have an 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.

I think this issue is the same thing...
It's not just when you move the mod wheel but likely it's a steady stream from the pitchbend, whose voltage is much more likely to hover near boundaries of the MIDI mapping (especially in your case with the very limited voltage range).
So the pitchbend, without some algorithm to tame it, will pump out adjacent-or-nearly-so pitch messages at a very high rate (or would if you didn't have those delay commands in your code which were the only things giving you any chance of getting the software not to hear the errant message.

Delays prevent processing and are not the best way to stabilize MIDI output and if you need to use them for this it's best they are a brief as possible. I found delay(1) was enough to give an early weak-smoothing method stability.

Adding ResponsiveAnalogRead() should either cure or at least dramatically reduce the amount of garbage MIDI.

If any remains it's best to continue calculating the result on each pass but to only update and send after an elapsed period.

Use elapsedMillis() for this or at least you should be able to turn down the delay times.

But to know for sure what its sending you need a MIDI monitor application so you can see every message it's generating.

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.
...and here too you can only know what your code is doing if you can see the messages that are received. (Although you can print them to the serial monitor instead but I like to know from the receiving side what's actually getting through and when.)

It could be difficult to hear a micro-tonal wobble in your intonation because your controller is sending a stream of pitch messages all very near the neutral value. But you definitely need to stop it all the same.
 
Last edited:
Hi everyone! I dont lnow why but I didnt get an email notification about the replies in this thread! Thanks a lot for the heads up about the elapsedmillis and responsiveanalogread libraries Oddson. Its really helped a lot with calming down the erratic readings I was getting from the old set up. I tried a few things to calm this down but in the end I decided to get a Teensy 3.2 with the AGND to try and help as well as putting .1uf caps between the wiper input and AGND. This combined with the 2 libraries made it pretty solid!

I kind of had to start again on this project as the wheels that I was using before were just so cheap so Ive bought a new set from Doepfer. These feel great and a pretty much working, I just have one issue that I cant quite get my head around. My new pitch wheel doing the bend down 2 semi tones fine, no wobble or anything, but when I go to bend up It gets to 2 semitones up just before the end of the travel but then goes down 2 semitones right at the top. I ran a serial monitor script with the wheels connected and my pitch bend is 500 in the centre 698 max and 344 low. I thought I'd just be able to add the 500 to my exisiting code and it would scale the wheels but unfortunately I'm still getting the same issue. Here's my code at the moment:

#include <elapsedMillis.h>

#include <ResponsiveAnalogRead.h>

ResponsiveAnalogRead analogOne(A0, true);
ResponsiveAnalogRead analogTwo(A1, true);
elapsedMillis sincePrint;





int16_t oldval;

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;
byte a_variable = 10;



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

unsigned int temp = analogRead(0);
temp -= 253;
temp /= 3.5;
byte new_value_cc1 = temp;

int16_t pval=analogRead(1)-500; //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;

a_variable =20;


//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);
}
while (usbMIDI.read()) ; // read and discard any incoming MIDI messages
}

Can anyone help me out with getting this last thing sorted?

Thanks so much for everyones help already!

Dan
 
I've not tried to compile your code but from the description I'd say your problem is that a variable used in calculating bend is overflowing it's capacity and is reading back on the other end of the scale...

But there are a number of other things 'wrong' with your code.

You've included the ResponsiveAnalogRead library and declared the objects to pass data to the library -- but you're not actually using them. You're just calling the regular AnalogRead() everywhere.

You're sending an initial midi event during startup (which isn't really standard - most midi devices don't output until they change).

Then in the comments it suggests impossible values will force the code to send (another!?) initial midi value... but because of overflowing these are not 'impossible' once they overflow and so don't guarantee they will be different enough from the reading to trigger a new message.

You define an elapsed millis value but then just call delay anyway...

I'm not sure why your raw range is so restricted -- is the voltage divider giving only a limited range of values?
 
Last edited:
Hi Oddson. Thanks a million for taking the time to reply!

So as you can tell I know nothing about trying to program, that code has come from a friends help, the excellent replies here and just experimenting. I really don't know what I'm doing! All of the comments in the code came from a sample code my friend wrote and sent to me in order to help me decipher what each line is doing.

In terms of the restricted reading it has to do with the physical travel of the pot when mounted to the wheel assembly, the assembly's datasheet mentions the pots' travel only covers 0-1.6v when 5v is applied.

I'm totally lost with where to go with this now. Having got the Set up sort of working with ableton I then tried it with a mainstage file I like to use live and it just caused the program to freeze. I guess this is to do with it constantly sending a message? Strange how ableton handled it though?

I guess I'm going to start over. Can anyone recommend me some reading to learn how to make this work? Alternatively if anyone in the London area would be willing to tutor me on this project (paid of course!) I'd love to hear from you!

My email is perdition_city@hotmail.co.uk
Thanks everyone for all your help so far!
 
If you just want to fix the code you have (since it nearly works for you) then just use pval = min(pval,16383); //untested but something like that!

You may need to limit the zero side too: pval = max(pval,0)

If you're not it too big a hurry I'll see about posting some improved code here at a later date.

(Could you post a link to the data sheet for the wheel assembly you're using?)
 
Last edited:
Thanks again Oddson, I'll try and add these bits to the existing code and see what happens. I'm more concerned with the mainstage issue as that's what I eventually wanted to use it with but I'll try and sort it and report back!

Would love to see what you come up with a bit later for sure! I'm on my phone at the moment and I have the data sheet for the wheel on my work desktop so will post it tomorrow. It's pretty light in terms of info!

Thanks again mate!

Dan
 
Last edited:
DOEPFER said:
Technical remarks: Pay attention that not the full rotating angle of the potentiometer is covered but only about 40%. If the end terminals of the potentiometer are e.g. connected to GND and +5V only a voltange range 0...+1.6V is covered ! In addition the two potentiometers work in the opposite direction as one is mounted from the left and the other from right side to the wheel ! Especially for DIY/OEM applications one has to pay attention to these special features. So far the modulation wheel set is not used in any of our products. In particular it cannot be used in combination with the electronics of LMK2+, LMK4+ and the DIY/OEM electronics MKE. But the modulation wheel set can be combined with Wheel Electronic.

Found this on the product details of an obsolete product (with strikeout applied to all the text including the above) .

Not really clear what stops the wheel motion so I wonder how consistent the reading is at the maximum point?

If you press slightly harder you may get a maximum reading greater than your presumed maximum which causes the variable to overflow.

I think you can get 7-bit equivalent resolution without changing the analog reference.
 
That's the one I've got. The way the pot rests against the bezel means you can't really push it past its maximum. However I was getting the modwheel overflowing at first until I changed the part of code

unsigned int temp = analogRead(0);
temp -= 253;
temp /= 3.5;
byte new_value_cc1 = temp;

Temp /=3.5; was originally 4 I think, and I can't remember it now but there was a thought process behind choosing that number.

For 7 bit resolution am I right in thinking I amend

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

To

usbMIDI.sendPitchBend(analogRead(1)<<7,1);
 
No... sorry that wasn't clear... don't change any bit shifting

I meant resolution as a theoretical value... how much of the output is anything other than noise... and I'm merely ballparking that you give up nearly two bits on voltage range and the last bit is always dodgy... should leave you about seven bits of effective resolution... and if so the LSB (D1 in the midi output) will be mostly noise and quantization error but it's not any worse than truncating.

I'll need to write the code to explain....
 
Last edited:
Code:
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
// ******CONSTANT VALUES******** - customize code behaviour here!

// SET THESE FOUR VALUES!
const int pitchPin = 22; // PIN numbers ** MUST CHANGE!
const int modPin = 23; 
const int pitchMaxRaw = 490; // Max reading with full bend up... as raw 10-bit value 
const int modMaxRaw = 495; // Max reading full mod down??? read note from DOEPFER on 2nd pot reversed

const int channel = 1; // MIDI channel
const int MIDIdelay = 5; // will update MIDI only if this many milliseconds have passed
//******VARIABLES***********
// data variables and a lagged copy to compare before updating MIDI value
int pitch;
int mod;
int pitchRaw;
int modRaw;
int pitchLag;
int modLag;
elapsedMillis  pitchUpdate; 
elapsedMillis  modUpdate; 


// ititialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead readPitch = {pitchPin,true};
ResponsiveAnalogRead readMod = {modPin,true};
  



void setup() {

}

void loop() {
  getAnalogData();
  while (usbMIDI.read()) {
  }
}


//************ANALOG SECTION**************
void getAnalogData(){  
  readPitch.update(); 
  if(readPitch.hasChanged()) {
    pitchRaw = readPitch.getValue();
    // remap to output data and send if changed and MIDIdelay has lapsed since last update for that parameter
    pitch = map(pitchRaw,0,pitchMaxRaw,0,16383);
    //pitch = max(pitch,0); // minimum (not needed here with 0 to 0 mapping on the lower end!
    pitch = min(pitch,16383); // cap to avoid overflow
    if (abs(pitch - pitchLag)>0 && pitchUpdate > MIDIdelay ){
      pitchLag = pitch;
      usbMIDI.sendPitchBend( pitch, channel);
      pitchUpdate = 0;
    }
  }

  readMod.update(); 
    if(readMod.hasChanged()) {
    modRaw = readMod.getValue();
    // remap to output data and send if changed and MIDIdelay has lapsed since last update for that parameter
    mod = map(modRaw,0,modMaxRaw,127,0); // N.B. - map does not limit values
    mod = max(mod,0); // minimum could overflow is modRaw is greater than calabrated 
    //mod = min(mod,127);
    if (mod != modLag && modUpdate > MIDIdelay ){ // resolution reduction should be enough wi
      modLag = mod;
      usbMIDI.sendControlChange(1, mod, channel); // CC = 1 is mod wheel in standard MIDI
      modUpdate = 0;
    }
  }
}
Here's a quick attempt at it... I happened to have a joystick's pots hooked up to PINS 22 and 23 and made them fill in for the Doepfer part.

Without the proper hardware it's hard to say for sure it's working as expected but it does limit changes to one quadrant of the joystick.

Note the mapping is reversed on the mod wheel as the text from Doepfer indicates that pot is reverse mounted.

I made up the limit value... you need to get the max readings on each pot to calibrate to the actual outputs as well as configure to the correct pins.
 
Here's a line-by-line explanation for the code:

#include <ResponsiveAnalogRead.h>
Include 'directive' tells the compiler to put all the code from this file here... including any 'includes' in the included file...


const int pitchPin = 22;
const int modPin = 23;

Constant data type (doesn't change as the program runs) keeps track of where your Teensy signals will be coming in from each pot wiper.


const int pitchMaxRaw = 490;
const int modMaxRaw = 495;

This should be the measured output of the pots at their maximum voltage output as a raw value. Implicitly this also sets the no-shift point in the middle of the pot for pitch bend. It's possible (likely?!) it will not rest exactly at the non-shift point.
Alternately we could read the output value while centered and double it for the pitchMaxRaw value so it will return to no shift when released.


const int MIDIdelay = 5;
By keeping elapsed millisecond counts since update for each pot we can compare to this value to see if an update in the MIDI value is due (e.g. modUpdate > MIDIdelay). You could have two such values if you wanted to allow one control to update more often than the other. It's yet another means of keeping the output manageable and stable. The number can be increased if you want fewer messages to be passed when you are wildly moving the controls. You want to use something like this rather than delay() calls which stop the processer from doing anything else and make the controller less responsive.


int pitch;
This is the MIDI output value that will become two 7-bit data bytes used in a pitch-bend message (MIDI loses one bit from each byte so it can keep track of what kind of byte something is).

A pitch bend message has D1 as the 'Least Significant Byte' (LSB) and D2 as the 'Most...' (MSB). The point I was making above (that your effective resolution is 7 or 8 bits) is not that you need to make sure the LSB is blank; rather it was to indicate the limitations of reading 1.6 volts range (assuming you power from 5 volts!) from a potentiometer using a 3.3 volt reference and a 10-bit ADC to map to a 14-bit parameter. Chances are it won't matter for your purposes but there are applications where very accurate pitch bend is advantageous. You can improve the effective resolution somewhat by providing a 1.6 volt reference voltage to AREF to use with the ADC or you could level-shift the signal to the full 3.3 volt range. But chances are you won't have to...

int mod;
MIDI value for Modulation wheel. With only 127 possible settings the resolution issue is not problematic provided we get stable ouput.

int pitchRaw;
int modRaw;

The raw (unmapped but still 'smoothed') values from the pots.

int pitchLag;
int modLag;

The lagged values - these are the MIDI values saved when the last MIDI message of that type was sent. By comparing the current calculated value we can tell when we need to send again.

elapsedMillis pitchUpdate;
elapsedMillis modUpdate;

These keep track of how long since we updated each message type. They are reset to zero each time a new MIDI message of that type is sent.


ResponsiveAnalogRead readPitch = {pitchPin,true};
ResponsiveAnalogRead readMod = {modPin,true};


This will initialize the objects used by the smoothing mechanism in the ResponsiveAnalogRead library.
We are telling the compiler the type (a custom type) and name of the objects so we can call them below as well as which data pin to read and whether to use 'sleep' mode (you can set this to false if you find the controller doesn't want to update when there are small voltage changes).



void setup() {
}

The setup() function allows code to be run exactly once prior to starting the main loop... I didn't use it above but I think you need to include a blank one to get it to compile...


void loop() {
getAnalogData();
while (usbMIDI.read()) {
}
}

The main loop... I could have just put all the remaining code here but I like to separate the analog, digital, and sysEx sections to improve readability.
The first line calls the analog section; the 'while' loop is empty but causes the usbMIDI code (included whenever you compile as a MIDI device) to clear the data buffers used to receive MIDI.
If your device is sent MIDI and you don't call this function the data buffer can get full and cause crashing.


void getAnalogData(){ ... }

Everything inside the braces is executed each time this function is called in the main loop.


readPitch.update();

Causes the ResponsiveAnalogRead object to be updated to its current value.

if(readPitch.hasChanged()) { ... }
This code will run only if the output has changed since last called... no point updating if the unmapped data isn't different!

pitchRaw = readPitch.getValue();
Get the new value... (this variable isn't strictly needed... we could have called .getValue() inside the map function below but this makes the map() function a bit easier to read.

pitch = map(pitchRaw,0,pitchMaxRaw,0,16383);
This is the replacement for Theremingenieur's mapping math... it's equivalent to using y = ax + b (linear function) but calculates the slope/intercept for you. It does not limit the output if your input is outside of the provided input range.

pitch = min(pitch,16383);
...so we add this to make sure we don't overflow the when .sendPitchBend() truncates to 14-bits

if (abs(pitch - pitchLag)>0 && pitchUpdate > MIDIdelay ){ ... }
This conditional will run the 'update' code the absolute value of the difference between the pitch and it's lag are greater than 0 AND the pitchUpdate was at least MIDIdelay milliseconds ago...
The absolute value thing only makes sense if you change the zero to some positive value. I put this in just in case the output was still not stable... I was on my hardware even at zero... Since we suspect much of the LSB part is noise anyway we can use values up to 64 without giving up any real resolution. But was wasn't able to test this out properly without the actual hardware.

pitchLag = pitch;
We lag the pitch value for the future comparisons...

usbMIDI.sendPitchBend( pitch, channel);
Then we send the MIDI...

pitchUpdate = 0;
Then we reset the timer.


readMod.update();
The mod wheel is exactly the same excepting:


mod = map(modRaw,0,modMaxRaw,127,0);
Mapping is reversed (assuming I'm understanding the product note) and is limited to 7 bits instead of 14.

mod = max(mod,0);
We have to watch the zero end for overflow as we've reversed the signal

if (mod != modLag && modUpdate > MIDIdelay ){...}
We can just use not-equals instead of absolute difference < threshold since the stability is pretty much guaranteed at 7 bits.

usbMIDI.sendControlChange(1, mod, channel); // CC = 1 is mod wheel in standard MIDI
Modulation wheel is CC=1 in standard MIDI.

Hope you find this helpful.
 
Last edited:
Hi Oddson, wow this is really amazing mate! I'm just about to try and give this a go, I've got my max and min values from the wheels already so I'll try and alter the values. Thanks for adding all of those comments as well man, thats literally the best thing ever for me to try and learn whats happening. Really cool, thanks again mate. Will report back how it goes!

Haha just as I was posting this I saw the follow up post as well. Man thats absolutely amazing, seriously man. Thank you so much for taking the time to write that, that accompanying description is REALLY helpful. Thank you again, I owe you a beer if you're ever in London!
 
Last edited:
... I owe you a beer if you're ever in London!
Can I stay in your flat? ;)
My wife and I were there for a month in 2014...cost a fortune but I was a great trip.

The comments probably took longer than the code so I hope you find them helpful.

Please note the code got only cursory testing on a joystick with full range of motion so I had to imagine what the output should look like if the pots were limited like the Doepfer part.

Do let me know if I don't have it correct!
 
Oh I know London, is outrageously expensive and getting worse. I love it though, oh and any time!

So thanks again for that amazing explanation, I amended and uploaded the code and it no longer causes mainstage to crash anymore. No more weird glitchy behaviour, nothing! You're a genius. There's still a few things to work out biut it seems so much more stable now!

Here's the code that I've used so far

// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
// ******CONSTANT VALUES******** - customize code behaviour here!

// SET THESE FOUR VALUES!
const int pitchPin = 1; // PIN numbers ** MUST CHANGE!
const int modPin = 0;
const int pitchMaxRaw = 1000; // Max reading with full bend up... as raw 10-bit value
const int modMaxRaw = 774; // Max reading full mod down??? read note from DOEPFER on 2nd pot reversed

const int channel = 1; // MIDI channel
const int MIDIdelay = 5; // will update MIDI only if this many milliseconds have passed
//******VARIABLES***********
// data variables and a lagged copy to compare before updating MIDI value
int pitch;
int mod;
int pitchRaw;
int modRaw;
int pitchLag;
int modLag;
elapsedMillis pitchUpdate;
elapsedMillis modUpdate;


// ititialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead readPitch = {pitchPin,true};
ResponsiveAnalogRead readMod = {modPin,true};




void setup() {

}

void loop() {
getAnalogData();
while (usbMIDI.read()) {
}
}


//************ANALOG SECTION**************
void getAnalogData(){
readPitch.update();
if(readPitch.hasChanged()) {
pitchRaw = readPitch.getValue();
// remap to output data and send if changed and MIDIdelay has lapsed since last update for that parameter
pitch = map(pitchRaw,0,pitchMaxRaw,0,16383);
//pitch = max(pitch,0); // minimum (not needed here with 0 to 0 mapping on the lower end!
pitch = min(pitch,16383); // cap to avoid overflow
if (abs(pitch - pitchLag)>0 && pitchUpdate > MIDIdelay ){
pitchLag = pitch;
usbMIDI.sendPitchBend( pitch, channel);
pitchUpdate = 0;
}
}

readMod.update();
if(readMod.hasChanged()) {
modRaw = readMod.getValue();
// remap to output data and send if changed and MIDIdelay has lapsed since last update for that parameter
mod = map(modRaw,0,modMaxRaw,127,0); // N.B. - map does not limit values
mod = max(mod,0); // minimum could overflow is modRaw is greater than calabrated
//mod = min(mod,127);
if (mod != modLag && modUpdate > MIDIdelay ){ // resolution reduction should be enough wi
modLag = mod;
usbMIDI.sendControlChange(1, mod, channel); // CC = 1 is mod wheel in standard MIDI
modUpdate = 0;
}
}
}

When I tried to use my pots max travel value (700 on the serial monitor) it would set the zero point as halfway between its maximum travel and zero on the pitch bend. I took your advice and doubled to the centre/ rest value (500) to 1000 and now the zero point of the sprung wheel is zero on the mainstage monitor. All good. However I'm still having issues with the wheel doing its full +/- 2 semi tones bend, it seems to a tone and a bit each way. Its the same each way.

Also the mod wheel works in reverse with this code. I tried replacing the modRaw and modMaxRaw values around but it didn't like that and stopped responding altogether. As a quick fix I just swapped my ground and 3.3v lines around on the breadboard and its now working as it should however again I'm not getting the full range (its about 0-70 instead of 127). I'm sure this is to do with not powering from 5v as I'm just taking 3.3v and AGND. Gonna read a little more on that part of the reply and try to digest it.

Thanks again!!
 
Can you get the following raw readings for whatever setup you've got now...

Mod wheel pulled fully toward you (bottom)
Mod wheel fully the other way
Pitch wheel full up
pitch wheel full down
pitch wheel resting (middle)

We can get working maps from those.

If the middle position is not exactly in the middle of the range we can still get it so that it centers with no shift yet still gets to the top and bottom of the range (there just may be a little flat section in the transfer function).
 
Ok, so here's the readings I've got from the serial monitor:

Mod wheel bottom 774
Mod wheel top 348 (this is because I swapped the v and gnd)

Pitch wheel up 700
Pwheel bottom 345
Centred 500
 
That's crazy... the pot isn't close to being linear as you have 155 positions below the middle but 200 above.

The note implied the limited ranges start from ground but these are in the middle of the range... so that's why my mapping is nowhere near correct.


If you try this:
Code:
    pitch = map(pitchRaw,345,700,0,16383);
    pitch = max(pitch,0); // need this now that the bottom isn't zero
    pitch = min(pitch,16383); // cap to avoid overflow
It should give you pitchbend across the full range but it will not centre.

Or you could try
pitch = map(pitchRaw,345,655,0,16383);
...along with the limit clamping.

The pitch shift should centre correctly but will hit the top value before the pot stops moving.

I'm not sure why the pot's response appears to be so non-linear. Please double check those measurements.



The mod wheel is simple and has no meaning to its middle value and so should not be a problem:


mod = map(modRaw,348,774,0,127);

(if you change the wiring back ... if not leave the 0 and 127 swapped as in my code.)
 
It's an assembly to control pitch and mod so it should have linear tapers...


It is linear just with way more variation than I'd expect... especially on a purpose made pitch wheel from someone like Doepfer.
 
Last edited:
Wow, I thought I posted this last night but I didn't press send. What a dope! Anyway...

Amazing! It works :D!!! So it appears I can spin the pot against the bezel where the wheel mounts, using a tuner and the handy 'pitch wheel lever' in mainstages GUI, I could spin the pot whilst the wheel was at its zero/ rest position and sort of fine tune it. I then had to slightly adjust the numbers I was using for my max and min values to get it to perfectly track the wheels motion, no thought or maths involved though unfortunately, I just entered random numbers near the values I got from the serial monitor to see which way they affected the tuning and then just fine tuned it from there. Its amazing man, I seriously cant thank you enough for all your help and for taking the time to write and explain that code to me your breakdown of it is so helpful This is a serious game changer for me when playing live so again thanks so much!!! Here's the code that I ended up using;

// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
// ******CONSTANT VALUES******** - customize code behaviour here!

// SET THESE FOUR VALUES!
const int pitchPin = 1; // PIN numbers ** MUST CHANGE!
const int modPin = 0;
const int pitchMaxRaw = 1000; // Max reading with full bend up... as raw 10-bit value
const int modMaxRaw = 774; // Max reading full mod down??? read note from DOEPFER on 2nd pot reversed

const int channel = 1; // MIDI channel
const int MIDIdelay = 5; // will update MIDI only if this many milliseconds have passed
//******VARIABLES***********
// data variables and a lagged copy to compare before updating MIDI value
int pitch;
int mod;
int pitchRaw;
int modRaw;
int pitchLag;
int modLag;
elapsedMillis pitchUpdate;
elapsedMillis modUpdate;


// ititialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead readPitch = {pitchPin,true};
ResponsiveAnalogRead readMod = {modPin,true};




void setup() {

}

void loop() {
getAnalogData();
while (usbMIDI.read()) {
}
}


//************ANALOG SECTION**************
void getAnalogData(){
readPitch.update();
if(readPitch.hasChanged()) {
pitchRaw = readPitch.getValue();
// remap to output data and send if changed and MIDIdelay has lapsed since last update for that parameter
pitch = map(pitchRaw,375,700,0,16383);
pitch = max(pitch,0); // need this now that the bottom isn't zero
pitch = min(pitch,16383); // cap to avoid overflow
if (abs(pitch - pitchLag)>0 && pitchUpdate > MIDIdelay ){
pitchLag = pitch;
usbMIDI.sendPitchBend( pitch, channel);
pitchUpdate = 0;
}
}

readMod.update();
if(readMod.hasChanged()) {
modRaw = readMod.getValue();
// remap to output data and send if changed and MIDIdelay has lapsed since last update for that parameter
mod = map(modRaw,348,675,0,127); // N.B. - map does not limit values
mod = max(mod,0); // minimum could overflow is modRaw is greater than calabrated
//mod = min(mod,127);
if (mod != modLag && modUpdate > MIDIdelay ){ // resolution reduction should be enough wi
modLag = mod;
usbMIDI.sendControlChange(1, mod, channel); // CC = 1 is mod wheel in standard MIDI
modUpdate = 0;
}
}
}

Thank you all again and special thanks (and a space to crash in London if you need!) to Oddson.

Amazing!!
 
Status
Not open for further replies.
Back
Top