tttapa / MIDI_controller

This is a library for creating a MIDI controller using an Arduino or Teensy board.
GNU General Public License v3.0
402 stars 70 forks source link

Can not compile on Teensy++ 2.0 #20

Closed DH1KLM closed 6 years ago

DH1KLM commented 6 years ago

Description of the problem or question

Can not compile any of your examples on Teensy++ 2.0, since always it gives the following error: "Please select a 'Serial + MIDI' option in the 'Tools > USB Type' menu" But Teensy++ 2.0 did not offer the Serial + MIDI option. This option only exits from Teensy LC upwards to Teensy 3.6. I can select either USB or Serial.

Teensy MIDI examples installed by Teensyduino Installer are compiling without problems.

FYI: On my Pro Micro your examples are compiling without errors.

Steps to reproduce the problem

Have tested two different PC's using Win 10 and 7, also different Arduino IDE 1.6.x to 1.8.x and various Teensyduino. On both PC's the same result. Pro micro > yes, Teensy++ 2.0 >no.

Hardware

Teensy++ 2.0

Software versions:

MIDI Controller library: 3.0.1 Arduino IDE: 1.8.5 Operating System: Windows 7/10 (Teensyduino): 1.4.1
(Encoder library): 1.4.1
(MIDIUSB library): 1.0.3

Full code

for example:

In file included from C:\Users\xxxx\Documents\Arduino\libraries\MIDI_controller-3.0.1\examples\Ex.13.Shift-Register\Ex.13.Shift-Register.ino:18:0:

C:\Users\xxxx\Documents\Arduino\libraries\MIDI_controller-3.0.1\src/MIDI_Controller.h:7:2: error: #error Please select a 'Serial + MIDI' option in the 'Tools > USB Type' menu.

error Please select a 'Serial + MIDI' option in the 'Tools > USB Type' menu.

^

Fehler beim Kompilieren für das Board Teensy++ 2.0.

tttapa commented 6 years ago

The error is produced here: https://github.com/tttapa/MIDI_controller/blob/ff983c5c470464edab95af5033ec6f65c6ce47ba/src/MIDI_Controller.h#L6-L8 This is actually just a warning, because selecting Serial + MIDI is required for the MIDI USB interface.
This library has to read MIDI USB packets, otherwise the connection will stall, and software might crash. Reading USB packets on the Teensy++ 2.0 is very different from the Teensy 3.x. Here's what it looks like on the Teensy 3.x: https://github.com/tttapa/MIDI_controller/blob/ff983c5c470464edab95af5033ec6f65c6ce47ba/src/MIDI_Interfaces/USBMIDI_Interface.h#L23-L38 For the Teensy++ 2.0, however, it's done like this:
https://github.com/PaulStoffregen/cores/blob/7099935c0e67f3bd518858f8d72e5b735fd9ce12/usb_midi/usb_api.cpp#L181-L203
There is no documentation on this piece of code, and I have no experience with the USB registers that are used, so I don't have a solution, I could try just copying this piece of code, but I can't test it.

One thing you could try is to replace lines 26-33 of USBMIDI_Interface.h with

return usbMIDI.read();

and comment out line 7 of MIDI_Controller.h and line 7 of USBMIDI_Interface.h.

DH1KLM commented 6 years ago

Have tried your suggestion, but it gives me a lot of new errors. But that is to complicated for me. It is a pity that your excellent code does not work with Teensy ++, since i need a lot of digital Pins.

So i have to switch back to ProMicro and find out how to connect a Button Matrix with at least 36 Buttons , 4 Encoders with pushbutton and 2 Analog potentiometers. For this purpose the ProMicro has to few digital input pins.

I have the intention to continue using your libraries, because it quickly succeeds in building a midi controller. But i dont know how to expand the digital input pins on ProMicro.

Just noticed that you also support Extended IO as well. But what should i use for my project? Shift Register or Port Expander SX1509 (is already in stock) or something like this?

Do you have any recommendations? If this is to much off topic, would you please send me a mail?

tttapa commented 6 years ago

I have no idea if it works, but at least this compiles: https://github.com/tttapa/MIDI_controller/commit/cbe25bb9cb43254586e7299978ff733e486293cc

tttapa commented 6 years ago

Just noticed that you also support Extended IO as well.
But what should i use for my project? Shift Register or Port Expander SX1509 (is already in stock) or something like this?

Currently, it only supports shift register outputs and analog multiplexers inputs.

DH1KLM commented 6 years ago

Just made a short test. It gives a lot of warnings, but it compiles like you already said. But much much better, it also works! You made my day! I only did a little test with 1 encoder and 1 button and they worked as expected. Now I am going to build the hardwarepart, after that i try to do my sketch and report back about possible findings.

DH1KLM commented 6 years ago

Hardware part is almost done and works like expected. 3 Encoders, 4 Pots and a 36 Button Matrix are working well. But i have one thing i like do. I need to have 2 push buttons (up/down) to scroll in a List.

scroll-hz-list

If i press the button, the cursor moves from lets say 10 Hz to 50 Hz (so far so good)
but if the button is released the cursor moves further from 50 Hz to 100 Hz and so on. How can it be done that only one step is executed per press and release activity? (10 Hz to 50 Hz) I tried another library (https://github.com/ghztomash/MIDIElements) His basic example works exactly this way.

I helped myself by integrating his library aditionaly, but it would be nice if your library could do this as well. Is it also possible to use such a function in a button matrix?

tttapa commented 6 years ago

What MIDIElements code are you using? What software are you using and what MIDI messages does it expect?

tttapa commented 6 years ago

You need the latest version (https://github.com/tttapa/MIDI_controller/commit/604fdda6a7d475de6c603cf8e0942111c24b6826) Then try this:

main.ino

#include <MIDI_Controller.h>
#include "ScrollButtons.h"

const uint8_t controller = MIDI_CC::General_Purpose_Controller_1;
const uint8_t channel = 1;

ScrollButtons scrlbtns(2, 3, controller, channel, TWOS_COMPLEMENT); // button up on pin 2, button down on pin 3

void setup() {}

void loop() {
  MIDI_Controller.refresh();
}

ScrollButtons.h

#ifndef ScrollButtons_H_
#define ScrollButtons_H_

#include "Arduino.h"
#include <MIDI_Outputs/MIDI_Control_Element.h>
#include <MIDI_Outputs/RotaryEncoder.h>
#include "PushButton.h"

class ScrollButtons : public MIDI_Control_Element
{
public:
  ScrollButtons(pin_t pinUp, pin_t pinDown, uint8_t controller, uint8_t channel, relativeCCmode mode = TWOS_COMPLEMENT);  // Constructor
  ~ScrollButtons(); // Destructor

private:
  void refresh(); // Check if the button state changed, and send a MIDI CC accordingly

  PushButton buttonUp, buttonDown;
  const uint8_t controller;
  const uint8_t channel;
  const relativeCCmode mode;
};

#endif

ScrollButtons.cpp

#include "ScrollButtons.h"
#include <MIDI_Controller.h>

ScrollButtons::ScrollButtons(pin_t pinUp, pin_t pinDown, uint8_t controller, uint8_t channel, relativeCCmode mode)  // Constructor
  : buttonUp(pinUp), buttonDown(pinDown), controller(controller), channel(channel), mode(mode) {}

ScrollButtons::~ScrollButtons() {} // Destructor

void ScrollButtons::refresh() {  // Check if the button state changed, and send a MIDI CC accordingly
  if (buttonUp.isPressed()) {
    uint8_t value = RotaryEncoder::mapRelativeCC(1, mode);
    MIDI_Controller.MIDI()->send(CONTROL_CHANGE, 
        channel + channelOffset * channelsPerBank,
        controller + addressOffset * channelsPerBank, value);
  }
  if (buttonDown.isPressed()) {
    uint8_t value = RotaryEncoder::mapRelativeCC(-1, mode);
    MIDI_Controller.MIDI()->send(CONTROL_CHANGE, 
        channel + channelOffset * channelsPerBank,
        controller + addressOffset * channelsPerBank, value);
  }
}

PushButton.h

#ifndef PUSHBUTTON_H_
#define PUSHBUTTON_H_

#include <Settings/Settings.h>
#include <ExtendedInputOutput/ExtendedInputOutput.h>

class PushButton
{
  public:
    PushButton(uint8_t pin) // Constructor (executes when a PushButton object is created)
      : pin(pin) { // remember the push button pin
      ExtIO::pinMode(pin, INPUT_PULLUP); // enable the internal pull-up resistor
    };
    bool isPressed() // read the button state check if the button has been pressed, debounce the button as well
    {
      bool pressed = false;
      bool state = ExtIO::digitalRead(pin);               // read the button's state
      int8_t stateChange = state - previousState;  // calculate the state change since last time

      if (stateChange == falling) { // If the button is pressed (went from high to low)
        if (millis() - previousBounceTime > debounceTime) { // check if the time since the last bounce is higher than the threshold
          pressed = true; // the button is pressed
        }
      }
      if (stateChange == rising) { // if the button is released or bounces
        previousBounceTime = millis(); // remember when this happened
      }

      previousState = state; // remember the current state
      return pressed; // return true if the button was pressed and didn't bounce
    };
  private:
    uint8_t pin;
    bool previousState = HIGH;
    unsigned long previousBounceTime = 0;

    const static unsigned long debounceTime = BUTTON_DEBOUNCE_TIME;
    const static int8_t rising = HIGH - LOW;
    const static int8_t falling = LOW - HIGH;
};

#endif // PUSHBUTTON_H_
DH1KLM commented 6 years ago

The MidiElements code for the buttons is this one https://github.com/ghztomash/MIDIElements/blob/master/examples/midiElements_basic_example/midiElements_basic_example.ino With this code it is easy to realize buttons which are mapped in the software to the desired function. In my case UP/DOWN and also toggling between 2 functions.

The software i am using, is for operating a HAM Radio SDR Transceiver. I am using https://www.hfrelectronics.com and https://github.com/w5wc/openPowerSDR/tree/master Both can be controlled via MIDI DJ controllers like Behringer CMD PL1, Hercules and so on. Also DIY MIDI controllers are working. The MIDI commands sent from the controller can be mapped to various functions.

I hope i can try your new code on Sunday and see what happens.

DH1KLM commented 6 years ago

Have tried the new code. Does not compile for Teensy but for Pro Micro. Have tried Branch "Master" and "Teensy++2.0" as well.

With two buttons the UP/DWN function works so far but a single button did not act as toggle function. (MIDI Modifier in Zeus) (MIDIElements does) And the buttons always have to be designated (one button up, the other one down) . It looks like the new UP/DWN function makes the buttons act as a encoder. (Shown also as Wheel in Zeus)

FYI the following screenshots showing the differences in result between the two librarys.

Screenshot from ZeusSDR with your new button function.

zeus midi

MidiOX screenshot with your new button function.

midi-ox-tttapa

Screenshot from ZeusSDR with Midielements Button and one tttapa encoder. Here you can see the Midielements button is working as MidiModifier (toggle) and allows to use one encoder on two Zeus functions.

zeus midi midielements button

MidiOX screenshot with Midielements Button.

midielements-button

But i also can live very well with the Midielements button library. There is no urgent need to implement such function in your code.

Anyway, I'm overjoyed that your library even exists and that you've taken the time to do the customization for Teensy ++ 2.0.

Thank you very much

tttapa commented 6 years ago

I forgot to merge my changes into the Teensy++2.0 branch.
This should solve it: https://github.com/tttapa/MIDI_controller/commit/5940837770bb2f76d8a40cbf24a9d4494a68bf31

Also note that I removed " = TWOS_COMPLEMENT" from ScrollButtons.cpp in my previous reply.

I've tested it with an Arduino Leonardo, and it compiles fine for the Teensy++2.0.