diff --git a/NuEVI/midi.cpp b/NuEVI/midi.cpp index 396d3e3..3dd09d7 100644 --- a/NuEVI/midi.cpp +++ b/NuEVI/midi.cpp @@ -184,16 +184,24 @@ void sendWLChannel(const uint8_t channel) { //Only 14 LSB of int value are used (2MSB are discarded), so only works for unsigned data 0-16383 //NOTE: This assumes code is running on a little-endian CPU, both for real device (Teensy) and simulator. -uint16_t midi16to14(uint16_t realdata) { +uint16_t midi16to14(const uint16_t realdata) { return (realdata & 0x3F80) >>7 | (realdata & 0x007F) <<8; } -uint16_t midi14to16(uint16_t mididata) { +uint16_t midi14to16(const uint16_t mididata) { return (mididata & 0x7F00) >> 8 | (mididata & 0x007F) <<7 ; } +//Read from a memory location, such as MIDI receive buffer +uint16_t midi14to16(const uint8_t* mididata) { + uint8_t msb = *mididata; + uint8_t lsb = *(mididata+1); + + return (msb & 0x007F) <<7 | (lsb & 0x007F); +} + //This is a bit different. MSB of each byte is just discarded (instead of discarding MSB for whole value). Just used for CRC (easier to compare) -uint32_t midi32to28(uint32_t realdata) { +uint32_t midi32to28(const uint32_t realdata) { uint8_t* p = (uint8_t*)&realdata; uint32_t r=0; diff --git a/NuEVI/midi.h b/NuEVI/midi.h index d663169..a3af25b 100644 --- a/NuEVI/midi.h +++ b/NuEVI/midi.h @@ -38,8 +38,9 @@ void sendWLChannel(const uint8_t channel); //Convert things between "regular data" and MIDI data (byte order and 7-bits-per-byte) -uint16_t midi16to14(uint16_t realdata); -uint16_t midi14to16(uint16_t mididata); -uint32_t midi32to28(uint32_t realdata); +uint16_t midi16to14(const uint16_t realdata); +uint16_t midi14to16(const uint16_t mididata); +uint16_t midi14to16(const uint8_t* mididata); +uint32_t midi32to28(const uint32_t realdata); #endif diff --git a/NuEVI/settings.cpp b/NuEVI/settings.cpp index b9a6ab8..c8da141 100644 --- a/NuEVI/settings.cpp +++ b/NuEVI/settings.cpp @@ -305,6 +305,7 @@ bool receiveSysexSettings(const uint8_t* data, const uint16_t length) { //Make sure length of receive buffer is enough to read all we need to. We can accept extra junk at the end though. if(lengthctouchHiLimit) continue; } - writeSetting(i, val); + writeSetting(addr, val); } //All went well @@ -397,17 +399,21 @@ void configShowMessage(const char* message) { } uint8_t* sysex_rcv_buffer = NULL; +uint16_t sysex_buf_size = 0; -void handleSysexChunk(const uint8_t *data, const uint16_t length, const bool last) { - size_t pos = 0; +void handleSysexChunk(const uint8_t *data, const uint16_t length, const uint8_t last) { + uint16_t pos; if(!sysex_rcv_buffer) { //Start out with an empty buffer - sysex_rcv_buffer = (uint8_t *)malloc(length); + pos = 0; + sysex_buf_size = length; + sysex_rcv_buffer = (uint8_t *)malloc(sysex_buf_size); } else { //Increase size of current buffer - size_t pos = sizeof(sysex_rcv_buffer); - sysex_rcv_buffer = (uint8_t *)realloc(sysex_rcv_buffer, pos + length); + pos = sysex_buf_size; + sysex_buf_size += length; + sysex_rcv_buffer = (uint8_t *)realloc(sysex_rcv_buffer, sysex_buf_size); } //Append this chunk to buffer @@ -415,9 +421,12 @@ void handleSysexChunk(const uint8_t *data, const uint16_t length, const bool las //If it's the last one, call the regular handler to process it if(last) { - handleSysex(sysex_rcv_buffer, pos+length); + handleSysex(sysex_rcv_buffer, sysex_buf_size); + + //Discard the buffer free(sysex_rcv_buffer); sysex_rcv_buffer = NULL; + sysex_buf_size = 0; } } diff --git a/simulation/include/Arduino.h b/simulation/include/Arduino.h index 8d0beff..ba160fe 100644 --- a/simulation/include/Arduino.h +++ b/simulation/include/Arduino.h @@ -85,8 +85,14 @@ public: void sendPitchBend(int value, uint8_t channel, uint8_t cable=0); void sendSysEx(uint16_t length, const uint8_t *data, bool hasTerm=false, uint8_t cable=0); bool read(uint8_t channel=0); - void setHandleSystemExclusive(__unused void (*fptr) (const uint8_t *array, uint8_t size)); - void setHandleSystemExclusive(__unused void (*fptr) (const uint8_t *data, uint16_t length, bool complete)); + void setHandleSystemExclusive(void (*fptr) (const uint8_t *array, unsigned int size)); + void setHandleSystemExclusive(void (*fptr) (const uint8_t *data, uint16_t length, uint8_t complete)); + + void receiveMidiData(const uint8_t *data, const uint16_t length); //Send midi data "into simulator" +private: + //Handlers registered to receive MIDI + void (*usb_midi_handleSysExPartial)(const uint8_t *data, uint16_t length, uint8_t complete); + void (*usb_midi_handleSysExComplete)(const uint8_t *data, unsigned int size); }; extern SimSerial Serial; diff --git a/simulation/src/simusbmidi.cpp b/simulation/src/simusbmidi.cpp index a240fc0..dfa5661 100644 --- a/simulation/src/simusbmidi.cpp +++ b/simulation/src/simusbmidi.cpp @@ -8,7 +8,6 @@ * Stub simulation of Teensy usbMidi */ - void SimUsbMidi::sendNoteOff(uint8_t note, uint8_t velocity, uint8_t channel, uint8_t __unused cable) { printf( "[usbMIDI::noteOff] note %03d vel %03d ch %02d\n", note, velocity, channel); @@ -54,16 +53,93 @@ void SimUsbMidi::sendSysEx(uint16_t length, const uint8_t __unused *data, bool _ printf( "[usbMIDI::sysEx] len %d\n", length); } +//Set a low chunk size on purpose just to let the receiver work for it +#define MIDI_SYSEX_CHUNK_SIZE 32 + +/* Test data for config mode + +//Carefully crafted config command chunk to send via midi +static const uint8_t midimessage[] = { + 0xf0, //Sysex start + 0x00, 0x3e, 0x7f, //Vendor + 'N', 'u', 'E', 'V', 'I', //header + 'c', '0', '2', //message code + 0, 102, //length + + //Payload + 0x00, 0x20, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, //00 + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x06, 0x07, //08 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, //10 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, //18 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, //20 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, //28 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, //30 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, //38 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, //40 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, //48 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, //50 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, //58 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, //60 + 0x2a, 0x11, 0x32, 0x5a, //crc32 + 0xf7 //sysex end marker +}; + +static bool midisent = false; + +//On first midi read, send a message +bool SimUsbMidi::read(uint8_t __unused channel) { + if(!midisent) { + this->receiveMidiData(midimessage, sizeof(midimessage)); + midisent=true; + } + return false; +} + +*/ + bool SimUsbMidi::read(uint8_t __unused channel) { return false; } -//Regular sysex handler -void SimUsbMidi::setHandleSystemExclusive(__unused void (*fptr) (const uint8_t *array, uint8_t size)) { +//Provide midi data for simulation to receive +void SimUsbMidi::receiveMidiData(const uint8_t *data, const uint16_t length) { + if(this->usb_midi_handleSysExPartial) { + //Chunked sysex receiver set, use that. + if(length<=MIDI_SYSEX_CHUNK_SIZE) { + //Send all in one go + printf( "[SimUsbMidi::receiveMidiData] usb_midi_handleSysExPartial(complete) %d B\n", length); + (this->usb_midi_handleSysExPartial)(data, length, true); + } else { + uint8_t* buf = (uint8_t*)malloc(MIDI_SYSEX_CHUNK_SIZE); + int pos=0; + while(posusb_midi_handleSysExPartial)(buf, bytesToSend, complete); + pos=pos+bytesToSend; + } + free(buf); + } + + } else if(this->usb_midi_handleSysExComplete) { + printf( "[SimUsbMidi::receiveMidiData] usb_midi_handleSysExComplete() %d B\n", length); + (this->usb_midi_handleSysExComplete)(data, length); + } else { + //Nobody listening + } +} + +//Regular sysex handler. For some reason the data pointer is not const, but we'll set it as such to not be dumb. +void SimUsbMidi::setHandleSystemExclusive(void (*fptr) (const uint8_t *array, unsigned int size)) { + this->usb_midi_handleSysExComplete = fptr; } //"Chunked" sysex handler (teensy extension), for large messages -void SimUsbMidi::setHandleSystemExclusive(__unused void (*fptr) (const uint8_t *array, uint16_t size, bool last)) { - +void SimUsbMidi::setHandleSystemExclusive(void (*fptr) (const uint8_t *array, uint16_t size, uint8_t last)) { + this->usb_midi_handleSysExPartial = fptr; }