DIY MIDI Footcontroller mit Arduino

Oh Gott, wie peinlich, es lag tatsächlich an der falschen Verkabelung! Danke jedenfalls. Mittlerweile habe ich 9 Taster angeschlossen (solche hier: http://www.reichelt.de/Drucktaster-...=2&ARTICLE=19988&GROUPID=3277&artnr=T+250A+WS ), die ich jeweils mit GND und direkt (ohne zusätzliche Widerstände) per INPUT_PULLUP mit den digitalen Pins meines Arduino Pro Micro (so einer hier: https://www.sparkfun.com/products/12640 ) verbunde habe.

Ich habe den Code von Götz Müller-Dürholt etwas angepasst und bekomme in der Arduino-Software im Seriellen Monitor auch angezeigt, dass etwas passiert, Jedoch habe ich 2 Probleme:

Zum einen sieht es so aus, als würden die Buttons die ich habe meistens 2 Signale von sich geben, beim Drücken und beim Loslassen. Wenn nicht sogar noch mehr.

Außterdem scheitere ich momentan daran, z.B. über Hairless-Midi und LoopMidi meinen Controller auch in einer DAW zu nutzen. Wenn Hairless Midi läuft (manchmal aus irgendwelchen Gründen tut es das nicht) und ich die Buttons drücke, kommen immer solche Fehlermeldungen:

+9.014 - Warning: got a status byte when we were expecting 2 more data bytes, sending possibly incomplete MIDI message 0x81
+9.014 - Serial In: Ch 2: Note %2 off velocity %3
+9.014 - Serial In: Ch 1: Note 40 on velocity 127
+9.014 - Warning: got a status byte when we were expecting 1 more data bytes, sending possibly incomplete MIDI message 0x90

Wähle ich bei MIDI OUT Microsoft GS Wavetable Synth aus, dann höre ich ein Piano, mit recht großer Latenz (grob geschätze halbe Sekunde).
Setze ich MIDI OUT und MIDI IN auf loopMIDI Port, den ich zuvor gestartet habe, empfange ich in meiner DAW (in meinem Fall Cakewalk Sonar Platinum) leider nichts.

Hier ist auch einmal der Code, den ich als absoluter Laie etwas angepasst habe.

Für Hilfe wäre ich wirklich mehr als dankbar!




int button2 = LOW;
int button2Old = LOW;
int button3 = LOW;
int button3Old = LOW;
int button4 = LOW;
int button4Old = LOW;
int button5 = LOW;
int button5Old = LOW;
int button6 = LOW;
int button6Old = LOW;
int button7 = LOW;
int button7Old = LOW;
int button8 = LOW;
int button8Old = LOW;
int button9 = LOW;
int button9Old = LOW;
int button10 = LOW;
int button10Old = LOW;


void setup() {
Serial.begin(9600);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
}

void loop(){
button2 = digitalRead(2);

if (button2 == HIGH && button2Old == LOW) {
Serial.write(144); // 1001 0000 = Note On Kanal 1
Serial.write(36); //Note C1
Serial.write(127);
button2Old = button2;
}
if (button2 == LOW && button2Old == HIGH) {
Serial.write(144); // 1001 0000 = Note On Kanal 1
Serial.write(36); //Note C1
Serial.write(0-127);
button2Old = button2;
}

button3 = digitalRead(3);

if (button3 == HIGH && button3Old == LOW) {
Serial.write(144);
Serial.write(38);
Serial.write(127);
button3Old = button3;
}
if (button3 == LOW && button3Old == HIGH) {
Serial.write(144);
Serial.write(38);
Serial.write(0-127);
button3Old = button3;
}

button4 = digitalRead(4);

if (button4 == HIGH && button4Old == LOW) {
Serial.write(144);
Serial.write(40);
Serial.write(127);
button4Old = button4;
}
if (button4 == LOW && button4Old == HIGH) {
Serial.write(144);
Serial.write(40);
Serial.write(0-127);
button4Old = button4;
}

button5 = digitalRead(5);

if (button5 == HIGH && button5Old == LOW) {
Serial.write(144);
Serial.write(41);
Serial.write(127);
button5Old = button5;
}
if (button5 == LOW && button5Old == HIGH) {
Serial.write(144);
Serial.write(41);
Serial.write(0-127);
button5Old = button5;
}

button6 = digitalRead(6);

if (button6 == HIGH && button6Old == LOW) {
Serial.write(144);
Serial.write(43);
Serial.write(127);
button6Old = button6;
}
if (button6 == LOW && button6Old == HIGH) {
Serial.write(144);
Serial.write(43);
Serial.write(0-127);
button6Old = button6;
}

button7 = digitalRead(7);

if (button7 == HIGH && button7Old == LOW) {
Serial.write(144);
Serial.write(45);
Serial.write(127);
button7Old = button7;
}
if (button7 == LOW && button7Old == HIGH) {
Serial.write(144);
Serial.write(45);
Serial.write(0-127);
button7Old = button7;
}

button8 = digitalRead(8);

if (button8 == HIGH && button8Old == LOW) {
Serial.write(144);
Serial.write(47);
Serial.write(127);
button8Old = button8;
}
if (button8 == LOW && button8Old == HIGH) {
Serial.write(144);
Serial.write(47);
Serial.write(0-127);
button8Old = button8;
}

button9 = digitalRead(9);

if (button9 == HIGH && button9Old == LOW) {
Serial.write(144);
Serial.write(48);
Serial.write(127);
button9Old = button9;
}
if (button9 == LOW && button9Old == HIGH) {
Serial.write(144);
Serial.write(48);
Serial.write(0-127);
button9Old = button9;
}

button10 = digitalRead(10);

if (button10 == HIGH && button10Old == LOW) {
Serial.write(144);
Serial.write(50);
Serial.write(127);
button10Old = button10;
}
if (button10 == LOW && button10Old == HIGH) {
Serial.write(144);
Serial.write(50);
Serial.write(0-127);
button10Old = button10;
}
}
 
Hi,
dass die buttons mehrere Signale geben ist völlig normal. Das Zauberwort heißt hier debounce. Da ist bei den Arduino Beispielen schon was dabei, wie man das macht. Ansonsten gibt es für den Arduino auch mehrere Button Libraries, die das mehr oder weniger automatisch machen.
Zum den Problemen mit den Midi Messages möchte ich noch einmal auf die Midi Library verweisen, die das Leben wesentlich vereinfacht und vielleicht auch deine Probleme Lösen kann.

Viele Grüße
Bastian
 
Ist das Absicht, dass du jedes mal bei button low 0-127 sendest als drittes Byte?
 
Weil ich noch auf die Taster warte habe ich zumindest mal die Beinchen angelötet und probiert die Werte eines Potis einzulesen und dann als Midi auszugeben.
Der Arduino läuft also und macht soweit was er soll :great:
2016-02-12 10.39.03.jpg
 
OK ich habe den Code soweit hingekriegt:

// simple switch MIDI trigger
boolean buttonLast[9];
const byte switchPin[] = {2,3,4,5,6,7,8,9,10}; // the 9 pins to use
const byte noteToSend [] = {36,38,40,41,43,45,47,48,50}; // notes to play for each pin
boolean button;

void setup() {
Serial.begin(115200); // Using Hairless at the default speed
for(int i=0; i< 10; i++){
pinMode(switchPin, INPUT_PULLUP);
buttonLast = HIGH; // assume button not pressed at start
}
}

void loop(){
for(int i =0; i<9; i++){
button = digitalRead(switchPin);
if (button == HIGH && buttonLast == LOW) {
sendNote(144,noteToSend,127);
buttonLast = button;
}
if (button == LOW && buttonLast == HIGH) {
sendNote(144,noteToSend,0);
buttonLast = button;
}
}
}
void sendNote(byte message, byte note, byte velocity){
Serial.write(message);
Serial.write(note);
Serial.write(velocity);
delay (20);
}

Nur habe ich jetzt unerwartet ein Problem mit der Latenz. Ich benutze Windows 10, Cakewalk Sonar PLatinum und habe ein Focusrite Scarlett 2i4 Audio Interface. Latenzen sind da normalerweise kein Problem.

Mit meinem USB Midi Masterkeyboard habe ich da auch keine Probleme, mit meinem selbstgebauten Controller allerdings schon.

Wie kann das sein? Also ich starte zunächst LoopMidi, erstelle da einen neuen Port, öfnne Hairless Midi, stelle meinen Controller ein und MIDI IN und MIDI OUT auf den LoopMidi Port, welchen ich dann in Cakewalk Sonar auswählen kann, aber nur da habe ich eine gewaltige Latenz.



Hat irgendjemand eine Idee?
 
Keine Ahnung, ob das die Latenz auslöst, aber Du setzt den MIDI Port auf eine Geschwindigkeit von 115200. Das ist zu hoch. MIDI arbeitet mit 31250 baud. Probier es mal damit.

Ausserdem würde ich das Delay, das lediglich dazu dient flattern der Button-Stati zu unterdrücken aus der sendNote() Methode rausnehmen und ans Ende von loop() setzen. Ein Delay von 10 sollte auch reichen.
 
  • Gefällt mir
Reaktionen: 1 Benutzer
Danke, habe beides probiert, es hilft aber beides nichts...
Sonst noch eine Idee?
 
@AndiH1213 : Ich würde auch empfehlen dir mal die MIDI-Library anzusehen (obwohl es @Direwolf schon mehrfach erfolglos in den Raum geworfen hat ;)). Das nimmt einem schonmal vieles ab was schiefgehen kann. Schau dir mal die Beispiele bei Github an (zum Beispiel das hier).

Kann es sein dass der Editor Array-indizes geschluckt und als BB-Code interpretiert hat? (das würde zumindest deren Abwesenheit und die kursive Schrift erklären... :gruebel:). Für Quellcode gibts hier übrigens eine Code Umgebung (Im Editor "Einfügen" und dann "Code"). Das macht das ganze deutlich lesbarer und es wird nichts fälschlich als BB-Code interpretiert.
 
Code:
// simple switch MIDI trigger
boolean buttonLast[9];
const byte switchPin[] = {2,3,4,5,6,7,8,9,10}; // the 9 pins to use
const byte noteToSend [] = {36,38,40,41,43,45,47,48,50}; // notes to play for each pin
boolean button;

void setup() {
Serial.begin(115200); // Using Hairless at the default speed
for(int i=0; i< 10; i++){
pinMode(switchPin[i], INPUT_PULLUP);
buttonLast[i] = HIGH; // assume button not pressed at start
   }
}

void loop(){
  for(int i =0; i<9; i++){
   button = digitalRead(switchPin[i]);
    if (button == HIGH && buttonLast[i] == LOW) {
      sendNote(144,noteToSend[i],127);
      buttonLast[i] = button;
      }
    if (button == LOW && buttonLast[i] == HIGH) {
      sendNote(144,noteToSend[i],0);
      buttonLast[i] = button;
     }
  }
}

void sendNote(byte message, byte note, byte velocity){
Serial.write(message);
Serial.write(note);
Serial.write(velocity);
delay (20);
}

Ok hier nochmal der Code. Ich glaube nicht, dass es daran liegt, er macht ja eigenttlich auch, was er soll, nur mit einer störenden Latenz.
Oh mann, ich würde das Gerät echt gerne benutzen, aber hab immer noch keine Ahnung, wie ich die Latenz loswerde...
 
Hast du wegen der Latenz noch etwas heraus gefunden?

Bei mir ging es leider noch nicht wirklich weiter.
Die Teile sind zwar mittlerweile alle da, aber ich kam noch nicht wirklich dazu.
Aber man muss sagen ich habe echt recht lange gebraucht um zu verstehen, wie die 6 Anschlüsse des Tasters funktionieren :redface:
 
Das mit der Latenz habe ich nun fast hingekriegt. D.h. eine minimale Latenz merke ich noch, aber das Hauptproblem war folgendes:

Die FTDI-Treiber für den Arduino sind standardmäßig auf 16ms gesetzt. Dies kann man jedoch ändern, indem man z.B. in der Datei ftdiport.inf den Eintrag für die Latenz auf beispielsweise 2ms (1ms wird nicht empfohlen) ändert, BEVOR man den Treiber installiert. Die Datei fand sich bei mir in dem entpackten Treiber-Ordner.

Nun habe ich aber ein neues Problem:

Ich möchte den Mobius VST Looper mit dem Arduino steuern. Das funktioniert auch erstmal ganz gut, ich kann alle meine Buttons bestimten Funktionen zuweisen.

Drücke ich jedoch RECORD (mithilfe eines zugewiesenen Buttons), so nimmt es nur für einen sehr kurzen Moment auf, so als würde nach etwa einer Sekunde der Button noch einmal betätigt. Dem ist aber nicht so und das würde ich auch ausschließen. Mit meinem Midi Keyboard funktioniert das einwandfrei.

Was mache ich hier falsch? (Zur Erinnerung: Ich bin absolut neu im Programmieren und habe das nur mit jeder Menge Hilfe hinbekommen)
 
Hast du mal ausgelesen, Welche Befehle geschickt werden? Vielleicht wird ja wirklich ein 2. geschickt.
 
Da ich heute krank war und somit zu Hause saß kam ich endlich dazu etwas zu basteln.

Also alle Taster an Kabel gelötet und mal ins Breadboard gesteckt.
Vielleicht hätte ich die Kabel kürzer wählen können. ;)

2016-02-23 21.10.54.jpg

Ich hatte versucht die MIDI Library zu verwenden, aber er hat bei mir genörgelt, dass er einen Befehl nicht kennt. Ich hatte keine Lust lange zu suchen, also sende ich die Befehle nun doch direkt.
Zuerst hatte ich kleine Probleme, da Arduino beim Index von Arrays bei anfängt. Ich hatte in letzter zeit immer Matlab verwendet, das startet mit 1. Aber nach etwas Zeit habe ich den Fehler entdeckt.
Es klappt schon soweit, dass man mit den 5 Tastern 5 PC Befehle senden kann.


Code:
int button[] = {LOW, LOW, LOW, LOW, LOW};
int buttonOld[] = {LOW, LOW, LOW, LOW, LOW};

int stdStatusByte = 193; //PC on channel 1
int dataBytePC[]  {1,2,3,4,5};


void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT);
  pinMode(3, INPUT);

}
void loop() {

  //check all buttons
  for(int i=0; i<=4; i++){
    button[i]=digitalRead(i+2);
    programChange(i, stdStatusByte, dataBytePC[i]);
  }

}

void programChange(int buttonNumber,int  statusByte,int dataByte){
   if(button[buttonNumber] == HIGH && buttonOld[buttonNumber] == LOW) {
      Serial.write(statusByte);
      Serial.write(dataByte);
     
   }
  buttonOld[buttonNumber]=button[buttonNumber];
  delay(10);
}
 
So nun habe ich auch mal die MIDI Buchse angelötet und gecheckt und siehe da es funktioniert.
Natürlich habe ich zuerst vergessen die baud rate richtig einzustellen :redface:

Auch der Teil um den Looper zu steuern funktioniert und auch das umschalten zwischen beiden Modi geht einwandfrei.
Ich habe auch zum Glück keine Probleme mit Latenzen :)

Ich bin gerade hellauf begeistert, es gab weniger Probleme als gedacht.

Am Wochenende werde ich mich dann wohl mal dran setzen das Ding ins Gehäuse einzubauen.


Code:
int button[] = {LOW, LOW, LOW, LOW, LOW, LOW};
int buttonOld[] = {LOW, LOW, LOW, LOW, LOW, LOW};

int statusBytePC = 193; // PC at channel 1
int dataBytePC[]  {0,1,2,3,4}; //different PC values for the switches


int statusByteLooper=176; //CC at channel 1
int dataByteLooper[]={88,89,93,90,92}; // CC values for Looper Mode, all other values are the same for
                                       // different Looper buttons


int Looper=0;  //variable for looper mode

void setup() {
  Serial.begin(31250); //MIDI at standard baud rate
  for(int i=2; i<=7; i++){   //initialize pins in input mode
      pinMode(i, INPUT);
  }


}
void loop() {
   //check if switch is in looper mode or not
   button[5]=digitalRead(7);
   
   if(button[5] == HIGH && buttonOld[5] == LOW && Looper==0) {
        Looper=1;
        buttonOld[5]=button[5];
        delay(10);
       
         
   } else if(button[5] == HIGH && buttonOld[5] == LOW && Looper==1){
        Looper=0;
        buttonOld[5]=button[5];
        delay(10);
   } else{
    buttonOld[5]=button[5];
   }

   //PC mode
   if(Looper==0){
        for(int i=0; i<=4; i++){
        button[i]=digitalRead(i+2);
        programChange(i, statusBytePC, dataBytePC[i]);
        }
   }
   //Looper mode
   if(Looper==1){
        for(int i=0; i<=4; i++){
        button[i]=digitalRead(i+2);
        Looperfunction(i, statusByteLooper, dataByteLooper[i]);
        }
   }


}

void programChange(int buttonNumber,int  statusByte,int dataByte){
   if(button[buttonNumber] == HIGH && buttonOld[buttonNumber] == LOW) {
      Serial.write(statusByte);
      Serial.write(dataByte);
     
   }
  buttonOld[buttonNumber]=button[buttonNumber]; //debounce
  delay(10);
}

void Looperfunction(int buttonNumber, int statusByte, int dataByte){
  if(button[buttonNumber] == HIGH && buttonOld[buttonNumber] == LOW){
    //Looper always needs 4 CCs for control
    Serial.write(statusByte);
    Serial.write(99);
    Serial.write(125);

    Serial.write(statusByte);
    Serial.write(98);
    Serial.write(dataByte);

    Serial.write(statusByte);
    Serial.write(6);
    Serial.write(0);

    Serial.write(statusByte); 
    Serial.write(38);
    Serial.write(1);  //value 1 on press

   
  }

  if(button[buttonNumber]==LOW && buttonOld[buttonNumber]==HIGH){
    Serial.write(statusByte);
    Serial.write(99);
    Serial.write(125);

    Serial.write(statusByte);
    Serial.write(98);
    Serial.write(dataByte);

    Serial.write(statusByte);
    Serial.write(6);
    Serial.write(0);

    Serial.write(statusByte);
    Serial.write(38);
    Serial.write(0);  //value 1 on release
  }
  buttonOld[buttonNumber]=button[buttonNumber]; //debounce
  delay(10);
}


Falls es jemanden interessiert kann ich dann auch einen Bauplan erstellen :)

Ich werde noch versuchen LEDs einzubauen, damit man weiß, was gerade passiert, so ist es glaube ich etwas unübersichtlich, aber die LEDs sind noch immer unterwegs.
 
Auch wenn das Ganze langsam in einen Monolog ausartet mache ich mal weiter :D

Heute habe ich das Gehäuse gebohrt in den Arduino und die Plantinenverbindung angelötet.
Fehlt noch die Stromversorgung und die MIDI Buchse. Über einen USB Anschluß könnte ich auch mal nachdenken, falls ich mal was umprogrammieren möchte.
Morgen werde ich die Kabel noch ordentlich verlegen und ein paar noch auf die richtige Länge kürzen um etwas Ordnung zu schaffen.
Dan fehlen nur noch die LEDs, aber die Sendung lässt auf sich warten.

2016-02-27 18.20.38-1.jpg 2016-02-27 18.20.48.jpg 2016-02-27 20.42.02.jpg
 
  • Gefällt mir
Reaktionen: 4 Benutzer
Nachdem ales funktioniert hatte wollte ich noch die MIDI Buchse und die Stromversorgung anlöten.
Dabei ist irgendwie die Masseverbindung im Platinenstecker kaputt gegangen und deswegen hat der Arduino Random MIDI befehe geschickt.
Hat mich fast eine Woche gekostet das zu entdecken, auch weil ich den Arduino bei der Suche irgendwie getötet hatte :redface:

Nun funktioniert aber alles und die LEDs sind auch da und montiert. Es gibt nun eine LED, die zeigt, ob man den Looper steuert oder PC Befehle sendet und jeweils eine die den ausgewählten Sound anzeigt
.2016-03-05 15.20.18.jpg

Jetzt kommt irgendwann noch die Beschriftung und vieleicht wird die Kiste noch angemalt.
 
Ich würde noch die Zahnscheiben innen montieren und die Unterlegscheiben, die momentan vermutlich innen montiert sind, dafür nach außen packen :)
 
Innen sind zur Zeit so unansehnliche weiße Plastik Unterlegscheiben, die dabei waren.
Ich werde mir noch welche aus Metall besorgen. Aber hatte gerade keine da.
 
Ich breche mir gerade einen ab mit der Baudrate und dem FTDI Treiber.
Ich verwende Midi OX und Midi Yok sowie den SpikenzieLabs Serial Midi Converter, um erstmal alles schön am PC sehen zu können.

Hat das jemand mit der Änderung bei "HKR,,"ConfigData",1,11,00,3F,3F......" hinbekommen?

AndiH1213: wenn du von Latenzproblemen schreibst, hast du somit das Baudratenproblem gelöst?
 
Ich habe gerade versucht, herauszufinden, was Midi OX und Yoke machen, aber ich habs nicht so wirklich kapiert, wofür das gut ist. :nix:
 

Ähnliche Themen


Unser weiteres Online-Angebot:
Bassic.de · Deejayforum.de · Sequencer.de · Clavio.de · Guitarworld.de · Recording.de

Musiker-Board Logo
Zurück
Oben