Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 3 FirstFirst 1 2 3 LastLast
Results 26 to 50 of 51

Thread: usbMIDI transmission error

  1. #26
    Senior Member Rolfdegen's Avatar
    Join Date
    Sep 2020
    Location
    Germany
    Posts
    303
    Quote Originally Posted by localhero View Post
    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)

    I do not understand what you mean

    1.Block
    F0 ....data... F7

    2.Block
    F0 ...data... F7

    3.Block
    F0 ...data... F7

    and more..

  2. #27
    Senior Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    316
    Can you explain to me exactly which line of code you mean?
    The fourth line in the screenshot of MIOS Studio in post#1 shows f0 only.

    Sketch in post#23 ran on bare T4.1 usbType MIDI, Win10, IDE 1.8.19 TD 1.56, produced this:-

    Click image for larger version. 

Name:	TruncatedSysex.jpg 
Views:	13 
Size:	193.7 KB 
ID:	28453

    Note the second block, finishes with F0 and has 115 bytes, should be 130.

    If you run the sketch as it is, monitoring, received blocks scroll upwards and when a faulty block is received is easy to spot. Good idea to have Actions open with cursor on Stop Display ready to click. Makes it easier to find the dodgy block.

    Just play with it, change chunkSize and delayAmt. Occurrence of truncated blocks seems pretty random, does seem to happen more frequently with larger blocks.

  3. #28
    Senior Member Rolfdegen's Avatar
    Join Date
    Sep 2020
    Location
    Germany
    Posts
    303
    Did you change the usb.c in your Arduino Library as I suggested ?

    After that it is important that your project has to be completely recompiled (restart Arduino IDE).


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

    Change green text in line number 364

    Last edited by Rolfdegen; 05-23-2022 at 12:02 PM.

  4. #29
    Senior Member Rolfdegen's Avatar
    Join Date
    Sep 2020
    Location
    Germany
    Posts
    303
    This is my code to send SysEx to usbMIDI()

    In the SysEx dump menu from my synthesizer I query a key and set the sendSyssExflag.
    If the flag was true then send sysex dump. I always send a block of 348 bytes.
    Then I increment count for the number of sysex blocks and send the next block.
    After each block I call a usb_midi_flush_output().

    Click image for larger version. 

Name:	20220523_135020.jpg 
Views:	15 
Size:	293.7 KB 
ID:	28455Click image for larger version. 

Name:	20220523_135048.jpg 
Views:	15 
Size:	305.1 KB 
ID:	28456


    Code:
    //*************************************************************************
    // Update SysEx Status
    //*************************************************************************
    FLASHMEM void updateSysExStatus(void)
    {
        // send SysEx ---------------------------------------------------------
        if (sendSysExFlag == true){
    
    
            static uint8_t count = 0;
            uint8_t filenumbers = 0;
            uint8_t patchno = 0;
            
            if (sysexDest == false && sysexTyp == false) {        // Patch via USB
                filenumbers = 1;                                // Filenumbers = 1
                progressBarPercent = 300;                        // Progressbar fast
                patchno = sysexSource;                            // set Patch No from menu
                timer_ProgressbarFlag = true;                    // start Progressbar
            } 
            else if (sysexDest == false && sysexTyp == true){    // Bank via USB
                filenumbers = 128;                                // Filenumbers = 128
                progressBarPercent = 110;                        // Progressbar slow
                patchno = 0;                                    // start Patch No                    
                timer_ProgressbarFlag = true;                    // start Progressbar
            }
            else if (sysexDest == true && sysexTyp == false) {    // Patch via Midi
                filenumbers = 1;                                // Filenumbers = 1
                progressBarPercent = 300;                        // Progressbar fast
                patchno = sysexSource;                            // set Patch No from menu
                timer_ProgressbarFlag = true;                    // start Progressbar
            }
            else if (sysexDest == true && sysexTyp == true){    // Bank via Midi
                filenumbers = 128;                                // Filenumbers = 128
                progressBarPercent = 7;                            // Progressbar slow
                patchno = 0;                                    // start Patch No
                timer_ProgressbarFlag = true;                    // start Progressbar
            }
            
            
            progressBarFlag = true;                                // start ProgressBar
            uint8_t sysexpatch = patchno + count;
            mySendSysEx(sysexpatch, sysexBank);
            count++;
            
            sysexDataLenght += 348;
                    
            //progressBarPercent = count;
            if (count >= filenumbers) {
                sendSysExFlag = false;
                count = 0;
            }
        }
        
        
        // wait Time to SysEx Receive Data (10sec)
        if (sysexRecTimeStatus == true && time_sysexRecStatus == false) {
            timer_sysexRec = millis();
            time_sysexRecStatus = true;
            if (PageNr == 11 && myPageShiftStatus[11] == true) {
                tft.fillRoundRect(123,20+(19*4),31,10,2,ST7735_RED);
                tft.setTextColor(ST7735_WHITE);
                print_String(198,130,97); // print "REC"
            }
        }
        
        // wait Time end
        else if (sysexRecTimeStatus == true && time_sysexRecStatus == true) {
            if ((millis() - timer_sysexRec) >= 15000){
                sysexRecTimeStatus = false;
                time_sysexRecStatus = false;
                if (PageNr == 11 && myPageShiftStatus[11] == true) {
                    tft.fillRoundRect(123,20+(19*4),31,10,2,ST7735_BLACK);
                    tft.fillRoundRect(123,19+(19*4),31,10,2,ST7735_BLUE);
                    tft.setTextColor(ST7735_WHITE);
                    print_String(198,130,97); // print "REC"
                }
            }
        }
    }
    
    
    //*************************************************************************
    // send Midi system exclusive dump
    //*************************************************************************
    FLASHMEM void mySendSysEx(uint8_t PatchNo, uint8_t BankNo)
    {
        byte sysexData[350];                                        // SysEx buffer 349 Byte
        uint8_t data_len = NO_OF_PARAMS;
        uint16_t sysexCount = 0;
        String numString = String(PatchNo + 1);
        String bankString = char(BankNo + 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();
        
        // convert Patch data into 7bit SysEx format
                                                                       // Ind. len   value
        sysexData[sysexCount++] = 0xF0;                                // -    1    0    - Start SysEx
        sysexData[sysexCount++] = 0x00;                                // -    1    1    - ID
        sysexData[sysexCount++] = 0x00;                                // -    1    2    - ID
        sysexData[sysexCount++] = 0x00;                                // -    1    3    - ID
        sysexData[sysexCount++] = 0x00;                                // -    1    4    - Device ID 0-64
        sysexData[sysexCount++] = PatchNo;                            // -    1    5    - Patch No
        sysexData[sysexCount++] = BankNo;                            // -    1    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)
                                                                    // (7)             - (not available)
        float_to_string(data[8], 4, sysexCount, sysexData);            // (8)    4    30    - midiClkTimeInterval
                                                                    // (9)            - (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)
                                                                    // (16)            - (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)
                                                                    // (19)            - (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)
                                                                    // (30)         - (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)
                                                                    // (33)         - (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)
                                                                    // (44)         - (not available)
                                                                    // (45)         - (not available)
                                                                    // (46)         - (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    122  - pitchEnvB (-1.00 - +1.00)
        float_to_sysex2Bytes(data[60], sysexCount, sysexData);        // (60) 2    127  - driveLevel (Osc level) (0.00 - 1.25)
        float_to_sysex5Bytes(data[61], sysexCount, sysexData);        // (61) 5    129  - myFilVelocity (0 - 1.00)
        float_to_sysex5Bytes(data[62], sysexCount, sysexData);        // (62) 5    134  - myAmpVelocity (0 - 1.00)
        uint8_to_sysex1Byte(data[63], sysexCount, sysexData);        // (63) 1    139  - myUnisono (0-2)
                                                                    // (64)             - (not available)
                                                                    // (65)             - (not available)
        uint8_to_sysex1Byte(data[66], sysexCount, sysexData);        // (66) 1    140  - WShaperNo (0-14)
        float_to_sysex5Bytes(data[67], sysexCount, sysexData);        // (67) 5    141  - WShaperDrive (0.10 - 5.00)
        uint14_to_sysex2Bytes(data[68], sysexCount, sysexData);        // (68) 2    146  - LFO1phase (0 - 180.0)
        uint14_to_sysex2Bytes(data[69], sysexCount, sysexData);        // (69) 2    148  - LFO2phase (0 - 180.0)
        for (uint8_t i = 0; i < 16; i++) {
            uint8_to_sysex1Byte(data[70+i], sysexCount, sysexData);    // (70-85)  16    150 - SeqNote1Buf (0 - 127)
        }
        for (uint8_t i = 0; i < 16; i++) {
            uint8_to_sysex1Byte(data[86+i], sysexCount, sysexData);    // (86-101) 16    166 - SeqNoteBufStatus (0 - 1)
        }
        uint14_to_sysex2Bytes(data[102], sysexCount, sysexData);    // (102) 2     182  - SEQbpmValue (101 - 462)
        float_to_sysex5Bytes(data[103], sysexCount, sysexData);        // (103) 5    184  - SEQdivValue (float)
        uint8_to_sysex1Byte(data[104], sysexCount, sysexData);        // (104) 1    189  - SEQstepNumbers (0 - 15)
        float_to_sysex5Bytes(data[105], sysexCount, sysexData);        // (105) 5    190  - SEQGateTime (float)
        uint8_to_sysex1Byte(data[106], sysexCount, sysexData);        // (106) 1    195  - SEQdirection (0 - 3)
        uint8_to_sysex1Byte(data[107], sysexCount, sysexData);        // (107) 1    196  - oscDetuneSync (0 - 1)
        int8_to_sysex2Bytes(data[108], sysexCount, sysexData);        // (108) 2    197  - oscPitchA (-12 - +12)
        float_to_sysex5Bytes(data[109], sysexCount, sysexData);        // (109) 5    199  - oscMasterTune (float)
        float_to_sysex5Bytes(data[110], sysexCount, sysexData);        // (110) 5    204  - OscVCFMOD (float)
        for (uint8_t i = 0; i < 16; i++) {
            uint8_to_sysex1Byte(data[111+i], sysexCount, sysexData);    // (111-126) 16     209 - SeqVeloBuf (0 - 127)
        }
        for (uint8_t i = 0; i < 48; i++) {
            uint8_to_sysex1Byte(data[127+i], sysexCount, sysexData);    // (127-174) 48     225 - SeqNote1Buf (0 - 127)
        }
        
        for (uint8_t i = 0; i < 16; i++) {
            uint8_to_sysex1Byte(data[175+i], sysexCount, sysexData);    // (175-190) 16     273 - SeqNoteCount (0 - 3)
        }
        uint8_to_sysex1Byte(data[191], sysexCount, sysexData);        // (191) 1    289 - SEQmode (0 - 2)
        uint8_to_sysex1Byte(data[192], sysexCount, sysexData);        // (192) 1    290 - SEQMidiClkSwitch (0 - 1)
        uint8_to_sysex1Byte(data[193], sysexCount, sysexData);        // (193) 1    291 - LadderFilterpassbandgain (0 - 127)
        uint8_to_sysex1Byte(data[194], sysexCount, sysexData);        // (194) 1    292 - LadderFilterDrive (1 - 127)
        int8_to_sysex2Bytes(data[195], sysexCount, sysexData);        // (195) 2    293 - envelopeType1 (-8 - +8)
        int8_to_sysex2Bytes(data[196], sysexCount, sysexData);        // (196) 2    295 - envelopeType2 (-8 - +8)
        float_to_sysex5Bytes(data[197], sysexCount, sysexData);        // (197) 5    297 - PitchWheelAmt (float)
        float_to_sysex5Bytes(data[198], sysexCount, sysexData);        // (198) 5    302 - MODWheelAmt (float)
        uint8_to_sysex1Byte(data[199], sysexCount, sysexData);        // (199) 1    307 - myFilter (1 - 2)
        float_to_sysex5Bytes(data[200], sysexCount, sysexData);        // (200) 5    308 - pwmRateA (-10.00 - + 10.00)
        float_to_sysex5Bytes(data[201], sysexCount, sysexData);        // (201) 5    313 - pwmRateB (-10.00 - + 10.00)
        uint14_to_sysex2Bytes(data[202], sysexCount, sysexData);    // (202) 2    318 - LFO1fadeTime (0 - 12000) Fade in
        uint14_to_sysex2Bytes(data[203], sysexCount, sysexData);    // (203) 2    320 - LFO1releaseTime (0 - 12000) Fade out
        float_to_sysex5Bytes(data[204], sysexCount, sysexData);        // (204) 5    322 - filterFM (0.00000 - 1.00000)  Osc1
        float_to_sysex5Bytes(data[205], sysexCount, sysexData);        // (205) 5    327 - filterFM2 (0.00000 - 1.00000)    Osc2
        uint14_to_sysex2Bytes(data[206], sysexCount, sysexData);    // (206) 2    332 - LFO2fadeTime (0 - 12000) Fade in
        uint14_to_sysex2Bytes(data[207], sysexCount, sysexData);    // (207) 2    334 - LFO2releaseTime (0 - 12000) Fade out
        float_to_sysex5Bytes(data[208], sysexCount, sysexData);        // (208) 5    336 - Osc1ModAmt (0.00000 - 1.00000) Fx Mod
        int8_to_sysex2Bytes(data[209], sysexCount, sysexData);        // (209) 2    341 - LFO1enCurve (-8 - +8)
        int8_to_sysex2Bytes(data[210], sysexCount, sysexData);        // (210) 2    343 - LFO2enCurve (-8 - +8)
        uint8_to_sysex1Byte(data[211], sysexCount, sysexData);        // (211) 1    345 - LFO1mode (0 - 1)
        uint8_to_sysex1Byte(data[212], sysexCount, sysexData);        // (212) 1    346 - LFO2mode (0 - 1)
        sysexData[sysexCount++] = 0xF7;                                //         1    347 - End SysEx (0xF7)
        
        // Send SysEx Dump
        if (sysexDest == false) {
            usbMIDI.sendSysEx(sysexCount, sysexData, true);            // send SysEx Dump via USB (default)
            } else {
            MIDI.sendSysEx(sysexCount, sysexData, true);            // send SysEx Dump via Midi
        }
        usb_midi_flush_output();
    }
    Last edited by Rolfdegen; 05-23-2022 at 12:30 PM.

  5. #30
    Senior Member Rolfdegen's Avatar
    Join Date
    Sep 2020
    Location
    Germany
    Posts
    303
    I wrote a small Arduino sketch and tested it on a Teensy 4.1 board.
    Transmission errors occur with unchanged usb.c file. With the change to usb.c file, there is no transmission error.
    The waiting time after transmission of a data block is very short.

    Press Button on Teensy Pin A3 (low activ) send 128 SysEx data blocks.
    Code:
    //*****************************************************************
    // Send SysEx data to usbMidi
    //*****************************************************************
    #include <usb_midi.h>
    #include <Bounce2.h>
    
    
    #define chunkSize 130
    #define Blocknumbers 128
    #define delayAmt 1
    #define buttonPin PIN_A3
    
    
    const int ledPin = 13;
    Bounce  myButton  = Bounce();
    boolean startFlag = false;
    byte data[chunkSize];
    
    
    //****************************************************************
    // fill buffer
    //****************************************************************
    void fillBuff() {
      unsigned scratch;
    
    
      // set Start and End Byte for SysEx 
      data[0] = 0xF0;
      data[129] = 0xF7;
    
    
      // fill with data
      for (uint16_t ct = 1; ct < (chunkSize-1); ct++) {
        scratch = (ct & 0b01111111);
        data[ct] = scratch;
      }
    }
    
    
    //***************************************************************
    // transmit SysEx data
    //***************************************************************
    void sendSysExData () {
       usbMIDI.sendSysEx(chunkSize, data, true);
       digitalWrite(ledPin, HIGH);
    }
    
    
    //***************************************************************
    // init setup
    //***************************************************************
    void setup() {
      usbMIDI.begin();
      pinMode(ledPin, OUTPUT);
      pinMode(buttonPin, INPUT_PULLUP);
      myButton.attach(buttonPin);
      myButton.interval(5); // 5ms for Keys debouncing
      fillBuff();
    }
    
    
    
    
    //**************************************************************
    // loop
    //**************************************************************
    void loop() {
    
    
      // press Key for transmit SysEx data
      myButton.update();
      if (myButton.fallingEdge()) {
        startFlag = true;
      }
    
    
      // send 128 Blocks with 130 Byte
      if (startFlag == true){
        for (uint8_t i = 0; i < Blocknumbers; i++) {
          sendSysExData();
          delay(delayAmt);
        }
        startFlag = false;
         digitalWrite(ledPin, LOW);
      } 
    }

  6. #31
    Senior Member Rolfdegen's Avatar
    Join Date
    Sep 2020
    Location
    Germany
    Posts
    303
    Quote Originally Posted by MatrixRat View Post
    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 0xF0 (SysEx start) and 0xF7 (SysEx end) in your fillBuff() function

  7. #32
    Junior Member
    Join Date
    Jan 2016
    Posts
    19
    Quote Originally Posted by Rolfdegen View Post
    I do not understand what you mean

    1.Block
    F0 ....data... F7

    2.Block
    F0 ...data... F7

    3.Block
    F0 ...data... F7

    and more..
    Hi Rolf,
    It's a dump of a DX7 bank with 32 patches inside. So the file actually already has only one F0, then 4102 bytes, then one F7 at the end.
    In MIDIOX, I see that the usbmidi lib truncates this 4104 buffer in 266 bytes blocks.
    My understanding is until F7 is not encountered, it is considered as "sysex continue" message, like this :
    Click image for larger version. 

Name:	image_2022-05-23_192146406.png 
Views:	13 
Size:	420.2 KB 
ID:	28457

    So here you see the first block "System exclusive" detected from the F0. Then "Sysex continue" blocks.
    And there are 2 "continue" blocks missing, and the last one too (the one I would like to see the F7).

  8. #33
    Junior Member
    Join Date
    Jan 2016
    Posts
    19
    Quote Originally Posted by Rolfdegen View Post
    I missing 0xF0 (SysEx start) and 0xF7 (SysEx end) in your fillBuff() function
    If I understand the third parameter for sendSysEx, if it's false it will add the missing start/stop bytes to the message.

  9. #34
    Senior Member Rolfdegen's Avatar
    Join Date
    Sep 2020
    Location
    Germany
    Posts
    303
    Yes. Your SysEx data block is too large. With MIDI-OX a maximum of only 2048 bytes per SysEx block can be received.
    Such a large block of data is not normal. All synthesizers I know send a block of less than 500 bytes for each patch.
    My DIY synthesizer does this too. The Yamaha technicians programmed badly
    Last edited by Rolfdegen; 05-23-2022 at 06:54 PM.

  10. #35
    Senior Member Rolfdegen's Avatar
    Join Date
    Sep 2020
    Location
    Germany
    Posts
    303
    I posted your DX7 problem in Sequencer Forum. Look at here: https://www.sequencer.de/synthesizer...i-dump.102499/

    Greetings Rolf

  11. #36
    Junior Member
    Join Date
    Jan 2016
    Posts
    19
    Quote Originally Posted by Rolfdegen View Post
    Yes. Your SysEx data block is too large. With MIDI-OX a maximum of only 2048 bytes per SysEx block can be received.
    Such a large block of data is not normal. All synthesizers I know send a block of less than 500 bytes for each patch.
    My DIY synthesizer does this too. The Yamaha technicians programmed badly
    I wanted to be sure, so I've checked the official Yamaha documentation. See page 37 here :
    http://synthmanuals.com/manuals/yama...nual/tx7e1.pdf
    Click image for larger version. 

Name:	image_2022-05-23_211403044.png 
Views:	10 
Size:	18.2 KB 
ID:	28463

  12. #37
    Junior Member
    Join Date
    Jan 2016
    Posts
    19
    I don't see any problem with long sysex messages. Like the MIDI Sample Dump Standard you can send samples.

    I've found this :
    I think your real problem is the 'generic USB to Midi cable' at it uses Microsoft class driver that doesn't work for long sysex.

    This is particularly a problem for older synths as their sysex messages were longer than 256 bytes (which is correct under the Midi spec. MS decided they knew better).


    I really think it's a USB problem, as I have also difficulties to get the whole bank with MIDIOS or Bome SendSX

  13. #38
    Senior Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    316
    Commented out line 364 C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4\us b.c as you suggest and no longer have truncated sysex. Thank you for finding it Rolf.

    Is not necessary to include Sysex status bytes (F0 and F7) in
    Code:
    byte data[chunkSize];
    when using
    Code:
    usbMIDI.sendSysEx(chunkSize, data, false, 0);
    @localhero, in your screenshot post# 32. I *think* that "Sysex Continue" is Midiox's way of telling us that its buffer is full so you need to increase it's buffer size.

    In Midiox>Options>Configure Buffers, set Size 2048 and Number 127.

  14. #39
    Senior Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    316
    Following on, 2048 bytes Sysex block size does seem to be the limit but I suspect this limit is imposed by the MS generic usbMidi driver.

    Perhaps borrow from Midiox the concept of Sysex Continue and say you want to send 4096 bytes, split it into two blocks of 2048 with F0 at the start and NO F7 at the end of the first block and NO F0 at the start but with F7 at the end for the second block if you get the drift..

  15. #40
    Senior Member Rolfdegen's Avatar
    Join Date
    Sep 2020
    Location
    Germany
    Posts
    303
    Annotation:


    The normal processor clock of the Teensy4.1 CPU is 600MHz. I reduced the clock setting for the processor in Arduino to 24Mhz. Transmission errors no longer occur.


    The transfer rate on the USB interface is probably so low that the input buffer of the MIDI-OX has enough time to process the received data.


    Greetings Rolf

  16. #41
    Senior Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    316
    24Mhz. Ouch! We gotta figure how to sidestep that. Neither Jeannie or my project will like it.
    Busy with home renovations, rain is coming, have a couple of ideas.

    Thinking of post 39, let's say we have a block of 512 bytes of sysex to send. How about splitting it into two blocks and we send the first with F0 at the start, then pause a little, then send the last block with the F7 at the end. Then see what MidiOx has to say.

    Second idea. I have an Iconnectivity MIO-10 interface which has a usbHost port. T4x works here. Windows can see the MIO-10 using it's generic class compliant driver. Better is to use the correct driver for access to the full capabilities of the device. When it rains, will plug that experimental T4.1 sysex code into it's usbHost then see what Midiox has to say.

  17. #42
    Senior Member Rolfdegen's Avatar
    Join Date
    Sep 2020
    Location
    Germany
    Posts
    303
    SysEx Dump works now. See short video.

    It was a bit more complicated than I thought. First, conversion routines had to be developed for all 212 parameter values in the Jeannie, which convert 8/16-bit integer values and 32-bit floating-point values into a 7-bit format for the SysEx dump. The same had to be converted back again.
    This was followed by functions for the transmission and reception of SysEx data. Last but not least, a simple menu for operation had to be developed.



    The transmission path is selected with Destination (Midi or USB)
    DUMP type is either a patch or a bank.
    DUMP-Bank sets the bank (A-P) for transmission or reception.
    Source is either the patch no. or when receiving the space in the selected patch bank.
    SYSEX-DUMP is set to send or receive SysEX data.
    The "Load/Save" button starts transmission or reception.
    A progress bar shows the progress of the transfer.

    Video: https://youtu.be/xRoLsR9HgU0

    Greetings Rolf

  18. #43
    Senior Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    316
    Glad you got it working.

    Following up, quoting myself
    How about splitting it into two blocks and we send the first with F0 at the start, then pause a little, then send the last block with the F7 at the end. Then see what MidiOx has to say.
    Got this idea to work. mentioning as the strategy may be worth looking at to slow large amounts of sysex for older synths.

  19. #44
    Junior Member
    Join Date
    Jan 2016
    Posts
    19
    Quote Originally Posted by MatrixRat View Post
    Glad you got it working.

    Following up, quoting myself

    Got this idea to work. mentioning as the strategy may be worth looking at to slow large amounts of sysex for older synths.
    Ok guys, I have good news.
    After a lot of trials, and errors in MIDIOX, I have finally managed to get it to work
    I had previously tried to split the message but it iddn't work because it was sent too quickly.

    So this is the code that works with the Teensy 4.1 kept at 600Mz and send the 4104 bytes in one F0 ... F7 message :
    usbMIDI.sendSysEx(2048, bank_data, true);
    delay(50);
    usbMIDI.sendSysEx(2048, bank_data+2048, true);
    delay(50);
    usbMIDI.sendSysEx(8, bank_data+4096, true);


    Houra, now I see the missing blocks, especially the "Sysex end" !!!
    Click image for larger version. 

Name:	image_2022-05-25_075130012.png 
Views:	12 
Size:	309.5 KB 
ID:	28476

    It's amazing I have spent so much time to get it. I had no need to change the usb.c (I prefer to keep the original files until Paul finds and fixes that in the Teensy code).
    Thanks for your help !

  20. #45
    Senior Member
    Join Date
    Feb 2021
    Posts
    142
    Quote Originally Posted by Rolfdegen View Post
    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
    }
    }
    Thanks for the thread. I have a very similar problem, but on Teensy 3.6 (using midi Ox). My synth's sysex messages are about 1200 bytes long, and after adjusting max limits in the library files, I can get single message transfers to happen without issues. But when I try to send say 50-100 of these in a row in bulk dump, I get small variable loss/insertion of data bytes on some, but not every attempt. I have tried splitting into blocks of about 200, with and without F0...F7 on each block, with all kinds of delays, and with and without explicit usb_midi_flush_output calls. But the problem persists.

    However, I haven't been able to try your approach of removing the flush call in USB.c as described here because I couldn't find matching code in Teensy 3 core usb.c file. Do you know if your method can be applied to T3?

  21. #46
    Senior Member
    Join Date
    Feb 2021
    Posts
    142
    Even running absolutely nothing but a sysex dump in a simple sketch I get errors on Teensy 3.6 with midi Ox.

    Here is my code, using a button press on pin 2 to start a dump. It should show 50000 bytes transferred, and sometimes it does (especially the first one or two times it's run it seems). But as often as not, there are some bytes missing, and the count is less than 50000. And changing the buffer size, or delay values etc. doesn't seem to solve it. Please let me know if you have any ideas on what else I can try. Thanks!

    Code:
    #include <Arduino.h>  
    #include <MIDI.h> 
    MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI ); 
    
    void setup() {
      pinMode(2, INPUT_PULLUP);
      MIDI.begin(MIDI_CHANNEL_OMNI); // midi serial init 
    }
    
    void loop() {
    
      if(!digitalRead(2))
      {
       byte patchData[50] = {0};  
       patchData[0]=0xF0;                    
       patchData[49]=0xF7;    
      
       for(int P=0;P<50;P++)    
       {                     
         for(int i=0;i<20;i++)
         {  
            usbMIDI.sendSysEx( 50, patchData, true);        
            delay(10);                  
         }   
         delay(50);
       } 
      }   
    }

  22. #47
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    445
    Quote Originally Posted by rvh View Post
    However, I haven't been able to try your approach of removing the flush call in USB.c as described here because I couldn't find matching code in Teensy 3 core usb.c file. Do you know if your method can be applied to T3?
    No idea if itíll work, but line 957 of usb_dev.c might be the one youíre looking for?

  23. #48
    Senior Member
    Join Date
    Feb 2021
    Posts
    142
    Quote Originally Posted by h4yn0nnym0u5e View Post
    No idea if itíll work, but line 957 of usb_dev.c might be the one youíre looking for?
    Excellent, thanks very much. And yes, it fixed my problem on T3.6 too, so thank you Rolf also!

    Paul, (if you see this) are you able to make use of these findings for T3 & T4 to improve the library, so this change doesn't need to be made manually?

  24. #49
    Senior Member
    Join Date
    Feb 2021
    Posts
    142
    After more thorough testing, it seems this is not a good solution because some of my other midi USB functions misbehaved (badly) after making the change. It seems we need the change specifically for sysex transfers, but not other USB midi functions.

  25. #50
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    445
    OK, so usb_midi_flush_output() is in usb_midi.c ... can you modify that so it does nothing IF a sysex is in progress, but works normally at all other times? You may need to add a parameter so you can force it to do something from your application, even during sysex - I think the code in your cross-post does that. There seem to be only 5 files that reference it in teensy3, and 4 files in teensy4.

    I'd have a go myself, but I'm in the throes of trying to get multi-file playback and recording from/to SD cards working...

Posting Permissions

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