Neue Antwort schreiben 
 
Themabewertung:
  • 0 Bewertung(en) - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
[Delphi] MIDI Analyse fehlt der Längenwert der Note
Magic94 Offline
mehr Kerne ist immer besser

Beiträge: 1.382
Registriert seit: Nov 2010
Beitrag #1
[Delphi] MIDI Analyse fehlt der Längenwert der Note
Ja :fresse: 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 :ninja: 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;

HP DL-580 G7
2x Intel Xeon E7-2870 (10 x 2,4GHz)
96GB DDR3-1333 RAM
NVIDIA GeForce GTX 1080 MSI (Blower)
Samsung 850 Pro 512GB auf PCIe Karte
4TB Seagate billigfieh
72GB 10K HP Drive
(Dieser Beitrag wurde zuletzt bearbeitet: 29.02.2012 13:37 von Magic94.)
29.02.2012 13:33
Alle Beiträge dieses Benutzers finden Diese Nachricht in einer Antwort zitieren
DosAmp Offline
Anderes Zeigegerät

Beiträge: 12.217
Registriert seit: Jul 2008
Beitrag #2
RE: [Delphi] MIDI Analyse fehlt der Längenwert der Note
Das MIDI-Format definiert nicht Noten als Bestandteile von Spuren, sondern Ereignisse, die eines nach dem anderen vom Synthesizer abgearbeitet werden. Vereinfacht gibt es da, wie du auch aus dem Quelltext herauslesen kannst, zum Beispiel Note-On (= Ton spielen), Note-Off (= Ton sofort verklingen lassen), Key After-Touch (= Ton mit einer gewissen Geschwindigkeit verzögert verklingen lassen) oder Channel After-Touch (= Spur verzögert verklingen lassen).

Das heißt, die Länge eines Tons ergibt sich nicht aus einem einzelnen (Note-on-)Events, wie es diese Prozedur nacheinander ausliest, sondern du musst dafür die Delta-Zeit (DeltaTimeTicks) des unmittelbar darauffolgenden Events auf derselben Spur heranziehen, das entweder den Ton ändert oder ausschaltet.
Siehe auch eine übersetzte Dokumentation des MIDI-Formats.

Erinnerst du dich an #whfclassics? Es ist zurück! In Pog-Form.
(Dieser Beitrag wurde zuletzt bearbeitet: 29.02.2012 17:35 von DosAmp.)
29.02.2012 16:42
Webseite des Benutzers besuchen Alle Beiträge dieses Benutzers finden Diese Nachricht in einer Antwort zitieren
Neue Antwort schreiben 


Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste