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

Please add support for CD74HC4067 ! CD74HC4051 provide only 1-8pins #28

Closed userdsp closed 6 years ago

userdsp commented 6 years ago

Please add support for CD74HC4067 ! I want to use banksellector with this mux like i can do it now with CD74HC4051. Also option for DigitalMultiplexor will be nice.

Bank pots(16);  
BankSelector bankselector(pots, 10, LED_BUILTIN, BankSelector::MOMENTARY); 

AnalogMultiplex multiplexer(A0, { 2, 3, 4, 5 } ); //CD74HC4067
// Create 8 new instances of the class 'Analog', on the 8 pins of the multiplexer,
// that send MIDI messages with controller 7 (channel volume) on channels 1 - 8
Analog potentiometers[] = {
  {multiplexer.pin(0), MIDI_CC::Channel_Volume, 1},
  {multiplexer.pin(1), MIDI_CC::Channel_Volume, 2},
  {multiplexer.pin(2), MIDI_CC::Channel_Volume, 3},
  {multiplexer.pin(3), MIDI_CC::Channel_Volume, 4},
  {multiplexer.pin(4), MIDI_CC::Channel_Volume, 5},
  {multiplexer.pin(5), MIDI_CC::Channel_Volume, 6},
  {multiplexer.pin(6), MIDI_CC::Channel_Volume, 7},
  {multiplexer.pin(7), MIDI_CC::Channel_Volume, 8},
  {multiplexer.pin(8), MIDI_CC::Channel_Volume, 9},
  {multiplexer.pin(9), MIDI_CC::Channel_Volume, 10},
  {multiplexer.pin(10), MIDI_CC::Channel_Volume, 11},
  {multiplexer.pin(11), MIDI_CC::Channel_Volume, 12},
  {multiplexer.pin(12), MIDI_CC::Channel_Volume, 13},
  {multiplexer.pin(13), MIDI_CC::Channel_Volume, 14},
  {multiplexer.pin(14), MIDI_CC::Channel_Volume, 15},
  {multiplexer.pin(15), MIDI_CC::Channel_Volume, 16}
};
void setup() {
pots.add(potentiometers, Bank::CHANGE_ADDRESS); // Add the control elements to the bank
}

CD74HC4067 :

pin4 pin3 pin2 pin1 Channel
on on on on 1
on on on off 2
on on off on 3
on on off off 4
on off on on 5
on off on off 6
on off off on 7
on off off off 8
off on on on 9
off on on off 10
off on off on 11
off on off off 12
off off on on 13
off off on off 14
off off off on 15
off off off off 16

Maybe you can add something like "if (numPinsOut > 8) pinMode(5, OUTPUT);" , and both 4051 and 4067 will be supported at the same time. Also will be so cool if there is a any way to use encoders thru those multiplexers! If you make this work I will be so happy :) I believe many other ppl too! Thank you very much I know i will be easy task for you! Best regards!

tttapa commented 6 years ago

It should be supported already, what makes you think that it doesn't work?

A digital multiplexer is kind of useles, since there is no difference in the implementation. If you really want to, you can use the AnalogMultiplex class with digital inputs.
That's not really a good idea, because you can address multiple buttons much more efficiently using a button matrix or using shift registers.

userdsp commented 6 years ago

My mistake! All 16 pins works but arduino freezes if I add pots.add(potentiometers, Bank::CHANGE_ADDRESS);

And what about Encoders thru mux?

tttapa commented 6 years ago

That's strange. What do you mean "freezes"? Does it stop running, or does it just stop sending MIDI messages? Try adding a blink without delay to the code:

void setup() {
  // ...
  pinMode(LED_BUILTIN, OUTPUT);
}

void blink() {
  static unsigned long previousBlinkTime = millis();
  if (millis() - previousBlinkTime > 250) {
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    previousBlinkTime += 250;
  }
}

void loop() {
  blink();
  // ...
}

If it stops blinking, you know it has entered an infinite loop (i.e. bad stuff happened).

userdsp commented 6 years ago

If i add pots.add(potentiometers, Bank::CHANGE_ADDRESS); it stop sending any midi messages One minute ill do it now

tttapa commented 6 years ago

And what about Encoders thru mux?

Encoders through a mux are a little harder, since they require hardware interrupts.

userdsp commented 6 years ago

I am using encoders without hardware interrupts on pins 7, 9, A4 ,A5. It was just interesting for me. Blink code ... led stop blinks if pots.add(potentiometers, Bank::CHANGE_ADDRESS); is active (not commented) I am using Uno with the 16U2 USB midi mod https://github.com/kuwatay/mocolufa

tttapa commented 6 years ago

I'll see what I can do.

userdsp commented 6 years ago

Sorry about your time! I start a fresh Scetch and everything its ok. maybe it was a conflict from another function witch was used for reading the first mux! Have a nice day and everything nice! BTW One last thing. Can i use mux and make buttons to be toggleSwitch mode? And how?

tttapa commented 6 years ago

You posted this code:

#include <MIDI.h>
#include "Controller.h"
#include <Shifty.h>
#include <MIDI_Controller.h>
//const uint8_t Channel = 10; // MIDI channel 1
//const uint8_t LController = 0x14; // MIDI Control Change controller number
//const uint8_t RController = 0x15; // MIDI Control Change controller number
const int speedMultiply = 1; // If the jog wheels or other encoders are too slow in your software, increase this value
// (it will be multiplied with the actual speed of the encoder, as the name implies.) Default is 1.

MIDI_CREATE_DEFAULT_INSTANCE();

Shifty myreg;

// Create a new instance of the class 'RotaryEncoder', called 'enc', on pin 2 and 3, controller number 0x14, on channel1,
// no change in speed (speed is multiplied by 1), it's used as a jog wheel, and the sign mode is set to two's complement.

RotaryEncoder encoderL(7, 9, 0x14, 6, speedMultiply, JOG, TWOS_COMPLEMENT);
RotaryEncoder encoderR(A4, A5, 0x15, 6, speedMultiply, JOG, TWOS_COMPLEMENT);
Bank pots1(16); // A bank with two address
BankSelector bankselector(pots1, 10, LED_BUILTIN, BankSelector::MOMENTARY); // A bank selector with a single toggle switch on pin 11 and an LED for feedback on pin 13

//int ledPin = 13;
//void OnNoteOn(byte channel, byte note, byte velocity) {
// digitalWrite(ledPin, HIGH); // Any Note-On turns on LED
//}
//void OnNoteOff(byte channel, byte note, byte velocity) {
// digitalWrite(ledPin, LOW); // Any Note-Off turns off LED
//}

AnalogMultiplex multiplexer1(A0, { 2, 3, 4, 5 } );

// Create 8 new instances of the class 'Analog', on the 8 pins of the multiplexer,
// that send MIDI messages with controller 7 (channel volume) on channels 1 - 8
Analog potentiometers1[] = {
{multiplexer1.pin(0), MIDI_CC::Channel_Volume, 1},
{multiplexer1.pin(1), MIDI_CC::Channel_Volume, 2},
{multiplexer1.pin(2), MIDI_CC::Channel_Volume, 3},
{multiplexer1.pin(3), MIDI_CC::Channel_Volume, 4},
{multiplexer1.pin(4), MIDI_CC::Channel_Volume, 5},
{multiplexer1.pin(5), MIDI_CC::Channel_Volume, 6},
{multiplexer1.pin(6), MIDI_CC::Channel_Volume, 7},
{multiplexer1.pin(7), MIDI_CC::Channel_Volume, 8},
{multiplexer1.pin(8), MIDI_CC::Channel_Volume, 9},
{multiplexer1.pin(9), MIDI_CC::Channel_Volume, 10},
{multiplexer1.pin(10), MIDI_CC::Channel_Volume, 11},
{multiplexer1.pin(11), MIDI_CC::Channel_Volume, 12},
{multiplexer1.pin(12), MIDI_CC::Channel_Volume, 13},
{multiplexer1.pin(13), MIDI_CC::Channel_Volume, 14},
{multiplexer1.pin(14), MIDI_CC::Channel_Volume, 15},
{multiplexer1.pin(15), MIDI_CC::Channel_Volume, 16}
};

//AnalogMultiplex multiplexer2(A1, { 2, 3, 4, 5 } );
//
// Create 8 new instances of the class 'Analog', on the 8 pins of the multiplexer,
// that send MIDI messages with controller 7 (channel volume) on channels 1 - 8
//Analog potentiometers2[] = {
// {multiplexer2.pin(0), MIDI_CC::Channel_Volume, 1},
// {multiplexer2.pin(1), MIDI_CC::Channel_Volume, 2},
// {multiplexer2.pin(2), MIDI_CC::Channel_Volume, 3},
// {multiplexer2.pin(3), MIDI_CC::Channel_Volume, 4},
// {multiplexer2.pin(4), MIDI_CC::Channel_Volume, 5},
// {multiplexer2.pin(5), MIDI_CC::Channel_Volume, 6},
// {multiplexer2.pin(6), MIDI_CC::Channel_Volume, 7},
// {multiplexer2.pin(7), MIDI_CC::Channel_Volume, 8},
// {multiplexer2.pin(8), MIDI_CC::Channel_Volume, 9},
// {multiplexer2.pin(9), MIDI_CC::Channel_Volume, 10},
// {multiplexer2.pin(10), MIDI_CC::Channel_Volume, 11},
// {multiplexer2.pin(11), MIDI_CC::Channel_Volume, 12},
// {multiplexer2.pin(12), MIDI_CC::Channel_Volume, 13},
// {multiplexer2.pin(13), MIDI_CC::Channel_Volume, 14},
// {multiplexer2.pin(14), MIDI_CC::Channel_Volume, 15},
// {multiplexer2.pin(15), MIDI_CC::Channel_Volume, 16}
//};

void setup() {
// ...
pinMode(LED_BUILTIN, OUTPUT);
pots1.add(potentiometers1, Bank::CHANGE_ADDRESS); // Add the control elements to the bank
// pinMode(ledPin, OUTPUT);
// MIDI.setHandleNoteOff(OnNoteOff);
// MIDI.setHandleNoteOn(OnNoteOn) ;
// digitalWrite(ledPin, HIGH);
// delay(400); // Blink LED once at startup
// digitalWrite(ledPin, LOW);

// pots1.add(encoderL, Bank::CHANGE_CHANNEL); // Add the control elements to the bank
// pots1.add(encoderL, Bank::CHANGE_ADDRESS); // Add the control elements to the bank
// pots1.add(encoderR, Bank::CHANGE_ADDRESS); // Add the control elements to the bank

// Set the number of bits you have (multiples of 8)
myreg.setBitCount(16);
// Set the clock, data, and latch pins you are using
// This also sets the pinMode for these pins
myreg.setPins(11, 12, 8);

MIDI.begin(MIDI_CHANNEL_OMNI); // Initialize the Midi Library.
// MIDI.turnThruOff();
// OMNI sets it to listen to all channels.. MIDI.begin(2) would set it
// to respond to notes on channel 2 only.
MIDI.setHandleControlChange(MyCCPWMFunction); // This command tells the MIDI Library
// MIDI.setHandleNoteOn(MyNoteFunction);
// the function you want to call when a Continuous Controller command
// is received. In this case it's "MyCCFunction".
}

void blink() {
static unsigned long previousBlinkTime = millis();
if (millis() - previousBlinkTime > 250) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
previousBlinkTime += 250;
}
}

void loop() {
// blink();
// ...
// Refresh the encoder (check whether the position has changed since last time, if so, send the difference over MIDI)
MIDI_Controller.refresh();
MIDI.read(); // Continuously check if Midi data has been received.
//MIDI.disconnectCallbackFromType(midi::NoteOff);
}

//*****************************************************************
// MyCCFunction is the function that will be called by the Midi Library
// when a Continuous Controller message is received.
// It will be passed byt es for Channel, Controller Number, and Value
// It checks if the controller number is within the 22 to 27 range
// If it is, light up the corresponding LED with the PWM brightness equal to the Value byte
void MyCCPWMFunction(byte channel, byte number, byte value) {
// myreg.batchWriteBegin();
// myreg.batchWriteEnd();
switch (number) {
case 0:
if (value >= 1) {
myreg.writeBit(0, HIGH);
break;
}
else {
myreg.writeBit(0, LOW);
break;
}
case 1:
if (value >= 1) {
myreg.writeBit(1, HIGH);
break;
}
else {
myreg.writeBit(1, LOW);
break;
}
case 2:
if (value >= 1) {
myreg.writeBit(2, HIGH);
break;
}
else {
myreg.writeBit(2, LOW);
break;
}
}
}

A couple of remarks: including and initializing the MIDI library will probably cause conflicts. The MIDI_Controller library uses the same interface to write to.
The MIDI Controller library includes a library for driving shift registers, so there's no need for Shifty.h.

You can use a mux to make buttons. Just use mux.pin(#) as the pin number.
If you have to read or write to the pin manually, you can use ExtIO::digitalRead(pin), ExtIO::digitalWrite(pin, state), etc.

tttapa commented 6 years ago

Do you have any idea what caused it to crash before?

userdsp commented 6 years ago

Thank you very much again! The crash was causing a loop in MyCCPWMFunction If there is // Command parameter 0=NOTE 1=CC 2=Toggle CC like here: http://www.notesandvolts.com/2016/07/arduino-midi-controller-multiplexers.html https://drive.google.com/file/d/0BwnVMB_6yujwR1dydVJ6MHJib2M/view i will be able to use all switches from push buttons. If not i must buy hardware toggle switches correct? The other library have different statements but i cant set pins manually and i cant use your banks witch works great!

tttapa commented 6 years ago

The crash was causing a loop in MyCCPWMFunction

I would be interested in you original code that caused the crash. It could reveal a bug in the library.

I'm not sure what you mean by the command parameter? If you want to use normal momentary push buttons, you can use the Digital class to send Note events, or the DigitalCC class to send Control Change events. If you have toggle switches, you can use the DigitalLatch class for Note events, or you could create your own control element for DigitalLatchCC (see wiki on how to do that).

userdsp commented 6 years ago

I want to use push buttons with will act like toggle buttons. First press = HIGH Second press = LOW Will be nice if you implemented in Control surface

tttapa commented 6 years ago

What software do you plan to use it with? All music programs I've come across do this toggling on the computer, not on the microcontroller.

The implementation is trivial, but I'm wondering if you really need it.
I'm currently finishing some other parts of the library, but reworking the Digital and DigitalLatch classes is on my list as well, I'll see what I can do.

Would you be willing to send me the code that caused the crash before?

userdsp commented 6 years ago

Ableton. I will post the code ASAP, because i'm not at my home, and my PC is shutted down.