Jump to content

MIDI-Problem


Thomas
 Share

Recommended Posts

Hallo!

Nachdem nun das akute Hardware-Problem beseitigt ist (hoffentlich...) treten jetzt die Softwarefehler wieder in den Vordergrund. Manche sind einfach Flüchtigkeitsfehler, manche andere Bugs, die man beseitigen oder Workarounden kann.

Aber einer bleibt:

Und zwar habe ich eine Snap-Shot-Funktionalität gebaut, bei dem bei drücken auf einen Button die Werte aus dem EEPROM gelesen werden und das komplette Event für alle Fader (z.B. b1 00 65) gesendet werden. (und natürlich werden die Fader auch auf Position gefahren. Soweit funktioniert es auch.

Jetzt sende ich aber vorher noch einen kurzen Sysex-String (z.B)

"F0 00 01 0f 20 73 F7" um die nachfolgenden MBs zu benachrichtigen "Hallo, Snapshot Nr. 1[2,3] ausgelöst") . Das funktioniert im Prinzip auch.

Jedoch kommen die Bytes nach der zweiten Midibox u.U. durchmischt an.

Laut MIDI-OX:

F9 F0 00 01 0f 20 B2 01 00 FE F9 B2 02 00 FE ... F9 B2 07 00 FE B2 73 00 F7

Aufgedröselt:

F9 ... häää? Warum jetzt schon.

F0 00 01 0f 20 ... sollte kommen, aber bricht ab.

B2 01 00 FE ... fast ok, Event von Midibox2, Fader01, welcher auf 00 steht.

F9 B2 02 00 FE ... weitere Events wie erwartet, maskiert

B2 73 00 F7 ... ein neues unterwartetes Event? wie kommt da sie verlorene 73 rein? 

Wenn ich MIDI-OX trauen kann. (Hatten wir schonmal das Thema)

Das Problem ist dass die Sysex-Strings (==intercom-Befehle) nicht mehr von der letzten über Display verfügenden Midibox empfangen werden. Jedenfalls nicht immer.

Kann das ein Problem mit dem MIDI-Merger sein?

Konnte ich mich verständlich ausdrücken?

Link to comment
Share on other sites

Vielleicht nochmal zum Verständnis:

MIDI-Box 1: (MBLink-Forward)

- verfügt über Button, generiert Befehle

- sendet Befehl und sendet Events

MIDI-Box 2: (MBLink-Forward)

- hat weder Buttons, noch Display

- wertet Befehl aus und generiert Snapshot-Events

- leitert Befehl und Events von 1 weiter

Nach MIDI-Box2 sieht der Strom wie oben beschrienen aus.

Die Events von MB1 kommen ordentlich danach. 

Link to comment
Share on other sites

Wieviele Bytes werden vom Snapshot gesendet? Vielleicht kommt es zu einem Buffer overrun? Der IN Buffer ist 64 bytes gross, wenn gleichzeitig eingehende und interne Events weitergeleitet werden sollen, entsteht das typische Bottleneck-Problem. Mit dem RAM Monitor von MIOS Studio kann man das debuggen (Rx Buffer: 0x500-0x53f, Tx Buffer: 0x540-0x56f)

Eine einfache Moeglichkeit waere, zwischen den einzelnen Events, die gesendet werden, ein Delay von 1 oder 2 mS einzufuegen (MIOS_Delay(2); ), um Zeitschlitze fuer die eingehenden Events freizulassen.

Faustregel: 1 mS = 3 bytes

Gruss,

        Thorsten.

Link to comment
Share on other sites

Hallo Thorsten!

Pro Snapshot werden 8-Events von Midibox 1 und 2 versandt.

D.h. im In-buffer von MIDI-Box 2 stehen maximal

7 bytes vom Sysex-Befehl der von MB1 zuerst gesendet wird

40 bytes von den 8x5 Bytes "F9 B1 0n vv FE" der Events.

Also 47.

Abgesehen davon. Bei einer Taktrate von 40Mhz und MIDI-Datenrate von

32000Bytes/s sollten 1250 Takte pro MIDI-Byte zur Verfügung stehen.

Sollte eigentlich reichen um alle reinkommenden MIDI-Bytes mit mehr als 1000 Befehlen zu verarbeiten und wieder zu senden.

Wo soll da ein Bottleneck entstehen? 

Link to comment
Share on other sites

Hallo Thomas,

das Bottleneck entsteht an der seriellen Schnittstelle - es handelt sich hier um einen asynchrones serielles Interface, das heisst: feste Baudrate und vorgegebene Bandbreite, die sich nicht erweitern laesst. Heisst: wenn am Eingang bereits mit voller Bandbreite empfangen wird, und die Daten zum Ausgang weitergeleitet werden sollen, dann sollte man vermeiden, bei maximaler Auslastung noch zusaetzliche MIDI Events hinzuzufuegen - ansonsten stauen sich die Daten auf, und es kann zu einem Buffer Overrun kommen.

In Deinem Projekt ist das vielleicht nicht der Fall (wie ich nach Deiner dritten Mail gemerkt habe), aber die potentielle Gefahr besteht immer. Und diese gilt es zu vermeiden.

Doch mir ist eingefallen, dass die vorgeschlagene Loesung am Ziel vorbeifuehrt. MIOS_Delay() ist voellig fehl am Platze, denn sie blockiert den Mainthread.

Ausserdem scheint das Problem in Deinem Programm zu sein, dass die Snapshot-Daten gesendet werden, waehrend der eingehende SysEx String noch nicht vollstaendig uebertragen wurde. Sendest Du die Daten vor oder nach dem 0xf7? Wahrscheinlich davor... und so werden sich alle nachfolgenden MIDI Parser (auch MIDI-Ox) fehlerhaft verhalten. U.u werden zusaetzliche Bytes hinzugefuegt oder von MIDI-Ox angezeigt, die gar nicht ueber die MIDI Leitung gegangen sind, weil die "State Machines" auseinanderlaufen (man darf nicht alles glauben, was MIDI-Ox anzeigt...)

Eine Loesung, die dafuer sorgt, dass das MIDI Protkoll eingehalten wird, und die zusaetzlich auch die Auslastung des MIDI Out Ports ausbalanciert (so dass ein Buffer Overrun sehr unwahrscheinlich wird), sieht wie folgt aus:

Der Snapshot sollte nicht sofort gesendet werden, sondern portionsweise mit jedem Aufruf von Tick() - der SysEx Parser sollte den Snapshot lediglich requesten, den Rest uebernimmt ein separater "Snapshot Handler".

Diese Methode hat zwei Vorteile: die Snapshot-Events werden erst gesendet, wenn der SysEx Stream beendet wurde, und durch das portionsweise Senden kommt der Merger nach jedem Event wieder zum Zuge - ist also zwischendurch wieder etwas eingetroffen, so werden die eingegangenen Daten zuerst versendet, und die intern generierten Daten werden verzoegert. Der interne Stream wird quasi automatisch blockiert - und so sollte es im Idealfall auch sein.

Hoert sich vielleicht kompliziert an, ist aber relativ einfach zu realisieren. In Tick() folgendes hinzufuegen:

(ich nehme an, dass 8 Events versendet werden sollen, snapshot_ctr ist eine globale Variable):


void Tick(void)
{
  // send part of snapshot until counter is 0 again
  if( snapshot_ctr ) {
      SendMIDIEvent(8-snapshot_ctr); // this function sends a part of the snapshot, selected with the counter
      --snapshot_ctr;
  }
}
[/code] Im SysEx Parser den Aufruf der Komplett-Snapshot Funktion durch folgendes ersetzen
[code]
  // request snapshot
  snapshot_ctr = 8;

das wars. Probiere es mal aus, Du wirst ueberrascht sein, wie gut es funktioniert ;-)

Gruss,

        Thorsten.

Link to comment
Share on other sites

Hallo Thorsten!

Doch mir ist eingefallen, dass die vorgeschlagene Loesung am Ziel vorbeifuehrt. MIOS_Delay() ist voellig fehl am Platze, denn sie blockiert den Mainthread.

Gut, das du das sagst bevor ich es implementiere. Allerdings würde es auch den MIDI-Strom verringern.

Ausserdem scheint das Problem in Deinem Programm zu sein, dass die Snapshot-Daten gesendet werden, waehrend der eingehende SysEx String noch nicht vollstaendig uebertragen wurde.

Das ist exakt die Frage. Denn laut Software wird von der MIDI-Box 1 erst  der Sysex-String gesendent und dann die Fader-Events.

Die MIDI-Box 2 parsed den Sysex-String, und sendet daraufhin selber ihre MIDI-Daten, nachdem die von EEPROM gelesen wurden.

Und da kommt scheinbar was durcheinander, so dass MIDI-Box "3" den Sysex-String verscrampelt bekommt.

 

Der Snapshot sollte nicht sofort gesendet werden, sondern portionsweise mit jedem Aufruf von Tick() - der SysEx Parser sollte den Snapshot lediglich requesten, den Rest uebernimmt ein separater "Snapshot Handler".

Das ist natürlich eine Idee. Zumal es bei zeitunkritischen Sysex-Commandos schon so funktioniert.

Ich habe aber noch ein großes Bedenken:

Es kann passieren, dass meine Audio-Software >127 Controllerbefehle sendet.

Und die müssen in jeder MIDI-Box geparsed und geforwarded werden. 

Mit den alten Midibox64 war das allerdings kein Problem.

Ich zerbreche mit gerade noch über etwas anderes den Kopf: Ich habe noch nicht probiert ob mein Netzteil tatsächlich 32 Fader auf einmal bewältigt. Falls nicht müsste dieser nur im Initaliserungs-, Audiosoftware-Start- oder Snapshot-Fall vorkommende Fall entschäft werden.

Link to comment
Share on other sites

Hallo,

ich habe da noch eine Frage.

Das Problem ist doch, dass ich MIDI-Daten sende bevor der Sysextring vollständig übertragen wurde.

Was passiert denn jetzt mit normalen Fader-Events beim Bewegen der Fader?

Die düfte man dann doch auch nicht direkt senden, oder? Kann doch dann auch sein, wenn ich an MIDI-Box2 einen Fader bewegen und dass entsprechende MIDI-Event senden will, dass gerade ein Event von MidBox1 herein kam, weil ich auch da einen Fader bewegte.

Link to comment
Share on other sites

Es kann passieren, dass meine Audio-Software >127 Controllerbefehle sendet.

Und die müssen in jeder MIDI-Box geparsed und geforwarded werden.

Die MIDI Events bestehen aus 3 Bytes? Dann hat jede MIDIbox bis zu 960 uS Zeit, das Event zu parsen, ohne dass es zu einem Buffer Overrun kommen kann. Die MIDI bytes werden ja via Interrupts im Hintergrund versendet, bleibt genuegend Zeit fuer den Mainthread - und wenn es mal etwas laenger dauert, macht das i.d.R. auch nichts, denn 64 Bytes auf der MIDI In Seite koennen bis zu 20 mS ueberbruecken. Kritisch wird es, wenn kontinuierlich MIDI Events empfangen werden, dann muss das Parsing in weniger als 960 uS abgehandelt sein.

Das ist uebrigens nicht die ganze Wahrheit - es gibt dann auch noch den Running Status, der aus einem 3-Byte Event zwei Bytes macht, somit waeren nur noch 640 uS Zeit. Und die ISRs lasten die CPU zusaetzlich aus, deren Ausfuehrungszeit haengt von unterschiedlichen Parametern ab... doch ich muss hier wohl nicht zu sehr ins Detail gehen, das Systemverhalten ist extrem fallabhaengig.

ch habe da noch eine Frage.

Das Problem ist doch, dass ich MIDI-Daten sende bevor der Sysextring vollständig übertragen wurde.

Was passiert denn jetzt mit normalen Fader-Events beim Bewegen der Fader?

Die düfte man dann doch auch nicht direkt senden, oder? Kann doch dann auch sein, wenn ich an MIDI-Box2 einen Fader bewegen und dass entsprechende MIDI-Event senden will, dass gerade ein Event von MidBox1 herein kam, weil ich auch da einen Fader bewegte.

Wenn ein neues MIDI Event eintrifft, bleibt MIOS solange in der "MPROC" (MIDI Processor) Schleife, bis das Event vollstaendig empfangen wurde. Die anderen Hooks wie Tick(), AIN_NotifyChange() oder DIN_NotifyToggle() werden in dieser Zeit nicht augerufen, lediglich die MPROC_*() Hooks und die ISRs

Wenn das Event nicht komplett eintrifft (Fehler auf der MIDI Sender Seite), wird nach ca. 2 Sekunden die MPROC_NotifyTimeout() Funktion aufgerufen, und das Parsing wird abgebrochen. Es macht Sinn, in diese Funktion eine Debug Meldung einzubauen, um ueber eine fehlerhafte Uebertragung informiert zu werden. Wenn sich Deine MIDIbox also scheinbar fuer kurze Zeit aufhaengt, dann koennten inkomplette MIDI Events die Fehlerursache sein.

Gruss,

        Thorsten.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...