vuott   11-09-2020, 01:36
#1
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":
Código:
Library "libasound:2"

Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
Private Const SND_SEQ_PORT_CAP_READ As Integer = 1
Private Const SND_SEQ_PORT_CAP_SUBS_READ As Integer = 32
Private Const SND_SEQ_PORT_TYPE_MIDI_GENERIC As Integer = 2
Private Const SND_SEQ_PORT_TYPE_APPLICATION As Integer = 1048576

' int snd_seq_open (snd_seq_t **handle, const char * name, int streams, int mode)
' Open the ALSA sequencer.
Private Extern snd_seq_open(handle As Pointer, name As String, streams As Integer, mode As Integer) As Integer

' int snd_seq_set_client_name (snd_seq_t *seq, const char *name)
' Set client name.
Private Extern snd_seq_set_client_name(seq As Pointer, name As String) As Integer

' int snd_seq_client_id (snd_seq_t *handle)
' Get the client id.
Private Extern snd_seq_client_id(handle As Pointer) As Integer

' int snd_seq_create_simple_port (snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)
' Create a port - simple version.
Private Extern snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer

' const char* snd_strerror (int errnum)
' Returns the message for an error code.
Private Extern snd_strerror(errnum As Integer) As String

' int snd_seq_close (snd_seq_t *handle)
' Close the sequencer.
Private Extern snd_seq_close(handle As Pointer) As Integer


Public Sub Main()

 Dim handle As Pointer
 Dim rit, id, porta As Integer
 
' Crea un Client de ALSA:
 rit = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_OUTPUT, 0)
 If rit < 0 Then Error.Raise("Imposible abrir el subsistema 'seq' de ALSA: " & snd_strerror(rit))
   
' Da un nombre al Client:
 snd_seq_set_client_name(handle, "Mi primer Client de ALSA")
   
' Obtiene el número de identificación del Client:
 id = snd_seq_client_id(handle)
 If id < 0 Then
  snd_seq_close(handle)
  Error.Raise("Imposible obtener el número de identificación del Client: " & snd_strerror(id))
 Endif
 Print "Número de identificación del Client: "; id
 
' Crea un Puerto del Client; le asigna la capacidad de "ser leído" (READ) por otros Clientes y realiza la suscripción.
' Obtiene tambien el número de identificación del Puerto del Client.
 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)
 If porta < 0 Then
   snd_seq_close(handle)
   Error.Raise("Imposible crear el Puerto del Client: " & snd_strerror(porta))
 Endif
 Print "Número del Puerto del Client: "; porta
 
' Mantiene vivo a este Client solo por 20 segundos:
 Wait 20
 
 ' Cerra el subsistema 'seq' de ALSA y destruye el Client:
 snd_seq_close(handle)
 
End

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.
Última modificación: 18-10-2020, 20:04 por vuott.

« Los horizontes perdidos nunca regresan. » (F. Battiato, 1983)

« Las ondas nunca regresan. » (Genesis: Ripples, 1976)

« Vita non suavis esse potest, nec Mors amara. »  (...vuott)
jguardon   12-09-2020, 11:01
#2
Espectacular Rolleyes

Por favor, usa el corrector ortográfico antes de pulsar el botón 'Enviar'
vuott   14-09-2020, 09:56
#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
Código:
Private fl As File
Private cb As ComboBox
Private bb As Byte[]
Private seq As Pointer
Private instrumenta As String[] = ["Acustic Grand Piano", "Bright Acustic Piano", "Electric Grand Piano", "Honky-tonk", "Electric Piano 1",
"Electric Piano 2", "Harpsichord", "Clavinet", "Celesta", "Glockenspiel", "Music Box", "Vibraphone", "Marimba", "Xylophone", "Tubular Bells",
"Dulcimer", "Hammond Organ", "Percussive Organ", "Rock Organ", "Church Organ", "Reed Organ", "Accordion", "Harmonica", "Tango Accordion",
"Acoustic Guitar (nylon)", "Acoustic Guitar (steel)", "Electric Guitar (jazz)", "Electric Guitar (clean)", "Electric Guitar(muted)",
"Overdriven Guitar", "Distortion Guitar", "Guitar Harmonics", "Acoustic Bass", "Electric Bass (finger)", "Electric Bass (pick)",
"Fretless Bass", "Slap Bass 1", "Slap Bass 2", "Synth Bass 1", "Synth Bass 2", "Violin", "Viola", "Cello", "Contrabass", "Tremolo Strings",
"Pizzicato Strings", "Orchestral Harp", "Timpani", "String Ensemble 1", "String Ensemble 2", "SynthStrings 1", "SynthStrings 2",
"Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit", "Trumpet", "Trombone", "Tuba", "Muted Trumpet", "French Horn", "Brass Section",
"Synth Brass 1", "Synth Brass 2", "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax", "Oboe", "English Horn", "Basson", "Clarinet",
"Piccolo", "Flute", "Recorder", "Pan Flute", "Bottle Blow", "Shakuhachi", "Whistle", "Ocarina", "Lead 1 (square)", "Lead 2 (sawtooth)",
"Lead 3 (caliope lead)", "Lead 4 (chiff lead)", "Lead 5 (charang)", "Lead 6 (voice)", "Lead 7 (fifths)", "Lead 8(brass+lead)",
"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)",
"FX 1 (rain)", "FX 2 (soundtrack)", "FX 3 (crystal)", "FX 4 (atmosphere)", "FX 5 (brightness)", "FX 6 (goblins)", "FX 7 (echoes)",
"FX 8 (sci-fi)", "Sitar", "Banjo", "Shamisen", "Koto", "Kalimba", "Bagpipe", "Fiddle", "Shanai", "Tinkle Bell", "Agogo", "Steel Drums",
"Woodblock", "Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse Cymbal", "Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet",
"Telephone Ring", "Helicopter", "Applause", "Gunshot"]


Public Sub Form_Open()

  Dim dev As String
 
  dev = Dir("/dev", "*midi*", gb.Device)[0]
 
  With Me
    .W = 400
    .H = 200
    .Center
  End With
  With cb = New ComboBox(Me) As "Combo"
    .W = 180
    .H = 30
    .X = (Me.W / 2) - (.W / 2)
    .Y = (Me.H / 2.5) - .H
    .Text = "Instrumenta"
    .List = instrumenta
  End With
 
  bb = New Byte[]
  CreaClient()

' Abre el file-device Midi en lectura y lo pone en "observación":
  fl = Open "/dev" &/ dev For Read Watch

End


Public Sub File_Read()
 
  Dim b As Byte
 
' Si hay algo que leer del file-device, lo lee:
  Read #fl, b

' Sólo lee los Mensajes Midi de NOTE-ON:
  If (b And 144) <> 144 Then Return
  bb.Push(b)
  If bb.Count == 3 Then
    EnvioMIDI(bb)
    bb = New Byte[]
  Endif
 
End

''''''''''''''''''''''''''''''''''''''''''''''''''

Library "libasound:2"

Public Struct snd_seq_event_t   ' Estructura del Evento Midi de ALSA
  type As Byte
  flags As Byte
  tag As Byte
  queue As Byte
  tick_time As Integer
  real_time As Integer
  source_client As Byte
  source_port As Byte
  dest_client As Byte
  dest_port As Byte
  channel As Byte
  note As Byte
  velocity As Byte
  off_velocity As Byte
  param As Integer
  value As Integer
End Struct
 
Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
Private Const SND_SEQ_QUEUE_DIRECT As Byte = 253
Private Const SND_SEQ_EVENT_NOTEON As Byte = 6
Private Const SND_SEQ_EVENT_PGMCHANGE As Byte = 11
 
' int snd_seq_open (snd_seq_t **handle, const char * name, int streams, int mode)
' Open the ALSA sequencer.
Private Extern snd_seq_open(handle As Pointer, name As String, streams As Integer, mode As Integer) As Integer

' const char * snd_strerror (int errnum)
' Returns the message for an error code.
Private Extern snd_strerror(err As Integer) As String
   
' int snd_seq_event_output (snd_seq_t *handle, snd_seq_event_t *ev)
' Output an event.
Private Extern snd_seq_event_output(handle As Pointer, ev As Snd_seq_event_t)

' int snd_seq_drain_output (snd_seq_t * seq)
' Drain output buffer to sequencer.
Private Extern snd_seq_drain_output(seq As Pointer) As Integer

' int snd_seq_close (snd_seq_t *handle)
' Close the sequencer.
Private Extern snd_seq_close(handle As Pointer) As Integer


Private Procedure CreaClient()
 
  Dim rit As Integer
 
  rit = snd_seq_open(VarPtr(seq), "default", SND_SEQ_OPEN_OUTPUT, 0)
  If rit < 0 Then Error.Raise("Imposible abrir el subsistema 'seq' de ALSA: " & snd_strerror(rit))
 
End


Private Procedure EnvioMIDI(mid As Byte[])
 
  Dim evento As New Snd_seq_event_t
 
  With evento
    .queue = SND_SEQ_QUEUE_DIRECT
    .dest_client = 128
    .dest_port = 0
    .channel = mid[0]
  End With
 
' Establece el tipo de instrumento musical con el Mensaje Midi "Program-Change":
  Mensaje(evento, SND_SEQ_EVENT_PGMCHANGE, mid, cb.Index)
 
  Mensaje(evento, SND_SEQ_EVENT_NOTEON, mid, 0)
 
End


Private Procedure Mensaje(ev As Snd_seq_event_t, tipo As Byte, nota As Byte[], instr As Integer)
 
 With ev
   .type = tipo
   .channel = nota[0]
   .note = nota[1]
   .velocity = nota[2]
   .value = instr
 End With
 
' Inserta el Evento de ALSA en el buffer:
  snd_seq_event_output(seq, ev)
 
' Envia el Evento:
  snd_seq_drain_output(seq)
 
End


Public Sub Form_Close()
 
  snd_seq_close(seq)
  fl.Close
 
End
Última modificación: 06-10-2020, 01:22 por vuott.

« Los horizontes perdidos nunca regresan. » (F. Battiato, 1983)

« Las ondas nunca regresan. » (Genesis: Ripples, 1976)

« Vita non suavis esse potest, nec Mors amara. »  (...vuott)
tincho   14-09-2020, 11:03
#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.
vuott   05-10-2020, 12:38
#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.
Código:
Private sndseq As Pointer

Library "libasound:2"

Public Struct snd_seq_event_t
  type As Byte
  flags As Byte
  tag As Byte
  queue As Byte
  tick_time As Integer
  real_time As Integer
  source_client As Byte
  source_port As Byte
  dest_client As Byte
  dest_port As Byte
  channel As Byte
  note As Byte
  velocity As Byte
  off_velocity As Byte
  param As Integer
  value As Integer
End Struct

Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
Private Const SND_SEQ_PORT_CAP_READ As Integer = 1   ' El puerto del Client puede ser "leído" por otro Client externo
Private Const SND_SEQ_PORT_TYPE_MIDI_GENERIC As Integer = 2
Private Const SND_SEQ_PORT_TYPE_APPLICATION As Integer = 1048576

' Enumeración para especificar los Mensajes Midi:
Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF, SND_SEQ_EVENT_KEYPRESS, SND_SEQ_EVENT_CONTROLLER = 10, SND_SEQ_EVENT_PGMCHANGE

' int snd_seq_open (snd_seq_t **handle, const char * name, int streams, int mode)
' Open the ALSA sequencer.
Private Extern snd_seq_open(handle As Pointer, name As String, streams As Integer, mode As Integer) As Integer

' const char * snd_strerror (int errnum)
' Returns the message for an error code.
Private Extern snd_strerror(err As Integer) As String

' int snd_seq_client_id (snd_seq_t *seq)
' Get the client id.
Private Extern snd_seq_client_id(seq As Pointer) As Integer

' int snd_seq_create_simple_port (snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)
' Create a port - simple version.
Private Extern snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer

' int snd_seq_alloc_queue (snd_seq_t *handle)
' Allocate a queue.
Private Extern snd_seq_alloc_queue(handle As Pointer) As Integer

' int snd_seq_connect_to (snd_seq_t *seq, int my_port, int dest_client, int dest_port)
' Simple subscription (w/o exclusive & time conversion).
Private Extern snd_seq_connect_to(seq As Pointer, my_port As Integer, dest_client As Integer, dest_port As Integer) As Integer

' int snd_seq_event_output (snd_seq_t *handle, snd_seq_event_t *ev)
' Output an event.
Private Extern snd_seq_event_output(handle As Pointer, ev As Snd_seq_event_t)

' int snd_seq_drain_output (snd_seq_t * seq)
' Drain output buffer to sequencer.
Private Extern snd_seq_drain_output(seq As Pointer) As Integer

' int snd_seq_close (snd_seq_t *handle)
' Close the sequencer.
Private Extern snd_seq_close(handle As Pointer) As Integer


Public Sub Main()
 
  Dim note As Byte[] = [60, 62, 64, 65, 67, 69, 71, 72]   ' Las 8 notas Midi a ejecutar
  Dim source_dest As New Byte[4]
  Dim n As Byte
  Dim ev As New Snd_seq_event_t
 
' Crea el Client de ALSA:
  CreaClient(source_dest)

' Establece el Evento Midi de ALSA con algunos valores:
  With ev
    .flags = 0
    .tag = 0
    .queue = 0
    .tick_time = 0
    .real_time = 0
    .source_client = source_dest[0]
    .source_port = source_dest[1]
    .dest_client = source_dest[2]
    .dest_port = source_dest[3]
    .channel = 0
  End With

' 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:
  program_change(ev, 48)
 
  For n = 0 To note.Max
' Invoca el sub-procedimiento para enviar a ALSA el Mensaje Midi "Note ON":
    Note_On(ev, note[n])
' Establece la duración del sonido de la nota musical:
    Wait 1
' Invoca el sub-procedimiento para enviar a ALSA el Mensaje Midi "Note OFF":
    Note_Off(ev, note[n])
  Next
   
  snd_seq_close(sndseq)
 
End


Private Function CreaClient(srcdst As Byte[])
 
  Dim rit As Integer
 
  rit = snd_seq_open(VarPtr(sndseq), "default", SND_SEQ_OPEN_OUTPUT, 0)
  If rit < 0 Then
    Error.Raise("Imposible abrir el sub-sistema 'seq' de ALSA: " & snd_strerror(rit))
  Endif
 
  srcdst[0] = snd_seq_client_id(sndseq)
 
  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)
  If srcdst[1] < 0 Then Error.Raise("Imposible crear el puerto de salida datos ALSA !")

  Fluidsynth(srcdst)
 
' Conecta este Client Gambas a otro Client (por ejemplo QSynth):
  rit = snd_seq_connect_to(sndseq, srcdst[1], srcdst[2], srcdst[3])
  If rit < 0 Then Error.Raise("Imposible conectarse al Client de ALSA destinatario de los datos: " & snd_strerror(rit))
   
  snd_seq_alloc_queue(sndseq)
 
End

Private Procedure program_change(ev_prch As Snd_seq_event_t, strum As Integer)
 
  With ev_prch
' Especifica que es un Messaggio Midi "Program Change":
    .type = SND_SEQ_EVENT_PGMCHANGE
' Asigna el valor relativo al instrumento musical según el estándar General Midi:
    .value = strum
  End With
   
  EnviaEvento(ev_prch)
 
End

Private Procedure Note_On(ev_nton As Snd_seq_event_t, nota As Byte)
 
  With ev_nton
' Especifica que es un Mensaje Midi "Note ON":
    .type = SND_SEQ_EVENT_NOTEON
' Especifica el número de la nota Midi a ejecutar:
    .note = nota
' Especifica el valor de "velocity":
    .velocity = 64
  End With
 
  EnviaEvento(ev_nton)
 
End

Private Procedure Note_Off(ev_ntoff As Snd_seq_event_t, nota As Byte)
 
  With ev_ntoff
' Especifica que es un Mensaje Midi "Note OFF":
    .type = SND_SEQ_EVENT_NOTEOFF
    .note = nota
    .velocity = 0
  End With
 
  EnviaEvento(ev_ntoff)
 
End

Private Procedure EnviaEvento(evento As Snd_seq_event_t)
 
  snd_seq_event_output(sndseq, evento)
 
  snd_seq_drain_output(sndseq)
 
End

Private Function Fluidsynth(sd As Byte[])
 
  Dim s As String
  Dim ss As String[]
  Dim c As Short
 
  s = File.Load("/proc/asound/seq/clients")
  If InStr(s, "FLUID Synth") == 0 Then Error.Raise("No encuentro FluidSinth !")
  ss = Split(s, "\n")
  For c = 0 To ss.Max
    If InStr(ss[c], "FLUID Synth") > 0 Then
      sd[2] = Scan(ss[c], "Client * : \"FLUID Synth*")[0]
      sd[3] = Scan(ss[c + 1], "  Port * : \"Synth*")[0]
    Endif
  Next
 
End
Última modificación: 06-10-2020, 01:14 por vuott.

« Los horizontes perdidos nunca regresan. » (F. Battiato, 1983)

« Las ondas nunca regresan. » (Genesis: Ripples, 1976)

« Vita non suavis esse potest, nec Mors amara. »  (...vuott)
kokodrilo   05-10-2020, 16:34
#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.
vuott   06-10-2020, 01:11
#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, 1983)

« Las ondas nunca regresan. » (Genesis: Ripples, 1976)

« Vita non suavis esse potest, nec Mors amara. »  (...vuott)
  
Usuarios navegando en este tema: 1 invitado(s)
Powered By MyBB, © 2002-2024 MyBB Group.
Made with by Curves UI.