[Ada] Problème avec Pm_Read de la bibliothèque portmidi

Problème avec Pm_Read de la bibliothèque portmidi [Ada] - Ada - Programmation

Marsh Posté le 23-10-2012 à 06:27:33    

Bonjour,
 
 
D'abord merci de me permettre de dire un mot sur ce sujet.
 
J'ai un problème avec la fonction Pm_Read de portmidi qui renvoie PmHostError .
 
Je vous fait le topo... j'essaie de lire deux flux MIDI (Master_Keyboard et Synt_In)
 
j'ai un paquet "devices" dont dépend un paquet "drivers" dont dépend un paquet Scheduler.
Le main dépend des trois.
Dans devices, je fait appel à Pm_Read de la bibliothèque portmidi dont j'ai fait un binding Ada.
 
Le prototype de la fonction Pm_Read est le suivant :
 

Code :
  1. int Pm_Read( PortMidiStream *stream, PmEvent *buffer, int32_t length );


 
Voici mon import.

Code :
  1. type PmEvent is
  2.      record
  3.         Message : Interfaces.C.Long := 0;
  4.         PmTimestamp : Interfaces.C.Long := 0;
  5.      end record;
  6.      
  7.  
  8.   type Pmevent_Access is access all Pmevent;
  9.  
  10.   Function Pm_Read(PortMidiStream : System.Address;            
  11.             Pm_Event : PmEvent_access;
  12.             length : Interfaces.C.Long) return PmError ;
  13.   pragma Import (C, Pm_Read, "Pm_Read" );


Tout ça fonction très bien habituellement, mais là, je sèche.
 
Peut-être un appel à Pm_Initialize mal placé ?
 
 
Bon, désolé pour le code, mais il faut ce qu'il faut.
 
 
 
Main file.

Code :
  1. with Text_Io;
  2. use Text_Io;
  3.  
  4. with Np.Midi.Devices, Np.Midi.Drivers, Np.Midi.Scheduler;
  5. use Np.Midi;
  6. procedure Main is
  7.  
  8.   Master_device : aliased Devices.Device_Type;
  9.   Synth_in_Device : aliased Devices.Device_Type;
  10.   Synth_Out_Device : aliased Devices.Device_Type;
  11. begin
  12.   Text_Io.Put_line("Enter device ID of Synth Out :" );
  13.   Devices.Initialize(Synth_Out_Device, Devices.MIDI_Out);
  14.   New_Line;
  15.   Text_Io.Put_line("Enter device ID of Master Keyboard :" );
  16.   Devices.Initialize(Master_Device, Devices.MIDI_In);
  17.   New_Line;
  18.   Text_Io.Put_line("Enter device ID of Synth In :" );
  19.   Devices.Initialize(Synth_In_Device, Devices.MIDI_In);
  20.   New_Line;
  21.   Text_Io.Put("Open all devices..." );
  22.   Devices.Open(Synth_Out_Device);
  23.   Devices.Open(Master_Device);
  24.   Devices.Open(Synth_In_Device);
  25.   Text_Io.Put_line(" Done." );
  26.  
  27.   declare
  28.      
  29.      Master_Driver : access Drivers.InputDriver_Type := new Drivers.InputDriver_Type(Master_Device'Access);      
  30.      Synth_In_Driver : access Drivers.InputDriver_Type := new Drivers.InputDriver_Type(Synth_In_Device'Access);
  31.      Synth_Out_Driver : access Drivers.OutputDriver_Type := new Drivers.OutputDriver_Type(Synth_Out_Device'Access);
  32.      
  33.   begin
  34.      
  35.      declare
  36.      The_Sched : Scheduler.Scheduler_Type(Master_Driver, Synth_In_Driver, Synth_Out_Driver);
  37.      begin
  38.      null;
  39.      end;            
  40.   end;
  41.   New_Line;
  42.   Text_Io.Put("Close all devices..." );
  43.   Devices.Close(Synth_Out_Device);            
  44.   Devices.Close(Master_Device);
  45.   Devices.Close(Synth_In_Device);
  46.   Text_Io.Put_line(" Done." );
  47. end Main;


 
 
Devices (Specification)

Code :
  1. with Portmidi, Porttime;
  2. use Portmidi, Porttime;
  3. with System;
  4.  
  5. package Np.Midi.Devices is
  6.  
  7.   pragma Elaborate_Body(Np.Midi.Devices);
  8.  
  9.  
  10.   type Device_Type is private;
  11.   type Mode_Type is (MIDI_In, MIDI_Out);
  12.   procedure Initialize (Device : in out Device_Type; Mode : in Mode_Type);
  13.   function  Initialized(Device : in     Device_Type) return Boolean;
  14.   procedure Open       (Device : in out Device_Type);
  15.   procedure Write      (Device : in     Device_Type; Message : in C.Long);
  16.   procedure Read       (Device : in     Device_Type; Message : out C.Long);
  17.   procedure Close      (Device : in out Device_Type);
  18.   function Name(Device : in Device_Type) return String;
  19.   Mode_Error      : exception;
  20.   Status_Error    : exception;
  21.   Not_Initialized : exception;      
  22. private
  23.  
  24.   type Device_Type is
  25.      record
  26.      Initialized    : Boolean := False;
  27.      Mode           : Mode_Type;
  28.      Id             : Integer;
  29.      Addr           : access System.Address;
  30.      The_Deviceinfo : access Portmidi.DeviceInfo;
  31.      end record;
  32.  
  33.  
  34.  
  35. end Np.Midi.Devices;


Devices (Implementation)

Code :
  1. with Ada.Integer_Text_Io;
  2. with Ada.Text_Io;
  3. use Ada;
  4. package body Np.Midi.Devices is
  5.  
  6.   use ErrorText_Conversion, DeviceInfo_Conversion;
  7.   procedure Initialize (Device : in out Device_Type; Mode : in Mode_type) is
  8.      
  9.   begin
  10.      case Mode is
  11.      when MIDI_Out =>
  12.         Device.The_DeviceInfo := new Portmidi.DeviceInfo;
  13.         Device.Addr := new System.Address;
  14.         loop
  15.            begin        
  16.           Text_Io.Put_Line("Select output device :" );
  17.           Text_Io.Put_Line("ID, Name" );
  18.           for I in 0..Portmidi.Pm_CountDevices-1 loop
  19.              declare
  20.             Name : Portmidi.T_ErrorText;
  21.              begin
  22.             Device.The_DeviceInfo.all :=
  23.               To_pointer(Portmidi.Pm_GetDeviceInfo(I)).all;
  24.             if Device.The_Deviceinfo.Output = 1 then
  25.                Name := To_Pointer(Device.The_Deviceinfo.name).all;
  26.                Text_Io.Put_Line(Integer'Image(I) & ", " & Interfaces.C.To_Ada(Name));
  27.             end if;
  28.              end;
  29.           end loop;
  30.           Text_Io.Put("Entre device ID : " );
  31.           Integer_Text_Io.Get(Device.Id);
  32.           Device.The_DeviceInfo.all :=
  33.             To_pointer(Portmidi.Pm_GetDeviceInfo(Device.id)).all;
  34.           if Device.The_Deviceinfo.Output = 1 Then
  35.              declare
  36.             Name : Portmidi.T_ErrorText;
  37.              begin
  38.             Device.Initialized := True;
  39.             
  40.             Device.Mode := MIDI_Out;
  41.             Name := To_Pointer(Device.The_Deviceinfo.name).all;
  42.             Text_Io.Put_Line("Your selected device :" );
  43.             Text_Io.Put(Interfaces.C.To_Ada(Name));        
  44.              end;
  45.              exit;
  46.           else
  47.              Text_Io.Put_Line("!! ********************** !!" );
  48.              Text_Io.Put_Line("!! Device not initialized !!" );
  49.              Text_Io.Put_Line("!! ********************** !!" );
  50.           end if;
  51.           
  52.            exception
  53.           when Text_Io.End_Error =>
  54.              return;
  55.            end;
  56.         end loop;            
  57.      when MIDI_In =>
  58.         Device.The_DeviceInfo := new Portmidi.DeviceInfo;
  59.         Device.Addr := new System.Address;
  60.  
  61.         loop
  62.            begin        
  63.           Text_Io.Put_Line("Select input device :" );
  64.           Text_Io.Put_Line("ID, Name" );
  65.           for I in 0..Portmidi.Pm_CountDevices-1 loop
  66.              declare
  67.             Name : Portmidi.T_ErrorText;
  68.              begin
  69.             Device.The_DeviceInfo.all :=
  70.               To_pointer(Portmidi.Pm_GetDeviceInfo(I)).all;
  71.             if Device.The_Deviceinfo.Input = 1 then
  72.                Name := To_Pointer(Device.The_Deviceinfo.name).all;
  73.                Text_Io.Put_Line(Integer'Image(I) & ", " & Interfaces.C.To_Ada(Name));
  74.             end if;
  75.              end;
  76.           end loop;
  77.           Text_Io.Put("Entre device ID : " );
  78.           Integer_Text_Io.Get(Device.Id);
  79.           Device.The_DeviceInfo.all :=
  80.             To_pointer(Portmidi.Pm_GetDeviceInfo(Device.id)).all;
  81.           if Device.The_Deviceinfo.Input = 1 Then
  82.              declare
  83.             Name : Portmidi.T_ErrorText;
  84.              begin            
  85.             Device.Initialized := True;
  86.             Device.Mode := MIDI_In;
  87.             Name := To_Pointer(Device.The_Deviceinfo.name).all;
  88.             Text_Io.Put_Line("Your selected device :" );
  89.             Text_Io.Put(Interfaces.C.To_Ada(Name));        
  90.              end;
  91.              exit;
  92.           else
  93.              Text_Io.Put_Line("!! ********************** !!" );
  94.              Text_Io.Put_Line("!! Device not initialized !!" );
  95.              Text_Io.Put_Line("!! ********************** !!" );
  96.           end if;
  97.           
  98.            exception
  99.           when Text_Io.End_Error =>
  100.              return;
  101.            end;
  102.         end loop;            
  103.      end case;
  104.   end Initialize;
  105.      
  106.   function  Initialized(Device : in     Device_Type) return Boolean is
  107.   begin
  108.      return Device.Initialized;
  109.   end Initialized;
  110.  
  111.   procedure Open       (Device : in out Device_Type) is
  112.      
  113.      Pm_Error   : PmError;
  114.      Time_Proc  : Porttime.Time_Access := Pt_Time'Access;
  115.      Time_Info  : System.Address;
  116.      latency    : Long_Integer := 0;      
  117.   begin
  118.      case Device.Mode is
  119.     
  120.      when MIDI_In =>
  121.         Pm_Error := Pm_OpenInput(Device.Addr, Device.Id, Device.The_DeviceInfo,
  122.                      128, Time_Proc, Time_Info);
  123.      when MIDI_Out =>
  124.         
  125.         Pm_Error := Pm_OpenOutput(Device.Addr, Device.Id, Device.The_DeviceInfo,
  126.                       0, Time_Proc, Time_Info, Latency);
  127.      end case;
  128.   end Open;
  129.  
  130.  
  131.   procedure Write      (Device : in     Device_Type; Message : in C.Long) is
  132.      
  133.      Pm_Error : PmError;
  134.      Pm_Event : PmEvent := (Message, 0);
  135.   begin
  136.      if not Device.Initialized then
  137.      raise Not_Initialized;
  138.      end if;
  139.      if Device.Mode /= MIDI_Out then
  140.      raise Mode_Error;
  141.      end if;      
  142.      Pm_Error := Pm_Write(Device.Addr.all, Pm_Event, 1);
  143.   end Write;
  144.  
  145.   procedure Read       (Device : in     Device_Type; Message : out C.Long) is
  146.      Pm_Error : PmError := PmNoError;
  147.      Pm_Event : PmEvent_Access := new PmEvent;
  148.   begin
  149.      if not Device.Initialized then
  150.      raise Not_Initialized;
  151.      end if;
  152.      if Device.Mode /= MIDI_In then
  153.      raise MODE_Error;
  154.      end if;
  155.      Pm_Error := Pm_SetFilter(Device.Addr.all, Pm_Filt_Active or Pm_Filt_Clock);
  156.      Pm_Error := Pm_Read(Device.Addr.All, Pm_Event, 1);            
  157.      case Pm_Error is
  158.      when PmNoError =>        
  159.         Message := Pm_Event.Message;                        
  160.      when others =>
  161.         Text_Io.Put(PmError'Image(Pm_Error));
  162.         raise Constraint_Error;
  163.      end case;    
  164.   end Read;
  165.  
  166.  
  167.   procedure Close      (Device : in out Device_Type) is
  168.      Pm_Error : PmError;
  169.   begin      
  170.      Pm_Error := Pm_Close(Device.Addr.all);      
  171.   end Close;
  172.  
  173.   function Name(Device : in Device_Type) return String is
  174.   begin
  175.      return C.To_Ada(To_Pointer(Device.The_Deviceinfo.name).all);
  176.   end Name;
  177.   Pm_Error : PmError;
  178. begin      
  179.   Pm_Error := Pm_Initialize;
  180. end Np.Midi.Devices;


Drivers (Specification)

Code :
  1. with Np.Midi.Devices;
  2. use Np.Midi.Devices;
  3. package Np.Midi.Drivers is
  4.   task type InputDriver_Type(Device : access Device_Type) is
  5.      entry Send(Message : out C.Long);
  6.   end InputDriver_Type;  
  7.  
  8.   protected type OutputDriver_Type(Device : access Device_Type) is
  9.      entry Receive(Message : in C.Long);
  10.   end OutputDriver_Type;
  11.  
  12. end Np.Midi.Drivers;


Drivers (Implementation)

Code :
  1. ackage body Np.Midi.Drivers is  
  2.  
  3.   task body InputDriver_Type is            
  4.      
  5.  
  6.   begin
  7.      
  8.      loop
  9.      declare
  10.         The_Message : C.Long;
  11.  
  12.      begin
  13.              Read(Device.all, The_Message);
  14.         select
  15.            when C."/=" (The_Message, 0) =>
  16.           accept Send(Message : out C.Long) do
  17.              Message := The_Message;
  18.           end Send;    
  19.         else
  20.            delay 0.001;
  21.         end select;
  22.  
  23.      exception
  24.         when Constraint_Error =>
  25.            null;
  26.      end;
  27.      end loop;      
  28.   end InputDriver_Type;
  29.  
  30.  
  31.   protected body OutputDriver_Type is
  32.      
  33.      entry Receive(Message : in C.Long) when True is
  34.      begin
  35.     
  36.      Write(Device.all, Message);
  37.      end Receive;
  38.   end OutputDriver_Type;
  39. end Np.Midi.Drivers;


 
Scheduler (Specification)

Code :
  1. with Np.Midi.Drivers;
  2. use Np.Midi.Drivers;
  3.  
  4. package Np.Midi.Scheduler is
  5.  
  6.  
  7.   task type Scheduler_Type(Master_Keyboard : access InputDriver_Type;
  8.                 Synth_Input     : access InputDriver_Type;
  9.                 Synth_Output    : access outputDriver_Type) is
  10.      entry Start;
  11.      entry Stop;
  12.   private
  13.      entry Receive(Message : in C.Long);
  14.   end Scheduler_Type;
  15.  
  16.  
  17.  
  18.  
  19.  
  20. end Np.Midi.Scheduler;


Scheduler (Implementation)

Code :
  1. with Text_Io;
  2. use Text_Io;
  3. package body Np.Midi.Scheduler is
  4.  
  5.  
  6.   task body Scheduler_Type is
  7.                  
  8.      task Synth_Input_Deamon is    
  9.      end Synth_Input_Deamon;
  10.      
  11.      task body Synth_Input_Deamon is
  12.      Message : C.Long;
  13.      begin
  14.      loop
  15.         Synth_Input.Send(Message);
  16.         Receive(Message);
  17.      end loop;
  18.      end Synth_Input_Deamon;
  19.      
  20.      task Master_Keyboard_Deamon is    
  21.      end Master_Keyboard_Deamon;
  22.      
  23.      task body Master_Keyboard_Deamon is
  24.      Message : C.Long;
  25.      begin
  26.      loop
  27.         Master_Keyboard.Send(Message);
  28.         Receive(Message);
  29.      end loop;
  30.      end Master_Keyboard_Deamon;                                                                          
  31.      
  32.   begin  
  33.      
  34.      loop    
  35.     
  36.      select
  37.         
  38.         accept Start;
  39.      or
  40.         
  41.         accept Stop;              
  42.      or
  43.         accept Receive(Message : in C.Long) do
  44.            Text_Io.Put_line(C.Long'Image(Message));
  45.         end Receive;
  46.      end select;
  47.      end loop;
  48.   end Scheduler_Type;      
  49. end Np.Midi.Scheduler;


 
 
 
 
Merci de votre lecture, et pour vos réponses.


Message édité par Profil supprimé le 23-10-2012 à 06:52:46
Reply

Marsh Posté le 23-10-2012 à 06:27:33   

Reply

Marsh Posté le 23-10-2012 à 11:23:49    

Je ne sais pas si c'est vraiment correct, mais j'ai apporter quelque modification à Read à l'image d'un exemple C

Code :
  1. procedure Read       (Device : in     Device_Type; Message : out C.Long) is
  2.         Pm_Error : PmError := PmNoError;
  3.         Pm_Event : PmEvent_Access := new PmEvent;
  4.      begin
  5.         if not Device.Initialized then
  6.         raise Not_Initialized;
  7.         end if;
  8.         if Device.Mode /= MIDI_In then
  9.         raise MODE_Error;
  10.         end if;
  11.         loop
  12.            Pm_Error := Pm_Poll(Device.Addr.all);
  13.            case  Pm_Error is
  14.               when Pmnoerror =>
  15.                  exit;
  16.               when others =>
  17.                  Pm_Error := Pm_Read(Device.Addr.All, Pm_Event, 1);                                      
  18.            end case;
  19.            delay 0.00001;          
  20.         end loop;
  21.            
  22.         loop
  23.            Pm_Error := Pm_Poll(Device.Addr.all);
  24.            case Pm_Error is                          
  25.               when Pmnoerror =>
  26.                  null;
  27.               when others =>
  28.                  Pm_Error := Pm_Read(Device.Addr.All, Pm_Event, 1);          
  29.                  case Pm_Error is                            
  30.                     when Pmnoerror =>
  31.                        null;
  32.                     when others =>
  33.                        Message := Pm_Event.Message;                        
  34.                        exit;
  35.                  end case;
  36.            end case;
  37.            delay 0.00001;          
  38.         end loop;              
  39.        
  40.      end Read;


 
Pour les delay je suis pas certain, mais ça a l'air important.

Message cité 1 fois
Message édité par Profil supprimé le 23-10-2012 à 11:25:08
Reply

Marsh Posté le 04-11-2012 à 12:24:12    


 
 
 
Personne dit mieux que ce code, qui me pose des problèmes.

Reply

Marsh Posté le 05-11-2012 à 11:25:42    

Salutation,
 
J'ai viré le premier délais, et dans le second, il faudrait a priori mettre 50microseconde.
Je vous laisse compter les zéro.

Reply

Marsh Posté le 07-11-2012 à 11:31:52    

Ce foutu Gate qui marche pas entre autres.  :heink:

Reply

Marsh Posté le 07-11-2012 à 13:52:21    

Rho ! Ce serait le main qu'il fallait modifier, je teste plus longuement mais... Ca vient peut-être d'ailleurs donc.
 

Reply

Marsh Posté le 07-11-2012 à 15:29:19    

Rha allah Dieu YHWH c'est encore pas ça....  :cry:  
 
Bon, j'en suis la pour la postérité, le meilleur code que j'ai.
 

Code :
  1. procedure Read       (Device : in     Device_Type; Message : out C.Long) is
  2.      Pm_Error : PmError := PmNoError;
  3.      Pm_Event : PmEvent_Access := new PmEvent;
  4.      
  5.   begin    
  6.      if not Device.Initialized then
  7.         raise Not_Initialized;
  8.      end if;
  9.      if Device.Mode /= MIDI_In then
  10.         raise MODE_Error;
  11.      end if;
  12.      Message := 0;
  13.      delay 0.01;
  14.      loop
  15.         Pm_Error := Pm_Poll(Device.Addr.all);          
  16.         if Pm_Error /= PmNoError then
  17.            Pm_Error := Pm_Read(Device.Addr.All, Pm_Event, 1);                                                            
  18.      
  19.         else
  20.            exit;
  21.         end if;
  22.      end loop;    
  23.      loop
  24.         Pm_Error := Pm_Poll(Device.Addr.all);                  
  25.         if Pm_Error /= Pmnoerror  then                    
  26.            Pm_Error := Pm_Read(Device.Addr.All, Pm_Event, 1);          
  27.            if Pm_Error /= Pmnoerror then
  28.               Message := Pm_Event.Message;                              
  29.               return;
  30.            end if;      
  31.         end if;      
  32.         delay 0.005;
  33.      end loop;
  34.      end Read;


 
C'est techniquement le même que l'original, mais avec un delay de 0.01 seconde en tête d'algo.

Reply

Marsh Posté le 07-11-2012 à 16:28:50    

Du coup même vous pouvez mettre 0.05.
Voilà, j'espère que sept fois sera la bonne.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed