Agradable con útil o desarrollo para ASIO en C ++


Como programador potencial y amante de la guitarra eléctrica, no podía evitar desarrollar software de música. Todos los que han intentado conectar una guitarra eléctrica a una computadora con Windows utilizando algún tipo de procesador de guitarra saben que a menudo se requiere una interfaz ASIO para estos fines (otros también son posibles, pero ASIO es el más popular). Esto se debe al hecho de que se dedica un tiempo considerable a procesar la entrada y salida de audio y, como resultado, se escucha un retraso desagradable al tocar un instrumento, lo que hace que el juego sea muy difícil. ASIO le permite omitir la etapa de mezcla de sonido cuando se emite y, en consecuencia, reduce significativamente el retraso. Lea más sobre esto aquí .

Cual es el problema


Decidí usar ASIO, porque el controlador es popular y conveniente, pero aquí me encontré con un problema: hay muy pocos artículos sobre el tema del desarrollo de esta tecnología. De hecho, todo lo que podía guiarme desde el principio: la documentación oficial del SDK y varios foros en inglés. Espero que si tienes un problema similar, el artículo te sea al menos un poco útil.

Biblioteca baja


El código del sitio web oficial de Stainberg que usa el SDK, que simplemente reproduce el silencio durante 20 segundos, toma 500 líneas. Sin embargo, hay una maravillosa biblioteca de Bass . Los fanáticos de trabajar con sonido saben cómo usarlo para crear flujos de sonido y canales, cómo aplicar efectos FX, mezclar ... Realmente espero que sí. Bass tiene un complemento Bassasio, que, de hecho, le permite configurar el controlador ASIO en unas pocas líneas de código y realizar la tarea idéntica al ejemplo anterior.

Instalar y configurar bibliotecas


  1. Descargue la biblioteca Bass y su complemento Bassasio . Este es el sitio oficial.
  2. Volcamos archivos .lib en una carpeta separada. En este caso, solté los archivos bass.lib y bassasio.lib en la carpeta Libs
  3. Los archivos .dll se transfieren a las carpetas Release y Debug . (bass.dll y bassasio.dll) Si esto no se hace, cuando ejecute el código de su aplicación, el programa arrojará un error como este:



  4. A continuación, en la configuración del proyecto, asignamos la ruta al vinculador con los archivos .lib al vinculador . Hacemos lo mismo para c / c ++ .





  5. Colocamos los archivos .h en la carpeta del proyecto y los incluimos en el proyecto, es decir, los archivos bass.h y bassasio.h .

    #include "bass.h" #include "bassasio.h" 


Ejemplo de uso


Por ejemplo, cree una pequeña aplicación de consola que reproduzca el sonido de una guitarra, es decir el programa redirigirá la transmisión desde la entrada de audio a la salida de audio. El código de la aplicación está disponible en el github, parece ser simple. Debería verse como un combo de guitarra (pegado y tocar), pero el sonido hasta ahora será claro (sin efectos).

Conectamos las bibliotecas en el párrafo anterior, ahora necesitamos inicializar los dispositivos de entrada y salida de sonido. ¡Empecemos!

BASS_Init () inicializa el dispositivo de salida de sonido y toma los siguientes parámetros como entrada:

Parámetros
int device : identificador del dispositivo de salida. Si configura el parámetro -1, se usará el dispositivo de salida estándar, si 0 - el sonido no se reproducirá en absoluto, es decir no se proporcionará a ningún dispositivo de salida.

DWORD freq - frecuencia de muestreo en Hz

DWORD flags - flags ... Hay muchos, puedes leer más en la documentación oficial www.un4seen.com/doc/#bass/BASS_Init.html . En resumen, con la ayuda de banderas puede elegir la profundidad de codificación de sonido, mono o estéreo, reproducción de sonido por más de dos altavoces, etc.

HWND win : instala la ventana principal de la aplicación. Para aplicaciones de consola, establezca en 0.

GUID * clsid - clase para inicializar el objeto que se usará para inicializar DirectSound. En otros casos, establezca en Nulo.

Inicializar el controlador ASIO es un poco más simple. Pasamos solo 2 parámetros a la función BASSASIO_Init :

Parámetros
int device : identificador del "dispositivo" ... la tecnología con la que funcionará la biblioteca. La cuestión es que si ha instalado software como una plataforma de guitarra o tiene una tarjeta de sonido con su propio controlador ASIO, verá varios elementos en la lista de "dispositivos" disponibles. Se puede obtener una lista llamando a la función BASS_ASIO_GetDeviceInfo () para cada identificador (clasificándolos). Como regla, 0 es nuestro controlador ASIO4ALL, que usaremos en el futuro. Un valor de -1 configurará el dispositivo por defecto, como se describe en la documentación.

 std::cout << "ASIO Devices info:" << std::endl; a = 0; count = 0; BASS_ASIO_DEVICEINFO asio_info; for (a = 0; BASS_ASIO_GetDeviceInfo(a, &asio_info); a++) std::cout << "Device " << a << ") " << asio_info.name << std::endl; std::cout << " ________ " << std::endl; 


Lista de conductores

DWORD flags - banderas. Solo hay 2 de ellos: BASS_ASIO_THREAD - ejecuta el controlador en un hilo separado y BASS_ASIO_JOINORDER - es responsable de la operación de los canales canales.

Código, inicialización del dispositivo de salida de sonido y controlador ASIO:

 try { if ( ! BASS_Init(0, 44100, 0, 0, NULL) ) throw BASS_ErrorGetCode(); if ( ! BASS_ASIO_Init( 0, NULL ) ) throw BASS_ASIO_ErrorGetCode(); } catch ( int err ) { std::cout << "Err no - " << err << std::endl; system("pause"); return; } 

Puede surgir la pregunta: ¿por qué el dispositivo de salida no se utiliza en BASS_Init (0)? El hecho es que la salida de audio se realizará a través de ASIO utilizando el complemento BASSASIO. No necesitamos una salida de sonido estándar usando la biblioteca BASS para implementar la tarea en cuestión, por lo tanto, 0. Sin embargo, vale la pena señalar un par de puntos:

  1. Puede trabajar el controlador ASIO en un dispositivo y emitir sonido utilizando medios estándar en otro (por ejemplo, se reproducirá música). Para hacer esto, solo seleccione diferentes dispositivos al inicializar BASS y configurar el controlador ASIO (Durante la operación, habrá su icono en el área de notificación).
  2. Para obtener una lista de los dispositivos disponibles, use BASS_GetDeviceInfo.
     setlocale(LC_ALL, "Rus"); std::cout << "Devices info:" << std::endl; int a, count = 0; BASS_DEVICEINFO info; for (a = 1; BASS_GetDeviceInfo(a, &info); a++) { if (info.flags&BASS_DEVICE_ENABLED) // device is enabled std::cout << "Device " << a << ") " << info.name << " is availible" << std::endl; else std::cout << "Device " << a << ") " << info.name << " is unable" << std::endl; } std::cout << " ________ " << std::endl; 



    BASS solo funciona con dispositivos que están actualmente activos. Los dispositivos desconectados simplemente no serán visibles.


    Dispositivos de salida de sonido activos

    BASSASIO es absolutamente igual independientemente de si el dispositivo fue desconectado por el sistema operativo o no. En la configuración del controlador, seleccione los dispositivos de entrada y salida de sonido que necesita.
  3. No tiene sentido tratar de emitir sonido usando BASS y BASSASIO simultáneamente en un solo dispositivo: la tecnología ASIO está diseñada específicamente para el hecho de que el sonido no será mezclado por el sistema operativo e irá directamente a la tarjeta de sonido para la salida posterior. Es decir solo escuchará el sonido de una aplicación que use ASIO.

A continuación, debemos dirigir el flujo de sonido desde el micrófono al dispositivo de salida de sonido. Hay varias formas de hacer esto. La forma más fácil es "reflejar" el canal.

Tenemos 3 canales: micrófono, auricular izquierdo y auricular derecho. Para transferir la señal del micrófono a los canales de salida, utilizamos la función

 BOOL BASS_ASIO_ChannelEnableMirror( DWORD channel -   BOOL input2 -   ? (0  1) DWORD channel2 –    ( ) ); 

Todo es simple aquí. Necesitamos transmitir la señal a los canales de salida 0 y 1 desde el canal de entrada 0:

 BASS_ASIO_ChannelEnableMirror( 0, 1, 0 ); BASS_ASIO_ChannelEnableMirror( 1, 1, 0 ); 

Entonces surge la pregunta: ¿cómo descubrí a qué canales necesito transmitir la señal? Respuesta: se puede encontrar información sobre los canales utilizando la función BASS_ASIO_ ChannelGetInfo .

 a = 0; BASS_ASIO_CHANNELINFO channel_info; std::cout << "inputs: " << std::endl; for (a = 0; BASS_ASIO_ChannelGetInfo(0, a, &channel_info ); a++ ) std::cout << a << ") " << channel_info.name << " format: " << channel_info.format << std::endl; std::cout << "Outputs: " << std::endl; for (a = 0; BASS_ASIO_ChannelGetInfo(1, a, &channel_info); a++) std::cout << a << ") " << channel_info.name << " format: " << channel_info.format << std::endl; std::cout << "__________" << std::endl; 



Todos los ajustes están listos. Inicio: BASS_ASIO_Start . Puede proporcionar parámetros para la longitud máxima de la muestra y el número de secuencias a la entrada, pero para nuestra tarea podemos dejar estos parámetros de forma predeterminada (rellenarlos con ceros).

 BASS_ASIO_Start( 0, 0 ); 

De hecho, eso es todo. Sin embargo, esta es una aplicación de consola, no se olvide del sistema ("pausa") , de modo que no se cierre inmediatamente después del inicio, e inmediatamente después de eso, libere memoria y deje de funcionar con los dispositivos y el controlador.

 BASS_ASIO_Stop(); BASS_ASIO_Free(); BASS_Stop(); BASS_Free(); return; 

Resumen


Dejaré el código fuente en el github .
Así que obtuvimos una aplicación de consola simple con tecnología ASIO. Al conectar el instrumento a la tarjeta de sonido, no escucharemos el retraso que podría haber sucedido con una conexión estándar utilizando herramientas estándar de Windows. Por supuesto, las posibilidades tanto de la biblioteca BASS como del complemento BASSASIO son más amplias que las presentadas anteriormente, sin embargo, ni el formato del artículo ni mi conocimiento serán suficientes para expresar absolutamente todo.

Si este tema fue al menos un poco interesante para usted, me alegraría intentarlo. A su vez, trataré de robar un poco de tiempo para escribir una secuela en la que podamos trabajar con efectos FX estándar del DX8 y obtener la apariencia de un simple procesador de guitarra.

Gracias por su atencion!

Source: https://habr.com/ru/post/464843/


All Articles