├── Changelog.md ├── library.properties ├── .gitignore ├── .github ├── dependabot.yml └── workflows │ └── check-arduino.yml ├── examples ├── Basic_IO │ └── Basic_IO.ino ├── NoteOnOffEverySec │ └── NoteOnOffEverySec.ino ├── Callbacks │ └── Callbacks.ino ├── SysExReceive │ └── SysExReceive.ino └── SysEx │ └── SysEx.ino ├── LICENSE ├── keywords.txt ├── src ├── UHS2-MIDI_Namespace.h ├── UHS2-MIDI_defs.h └── UHS2-MIDI.h └── README.md /Changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | ## 2023.08.12(1.0.1) 3 | - Add new API ```void setCableNumber(uint8_t cn)``` 4 | 5 | ## 2021.05.10(1.0.0) 6 | - GA 7 | - update document 8 | 9 | ## 2021.05.06(0.0.3) 10 | - Add UHS2MIDI_CREATE_CUSTOM_INSTANCE macro 11 | 12 | ## 2021.05.02(0.0.2) 13 | - Refactaring: improve performance and reduce SRAM usage 14 | 15 | ## 2021.04.30(0.0.1) 16 | - initial release 17 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=UHS2-MIDI 2 | version=1.0.1 3 | author=Yuuichi Akagawa 4 | maintainer=Yuuichi AKagawa 5 | sentence=USB Host Shield Library 2.0 MIDI I/O for Arduino 6 | paragraph=USB Host Shield Library 2.0 MIDI transport for FortySevenEffects MIDI Library. 7 | category=Communication 8 | url=https://github.com/YuuichiAkagawa/Arduino-UHS2MIDI 9 | architectures=* 10 | includes=UHS2-MIDI.h 11 | depends=MIDI Library, USB Host Shield Library 2.0 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | 35 | # Backup files 36 | *.bak 37 | 38 | # macOS 39 | examples/.DS_Store 40 | .DS_Store 41 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # See: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#about-the-dependabotyml-file 2 | version: 2 3 | 4 | updates: 5 | # Configure check for outdated GitHub Actions actions in workflows. 6 | # See: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot 7 | - package-ecosystem: github-actions 8 | directory: / # Check the repository's workflows under /.github/workflows/ 9 | schedule: 10 | interval: daily 11 | -------------------------------------------------------------------------------- /.github/workflows/check-arduino.yml: -------------------------------------------------------------------------------- 1 | name: Check Arduino 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | pull_request: 7 | schedule: 8 | # Run every Thursday at 9 PM UTC to catch breakage caused by new rules added to Arduino Lint. 9 | - cron: "0 21 * * 4" 10 | workflow_dispatch: 11 | repository_dispatch: 12 | 13 | jobs: 14 | lint: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v6 20 | 21 | - name: Arduino Lint 22 | uses: arduino/arduino-lint-action@v2 23 | with: 24 | compliance: specification 25 | library-manager: update 26 | project-type: library 27 | -------------------------------------------------------------------------------- /examples/Basic_IO/Basic_IO.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Simple tutorial on how to receive and send MIDI messages. 4 | // Here, when receiving any message on channel 4, the Arduino 5 | // will blink a led and play back a note for 1 second. 6 | 7 | USB Usb; 8 | UHS2MIDI_CREATE_DEFAULT_INSTANCE(&Usb); 9 | 10 | void setup() 11 | { 12 | pinMode(LED_BUILTIN, OUTPUT); 13 | MIDI.begin(4); // Launch MIDI and listen to channel 4 14 | 15 | if (Usb.Init() == -1) { 16 | while (1); //halt 17 | }//if (Usb.Init() == -1... 18 | delay( 200 ); 19 | } 20 | 21 | void loop() 22 | { 23 | Usb.Task(); 24 | if (MIDI.read()) // If we have received a message 25 | { 26 | digitalWrite(LED_BUILTIN, HIGH); 27 | MIDI.sendNoteOn(42, 127, 1); // Send a Note (pitch 42, velo 127 on channel 1) 28 | delay(1000); // Wait for a second 29 | MIDI.sendNoteOff(42, 0, 1); // Stop the note 30 | digitalWrite(LED_BUILTIN, LOW); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Yuuichi Akagawa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/NoteOnOffEverySec/NoteOnOffEverySec.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | USB Usb; 4 | UHS2MIDI_CREATE_DEFAULT_INSTANCE(&Usb); 5 | 6 | unsigned long t1 = millis(); 7 | 8 | void handleNoteOn(byte inChannel, byte inNumber, byte inVelocity) 9 | { 10 | Serial.print("NoteOn "); 11 | Serial.print(inNumber); 12 | Serial.print("\tvelocity: "); 13 | Serial.println(inVelocity); 14 | } 15 | 16 | void handleNoteOff(byte inChannel, byte inNumber, byte inVelocity) 17 | { 18 | Serial.print("NoteOff "); 19 | Serial.print(inNumber); 20 | Serial.print("\tvelocity: "); 21 | Serial.println(inVelocity); 22 | } 23 | 24 | void setup() 25 | { 26 | Serial.begin(115200); 27 | while (!Serial); 28 | 29 | MIDI.begin(); 30 | MIDI.setHandleNoteOn(handleNoteOn); 31 | MIDI.setHandleNoteOff(handleNoteOff); 32 | 33 | if (Usb.Init() == -1) { 34 | while (1); //halt 35 | }//if (Usb.Init() == -1... 36 | delay( 200 ); 37 | 38 | Serial.println("Arduino ready."); 39 | } 40 | 41 | // ----------------------------------------------------------------------------- 42 | // 43 | // ----------------------------------------------------------------------------- 44 | void loop() 45 | { 46 | Usb.Task(); 47 | MIDI.read(); 48 | 49 | if ((millis() - t1) > 500) 50 | { 51 | t1 = millis(); 52 | 53 | MIDI.sendNoteOn(27, 55, 1); 54 | MIDI.sendNoteOff(27, 55, 1); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for UHS2-MIDI 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | uhs2MidiTransport KEYWORD1 9 | UHS2-MIDI.h KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | run KEYWORD2 16 | noteOn KEYWORD2 17 | noteOff KEYWORD2 18 | afterTouchPoly KEYWORD2 19 | controlChange KEYWORD2 20 | programChange KEYWORD2 21 | afterTouchChannel. KEYWORD2 22 | pitchBend KEYWORD2 23 | systemExclusive KEYWORD2 24 | timeCodeQuarterFrame KEYWORD2 25 | songPosition KEYWORD2 26 | songSelect KEYWORD2 27 | tuneRequest KEYWORD2 28 | clock KEYWORD2 29 | start KEYWORD2 30 | Continue KEYWORD2 31 | stop KEYWORD2 32 | activeSensing KEYWORD2 33 | systemReset KEYWORD2 34 | timeCodeQuarterFrame KEYWORD2 35 | sysEx KEYWORD2 36 | afterTouch KEYWORD2 37 | polyPressure KEYWORD2 38 | 39 | ####################################### 40 | # Instances (KEYWORD3) 41 | ####################################### 42 | 43 | MIDI KEYWORD3 44 | uhs2MIDI KEYWORD3 45 | 46 | ####################################### 47 | # Constants (LITERAL1) 48 | ####################################### 49 | 50 | # Namespace, considering it as a literal 51 | UHS2MIDI LITERAL1 52 | -------------------------------------------------------------------------------- /src/UHS2-MIDI_Namespace.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file UHS2-MIDI_Namespace.h 3 | * Project Arduino UHS2 MIDI transport 4 | * @brief UHS2 MIDI transport for the Arduino - Namespace declaration 5 | * @author Yuuichi Akagawa 6 | * @date 20/12/2020 7 | * @license MIT - Copyright (c) 2020 Yuuichi Akagawa 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #pragma once 29 | 30 | #define UHS2MIDI_NAMESPACE uhs2Midi 31 | #define BEGIN_UHS2MIDI_NAMESPACE namespace UHS2MIDI_NAMESPACE { 32 | #define END_UHS2MIDI_NAMESPACE } 33 | 34 | #define USING_NAMESPACE_UHS2MIDI using namespace UHS2MIDI_NAMESPACE; 35 | 36 | BEGIN_UHS2MIDI_NAMESPACE 37 | 38 | END_UHS2MIDI_NAMESPACE 39 | -------------------------------------------------------------------------------- /examples/Callbacks/Callbacks.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | USB Usb; 5 | UHS2MIDI_CREATE_DEFAULT_INSTANCE(&Usb); 6 | 7 | // ----------------------------------------------------------------------------- 8 | 9 | // This function will be automatically called when a NoteOn is received. 10 | // It must be a void-returning function with the correct parameters, 11 | // see documentation here: 12 | // https://github.com/FortySevenEffects/arduino_midi_library/wiki/Using-Callbacks 13 | 14 | void handleNoteOn(byte channel, byte pitch, byte velocity) 15 | { 16 | // Do whatever you want when a note is pressed. 17 | 18 | // Try to keep your callbacks short (no delays ect) 19 | // otherwise it would slow down the loop() and have a bad impact 20 | // on real-time performance. 21 | } 22 | 23 | void handleNoteOff(byte channel, byte pitch, byte velocity) 24 | { 25 | // Do something when the note is released. 26 | // Note that NoteOn messages with 0 velocity are interpreted as NoteOffs. 27 | } 28 | 29 | // ----------------------------------------------------------------------------- 30 | 31 | void setup() 32 | { 33 | // Connect the handleNoteOn function to the library, 34 | // so it is called upon reception of a NoteOn. 35 | MIDI.setHandleNoteOn(handleNoteOn); // Put only the name of the function 36 | 37 | // Do the same for NoteOffs 38 | MIDI.setHandleNoteOff(handleNoteOff); 39 | 40 | // Initiate MIDI communications, listen to all channels 41 | MIDI.begin(MIDI_CHANNEL_OMNI); 42 | 43 | if (Usb.Init() == -1) { 44 | while (1); //halt 45 | }//if (Usb.Init() == -1... 46 | delay( 200 ); 47 | } 48 | 49 | void loop() 50 | { 51 | Usb.Task(); 52 | // Call MIDI.read the fastest you can for real-time performance. 53 | MIDI.read(); 54 | 55 | // There is no need to check if there are messages incoming 56 | // if they are bound to a Callback function. 57 | // The attached method will be called automatically 58 | // when the corresponding message has been received. 59 | } 60 | -------------------------------------------------------------------------------- /src/UHS2-MIDI_defs.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file UHS2-MIDI_defs.h 3 | * Project Arduino UHS2 MIDI transport 4 | * @brief UHS2 MIDI transport for the Arduino - Definitions 5 | * @author Yuuichi Akagawa 6 | * @date 20/12/2020 7 | * @license MIT - Copyright (c) 2020-2021 Yuuichi Akagawa 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #pragma once 29 | 30 | #include "UHS2-MIDI_Namespace.h" 31 | 32 | BEGIN_UHS2MIDI_NAMESPACE 33 | 34 | //USB-MIDI event packet 35 | typedef union 36 | { 37 | uint8_t buf[4]; 38 | struct{ 39 | uint8_t header; 40 | uint8_t byte1; 41 | uint8_t byte2; 42 | uint8_t byte3; 43 | } p; 44 | } usbMidiEventPacket_t; 45 | 46 | using namespace MIDI_NAMESPACE; 47 | 48 | const uint8_t Fsys2cin[] PROGMEM = {0, 2, 3, 2, 0, 0, 5, 0, 0xf, 0, 0xf, 0xf, 0xf, 0, 0xf, 0xf}; 49 | 50 | #define MAKEHEADER(cn, cin) (((cn & 0x0f) << 4) | cin) 51 | 52 | END_UHS2MIDI_NAMESPACE 53 | -------------------------------------------------------------------------------- /examples/SysExReceive/SysExReceive.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | byte sysex14[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0x37, 0x33, 0x50, 0xF7 }; 4 | byte sysex15[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0x37, 0x33, 0x50, 0x4D, 0xF7 }; 5 | byte sysex16[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0x37, 0x33, 0x32, 0x50, 0x4D, 0xF7 }; 6 | byte sysexBig[] = { 0xF0, 0x41, 7 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 8 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 9 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 10 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 11 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 12 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 13 | 0x7a, 14 | 15 | 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 16 | 0xF7 17 | }; 18 | 19 | USB Usb; 20 | UHS2MIDI_CREATE_DEFAULT_INSTANCE(&Usb); 21 | 22 | unsigned long t0 = millis(); 23 | 24 | // ----------------------------------------------------------------------------- 25 | // 26 | // ----------------------------------------------------------------------------- 27 | void setup() 28 | { 29 | Serial.begin(115200); 30 | while (!Serial); 31 | 32 | // Listen for MIDI messages on channel 1 33 | MIDI.begin(1); 34 | 35 | MIDI.setHandleSystemExclusive(OnMidiSysEx); 36 | 37 | if (Usb.Init() == -1) { 38 | while (1); //halt 39 | }//if (Usb.Init() == -1... 40 | delay( 200 ); 41 | } 42 | 43 | // ----------------------------------------------------------------------------- 44 | // 45 | // ----------------------------------------------------------------------------- 46 | void loop() 47 | { 48 | Usb.Task(); 49 | // Listen to incoming notes 50 | MIDI.read(); 51 | 52 | // send a note every second 53 | // (dont cáll delay(1000) as it will stall the pipeline) 54 | if ((millis() - t0) > 1000) 55 | { 56 | t0 = millis(); 57 | // Serial.print(F("."); 58 | 59 | MIDI.sendSysEx(sizeof(sysex14), sysex14, true); 60 | } 61 | } 62 | 63 | // ----------------------------------------------------------------------------- 64 | // 65 | // ----------------------------------------------------------------------------- 66 | void OnMidiSysEx(byte* data, unsigned length) { 67 | Serial.print(F("SYSEX: (")); 68 | Serial.print(length); 69 | Serial.print(F(" bytes) ")); 70 | for (uint16_t i = 0; i < length; i++) 71 | { 72 | Serial.print(data[i], HEX); 73 | Serial.print(" "); 74 | } 75 | Serial.println(); 76 | } 77 | -------------------------------------------------------------------------------- /examples/SysEx/SysEx.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | byte sysex4[] = { 0xF0, 0x43, 0x20, 0xF7 }; 4 | byte sysex5[] = { 0xF0, 0x43, 0x20, 0x7E, 0xF7 }; 5 | byte sysex6[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0xF7 }; 6 | byte sysex7[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0xF7 }; 7 | byte sysex8[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0xF7 }; 8 | byte sysex9[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0xF7 }; 9 | byte sysex10[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0xF7 }; 10 | byte sysex11[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0xF7 }; 11 | byte sysex12[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0x37, 0xF7 }; 12 | byte sysex13[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0x37, 0x33, 0xF7 }; 13 | byte sysex14[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0x37, 0x33, 0x50, 0xF7 }; 14 | byte sysex15[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0x37, 0x33, 0x50, 0x4D, 0xF7 }; 15 | byte sysex16[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0x37, 0x33, 0x32, 0x50, 0x4D, 0xF7 }; 16 | byte sysexBig[] = { 0xF0, 0x41, 17 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 18 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 19 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 20 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 21 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 22 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 23 | 0x7a, 24 | 25 | 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 26 | 0xF7 27 | }; 28 | 29 | USB Usb; 30 | UHS2MIDI_CREATE_DEFAULT_INSTANCE(&Usb); 31 | 32 | unsigned long t0 = millis(); 33 | unsigned long t1 = millis(); 34 | 35 | // ----------------------------------------------------------------------------- 36 | // 37 | // ----------------------------------------------------------------------------- 38 | void setup() 39 | { 40 | // Listen for MIDI messages on channel 1 41 | MIDI.begin(1); 42 | 43 | if (Usb.Init() == -1) { 44 | while (1); //halt 45 | }//if (Usb.Init() == -1... 46 | delay( 200 ); 47 | } 48 | 49 | // ----------------------------------------------------------------------------- 50 | // 51 | // ----------------------------------------------------------------------------- 52 | void loop() 53 | { 54 | Usb.Task(); 55 | // Listen to incoming notes 56 | MIDI.read(); 57 | 58 | // send 10 NoteOn 7 SysEx per second 59 | if ((millis() - t0) > 100) 60 | { 61 | t0 = millis(); 62 | 63 | MIDI.sendNoteOn(27, 55, 1); 64 | MIDI.sendSysEx(sizeof(sysex11), sysex11, true); 65 | } 66 | 67 | // send NoteOff every 750ms 68 | if ((millis() - t1) > 750) 69 | { 70 | t1 = millis(); 71 | 72 | MIDI.sendNoteOff(27, 55, 1); 73 | } 74 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arduino USB Host Shield 2.0 MIDI Transport 2 | [![arduino-library-badge](https://www.ardu-badge.com/badge/UHS2-MIDI.svg?)](https://www.ardu-badge.com/UHS2-MIDI) 3 | [![Check Arduino status](https://github.com/YuuichiAkagawa/Arduino-UHS2MIDI/actions/workflows/check-arduino.yml/badge.svg)](https://github.com/YuuichiAkagawa/Arduino-UHS2MIDI/actions/workflows/check-arduino.yml") 4 | [![License](https://img.shields.io/github/license/YuuichiAkagawa/Arduino-UHS2MIDI.svg?maxAge=3600)](LICENSE) 5 | 6 | USB Host Shield 2.0 MIDI transport layer for the [FortySevenEffects Arduino MIDI Library](https://github.com/FortySevenEffects/arduino_midi_library) and uses the underlying [USB Host Shield 2.0](https://github.com/felis/USB_Host_Shield_2.0) library. 7 | This library is based on the [Arduino-USBMIDI](https://github.com/lathoub/Arduino-USBMIDI). 8 | 9 | ## Installation 10 | Install from Arduino Library Manager. Search for UHS2-MIDI. 11 | ![arduino-library-manager](https://user-images.githubusercontent.com/926923/117981071-92c41d80-b36f-11eb-9cd1-30423f708880.png) 12 | 13 | ## Usage 14 | ### Basic / Default 15 | ```cpp 16 | #include 17 | ... 18 | USB Usb; 19 | UHS2MIDI_CREATE_DEFAULT_INSTANCE(&Usb); 20 | ... 21 | void setup() 22 | { 23 | MIDI.begin(1); 24 | if (Usb.Init() == -1) { 25 | while (1); //halt 26 | }//if (Usb.Init() == -1... 27 | ... 28 | } 29 | void loop() 30 | { 31 | Usb.Task(); 32 | MIDI.read(); 33 | ... 34 | ``` 35 | will create a instance named `MIDI` (transport instance named `__uhs2MIDI`) and is by default connected to cable number 0 - and listens to incoming MIDI on channel 1. 36 | 37 | ### Modified 38 | ```cpp 39 | #include 40 | ... 41 | USB Usb; 42 | UHS2MIDI_CREATE_INSTANCE(&Usb, 4, MIDI); 43 | ``` 44 | will create a instance named `MIDI` (transport instance named `__uhs2MIDI`) and is connected to cable number 4. 45 | 46 | ### Custom Settings 47 | ```cpp 48 | #include 49 | ... 50 | struct MySettings : public midi::DefaultSettings 51 | { 52 | static const unsigned SysExMaxSize = 512; // Accept SysEx messages up to 512 bytes long. 53 | }; 54 | USB Usb; 55 | UHS2MIDI_CREATE_CUSTOM_INSTANCE(&Usb, 0, MIDI, MySettings); 56 | ``` 57 | will create a instance named `MIDI` (transport instance named `__uhs2MIDI`) and change the maximum size of SysEx messages to 512 bytes. 58 | ### Advanced 59 | ```cpp 60 | #include 61 | ... 62 | USB Usb; 63 | UHS2MIDI_NAMESPACE::uhs2MidiTransport uhs2MIDI2(&Usb, 5); 64 | MIDI_NAMESPACE::MidiInterface MIDI2((UHS2MIDI_NAMESPACE::uhs2MidiTransport&)uhs2MIDI2); 65 | ``` 66 | will create a instance named `uhs2MIDI2` (and underlaying MIDI object `MIDI2`) and is by default connected to cable number 5. 67 | 68 | ### Change CableNumber 69 | ```cpp 70 | #include 71 | ... 72 | USB Usb; 73 | UHS2MIDI_CREATE_DEFAULT_INSTANCE(&Usb); 74 | void setup() 75 | { 76 | MIDI.begin(4); // Launch MIDI and listen to channel 4 77 | MIDI.getTransport()->setCableNumber(1); // Change CableNumber to 1 later 78 | ``` 79 | ## Tested boards / modules 80 | - Arduino UNO R3 81 | 82 | ## Changelog 83 | [Chagelog](/Changelog.md) 84 | 85 | ## Other Transport protocols: 86 | The libraries below the same calling mechanism (API), making it easy to interchange the transport layer. 87 | - [Arduino USB-MIDI Transport](https://github.com/lathoub/USB-MIDI) 88 | - [Arduino AppleMIDI Transport](https://github.com/lathoub/Arduino-AppleMIDI-Library) 89 | - [Arduino ipMIDI Transport](https://github.com/lathoub/Arduino-ipMIDI) 90 | - [Arduino BLE-MIDI Transport](https://github.com/lathoub/Arduino-BLE-MIDI) 91 | - [Arduino USB Host Library SAMD MIDI Transport](https://github.com/YuuichiAkagawa/Arduino-USBHSAMD-MIDI) 92 | -------------------------------------------------------------------------------- /src/UHS2-MIDI.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 lathoub 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | /* 23 | ******************************************************************************* 24 | * Original version: https://github.com/lathoub/Arduino-USBMIDI/blob/master/src/USB-MIDI.h 25 | * 26 | * Modified for the USB Host Shield 2.0 + USBH_MIDI 27 | * copyright (c) 2020-2023 Yuuichi Akagawa 28 | ******************************************************************************* 29 | */ 30 | #pragma once 31 | 32 | #include 33 | #include 34 | 35 | #include "UHS2-MIDI_defs.h" 36 | #include "UHS2-MIDI_Namespace.h" 37 | 38 | #define UHS2_MIDI_VERSION 10001 39 | 40 | BEGIN_UHS2MIDI_NAMESPACE 41 | class uhs2MidiTransport : public USBH_MIDI 42 | { 43 | private: 44 | uint8_t mTxIndex; 45 | MidiType mTxStatus; 46 | usbMidiEventPacket_t mTxPacket; 47 | uint8_t mRxLength; 48 | uint8_t mRxIndex; 49 | usbMidiEventPacket_t mRxPacket; 50 | 51 | uint8_t cableNumber; 52 | 53 | public: 54 | uhs2MidiTransport(USB *p, uint8_t cableNumber = 0) : USBH_MIDI(p) 55 | { 56 | this->cableNumber = cableNumber; 57 | }; 58 | 59 | static const bool thruActivated = false; 60 | 61 | uint8_t SendData(usbMidiEventPacket_t &packet){ 62 | if( !bPollEnable ) return 4; 63 | return USBH_MIDI::SendRawData(4, packet.buf); 64 | }; 65 | 66 | uint8_t RecvData(usbMidiEventPacket_t &packet){ 67 | uint8_t rc = USBH_MIDI::RecvData(packet.buf, true); 68 | if( rc == 0 ) { 69 | packet.p.header = 0; 70 | } 71 | return rc; 72 | }; 73 | 74 | void begin() 75 | { 76 | mTxIndex = 0; 77 | mRxIndex = 0; 78 | mRxLength = 0; 79 | }; 80 | 81 | bool beginTransmission(MidiType status) 82 | { 83 | mTxStatus = status; 84 | 85 | byte cin = 0; 86 | if (status < SystemExclusive) { 87 | // Non System messages 88 | cin = ((status & 0xF0) >> 4); 89 | mTxPacket.p.header = MAKEHEADER(cableNumber, cin); 90 | } 91 | else { 92 | // Only System messages 93 | cin = pgm_read_byte_near(Fsys2cin + (status & 0x0F)); 94 | mTxPacket.p.header = MAKEHEADER(cableNumber, cin); 95 | } 96 | 97 | mTxPacket.p.byte1 = mTxPacket.p.byte2 = mTxPacket.p.byte3 = 0; 98 | mTxIndex = 0; 99 | 100 | return true; 101 | }; 102 | 103 | void write(byte byte) 104 | { 105 | if (mTxStatus != MidiType::SystemExclusive) { 106 | mTxPacket.buf[mTxIndex+1] = byte; 107 | } 108 | else if (byte == MidiType::SystemExclusiveStart) { 109 | mTxPacket.p.header = MAKEHEADER(cableNumber, 0x04); 110 | mTxPacket.p.byte1 = byte; 111 | } 112 | else // SystemExclusiveEnd or SysEx data 113 | { 114 | if (byte == MidiType::SystemExclusiveEnd) 115 | mTxPacket.p.header = MAKEHEADER(cableNumber, (0x05 + mTxIndex)); 116 | 117 | switch(mTxIndex){ 118 | case 0: 119 | mTxPacket.p.byte1 = byte; 120 | mTxPacket.p.byte2 = mTxPacket.p.byte3 = 0x00; 121 | break; 122 | case 1: 123 | mTxPacket.p.byte2 = byte; 124 | mTxPacket.p.byte3 = 0x00; 125 | break; 126 | case 2: 127 | mTxPacket.p.byte3 = byte; 128 | if (byte != MidiType::SystemExclusiveEnd) 129 | SendData(mTxPacket); 130 | break; 131 | default: 132 | break; 133 | } 134 | } 135 | mTxIndex = (mTxIndex == 2) ? 0 : mTxIndex+1; 136 | }; 137 | 138 | void endTransmission() 139 | { 140 | SendData(mTxPacket); 141 | }; 142 | 143 | byte read() 144 | { 145 | auto byte = mRxPacket.buf[mRxIndex++]; 146 | mRxLength--; 147 | return byte; 148 | }; 149 | 150 | unsigned available() 151 | { 152 | // consume mRxBuffer first, before getting a new packet 153 | if (mRxLength > 0) 154 | return mRxLength; 155 | 156 | mRxIndex = 1; 157 | auto len = (size_t)RecvData(mRxPacket); 158 | if (mRxPacket.p.header != 0) { 159 | //auto cn = GETCABLENUMBER(mRxPacket); 160 | auto cn = (mRxPacket.p.header >> 4) & 0x0f; 161 | if (cn != cableNumber) 162 | return 0; 163 | mRxLength = len; 164 | } 165 | return mRxLength; 166 | }; 167 | 168 | void setCableNumber(uint8_t cn){ 169 | if( cn > 15 ) 170 | return; 171 | cableNumber = cn; 172 | }; 173 | }; 174 | 175 | END_UHS2MIDI_NAMESPACE 176 | 177 | #define UHS2MIDI_CREATE_INSTANCE(USBH, CableNr, Name) \ 178 | UHS2MIDI_NAMESPACE::uhs2MidiTransport __uhs2##Name(USBH, CableNr);\ 179 | MIDI_NAMESPACE::MidiInterface Name((UHS2MIDI_NAMESPACE::uhs2MidiTransport&)__uhs2##Name); 180 | 181 | #define UHS2MIDI_CREATE_DEFAULT_INSTANCE(USBH) \ 182 | UHS2MIDI_CREATE_INSTANCE(USBH, 0, MIDI) 183 | 184 | #define UHS2MIDI_CREATE_CUSTOM_INSTANCE(USBH, CableNr, Name, Settings) \ 185 | UHS2MIDI_NAMESPACE::uhs2MidiTransport __uhs2##Name(USBH, CableNr);\ 186 | MIDI_NAMESPACE::MidiInterface Name((UHS2MIDI_NAMESPACE::uhs2MidiTransport&)__uhs2##Name); 187 | --------------------------------------------------------------------------------