Autor |
Beitrag |
Noodel
Beiträge: 27
|
Verfasst: Fr 23.01.09 19:24
Ich möchte eine MIDI-Datei in Delphi per FileStream einlesen und danach analysieren: So möchte ich die einzelnen Stimmen/Instrumente rausfiltern und die MIDI-Kommandos (Taste drücken, Taste loslassen, welche Taste usw.) den Instrumenten zuordnen.
Alle wichtigen MIDI-Behlfe und der Aufbau einer MIDI-Datei sind hier beschrieben.
Mein Ansatz ist bisher so:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64:
| function SwapInt(value:Integer):Integer; type Tswaprec=packed record case boolean of True:(int:Integer); False:(b:array[1..4] of byte); end; var swaprec,swaprecRes:TSwapRec; i:integer; begin swaprec.int:=value; for i:=1 to 4 do swaprecRes.b[i]:=swaprec.b[5-i]; result:=swaprecRes.int; end;
function SwapWord(Value:Word):Word; type Tswaprec=packed record case boolean of True:(w:word); False:(b:array[1..2] of byte); end; var swaprec,swaprecRes:TSwapRec; i:integer; begin swaprec.w:=value; for i:=1 to 2 do swaprecRes.b[i]:=swaprec.b[3-i]; result:=swaprecRes.w; end;
procedure TForm1.Button1Click(Sender: TObject); var midi:TFileStream; s:string; i:Integer; w:word; begin midi:=tFilestream.create('d:\mission.mid',fmopenread); try setlength(s,4); midi.Read(s[1],4); if s<>'MThd' then raise Exception.create('MThd-Fehler'); midi.Read(i,4); i:=swapInt(i); if i<>6 then raise Exception.create('Headersize -Fehler'); midi.Read(w,2); w:=swapWord(w); case w of 0:showmessage('eine Spur'); 1:showmessage('mehrere Spuren, synchron'); 2:showmessage('mehrere Spuren, nicht synchron'); else raise Exception.create('MIDI-Format unbekannt'); end; midi.Read(w, 2); w := swapWord(w); if (w > 0) AND (w < 26) then begin showmessage(IntToStr(w)+' Tracks'); end; midi.Read(w, 2); w := swapWord(w); showmessage(IntToStr(w)+' Delta-time ticks pro Viertelnote'); finally midi.free; end; end; |
So lese ich aber bisher nur den Header-Chunk aus. Für die Track-Chunks fehlt mir der Ansatz. Soll ich da mit einer while-Schleife durchgehen? Muss ich da immer 2 Bytes oder 4 Bytes zusammen auslesen? Oder muss ich es als ASCII interpretieren?
Ich hoffe, ihr könnt mir helfen. Danke im Voraus für eure Antworten!
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 23.01.09 19:48
|
|
Noodel
Beiträge: 27
|
Verfasst: Fr 23.01.09 21:17
Danke!
Ich hab es jetzt so gemacht, wie du meintest: 4 Bytes als Integer-Wert ausgelesen. So sieht der Code aus:
Delphi-Quelltext 1: 2: 3: 4: 5:
| while midi.Position < midi.Size do begin midi.Read(i, 4); i := swapWord(i); Memo1.Lines.Add(IntToStr(i)); end; |
Ist das so richtig?
Wenn ich die Werte dann einzeln ausgeben lasse, kommt das raus:
20739
48560
20739
48514
20739
48514
...
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 23.01.09 21:22
Naja, Moment, du musst immer zweimal die 4 Byte als Integer lesen und dann den restlichen Chunk. Dessen Größe steht ja im zweiten Integer.
Was macht swapWord? Ich müsste vielleicht nochmal in die Doku schauen, aber erstmal hatte ich da nix davon gesehen.
|
|
Noodel
Beiträge: 27
|
Verfasst: Fr 23.01.09 23:08
Sorry, falls das jetzt dumme Fragen sind, aber ich kenne mich überhaupt nicht aus mit Hex-Daten und dem Auslesen aus Dateien:
1) Die swap-Funktionen sind zum Umdrehen von Big Endian auf Little Endian.
2) Wie groß sind denn die "Pakete", in denen ich den restlichen Chunk einlese? Sind es immer 4 Byte, 2 Byte, ...?
Auf der Seite mit der MIDI-Aufbau-Beschreibung steht ja folgendes:
"jedes MIDI-Kommando hat 2 Teile. Der linken Nybble (Ein Nybble = 4 Bit) enthält das Kommando und rechte Nybble enthält den Kanal auf welchem das Kommando ausgeführt werden soll. Es gibt 16 Midi-Kanäle und 8 Midi-Kommandos (das Kommandonybble muss einen MSB von 1 haben). In der folgenden Tabelle gibt "x" den Kanal an."
Die beiden Teile des Kommandos haben ja jeweils 0,5 Byte. Muss ich die Teile einzeln auslesen oder zusammen (als 1-Byte-Paket)?
Du hast mir jetzt zwar gesagt, wie es sein sollte, aber ich versteh das noch nicht ganz. Könntest du das bitte mal in Code schreiben (Pseudo oder Delphi)? Das wäre nett.
|
|
Noodel
Beiträge: 27
|
Verfasst: So 25.01.09 13:39
Hat keiner eine Idee? Irgendwas mache ich nämlich noch falsch. Wenn ich 4 Bytes einlese und auch wenn ich 2 Bytes einlese, kommt immer eine Zahlenkette raus, die aber nicht rauskommen sollte.
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 25.01.09 21:20
Schau dir lieber die englische Version an, die deutsche ist teilweise schlicht falsch übersetzt...
Original: Zitat: | According to the MIDI spec, the entire delta-time should be at most 4 bytes long. |
Übersetzung: Zitat: | Die Delta-Zeit sollte mindestens 4 Bytes lang sein. |
Also statt höchstens wie im Original mindestens...
Diese Seite scheint auch hilfreich zu sein:
www.camx.de/kurs_kap5.html
Ich hab mal versucht die Spezifikation umzusetzen. Ich habe das nicht getestet, sondern einfach so hingeschrieben, deshalb mag auch totaler Blödsinn dabei herauskommen oder es umständlicher sein als nötig. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173:
| procedure TForm1.Button1Click(Sender: TObject);
procedure OpenMidi(FileName: string);
function SwapCardinal(Value: Cardinal): Cardinal; type TCardinalBytes = array[0..3] of Byte; begin TCardinalBytes(Result)[0] := TCardinalBytes(Value)[3]; TCardinalBytes(Result)[1] := TCardinalBytes(Value)[2]; TCardinalBytes(Result)[2] := TCardinalBytes(Value)[1]; TCardinalBytes(Result)[3] := TCardinalBytes(Value)[0]; end;
function SwapWord(Value: Word): Word; begin Result := (Value shr 8) or (Value shl 8); end;
type TMidiFileFormat = (mffSingleTrack = 0, mffMultiTrackSync = 1, mffMultiTrackAsync = 2); var MidiFile: TFileStream; MidiFileSize: Int64; TempByteValue: Byte; FileFormat: TMidiFileFormat; DeltaTimeTicks, TrackCount, TempWordValue: Word; Signature, ChunkSize, DeltaValue: Cardinal; EventChannel, EventData1, EventData2: Byte; begin MidiFile := TFileStream.Create(FileName, fmOpenRead); try MidiFileSize := MidiFile.Size;
if MidiFileSize < 8 then raise Exception.Create('Datei kleiner als 8 Byte!'); MidiFile.ReadBuffer(Signature, SizeOf(Signature)); if SwapCardinal(Signature) <> $4D546864 then raise Exception.Create('Falsche Header-Signatur!'); MidiFile.ReadBuffer(ChunkSize, SizeOf(ChunkSize)); ChunkSize := SwapCardinal(ChunkSize); if MidiFileSize - MidiFile.Position < ChunkSize then raise Exception.Create('Restliche Dateigröße kleiner als die angegebene Chunkgröße!'); MidiFile.ReadBuffer(TempWordValue, SizeOf(TempWordValue)); FileFormat := TMidiFileFormat(SwapWord(TempWordValue)); MidiFile.ReadBuffer(TrackCount, SizeOf(TrackCount)); TrackCount := SwapWord(TrackCount); MidiFile.ReadBuffer(DeltaTimeTicks, SizeOf(DeltaTimeTicks)); DeltaTimeTicks := SwapWord(DeltaTimeTicks);
while MidiFile.Position < MidiFileSize do begin MidiFile.ReadBuffer(Signature, SizeOf(Signature)); if SwapCardinal(Signature) <> $4D54726B then raise Exception.Create('Falsche Track-Chunk-Signatur!'); MidiFile.ReadBuffer(ChunkSize, SizeOf(ChunkSize)); ChunkSize := SwapCardinal(ChunkSize); if MidiFileSize - MidiFile.Position < ChunkSize then raise Exception.Create('Restliche Dateigröße kleiner als die angegebene Chunkgröße!');
MidiFile.ReadBuffer(TempByteValue, SizeOf(TempByteValue)); Dec(ChunkSize); DeltaValue := TempByteValue; if TempByteValue and $80 = $80 then begin DeltaValue := DeltaValue and $7F; repeat MidiFile.ReadBuffer(TempByteValue, SizeOf(TempByteValue)); Dec(ChunkSize); DeltaValue := DeltaValue shl 7 + (TempByteValue and $7F); until (ChunkSize = 0) or (TempByteValue and $80 = 0); end;
while ChunkSize > 0 do begin MidiFile.ReadBuffer(TempByteValue, SizeOf(TempByteValue)); Dec(ChunkSize); EventChannel := TempByteValue and $F0; case TempByteValue shr 4 of $8: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.ReadBuffer(EventData2, SizeOf(EventData2)); Dec(ChunkSize, 2); ShowMessage('Note off für Channel ' + IntToStr(EventChannel) + ' - Data1: ' + IntToStr(EventData1) + ', Data2: ' + IntToStr(EventData2)); end; $9: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.ReadBuffer(EventData2, SizeOf(EventData2)); Dec(ChunkSize, 2); ShowMessage('Note on für Channel ' + IntToStr(EventChannel) + ' - Data1: ' + IntToStr(EventData1) + ', Data2: ' + IntToStr(EventData2)); end; $A: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.ReadBuffer(EventData2, SizeOf(EventData2)); Dec(ChunkSize, 2); ShowMessage('Key after-touch für Channel ' + IntToStr(EventChannel) + ' - Data1: ' + IntToStr(EventData1) + ', Data2: ' + IntToStr(EventData2)); end; $B: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.ReadBuffer(EventData2, SizeOf(EventData2)); Dec(ChunkSize, 2); ShowMessage('Control Change für Channel ' + IntToStr(EventChannel) + ' - Data1: ' + IntToStr(EventData1) + ', Data2: ' + IntToStr(EventData2)); end; $C: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); Dec(ChunkSize); ShowMessage('Program (patch) change für Channel ' + IntToStr(EventChannel) + ' - Data: ' + IntToStr(EventData1)); end; $D: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); Dec(ChunkSize); ShowMessage('Channel after-touch für Channel ' + IntToStr(EventChannel) + ' - Data: ' + IntToStr(EventData1)); end; $E: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.ReadBuffer(EventData2, SizeOf(EventData2)); Dec(ChunkSize, 2); ShowMessage('Pitch wheel change für Channel ' + IntToStr(EventChannel) + ' - Data1: ' + IntToStr(EventData1) + ', Data2: ' + IntToStr(EventData2)); end; $F: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.Position := MidiFile.Position + EventData1; Dec(ChunkSize, 1 + EventData1); ShowMessage('Meta-Event der Länge ' + IntToStr(EventData1)); end; end; end;
MidiFile.Position := MidiFile.Position + ChunkSize; end;
MidiFile.Free; except on E: Exception do begin ShowMessage('Fehler: ' + E.Message); MidiFile.Free; end; end; end;
begin OpenMidi('d:\mission.mid'); end; | Was hast du eigentlich vor? Also ich meine, weil du das selbst schreiben willst, schließlich gibts ja auch Komponenten zum Abspielen usw.
|
|
Noodel
Beiträge: 27
|
Verfasst: So 25.01.09 22:10
Super, danke!!!!!
Das ist genau der Code denn ich brauchte. Jetzt ist mein Problem eigentlich gelöst. Den Rest werde ich wohl selbst schaffen. Ich möchte die MIDI-Kommandos nicht einfach abspielen, sondern daraus Noten erzeugen lassen und noch andere Dinge damit machen. Das Ganze soll später werden wie die Software "Synthesia" ( www.synthesiagame.com/). Auf der Seite ist auch ein Video, da kannst du dir ja mal ansehen, was das Programm macht.
Dafür das dein Code nicht getestet ist, ist er super: Hat direkt funktioniert. Eine Frage zu dem Code habe ich aber noch:
Wofür ist die Variable FileFormat? Brauche ich die oder kann ich die weglassen? Weil du benutzt sie später nicht mehr!?
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 25.01.09 22:41
Naja, das ist die Unterscheidung zwischen Multitrackdateien synchron, synchron und Singletrackdateien. Da ich die Datei nicht wirklich weiter auswerte, brauche ich die Unterscheidung auch nicht, für dich könnte es durchaus interessant werden.
|
|
Noodel
Beiträge: 27
|
Verfasst: Mo 26.01.09 21:22
OK, danke! Leider hab ich jetzt doch noch ein Problem mit dem Code gefunden:
Wenn ich alle Showmessage-Befehle bei den Events auskommentiere, dann wird ja im Case-Of-Teil nichts mehr ausgegeben. Dann erscheint die folgende Meldung direkt nach dem Öffnen der Midi-Datei per MidiOpen():
"Im Projekt name.exe ist eine Exception der Klasse EReadError aufgetreten. Meldung: 'Stream-Lesefehler'. Prozess wurde angehalten. Mit Einzelne Anweisung oder Start fortsetzen."
Woran liegt das?
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mo 26.01.09 21:27
Wie gesagt: ich hatte es nicht getestet. Hast du denn einmal debuggt wo genau der Fehler auftritt? Und du hast nur die ShowMessages gelöscht? Dann vermute ich, dass der Fehler einfach weiter hinten auftritt und du die ShowMessages nicht so lange weggeklickt hattest.
Woran das dann liegt musst du in der Datei an der entsprechenden Position schauen. Du kannst ja z.B. Debugausgaben in eine Datei schreiben, dann siehst du wo der Fehler auftritt.
|
|
Noodel
Beiträge: 27
|
Verfasst: Mo 26.01.09 23:00
Danke für die schnelle Antwort!
Ich hab die Stelle gefunden: Die Exception wird ausgeführt:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| except on E: Exception do begin ShowMessage('Fehler: ' + E.Message); MidiFile.Free; end; end; |
Wenn ich diesen Teil (oder nur den Showmessage-Befehl da drin) auskommentiere, kommt der Fehler nicht mehr. Warum wird diese Exception überhaupt ausgeführt? Ist weiter oben irgendwo ein Fehler, sodass die Exception "on E" in Kraft tritt?
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mo 26.01.09 23:13
Der Fehler tritt dann weiter auf, nur wird er nicht mehr angezeigt. Wenn das Programm in dem Except Teil angekommen ist, dann ist es schon zu spät. Die Frage ist wo der Fehler vorher auftritt.
|
|
Noodel
Beiträge: 27
|
Verfasst: Di 27.01.09 22:47
Hmm, ich hab den Code jetzt ein paar Mal durchgeguckt. Ich finde einfach keine Stelle, wo dieser Fehler auftreten könnte. Wär super, wenn sich jemand von euch den Code noch mal angucken könnte.
Außerdem bin ich mir nicht sicher, ob mit diesem Code von jaenicke die Daten komplett richtig ausgelesen werden. Meiner Meinung nach erkennt das viel zu viele Channels. Ich hab mal mein Programm angehängt. Da ist auch eine Beispiel-MIDI-Datei bei, falls ihr keine MIDIs habt. Vielleicht könnt ihr das Programm ja mal testen. Einfach starten und auf "Datei" => "MIDI laden" klicken.
Einloggen, um Attachments anzusehen!
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 28.01.09 03:43
Wie wäre es mit debuggen?
20 Sekunden debuggen sagen mir: Am Anfang wird ein ChunkSize von 50 eingelesen. Danach ein metaevent. Dessen Größe wird aber mit 84 angegeben. So groß ist der Chunk aber gar nicht.
Wie ich das gesehen habe habe ich mal ganz schnell als Video aufgenommen, vielleicht hilft dir das ja...
www.sj-berlin.de/ser...midi/Midi_Debug.html
// EDIT:
Ok, ich habe noch einmal geschaut. Das Metaevent hat noch einen Typ vor der Länge. 84 = $54 heißt SMPTE Offset. D.h. es müssen ebenfalls zwei Bytes gelesen werden und der zweite ist erst die Größe.
Ich habe übrigens auch nicht diese Seite noch gefunden dazu:
253.ccarh.org/handout/smf/
|
|
Noodel
Beiträge: 27
|
Verfasst: Mi 28.01.09 18:30
Danke!!!
Mit dem Video das war super, da hab ichs natürlich direkt verstanden. Danke auch noch für den Tipp (Edit). Ich habe es jetzt so gemacht, so müsste es stimmen, oder?
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| $F: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.ReadBuffer(EventData2, SizeOf(EventData2)); MidiFile.Position := MidiFile.Position + EventData2; Dec(ChunkSize, 2 + EventData2); ShowMessage('Meta-Event der Länge ' + IntToStr(EventData2)); end; |
PS: Sorry, dass ich nicht debuggt habe. Ich hab auch nicht Borland Developer Studio, sondern das einfache Borland Delphi. Ich habe da die Debug-Funktion noch nie benutzt. Bisher hab ich sie nie gebraucht und weiß deshalb auch nicht, wie man damit umgeht. Ich werds mir aber mal angucken.
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 28.01.09 18:55
Noodel hat folgendes geschrieben : | so müsste es stimmen, oder? |
Ja, ich denke schon. Zumindest gab es ja so keinen Fehler mehr. Verglichen mit den MIDI-Events habe ich nicht, da fehlt mir ein guter Viewer.
// EDIT:
Ach ja: Aufgefallen ist mir, dass auf einem Channel ständig Note aus kam (und das vor dem ersten Note an) und auf anderen Note an. Wenn in den Metaevents der Rest gesteuert wird, dann kann das natürlich trotzdem stimmen. Das hab ich mir nicht weiter angeschaut.
Noodel hat folgendes geschrieben : | PS: Sorry, dass ich nicht debuggt habe. Ich hab auch nicht Borland Developer Studio, sondern das einfache Borland Delphi. Ich habe da die Debug-Funktion noch nie benutzt. Bisher hab ich sie nie gebraucht und weiß deshalb auch nicht, wie man damit umgeht. Ich werds mir aber mal angucken. |
Das ist Delphi 2006, von der Funktionalität und dem Aussehen her identisch mit dem kostenlosen Turbo Delphi Explorer, dort kannst du nur keine Packages und damit keine Fremdkomponenten nachinstallieren (aber natürlich per Code erzeugen). Genauer habe ich das hier geschrieben:
www.delphi-library.d...ewtopic.php?p=539975
Der Unterschied beim Debuggen im Vergleich zu älteren Delphiversionen ist z.B., dass man dort nicht per Mouseover den Variableninhalt sieht und Klassen auch nicht bequem auswerten kann. Strg + F7 zum Auswerten eines markierten Ausdrucks / einer Variable sowie die Überwachung von Ausdrücken und natürlich das schrittweise durchgehen per F8 gibts aber da auch schon.
|
|
Noodel
Beiträge: 27
|
Verfasst: Mi 28.01.09 20:43
OK, dann kann ich ja nächstes Mal selber debuggen.
Zu deinem Edit:
Ich glaube auch, dass die Channels nicht stimmen. Denn du liest in dem Code zuerst den EventChannel aus und dann erst das Midi-Kommando. Außerdem reichen die Channels so bis 128 oder sogar noch höher, das ist sehr komisch.
Eigentlich sollten die Channels aber in dem Command Byte drinstecken, das du auch per "Case of" unterscheidest ($8, $9 usw). Kann es sein, dass dieser Wert, den du als Channel hast, eigentlich der Delta-Wert ist? Der sollte nämlich immer vor dem Kommando stehen und das würde passen. Deshalb wäre z.B. bei "0x8n kk vv" der Kanal "n" und nicht der Wert, der vor diesem Command Byte steht.
Das ist auch bei Wikipedia gut beschreiben (Tabelle):
de.wikipedia.org/wik...nterface#Statusbytes
Hast du das in deinem Code richtig oder ist da etwas vertauscht? Wenn etwas vertauscht ist: Weißt du vielleicht, was ich ändern muss, damit es passt?
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 28.01.09 20:51
Stimmt, ganz richtig ist es nicht, aber nicht so wie du jetzt vermutest. Delphi-Quelltext 1: 2: 3: 4:
| MidiFile.ReadBuffer(TempByteValue, SizeOf(TempByteValue)); Dec(ChunkSize); EventChannel := TempByteValue and $F0; case TempByteValue shr 4 of | Ich lese das eine Byte auf einmal aus. Dann lese ich den Channel aus. Allerdings ist die Bitmaske falsch. So nehme ich die linken 4 Bit statt den rechten. Also muss dort $0F bzw. $F hin.
Danach stimmt es wieder, denn ich schiebe die Bits nach rechts und habe damit nur noch die linken 4 Bit in den vorher rechten 4 Bit. Natürlich hätte ich auch wieder and nehmen und mit $80 etc. vergleichen können.
Beispiel, TempByteValue schreibe ich als 8 Bits mit deren Indizes "12345678": Quelltext 1: 2: 3: 4: 5: 6: 7:
| TempByteValue and $F0; 12345678 and $F0 = 12345678 and 11110000 = 12340000 richtig wäre aber, dass die rechten Bits übrigbleiben.
TempByteValue shr 4 12345678 shr 4 = 00001234 denn die Bits werden ja um 4 Plätze nach rechts geschoben. |
|
|
Noodel
Beiträge: 27
|
Verfasst: Mi 28.01.09 21:04
OK, also musste ich noch das "$F0" in "$0F" ändern und alles stimmt!? Den Rest gleicht das "shr 4" wieder aus, sodass alles richtig ist!?
Jetzt müsste alles stimmen, du kannst es ja mal ausprobieren, hab das aktualisierte Programm wieder angehängt.
Und wie komme ich jetzt an den korrekten DeltaValue? Bei dem aktuellen Code ist er nämlich immer 0, das kann ja nicht richtig sein. Man braucht den DeltaValue ja, weil mit ihm und den DeltaTimeTicks/Viertelnote den aktuellen Timestamp für jedes Kommando berechnet.
Einloggen, um Attachments anzusehen!
|
|
|