paco   12-01-2025, 11:43
#1
Hola,

Estoy realizando una aplicación de prueba para sintetizar y editar fragmentos de sonido. El resultado final se encuentra en un vector numérico conteniendo los valores de cada una de la muestras. Para escuchar el fragmento de audio lo que hago es exportar este vector (debidamente convertido en una cadena) en un archivo 'wav' y luego importarlo otra vez para reproducirlo. Esto funciona bien.

Pero me gustaría poder escuchar el fragmento directamente, sin tener que exportarlo y volverlo a importar. O sea, enviar el vector con las muestras a la tarjeta de sonido directamente. Y ahí es donde estoy estancado. Supongo que no debe ser algo difícil, pero no encuentro la forma. Agradecería cualquier idea al respecto.

Muchas gracias.
vuott   12-01-2025, 17:40
#2
(12-01-2025, 11:43)paco escribió: El resultado final se encuentra en un vector numérico conteniendo los valores de cada una de la muestras.
Hola,
un vector (array) numérico de que tipo (Byte, Short, ...) ?

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

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

« Vita non suavis esse potest, nec Mors amara. »  (...vuott)
paco   13-01-2025, 11:12
#3
Integer (entero con signo).
vuott   13-01-2025, 12:41
#4
...Integer..... que raro !
Porqué Integer ? Huh
Generalmente se utiliza el tipo Short...... resolución de audio de 16 bits.


Sin embargo, un modo implica el uso de los recursos del Componente gb.media.
Este modo implica tambien la creación de un archivo de soporte a partir de datos vectoriales de tipo Integer[]

Código:
Public Sub Main()

  Dim fileaudio As String
  Dim ii As Integer[]
  Dim fl As File
  Dim d As Float
  Dim pl As MediaPipeline
  Dim src, raw, snk As MediaControl
 
  ........
  ' Aquí se asume que el vector de tipo Integer[] ya está poblado con los datos de audio en bruto.
  ........

' Crea un archivo de soporte, para que los datos de audio en bruto puedan ser cargados en el sistema GStreamer (gb.media):
  fileaudio = Temp
  fl = Open fileaudio For Create
  ii.Write(fl, 0, ii.Count / SizeOf(gb.Integer))
  fl.Close

' Calcula la duración del audio cargado:
  d = (ii.Count * 8) / (44100 * 16 * 2)
  Print Time(0, 0, 0, d * 1000)

  pl = New MediaPipeline 

' Carga los datos de audio:
  src = New MediaControl(pl, "filesrc")
  src["location"] = fileaudio
 
' Interpreta los datos de audio en bruto:
  raw = New MediaControl(pl, "rawaudioparse")
  snk = New MediaControl(pl, "autoaudiosink")

  src.LinkTo(raw)
  raw.LinkTo(snk)
 
  pl.Play()

  Wait d
 
  pl.Close

End
Última modificación: 13-01-2025, 16:49 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)
paco   13-01-2025, 17:07
#5
Muchas gracias.
Esto es exactamente lo que buscaba.
Es cierto, con short es mejor...
vuott   13-01-2025, 18:21
#6
(13-01-2025, 17:07)paco escribió: Es cierto, con short es mejor...
También puedes usar un array de tipo Byte[].

Sin embargo, si no quieres usar el archivo temporaneo de soporte, y queires enviar los datos de audio directamente a la tarjeta de sonido, deberías utilizar las funciones externas de ALSA.
En general:
https://www.gambas-it.org/wiki/index.php...PI_di_ALSA
Última modificación: 13-01-2025, 18:30 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)
paco   15-01-2025, 13:07
#7
Muchas gracias Vuot, ha resultado muy útil tu aportación.

Creo que con un array tipo 'Byte' perdería mucho la resolución. Con 'Short' queda bien.

La solución 'gb.media' funciona bien, pero hay que exportar un fichero auxiliar para luego volver a importarlo, que es lo que quería evitar.

Lo que parece mejor es la API de ALSA. Todavía tengo que trabajar mas con esto, pero ya he conseguido que suene. Ahora tengo que afinarlo (por ejemplo, para que suene en estéreo, con dos canales de audio). Esto es un ejemplo del código con la API de ALSA. Es una implementación muy simple, pero funciona. Cualquier idea de mejora será bienvenida:

'array con las muestras de audio
private xondaL as new short[]

'frecuencia de muestreo
private fmuestreo as integer = 44100

'librera API de ALSA
Library "libasound:2.0.0" 
   
Private Const device As String = "default" 
Private Const SND_PCM_STREAM_PLAYBACK As Integer = 0 
Private Const SND_PCM_FORMAT_S16_LE As Byte = 2
Private Const SND_PCM_ACCESS_RW_INTERLEAVED As Integer = 3 
Private Extern snd_pcm_open(pcm As Pointer, name As String, pcm_stream As Integer, mode As Integer) As Integer
Private Extern snd_pcm_set_params(pcm As Pointer, formatI As Integer, accesso As Integer, channels As Integer, rate As Integer, soft_resample As Integer, latency As Integer) As Integer 
Private Extern snd_pcm_writei(pcm As Pointer, buffer As Short[], size As Integer) As Integer
Private Extern snd_strerror(errnum As Integer) As String
Private Extern snd_pcm_close(pcm As Pointer) 

'---------
'Aquí va la aplicación para generar las muestras de audio
'---------

Public Sub AlsaPlay()
Dim err, frames As Integer
Dim handle As Pointer

  err = snd_pcm_open(VarPtr(handle), device, SND_PCM_STREAM_PLAYBACK, 0)
  If err < 0 Then Error.Raise("Error en la apertura del sub-sistema PCM: " & snd_strerror(err))
   
  err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 1, fmuestreo, 1, 500000)
  If err < 0 Then Error.Raise("Error en los parmetros del sub-sistema PCM: " & snd_strerror(err))

  frames = snd_pcm_writei(handle, xondaL, xondaL.Length)
  If frames < 0 Then Error.Raise("Error en la funcion 'snd_pcm_writei' !")

  snd_pcm_close(handle) 
End
  
Usuarios navegando en este tema: 1 invitado(s)
Powered By MyBB, © 2002-2025 MyBB Group.
Made with by Curves UI.