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) = '
1'
then
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) = '
1'
then
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) = '
1'
then
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.