Este foro usa cookies
Este foro utiliza cookies para almacenar su información de inicio de sesión si está registrado y su última visita si no lo está. Las cookies son pequeños documentos de texto almacenados en su computadora; las cookies establecidas por este foro solo se pueden usar en este sitio web y no representan ningún riesgo de seguridad. Las cookies en este foro también rastrean los temas específicos que ha leído y la última vez que los leyó. Si Ud. continúa navegando, entenderemos que acepta todas las cookies.

Se almacenará una cookie en su navegador, independientemente de la elección, para evitar que se le vuelva a hacer esta pregunta. Podrá cambiar la configuración de sus cookies en cualquier momento utilizando el enlace en el pie de página.

El foro antiguo se encuentra accesible desde https://foro.gambas-es.org en modo de solo lectura.

Calificación:
  • 1 voto(s) - 5 Media
  • 1
  • 2
  • 3
  • 4
  • 5

Interconectar un programa Gambas a otro a través ALSA para enviar datos MIDI
#1
Music 

INTERCONECTAR UN PROGRAMA GAMBAS A OTRA APLICACION A TRAVÉS ALSA PARA ENVIAR DATOS MIDI

Quid est A.L.S.A. ?

ALSA (Advanced Linux Sound Architecture) es un componente del kernel que sustituye al original Open Sound System (OSS) utilizado para proporcionar driver de dispositivo para tarjetas de audio.
Además de los driver de audio, ALSA también ofrece una libreria en espacio-usuario para desarrolladores de aplicaciones que deseen utilizar las funciones de los driver a través de una API en lugar de una interacción directa con los driver del kernel.


Es posible enviar datos Midi desde una aplicación a otra aplicación a través ALSA. De misma manera una aplicación puede rebir datos Midi de otros aplicaciones.
Para ello, las aplicaciones que deseen intercambiar datos Midi deben conectarse al ALSA, y en particolar al sub-sistema de ALSA que gestiona el Midi: la "Interfaz Sequencer".
Las aplicaciones, por lo tanto, se convierten en "Client" de ALSA, que representa su "Server".

 APLICACIÓN-Client_A ---> A L S A <--- APLICACIÓN-Client_B

Así, si se pretende realizar una aplicación Midi que debe relacionarse con ALSA, será necesario que se conciba en primer lugar como "Client" Midi de ALSA.
ALSA sólo se ocupa de programar eventos Midi y enviarlos al destino en el momento adecuado. Todo el procesamiento de eventos MIDI tiene que hacerse dentro de los Clientes.
En efecto la interfaz de ALSA está diseñada para ofrecer eventos MIDI entre los Clientes/Puertos.


USAR EN GAMBAS LOS RECURSOS DE ALSA

Gambas, por ahora, no tiene un su Componente para gestionar directamente los recursos del sistema de sonido ALSA.
Es posible, pero, usar las funciones externas del API de ALSA, invocando su libreria:
 Library "libasound:2"

A continuación, cada una de las funciones externas de ALSA se declarará con EXTERN, para que puedan utilizarse en las rutinas.


CREAR UN CLIENT DE ALSA

Para crear una aplicación, que se relaciona con el ALSA como su "Client", se necesitan varias fases de desarrollo.

El API de ALSA proporciona una función específica para crear un ''Client'' Midi de ALSA:
 int snd_seq_open (snd_seq_t ** seqp, const char * name, int streams, int mode)

Esta función será declarada en Gambas:
 Private Extern snd_seq_open(seqp As Pointer, name As String, streams As Integer, mode As Integer) As Integer

Donde:
- "seqp" es un handle al sub-sistema "Sequencer" de ALSA;
- "name" es en nombre del dispositivo de sonido;
- "streams" establece la gestión de datos Midis del sub-sistema "Sequencer" de ALSA;
- "mode" que hará que las operaciones de lectura/escritura bloqueen o no bloqueen.


DAR UN NOMBRE AL "CLIENT"

Si lo desea, es posible asignar un nombre al "Client" que estamos creando.

El API de ALSA proporciona una función específica para eso:
 int snd_seq_set_client_name(snd_seq_t *seq, const char *name)

Esta función será declarada en Gambas:
 Private Extern snd_seq_set_client_name(seq As Pointer, name As String) As Integer


OBTENER EL NUMERO DE IDENTIFICACION DEL "CLIENT"

Para obtener el número de identificación del nuestro "Client", ALSA proporciona esta función:
 int snd_seq_client_id(snd_seq_t *seq)

que será declarada en Gambas:
 Private Extern snd_seq_client_id(seq As Pointer) As Integer


CREACION DEL PUERTO DEL "CLIENT" Y SU CAPACIDAD

Hemos dicho que una aplicación-Client de ALSA envia o recibe datos Midi desde otras aplicaciones-Client a través ALSA (más precisamente a través un sub-sistema de ALSA adecuado para el tipo de datos enviados).
Un "Client" envia o recibe datos mediante una o más sus Puertos.
Cada Puerto del "Client" tiene su particular "Capacidad"; es decir que puede solo ser "Leído" (READ) o solo ser "Escrito" (WRITE), o ambas (DUPLEX).
ATENCIÓN: la definición de la "Capacidad " ("READ", "WRITE" o "DUPLEX") del Puerto de un Client debe considerarse siempre "desde el punto de vista del otro Client " de ALSA, al que el nuestro Client desea conectarse.
Por lo tanto, si configuramos - por ejemplo - la "Capacidad" del puerto del nuestro Client a READ (en lectura), significa que el otro Client, al que el nuestro Cliente se conecta, podrá "leer" los datos desde el Puerto de nuestro Client. En este caso el nuestro Client sólo puede escribir (enviar) datos a su propio puerto.
Es decir, en este caso, si la Capacidad del Puerto del nuestro Client es "READ", el nuestro Client puede escibir (es decir "enviar") datos Midi a su Puerto y un otro Client (al que el nuestro està conectado) puede LEER (es decir "recibir") aquellos datos Midi desde el Puerto de nuestro Client.

Para establecer la capacidad de un puerto del Client, que estamos creando, utilizamos las siguientes Constantes de ALSA:
 SND_SEQ_PORT_CAP_READ
 SND_SEQ_PORT_CAP_WRITE
 SND_SEQ_PORT_CAP_DUPLEX

Para crear un Puerto del Client, se usa esta función:
 int snd_seq_create_simple_port(snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)

que será declarada en Gambas:
 Private Extern snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer


EJEMPLO PRACTICO

Vamos a crear ahora una muy simple aplicación-Client con su Puerto con capacidad "READ":
GAMBAS
  1. Library "libasound:2"
  2.  
  3. Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
  4. Private Const SND_SEQ_PORT_CAP_READ As Integer = 1
  5. Private Const SND_SEQ_PORT_CAP_SUBS_READ As Integer = 32
  6. Private Const SND_SEQ_PORT_TYPE_MIDI_GENERIC As Integer = 2
  7. Private Const SND_SEQ_PORT_TYPE_APPLICATION As Integer = 1048576
  8.  
  9. ' int snd_seq_open (snd_seq_t **handle, const char * name, int streams, int mode)
  10. ' Open the ALSA sequencer.
  11. Private Extern snd_seq_open(handle As Pointer, name As String, streams As Integer, mode As Integer) As Integer
  12.  
  13. ' int snd_seq_set_client_name (snd_seq_t *seq, const char *name)
  14. ' Set client name.
  15. Private Extern snd_seq_set_client_name(seq As Pointer, name As String) As Integer
  16.  
  17. ' int snd_seq_client_id (snd_seq_t *handle)
  18. ' Get the client id.
  19. Private Extern snd_seq_client_id(handle As Pointer) As Integer
  20.  
  21. ' int snd_seq_create_simple_port (snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)
  22. ' Create a port - simple version.
  23. Private Extern snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer
  24.  
  25. ' const char* snd_strerror (int errnum)
  26. ' Returns the message for an error code.
  27. Private Extern snd_strerror(errnum As Integer) As String
  28.  
  29. ' int snd_seq_close (snd_seq_t *handle)
  30. ' Close the sequencer.
  31. Private Extern snd_seq_close(handle As Pointer) As Integer
  32.  
  33.  
  34. Public Sub Main()
  35.  
  36.  Dim handle As Pointer
  37.  Dim rit, id, porta As Integer
  38.  
  39. ' Crea un Client de ALSA:
  40.  rit = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_OUTPUT, 0)
  41.  If rit < 0 Then Error.Raise("Imposible abrir el subsistema 'seq' de ALSA: " & snd_strerror(rit))
  42.    
  43. ' Da un nombre al Client:
  44.  snd_seq_set_client_name(handle, "Mi primer Client de ALSA")
  45.    
  46. ' Obtiene el número de identificación del Client:
  47.  id = snd_seq_client_id(handle)
  48.  If id < 0 Then
  49.   snd_seq_close(handle)
  50.   Error.Raise("Imposible obtener el número de identificación del Client: " & snd_strerror(id))
  51.  Print "Número de identificación del Client: "; id
  52.  
  53. ' Crea un Puerto del Client; le asigna la capacidad de "ser leído" (READ) por otros Clientes y realiza la suscripción.
  54. ' Obtiene tambien el número de identificación del Puerto del Client.
  55.  porta = snd_seq_create_simple_port(handle, "Puerto", SND_SEQ_PORT_CAP_READ Or SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC Or SND_SEQ_PORT_TYPE_APPLICATION)
  56.  If porta < 0 Then
  57.    snd_seq_close(handle)
  58.    Error.Raise("Imposible crear el Puerto del Client: " & snd_strerror(porta))
  59.  Print "Número del Puerto del Client: "; porta
  60.  
  61. ' Mantiene vivo a este Client solo por 20 segundos:
  62.  Wait 20
  63.  
  64.  ' Cerra el subsistema 'seq' de ALSA y destruye el Client:
  65.  snd_seq_close(handle)
  66.  



Podemos ver el efecto practico de este codigo, abriendo el archivo de sistema: /proc/asound/seq/clients .
En este archivo de texto encontraremos la referencia a nuestro Client creado. Rolleyes
En particular, si no hay otro Client de ALSA activo, nosotros veremos esta referencia:
...........................................................................
Client 128 : "Mi primer Client de ALSA" [User]
  Port   0 : "Puerto" (R-e-)

...........................................................................
Donde las palabras:
"Client " = ...el nuestro programa es un Client de ALSA;
"128 " = el número de identificación del nuestro Client;
"Mi primer Client de ALSA " = el nombre que le dimos al nuestro Client;
"[User] " = especifica que este Client ha sido creado por un usuario;
"Port " = se refiere a el Puerto del nuestro Client;
"0 " = el número de identificación del Puerto del nuestro Client;
"Puerto " = el nombre que le dimos al Puerto (2° argumento de la función "snd_seq_create_simple_port( ) " )
"R " = el Puerto del Client tiene su Capacidad a READ.

"Los horizontes perdidos nunca regresan. " (F. Battiato, La stagione dell'amore, 1983)

"Las ondas nunca regresan. " (Genesis: Ripples - A trick of the tail, 1976)
[-] Los siguientes 1 usuarios dice gracias a vuott por este post:
  • Shell
    ¡Gracias!
#2

Espectacular Rolleyes

Por favor, usa el corrector ortográfico antes de pulsar el botón 'Enviar'
    ¡Gracias!
#3

OBTENER DATOS MIDI BRUTOS DE UN DISPOSITIVO EXTERNO Y ENVIARLOS A UN CLIENT-SOFTSYNTH A TRAVÉS ALSA

Bueno, ahora veamos cómo obtener datos Midi brutos de un dispositivo externo (por ejemplo, un teclado Midi) y enviarlos a través de ALSA a un Client-Softsynth para que proporcione los sonidos necesarios para escuchar las notas.
Podríamos utilizar los recursos del API del ALSA para recibir los datos brutos del dispositivo Midi externo, pero no será absolutamente necesario: en efecto è posible tambien recibir esos datos Midi crudos leyendo desde el file-device que se crea al conectar el teclado Midi al ordenador.
ALSA no acepta simples datos Midi brutos (como son enviados por los teclados Midi).
ALSA acepta los datos Midi rigurosamente en forma de sus "Eventos Midi ", según las especificaciones de ALSA.
Así, cada "Mensaje", previsto por el protocolo Midi, debe ser organizado en una porción de memoria asignada, introduciendo varios valores, y luego enviado a ALSA.
La primera parte (16 byte) de esta memoria será ocupada por valores comunes a todos los "Eventos Midi" de ALSA; la parte restante y última será ocupada por los valores de los "Mensajes" específicos del protocolo Midi.
Para organizar un "Evento Midi " de ALSA podemos utilizar el Objeto Estructura de Gambas como sigue:

Public Struct Snd_seq_event_t
  type As Byte
  flags As Byte
  tag As Byte           
  queue As Byte                 Datos comunes
  tick_time As Integer         a todos
  real_time As Integer        los Eventos Midi ALSA
  source_client As Byte
  source_port As Byte
  dest_client As Byte
  dest_port As Byte

    channel As Byte
    note As Byte                   Datos pertenecientes
    velocity As Byte              a los especificos "Mensajes"
    off_velocity As Byte        del protocolo Midi
    param As Integer
    value As Integer

End Struct

A continuación mostramos un simple ejemplo, en un entorno gráfico, para recibir los datos Midi brutos, enviados desde el dispositivo Midi a través de su archivo-device del sistema, y para enviarlos enseguida a través de ALSA al Client-softsynth.
Por lo tanto al pulsar una tecla del teclado Midi externo, oiremos el sonido de su nota con el timbre del instrumento musical elegido en el Combobox.
Como se puede ver, utilizamos un código especial para la gestión de recursos de ALSA, en el que no se creará arbitrariamente un Puerto de nuestro cliente mediante la especifica función externa de ALSA. Al mismo tiempo, sin embargo, deberemos asignar al miembro "queue" de la Estructura de los "Eventos Midi" de ALSA el valor de la Constante "SND_SEQ_QUEUE_DIRECT" que es igual a 253.
Funcionamiento:
1) conectar un teclado Midi al ordenador;
2) lanzar el softhsynth (p.e. Qsynth);
3) luego lanzar el código ejemplo subyacente;
4) elegir un instrumento musical de la lista "General Midi" contenida por el ComboBox;
5) ...tocar el teclado Midi externo. Rolleyes
GAMBAS
  1. Private instrumenta As String[] = ["Acustic Grand Piano", "Bright Acustic Piano", "Electric Grand Piano", "Honky-tonk", "Electric Piano 1",
  2. "Electric Piano 2", "Harpsichord", "Clavinet", "Celesta", "Glockenspiel", "Music Box", "Vibraphone", "Marimba", "Xylophone", "Tubular Bells",
  3. "Dulcimer", "Hammond Organ", "Percussive Organ", "Rock Organ", "Church Organ", "Reed Organ", "Accordion", "Harmonica", "Tango Accordion",
  4. "Acoustic Guitar (nylon)", "Acoustic Guitar (steel)", "Electric Guitar (jazz)", "Electric Guitar (clean)", "Electric Guitar(muted)",
  5. "Overdriven Guitar", "Distortion Guitar", "Guitar Harmonics", "Acoustic Bass", "Electric Bass (finger)", "Electric Bass (pick)",
  6. "Fretless Bass", "Slap Bass 1", "Slap Bass 2", "Synth Bass 1", "Synth Bass 2", "Violin", "Viola", "Cello", "Contrabass", "Tremolo Strings",
  7. "Pizzicato Strings", "Orchestral Harp", "Timpani", "String Ensemble 1", "String Ensemble 2", "SynthStrings 1", "SynthStrings 2",
  8. "Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit", "Trumpet", "Trombone", "Tuba", "Muted Trumpet", "French Horn", "Brass Section",
  9. "Synth Brass 1", "Synth Brass 2", "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax", "Oboe", "English Horn", "Basson", "Clarinet",
  10. "Piccolo", "Flute", "Recorder", "Pan Flute", "Bottle Blow", "Shakuhachi", "Whistle", "Ocarina", "Lead 1 (square)", "Lead 2 (sawtooth)",
  11. "Lead 3 (caliope lead)", "Lead 4 (chiff lead)", "Lead 5 (charang)", "Lead 6 (voice)", "Lead 7 (fifths)", "Lead 8(brass+lead)",
  12. "Pad 1 (new age)", "Pad 2 (warm)", "Pad 3 (polysynth)", "Pad 4 (choir)", "Pad 5 (bowed)", "Pad 6 (metallic)", "Pad 7 (halo)", "Pad 8 (sweep)",
  13. "FX 1 (rain)", "FX 2 (soundtrack)", "FX 3 (crystal)", "FX 4 (atmosphere)", "FX 5 (brightness)", "FX 6 (goblins)", "FX 7 (echoes)",
  14. "FX 8 (sci-fi)", "Sitar", "Banjo", "Shamisen", "Koto", "Kalimba", "Bagpipe", "Fiddle", "Shanai", "Tinkle Bell", "Agogo", "Steel Drums",
  15. "Woodblock", "Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse Cymbal", "Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet",
  16. "Telephone Ring", "Helicopter", "Applause", "Gunshot"]
  17.  
  18.  
  19. Public Sub Form_Open()
  20.  
  21.   Dim dev As String
  22.  
  23.   dev = Dir("/dev", "*midi*", gb.Device)[0]
  24.  
  25.   With Me
  26.     .W = 400
  27.     .H = 200
  28.     .Center
  29.   With cb = New ComboBox(Me) As "Combo"
  30.     .W = 180
  31.     .H = 30
  32.     .X = (Me.W / 2) - (.W / 2)
  33.     .Y = (Me.H / 2.5) - .H
  34.     .Text = "Instrumenta"
  35.     .List = instrumenta
  36.  
  37.   bb = New Byte[]
  38.   CreaClient()
  39.  
  40. ' Abre el file-device Midi en lectura y lo pone en "observación":
  41.   fl = Open "/dev" &/ dev For Read Watch
  42.  
  43.  
  44.  
  45. Public Sub File_Read()
  46.  
  47.   Dim b As Byte
  48.  
  49. ' Si hay algo que leer del file-device, lo lee:
  50.   Read #fl, b
  51.  
  52. ' Sólo lee los Mensajes Midi de NOTE-ON:
  53.   If (b And 144) <> 144 Then Return
  54.   bb.Push(b)
  55.   If bb.Count == 3 Then
  56.     EnvioMIDI(bb)
  57.     bb = New Byte[]
  58.  
  59.  
  60. ''''''''''''''''''''''''''''''''''''''''''''''''''
  61.  
  62. Library "libasound:2"
  63.  
  64. Public Struct snd_seq_event_t   ' Estructura del Evento Midi de ALSA
  65.   type As Byte
  66.   flags As Byte
  67.   tag As Byte
  68.   queue As Byte
  69.   tick_time As Integer
  70.   real_time As Integer
  71.   source_client As Byte
  72.   source_port As Byte
  73.   dest_client As Byte
  74.   dest_port As Byte
  75.   note As Byte
  76.   velocity As Byte
  77.   off_velocity As Byte
  78.   value As Integer
  79.  
  80. Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
  81. Private Const SND_SEQ_QUEUE_DIRECT As Byte = 253
  82. Private Const SND_SEQ_EVENT_NOTEON As Byte = 6
  83. Private Const SND_SEQ_EVENT_PGMCHANGE As Byte = 11
  84.  
  85. ' int snd_seq_open (snd_seq_t **handle, const char * name, int streams, int mode)
  86. ' Open the ALSA sequencer.
  87. Private Extern snd_seq_open(handle As Pointer, name As String, streams As Integer, mode As Integer) As Integer
  88.  
  89. ' const char * snd_strerror (int errnum)
  90. ' Returns the message for an error code.
  91. Private Extern snd_strerror(err As Integer) As String
  92.    
  93. ' int snd_seq_event_output (snd_seq_t *handle, snd_seq_event_t *ev)
  94. ' Output an event.
  95. Private Extern snd_seq_event_output(handle As Pointer, ev As Snd_seq_event_t)
  96.  
  97. ' int snd_seq_drain_output (snd_seq_t * seq)
  98. ' Drain output buffer to sequencer.
  99. Private Extern snd_seq_drain_output(seq As Pointer) As Integer
  100.  
  101. ' int snd_seq_close (snd_seq_t *handle)
  102. ' Close the sequencer.
  103. Private Extern snd_seq_close(handle As Pointer) As Integer
  104.  
  105.  
  106. Private Procedure CreaClient()
  107.  
  108.   Dim rit As Integer
  109.  
  110.   rit = snd_seq_open(VarPtr(seq), "default", SND_SEQ_OPEN_OUTPUT, 0)
  111.   If rit < 0 Then Error.Raise("Imposible abrir el subsistema 'seq' de ALSA: " & snd_strerror(rit))
  112.  
  113.  
  114.  
  115. Private Procedure EnvioMIDI(mid As Byte[])
  116.  
  117.   Dim evento As New Snd_seq_event_t
  118.  
  119.   With evento
  120.     .queue = SND_SEQ_QUEUE_DIRECT
  121.     .dest_client = 128
  122.     .dest_port = 0
  123.     .channel = mid[0]
  124.  
  125. ' Establece el tipo de instrumento musical con el Mensaje Midi "Program-Change":
  126.   Mensaje(evento, SND_SEQ_EVENT_PGMCHANGE, mid, cb.Index)
  127.  
  128.   Mensaje(evento, SND_SEQ_EVENT_NOTEON, mid, 0)
  129.  
  130.  
  131.  
  132. Private Procedure Mensaje(ev As Snd_seq_event_t, tipo As Byte, nota As Byte[], instr As Integer)
  133.  
  134.  With ev
  135.    .type = tipo
  136.    .channel = nota[0]
  137.    .note = nota[1]
  138.    .velocity = nota[2]
  139.    .value = instr
  140.  
  141. ' Inserta el Evento de ALSA en el buffer:
  142.   snd_seq_event_output(seq, ev)
  143.  
  144. ' Envia el Evento:
  145.   snd_seq_drain_output(seq)
  146.  
  147.  
  148.  
  149. Public Sub Form_Close()
  150.  
  151.   snd_seq_close(seq)
  152.   fl.Close
  153.  



"Los horizontes perdidos nunca regresan. " (F. Battiato, La stagione dell'amore, 1983)

"Las ondas nunca regresan. " (Genesis: Ripples - A trick of the tail, 1976)
    ¡Gracias!
#4

Esto se esta poniendo cada vez mas interesante, lastima que no dispongo de un teclado midi, que si no ahora mismo me ponía con esto.
Vuott, gracias por compartir estas cosas.
Saludos.

1 Saludo.
    ¡Gracias!
#5

ENVIAR EVENTOS MIDI DE ALSA DESDE NUESTRO PROGRAMA A UN SOFTSYNTH

En este otro ejemplo, los datos Midi serán enviados por el propio programa y no por un dispositivo externo. En particular, vamos a ejecutar 8 notas de la escala musical de Do mayor.
  Desde el punto de vista del Midi, por lo tanto, tendremos que enviar Mensajes Midi de "Note On", para activar la ejecución de una nota musical Midi, y Mensajes Midi de "Note Off" para hacer cesar la ejecución de la nota. También enviaremos previamente un mensaje Midi de "Program Change" para establecer el sonido del instrumento seleccionado según el estándar General Midi.
  En el código anterior nos dimos cuenta de que ALSA sólo acepta eventos Midi si se envían en el modo rígido representado por la Estructura "snd_seq_event_t ". Por lo tanto, los eventos Midi de ALSA, que corresponden a los Mensajes Midi, deberán ser rígidamente y correctamente configurados y enviados a ALSA a través de esta Estructura. En el código estableceremos algunos miembros de esa Estructura de forma genérica y válida para los tres Mensajes Midi que deberemos enviar.
  Antes de lanzar el programa, hace falta lanzar el Softsyhth "Qsynth" para permitir escuchar el sonido. El código detectará automáticamente el programa "Qsynth" (que es otro "Client" de ALSA) y se conectará a él. Rutinas especiales se encargarán de los datos relativos al específico Mensaje Midi, que se enviarán al sub-sistema "Seq" de ALSA.
GAMBAS
  1.  
  2. Library "libasound:2"
  3.  
  4. Public Struct snd_seq_event_t
  5.   type As Byte
  6.   flags As Byte
  7.   tag As Byte
  8.   queue As Byte
  9.   tick_time As Integer
  10.   real_time As Integer
  11.   source_client As Byte
  12.   source_port As Byte
  13.   dest_client As Byte
  14.   dest_port As Byte
  15.   note As Byte
  16.   velocity As Byte
  17.   off_velocity As Byte
  18.   value As Integer
  19.  
  20. Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
  21. Private Const SND_SEQ_PORT_CAP_READ As Integer = 1   ' El puerto del Client puede ser "leído" por otro Client externo
  22. Private Const SND_SEQ_PORT_TYPE_MIDI_GENERIC As Integer = 2
  23. Private Const SND_SEQ_PORT_TYPE_APPLICATION As Integer = 1048576
  24.  
  25. ' Enumeración para especificar los Mensajes Midi:
  26. Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF, SND_SEQ_EVENT_KEYPRESS, SND_SEQ_EVENT_CONTROLLER = 10, SND_SEQ_EVENT_PGMCHANGE
  27.  
  28. ' int snd_seq_open (snd_seq_t **handle, const char * name, int streams, int mode)
  29. ' Open the ALSA sequencer.
  30. Private Extern snd_seq_open(handle As Pointer, name As String, streams As Integer, mode As Integer) As Integer
  31.  
  32. ' const char * snd_strerror (int errnum)
  33. ' Returns the message for an error code.
  34. Private Extern snd_strerror(err As Integer) As String
  35.  
  36. ' int snd_seq_client_id (snd_seq_t *seq)
  37. ' Get the client id.
  38. Private Extern snd_seq_client_id(seq As Pointer) As Integer
  39.  
  40. ' int snd_seq_create_simple_port (snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)
  41. ' Create a port - simple version.
  42. Private Extern snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer
  43.  
  44. ' int snd_seq_alloc_queue (snd_seq_t *handle)
  45. ' Allocate a queue.
  46. Private Extern snd_seq_alloc_queue(handle As Pointer) As Integer
  47.  
  48. ' int snd_seq_connect_to (snd_seq_t *seq, int my_port, int dest_client, int dest_port)
  49. ' Simple subscription (w/o exclusive & time conversion).
  50. Private Extern snd_seq_connect_to(seq As Pointer, my_port As Integer, dest_client As Integer, dest_port As Integer) As Integer
  51.  
  52. ' int snd_seq_event_output (snd_seq_t *handle, snd_seq_event_t *ev)
  53. ' Output an event.
  54. Private Extern snd_seq_event_output(handle As Pointer, ev As Snd_seq_event_t)
  55.  
  56. ' int snd_seq_drain_output (snd_seq_t * seq)
  57. ' Drain output buffer to sequencer.
  58. Private Extern snd_seq_drain_output(seq As Pointer) As Integer
  59.  
  60. ' int snd_seq_close (snd_seq_t *handle)
  61. ' Close the sequencer.
  62. Private Extern snd_seq_close(handle As Pointer) As Integer
  63.  
  64.  
  65. Public Sub Main()
  66.  
  67.   Dim note As Byte[] = [60, 62, 64, 65, 67, 69, 71, 72]   ' Las 8 notas Midi a ejecutar
  68.   Dim source_dest As New Byte[4]
  69.   Dim n As Byte
  70.   Dim ev As New Snd_seq_event_t
  71.  
  72. ' Crea el Client de ALSA:
  73.   CreaClient(source_dest)
  74.  
  75. ' Establece el Evento Midi de ALSA con algunos valores:
  76.   With ev
  77.     .flags = 0
  78.     .tag = 0
  79.     .queue = 0
  80.     .tick_time = 0
  81.     .real_time = 0
  82.     .source_client = source_dest[0]
  83.     .source_port = source_dest[1]
  84.     .dest_client = source_dest[2]
  85.     .dest_port = source_dest[3]
  86.     .channel = 0
  87.  
  88. ' Invoca el sub-procedimiento para enviar a ALSA el Mensaje Midi "Program Change", especificando en el segundo argumento el número de identificación GM del instrumento musical a utilizar:
  89.   program_change(ev, 48)
  90.  
  91.   For n = 0 To note.Max
  92. ' Invoca el sub-procedimiento para enviar a ALSA el Mensaje Midi "Note ON":
  93.     Note_On(ev, note[n])
  94. ' Establece la duración del sonido de la nota musical:
  95.     Wait 1
  96. ' Invoca el sub-procedimiento para enviar a ALSA el Mensaje Midi "Note OFF":
  97.     Note_Off(ev, note[n])
  98.   Next
  99.    
  100.   snd_seq_close(sndseq)
  101.  
  102.  
  103.  
  104. Private Function CreaClient(srcdst As Byte[])
  105.  
  106.   Dim rit As Integer
  107.  
  108.   rit = snd_seq_open(VarPtr(sndseq), "default", SND_SEQ_OPEN_OUTPUT, 0)
  109.   If rit < 0 Then
  110.     Error.Raise("Imposible abrir el sub-sistema 'seq' de ALSA: " & snd_strerror(rit))
  111.  
  112.   srcdst[0] = snd_seq_client_id(sndseq)
  113.  
  114.   srcdst[1] = snd_seq_create_simple_port(sndseq, "porta_", SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC Or SND_SEQ_PORT_TYPE_APPLICATION)
  115.   If srcdst[1] < 0 Then Error.Raise("Imposible crear el puerto de salida datos ALSA !")
  116.  
  117.   Fluidsynth(srcdst)
  118.  
  119. ' Conecta este Client Gambas a otro Client (por ejemplo QSynth):
  120.   rit = snd_seq_connect_to(sndseq, srcdst[1], srcdst[2], srcdst[3])
  121.   If rit < 0 Then Error.Raise("Imposible conectarse al Client de ALSA destinatario de los datos: " & snd_strerror(rit))
  122.    
  123.   snd_seq_alloc_queue(sndseq)
  124.  
  125.  
  126. Private Procedure program_change(ev_prch As Snd_seq_event_t, strum As Integer)
  127.  
  128.   With ev_prch
  129. ' Especifica que es un Messaggio Midi "Program Change":
  130.     .type = SND_SEQ_EVENT_PGMCHANGE
  131. ' Asigna el valor relativo al instrumento musical según el estándar General Midi:
  132.     .value = strum
  133.    
  134.   EnviaEvento(ev_prch)
  135.  
  136.  
  137. Private Procedure Note_On(ev_nton As Snd_seq_event_t, nota As Byte)
  138.  
  139.   With ev_nton
  140. ' Especifica que es un Mensaje Midi "Note ON":
  141.     .type = SND_SEQ_EVENT_NOTEON
  142. ' Especifica el número de la nota Midi a ejecutar:
  143.     .note = nota
  144. ' Especifica el valor de "velocity":
  145.     .velocity = 64
  146.  
  147.   EnviaEvento(ev_nton)
  148.  
  149.  
  150. Private Procedure Note_Off(ev_ntoff As Snd_seq_event_t, nota As Byte)
  151.  
  152.   With ev_ntoff
  153. ' Especifica que es un Mensaje Midi "Note OFF":
  154.     .type = SND_SEQ_EVENT_NOTEOFF
  155.     .note = nota
  156.     .velocity = 0
  157.  
  158.   EnviaEvento(ev_ntoff)
  159.  
  160.  
  161. Private Procedure EnviaEvento(evento As Snd_seq_event_t)
  162.  
  163.   snd_seq_event_output(sndseq, evento)
  164.  
  165.   snd_seq_drain_output(sndseq)
  166.  
  167.  
  168. Private Function Fluidsynth(sd As Byte[])
  169.  
  170.   Dim ss As String[]
  171.   Dim c As Short
  172.  
  173.   s = File.Load("/proc/asound/seq/clients")
  174.   If InStr(s, "FLUID Synth") == 0 Then Error.Raise("No encuentro FluidSinth !")
  175.   ss = Split(s, "\n")
  176.   For c = 0 To ss.Max
  177.     If InStr(ss[c], "FLUID Synth") > 0 Then
  178.       sd[2] = Scan(ss[c], "Client * : \"FLUID Synth*")[0]
  179.       sd[3] = Scan(ss[c + 1], "  Port * : \"Synth*")[0]
  180.     Endif
  181.   Next
  182.  



"Los horizontes perdidos nunca regresan. " (F. Battiato, La stagione dell'amore, 1983)

"Las ondas nunca regresan. " (Genesis: Ripples - A trick of the tail, 1976)
    ¡Gracias!
#6

hola vuott, excelente, sin dudas eres un gurú de la programación, ya que veo tu pontencial, te doy una gran idea que manejo hace mucho pero no he hecho nada porque soy un batata programando.
Esta idea es muy importante para la privacidad de la gente, y seria necesario en cientos de programas, ningún programa implementa esto, por eso para mi es una gran idea y muy necesaria pero yo por ahora no tengo la capacidad para llevarlo al código pero tu si.
La idea es la siguiente espero poder explicarla bien sino me dicen, trataría de un programa que actuara entre un micrófono y alsa o el encargado de sonido, el cual captura el sonido del micrófono, varia sus frecuencias ( para camuflar la voz aquí la gran idea) y lo pasa a alza, entonces, cualquier programa que use un micrófono obtendrá una voz encriptada por decir de alguna manera.
bueno esa es la idea vuott, seguramente vos tendrás otras ideas u otro planteo para resolver esta cuestión, yo te tiro la idea por si a ti te gusta y le hechas mano y dejas el código publico para que los programadores la puedan usar en sus aplicaciones. saludos

El tiempo de las manifestaciones caducó pero el boicot con auto sacrificio es el camino para derrotar al sistema.
    ¡Gracias!
#7

(05-10-2020, 16:34)kokodrilo escribió:  trataría de un programa que actuara entre un micrófono y alsa o el encargado de sonido, el cual captura el sonido del micrófono, varia sus frecuencias

Con respecto a este tu problema, por favor, abre un nuevo tema separado.
gracias.

"Los horizontes perdidos nunca regresan. " (F. Battiato, La stagione dell'amore, 1983)

"Las ondas nunca regresan. " (Genesis: Ripples - A trick of the tail, 1976)
    ¡Gracias!


Posibles temas similares…
Tema / Autor Respuestas Vistas Último mensaje
Último mensaje por vuott
21-10-2020, 19:30

Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)