MIDI USB teensy and potiometer-- Jittery CC values

Status
Not open for further replies.

JittrBox

Member
Hi to all
this is my 1st post and am 1 day old teensy 3.0 user

I purchased to teensy 3.0 yesterday and got the MIDI to work in MaxMSP and in ableton.

I followed the circuit from little scale .
http://little-scale.blogspot.ca/2012...ontroller.html

EVERYTHING works but 2 unwanted things happen.

- I am getting continuous data (even when not touching the pot)
-Most importantly the CC data is jumpy and jittery.
-so when mapping MIDI in Ableton it's a bit of a nightmare 'cause (getting continuous data sent from the teensy) I can't
un-assign previously assigned MIDI areas.

Now he (little-scale) mentions to use a ;
• 1 x 100kΩ B-type potentiometer

But I get better results using a B5K pot.

Also by connection the (+) to the 3.3V pin , I get less jitter.


-----
Anyw suggestions would be greatly appreciated

Endless thanks

phil
 
Helping you help me :) !!!

I found this in the comment of the little scale post.
http://redbinary.com/pacmod-midi-dj-controller/
I tried it out , and yes the jitter has gone way down but
even with no jitter it's not working well .

BEHAVIOUR: it seems as if the are getting stored somewhere and then they come flying out in shot.
Then I have control for a while and then boum! no more control @ all for a while.
 
here it is

http://little-scale.blogspot.ca/2012/10/a-very-simple-diy-usb-midi-controller.html

Another great one I have found and is the most stable with the least jump and jitter is
http://tomashg.com/?tag=teensy

He (tomash) created a library that fast forward all MIDI coding for teensy and it's seems amazing.
I tried it and it very stable, a jump only once in a while.

The only problem I have now is that my value is constantly being sent.
which I figure is normal since the 3.3v or 5 v output is constantly feeding the Potentiometer.

So , I tried have a few code where if there is no value change then don't send anything.
but the fact that there is "jittering" on the value and I guess it changes the value so it keeps it active.

Also , it is obvious I am nowhere near a real C programmer and this would be a 2 sec solution in MaxMSP (just use the [change] object)
So maybe I just need to have a tiny part of code (which I tried hacking/programing (with no success) over the arduino/ teensy/USB-MIDI/analog control change/example
-don't send if value is not changing. But again why is the value jittery in the 1st place is this common ??

Thank you so much nanthonos and every else for anyhelp.

phil
 
How are you powering the teensy, are you using USB power from the computer? That is a very noisy power source and would give jittery signals. Its better to have a separate analog power supply and ground.
You can use averaging to smooth out the values, and you can also use a lower number of bits.

As most MIDI data is only 7bit, you should compute the 7bit value and compare it to the last one sent, and only send another if the 7bit value has changed.
 
this is sorta what I ending up doing (code below). It works sort of but still sending having some jittering a little.
I need to keep it USB cause I want to make little module-contollers to use with Ableton live. HOW DO SAY "M-AUDIO" CONTROLLERS get rid of the jitter ?.

Also I was think if I would I do a sort of , if condition is TRUE @ at least 3 times then then send the value.
would I use a for loop type combo <-- or your averaging thing could be could. <-- How would I do that (averaging) in my code
thanks

int pot = 0;
int potbefore = 0;

void setup() {
Serial.begin (9600);
pinMode (pot, INPUT);
}

void loop() {

int current = analogRead(pot)/8;

/* Serial.print ("current outside of if:"); Serial.println (current, DEC); Serial.print ("potbef outside of if:"); Serial.println (potbef, DEC); */

if (current != potbefore) {


usbMIDI.sendControlChange(1, current, 1);

potbefore = current;
}
delay (10);
}
 
A really great way to deal with this would involve implementing slight hysteresis while converting from 10 to 7 bits.

Edit: also, for the sake of testing, please try printing the original 10 bit analog values to the serial monitor. Are you getting noise that's really changing the readings by 8 or more? If it's only 1 or 2 difference, then a hysteresis of 3 or 4 would completely kill the jitter as seen by MIDI. If you really have noise that's 8 or more codes in the original 10 bits, then you've got an analog signal issue.
 
Last edited:
I apologize for my ignorance Paul , but how would I go about doing this, (changing from 10 to 7 bits).
I am learning and learning thanks to you guys. When I solve this problem I will help other in the future thanks to you guys :)

hope to hear from you soon
thanks again
 
this code taken from http://forum.arduino.cc/index.php?topic=117264.15;wap2
would seem to be the way to convert to 7bit



// Read multiple potentiometers and send the results over MIDI out.
// from
// http://arduino.cc/forum/index.php/topic,117264.0.html
// adapted to run on Teensy with usbMIDI feature
// http://www.pjrc.com/teensy/td_midi.html


// Variables:
static int input_nb = 2; // select number of desired analog inputs (max 6 for Uno)
int AnalogValue[2] = {0,0}; // raw analog readings
byte lastCValue[2] = {255,255}; // previous controller values
// select the midi Controller Number for each input (22 to 31 are free)
// for list, see
// http://www.midi.org/techspecs/midimessages.php#3
byte midiCCselect[2] = {22,23};
byte cc; // Analog reading converted to 7 bit value
byte channel = 1; // MIDI channel number from 1 (not 0) to 16

void setup() {
// launch MIDI by selecting USB MIDI in the Arduino IDE with Teensyduino installed
// http://www.pjrc.com/teensy/teensyduino.html
}

void loop() {
for (int i =0; i < input_nb; i++) {
// Arduino ADC gives values in range 0 to 1023
AnalogValue = analogRead(i);
// convert to a control value, range from 0 to 127, for MIDI:
cc = AnalogValue/8;

// check if control value has changed from last time
if (cc != lastCValue ) {
//send control change on cc#i
usbMIDI.sendControlChange(midiCCselect, cc, channel);
// update last controller value to current one
lastCValue = cc;
} // end if

} // end for
}
 
Before I write up a lengthy explanation or some sample code, could you please try printing the numbers from analogRead() to the serial monitor? Those would be the original ones, before dividing by 8, so the range is 0 to 1023. Try it a couple times with the pot at different positions, like once near the middle and once near each end.

Can you copy and paste about 20 of the number from each test? Let's take a look at the actual numbers you're getting. Then we'll get into idea to deal with the issue, knowing what the issue actually looks like in the original numbers.
 
That code doesn't do hysteresis. It only checks if the value changed. You can find pretty much the same thing in 1.17-rc2, under File > Examples > Teensy > USB_MIDI > AnalogControlChange.

I might write up another example with hysteresis. But first, let's look at the actual raw analogRead numbers.
 
Sorry I had not seen you message ( the pot is a B5K)
Here it is in the middle position : 901 900 901 900 898 901 900 901 900 901 901 900 901 900 903 900 899 901 900 901 900 899 900 899 903 900 899 900 901 899 900 899 900 901 899 900 901 900 901 900 899 900 899 901 900 901 902 901 903 900 901 900 902 900 899 900 901 900 901 900 900 899 900 899 898 900 901 899 901 900 901 900 901 899 902 899 900 899 900 899 900 899 901 903 899 900 903 900 899 900

At the 1023 end: 1019
1016 1021 1022 1023 1022 1023 1022 1023 1022 1023 1022 1023 1021 1023 1023 1021 1023 1021 1023 1021 1019 1020 1022 1018 1019 1016 1017 1018 1014 1016 1018 1015 1016 1015 1020 1016 1015 1016 1015 1016 1015 1016 1015 1016 1017 1015 1014 1016 1015 1017 1015 1017 1018 1016 1015 1022 1017 1016 10171018 1016 1015 1017 1015 1018 1017 1015 1016 1017 1001 1012 1017 1015 1014 1015 1016 1014 1017 1020 1017 1016 1015 1014 1013 1015 1016 1017 1015 1016 1014 1015 1017 1016 101510161015101610141015101610171015
1015 1016 1017 1016 1011 1012 1015 1014 1016 1015 1018 1016 1015 1016 1015 1016 1013 1016 1015 1016


low position 121212121213121213212121212121212131232121212123212121212313212121212321213231212123121232132121213231212121323121323121212123123121231212342123212121212131212123123123121212121212121212123212121212123121231212321212312121213212121232121212121212132121212121321212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121312121212121212121212121212121212121213121212121212121212121212121212121212123212121
 
I don't know if this can help you help me

I tried the same code (below) strictly with the arduino uno and serial monitor, then sent this to MAXMSP's serial monitor to see the
behavior. And it works really fine , could almost say perfect. it has very rare +-1 jumps. and it is respecting the. != . On the teensy
when testing with MIDI in maxMSP , (have little patch running to see if the same value is being sent), even if there is no +- jump, same value
keeps getting sent 50% of the time.

** does keeping it strictly on arduino say anything to you


int pot = 0;
int potbef = 0;



void setup() {
Serial.begin (9600);
pinMode (pot, INPUT);
}

void loop() {

int current = analogRead(pot)/8;


if (current != potbef) {

Serial.println (current, DEC); // I CHANGE ( usbMIDI.sendControlChange(1, current, 1); for this
potbef = current;
}
delay (10);
}
 
Hysteresis is just making the current value "sticky". You keep track of the current value, and only change it if the raw reading differs more than a minimum amount. So for your readings, where the reading can go between 1023 and 1001, you might use a threshold of +/- 14 (22 range/2 + a little). Essence of algorithm:
Code:
#define THRESHOLD 14
int current;

void update_current( int raw )
{
    int delta = raw - current;
    if ( delta <= -THRESHOLD || delta >= THRESHOLD )
        current = raw;
}
As Paul said, note that you want to do this on the unscaled 10-bit readings. When you scale to 8 bits, you introduce non-linearities that amplify jumpy readings near a multiple of four. Imagine a reading which jitters between two values in the raw 10-bit reading: 4 5 5 4 5 4 4 5 4. Convert this to 8 bits and the jitter disappears; they all become 1. Now, imagine that jitter between 3 and 4: 3 4 4 3 4 3 3 4 3. Converting to 8 bits preserves the jitter: 0 1 1 0 1 0 0 1 0. A jitter of one in the raw is still a jitter of 1 in the scaled version. So to do hysteresis on the 8-bit scaled version, we have to use the equivalent hysteresis of 4 in the raw version. Imagine the control is turned up by one unit: 4 5 5 4 5 4 4 5 4. All these convert to 1 in 8 bits, but the hysteresis doesn't change the current value, which is still at 0; we'd have to turn the control up to 8 to get the output to jump, and it'd then jump to 2.

If we do hysteresis on the raw version, we can use a threshold of one as well. So for the 3 4 jitter, say the current value sticks at 3. When the control changes by one raw unit, jittering now between 4 and 5, it gets picked up, because the threshold is only one in the raw units. And since the current value moves to 4 or 5, the 8-bit output changes from 0 to 1, registering the control change.

So, the managing code:
Code:
...
int raw = read_analog();
update_current( raw );
uint8_t scaled = current >> 2;
...

One other thing: I wonder whether the hysteresis code should use a slightly asymmetrical threshold based on which direction it previously moved the current value. e.g. if it just went from 10 to 11, it might use thresholds of -2 and +1, jumping to 12, but not back to 10, requiring that raw go to 9 before it jumps down.
 
thanks a lot blargg. I don't think I grasp all that you're saying since yesterday around 2am was the 1s time I heard the word hysteresis.
I'll test out the code you gave me. Where do I place it ? inside the void loop ? I'm learning thanks.

#define THRESHOLD 14
int current;

void update_current( int raw )
{
int delta = raw - current;
if ( delta <= -THRESHOLD || delta >= THRESHOLD )
current = raw;
}
 
I thought more about the hysteresis code I posted and the nagging detail at the end and I think it could be done better. The way I have it, the reading can only jump in THRESHOLD-sized jumps at minimum. It should move the current value a smaller amount:
Code:
#define THRESHOLD 14
int current;

void update_current( int raw )
{
    int delta = raw - current;
    
    if ( delta <= -THRESHOLD )
    	current = raw + THRESHOLD;
    
    if ( delta >= THRESHOLD )
    	current = raw - THRESHOLD;
}
THRESHOLD is the typical error noise in either direction, thus current should generally be at the center of this. Now current can step one unit at a time if the reading behind the jitter is stepping at that rate. You can think of current as a little box over the jittery value:
Code:
  current
     |
+----+-----+
|          |
| ******** |
   jittery
So when the value bumps up against the edge, it moves the box:
Code:
|    *     |
|  *       |
|       *  |
|         *|
 |         *|
    |         *|
    |        * |
    |  *       |
    |      *   |
    |*         |
 |*         |
 |      *   |
 |   *      |
|*         |
The great thing about microcontrollers now is that you can program in C or C++, so you can easily test these algorithms on your host machine. You should definitely try to understand this before coding it. You could write a little test program that generated a jittery value, then play with algorithms to de-jitter it.
 
thanks so blargg with all of this diagrams and all. I completely grasp the principal , and this might not have even came
to the forum if I could do the patch in MaxMSP. <--Been a "Maxer" 7 years and deal well with these issues in Max.
The problem is that I can't consider myself a C or C++ coder. I'm a hacking and can dable @ the code and get stuff to work , but it's just not my language.

Now, I've been wanting to learn for a while and did look it up information many few times, even youtube, but I can't really find the one that is C for arduino. It's either to simple or to over the top with exceptions here and exception there to the code.

Now, as I mentionned before <-- when I try this circuit in straight arduino UNO (no teensy & no MIDI CC) and keep it all serial and test the " != code" in the serial monitor on on MaxMSP, All is almost perfect<------ no value is sent it the pot is not touch. This has made me doubt that 's it's a physical (pot) problem


What do you think?/suspect
 
I see; here's my modification to your loop() to use this code:
Code:
#define THRESHOLD 14

int update_current( int raw )
{
    static int current;
    int delta = raw - current;
    
    if ( delta <= -THRESHOLD )
        current = raw + THRESHOLD;
    
    if ( delta >= THRESHOLD )
        current = raw - THRESHOLD;
    
    return current;
}

void loop() {
    int raw = analogRead(pot);
    int current = update_current( raw );
    int scaled = current / 8;
    
    /* Serial.print ("current outside of if:"); Serial.println (current, DEC); Serial.print ("potbef outside of if:"); Serial.println (potbef, DEC); */

    if (scaled != potbefore) {
        usbMIDI.sendControlChange(1, scaled, 1);

        potbefore = scaled;
    }
    delay (10);
}

Further, here's a little test program I made of update_current():

Code:
#if 0
gcc hysteresis.c && ./a.out; exit
#endif

#include <stdio.h>
#include <stdlib.h>

#define NOISE 14

// try reducing to see how too small a threshold allows jitter through
#define THRESHOLD 14

int update_current( int raw )
{
    static int lowpass;
    static int current;
    int delta = raw - current;
    
    if ( delta <= -THRESHOLD )
        current = raw + THRESHOLD;
    
    if ( delta >= THRESHOLD )
        current = raw - THRESHOLD;
    
    return current;
}

static int ranged_rand( int range )
{
    return (long long) rand() * range / (RAND_MAX + 1LL);
}

int main()
{
    int r;
    for ( r = 20; r < 30; r++ )
    {
        int n;
        for ( n = 20; n--; )
        {
            int raw = r + ranged_rand( NOISE*2+1 ) - NOISE;
            int cur = update_current( raw );
            printf( "%2d %2d\n", raw, cur );
        }
    }
}

It simulates the jittery raw input by adding random noise of +/-NOISE. It then has the knob get slowly turned from 20 to 30, and shows how the algorithm is able to pick this small change out of the jitter. Try reducing THRESHOLD to see how having it too low compared to the noise allows jitter through. When run, it outputs the raw value, and the current one:
Code:
29 15
17 15
27 15
28 15
31 17
11 17
15 17
27 17
13 17
21 17
19 17
23 17
16 17
20 17
32 18
31 18
23 18
26 18
 9 18
22 18
 7 18
13 18
10 18
29 18
11 18
18 18
10 18
10 18
34 20
13 20
21 20
30 20
24 20
15 20
24 20
21 20
20 20
34 20
15 20
28 20
22 20
29 20
19 20
32 20
15 20
17 20
30 20
33 20
 9 20
34 20
22 20
10 20
13 20
26 20
32 20
17 20
 9 20
 8 20
20 20
 9 20
15 20
36 22
34 22
32 22
16 22
24 22
19 22
30 22
23 22
27 22
23 22
10 22
21 22
35 22
35 22
29 22
16 22
29 22
26 22
18 22
29 22
14 22
22 22
34 22
33 22
19 22
16 22
35 22
19 22
29 22
36 22
26 22
28 22
34 22
22 22
35 22
21 22
32 22
29 22
35 22
24 22
17 22
37 23
36 23
15 23
35 23
28 23
23 23
28 23
18 23
33 23
19 23
23 23
17 23
16 23
18 23
26 23
22 23
15 23
36 23
14 23
15 23
25 23
33 23
39 25
38 25
31 25
22 25
32 25
22 25
20 25
18 25
28 25
18 25
16 25
32 25
15 25
34 25
16 25
32 25
15 25
39 25
14 25
27 25
17 25
19 25
35 25
33 25
31 25
40 26
30 26
34 26
15 26
16 26
27 26
15 26
14 26
18 26
25 26
35 26
30 26
35 26
15 26
18 26
41 27
19 27
38 27
17 27
41 27
15 27
38 27
16 27
14 27
39 27
30 27
19 27
18 27
24 27
39 27
36 27
25 27
30 27
31 27
27 27
34 27
17 27
29 27
36 27
23 27
42 28
31 28
39 28
35 28
32 28
15 28
35 28
38 28
40 28
39 28
38 28
 
Last edited:
MAn 0 man Blargg!!! O MAn !!!

You do it !! , been a whole 8-9 days on this till 4am sometimes. your code works perfectly , I mean perfectly !!! :) Thanks so much.
only 1 question, any reason why the range is from 1 to 126 instead of 0 to 127 ??
If I can't figure it out I'll just use the map() function :) !

further more ,
I've contacted people all around today to see if anyone would help get start in the C world.
Will study your code as an example :)

Thanks so much again man. I hope other future teensy user will benefit from this (your generosity) .
 
ah shit !! with further testing ...

there is bug between value 1 and 8 <-- all the values start spinning like crazy !!??? ;-(
 
only 1 question, any reason why the range is from 1 to 126 instead of 0 to 127 ??
The jitter makes it harder to tell when it's at the end of the range. From what I can tell, my code limits the raw range of 0-1023 to 0+THRESHOLD to 1023-THRESHOLD, so 14 to 1009. Divided by 8 gives 1 to 126. So you'll want to do map( current, THRESHOLD, 1023-THRESHOLD, 0, 127 ) if I understand map().

My code starts current out at 0 which might mislead you that it can go to 0. It should be fixed like this:
Code:
#define THRESHOLD 14

int update_current( int raw )
{
    static int current = THRESHOLD;
 
where do i place it in your code. I
replaced the section and nothing happens


int update_current( int raw )
{

static int current;
int delta = raw - current;

if ( delta <= -THRESHOLD )
current = raw + THRESHOLD;

if ( delta >= THRESHOLD )
current = raw - THRESHOLD;

return current;


}
 
The minor fix was to change
Code:
static int current;
to
Code:
static int current = THRESHOLD;

As for the jitter at zero, you'd have to dump a log of the raw values while you confirm that the jitter is happening. Based on your earlier log, I don't see how it could occur, so I'm concluding that you're getting different raw values than your earlier log.
 
...
... then when I hit @ around 8 it start to go crazy/ then 0/ then when i come back up it goes from 14 - 8 before it starts going up again from 8.

...[/url]

Actually, sounds like dust in a reasonable pot or just not a very high quality pot at all - have you tried with another pot? If so, how much did you pay for the pot(s) ?
 
Status
Not open for further replies.
Back
Top