Encodage sur 3 bytes

[Résolu]
Signaler
-
 Utilisateur anonyme -
Salut à tous ,

J'ai un petit soucis que je vous expose : Lors de la réalisation d'un fichier midi il est possible de définir le tempo en utilisant un méta évènement de la manière suivante :

Set Tempo
This meta event sets the sequence tempo in terms
of microseconds per quarter-note which is encoded in three bytes. It
usually is found in the first track chunk, time-aligned to occur at the
same time as a MIDI clock message to promote more accurate
synchronization. If no set tempo event is present, 120 beats per minute
is assumed. The following formula's can be used to translate the tempo
from microseconds per quarter-note to beats per minute and back.

MICROSECONDS_PER_MINUTE = 60000000

BPM = MICROSECONDS_PER_MINUTE / MPQN
MPQN = MICROSECONDS_PER_MINUTE / BPM


Meta Event, Type, Length, Microseconds/Quarter-Note, ----
255 (0xFF), 81 (0x51), 3, 0-8355711

Pour y arriver j'utilise le code suivant

TMidiWriter = class(TComponent)
  private
    MPQN: Integer;
    EventsStream:   TMemoryStream;
End;

Procedure Write_Tempo(onst MPQN: Integer;AStream:TStream);
var
  MPQNCp  : Longint;
  w:array of LongInt;
  k: byte;
begin
  If Not Assigned(AStream) Then Exit;
  MPQNCp := MPQN;
  SetLength(W,3);
  for k := 0 to 2 do
  begin
    w[k]:= Byte(MPQNCp and $FF);
    MPQNCp := MPQNCp shr 8;
  end;  
  for k := 2 Downto 0 do
  AStream.Write(w[k],1);
end;

procedure TMidiWriter.Add_SetTempo_Event(Const BPM: Integer);
var
  Meta_Val,Event_Type,SwSize: byte;
begin
  if (not Assigned(EventsStream)) then Exit;
  With EventsStream Do
    Begin
      MPQN:=60000000 Div BPM;
      Meta_Val:=255; Write(Meta_Val,1);
      Event_Type:=81; Write(Event_Type,1);
      SwSize:=3; Write(SwSize,1);
      Write_Tempo(MPQN,EventsStream);
    End; 
end;

Seulement quant je lance la lecture de mon fichier midi, ca plante. Le probleme vient bien du "tempo" car en l'absence de ce dernier, le fichier midi est bon. Je ne vois pas d'ou vient mon erreur

 merci

10 réponses

Messages postés
4202
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
13 juin 2020
37
Solution 1 :

const
  MICROSECBYMIN = 60000000;

type
  TTempoEvent = record
    vMeta : byte;
    eType : byte;
    sSize : byte;
    vMPQN : LongWord;
  end;

const
  SizeOfTempoEvent = SizeOf(TTempoEvent); // ou SizeOf(TTempoEvent)-1;

procedure MPQNToTempoEvent(const MPQN: LongWord): TTempoEvent;
begin
  result.vMeta := $FF;
  result.eType := $51;
  result.sSize := 3;

  result.vMPQN := MPQN;




end;

procedure BPMToTempoEvent(const BPM: LongWord): TTempoEvent;
var MPQN : LongWord;
begin
  MPQN := 60000000 div BPM;


  result.vMeta := $FF;
  result.eType := $51;
  result.sSize := 3;

  result.vMPQN := MPQN;




end;

function GetMPQNFromTempoEvent(const TE: TTempoEvent): LongWord;
begin

  result := $00FFFFFF and TE.vMPQN;

end;

function GetBPMFromTempoEvent(const TE: TTempoEvent): LongWord;
begin

  result := 60000000 div ($00FFFFFF and TE.vMPQN);

end;

procedure GetAllFromTempoEvent(const TE: TTempoEvent; var MPQN, BPM: LongWord);
begin

  MPQN := $00FFFFFF and TE.vMPQN;
  BPM  := 60000000 div MPQN;

end;

function WriteTempoEvent(Stream: TStream; const TE: TTempoEvent): boolean;
begin  result :Stream.Write(TE, SizeOfTempoEvent) SizeOfTempoEvent;
end;

function ReadTempoEvent(Stream: TStream; var TE: TTempoEvent): boolean;
begin  result :Stream.Read(TE, SizeOfTempoEvent) SizeOfTempoEvent;
end;


<hr size="2" width="100%" />


Solution 2 :




const
  MICROSECBYMIN = 60000000;

type
  TTempoEvent = record
    vMeta : byte;
    eType : byte;
    sSize : byte;
    vMPQN : array[0..2] of byte;
  end;

const
  SizeOfTempoEvent = SizeOf(TTempoEvent);

procedure MPQNToTempoEvent(const MPQN: LongWord): TTempoEvent;
begin
  result.vMeta := $FF;
  result.eType := $51;
  result.sSize := 3;



  result.vMPQN[0] := byte(MPQN);

  result.vMPQN[1] := byte(MPQN shr 8);

  result.vMPQN[2] := byte(MPQN shr 16);

end;

procedure BPMToTempoEvent(const BPM: LongWord): TTempoEvent;
var MPQN : LongWord;
begin
  MPQN := 60000000 div BPM;


  result.vMeta := $FF;
  result.eType := $51;
  result.sSize := 3;



  result.vMPQN[0] := byte(MPQN);

  result.vMPQN[1] := byte(MPQN shr 8);

  result.vMPQN[2] := byte(MPQN shr 16);

end;

function GetMPQNFromTempoEvent(const TE: TTempoEvent): LongWord;
begin

  result := (TE.vMPQN[0]) or (TE.vMPQN[1] shl 8) or (TE.vMPQN[0] shl 16);

end;

function GetBPMFromTempoEvent(const TE: TTempoEvent): LongWord;
begin

  result := 60000000 div ((TE.vMPQN[0]) or (TE.vMPQN[1] shl 8) or (TE.vMPQN[0] shl 16));

end;

procedure GetAllFromTempoEvent(const TE: TTempoEvent; var MPQN, BPM: LongWord);
begin

  MPQN := (TE.vMPQN[0]) or (TE.vMPQN[1] shl 8) or (TE.vMPQN[0] shl 16);
  BPM  := 60000000 div MPQN;

end;

function WriteTempoEvent(Stream: TStream; const TE: TTempoEvent): boolean;
begin  result :Stream.Write(TE, SizeOfTempoEvent) SizeOfTempoEvent;
end;

function ReadTempoEvent(Stream: TStream; var TE: TTempoEvent): boolean;
begin  result :Stream.Read(TE, SizeOfTempoEvent) SizeOfTempoEvent;
end;









<hr size="2" width="100%" />
Messages postés
4202
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
13 juin 2020
37




const
  MICROSECBYMIN = 60000000;

type
  TTempoEvent = record
    vMeta : byte;
    eType : byte;
    sSize : byte;
    vMPQN : array[0..2] of byte;
  end;

const
  SizeOfTempoEvent = SizeOf(TTempoEvent);

procedure MPQNToTempoEvent(const MPQN: LongWord): TTempoEvent;
begin
  result.vMeta := $FF;
  result.eType := $51;
  result.sSize := 3;



  result.vMPQN[0] := byte(MPQN shr 16);

  result.vMPQN[1] := byte(MPQN shr 8);

  result.vMPQN[2] := byte(MPQN);

end;

procedure BPMToTempoEvent(const BPM: LongWord): TTempoEvent;
var MPQN : LongWord;
begin
  MPQN := 60000000 div BPM;


  result.vMeta := $FF;

  result.eType := $51;

  result.sSize := 3;



  result.vMPQN[0] := byte(MPQN shr 16);

  result.vMPQN[1] := byte(MPQN shr 8);

  result.vMPQN[2] := byte(MPQN);

end;

function GetMPQNFromTempoEvent(const TE: TTempoEvent): LongWord;
begin

  result := (TE.vMPQN[0] shl 16) or (TE.vMPQN[1] shr 8) or TE.vMPQN[0];

end;

function GetBPMFromTempoEvent(const TE: TTempoEvent): LongWord;
begin

  result := 60000000 div ((TE.vMPQN[0] shl 16) or (TE.vMPQN[1] shr 8) or TE.vMPQN[0]);

end;

procedure GetAllFromTempoEvent(const TE: TTempoEvent; var MPQN, BPM: LongWord);
begin

  MPQN := (TE.vMPQN[0] shl 16) or (TE.vMPQN[1] shr 8) or TE.vMPQN[0];
  BPM  := 60000000 div MPQN;

end;

function WriteTempoEvent(Stream: TStream; const TE: TTempoEvent): boolean;
begin  result :Stream.Write(TE, SizeOfTempoEvent) SizeOfTempoEvent;
end;

function ReadTempoEvent(Stream: TStream; var TE: TTempoEvent): boolean;
begin  result :Stream.Read(TE, SizeOfTempoEvent) SizeOfTempoEvent;
end;











<hr size="2" width="100%" />

foxi : Bien joué mais ca fonctionne pas .
Messages postés
4202
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
13 juin 2020
37
ha ...

qu'est ce qui se passe ? ça plante ? le BPM est erroné ?

<hr size="2" width="100%" />

Re : Oui ca plante à la lecture. Le fichier est considéré comme éronné
Messages postés
4202
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
13 juin 2020
37
mmm ...

il faudrait editer en Hexa plusieur fichier Midi et voir comment est stocké l'evenement ...

peut etre que le MPQN est stocké dans un DWord et non dans un tableau de 3 bytes.

<hr size="2" width="100%" />

Ca avance, ca avance : ca plante plus, sauf que plus le tempo augmente plus le morceau est lent (hé hé ).

Merci à toi  : En fait il y avait 2 problèmes. Celui là et un autre : En fait tout message midi doit etre accompagné d'un temps (Delta Time) meme ce type de message : hors cela ne figurait nul part. En fait il y a bcp d'aneries   de dit sur le sujet ce qui fait que j'avance à taton.
Messages postés
4202
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
13 juin 2020
37
ah ben oui, ça parait logique puisqu'il faut bien savoir quand declancher l'evenement en question ...

au final c'est laquelle de solution qui marche ? la toute premiere ? ou en deuxieme 1 ou 2 ?

<hr size="2" width="100%" />

Désolé de répondre que maintenant (un concours sur le feu ) : solution2 validée et tout marche nickel .  Merci à toi et pardon pour le retard