Autor |
Beitrag |
jaenicke
Beiträge: 19289
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:06
Ist der Deltawert wirklich immer 0? Das Problem ist: Wenn der 0 ist, dann ist das Bit nicht gesetzt. Und das markiert eben das Ende des Werts.
Das der Wert am Anfang 0 ist, sollte richtig sein, aber immer natürlich nicht. Mal schauen...
|
|
Noodel
Beiträge: 27
|
Verfasst: Do 29.01.09 17:09
Ja, der DeltaValue ist immer 0. Zumindest in der while-Schleife (ChunkSize > 0) sollte der DeltaValue ja immer einen Wert > 0 haben. Aber auch da hat er immer den Wert 0. Irgendwo muss also noch ein kleiner Fehler sein. Ich weiß nur leider nicht wo.
|
|
jaenicke
Beiträge: 19289
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Do 29.01.09 18:00
Das Auslesen klappt aber offensichtlich. Um das zu verdeutlichen probiere einmal diesen Code aus. Der spielt auf dem internen Lautsprecher exakt die Melodie, die in der Datei drin ist, ab. Natürlich jetzt nicht mit den richtigen Noten, aber die Tonänderungen stimmen überein. 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:
| 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 or fmShareDenyNone); 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 $F; case TempByteValue shr 4 of $8: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.ReadBuffer(EventData2, SizeOf(EventData2)); Dec(ChunkSize, 2); end; $9: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.ReadBuffer(EventData2, SizeOf(EventData2)); Dec(ChunkSize, 2); Windows.Beep(EventData1 * 10, 500); Sleep(500); end; $A: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.ReadBuffer(EventData2, SizeOf(EventData2)); Dec(ChunkSize, 2); end; $B: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.ReadBuffer(EventData2, SizeOf(EventData2)); Dec(ChunkSize, 2); end; $C: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); Dec(ChunkSize); end; $D: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); Dec(ChunkSize); end; $E: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.ReadBuffer(EventData2, SizeOf(EventData2)); Dec(ChunkSize, 2); end; $F: begin MidiFile.ReadBuffer(EventData1, SizeOf(EventData1)); MidiFile.ReadBuffer(EventData2, SizeOf(EventData2)); MidiFile.Position := MidiFile.Position + EventData2; Dec(ChunkSize, 2 + EventData2); end; end; end;
end;
MidiFile.Free; except on E: Exception do begin ShowMessage('Fehler: ' + E.Message + ' an Position ' + IntToStr(MidiFile.Position)); MidiFile.Free; end; end; ShowMessage('Fertig!'); end; |
|
|
Noodel
Beiträge: 27
|
Verfasst: Do 29.01.09 21:43
Ja, das scheint wirklich zu stimmen. Aber man muss ja an die richtigen DeltaValues kommen, damit man weiß, wie lange eine Note gespielt wird. Wenn man den richtigen DeltaValue nicht hat, muss man (wie in diesem Beispiel-Code) eine festgelegte Zeit nehmen, die dann für jede Note gleich ist. Das war ja jetzt nur ein Test, aber beim späteren Programm soll das natürlich anders sein. Also muss man irgendwie die richtige DeltaTime rauskriegen, aber wie?
Also ich habe schon mal durchgeguckt: Dieses Mal scheint es nicht daran zu liegen, dass zwei Buchstaben vertauscht sind ("0F" statt "F0" oder so). Es muss also irgendeinen anderen Grund dafür geben, dass der DeltaValue immer 0 ist. Der ist doch 0, oder? Das kannst du ja in deinem Developer Studio überwachen (wie in deinem Video gezeigt).
|
|
Noodel
Beiträge: 27
|
Verfasst: Sa 31.01.09 20:23
Hat noch jemand eine Idee, woran es liegen könnte, dass der DeltaValue immer 0 ist?
Im Moment wird er ja hier ausgelesen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| 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; |
Ich glaube aber, das ist nicht richtig. Denn jedes MIDI-Kommando hat noch eine eigene Delta-Zeitangabe. Die müsste man also auslesen, wenn man auch die einzelnen Kommandos ausliest (while ChunkSize > 0). Aber da wird ja im Moment schon alles ausgelesen. Ist vielleicht einer der Werte, die jetzt schon ausgelesen werden, die Delta-Zeit?
|
|
PeterK
Hält's aus hier
Beiträge: 1
|
Verfasst: Mo 13.07.09 16:52
www.wilsonc.demon.co.uk/delphi3.htm
* MIDI Controls & Sequencer
D4 version, with lots of new features, and vastly enhanced 'sequencer' demo. Beta version of my MIDI controls for Delphi 3 & 4 (Windows 95 and NT). Read, write and manipulate MIDI files. Do MIDI playback, including fast forward, etc. Display MIDI data in piano roll and event list styles. Unlimited virtual midi output ports. All sorts of other goodies including the famous piano keyboard control. Source included.
Now includes variable playback tempo, Tempo Map Component, Controller Map Component.
|
|
Mitmischer 1703
Beiträge: 754
Erhaltene Danke: 19
Win 7, Debian
Delphi Prism, Delphi 7, RAD Studio 2009 Academic, C#, C++, Java, HTML, PHP
|
Verfasst: Mo 13.07.09 17:00
Hm, nach meinem Gehör sind alle Noten mit b-chen oder Kreuzchen (also cis/des...) immer ein c!
_________________ Die Lösung ist nicht siebzehn.
|
|
juerg5524
Hält's aus hier
Beiträge: 5
|
Verfasst: Di 14.07.20 10:22
So wie die DeltaZeit ausgelesen wird, muss auch die variable Zeit nach einem Ton-An-Kommando bestimmt werden. Damit der Ton klingt, einen "sleep" zu dieser Zeit einsetzen.
Übrigens: Beim Meta-Event muss ebenfalls die Länge mit variabler Länge bestimmt werden.
|
|
juerg5524
Hält's aus hier
Beiträge: 5
|
Verfasst: Mi 22.07.20 12:06
|
|
|