Ja
Delphi aber ist ok.
Also ich habe im Internet
Noodles Midi ausleseprocedure gefunden und bin dabei die Ausgabe für mich noch etwas zu modifizieren.
Leider lies diese Procedure nur die Notenwerte auf den verschiedenen Channeln aus, aber woher weiss ich wie lange diese Note spielt? Das alles lässt sich ja binnen weniger Sekunden ausführen, also ist Zeit messen wohl nicht möglich.
Bin ich wieder nur blind
oder ist die Procedure leicht unbrauchbar?
Code:
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;
// ### Header ###
if MidiFileSize < 8 then
raise Exception.Create('Datei kleiner als 8 Byte!');
// Signatur
MidiFile.ReadBuffer(Signature, SizeOf(Signature));
if SwapCardinal(Signature) <> $4D546864 then
raise Exception.Create('Falsche Header-Signatur!');
// Header-Chunk-Größe
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!');
// Dateiformat
MidiFile.ReadBuffer(TempWordValue, SizeOf(TempWordValue));
FileFormat := TMidiFileFormat(SwapWord(TempWordValue));
// Trackanzahl
MidiFile.ReadBuffer(TrackCount, SizeOf(TrackCount));
TrackCount := SwapWord(TrackCount);
// delta-time ticks pro Viertelnote
MidiFile.ReadBuffer(DeltaTimeTicks, SizeOf(DeltaTimeTicks));
DeltaTimeTicks := SwapWord(DeltaTimeTicks);
// ### Tracks ###
while MidiFile.Position < MidiFileSize do
begin
// Signatur
MidiFile.ReadBuffer(Signature, SizeOf(Signature));
if SwapCardinal(Signature) <> $4D54726B then
raise Exception.Create('Falsche Track-Chunk-Signatur!');
// Track-Chunk-Größe
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!');
// ### Events ###
// Delta-Time
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
// Command byte
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);
// 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
// Meta-Event
MidiFile.ReadBuffer(EventData1, SizeOf(EventData1));
MidiFile.ReadBuffer(EventData2, SizeOf(EventData2));
MidiFile.Position := MidiFile.Position + EventData2; // testweise überspringen
Dec(ChunkSize, 2 + EventData2);
// ShowMessage('Meta-Event der Länge ' + IntToStr(EventData2));
end;
end;
end;
// Rest des Chunks testweise einfach überspringen
// MidiFile.Position := MidiFile.Position + ChunkSize;
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;