diff options
| author | Donald Delmar Davis <don@suspectdevices.com> | 2013-02-02 15:13:20 -0800 |
|---|---|---|
| committer | Donald Delmar Davis <don@suspectdevices.com> | 2013-02-02 15:13:20 -0800 |
| commit | 0b5f07dd03905e48e1d8de75240f0a3260e7fadb (patch) | |
| tree | 1353b3d0a59baba7b095eb24c2a067b3baa32c66 /sysexdemo | |
| parent | e2a70687030570585c7dad99ca6437bd07442e06 (diff) | |
Diffstat (limited to 'sysexdemo')
| -rw-r--r-- | sysexdemo/MidiSpecs.h | 143 | ||||
| -rw-r--r-- | sysexdemo/qtest.py | 38 | ||||
| -rw-r--r-- | sysexdemo/sysexdemo.ino | 149 |
3 files changed, 330 insertions, 0 deletions
diff --git a/sysexdemo/MidiSpecs.h b/sysexdemo/MidiSpecs.h new file mode 100644 index 0000000..2a09d93 --- /dev/null +++ b/sysexdemo/MidiSpecs.h @@ -0,0 +1,143 @@ +/*--------------------------------------------------------------------------MidiSpecs.h + * + * These defines are based on specs created by the USB and MMA standards organizations. + * There are not a lot of other ways to code them so liscensing this is rather ludicrous. + * However, in order to be able to embed this in client projects, and avoid the stupidity + * of enforced open/closed everything I will declare the following about this file. + * + * Copyright (c) 2011 Donald Delmar Davis, Suspect Devices + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/* + * USB midi commands from + * MIDI10.pdf "Universal Serial Bus Device Class Definition for MIDI Devices" + * REV 1. (1999) + * http://www.usb.org/developers/devclass_docs/midi10.pdf + * + */ + +#ifndef __LETS_MIDI_SPECS_H__ +#define __LETS_MIDI_SPECS_H__ +#include <stdint.h> +#include <stdbool.h> + +#if defined(__GNUC__) +typedef struct +{ + unsigned cable : 4; + unsigned cin : 4; // this is the low nibble. + uint8_t midi0; + uint8_t midi1; + uint8_t midi2; +} __attribute__ ((__packed__)) MIDI_EVENT_PACKET_t ; +#else +typedef struct // may need to be adjusted for other compilers and bitfield order... +{ + unsigned cable : 4; + unsigned cin : 4; + uint8_t midi0; + uint8_t midi1; + uint8_t midi2; +} MIDI_EVENT_PACKET_t ; +#endif + + +#define CIN_MISC_FUNCTION 0x00 /* Reserved for future extension. */ +#define CIN_CABLE_EVENT 0x01 /* Reserved for future extension. */ +#define CIN_2BYTE_SYS_COMMON 0x02 /* 2Bytes -- MTC, SongSelect, etc. */ +#define CIN_3BYTE_SYS_COMMON 0x03 /* 3Bytes -- SPP, etc. */ +#define CIN_SYSEX 0x04 /* 3Bytes */ +#define CIN_SYSEX_ENDS_IN_1 0x05 /* 1Bytes */ +#define CIN_SYSEX_ENDS_IN_2 0x06 /* 2Bytes */ +#define CIN_SYSEX_ENDS_IN_3 0x07 /* 3Bytes */ +#define CIN_NOTE_OFF 0x08 /* 3Bytes */ +#define CIN_NOTE_ON 0x09 /* 3Bytes */ +#define CIN_AFTER_TOUCH 0x0A /* 3Bytes */ +#define CIN_CONTROL_CHANGE 0x0B /* 3Bytes */ +#define CIN_PROGRAM_CHANGE 0x0C /* 2Bytes */ +#define CIN_CHANNEL_PRESSURE 0x0D /* 2Bytes */ +#define CIN_PITCH_WHEEL 0x0E /* 3Bytes */ +#define CIN_1BYTE 0x0F /* 1Bytes */ +//#define CIN_IS_SYSEX(cin) ((cin == CIN_SYSEX)||(cin == CIN_SYSEX_ENDS_IN_1)||(cin == CIN_SYSEX_ENDS_IN_2)||(cin == CIN_SYSEX_ENDS_IN_3)) +#define CIN_IS_SYSEX(cin) ( ((cin) & ~(0x08)) && ((cin) &0x04) ) + +/* + * MIDI V1 message definitions these are from the MMA document + * http://www.midi.org/techspecs/midimessages.php + */ +#define MIDIv1_BAUD_RATE 31250 + +/* + * parse midi (v1) message macros + */ +#define MIDIv1_IS_STATUS(b) ((b) & 0x80) +#define MIDIv1_IS_VOICE(b) ((b) <= 0xEF) +#define MIDIv1_VOICE_COMMAND(b) ((b) & 0xF0) +#define MIDIv1_VOICE_CHANNEL(b) ((b) & 0x0F) +#define MIDIv1_IS_SYSCOMMON(b) (((b) >= 0xF0) & ((b) < 0xF8)) +#define MIDIv1_IS_REALTIME(b) ((b) >= 0xF8) + +/* + * Voice category messages + */ +#define MIDIv1_NOTE_OFF 0x80 /* 2 bytes data -- CIN_NOTE_OFF */ +#define MIDIv1_NOTE_ON 0x90 /* 2 bytes data -- CIN_NOTE_ON */ +#define MIDIv1_AFTER_TOUCH 0xA0 /* 2 bytes data -- CIN_AFTER_TOUCH */ +#define MIDIv1_CONTROL_CHANGE 0xB0 /* 2 bytes data -- CIN_CONTROL_CHANGE */ +#define MIDIv1_PROGRAM_CHANGE 0xC0 /* 1 byte data -- CIN_PROGRAM_CHANGE */ +#define MIDIv1_CHANNEL_PRESSURE 0xD0 /* 1 byte data -- CIN_CHANNEL_PRESSURE */ +#define MIDIv1_PITCH_WHEEL 0xE0 /* 2 bytes data -- CIN_PITCH_WHEEL */ + +/* + * System common category messages + */ +#define MIDIv1_SYSEX_START 0xF0 +#define MIDIv1_SYSEX_END 0xF7 +#define MIDIv1_MTC_QUARTER_FRAME 0xF1 /* 1 byte data -- CIN_2BYTE_SYS_COMMON */ +#define MIDIv1_SONG_POSITION_PTR 0xF2 /* 2 bytes data -- CIN_3BYTE_SYS_COMMON */ +#define MIDIv1_SONG_SELECT 0xF3 /* 1 byte data -- CIN_2BYTE_SYS_COMMON */ +#define MIDIv1_TUNE_REQUEST 0xF6 /* no data -- CIN_1BYTE */ + +/* + * Realtime category messages, can be sent anytime + */ +#define MIDIv1_CLOCK 0xF8 /* no data -- CIN_1BYTE */ +#define MIDIv1_TICK 0xF9 /* no data -- CIN_1BYTE */ +#define MIDIv1_START 0xFA /* no data -- CIN_1BYTE */ +#define MIDIv1_CONTINUE 0xFB /* no data -- CIN_1BYTE */ +#define MIDIv1_STOP 0xFC /* no data -- CIN_1BYTE */ +#define MIDIv1_ACTIVE_SENSE 0xFE /* no data -- CIN_1BYTE */ +#define MIDIv1_RESET 0xFF /* no data -- CIN_1BYTE */ + +/* + * Susbset of universal sysex (general info request) + * As described http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/midispec.htm + */ +#define USYSEX_NON_REAL_TIME 0x7E +#define USYSEX_REAL_TIME 0x7F +#define USYSEX_ALL_CHANNELS 0x7F +#define USYSEX_GENERAL_INFO 0x06 +#define USYSEX_GI_ID_REQUEST 0x01 +#define USYSEX_GI_ID_RESPONSE 0x02 + +#endif + + diff --git a/sysexdemo/qtest.py b/sysexdemo/qtest.py new file mode 100644 index 0000000..bd2c4b2 --- /dev/null +++ b/sysexdemo/qtest.py @@ -0,0 +1,38 @@ +import rtmidi_python as rtmidi + +import rtmidi_python as rtmidi + +def callback(message, time_stamp): + if (len(message)>4 and message[0]==240 + and message[1]==125 and message[2]==51 and message[3]==51 + ): + decodeHexLine(message); + #print message, time_stamp + +#:llaaaattd1..dncs +def decodeHexLine(payload): +# print payload + # length = int(chr(payload[5])+chr(payload[6]),16) + #address = int(chr(payload[7])+chr(payload[8])+chr(payload[9])+chr(payload[10]),16) + #type = int(chr(payload[11])+chr(payload[12]),16) + #type = int(chr(payload[len(payload)-2])+chr(payload[len(payload)-2]),16) + high=None + decoded='' + for byte in payload[13:len(payload)-3] : + #print byte,'/', + if high is None: + high=byte + else: + pair=chr(high)+chr(byte) + #print "["+pair+"]", + decoded=decoded+chr(int(pair,16)) + high=None + print decoded + +midi_in = rtmidi.MidiIn() +print midi_in.ports +midi_in.callback = callback +midi_in.ignore_types(False,False,False) +midi_in.open_port(0) + +while 1: pass diff --git a/sysexdemo/sysexdemo.ino b/sysexdemo/sysexdemo.ino new file mode 100644 index 0000000..aa8ebfb --- /dev/null +++ b/sysexdemo/sysexdemo.ino @@ -0,0 +1,149 @@ +/*----------------------------------------------------------------------sysextest.ino + * this uses pjrc's midi library to get the sysex info. + * + */ +#include <Wire.h> +#include <MIDI.h> +#include "MidiSpecs.h" +#include <WiiChuck.h> + +#include <stdio.h> +#include <stdarg.h> + +WiiChuck wii = WiiChuck(); // sda, scl + + + +void sendThroughSysex(char *printbuffer, int bufferlength); +uint8_t sysexbuffer[80]={0xF0,0x7D,0x33,0x33,0x00,0xf7}; +char _pBr[40]; +int _nChars; +#define debug(...) _nChars = sprintf(_pBr, __VA_ARGS__); sendThroughSysex(_pBr,_nChars); +void setup() { + wii.init(); + + ; +} + +uint8_t t=0; + +/*--------------------------------------------------------------------------check_midi() + * + * check midi looks for sysex messages and responds to the universal sysex general + * info request + * + */ +uint8_t identityResponse[]={MIDIv1_SYSEX_START,USYSEX_NON_REAL_TIME,USYSEX_ALL_CHANNELS, + USYSEX_GENERAL_INFO,USYSEX_GI_ID_RESPONSE, + 0x7d,0x03,0x0d, // vendor id and family + 0x01,0x01, // product id + 0x00,0x00,0x00,0x01, // version + MIDIv1_SYSEX_END}; + +bool check_midi() { + uint8_t *theSysex,theLength; + if (usbMIDI.read() && usbMIDI.getType()==7) { + debug("I Got a Sysex (length=%d) !",theLength=usbMIDI.getData1()); + theSysex=usbMIDI.getSysExArray(); + if ((theLength>=6) + && (theSysex[1]==USYSEX_NON_REAL_TIME) + && (theSysex[3]==USYSEX_GENERAL_INFO) + && (theSysex[4]==USYSEX_GI_ID_REQUEST) + ) { + //debug("sending identity"); + usbMIDI.sendSysEx(sizeof(identityResponse),identityResponse); + return(true); + } + if (theLength==2) { + debug("Empty Sysex Recieved"); + } + } +} + + +#define MIDI_TASKS {check_midi();} +#define AUDIBLE_LAG_MS 15 + +/* + * NOTE doesnt check for millis rollover. + */ +void idle(int ms) { + long int cmillis; + long int endmillis=millis()+ms; + long lag=millis(); + while ((cmillis=millis())<endmillis) { + if (cmillis>=lag) { + MIDI_TASKS; + lag=cmillis+AUDIBLE_LAG_MS; + } + } +} + + + +void loop() { + int n; + for (t=1; t<126; t++){ + usbMIDI.sendNoteOn(t,127,1); + idle(100); + usbMIDI.sendNoteOff(t,0,1); + idle(100); + debug("note#%02X",t); + } +} + + + +void sendThroughSysex(char *printbuffer, int bufferlength) { + int n; + n = iHexLine(1, 0 , (uint8_t *) printbuffer, (uint8_t) bufferlength ,sysexbuffer+4); + sysexbuffer[n+4]=0xf7; + sysexbuffer[n+5]=0x00; + usbMIDI.sendSysEx(n+5,sysexbuffer); +} + +#define HIGHBYTE(x) ((uint8_t) (((x) >> 8) & 0x00ff) ) +#define LOWBYTE(x) ((uint8_t) ((x) & 0x00ff) ) +#define HIGHNIBBLE(x) ((((uint8_t)(x)) & 0xF0) >> 4) +#define LOWNIBBLE(x) (((uint8_t)(x)) & 0x0F) +#define HEXCHAR(c) ((c>9)?55+c:48+c) + +uint8_t iHexLine(uint8_t rectype, uint16_t address, uint8_t *payload,uint8_t payloadlength, uint8_t *buffer) { + + int i=0; int j; + uint8_t n=0; + uint16_t checksum=0; + //uint16_t length=0; + + buffer[i++]=':'; + + checksum+=payloadlength; + buffer[i++]=HEXCHAR(HIGHNIBBLE(payloadlength)); + buffer[i++]=HEXCHAR(LOWNIBBLE(payloadlength)); + + n=HIGHBYTE(address); + checksum+=n; + buffer[i++]=HEXCHAR(HIGHNIBBLE(n)); + buffer[i++]=HEXCHAR(LOWNIBBLE(n)); + + n=LOWBYTE(address); + checksum+=n; + buffer[i++]=HEXCHAR(HIGHNIBBLE(n)); + buffer[i++]=HEXCHAR(LOWNIBBLE(n)); + + n=rectype; + checksum+=n; + buffer[i++]=HEXCHAR(HIGHNIBBLE(n)); + buffer[i++]=HEXCHAR(LOWNIBBLE(n)); + + for (j=0; j<payloadlength ; j++) { + n=payload[j]; + checksum+=n; + buffer[i++]=HEXCHAR(HIGHNIBBLE(n)); + buffer[i++]=HEXCHAR(LOWNIBBLE(n)); + } + n=~((uint8_t) checksum&0x00ff)+1; + buffer[i++]=HEXCHAR(HIGHNIBBLE(n)); + buffer[i++]=HEXCHAR(LOWNIBBLE(n)); + return i; +} |
