arpruss / USBComposite_stm32f1

USB Composite library for STM32F1 (HID, Serial, MIDI and XBox360 controller)
Other
382 stars 76 forks source link

Strange USBMIDI behaviour #34

Closed celoranta closed 4 years ago

celoranta commented 4 years ago

Hello All.

Relatively new programmer and newb embedded system guy here, but old-time midi guru.

My programming/hardware/USBComposite library is encountering a weird issue that I can't seem to troubleshoot in the code. I am trying to dedicate 8 pins as outputs (PWM-capable outputs, to drive LEDs) and another 8 as digital inputs.

Everything is working well to a point:

A press-and-hold on an input sends a MIDI note ON out via USB. The associated output port lights up the LED. A release sends the corresponding MIDI note OFF, and the LED turns back off. Additionally, a quick 'tap' of an input switch sends a MIDI ON note with no corresponding OFF. The subsequent press/release sends the OFF upon release.

BUT... then I set certain outputs to HIGH, and suddenly I am sending several predictable-yet-unintended MIDI note ON and OFF messages with every input trigger cycle. I have no idea why the status of an output port should be affecting the MIDI data being triggered.

For my part, this could be hardware, this could be library, or this could be my own poor coding/hardware knowledge.

I'll post my code below. Any insight would be appreciated.

_#include <USBComposite.h>

//Note assignment 
struct Assignment {
  byte note;
  byte notePin;
  byte ledPin;
};
struct State {
  byte currentPinStatus;
  byte prevPinStatus;
  bool tapCountFlag;
  int tapCount;
  bool heldNoteFlag;
};
struct ActionBuffer {
  Assignment assignment;
  State state;
};

//Data
const byte pinOFF = HIGH;
const byte pinON = LOW;
const byte loopDelay = 10;
const int tapDelay = 150;
const byte defaultPinValue = 2;
const byte boardLEDPin = 32;

State defaults = {defaultPinValue, defaultPinValue, false, 0, false};

//Pin 0 as LED output causes additional MIDI notes to be sent. (notes 0, 9, and 97... both ON and OFF commands are sent.)
//Pin 16 as LED output causes additional MIDI notes to be sent. (notes 0, 9, and 97... both ON and OFF commands are sent.)
//Using Pins 8, 9, 10, 17, 22, 23, 24, or 25 as LED output causes a suite of unintended MIDI notes to be sent.

Assignment assignments[] = {
  Assignment {note: 60, notePin: 19, ledPin: 1},
  Assignment {note: 61, notePin: 20, ledPin: 2},
  Assignment {note: 62, notePin: 21, ledPin: 3},
  Assignment {note: 63, notePin: 15, ledPin: 6},
  Assignment {note: 64, notePin: 31, ledPin: 7}
};
ActionBuffer actionBuffers[sizeof(assignments)] = {};
USBMIDI midi;
void LEDOn() {
  if (digitalRead(boardLEDPin) == HIGH) {
    digitalWrite(boardLEDPin, LOW);
  }
};
void LEDOff() {
  if (digitalRead(boardLEDPin) == LOW) {
    digitalWrite(boardLEDPin, HIGH);
  }
};
void flashLED(byte qty) {
  for (int i = 0; i < qty; i++) {
    LEDOn();
    delay(10);
    LEDOff();
  }
};
void setup() {
  //From Example
  USBComposite.setProductId(0x0031);
  midi.begin();
  delay(1000);
  //Chris's Setup Code
  for (int i = 0; i < sizeof(assignments); i++) {
    Assignment thisAssignment = assignments[i];
    actionBuffers[i] = {assignments[i], defaults};
    pinMode(actionBuffers[i].assignment.notePin, INPUT_PULLUP);
    pinMode(actionBuffers[i].assignment.ledPin, OUTPUT);
    //digitalWrite(actionBuffers[i].assignment.ledPin, LOW);
  };
  pinMode(boardLEDPin, OUTPUT);
  LEDOff();
}
void loop() {
  for (int i = 0; i < sizeof(assignments); i++) {
    //Shift existing pin value to 'previous' and check new status
    actionBuffers[i].state.prevPinStatus = actionBuffers[i].state.currentPinStatus;
    actionBuffers[i].state.currentPinStatus = digitalRead(actionBuffers[i].assignment.notePin);
    //If tap flag is on,
    if (actionBuffers[i].state.tapCountFlag == true) {
      //increment the tapDelayCount
      actionBuffers[i].state.tapCount += loopDelay;
      //if tap count is over the theshold
      if (actionBuffers[i].state.tapCount >= tapDelay) {
        //turn off the flag
        actionBuffers[i].state.tapCountFlag = false;
      };
    }
    //if tap flag is off
    if (actionBuffers[i].state.tapCountFlag == false) {
      //reset the counter
      actionBuffers[i].state.tapCount = 0;
    };

    //Skip the rest of this loop iteration if the pin has not changed
    if (actionBuffers[i].state.currentPinStatus != actionBuffers[i].state.prevPinStatus) {
      //If pin has changed to ON...
      /*else*/ if (actionBuffers[i].state.currentPinStatus == pinON) {
        //and the held note flag is off
        if (actionBuffers[i].state.heldNoteFlag == false) {
          //play note on
          midi.sendNoteOn(0, actionBuffers[i].assignment.note, 127);
          //and turn on tap count flag
          actionBuffers[i].state.tapCountFlag = true;
         digitalWrite(actionBuffers[i].assignment.ledPin, HIGH);    
        }
        //but if the held note flag is on
        else {
          //clear the held note flag
          actionBuffers[i].state.heldNoteFlag = false;
        }
      }
      //If pin has changed from ON
      /*else*/ if (actionBuffers[i].state.prevPinStatus == pinON && actionBuffers[i].state.currentPinStatus != pinON) {
        //and if tap count flag is OFF
        if (actionBuffers[i].state.tapCountFlag == false) {
          //turn note off
          midi.sendNoteOff(0, actionBuffers[i].assignment.note, 127);
         digitalWrite(actionBuffers[i].assignment.ledPin, LOW);    
        }
        //but if tap count flag is ON
        else {
          //throw the held note flag.
          actionBuffers[i].state.heldNoteFlag = true;
          //And clear the tap count flag
          actionBuffers[i].state.tapCountFlag = false;
          flashLED(1);
        }
      }
    }
  };
  delay(loopDelay);
  //flashLED(2);
}_
celoranta commented 4 years ago

Realized since my post that pwm has nothing to do with analog input pins. Issue still outstanding. Edited.

celoranta commented 4 years ago

Realized since my post that pwm has nothing to do with analog input pins. Issue still outstanding. Edited.

..aaand I've realized that my previous realization was incorrect. Those pins are capable of analog output via PWM as well as analog input. Re-edited to re-add previously deleted.

celoranta commented 4 years ago

Ah. The problem was me. Go figure. C logical errors. sizeof() returns byte qty and not index qty. Problem was compounded by many similar errors. All fixed.

4dvn commented 4 years ago

Ah. The problem was me. Go figure. C logical errors. sizeof() returns byte qty and not index qty. Problem was compounded by many similar errors. All fixed.

I need to make the 16 buttons from note 36 to 51, can you send me the code via my email: vuha.hau@hyper.vn, i can't find how to program the note buttons. Thank you!