Midi empfangen und verarbeiten

Hallo, ich versuche grade einen Midi-Controller zu bauen. Das Senden von Midi klappt auch (auch mit geflashtem USB Chip). Jetzt möchte ich aber MIDI empfangen, um einen Wert im Arduino zu ändern. Der RotaryEncoder im Scatch sendet Midi an den Rechner und ich kann damit z.B. Fader steuern. (in meinem Falle Ableton Live) Wenn man jetzt per Maus den Fader in Ableton bewegt, sendet Ableton den aktuellen Wert per Midi zurück zum Arduino. der soll ausgelesen werden und in den potiWert kopiert werden, damit der Arduino weiß, an welcher Stelle der Fader steht, und beim Drehen kein Sprung entsteht. Es sieht momentan so aus:

byte controlChange = 176; // Midi Kanal 1
byte controllerNummer[] = {20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36};
byte controllerWert[16];
byte controllerWertAlt[16];
int PotiWert[16];

byte RXcontrolchange;
byte RXcontrollerNummer;
byte RXcontrollerWert;
// encoder kram anfang
#define encoderPinA 2
#define encoderPinB 3
volatile int encoderPos = 0;  // a counter for the dial
unsigned int lastReportedPos = 1;   // change management
static boolean rotating=false;      // debounce management
boolean A_set = false;            
boolean B_set = false;
// encoder kram ende


void setup() { 
   pinMode(encoderPinA, INPUT); 
  pinMode(encoderPinB, INPUT); 
 
  digitalWrite(encoderPinA, HIGH);  
  digitalWrite(encoderPinB, HIGH);  
 
  attachInterrupt(0, doEncoderA, CHANGE); 
  attachInterrupt(1, doEncoderB, CHANGE); 
 
  Serial.begin(9600);  
}
 
void loop()
{ 
  checkMIDI();           // MIDI WIRD ABGEFRAGT
  rotating = true;  
 
  if (lastReportedPos != encoderPos)
  {
    if (encoderPos>126) encoderPos=126; 
    if (encoderPos<=0) encoderPos=0;
    sendeMIDI(controlChange,1,encoderPos);
    lastReportedPos = encoderPos;
  }
   if (encoderPos != RXcontrollerWert) encoderPos = RXcontrollerWert;   // Empfangener Wert wird übergeben
   lastReportedPos = encoderPos;  
}
 
// Interrupt on A changing state


void doEncoderA()
{
  if ( rotating ) delay (1);  // wait a little until the bouncing is done
  if( digitalRead(encoderPinA) != A_set ) {  // debounce once more
    A_set = !A_set;
    // adjust counter + if A leads B
    if ( A_set && !B_set ) 
      encoderPos += 1;
    rotating = false;  // no more debouncing until loop() hits again
  }
}
 
// Interrupt on B changing state, same as A above
void doEncoderB(){
  if ( rotating ) delay (1);
  if( digitalRead(encoderPinB) != B_set ) {
    B_set = !B_set;
    //  adjust counter - 1 if B leads A
    if( B_set && !A_set ) 
      encoderPos -= 1;
    rotating = false;
  }
}
void sendeMIDI(byte statusByte, byte dataByte1, byte dataByte2) {
 Serial.write(statusByte);
 Serial.write(dataByte1);
 Serial.write(dataByte2);

}

void checkMIDI(){
  do{
    if (Serial.available()){
      RXcontrolchange = Serial.read();//read first byte
      RXcontrollerNummer = Serial.read();//read next byte
      RXcontrollerWert = Serial.read();//read final byte
    }
  }
  while (Serial.available() > 2);//when at least three bytes available
}

Leider funktioniert es so nicht, und ich bekomme nur wert 1 raus beim Encoder drehen.
Hat jemand eine Idee?

Gruß Florian

Hallo,

ich versuche mal die Frage zu übersetzen:

  • Du hast einen Arduino Uno ?

  • Auf dessen 16u2 hast du eine Midi Firmware geschrieben ? (Habe gestern erst in einem anderen Thread gelesen, dass es das gibt.)

  • Diese Midi Firmware funktioniert alleine ? Also wenn du irgendeinen Wert schickst ?

  • Und dieser Encoder Code funktioniert alleine, also ohne Midi ?

Ja, genau. Einen Uno.
Die Firmware habe ich auf den Chip geflashed, damit meldet sich der Uno als MIDI Device am Rechner an, man benötigt keinen Treiber.
Midi vom Uno zum Rechner funktioniert problemlos. Ich frage den Encoder ab und sende dann einen entsprechenden Midi Wert. von 0-127. Damit kann ich dann Fader steuern. Jetzt möchte ich aber, dass wenn ich am Rechner den Fader mit der Maus bewege, der Midi-Wert im Uno auch mit geändert wird, damit ich keine Sprünge bekomme. Also sowas: Am Encoder den wert auf 127 gestellt, dann mit der Maus den Fader nach unten bewegt, z.B. auf Wert 50. Das weiß der Uno aber nicht und sendet beim runterdrehen dann die 126 und nicht die 49.
Jetzt sendet mein Programm am Rechner aber beim Bewegen des Faders einen Midi wert zurück zum Uno mit genau dem aktuellen Fader-Wert. Und den möchte ich mit dem Uno verarbeiten, damit der Wert am Rechner und im Uno identisch sind.

Gruß

Ok, damit ist natürlich die serielle Ausgabe des Unos belegt und man kann auf diesem Wege keine Debugausgaben machen. Das ist der Nachteil an dieser "Lösung".

Man muss irgendeinen Weg finden zu schauen, ob und was der Uno empfängt. Ich nehme an eine zweite serielle Verbindung zum PC über SoftwareSerial und einen FTDI-Adapter hast du nicht zufällig ?

Ansonsten störe ich mich an diesem Teil im Code

void checkMIDI(){
  do{
    if (Serial.available()){
      RXcontrolchange = Serial.read();//read first byte
      RXcontrollerNummer = Serial.read();//read next byte
      RXcontrollerWert = Serial.read();//read final byte
    }
  }
  while (Serial.available() > 2);//when at least three bytes available
}

Da steht die Abfrage auf > 2 erst nach dem Schleifendurchlauf. Wenn nur ein Byte angekommen ist, geht er da auch rein, liest es und in RXcontrollerNummer und RXcontrollerwert steht Quatsch.

Ein

while (Serial.available() > 2)
{
      RXcontrolchange = Serial.read();//read first byte
      RXcontrollerNummer = Serial.read();//read next byte
      RXcontrollerWert = Serial.read();//read final byte
}

erscheint mir irgendwie plausibler.

Weiterhin kann ich nicht erkennen, was mit RXcontrolchange usw. nach dem Einlesen sonst noch wo passiert.

damit ich keine Sprünge bekomme

In Cubase (verwende ich) kann man auf relative Verarbeitung umstellen, dann sind die Sprünge weg. Ist zwar schon ewig her dass ich das mal probiert habe, aber meine das ging allein in den Cubase Optionen.

Gibt das Ableton vielleicht auch her?

Hallo, erstmal danke für die Hinweise. Ich werde das umstellen der while Zeile probieren. Mit den zwei weiteren RX Variablen passiert noch nichts, die sind für weitere Controller vorgesehen.
Ja, bei Ableton gibt es auch relative Werte für MIDI, aber das wollte ich gerne umgehen, da die Auflösung der Abstufung darunter je nach Stellung sehr leidet.
Ich werde Montag an der Sache weiter arbeiten.
Eine zweite serielle Abfrage könnte ich einrichten. Werde probieren, das mal vorzubereiten.
Schönes Wochenende allen.
Gruß Florian

Hallo zusammen,
ich bin erfolgreich gewesen.
Den Teil mit dem übergeben des Wertes habe ich in die Midi-Abfrage mit reingepackt, denn er soll ja nur angleichen, wenn ein neuer Midi Wert angekommen ist.
Und die while Bedingung habe ich, wie ArduFE es schreib, davor gepackt. Schon funktioniert es, wie ich es mir vorstelle. Ableton übergibt den neuen Midi-Wert an den Arduino und setzt den Poti Wert auf neue Position.
Vielen Dank euch!
Gruß Florian

PS, der fertige Teil des MIDI Check sieht so aus

void checkMIDI(){

    while (Serial.available() > 2)
   {
      RXcontrolchange = Serial.read();
      RXcontrollerNummer = Serial.read();
      RXcontrollerWert = Serial.read();
         if (encoderPos != RXcontrollerWert) 
            {
            encoderPos = RXcontrollerWert;  
            lastReportedPos = RXcontrollerWert;  
            }
    
   }

}