Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

FORCER UNE GAMME MUSICALE EN MIDI


Information sur la source

Catégorie :Multimedia Classé sous : midi, gammes, transposition Niveau : Initié Date de création : 08/07/2008 Date de mise à jour : 10/07/2008 01:13:14 Vu : 2 007

Note :
10 / 10 - par 1 personne
10,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (3)
Ajouter un commentaire et/ou une note

Description

Ce code utilise un algorythme simple qui permet d'appliquer une transposition midi aux messages midi de types note on/note off.Il est utilisable dans le contexte d'un instruemnt vsti ou d'une application midi.
 

Source

  • type
  • TScale = array [0..11] of integer;
  • ====================================================================
  • Scale: TScale;
  • // les gammes courantes converties en table de transposition
  • // Db Eb Gb Ab Bb
  • const // C C# D D# E F F# G G# A A# B
  • Maj : TScale = ( 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0);
  • MinNat : TScale = ( 0, -1, 0, 0,-1, 0, -1, 0, -1, 0, 0,-1);
  • MinMelo: TScale = ( 0, -1, 0, 0,-1, 0, -1, 0, 0,-1, -1, 0);
  • MinHarm: TScale = ( 0, -1, 0, 0,-1, 0, -1, 0, 0,-1, 0,-1);
  • _7ThDom: Tscale = ( 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, 0,-1);
  • DoriMin: Tscale = ( 0, -1, 0, 0,-1, 0, -1, 0, -1, 0, 0,-1);
  • Locrian: Tscale = ( 0, 0,-1, 0,-1, 0, 0,-1, 0,-1, 0,-1);
  • Dim : TScale = ( 0, -1, 0, 0,-1, 0, 0,-1, 0, 0, -1, 0);
  • PentMaj: Tscale = ( 0, -1, 0, -1, 0,-1, -2, 0, -1, 0, -1,-2);
  • PentMin: Tscale = ( 0, -1,-2, 0,-1, 0, -1, 0, -1,-2, 0,-1);
  • Blues : Tscale = ( 0, -1,-2, 0,-1, 0, 0, 0, -1,-2, 0,-1);
  • DemiTT : Tscale = ( 0, -1, 0, -1, 0,-1, 0,-1, 0,-1, 0,-1);
  • TT : Tscale = ( 0, -1, 0, -1, 0,-1, 0,-1, 0,-1, 0,-1);
  • BBmaj : Tscale = ( 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0);
  • BBDom : Tscale = ( 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, 0, 0);
  • BBmin : TScale = ( 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0,-1);
  • Lydian : TScale = ( 0, -1, 0, -1, 0,-1, 0, 0, -1, 0, -1, 0);
  • LydDom : Tscale = ( 0, -1, 0, -1, 0,-1, 0, 0, -1, 0, 0,-1);
  • Augm : Tscale = ( 0, -1,-2, 0, 0,-1, -2, 0, 0,-1, -2, 0);
  • Phryg : TScale = ( 0, 0,-1, 0,-1, 0, -1, 0, 0,-1, 0,-1);
  • TFullD : Tscale = ( 0, 0,-1, 0, 0,-1, 0,-1, 0,-1, 0,-1);
  • ========================================================================
  • procedure processMIDI(time,status,channel,data1,data2:integer);
  • begin
  • if (Status=$90) or (Status=$80) then
  • begin // scale = pointer vers une des TScale déclarée en constante
  • n:= data1 mod 12; // détéction de la note courante quelque soit l'octave
  • n:= scale[n]+key; // key = dominante de la gamme , on ajoute la valeur de transposition
  • data1:= data1+n; // à la valeur initiale
  • end;
  • case status of
  • $80: MIDI_NoteOff(channel,data1,data2,0); // sortie midi spécifique au programme :
  • $90: MIDI_NoteOn(channel,data1,data2,0); // thru (in = out) sauf s'il faut transposer.
  • $A0: MIDI_PolyAftertouch(channel,data1,data2,0);
  • $B0: MIDI_CC(channel,data1,data2,0);
  • $C0: MIDI_ProgramChange(channel,data1,0);
  • $D0: MIDI_ChannelAftertouch(channel,data1,0);
  • $E0: MIDI_PitchBend2(channel,data1,data2,0);
  • end;
type
TScale  = array [0..11] of integer;

====================================================================

    Scale: TScale;

// les gammes courantes converties en table de transposition

                    //     Db     Eb        Gb     Ab     Bb
  const            //   C  C#  D  D#  E  F  F#  G  G#  A  A#  B
    Maj    : TScale = ( 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0);
    MinNat : TScale = ( 0, -1, 0,  0,-1, 0, -1, 0, -1, 0,  0,-1);
    MinMelo: TScale = ( 0, -1, 0,  0,-1, 0, -1, 0,  0,-1, -1, 0);
    MinHarm: TScale = ( 0, -1, 0,  0,-1, 0, -1, 0,  0,-1,  0,-1);
    _7ThDom: Tscale = ( 0, -1, 0, -1, 0, 0, -1, 0, -1, 0,  0,-1);
    DoriMin: Tscale = ( 0, -1, 0,  0,-1, 0, -1, 0, -1, 0,  0,-1);
    Locrian: Tscale = ( 0,  0,-1,  0,-1, 0,  0,-1,  0,-1,  0,-1);
    Dim    : TScale = ( 0, -1, 0,  0,-1, 0,  0,-1,  0, 0, -1, 0);
    PentMaj: Tscale = ( 0, -1, 0, -1, 0,-1, -2, 0, -1, 0, -1,-2);
    PentMin: Tscale = ( 0, -1,-2,  0,-1, 0, -1, 0, -1,-2,  0,-1);
    Blues  : Tscale = ( 0, -1,-2,  0,-1, 0,  0, 0, -1,-2,  0,-1);
    DemiTT : Tscale = ( 0, -1, 0, -1, 0,-1,  0,-1,  0,-1,  0,-1);
    TT     : Tscale = ( 0, -1, 0, -1, 0,-1,  0,-1,  0,-1,  0,-1);
    BBmaj  : Tscale = ( 0, -1, 0, -1, 0, 0, -1, 0,  0, 0, -1, 0);
    BBDom  : Tscale = ( 0, -1, 0, -1, 0, 0, -1, 0, -1, 0,  0, 0);
    BBmin  : TScale = ( 0, -1, 0,  0, 0, 0, -1, 0, -1, 0,  0,-1);
    Lydian : TScale = ( 0, -1, 0, -1, 0,-1,  0, 0, -1, 0, -1, 0);
    LydDom : Tscale = ( 0, -1, 0, -1, 0,-1,  0, 0, -1, 0,  0,-1);
    Augm   : Tscale = ( 0, -1,-2,  0, 0,-1, -2, 0,  0,-1, -2, 0);
    Phryg  : TScale = ( 0,  0,-1,  0,-1, 0, -1, 0,  0,-1,  0,-1);
    TFullD : Tscale = ( 0,  0,-1,  0, 0,-1,  0,-1,  0,-1,  0,-1);


========================================================================

procedure processMIDI(time,status,channel,data1,data2:integer);
begin
  if (Status=$90) or (Status=$80) then
    begin                // scale = pointer vers une des TScale déclarée en constante
      n:= data1 mod 12; // détéction de la note courante quelque soit l'octave
      n:= scale[n]+key; // key = dominante de la gamme , on ajoute la valeur de transposition
      data1:= data1+n;  // à la valeur initiale
    end;
  case status of
    $80: MIDI_NoteOff(channel,data1,data2,0);    // sortie midi spécifique au programme :
    $90: MIDI_NoteOn(channel,data1,data2,0);     // thru (in = out) sauf s'il faut transposer.
    $A0: MIDI_PolyAftertouch(channel,data1,data2,0);
    $B0: MIDI_CC(channel,data1,data2,0);
    $C0: MIDI_ProgramChange(channel,data1,0);
    $D0: MIDI_ChannelAftertouch(channel,data1,0);
    $E0: MIDI_PitchBend2(channel,data1,data2,0);
  end;

Historique

08 juillet 2008 01:56:37 :
ajout d'un fichier joint + petites corrections syntaxiques...
08 juillet 2008 01:58:19 :
correction orthographique dans le titre
10 juillet 2008 01:13:15 :
Suppression de l'entrée

Commentaires et avis

signaler à un administrateur
Commentaire de jackalunion le 10/07/2008 11:12:38 10/10

J'ai compris a quoi consitste cette procedure , elle est trés utile mais elle marche pas pour moi. mais ça mèrite

signaler à un administrateur
Commentaire de Francky23012301 le 10/07/2008 15:10:48

Salut,

Ca pourra aider certains mais quelques remarques:
*En Snippet cela aurait été mieux
*Pourquoi utiliser le type integer : status,channel,data1,data2 sont des bytes
*time ce n'est pas un integer : c'est légèrement plus complexe car il s'agit d'un type de longueur variable. Ton truc marchera pas dans bon nombres de cas

@Jack : Normal que ca ne fasse rien. L'entrée et la sortie Midi ne sont pas sélectionnée. Si tu veux un truc qui fonctionne :

unit MidiCom;

interface

uses
  Windows, SysUtils, Classes, MmSystem, Contnrs;

type

  TOnMidiInReceiveData = procedure(const Status, Data1, Data2: byte) of object;
  TOnMidiInBuffer      = procedure(const AStream: TMemoryStream) of object;

  TMidiCom = class(TComponent)
  private
    MidiIn:      THandle;
    MidiOut:     THandle;
    ResultCom:   MMResult;
    MidiInCount: integer;
    MidiOutCount: integer;
    fDataStream: TMemoryStream;
    fDataHeader: TMidiHdr;
    fExData:     array[0..2048] of char;
    fOnMidiInReceiveData: TOnMidiInReceiveData;
    fOnMidiInBuffer: TOnMidiInBuffer;
    procedure Send_MidiInBuffer;
    procedure Send(const AStream: TMemoryStream); overload;
    procedure Send(const AString: string); overload;
    procedure StrToStream(const AString: string; const AStream: TMemoryStream);
  protected
  public
    function Open_MidiIn(Index: integer): boolean;
    function Open_MidiOut(Index: integer): boolean;
    function Close_MidiIn: boolean;
    function Close_MidiOut: boolean;
    procedure MidiIn_List(AStrings: TStrings);
    procedure MidiOut_List(AStrings: TStrings);
    procedure SendData(Status, Data1, Data2: byte);
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property OnMidiInReceiveData: TOnMidiInReceiveData
      Read fOnMidiInReceiveData Write fOnMidiInReceiveData;
    property OnMidiInBuffer: TOnMidiInBuffer Read fOnMidiInBuffer Write fOnMidiInBuffer;
  end;

var
  AMidiCom: TMidiCom;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('MUSIC_PRO', [TMidiCom]);
end;

procedure MidiInCallBack(AMidiInHandle: PhMidiIn; aMsg: UInt;
  aData, aMidiData, aTimeStamp: integer); stdcall;
begin
  if AMsg = Mim_Data then
    if AMidiCom.MidiIn <> 0 then
      AMidiCom.OnMidiInReceiveData(aMidiData and $000000FF, (aMidiData and $0000FF00) shr
        8, (aMidiData and $00F0000) shr 16);
  if AMsg = Mim_LongData then
    AMidiCom.Send_MidiInBuffer;
end;

constructor TMidiCom.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  MidiInCount := -1;
  MidiOutCount := -1;
  MidiIn      := 0;
  MidiOut     := 0;
  fDataHeader.dwBufferLength := 2048;
  fDataHeader.lpData := fExData;
  fDataStream := TMemoryStream.Create;
  AMidiCom    := Self;
end;

destructor TMidiCom.Destroy;
begin
  fDataStream.Free;
  Close_MidiIn;
  Close_MidiOut;
  inherited;
end;

{>>ENTREE MIDI}

procedure TMidiCom.MidiIn_List(AStrings: TStrings);
var
  Index:  integer;
  InCaps: TMidiInCaps;
begin
  AStrings.Clear;
  for Index := 0 to (MidiInGetNumDevs - 1) do
  begin
    //On récupère les capacités de l'entrée Midi numéro Index
    ResultCom := MidiInGetDevCaps(Index, @InCaps, SizeOf(TMidiInCaps));
    if ResultCom = MmSysErr_NoError then
    begin
      AStrings.Add(InCaps.szPName);
      Inc(MidiInCount);
    end;
  end;
end;

function TMidiCom.Open_MidiIn(Index: integer): boolean;
begin
  Result := False;
  if (MidiInCount > -1) and (Index > -1) and (Index <= MidiInCount) then
  begin
    //Si l'entrée Midi a déjà été définit on sort
    if MidiIn <> 0 then
      Exit;
    //On ouvre l'entrée midi :  MidiInCallBack sera le callback utilisé pour récupérer les données recues
    ResultCom := MidiInOpen(@MidiIn, Index, cardinal(@MidiInCallBack),
      Index, CallBack_Function);
    if ResultCom = MmSysErr_NoError then
    begin
      fDataHeader.dwFlags := 0;
      //On prépare le buffer pour l'entrée Midi
      ResultCom := MidiInPrepareHeader(MidiIn, @fDataHeader, SizeOf(TMidiHdr));
      if ResultCom = MmSysErr_NoError then
      begin
        //On envoit un buffer d'entré dans l'entrée Midi
        ResultCom := MidiInAddBuffer(MidiIn, @fDataHeader, SizeOf(TMidiHdr));
        if ResultCom = MmSysErr_NoError then
        begin
          //On allume l'entrée Midi
          ResultCom := MidiInStart(MidiIn);
          if ResultCom = MmSysErr_NoError then
            Result := True;
        end;
      end;
    end;
  end;
end;

function TMidiCom.Close_MidiIn: boolean;
begin
  Result := False;
  if MidiIn = 0 then
    Exit;
  //On arrète l'entrée midi
  ResultCom := MidiInStop(MidiIn);
  if ResultCom = MmSysErr_NoError then
  begin
    //On détruit l'entrée Midi
    ResultCom := MidiInReset(MidiIn);
    if ResultCom = MmSysErr_NoError then
    begin
      //On nettoye le Buffer
      ResultCom := MidiInUnPrepareHeader(MidiIn, @fDataHeader, SizeOf(TMidiHdr));
      if ResultCom = MmSysErr_NoError then
        Result := True;
    end;
  end;
end;

procedure TMidiCom.Send_MidiInBuffer;
begin
  if fDataHeader.dwBytesRecorded = 0 then
    Exit;
  fDataStream.Write(fExData, fDataHeader.dwBytesRecorded);
  if fDataHeader.dwFlags and MHdr_Done = MHdr_Done then
  begin
    fDataStream.Position := 0;
    fOnMidiInBuffer(fDataStream);
    fDataStream.Clear;
  end;
  fDataHeader.dwBytesRecorded := 0;
  //On prépare le buffer pour l'entrée Midi
  ResultCom := MidiInPrepareHeader(MidiIn, @fDataHeader, SizeOf(TMidiHdr));
  if ResultCom = MmSysErr_NoError then
  begin
    //On envoit un buffer d'entré dans l'entrée Midi
    ResultCom := MidiInAddBuffer(MidiIn, @fDataHeader, SizeOf(TMidiHdr));
  end;
end;


{>>SORTIE MIDI}

procedure TMidiCom.MidiOut_List(AStrings: TStrings);
var
  Index:   integer;
  OutCaps: TMidiOutCaps;
begin
  AStrings.Clear;
  for Index := 0 to (MidiOutGetNumDevs - 1) do
  begin
    //On récupère les capacités de la sortie Midi numéro Index
    ResultCom := MidiOutGetDevCaps(Index, @OutCaps, SizeOf(TMidiOutCaps));
    if ResultCom = MmSysErr_NoError then
    begin
      AStrings.Add(OutCaps.szPName);
      Inc(MidiOutCount);
    end;
  end;
end;

function TMidiCom.Close_MidiOut: boolean;
begin
  Result    := False;
  ResultCom := MidiOutClose(MidiOut);
  if ResultCom = MmSysErr_NoError then
    Result := True;
end;

function TMidiCom.Open_MidiOut(Index: integer): boolean;
begin
  Result := False;
  if (MidiOutCount > -1) and (Index > -1) and (Index <= MidiOutCount) then
  begin
    if MidiOut <> 0 then
      Exit;
    //Ouverture de la sortie Midi
    ResultCom := MidiOutOpen(@MidiOut, Index, 0, 0, CallBack_Null);
    if ResultCom = MmSysErr_NoError then
      Result := True;
  end;
end;

procedure TMidiCom.SendData(Status, Data1, Data2: byte);
var
  AMsg: cardinal;
begin
  if MidiOut = 0 then
    Exit;
  AMsg      := Status + (Data1 * $100) + (Data2 * $10000);
  //On envoit le message à la sortie Midi
  ResultCom := MidiOutShortMsg(MidiOut, AMsg);
end;

procedure TMidiCom.Send(const AString: string);
var
  AStream: TMemoryStream;
begin
  AStream := TMemoryStream.Create;
  try
    StrToStream(AString, AStream);
    Send(AStream);
  finally
    AStream.Free;
  end;
end;

procedure TMidiCom.Send(const AStream: TMemoryStream);
var
  ADataHeader: TMidiHdr;
begin
  AStream.Position := 0;
  ADataHeader.dwBufferLength := AStream.Size;
  ADataHeader.lpData := AStream.Memory;
  ADataHeader.dwFlags := 0;
  //Préparation de la zone tambon pour la sortie Midi
  ResultCom := MidiOutPrepareHeader(MidiOut, @ADataHeader, SizeOf(TMidiHdr));
  if ResultCom = MmSysErr_NoError then
  begin
    //On envoit le message à la sortie Midi
    ResultCom := MidiOutLongMsg(MidiOut, @ADataHeader, SizeOf(TMidiHdr));
    if ResultCom = MmSysErr_NoError then
      //On nettoye le Buffer
      ResultCom := MidiOutUnPrepareHeader(MidiOut, @ADataHeader, SizeOf(TMidiHdr));
  end;
end;

procedure TMidiCom.StrToStream(const AString: string; const AStream: TMemoryStream);
const
  HexChar = '123456789ABCDEF';
var
  Index: integer;
  Str:   string;
begin
  Str := StringReplace(AnsiUpperCase(AString), '  ', '', [rfReplaceAll]);
  AStream.Position := 0;
  for Index := 1 to (Length(Str) div 2 - 1) do
    PChar(AStream.Memory)[Index - 1] :=
      char(AnsiPos(Str[Index * 2 - 1], HexChar) shl 4 + AnsiPos(Str[Index * 2], HexChar));
end;

L'idée est cependant louable ;).

signaler à un administrateur
Commentaire de dirk le 12/04/2009 11:48:04

Le code présenté est basé sur le template VST de Tobybear. Hors dece cadre,  en effet ça ne veut pas dire grand-chose.

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

Piano midi [ par sebrs1 ] Comment faire pour jouer des ons de piano en midi?@+Sebrs1PS (qui ne signifie pas playstation :-)) : visitez mon site qui fait ses début svphttp://pro MIDI files [ par magic123 ] Salut tout le monde, J'aurais besoin d'informations pour savoir comment faire pour lire et décoder un midi file, ceci afin d'effectuer quelques modifi Insérer un fichier Midi sous Delphi [ par frutygirls ] Bonjour ! Nous avons un TP à faire en cours et nous souhaitons y ajouter un fond musical, mais nous galèrons ! Nous avons commencé à insérer un objet Fichiers Midi - Bug avec la longueur des chemins ? [ par Udun ] J'ai rencontr&#233; une erreur bizarre dans Delphi. En effet, avec le composantMediaPlayer, je lisais des fichiers midi et j'ai rencontr&#233; l'erreu Port Jeux (MIDI) avec WinXP [ par PHIL63 ] Bonjour &#224; tous,J'aurais besoin dans une application, de pouvoir d&#233;tecter si il y a un appuie sur le bouton feu du port joystick (c'est pas p MIDI [ par Nicolas___ ] Voila , hier j'ai telecharg&#233; un logicile excellent TS-AudioToMIDI disponible sur www.Telecharger.com&nbsp;le but &#233;tant ,pour ceux qui ne l'a Midi : Testeurs pour un composant [ par Francky23012301 ] Salut  à tous,Je viens de faire un composant TMidiCom (Com c'est pour communication ) dont le but est de communiquer avec un appareil midi comme un sy SoundFont [ par Francky23012301 ] Salut à tous,Je suis entrain de faire un soft avec le protocole Midi. J'ai voulu utiliser la dll Bass mais à force de décortiquer cette Dll admet pas Stratégie pour décaler des bits [ par Francky23012301 ] Salut la compagnie ,Je travaille sur les fichiers midi : les évènements midi utilisent un paramètre qui est un DeltaTime et qui peut (et doit ) codé s Problème sur routines de WinMM.dll, gestion de Midi [ par Bacterius ] Bonsoir,je voudrais pouvoir jouer un son midi sans media player.J'ai trouvé sur MSDN quelques infos interessantes dans la DLL WinMM.dll ...mais je ne


Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,827 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.