TheKikGen / USBMidiKliK

A robust USB MIDI Arduino firmware, with a dual bootloader, based on the LUFA library
89 stars 17 forks source link

Assistance needed for enhancement #9

Closed orzdk closed 5 years ago

orzdk commented 5 years ago

First of all thank you for this extremely solid piece of work.

I wonder if you (or some other kind soul) can help a beginner out with an custom enhancement. I hope it's ok to open an issue for questions like this, if not, please just close it.

What I want to do, is to add an analog pin listener to USBMidiKliK. When the value of any of 4 potentiometers change, the value should be mapped to MIDI CC controller 1-4 values 0-127, put in a neat midiPacket_t, inserted into the ring buffer and shipped to Serial or USB.

I made some tweaks to naught101/midi_knobs/midi_knobs.ino and now the general logic works as I need it to, but I need guidance how to correctly implement it in the USBMidiKlik architecture.

I have integrated the modified naught101 code, and added an #include wiring_analog.c (probably a completely backwards way to do this include :/ ) to be able to utilize the analogRead() function, from the AVR Core (ArduinoCore-avr-master), and I basically added the following code to USBMidiKlik_dual.cpp:

/////////////////////////////////////////////////////////////////////////////// // PROCESS POTMETER TO SERIAL/USB // ---------------------------------------------------------------------------- // Check whether any potmeters has changed ///////////////////////////////////////////////////////////////////////////////

include "wiring_analog.c"

define N_POTS 1

const uint8_t MIDICC = 0x0B;

const int potPins[] = {0, 1, 2, 3}; const uint8_t potCC[] = {0x0A, 0x0B, 0x0C, 0x0D};

uint8_t potVals[N_POTS];
uint8_t potValsPrev[] = {0, 0, 0, 0};

static int map(int x, int x1, int x2, int y1, int y2){ return (x - x1) * (y2 - y1) / (x2 - x1) + y1; }

static void SendCC(byte channel, byte control, byte value){ MIDI_EventPacket_t MIDIEvent = {0x0B, 0xB0 | channel, control, value}; RoutePacketToTarget(FROM_USB, (midiPacket_t )&MIDIEvent); RoutePacketToTarget(FROM_SERIAL, (midiPacket_t )&MIDIEvent); }

static void ProcessPots(){ for (int i=0;i<N_POTS;i++) {
if (abs(potValsPrev[i] - potVals[i]) > 1)
{ SendCC(0, potCC[i], potVals[i]); potValsPrev[i] = potVals[i]; } } }

static void ReadPots(){ for (int i=0; i < N_POTS; i++) { int val = analogRead(potPins[i]); int mval = (uint8_t)(map(val, 0, 1023, 0, 127)); potVals[i] += (mval - potVals[i])/4; } }

///////////////////////////////////////////////////////////////////////////////

I then tried to find where to properly hook it up, and i ended up adding calls to ReadPots() and ProcessPots() in the infinite loop in ProcessMidiUSBMode() which seemed most suitable.

for ( ;; ) { ... ProcessMidiToUsb(); ProcessUsbToMidi(); ReadPots(); ProcessPots(); MIDI_Device_USBTask(&Keyboard_MIDI_Interface); USB_USBTask(); }

Much to my surprise my changes actually compiles, but as very much expected, operating the CC potentiometer on my breadboard does not seem to send any MIDI. The Pro Micro still presents itself to my laptop as a USBMidiKlik device, so I do not believe I have completely broken the code, but my own changes do not work.

I think my first, very basic question on this long story is, if my approach to creating sending off the CC midi packages using RoutePacketToTarget, is anywhere near the correct solution for the task at hand, assuming the CC logic is working.

tttapa commented 5 years ago

As far as I know, you don't need USBMidiKlik for the Pro Micro. It is supported by the official MIDIUSB library.

To my understanding, the USBMidiKlik is primarily used to add MIDI over USB capabilities to the Arduino Uno, that doesn't support the MIDIUSB library, by replacing the firmware of the ATmega16U2.

orzdk commented 5 years ago

Thank you for your input tttapa. I must admit that my knowledge of MIDI and AVR is far too narrow to neither deny nor confirm your thesis. My scenario is simple, i need something that works like a USB MIDI interface like Roland UM-ONE, - and a Pro Micro and this code + the standard MIDI circuits seemed to do the trick. As USBMidiKlik seems to be very well written and to my knowledge constitutes the best publicly available AVR USB-Midi Interface code by far, I thought why not try to plug in the CC potmeter stuff if possible.

To my understanding, I don't nescessarily think it's a matter of "having to use" USBMidiKlik vs. USBMIDI, - this is a complete interface solution, whereas USBMIDI is a library, and I get from comments in the code that USBMidiKlik actually uses USBMIDI for certain operations. Please correct me if I do not get this right.

With regards to how the differences between an ATmega32U4 Pro Micro and an ATmega16U2+ATmega8U2 Uno, relates to the viability of a given code solution/library, and how USBMidiKlik handles those differences in the operation of the bootloader and USB Serial Descriptor flashing logic,- absolutely no clue, still learning this black magic wizardry: )

tttapa commented 5 years ago

I'm confused: do you want something to convert Serial/5-pin DIN MIDI to MIDI over USB, or do you want a MIDI Controller that sends out MIDI over USB when potentiometers change?