MIDI senden: GO hängt sich auf

  • Ok, tut mir leid, da habe ich wohl einige Schritte in der Erzählung ausgelassen. Also:

    Ich will bestimmte Informationen aus Grandorgue (GO) über MIDI an den Arduino senden. Habe mich des Aufbaus und des Codes von Ulrich, dem Macher von Midistops, bedient. Er hat das auf seinem Blog so präsentiert. Solange es Standard-NoteOn/NoteOff Befehle anbelangt, funktioniert das auch super. Probleme habe ich beim Senden von Sysex aus GO an Arduino. Denn da kommt gefühlt Unsinn an.


    Ich möchte aus GO das Feld der Setzernummer an das MIDI-USB-Kabel senden.

    mps-orgelseite.de/home/index.php?attachment/2191/


    Wenn ich dort über Hairless Midi "reinhorche", sehe ich das folgende Nachricht gesendet wird. Und zwar immer gleich, egal welche Zahl eigentlich angezeigt wird.

    Code
    0x7d 0x1 0x0 0x1 0x0 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 

    Ich schaue mit dem Seriellen Monitor, was über die DIN-Buchse auf dem Arduino ankommt. Auch immer das gleiche, sieht aber so aus:

    mps-orgelseite.de/home/index.php?attachment/2190/


    Kommt mir komisch vor, also sende ich die Sysex Nachricht an LoopMidi.

    sysexLoopMIDI.PNG


    Wenn ich jetzt per Hairless schaue, was gesendet wird, sieht das schon anders aus. An den gelb markierten Stellen habe ich beim Setzer erst die Einer, dann die Zehner, dann die Hunderter hochgezählt.

    sysexhairlessloopMidi.PNG

    Weiterhin kurios: wenn ich als MIDI-Device das Kabel auswähle, kommt nur jeder zweite Klick als MIDI-Befehl an. Also einmal klicken und ich sehe so eine HEX-Aufzählung, nochmal klicken und es passiert nichts, wieder klicken und es kommt die HEX-Zeile. Wähle ich LoopMidi als Empfänger aus, wird bei jeder Aktivität eine Sysex Nachricht geschickt.


    Ich stelle mir nun die Frage, was muss ich tun, um die dreistellige Anzeige aus GO via Arduino auf ein Display zu transportieren. Denn genau dafür kann die Anzeige doch Sysex senden.

  • Ist es logisch, dass das SySex-Hauptwerk in einer ARDUINO-Libary erscheint?

    Kann man nicht auch 127 Noten mit 127 Velocity-Werten über CH-16 mit Note on/off senden?

    Genug Auswahl damit, oder?

    GO lässt bei genau diesem Feld ausschließlich Sysex zu. Sonst hätte ich vielleicht auch schon angefangen, zu improvisieren.

  • Kommen bei deinem Arduino Daten an? Bedenke auch dass Midi je nach Implementierung anders nummeriert ist. Je nach Bibliothek führt die Angabe von Kanal 1 zu Kanal 0 und 2 zu 1 und so weiter :)

    Wenn ich dir einen guten Ratschlag geben darf:

    Lasse es! Also die Kommunikation zwischen GO und Arduino. Das ist eine so komplexe Sache (wie du selber siehst) dass es selbst mich an die Grenzen der Verzweiflung gebracht hat. Spätestens wenn du mit Setzer arbeitest die nicht fix sind, sondern frei Programmiert werden können (also aktuelle Registrierung mit Set auf Platz 1 speichern) fängt der Spaß an. GO sagt dir per Midi das am Rechner der Button gewählt wurde. Nun weißt du aber erst einmal nicht was dort hinterlegt ist und so weiter.

    Ich würde dir den Ratschlag geben nur über deinen Spieltisch zu arbeiten. Bedeutet dein Arduino kümmert sich um alles und sendet nur noch was für Register gewählt werden sollen. Dann musst du zwar eine Logik schreiben welche die Daten speichert, aber das ist kein Problem. Beispiel du hast 30 Register und 10 Setzer. Dann erstellst du für jeden ein Array mit 30 Felder. Dort speicherst du einfach für jedes Register 0=Aus oder 1=An. Wenn du nun Taste 1 drückst, dann sendet dein Programm in einer Schleife einfach für jedes Register NoteON/OFF. Da deine Steuerung weiß was los ist kann sie auch selbstständig LED's schalten und ein Display ansteuern. GO müsste nur einmalig ein Signal senden wenn es gestartet wurde, damit dein Arduino den aktuellen Stand beim Start senden kann.

    Speichern ließen sich die Daten z.B im Flash (würde ich nicht machen weil Lebensdauer), oder auf einem SDKarten Modul für ein paar Cent. Diese Zweiwege Kommunikation und Synchronisation ist wirklich die absolute Königsdisziplin und für dich als Einsteiger wohl nicht machbar. Da verzweifeln echte Nerds. Ich habe dann auch aufgegeben weil es mir das nicht wert war. Ich will ja auch nicht während ich spiele an einem Monitor zusätzlich etwas machen.

    BTW Schau mal bei Google nach Arduino Sysex, da findest du viele Fragen, Probleme und Lösungen.

    Melodeum.de - Wissenswertes zu Harmonium

  • GO benutzt hier das Sysex-Nachrichtenformat von Hauptwerk. Das erste Byte 0x7d ist die feste Herstellerkennung, das darauffolgende Byte 0x01 ist der Code für eine LCD-Nachricht. Dann folgen zwei Bytes für die ID des anzusteuernden Panels (hier 0x01), und schließlich noch ein Byte für die Farbcodierung (hier 0x00). Danach kommt dann der Text als 32 Byte 7-bit ASCII. Nachzulesen ist das alles in der Bedienungsanleitung von Hauptwerk. Wenn man nur ein Panel selbst ansteuern will, kann man die ersten 5 Bytes der Nachricht auch ignorieren und nur die benötigten Bytes aus dem Text extrahieren. Diese lassen sich dann auch ganz einfach ausgeben, es handelt sich ja bereits um Text.

    Ich stelle mir nun die Frage, was muss ich tun, um die dreistellige Anzeige aus GO via Arduino auf ein Display zu transportieren. Denn genau dafür kann die Anzeige doch Sysex senden.

    Benutzt du weiterhin die Arduino Midi Library auf dem Controller? Falls ja, kannst du die Sysex-Nachrichten ganz einfach über einen Callback abfangen, und dann dein Display direkt mit dem empfangenen Text ansteuern.

    Dieses Beispiel schreibt die empfangene Setzer-Nummer auf drei 7-Segment-Anzeigen. Wenn du stattdessen ein LCD-Panel ansteuern willst, kannst du einfach dafür eine passende Library nehmen. Bei der Ansteuerung ist noch darauf zu achten, dass data hier am Anfang auch das Startbyte 0xF0 und am Ende das Abschlussbyte 0xF7 enthält. Hairless-Midi zeigt dir in den Debug-Nachrichten nur die Sysex-Nachricht zwischen Start- und Endbyte an, daher ist im Code der Index um eins höher als man vielleicht erwartet.

    Falls dir ein ausführlicheres Codebeispiel für den Arduino bei der Programmierung hilft, kannst du mal hier schauen. In MIDIControl.cpp findest du unter anderem den Code, den ich benutze um aus GO heraus die Setzer-Nummer mit einem Arduino auf einem 7-Segment-Panel anzuzeigen (allerdings versende ich in GO 16 Byte String Werte statt 32 Byte LCD Werte, das Prinzip ist aber das gleiche).

    Ich würde dir den Ratschlag geben nur über deinen Spieltisch zu arbeiten. Bedeutet dein Arduino kümmert sich um alles und sendet nur noch was für Register gewählt werden sollen. Dann musst du zwar eine Logik schreiben welche die Daten speichert, aber das ist kein Problem. Beispiel du hast 30 Register und 10 Setzer. Dann erstellst du für jeden ein Array mit 30 Felder. Dort speicherst du einfach für jedes Register 0=Aus oder 1=An. Wenn du nun Taste 1 drückst, dann sendet dein Programm in einer Schleife einfach für jedes Register NoteON/OFF. Da deine Steuerung weiß was los ist kann sie auch selbstständig LED's schalten und ein Display ansteuern. GO müsste nur einmalig ein Signal senden wenn es gestartet wurde, damit dein Arduino den aktuellen Stand beim Start senden kann.

    Ja, das kann man natürlich auch machen. Mir stellt sich allerdings die Frage, wieso es gerade für Programmiereinsteiger einfacher sein sollte gleich die ganze Setzerlogik selbst zu implementieren, anstatt einfach den internen Setzer von GO zu benutzen :) Der lässt sich über MIDI ja prinzipiell genauso ansteuern wie etwa die Registerschalter.

  • @ Terz

    Ja, genau. Soweit war ich im Grunde auch gekommen und habe nach einer Lösung gesucht, HEX in ASCII zu wandeln. Was bei meinen Versuchen mit der MIDI-Library ging, solange da kein "0x" o.ä. davor stand.

    @ Haralder

    Glaub mir, ich hab fast das gesamte Internet nach dieser Fragezerstellung zergoogelt :) Generell habe ich mein Projekt bislang, bis auf wenige Ausnahmen, nur anhand von Googeln umgesetzt. Und ich hätte die Aufgabe als absolut lösbar eingeordnet, weil es von den GO-Entwicklern ja so gedacht ist, zudem Sysex ein MIDI-Standard ist und zudem auch von verschiedenen Arduino-Librarys unterstützt wird. Außerdem hat der Nutzer ulliken66 das ja schon genau so mittels Arduino umgesetzt und auf seinem Blog gezeigt. Ich wollte halt das Rad nicht neu erfinden, sondern GO alles machen lassen und es dabei nur über meinen Spieltisch ansteuern und ggf. Informationen über Displays oder LEDs anzeigen lassen.

    Das Ganze selbst du machen hatte ich zum Schluss auch erwogen. Immerhin hat Sabine es auch so umgesetzt und das in ihren Videos dargestellt. Das wäre ja eine Vorlage gewesen.

    techlit

    Vielen Dank! Das werde ich gleich heute Abend testen!!! Sevseg ist eigentlich auch meine präferierte Lösung, habe nur mit LCD angefangen, weil ich erst einmal einen funktionierenden Weg nachbauen wollte, ehe ich abwandele.

  • Deine Aussagen sind etwas ungenau, das macht es etwas schwierig. Hex ist ja auch ascii, du meinst wahrscheinlich Hex-Darstellung (Ascii) in Dezimal-Darstellung (Ascii). Die Daten liegen wahrscheinlich in einem Byte-Array, wo du das 0x überspringen kannst.

  • Mir stellt sich allerdings die Frage, wieso es gerade für Programmiereinsteiger einfacher sein sollte gleich die ganze Setzerlogik selbst zu implementieren, anstatt einfach den internen Setzer von GO zu benutzen

    Ganz einfach, weil du bei der Zweiwege Lösung neben einer Setzer Logik im Arduino zusätzlich den Abgleich mit GO über ein komplexes Protokoll wie Midi abwickeln musst. Beide Teile müssen ja die identischen Informationen haben. Bei einem Spieltisch der einfach nur Taster hat ist das noch ganz simpel. Midisignal für den zugewiesenen Setzer schicken und fertig. Aber wenn der Spieltisch dann auch signalisieren soll welche Register nun aktiv sind (was erst einmal nur GO weiß), dann muss deine Steuerung irgendwie an die bei GO hinterlegten Daten kommen und abgleichen.

    Midi ist eigentlich ein sehr simples Protokoll, aber trotzdem nicht einfach zu handhaben. Vor allem muss es ja auch zuverlässig funktionieren und da ist die Master (Arduino) Slave (GO) am einfachsten.

    Melodeum.de - Wissenswertes zu Harmonium

  • Da ich schon viele Jahre nicht mehr in C programmiert habe, war es mir ein Vergnügen, so ein kleines Converter-Programm ohne Bibliotheks-Funktionen zu schreiben. Falls du so was noch brauchst (Hex zu Dezimal), kann ich den Code gerne weitergeben.

  • zudem Sysex ein MIDI-Standard ist und zudem auch von verschiedenen Arduino-Librarys unterstützt wird

    Kannst du vieleicht auf deinem Arduino mal das folgende Programm ausführen und schauen ob und was dieser dann bei Signale von GO auswirft?


    Selber senden kann man ja ganz gut mit

    Zum convertieren müsste es doch auch fertige Lösungen geben. Ich persönlich würde aber eher bei Midi in Reinform bleiben.

    Melodeum.de - Wissenswertes zu Harmonium

  • Ganz einfach, weil du bei der Zweiwege Lösung neben einer Setzer Logik im Arduino zusätzlich den Abgleich mit GO über ein komplexes Protokoll wie Midi abwickeln musst. Beide Teile müssen ja die identischen Informationen haben. Bei einem Spieltisch der einfach nur Taster hat ist das noch ganz simpel. Midisignal für den zugewiesenen Setzer schicken und fertig. Aber wenn der Spieltisch dann auch signalisieren soll welche Register nun aktiv sind (was erst einmal nur GO weiß), dann muss deine Steuerung irgendwie an die bei GO hinterlegten Daten kommen und abgleichen.

    Diesen Gedanken verstehe ich ehrlich gesagt noch nicht, aber vielleicht reden wir auch über verschiedene Dinge. Wieso braucht es überhaupt eine Setzer-Logik im Arduino? Der Arduino, der meinen Spieltisch kontrolliert, speichert zum Beispiel gar keinen eigenen Zustand sondern zeigt einfach immer nur das an, was GO per Midi übermittelt (also vor allem den Zustand der Setzerschalter, die Setzernummer und die Registerschalter). GO schickt dabei die Midi-Nachrichten immer dann, wenn sich der Zustand eines Schalters in GO ändert, unabhängig davon wie der Schalter betätigt wurde. Es ist also egal ob ich ein Register mit der Maus einschalte, oder mit dem physischen Schalter (d.h. per noteOn-Nachricht vom Arduino an GO). In beiden Fällen schickt GO eine noteOn/noteOff-Nachricht zurück an den Arduino, wodurch die Led des betreffenden Registerschalters ein- bzw. ausgeschaltet wird. Ich muss mir im Arduino gar nicht merken, welche Register gerade ausgewählt sind, sondern einfach nur auf die eingehenden Midi-Nachrichten reagieren. Wenn ich den Setzer weiter schalte, schickt GO nicht nur per Sysex-Nachricht die neue Setzer-Nummer, sondern automatisch auch alle noteOn/noteOff-Nachrichten für diejenigen Register, die sich geändert haben. Eine Synchronisierung zwischen dem Arduino und GO, wie du sie ansprichst, ist somit eigentlich nicht nötig (oder ich verstehe nicht, was du damit meinst). Der Arduino muss einfach immer nur den Zustand ausgeben, den GO per Midi meldet. Mit den Callback-Handlern der Arduino Midi Library funktioniert das auch ganz wunderbar und ergibt schön einfachen Code :).

  • In beiden Fällen schickt GO eine noteOn/noteOff-Nachricht zurück an den Arduino, wodurch die Led des betreffenden Registerschalters ein- bzw. ausgeschaltet wird.

    Okay, dann muss man es wirklich nicht machen. Hat sich das mal geändert? Ich weiß noch damals (zwei jahre oder so) habe ich nicht diese Signale rausbekommen. Kann aber auch durchaus ein Fehler von mir gewesen sein. Ich würde trotzdem eher nicht Sysex nutzen sondern pures Midi. Ist einfacher weil man sich beim auslesen mit MIDIUSB das konvertieren spart.

    Melodeum.de - Wissenswertes zu Harmonium

  • Okay, dann muss man es wirklich nicht machen. Hat sich das mal geändert? Ich weiß noch damals (zwei jahre oder so) habe ich nicht diese Signale rausbekommen.

    Ich nutze GO in Version 3.9.0, und da ist das Verhalten wie beschrieben. Mit früheren Versionen habe ich keine Erfahrung, daher kann ich nicht sagen ob sich das irgendwann mal geändert hat.

    Ich würde trotzdem eher nicht Sysex nutzen sondern pures Midi. Ist einfacher weil man sich beim auslesen mit MIDIUSB das konvertieren spart.

    Für Labels wie z.B. die Setzernummer geht das leider nicht, weil man die in GO nur per Sysex versenden kann. Für normale Schalter ist pures Midi natürlich die bessere Wahl.

  • Für Labels wie z.B. die Setzernummer geht das leider nicht, weil man die in GO nur per Sysex versenden kann.

    Ich bin damit nicht so vertraut. Diese Sysex sind aber statisch wenn man es einmal eingerichtet hat? Dann würde es ja reichen den Hex einfach zu prüfen um was es sich handelt ohne ihn umwandeln zu müssen oder?

    Melodeum.de - Wissenswertes zu Harmonium

  • Ich bin damit nicht so vertraut. Diese Sysex sind aber statisch wenn man es einmal eingerichtet hat? Dann würde es ja reichen den Hex einfach zu prüfen um was es sich handelt ohne ihn umwandeln zu müssen oder?

    Was meinst du mit "umwandeln"? Die Sysex versenden die Werte der Labels als Text, zusammen mit ein paar HW-spezifischen Steuerinformationen. In dem Beispiel wird die Setzernummer also nicht als Zahl, sondern als ASCII-codierter Text übertragen. Wenn man die Steuerinformationen von der Sysex-Nachricht abschneidet, kann man sie dann z.B. einfach auf ein LCD-Panel ausgeben.

  • Da ich schon viele Jahre nicht mehr in C programmiert habe, war es mir ein Vergnügen, so ein kleines Converter-Programm ohne Bibliotheks-Funktionen zu schreiben. Falls du so was noch brauchst (Hex zu Dezimal), kann ich den Code gerne weitergeben.

    Das würde mich in der Tat sehr interessieren!

    Haralder

    Es ist wie techlit schreibt. Ich wollte das Rad selbstverständlich nicht neu erfinden. GO hat alle Funktionen, die ich entweder per Arduino bediene oder aber den Arduino über einen Zustand informieren lasse. Bzgl. Register richte ich es z.B. so ein (Code bereits fertig), dass jeder Registerzug beim Betätigen einen NoteOn/NoteOff-Befehl sendet, egal ob das Register manuell durch mich oder durch eine Setzereinstellung an-/abgewählt wurde. Der Arduino nimmt dieses Signal zum Anlass, eine LED im entsprechenden Registerschalter am Spieltisch zu schalten. So habe ich immer den Überblick am Spieltisch, welche Register grad "an" sind. Daher auch der Tanz mit der Setzerplatz-Anzeige. Ich will alles am Spieltisch sehen und bedienen, also genau wie du auch geraten hast :) Das mit Sysex kam vor ein paar Jahren mal als neue Anforderung. Gelesen habe ich es in der Dokumentation von GO, dass das geht.

    Ich bin damit nicht so vertraut. Diese Sysex sind aber statisch wenn man es einmal eingerichtet hat? Dann würde es ja reichen den Hex einfach zu prüfen um was es sich handelt ohne ihn umwandeln zu müssen oder?

    Was meinst du mit statisch? Bei jeder Änderung an der Nummer (egal ob Einer, Zehner, Hunderter) wird eine neue Sysex Nachricht gesendet. Siehe Screenshot von mir weiter oben, wo ich die Änderungen gelb markiert hatte.

    Ich fange jetzt mal das Testen mit den verschiedenen hier gemachten Vorschlägen an und melde mich wieder. Auf jeden Fall schon einmal vielen Dank für die viele Hilfe, ihr seid super! Wenn dann am Ende (hoffentlich) eine Lösung steht, würde ich die in meinem Erfahrungsbericht mit aufführen, logischerweise mit euch als Urhebern.

  • Das würde mich in der Tat sehr interessieren!

    Ich find's grad nicht mehr! Ist nicht in der Projekt-History gelandet. Aber es wird auffindbar sein ;)

    Edit:
    Im falschen Ordner gelandet... Beim markieren als Code sind die Einrückungen verloren gegangen, aber zum Anschauen reicht es ja.
    Der Code kommt ohne Bibliothek aus, also ein reines C-Programm.

    getValFromHexChar wandelt ein einzelnes Hex-Zeichen in einen binären Wert. Erlaubt sind 0..9 und a..f oder A..F.

    toAscii wandelt einen binären Wert in eine 3-stellige Dezimalzeichenkette. Der Parameter fillZeroes gibt an, ob führende Nullen verwendet werden sollen, also z.B. "001". Der Code funktioniert für 8-Bit-Werte (0x00 - 0xFF).

    Das Hauptprogramm wandelt den Beispielwert "0x70" in eine Dezimalzahl als Zeichenkette "112".

    Das "0x" wird bei der Verarbeitung überlesen, der Code geht also von einem Hex-Wert aus.

    Zwecks Übersichtlichkeit habe ich Speicherfreigaben oder Fehlerprüfung beim zu übergebenden Wert weggelassen.

  • Ich kenne mich auf dem Arduino nicht aus, aber falls eine Bibliothek zur Verfügung steht wie in C,

    dann kann man toAscii so ersetzen:

    Code
    #include <stdlib.h>
    ...
    char ascii[5];
    _itoa_s(intVal, &ascii[0], 5, 10);