usbMIDI transmission error

Rolfdegen

Well-known member
Hello teensy friends


I programmed a midi dump function for my Synthesizer with Teensy 4.1. Transmission errors occur when I send Patch Bank data to the PC via usbMIDI.sendSysEx. The data packet is 128 * 348 bytes in size.

I have added long waiting times after 348 bytes to avoid transmission errors. But I'm not sure if this is the right way.

Thanks for help :)


SysEx dump.jpg



Code:
//*************************************************************************
// usbMidi send SystemExclusive
//*************************************************************************
FLASHMEM void mySendSysEx(void)
{
    screenFlagSysex = true;    // draw ProgressBar
    
    byte sysexData[350];            // SysEx buffer 349 Byte
    
    uint8_t patchNo = (sysexSource + 1);            // Patch No 1-128
    //uint8_t currentPatchBank = sysexBank;            // A-P = 0-15
    String numString = (patchNo);
    //String bankString = char(currentPatchBank + 65);
    //String fileString = (bankString + "/" + numString);
    uint8_t data_len = NO_OF_PARAMS;
    uint16_t sysexCount = 0;
    uint8_t filenumbers = 0;
    uint8_t delayTime = 120;
    
    // set filenumbers
    if (sysexTyp == 0) {
        filenumbers = 1;
    } else {
        filenumbers = 128;
    }
    
    for (uint8_t i = 0; i < filenumbers; i++) {
        
        if (sysexTyp == 0) {
            numString = String(patchNo);
        } else {
            numString = String(i + 1);
        }
        
        String bankString = char(sysexBank + 65);
        String fileString = (bankString + "/" + numString);
        
        // get Sound File String
        File patchFile = SD.open(fileString.c_str());
        String data[data_len]; //Array of data read in
        recallPatchData(patchFile, data);
        patchFile.close();
        
        // Sysex data                                                  // Ind. len   value
        sysexData[sysexCount++] = 0xF0;                                // -    0    - Start SysEx
        sysexData[sysexCount++] = 0x00;                                // -    1    - ID
        sysexData[sysexCount++] = 0x00;                                // -    2    - ID
        sysexData[sysexCount++] = 0x00;                                // -    3    - ID
        sysexData[sysexCount++] = 0x00;                                // -    4    - Device ID 0-64
        sysexData[sysexCount++] = patchNo;                            // -    5    - Patch No
        sysexData[sysexCount++] = currentPatchBank;                    // -    6    - Bank No
        float_to_string(data[0], 12, sysexCount, sysexData);        // (0)    12    7    - Patch Name
        float_to_sysex1Byte(data[1], sysexCount, sysexData);        // (1)    1    19  - oscALevel (0 - 1.00)
        float_to_sysex1Byte(data[2], sysexCount, sysexData);        // (2)    1    20  - oscBLevel (0 - 1.00)
        float_to_sysex2Bytes(data[3], sysexCount, sysexData);        // (3)    2    21  - noiseLevel ( -1.00 - +1.00)
        uint8_to_sysex1Byte(data[4], sysexCount, sysexData);        // (4)    1    23  - unison (0 - 2)
        uint8_to_sysex1Byte(data[5], sysexCount, sysexData);        // (5)    1    24  - oscFX    (0 - 6)
        float_to_sysex5Bytes(data[6], sysexCount, sysexData);        // (6)    5     25  - detune (0 - 1.00000)
        //sysexCount = String_to_bin(data[7], 4, sysexCount);        // (7)             - lfoSyncFreq (not available)
        float_to_string(data[8], 4, sysexCount, sysexData);            // (8)    4    30    - midiClkTimeInterval
        //sysexCount = String_to_bin(data[9], 4, sysexCount);        // (9)            - lfoTempoValue (not available)
        float_to_sysex5Bytes(data[10], sysexCount, sysexData);        // (10) 5     34  - keytrackingAmount (0 - 1.0000)
        float_to_sysex5Bytes(data[11], sysexCount, sysexData);        // (11)    5    39  - glideSpeed (0 - 1.00000)
        int8_to_sysex2Bytes(data[12], sysexCount, sysexData);        // (12)    2    44  - oscPitchA (-24 - +24)
        int8_to_sysex2Bytes(data[13], sysexCount, sysexData);        // (13) 2     46  - oscPitchB (-24 - +24)
        uint8_to_sysex1Byte(data[14], sysexCount, sysexData);        // (14) 1     48  - oscWaveformA (0 - 63)
        uint8_to_sysex1Byte(data[15], sysexCount, sysexData);        // (15)    1    49    - oscWaveformB (0 - 63)
        //sysexCount = String_to_bin(data[9], 4, sysexCount);        // (16)            - pwmSource (1) (not available)
        float_to_sysex1Byte(data[17], sysexCount, sysexData);        // (17) 1   50  - pwmAmtA (0 - 0.99)
        float_to_sysex1Byte(data[18], sysexCount, sysexData);        // (18) 1   51  - pwmAmtB (0 - 0.99)
        //sysexCount = String_to_bin(data[19], 6, sysexCount);        // (19)            - pwmRate (not available)
        float_to_sysex2Bytes(data[20], sysexCount, sysexData);        // (20) 2     52  - pwA (-1.00 - +1.00)
        float_to_sysex2Bytes(data[21], sysexCount, sysexData);        // (21) 2     54  - pwB (-1.00 - +1.00)
        float_to_string(data[22], 4, sysexCount, sysexData);        // (22) 4    56  - filterRes (0 - 15.0)
        uint14_to_sysex2Bytes(data[23], sysexCount, sysexData);        // (23) 2     60  - filterFreq (18 - 12000)
        float_to_string(data[24], 4, sysexCount, sysexData);        // (24) 4     62  - filterMix (0 - -99.0)
        float_to_sysex2Bytes(data[25], sysexCount, sysexData);        // (25) 2    66  - filterEnv (-1.00 - +1.00)
        float_to_sysex5Bytes(data[26], sysexCount, sysexData);        // (26) 5    67  - oscLfoAmt (0 - 1.00000)
        float_to_sysex5Bytes(data[27], sysexCount, sysexData);        // (27) 5     73  - oscLfoRate (0 - 40.0000)
        uint8_to_sysex1Byte(data[28], sysexCount, sysexData);        // (28) 1     78  - oscLFOWaveform (0 - 12)
        uint8_to_sysex1Byte(data[29], sysexCount, sysexData);        // (29) 1     79  - oscLfoRetrig (0 - 1)
        //sysexCount = String_to_bin(data[30], 1, sysexCount);        // (30)         - oscLFOMidiClkSync (not available)
        uint8_to_sysex1Byte(data[31], sysexCount, sysexData);        // (31) 1     80  - myFilterLFORateValue (1 - 127)
        uint8_to_sysex1Byte(data[32], sysexCount, sysexData);        // (32) 1    81  - filterLfoRetrig (0 - 1)
        //sysexCount = String_to_bin(data[33], 1, sysexCount);        // (33)         - oscLFOMidiClkSync (not available)
        float_to_sysex5Bytes(data[34], sysexCount, sysexData);        // (34) 5     82  - filterLfoAmt (0 - 1.00000)
        uint8_to_sysex1Byte(data[35], sysexCount, sysexData);        // (35) 1    87  - filterLFOWaveform (0 - 12)
        uint14_to_sysex2Bytes(data[36], sysexCount, sysexData);        // (36) 2    88  - filterAttack (0 - 11880)
        uint14_to_sysex2Bytes(data[37], sysexCount, sysexData);        // (37) 2     90  - filterDecay (0 - 11880)
        float_to_sysex1Byte(data[38], sysexCount, sysexData);        // (38) 1    92  - filterSustain (0 - 1.00)
        uint14_to_sysex2Bytes(data[39], sysexCount, sysexData);        // (39) 2    94  - filterRelease (0 - 11880)
        uint14_to_sysex2Bytes(data[40], sysexCount, sysexData);        // (40) 2    96  - ampAttack (0 - 11880)
        uint14_to_sysex2Bytes(data[41], sysexCount, sysexData);        // (41) 2     98  - ampDecay (0 - 11880)
        float_to_sysex1Byte(data[42], sysexCount, sysexData);        // (42) 1    100  - ampSustain (0 - 1.00)
        uint14_to_sysex2Bytes(data[43], sysexCount, sysexData);        // (43) 2     101  - ampRelease (0 - 11880)
        //sysexCount = String_to_bin(data[44], 4, sysexCount);        // (44)          - fxAmt (not available)
        //sysexCount = String_to_bin(data[45], 4, sysexCount);        // (47)          - Dummy                                                        // (45)            - fxMix (not available)
        //sysexCount = String_to_bin(data[46], 4, sysexCount);        // (46)           - pitchEnv (not available)
        uint8_to_sysex1Byte(data[47], sysexCount, sysexData);        // (47) 1    102  - velocitySens (0-4)
        uint8_to_sysex1Byte(data[48], sysexCount, sysexData);        // (48) 1    103  - chordDetune (0 - 127)
        uint8_to_sysex1Byte(data[49], sysexCount, sysexData);        // (49) 1    104  - FxPot1value (0 - 127)
        uint8_to_sysex1Byte(data[50], sysexCount, sysexData);        // (50) 1    105  - FxPot2value (0 - 127)
        uint8_to_sysex1Byte(data[51], sysexCount, sysexData);        // (51) 1    106  - FxPot3value (0 - 127)
        uint8_to_sysex1Byte(data[52], sysexCount, sysexData);        // (52) 1    107  - FxPrgNo (0 - 15)
        uint8_to_sysex1Byte(data[53], sysexCount, sysexData);        // (53) 1    108  - FxMixValue (0 - 127)
        float_to_sysex5Bytes(data[54], sysexCount, sysexData);        // (54) 5    109  - FxMixValue (10000 - 60000)
        uint8_to_sysex1Byte(data[55], sysexCount, sysexData);        // (55) 1    114  - Osc1WaveBank (0 - 15)
        uint8_to_sysex1Byte(data[56], sysexCount, sysexData);        // (56) 1    115  - Osc1WaveBank (0 - 15)
        uint8_to_sysex1Byte(data[57], sysexCount, sysexData);        // (57) 1    116  - myBoost (0 - 1)
        float_to_sysex5Bytes(data[58], sysexCount, sysexData);        // (58) 5    117  - pitchEnvA (-1.00 - +1.00)
        float_to_sysex5Bytes(data[59], sysexCount, sysexData);        // (59) 5    119  - pitchEnvB (-1.00 - +1.00)
        float_to_sysex2Bytes(data[60], sysexCount, sysexData);        // (60) 2    121  - driveLevel (Osc level) (0.00 - 1.25)
        float_to_sysex5Bytes(data[61], sysexCount, sysexData);        // (61) 5    123  - myFilVelocity (0 - 1.00)
        
        
        // wait time (protection for buffer overflow)
        usbMIDI.sendSysEx(sysexCount, sysexData, true);
        sysexCount = 0;
        delay(delayTime);
        
        
        float_to_sysex5Bytes(data[62], sysexCount, sysexData);        // (62) 2    125  - myAmpVelocity (0 - 1.00)
        uint8_to_sysex1Byte(data[63], sysexCount, sysexData);        // (63) 1    127  - myUnisono (0-2)
        //sysexCount = String_to_bin(data[46], 4, sysexCount);        // (64)             - (not available)
        //sysexCount = String_to_bin(data[46], 4, sysexCount);        // (65)             - (not available)
        uint8_to_sysex1Byte(data[66], sysexCount, sysexData);        // (66) 1    128  - WShaperNo (0-14)
        float_to_sysex5Bytes(data[67], sysexCount, sysexData);        // (67) 5    129  - WShaperDrive (0.10 - 5.00)
        uint14_to_sysex2Bytes(data[68], sysexCount, sysexData);        // (68) 2    134  - LFO1phase (0 - 180.0)
        uint14_to_sysex2Bytes(data[69], sysexCount, sysexData);        // (69) 2    139  - LFO2phase (0 - 180.0)
        for (uint8_t i = 0; i < 16; i++) {
            uint8_to_sysex1Byte(data[70+i], sysexCount, sysexData);    // (70-85)  16    144 - SeqNote1Buf (0 - 127)
        }
        for (uint8_t i = 0; i < 16; i++) {
            uint8_to_sysex1Byte(data[86+i], sysexCount, sysexData);    // (86-101) 16    160 - SeqNoteBufStatus (0 - 1)
        }
        uint14_to_sysex2Bytes(data[102], sysexCount, sysexData);    // (102) 2     176  - SEQbpmValue (101 - 462)
        float_to_sysex5Bytes(data[103], sysexCount, sysexData);        // (103) 5    178  - SEQdivValue (float)
        uint8_to_sysex1Byte(data[104], sysexCount, sysexData);        // (104) 1    183  - SEQstepNumbers (0 - 15)
        float_to_sysex5Bytes(data[105], sysexCount, sysexData);        // (105) 5    184  - SEQGateTime (float)
        uint8_to_sysex1Byte(data[106], sysexCount, sysexData);        // (106) 1    189  - SEQdirection (0 - 3)
        uint8_to_sysex1Byte(data[107], sysexCount, sysexData);        // (107) 1    190  - oscDetuneSync (0 - 1)
        int8_to_sysex2Bytes(data[108], sysexCount, sysexData);        // (108) 2    191  - oscPitchA (-12 - +12)
        float_to_sysex5Bytes(data[109], sysexCount, sysexData);        // (109) 5    193  - oscMasterTune (float)
        float_to_sysex5Bytes(data[110], sysexCount, sysexData);        // (110) 5    198  - OscVCFMOD (float)
        for (uint8_t i = 0; i < 16; i++) {
            uint8_to_sysex1Byte(data[111+i], sysexCount, sysexData);    // (111-126) 16     203 - SeqVeloBuf (0 - 127)
        }        
        for (uint8_t i = 0; i < 48; i++) {
            uint8_to_sysex1Byte(data[127+i], sysexCount, sysexData);    // (127-174) 48     219 - SeqNote1Buf (0 - 127)
        }
            
        for (uint8_t i = 0; i < 16; i++) {
            uint8_to_sysex1Byte(data[175+i], sysexCount, sysexData);    // (175-190) 16     267 - SeqNoteCount (0 - 3)
        }        
        uint8_to_sysex1Byte(data[191], sysexCount, sysexData);        // (191) 1    283 - SEQmode (0 - 2)
        uint8_to_sysex1Byte(data[192], sysexCount, sysexData);        // (192) 1    284 - SEQMidiClkSwitch (0 - 1)
        uint8_to_sysex1Byte(data[193], sysexCount, sysexData);        // (193) 1    285 - LadderFilterpassbandgain (0 - 127)
        uint8_to_sysex1Byte(data[194], sysexCount, sysexData);        // (194) 1    286 - LadderFilterDrive (1 - 127)
        int8_to_sysex2Bytes(data[195], sysexCount, sysexData);        // (195) 2    287 - envelopeType1 (-8 - +8)
        int8_to_sysex2Bytes(data[196], sysexCount, sysexData);        // (196) 2    289 - envelopeType2 (-8 - +8)
        float_to_sysex5Bytes(data[197], sysexCount, sysexData);        // (197) 5    291 - PitchWheelAmt (float)
        float_to_sysex5Bytes(data[198], sysexCount, sysexData);        // (198) 5    296 - MODWheelAmt (float)
        uint8_to_sysex1Byte(data[199], sysexCount, sysexData);        // (199) 1    301 - myFilter (1 - 2)
        float_to_sysex5Bytes(data[200], sysexCount, sysexData);        // (200) 5    302 - pwmRateA (-10.00 - + 10.00)
        float_to_sysex5Bytes(data[201], sysexCount, sysexData);        // (201) 5    307 - pwmRateB (-10.00 - + 10.00)
        uint14_to_sysex2Bytes(data[202], sysexCount, sysexData);    // (202) 2    312 - LFO1fadeTime (0 - 12000) Fade in
        uint14_to_sysex2Bytes(data[203], sysexCount, sysexData);    // (203) 2    314 - LFO1releaseTime (0 - 12000) Fade out
        float_to_sysex5Bytes(data[204], sysexCount, sysexData);        // (204) 5    316 - filterFM (0.00000 - 1.00000)  Osc1
        float_to_sysex5Bytes(data[205], sysexCount, sysexData);        // (205) 5    321 - filterFM2 (0.00000 - 1.00000)    Osc2
        uint14_to_sysex2Bytes(data[206], sysexCount, sysexData);    // (206) 2    326 - LFO2fadeTime (0 - 12000) Fade in
        uint14_to_sysex2Bytes(data[207], sysexCount, sysexData);    // (207) 2    328 - LFO2releaseTime (0 - 12000) Fade out
        float_to_sysex5Bytes(data[208], sysexCount, sysexData);        // (208) 5    330 - Osc1ModAmt (0.00000 - 1.00000) Fx Mod
        int8_to_sysex2Bytes(data[209], sysexCount, sysexData);        // (209) 2    335 - LFO1enCurve (-8 - +8)
        int8_to_sysex2Bytes(data[210], sysexCount, sysexData);        // (210) 2    337 - LFO2enCurve (-8 - +8)
        uint8_to_sysex1Byte(data[211], sysexCount, sysexData);        // (211) 1    339 - LFO1mode (0 - 1)
        uint8_to_sysex1Byte(data[212], sysexCount, sysexData);        // (212) 1    340 - LFO2mode (0 - 1)
        sysexData[sysexCount++] = 0xF7;                                // 1    346 - End SysEx (0xF7)
        
        usbMIDI.sendSysEx(sysexCount, sysexData, true);        // send SysEx data
        
        // wait time (protection for buffer overflow)
        sysexCount = 0;
        delay(delayTime);
    }


    Serial.println("transfer complete..");
    
}





//*************************************************************************
// convert float to SysEx string
//*************************************************************************
FLASHMEM void float_to_string (String value, uint8_t len, uint16_t &sysexCount, byte *sysexData)
{
    for (uint8_t i = 0; i < len; i++) {
        sysexData[sysexCount++] = value[i];
        sysexChecksum += value[i];
    }
}




//*************************************************************************
// convert float into SysEx uint7Bit  (float 0 - 0.127)
//*************************************************************************
FLASHMEM void float_to_sysex1Byte (String value, uint16_t &sysexCount, byte *sysexData)
{
    uint8_t val = (value.toFloat() * 100);
    sysexData[sysexCount++] = val; 
    sysexChecksum += val;
}








//*************************************************************************
// convert float into SysEx uint7Bit  (- 127 - +127)
//*************************************************************************
FLASHMEM void int8_to_sysex2Bytes (String value, uint16_t &sysexCount, byte *sysexData)
{
    uint8_t l_byte = (uint8_t)(value.toInt());
    uint8_t h_byte = 0;
    
    if (l_byte > 127) {
        l_byte = 256 - l_byte;            // make positive value
        h_byte = 1;                        // minus Sign
    }


    sysexData[sysexCount++] = h_byte;    // Sign (- = 1 / + = 0)
    sysexChecksum += h_byte;
    sysexData[sysexCount++] = l_byte;    // data
    sysexChecksum += l_byte;
}


//*************************************************************************
// convert string into SysEx int7 (float -1.27 - +1.27)
//*************************************************************************
FLASHMEM void float_to_sysex2Bytes (String value, uint16_t &sysexCount, byte *sysexData)
{
    uint8_t h_byte = int8_t(value.toFloat() * 100);                            
    int8_t l_byte = h_byte;
    
    // calc h_byte
    h_byte >>= 7;
    
    // l_byte is sign 
    if (l_byte < 0) {    
        l_byte = l_byte * (-1);
    }
    
    sysexData[sysexCount++] = h_byte;    // Sign (- = 1 / + = 0)
    sysexChecksum += h_byte;
    sysexData[sysexCount++] = l_byte;    // data
    sysexChecksum += l_byte;
}


//*************************************************************************
// convert float into SysEx uint14 (float 0.00 - 16.383)
//*************************************************************************
FLASHMEM uint16_t float_to_uint14bit (String value, uint16_t sysexCount, byte *sysexData)
{
    uint8_t h_byte = int8_t(value.toFloat() * 100);                            
    int8_t l_byte = h_byte;
    
    // calc h_byte
    h_byte >>= 7;
    
    // l_byte is sign 
    if (l_byte < 0) {    
        l_byte = l_byte * (-1);
    }
    
    sysexData[sysexCount++] = h_byte;    // Sign (- = 1 / + = 0)
    sysexChecksum += h_byte;
    sysexData[sysexCount++] = l_byte;    // data
    sysexChecksum += l_byte;
    
    return sysexCount;
}


//*************************************************************************
// convert 7bit value into SysEx 1Byte ( 0-127)
//*************************************************************************
FLASHMEM void uint8_to_sysex1Byte (String value, uint16_t &sysexCount, byte *sysexData)
{
    uint8_t val =  value.toInt();
    sysexData[sysexCount++] = val;
    sysexChecksum += val;
    
}


//*************************************************************************
// convert 14bit value into SysEx 2Byte (0-16383)
//*************************************************************************
FLASHMEM void uint14_to_sysex2Bytes (String value, uint16_t &sysexCount, byte *sysexData)
{
    uint16_t var16 = (value.toInt());
    uint16_t var16_x = var16;
    
    // calc h_byte & l_byte -----------
    var16 = var16 << 1;
    uint8_t h_byte = var16 >> 8;
    uint8_t l_byte = var16_x & 0x7F;
    
    sysexData[sysexCount++] = h_byte;
    sysexChecksum += h_byte;
    sysexData[sysexCount++] = l_byte;
    sysexChecksum += l_byte;    
}




//*************************************************************************
// convert 32bit float value into SysEx 5Byte
//*************************************************************************
FLASHMEM void float_to_sysex5Bytes(String value, uint16_t &sysexCount, byte *sysexData)
{
    uint8_t sysexBytes[5];
    uint8_t temp_val = 0;
    uint8_t bit_val = 0;
    
    union {
        float fval;
        byte bval[4];
    } floatAsBytes;
    
    floatAsBytes.fval = (value.toFloat());
    
    //  Bit mask
    for (uint8_t i = 0; i < 4; i++) {
        
        // Bit 0-6 to Byte 1-4
        sysexBytes[i] = floatAsBytes.bval[i] & 0x7F;
        
        // Bit7 to 5.Byte
        temp_val = floatAsBytes.bval[i];
        bit_val = bit_val << 1;
        if (temp_val >= 128) {
            bit_val = (bit_val | 0x01);
        }
    }
    sysexBytes[4] = bit_val;
    
    // write sysex buffer
    for (uint8_t i = 0; i < 5; i++){
        sysexData[sysexCount++] = sysexBytes[i];
        sysexChecksum += sysexBytes[i];
    }
}
 
Last edited:
Wow, That's huge. Fourth line looks truncated after F0. Seen similar truncations if some data miscalculation tries to send a value >127, not the case here as the four byte header (zeros) was supposed to come next.

My hunch is buffer overrun.
 
Tranfer only one patch, it no error.

To protect against Buffer overflow, I made a wait time 120ms after sending each patch.

Is there a way to query a faulty USB transfer :confused:
 
Largest sysex dump here 4 x 140 bytes. Did need delay but used non-blocking type. What about a ring buffer?
 
After transferring a patch (348 bytes) I wait 120ms. From time to time there are transmission errors.
 
If you post a sketch here that dumps that sysex in response to serial monitor keypress am happy to test on Windows with Midiox.
 
Now.. I have implemented USB and Midi SysEx transmission. USB often has transmission errors. Midi works without error :)

Code:
a lot of sysex data..

        uint14_to_sysex2Bytes(data[207], sysexCount, sysexData);    // (207) 2    328 - LFO2releaseTime (0 - 12000) Fade out
        float_to_sysex5Bytes(data[208], sysexCount, sysexData);        // (208) 5    330 - Osc1ModAmt (0.00000 - 1.00000) Fx Mod
        int8_to_sysex2Bytes(data[209], sysexCount, sysexData);        // (209) 2    335 - LFO1enCurve (-8 - +8)
        int8_to_sysex2Bytes(data[210], sysexCount, sysexData);        // (210) 2    337 - LFO2enCurve (-8 - +8)
        uint8_to_sysex1Byte(data[211], sysexCount, sysexData);        // (211) 1    339 - LFO1mode (0 - 1)
        uint8_to_sysex1Byte(data[212], sysexCount, sysexData);        // (212) 1    340 - LFO2mode (0 - 1)
        sysexData[sysexCount++] = 0xF7;                                // 1    346 - End SysEx (0xF7)
        
        usbMIDI.sendSysEx(sysexCount, sysexData, true);        // send SysEx data via USB
        
        MIDI.sendSysEx(sysexCount, sysexData, true);        // send SysEx data via Midi
        
    }


    Serial.println("transfer complete..");
 
There is an interesting post here https://forum.pjrc.com/threads/4975...ata-on-usbMidi?p=168107&viewfull=1#post168107

It works usb_midi_flush_output() by commenting out into usb.c file in the Arduino Lib.

File Path: C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4

Code:
{
    code...
       
    if ((USB1_USBINTR & USB_USBINTR_SRE) && (status & USB_USBSTS_SRI)) {
        //printf("sof %d\n", usb_reboot_timer);
        if (usb_reboot_timer) {
            if (--usb_reboot_timer == 0) {
                usb_stop_sof_interrupts(NUM_INTERFACE);
                _reboot_Teensyduino_();
            }
        }
        #ifdef MIDI_INTERFACE
        //usb_midi_flush_output();
        #endif
        #ifdef MULTITOUCH_INTERFACE
        usb_touchscreen_update_callback();
        #endif
        #ifdef FLIGHTSIM_INTERFACE
        usb_flightsim_flush_output();
        #endif
    }
}

A patch bank is now transferred error-free via USB in less than 2 seconds :)
Via Midi it takes about 15 seconds.
 
Moderator Edit: some info in this message is technically incorrect. Please see msg #88 for detail.


As I understand it, the usb_midi_flush_output() function is responsible for deleting unread data in the midi buffer.

Since I am constantly querying the Midi buffer in my Polyphonic DIY Synthesizer with MIDI.read() and usbMIDI.read, there should be no disadvantages if this function is switched off.

On github I will then point out the changes in the Arduino Library and the changed usb.c File.

20220505_084324.jpg20220505_092444.jpg20220505_084723.jpg

But my thoughts are still buzzing, why are there transmission errors via USB Midi? :confused:
 
Last edited by a moderator:
Hi,
I've got some problem with usbMidi too.
I try to send a DX7 bank sysex file by usbMidi (file stored on a SD card).

When I send only a patch it's working perfectly.
But when I try to send the whole file (4104 bytes, 32 patches in the bank) then I never receive the 4104 bytes.
On my PC, in Bome SendSx I see that :
Received 1024 bytes succesfully.
Received 3072 bytes of bulk dump (at 341333 bytes/s = 333,33 KB/s)


I never see the 4104 bytes arriving.
I simply use :
usbMIDI.sendSysEx(4104, bank_data, true);

What am I doing wrong ?
Regards
 
I think it's a bug in the teensy 4 USB library. Paul should know what doesn't work there.

I modified the usb.c in the midi library. It works. But it's not a good solution.

File Path: C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4\usb.c

Change red text in line number 364

{
code...

if ((USB1_USBINTR & USB_USBINTR_SRE) && (status & USB_USBSTS_SRI)) {
//printf("sof %d\n", usb_reboot_timer);
if (usb_reboot_timer) {
if (--usb_reboot_timer == 0) {
usb_stop_sof_interrupts(NUM_INTERFACE);
_reboot_Teensyduino_();
}
}
#ifdef MIDI_INTERFACE
//usb_midi_flush_output();
#endif
#ifdef MULTITOUCH_INTERFACE
usb_touchscreen_update_callback();
#endif
#ifdef FLIGHTSIM_INTERFACE
usb_flightsim_flush_output();
#endif
}
}
 

Attachments

  • Sys 1.jpg
    Sys 1.jpg
    432.4 KB · Views: 54
Last edited:
I think it's a bug in the teensy 4 USB library. Paul should know what doesn't work there.

I modified the usb.c in the midi library. It works. But it's not a good solution.
//usb_midi_flush_output();
}

Thanks.
So I've tried it but it doesn't solve the problem for me.
Now I see that:
Received 1024 bytes succesfully.
Received 3235 bytes of bulk dump (at 1078333 bytes/s = 1053,06 KB/s)
 
Which SysEx tool are you using on the PC?

I use Mios Studio without problems. When I use MIDI-OX I have the same problems.
 
In MIDI-OX I discovered an error when receiving SysEx Dump. The number of received SysEx data is displayed incorrectly in the preview window of the SysEx Dump function.
Instead of 44,544 bytes, I see 44,766 bytes. In the large main window, however, the number of bytes is correct.


MidiOX-2.png


However, if the SysEx dump data is saved directly to a file (Sysex Configure > tick "Save Dump directly to file"), no errors occur.
The number of data received matches the data to be sent.

SysEx-1.png




But.. The Sysex transmission problem with usbMidi is still there :confused:

Greetings from germany. Rolf
 
Last edited:
If you disabled in usb.c the usb midi flush output() you have to after midi data has been sent, a flush() must be sent.

This function forces the USB layer to send the data immediately. Since the USB bus is not realtime, a usbMIDI() doesn’t guarantee the data to be sent with the correct timing unless immediately followed by a flush().

Code:
usbMIDI.sendSysEx(buf_lenght, data, true);
usb_midi_flush_output();
 
Thanks Rolf
I've tried all your suggestions, unfortunately I'm still stuck with no complete bank dump.
I'm going crazy with such a "simple" thing.

If my calculations are right (and MIDIOX displays the blocks right) I receive 3584 bytes (14*256 blocks: 1 sysex start block with F0, 13 sysex continue).
So there are 3 blocks missing to get to 4102 bytes:
- 2*256 continue
- 1*8 bytes sysex end (with F7)
 
Last edited:
Been able to reproduce this with the following sketch:-

Code:
#define chunkSize 128
#define delayAmt 100

byte data[chunkSize];

void fillBuff() {
  unsigned scratch;
  for (uint16_t ct = 0; ct <= chunkSize; ct++) {
    scratch = (ct & 0b01111111);
    data[ct] = scratch;
  }
}

void setup() {
  delay(1000);
  fillBuff();
}

void loop() {
  usbMIDI.sendSysEx(chunkSize, data, false, 0);
  delay(delayAmt);
}

Monitored with Midiox.


When the error occurs, a block may be shorter or longer than is supposed to be.
 
I missing usbMidi.read() in your code !

Code:
// discard incoming MIDI messages
 while (usbMIDI.read()) {
    // ignore incoming messages
  }

What Arduino CPU and Windows Version are you using?

I am using Teensy 4.1 with Midi and USB. Both ports work fine with the change in the usb.c file.

You check another tool. MIOS Studio its a very good tool and free.

Link: http://www.ucapps.de/mios_studio.html

My Polyphonic DIY Synthesizer with Teensy 4.1, Midi IN, Midi Out/Thru and USB port
Platinen-R-ckseite.png


Photo-Room-20211216-115228.png


Photo-Room-20211216-114225.png


Link: https://forum.pjrc.com/threads/63255-New-Teensy-4-1-DIY-Synthesizer/page8?highlight=Teensy+Shruthi

Greetings from germany. Rolf
 
Last edited:
Wow, That's huge. Fourth line looks truncated after F0. Seen similar truncations if some data miscalculation tries to send a value >127, not the case here as the four byte header (zeros) was supposed to come next.

My hunch is buffer overrun.

Can you explain to me exactly which line of code you mean?
 
Back
Top