Einzelnen Beitrag anzeigen

EWeiss
(Gast)

n/a Beiträge
 
#7

AW: Hardcode MidiHeader

  Alt 13. Apr 2011, 20:07
Jetzt dürft ihr alle nochmal über mich und meinen Programmierstil herziehen.

Delphi-Quellcode:
unit uMidi;

interface
uses Windows, Classes, SKAeroAPI, Math, SysUtils, uGlobal, uSound;

var
  CurrentByte: Integer;
  DeltaTime: Integer;
  LastDeltaTime: Integer;
  TotalBytes: Integer;
  MidiInst: Integer;
  TrackDataStartByte: Integer;
  MidiIsDrum: BOOL;
  MidiDrumNum: Integer;
  Bytes: array[1..10000] of byte;
  DeltaBinArray: array[0..3] of string;
  DeltaTimeArray: array[0..3] of byte;
  DB: Integer;
  TempZ: Integer;
  
function ConvertToBinary(BInput: Integer): string;
procedure ExpMidiFile(MidiFile: string);

implementation
uses uMidiTracker;

procedure MidiFileStartNote(ActiveSpur, ActiveNote: Integer);
var
  Flip: Integer;

begin

  if MidiIsDrum then
  begin
    Flip := MidiDrumNum;
    TempZ := 9;
  end else
  begin
    Flip := 127 - Grid[ActiveSpur, ActiveNote];
    TempZ := ActiveSpur;
  end;
  // Start Noten Befehl + Channel
  Bytes[CurrentByte] := 144 + TempZ;
  inc(CurrentByte);
  Bytes[CurrentByte] := Flip + Basenote; // Note + Basenote
  inc(CurrentByte);
  Bytes[CurrentByte] := 127; // Geschwindigkeit
  inc(CurrentByte);

end;

procedure MidiFileStopNote(ActiveSpur: Integer);
var
  Flip: Integer;

begin

  if MidiIsDrum then
  begin
    Flip := MidiDrumNum;
    TempZ := 9;
  end else
  begin
    Flip := 127 - (MidiTracker.OldNote[ActiveSpur] mod 1000);
    TempZ := ActiveSpur;
  end;
  // Stop Noten Befehl + Channel
  Bytes[CurrentByte] := 128 + TempZ;
  inc(CurrentByte);
  Bytes[CurrentByte] := Flip + Basenote; // Note + Basenote
  inc(CurrentByte);
  Bytes[CurrentByte] := 0; // Geschwindigkeit
  inc(CurrentByte);

end;

procedure ConvertDeltaTime;
var
  DB, DA, DC, DD: Integer;
  Temp: string;

begin
    // 12 Delta schläge pro 16tel Note
    DB := DeltaTime * 12;
    Temp := ConvertToBinary(DB);

    DA := Length(Temp) mod 7;
    if DA <> 0 then
      Temp := StringOfChar('0', 7 - DA) + Temp;

    DD := Length(Temp) div 7 - 1;
    for DA := 0 to DD do
    begin
      DeltaBinArray[DA] := MidStr(Temp, DA * 7 + 1, 7);
      if DA = DD then
        DeltaBinArray[DA] := '0' + DeltaBinArray[DA]
      else
      DeltaBinArray[DA] := '1' + DeltaBinArray[DA];
    end;

    // Konvertiere Binärzeichenfolge in DeltaBinArray zu Bytes ins DeltaTimeArray
    for DA := 0 to DD do
    begin
      DB := 0;
      for DC := 1 to 8 do
      begin
        if MidStr(DeltaBinArray[DA], DC, 1) = '1then
          DB := DB + trunc(Math.Power(2, (8 - DC)));
      end;
      DeltaTimeArray[DA] := DB;
    end;

    for DA := 0 to DD do
    begin
      Bytes[CurrentByte] := DeltaTimeArray[DA];
      inc(CurrentByte);
    end;

end;


procedure ConvertTempo;
var
  DB: Integer;
  DA, DC: Integer;
  MPQN: Integer;
  BytesArray: array[0..2] of string; // microsekunden pro viertel Note
  Temp: string;
  
begin

  MPQN := 60000000 div MidiTracker.Tempo;

  DB := MPQN;
  Temp := ConvertToBinary(DB);

  Temp := StringOfChar('0', 24 - Length(Temp)) + Temp;

  for DA := 0 to 2 do
    BytesArray[DA] := MidStr(Temp, DA * 8 + 1, 8);

  // Konvertiere Binärzeichenfolge in BytesArray zu Bytes
  for DA := 0 to 2 do
  begin
    DB := 0;
    for DC := 1 to 8 do
    begin
      if MidStr(BytesArray[DA], DC, 1) = '1then
        DB := DB + trunc(Math.Power(2, (8 - DC)));
    end;
    Bytes[27 + DA] := DB;
  end;

end;

function ConvertToBinary(BInput: Integer): string;
var
  Power: Integer;
  BTemp: string;
  BNum: Integer;
  BA, BB: Integer;

begin
  BNum := BInput;

  Power := 0;
  while trunc(Math.Power(2, Power)) < BNum do
    inc(Power);

  dec(Power);

  if Power < 0 then
    Power := 0;

  BTemp := '';

  for BA := Power downto 0 do
  begin
    BB := trunc(Math.Power(2, BA));
    if BNum >= BB then
    begin
      BTemp := BTemp + '1';
      BNum := BNum - BB;
    end else
    BTemp := BTemp + '0'
  end;
  Result := BTemp;

end;

procedure ConvertTrackLength;
var
  DA, DC: Integer;
  TotalBytesArray: array[0..3] of string;
  Temp: string;
  
begin
  // Ins binär formate konvertieren
  DB := TotalBytes;
  Temp := ConvertToBinary(DB);

  Temp := StringOfChar('0', 32 - length(Temp)) + Temp;

  for DA := 0 to 3 do
    TotalBytesArray[DA] := MidStr(Temp, DA * 8 + 1, 8);

  // Konvertiere Binärzeichenfolge in TotalBytesArray zu Bytes
  for DA := 0 to 3 do
  begin
    DB := 0;
    for DC := 1 to 8 do
    begin
      if MidStr(TotalBytesArray[DA], DC, 1) = '1then
        DB := DB + trunc(Math.Power(2, (8 - DC)));
    end;
    Bytes[TrackDataStartByte - (4 - DA)] := DB;
  end;

end;

procedure ExpMidiFile(MidiFile: string);
var
  IntZ: Integer;
  IntA: Integer;
  f: TFileStream;

begin
  // MIDI File Header Chunk (14 bytes)
  // MTHD
  Bytes[1] := ord('M');
  Bytes[2] := ord('T');
  Bytes[3] := ord('h');
  Bytes[4] := ord('d');

  // Headerlänge 6 bytes
  Bytes[5] := 0;
  Bytes[6] := 0;
  Bytes[7] := 0;
  Bytes[8] := 6;

  // 6 byte Header
  // 0 - Einzelne Spur
  // 1 - Mehrere Spuren, Syncron
  // 2 - Mehrere Spuren, ASyncron
  Bytes[9] := 0;
  Bytes[10] := 1;

  Bytes[11] := 0;
  Bytes[12] := 9; // Spur Nummer

  Bytes[13] := 0;
  Bytes[14] := 48; // Anzahl der Delta-Zeit sekunde pro Viertelnote

  // Spur 1
  // MTRK
  Bytes[15] := ord('M');
  Bytes[16] := ord('T');
  Bytes[17] := ord('r');
  Bytes[18] := ord('k');

  // Anzahl der Bytes in der Spur
  Bytes[19] := 0;
  Bytes[20] := 0;
  Bytes[21] := 0;
  Bytes[22] := 19;

  // Geschwindigkeit
  Bytes[23] := 0; // delta Zeit
  Bytes[24] := 255; // FF (Meta Befehl)
  Bytes[25] := 81; // Tempo Befehl
  Bytes[26] := 3; // 3 bytes für Tempo Beschreibung

  ConvertTempo; // 3 bytes fürs Tempo schreiben

  // Zeit Signatur
  Bytes[30] := 0; // delta Zeit
  Bytes[31] := 255; // FF (Meta Befehl)
  Bytes[32] := 88; // Zeit Signatur Befehl
  Bytes[33] := 4; // 4 bytes
  Bytes[34] := 4; // Zähler
  Bytes[35] := 2; // Nenner (2 = 1/4, 3 = 1/8, 4 = 1/16, etc.)
  Bytes[36] := 24; // ?
  Bytes[37] := 8; // 32 Note in einer 4 Note;

  // Spur Ende
  Bytes[38] := 0; // delta Zeit
  Bytes[39] := 255; // Spurende Befehl
  Bytes[40] := 47;
  Bytes[41] := 0;

  With MidiTracker do
  begin
    // Spuren schreiben
    CurrentByte := 41;
    MidiTracker.FindEndOfSong;
    inc(MidiTracker.SongLength);

    // Spuren einlesen
    for IntZ := 0 to 7 do
    begin
      inc(CurrentByte);

      OldNote[IntZ] := -1;
      OldInst[IntZ] := -1;
      LastDeltaTime := 0;
      TotalBytes := 0;

      // MTRK
      Bytes[CurrentByte] := ord('M');
      inc(CurrentByte);
      Bytes[CurrentByte] := ord('T');
      inc(CurrentByte);
      Bytes[CurrentByte] := ord('r');
      inc(CurrentByte);
      Bytes[CurrentByte] := ord('k');
      inc(CurrentByte);
      CurrentByte := CurrentByte + 4;

      TrackDataStartByte := CurrentByte;

      if SKAERO_GetCheckButtonStatus(SKAERO_GetMainItem(MainHandle,
        IntZ + ID_HIDETRACK_FIRST)) = False then
      begin
        for IntA := 0 to SongLength do
        begin
          // NotenTyp suchen
          if OldNote[IntZ] = -1 then
            OldNoteType := BlankNote;
          if (OldNote[IntZ] >= 0) and (OldNote[IntZ] < 1000) then
            OldNoteType := StartingNote;
          if OldNote[IntZ] >= 1000 then
            OldNoteType := ContinuingNote;

          if IntA = SongLength then
          begin
            NoteType := BlankNote;
          end else
          begin
            if Grid[IntZ, IntA] = -1 then
              NoteType := BlankNote;
            if (Grid[IntZ, IntA] >= 0) and (Grid[IntZ, IntA] < 1000) then
              NoteType := StartingNote;
            if Grid[IntZ, IntA] >= 1000 then
              NoteType := ContinuingNote;
          end;

          // Ändere das Instrument wenn nötig
          // wird eine neue Note gespielt und das Instrument unterscheidet sich vom alten
          MidiInst := (InstGrid[IntZ, IntA]);
          if (NoteType = StartingNote) and (MidiInst <> OldInst[IntZ]) then
          begin
            // Instrument wählen
            if MidiInst < 128 then
            begin
              DeltaTime := IntA - LastDeltaTime;
              ConvertDeltaTime;
              // Intrumenten Befehl + Channel
              Bytes[CurrentByte] := 192 + IntZ;
              inc(CurrentByte);
              Bytes[CurrentByte] := MidiInst;
              inc(CurrentByte);
              LastDeltaTime := IntA;
              MidiIsDrum := False;
            end else
            begin
              // Perkussions Instrument
              MidiIsDrum := True;
              MidiDrumNum := MidiInst - 93;
            end;
          end;

          //Stop die Alte Note und starte Neue
          if (OldNoteType <> BlankNote) and (NoteType = StartingNote) then
          begin
            // Stope die Alte Note
            DeltaTime := IntA - LastDeltaTime;
            ConvertDeltaTime;
            MidiFileStopNote(IntZ);
            // Starte neue Note
            Bytes[CurrentByte] := 0; // Delta zeit
            inc(CurrentByte);
            MidiFileStartNote(IntZ, IntA);
            LastDeltaTime := IntA;
          end;

          // Stop die Alte Note aber keine Neue
          if (OldNoteType <> BlankNote) and (NoteType = BlankNote) then
          begin
            DeltaTime := IntA - LastDeltaTime;
            ConvertDeltaTime;
            MidiFileStopNote(IntZ);
            LastDeltaTime := IntA;
          end;

          // Starte neue Note aber stoppe nicht die Alte
          if (OldNoteType = BlankNote) and (NoteType = StartingNote) then
          begin
            DeltaTime := IntA - LastDeltaTime;
            ConvertDeltaTime;
            MidiFileStartNote(IntZ, IntA);
            LastDeltaTime := IntA;
          end;

          // Setze die Alte Note als Aktuelle note
          OldNote[IntZ] := Grid[IntZ, IntA];

          // Setze das Alte Instrument als Aktuelles
          if NoteType = StartingNote then
            OldInst[IntZ] := InstGrid[IntZ, IntA];
        end; // End for IntA
      end; // End SKAERO_GetCheckButtonStatus

      // Spur ende
      DeltaTime := SongLength - LastDeltaTime; // Delta Zeit
      ConvertDeltaTime;
      Bytes[CurrentByte] := 255;
      inc(CurrentByte);
      Bytes[CurrentByte] := 47;
      inc(CurrentByte);
      Bytes[CurrentByte] := 0;

      TotalBytes := CurrentByte - TrackDataStartByte + 1;
      ConvertTrackLength;
    end; // for IntZ
  end; // End with MidiTracker

  // Datei schreiben
  f := TFileStream.Create(MidiFile, fmCreate or fmOpenReadWrite);
  f.Write(Bytes[1], CurrentByte);
  f.Free;

end;

end.
Und es funktioniert 100% auch ohne Header als Record und der ganze andere Kram
der für mich in manchen Situationen uninteressant und unnötig ist.
Warum eine Komponente vom 500KB in ein Projekt integrieren wenn es auch anders geht.

gruss
  Mit Zitat antworten Zitat