Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 2 1 2 LastLast
Results 1 to 25 of 30

Thread: MIDI Problems

  1. #1

    MIDI Problems

    Hi all.......I have a program that runs fine on a Mega and it also works on the Teensy 2.0 in serial mode (using Hairless) but will not work in MIDI mode. Haven't found any joy on the net. It's for a device to send MIDI pitch bend

    Here's the code:

    // Vibe Bar Main Program
    //
    // Sees the movement of the Vibe Bar
    // Between full left and dead spot
    // Between full right and dead spot
    // Between full forward and dead spot
    // Between full back and dead spot
    // and maps to MIDI output.
    //
    // Claude Woodward 17/06/15
    //

    #include <Vibe_Bar_Configuration.h>
    #include <EEPROM.h>

    // MIDI Libraries
    #include <MIDI.h>
    #include <midi_Defs.h>
    #include <midi_Message.h>
    #include <midi_Namespace.h>
    #include <midi_Settings.h>

    // MIDI Constants
    int pitchBEND = 224;

    // These Analog pins are defined in ~/Documents/Arduino/libraries/Vibe_Bar_Configuration/Vibe_Bar_Configuration.cpp
    // These lines tell the Arduino where the Hall Effect sensors are connected to
    extern const int SENSOR_LEFT_RIGHT;
    extern const int SENSOR_FWD_BACK;

    // These Analog pins are defined in ~/Documents/Arduino/libraries/Vibe_Bar_Configuration/Vibe_Bar_Configuration.cpp
    // This defines where the Arduino built-in LED is
    extern const int LED_PIN;

    // These are text names for non-volatile memory addresses
    // These are defined in ~/Documents/Arduino/libraries/Vibe_Bar_Configuration/Vibe_Bar_Configuration.cpp
    extern const int VIBE_LR_MIN1;
    extern const int VIBE_LR_MIN2;
    extern const int VIBE_LR_MAX1;
    extern const int VIBE_LR_MAX2;
    extern const int VIBE_LR_DEAD_MIN1;
    extern const int VIBE_LR_DEAD_MIN2;
    extern const int VIBE_LR_DEAD_MAX1;
    extern const int VIBE_LR_DEAD_MAX2;
    extern const int VIBE_FB_MIN1;
    extern const int VIBE_FB_MIN2;
    extern const int VIBE_FB_MAX1;
    extern const int VIBE_FB_MAX2;
    extern const int VIBE_FB_DEAD_MIN1;
    extern const int VIBE_FB_DEAD_MIN2;
    extern const int VIBE_FB_DEAD_MAX1;
    extern const int VIBE_FB_DEAD_MAX2;

    // This is called a 'class' it contains functions and data that alre all carried around together
    // This particular class contains the graph mapping the hall effect sensor reading to a MIDI output
    class CustomCalibration {
    public:
    void setup( int minVal, int maxVal, int deadMin, int deadMax, int outMin, int outMax ) {
    _minVal = minVal;
    _maxVal = maxVal;
    _deadMin = deadMin;
    _deadMax = deadMax;
    _outMin = outMin;
    _outMax = outMax;
    _outMid = ( outMin + outMax ) / 2;
    if ( minVal > deadMin || deadMin > deadMax || deadMax > maxVal || outMin > outMax )
    {
    pinMode(LED_PIN,OUTPUT);
    Serial.begin(19200);
    Serial.println("EEPROM Calibration Value Check Failed: Possible cause = bad calibration");
    while (true){
    digitalWrite(LED_PIN,HIGH);
    delay(500);
    digitalWrite(LED_PIN,LOW);
    delay(500);
    Serial.print(" minVal = ");
    Serial.print(_minVal);
    Serial.print(" maxVal = ");
    Serial.print(_maxVal);
    Serial.print(" deadMin = ");
    Serial.print(_deadMin);
    Serial.print(" deadMax = ");
    Serial.print(_deadMax);
    Serial.print(" outMin = ");
    Serial.print(_outMin);
    Serial.print(" outMax = ");
    Serial.print(_outMax);
    Serial.println();
    }
    }
    }

    int Map(int value) {
    if( value < _minVal ) {
    return _outMin;
    } else if ( value < _deadMin ) {
    return map( value, _minVal, _deadMin, _outMin, _outMid );
    } else if ( value < _deadMax ) {
    return _outMid;
    } else if ( value < _maxVal ) {
    return map( value, _deadMax, _maxVal, _outMid, _outMax );
    } else {
    return _outMax;
    }
    }
    private:
    int _minVal, _maxVal, _deadMin, _deadMax, _outMin, _outMax, _outMid;
    };

    CustomCalibration leftRightCalibration, fwdBackCalibration;

    void setup() {
    // MIDI Range constants
    int midiMin = 0;
    int midiMax = 127;

    // Initialise the Serial port (MIDI is sent over Serial)
    Serial.begin(31250);//(19200);//

    // Create custom mapping objects (they map the Hall Effect sensor values to the MIDI range - and incorporate a 'dead spot')
    leftRightCalibration = CustomCalibration();
    fwdBackCalibration = CustomCalibration();

    // Load calibration points from the EEPROM (these are stored during the calibration routine)
    leftRightCalibration.setup( EEPROM.read(VIBE_LR_MIN1) + EEPROM.read(VIBE_LR_MIN2)*256, EEPROM.read(VIBE_LR_MAX1) + EEPROM.read(VIBE_LR_MAX2)*256,
    EEPROM.read(VIBE_LR_DEAD_MIN1) + EEPROM.read(VIBE_LR_DEAD_MIN2)*256, EEPROM.read(VIBE_LR_DEAD_MAX1) + EEPROM.read(VIBE_LR_DEAD_MAX2)*256, midiMin, ( ( midiMax * 2 ) / 3 ) + 1 );
    fwdBackCalibration.setup( EEPROM.read(VIBE_FB_MIN1) + EEPROM.read(VIBE_FB_MIN2)*256, EEPROM.read(VIBE_FB_MAX1) + EEPROM.read(VIBE_FB_MAX2)*256,
    EEPROM.read(VIBE_FB_DEAD_MIN1) + EEPROM.read(VIBE_FB_DEAD_MIN2)*256, EEPROM.read(VIBE_FB_DEAD_MAX1) + EEPROM.read(VIBE_FB_DEAD_MAX2)*256, midiMin, ( midiMax * 1 ) / 3 );
    }

    void loop() {
    // Read Sensors
    int leftRightRawValue = analogRead( SENSOR_LEFT_RIGHT );
    int fwdBackRawValue = analogRead( SENSOR_FWD_BACK );
    // Map to MIDI range
    int leftRightValue = leftRightCalibration.Map( leftRightRawValue );
    int fwdBackValue = fwdBackCalibration.Map( fwdBackRawValue );
    // Combine Left-Right and Forward-Back into a single bend measurement
    int bendVal = leftRightValue + fwdBackValue;
    // Send as MIDI command
    MIDImessage(pitchBEND, 0, bendVal);

    }

    void MIDImessage(int command, int MIDInote, int MIDIvelocity) {
    Serial.write(command);
    Serial.write(MIDInote);
    Serial.write(MIDIvelocity);
    delay(20);
    }

    Any ideas?

    sonicmanipulator

  2. #2
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,110
    Quote Originally Posted by sonicmanipulator View Post
    Hi all.......I have a program that runs fine on a Mega and it also works on the Teensy 2.0 in serial mode (using Hairless) but will not work in MIDI mode. Haven't found any joy on the net. It's for a device to send MIDI pitch bend...
    Do you mean you want MIDI through the USB interface? You will have to convert to usbMIDI send command.

    You need something like this:
    usbMIDI.sendPitchBend(value, channel)

    in place of this:
    MIDImessage(pitchBEND, 0, bendVal);

    Documentation page: https://www.pjrc.com/teensy/td_midi.html

    Does the calibration stuff all work?

  3. #3
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,110
    As the MIDImessage() call contains a delay(20) command you may need to add a delay in after calling the usbMIDI send to limit output.

  4. #4

    Midi Problems

    Quote Originally Posted by oddson View Post
    Do you mean you want MIDI through the USB interface? You will have to convert to usbMIDI send command.

    You need something like this:
    usbMIDI.sendPitchBend(value, channel)

    in place of this:
    MIDImessage(pitchBEND, 0, bendVal);

    Documentation page: https://www.pjrc.com/teensy/td_midi.html

    Does the calibration stuff all work?
    Thanks for getting back so quick. I did this:


    void loop() {
    // Read Sensors
    int leftRightRawValue = analogRead( SENSOR_LEFT_RIGHT );
    int fwdBackRawValue = analogRead( SENSOR_FWD_BACK );
    // Map to MIDI range
    int leftRightValue = leftRightCalibration.Map( leftRightRawValue );
    int fwdBackValue = fwdBackCalibration.Map( fwdBackRawValue );
    // Combine Left-Right and Forward-Back into a single bend measurement
    int bendVal = leftRightValue + fwdBackValue;
    // Send as MIDI command
    usbMIDI.sendPitchBend( 0, bendVal);
    delay(20);
    }

    void MIDImessage(int command, int MIDInote, int MIDIvelocity) {
    Serial.write(command);
    Serial.write(MIDInote);
    Serial.write(MIDIvelocity);
    delay(20);
    }

    with the extra delay. I now get MIDI but the PB values are turning into channel numbers. I should probably know this (I'm not a native coder and a friend wrote the code for me. I tried swapping the order around but no joy. The cal routine works as it's before the MIDI part. Any suggestions?

    sonicmanipulator

  5. #5
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,110
    Quote Originally Posted by sonicmanipulator View Post
    .... I tried swapping the order around but no joy...
    Joy or no, that's how they go. Value then channel.
    If the calibration is not working that would explain why reversing the parameters didn't sort it. I don't understand it sufficiently. Are there error messages in the serial print window?

  6. #6
    Quote Originally Posted by oddson View Post
    Joy or no, that's how they go. Value then channel.
    If the calibration is not working that would explain why reversing the parameters didn't sort it. I don't understand it sufficiently. Are there error messages in the serial print window?
    Ok, I did it again an now I get the channel first, then Value then BP command. Should be BP then Value......mmmmmm

    usbMIDI.sendPitchBend( bendVal,1);
    delay(20);
    }

    void MIDImessage(int command, int MIDInote, int MIDIvelocity) {
    Serial.write(command);
    Serial.write(MIDInote);
    Serial.write(MIDIvelocity);
    delay(20);
    }

  7. #7
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,101
    now I get the channel first, then Value then BP command
    What program are you using that displays these values?
    I wrote a sketch to send a "usbMIDI.sendPitchBend( 43,1);" message every half second to the PC and used MIDI-Ox to monitor it. MidiOx receives and displays the correct message - "E0 2B".

    Pete

  8. #8
    Quote Originally Posted by el_supremo View Post
    What program are you using that displays these values?
    I wrote a sketch to send a "usbMIDI.sendPitchBend( 43,1);" message every half second to the PC and used MIDI-Ox to monitor it. MidiOx receives and displays the correct message - "E0 2B".

    Pete
    Interesting. I'm on a Mac using Logic Pro x. I found the MIDI message part at the end is redundant but for some reason it's still sending those 2 bytes ass about (to use a technical term). So close!! Can you put your code up and I'll see if it works on mine.

    If you're interested in the controllers I'm using, here's a video:

    https://www.youtube.com/watch?v=-bYc_AINC3I

    sonicmanipulator

  9. #9
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,101
    Code:
    void setup()
    {
    }
    void loop()
    {
      usbMIDI.sendPitchBend( 43,1);
      delay(500);
    }
    Pete

  10. #10
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,110
    The last six lines should not just be redundant they should never fire... you should be able to delete them without impact on how the sketch runs.

    If deleting them changes things then I'm not understanding what the code is doing.

    I would forget about the midi output until you are sure bendVal is tracking as you would expect.

    I would put in a serial.print(bendVal) next to the midi send and make sure you're seeing sensible values that reflect the movements detected by the hall sensors. (Maybe up the delay to 500 to slow down the print so you can see the values as you move the bar slowly.)
    Last edited by oddson; 10-06-2016 at 06:02 PM.

  11. #11
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,110
    oh.. and without the configuration file no one can really know what's going on with the calibration routine which is far-and-away the most complex thing going on here.

  12. #12
    Senior Member
    Join Date
    Aug 2013
    Location
    Gothenburg, Sweden
    Posts
    293
    The exchange of comments is confusing, and its very hard to give advice to the OP.

    How is the Teensy connected to the host (Mac) USB MIDI or Serial Midi and a MIDI dongle, or perhaps both ?

    What is the expected response behaviour of the program, what data do you expect to receive and what is the data that is actually is received ?

    I found the MIDI message part at the end is redundant but for some reason it's still sending those 2 bytes ass about (to use a technical term).
    What bytes are received through what channel ? How do you see the offending bytes ?

    Without precisely describing the current setup, the expected results and then the observed results it is almost impossible to give much help.

  13. #13
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,101
    it's still sending those 2 bytes ass about
    All I have to go on is that you say the message is received backwards but you still haven't explained precisely how you know that those two bytes are the wrong way round.
    MidiOx on a PC shows that it correctly receives the pitchbend message from my sketch on a Teensy. So the Teensy is sending the correct message.
    You aren't receiving it correctly.


    Pete

  14. #14
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,110
    Quote Originally Posted by mlu View Post
    The exchange of comments is confusing, and its very hard to give advice to the OP.
    True...
    How is the Teensy connected to the host (Mac) USB MIDI or Serial Midi and a MIDI dongle, or perhaps both ?
    If it was not via USB MIDI it would not compile with usbMIDI.sendPitchBend() in the code.

    What is the expected response behaviour of the program, what data do you expect to receive and what is the data that is actually is received ?
    I'm not sure of the mapping... as I said above... but there are apparently two hall-effect sensors that produce voltages based on their motion from a stable mid position. So there is effectively a two-dimensional mapping to a single pitchbend value. By avoiding the midi side at first and using serial.print() to output the bendVal the OP might be able to see what's not working correctly.

    If it was failing outright I would expect the OP would have seen error messages in the serial monitor from this line returning 'true' and printing troubleshooting info:
    if ( minVal > deadMin || deadMin > deadMax || deadMax > maxVal || outMin > outMax )

    What bytes are received through what channel ? How do you see the offending bytes ?
    Yes... OP needs to be more precise when describing observed behaviour -- especially since no one is likely going to whip-up the hardware on their end just to test.

    Without precisely describing the current setup, the expected results and then the observed results it is almost impossible to give much help.
    I've assumed the hardware is two hall-effect analog output sensors that do not vary across the full voltage range and therefore need to be calibrated before being mapped. Without the configuration details it's impossible to say how.

    It's common for MIDI projects to attract coding neophytes and it's just as common to not know where to start and to try too difficult a project for a first go... in this case the example project being altered is less simple than most midi controllers because of the remapping issue. If the OP can sort out that part they might have a chance at porting this to usbMIDI but it looks like it might be tricky. In the absence of the missing file I can't say more.
    Last edited by oddson; 10-06-2016 at 07:04 PM.

  15. #15
    Senior Member
    Join Date
    Aug 2013
    Location
    Gothenburg, Sweden
    Posts
    293
    Since the code supposedly works on a Teensy in serial mode, I assume the issues is in transitioning from serial MIDI to USB MIDI, rather than the sensors themselves.

    Wrongly calibrated sensors will create weird behaviour, but not communication bytes in 'wrong' places

  16. #16
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,110
    Quote Originally Posted by mlu View Post
    ...Wrongly calibrated sensors will create weird behaviour, but not communication bytes in 'wrong' places
    Of course...

    The old code is using the second byte not as midi channel but as the second byte of data for the pitchbend which it's leaving as zero.

    usbMIDI.sendPitchBend() needs to have a 14 bit integer range not 7 so the line would be:

    usbMIDI.sendPitchBend(bendVal<<7,1);

  17. #17
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,110
    I suspect the data-byte order issue is related to that as the low values sent as the bend amount may have looked like channel 0.

    bendVal<<7 is a fancy way have multiplying by 128 to bring the bit levels up from 7 to 14 bits.

    I'd still like to see the config file as it's doing something interesting and I'd like to know how.
    Last edited by oddson; 10-06-2016 at 08:23 PM.

  18. #18
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,101
    Just to clarify: MidiOx actually reports "E0 2B 00". The low order 7 bits of a pitchbend value are sent first. The value of 43 that my code sends, is sent as 43 (= 0x2B) in the low order (first) 7 bits and the remaining bits are zero.

    usbMIDI.sendPitchBend() needs to have a 14 bit integer range not 7 so the line would be:

    usbMIDI.sendPitchBend(bendVal<<7,1);
    No. You don't need to shift the value up. The MIDI library pitchbend routine accepts an integer and sends the command byte, then the low order 7 bits of the pitchbend value followed by the next higher order 7 bits.

    Pete

  19. #19
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,110
    ...No. You don't need to shift the value up.
    usbMIDI.sendPitchBend(value, channel)
    The function takes two parameters, value and channel. The two data bytes (that contain 14 bits of pitchbend resolution data) are extracted from the integer value such that:
    • 0 is full bend down
    • 16383 is full up
    • 8192 is no bend


    If you have only 7 bits of data you would pad the LSB with zero -- which is what the code at the bottom was doing with the original MIDI call. To do the same thing in the usbMIDI library you need to shift the data up 7 bits.

    I did some testing... I'm pretty sure.

  20. #20
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,101
    I checked out my SY77 synth and 61es keyboard and you are correct. They both change only the high order 7 bits.

    Pete

  21. #21
    Quote Originally Posted by oddson View Post
    True...

    If it was not via USB MIDI it would not compile with usbMIDI.sendPitchBend() in the code.

    I'm not sure of the mapping... as I said above... but there are apparently two hall-effect sensors that produce voltages based on their motion from a stable mid position. So there is effectively a two-dimensional mapping to a single pitchbend value. By avoiding the midi side at first and using serial.print() to output the bendVal the OP might be able to see what's not working correctly.

    If it was failing outright I would expect the OP would have seen error messages in the serial monitor from this line returning 'true' and printing troubleshooting info:
    if ( minVal > deadMin || deadMin > deadMax || deadMax > maxVal || outMin > outMax )

    Yes... OP needs to be more precise when describing observed behaviour -- especially since no one is likely going to whip-up the hardware on their end just to test.

    I've assumed the hardware is two hall-effect analog output sensors that do not vary across the full voltage range and therefore need to be calibrated before being mapped. Without the configuration details it's impossible to say how.

    It's common for MIDI projects to attract coding neophytes and it's just as common to not know where to start and to try too difficult a project for a first go... in this case the example project being altered is less simple than most midi controllers because of the remapping issue. If the OP can sort out that part they might have a chance at porting this to usbMIDI but it looks like it might be tricky. In the absence of the missing file I can't say more.


    Thanks for all your comments.

    So to be clear, I'm using the usbMIDI going into a Mac running Logic X. The environment input viewer displays channel, command, value.
    Using the code below I get channel, value, command. The values display 0 - 127 when I move the bar suggesting the program works. When I use the non usbMIDI code running on a MEGA, I connect the TX (MIDI) out to a MIDI to USB circuit and it sends everything fine. And I know if the cal routine doesn't add up, the program won't run. So it must be the way the Teensy deals with MIDI. It wouldn't be a library thing would it?

    A very vexing problem


    void loop() {
    // Read Sensors
    int leftRightRawValue = analogRead( SENSOR_LEFT_RIGHT );
    int fwdBackRawValue = analogRead( SENSOR_FWD_BACK );
    // Map to MIDI range
    int leftRightValue = leftRightCalibration.Map( leftRightRawValue );
    int fwdBackValue = fwdBackCalibration.Map( fwdBackRawValue );
    // Combine Left-Right and Forward-Back into a single bend measurement
    int bendVal = leftRightValue + fwdBackValue;
    // Send as MIDI command
    //MIDImessage(pitchBEND, 0, bendVal);
    usbMIDI.sendPitchBend( bendVal,1);
    delay(20);
    }
    /*void MIDImessage(int command, int MIDInote, int MIDIvelocity) {
    Serial.write(command);
    Serial.write(MIDInote);
    Serial.write(MIDIvelocity);
    delay(20);
    }*/

  22. #22
    Quote Originally Posted by oddson View Post
    True...

    If it was not via USB MIDI it would not compile with usbMIDI.sendPitchBend() in the code.

    I'm not sure of the mapping... as I said above... but there are apparently two hall-effect sensors that produce voltages based on their motion from a stable mid position. So there is effectively a two-dimensional mapping to a single pitchbend value. By avoiding the midi side at first and using serial.print() to output the bendVal the OP might be able to see what's not working correctly.

    If it was failing outright I would expect the OP would have seen error messages in the serial monitor from this line returning 'true' and printing troubleshooting info:
    if ( minVal > deadMin || deadMin > deadMax || deadMax > maxVal || outMin > outMax )

    Yes... OP needs to be more precise when describing observed behaviour -- especially since no one is likely going to whip-up the hardware on their end just to test.

    I've assumed the hardware is two hall-effect analog output sensors that do not vary across the full voltage range and therefore need to be calibrated before being mapped. Without the configuration details it's impossible to say how.

    It's common for MIDI projects to attract coding neophytes and it's just as common to not know where to start and to try too difficult a project for a first go... in this case the example project being altered is less simple than most midi controllers because of the remapping issue. If the OP can sort out that part they might have a chance at porting this to usbMIDI but it looks like it might be tricky. In the absence of the missing file I can't say more.
    Here's a possible clue - I swapped the usbMIDI for CC and sends everything in the right order:

    // Send as MIDI command
    usbMIDI.sendControlChange(7, bendVal, 1);
    //usbMIDI.sendPitchBend( bendVal,1);
    delay(20);
    }

  23. #23
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,110
    Control change works because usbMIDI.sendControlChange() is expecting a 7-bit value as it's data parameter.

    As I've said above (#16, 17 and 19) usbMIDI.sendPitchBend is looking for 14 bits of range and so to get a sweep of the fullest range you need to multiply your 7-bit value by 128 (or shift the bits up by 7 places in its binary form which is the same thing).

    Did you try

    usbMIDI.sendPitchBend( bendVal<<7,1);

    This should give you pitchbend output across the full* range

  24. #24
    Quote Originally Posted by oddson View Post
    Control change works because usbMIDI.sendControlChange() is expecting a 7-bit value as it's data parameter.

    As I've said above (#16, 17 and 19) usbMIDI.sendPitchBend is looking for 14 bits of range and so to get a sweep of the fullest range you need to multiply your 7-bit value by 128 (or shift the bits up by 7 places in its binary form which is the same thing).

    Did you try

    usbMIDI.sendPitchBend( bendVal<<7,1);

    This should give you pitchbend output across the full* range
    YES YES YES!!! you've done it - praise him with great praise!
    Thanks so much.......it's been doing my brain in. Much relieved.

    sonicmanipulator

  25. #25
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,101
    That only leaves the mystery of how this code was supposed to work on a Mega and Teensy2 but needs a modification to work with USBSerial when AFAICT all the drivers involved handle the pitchbend value in the same way.

    Pete

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •