Mini Manual de OpenAL Por Daniel Barrero (dbarrero@cable.net.co) - 22/4/2002 Basado en los excelentes tutoriales de: Jorge bernal Martinez (lordloki@users.berlios.de , http://worldspace.berlios.de/openal/index.html) Introducción Open AL es una interface de software para el hardware de sonido de manera analoga al modo como OpenGL es una interface de software para el hardware grafico, esta interface consiste de una serie de comandos para la manipulacion de ondas sonoras, incluyendo la posicion de las fuentes de sonidos (emisores) asi como los receptores de audio. La característica principal de esta libreria es su capacidad de proporcionarn un sonido 3D, es decir, el sonido variara dependiendo de donde la ubicacion en el espacio del receptor, sus movimientos respectivos, de los objetos que se encuentren definidos en la escena, etc. Dicho sonido también dependerá de donde se encuentre la fuente de sonido, de su velocidad, de si se aleja o se acerca, y del tipo de sala en la que nos encontremos. Los principales conceptos que se utilizaran con mayor frecuencia: Efecto Doppler : Este efecto es debido principalmente a la velocidad relativa de la fuente de sonido (source) con respecto al observador (listener) y en menor medida a la velocidad del sonido en el medio donde nos encontremos. Lo que produce dicho efecto es un cambio de intensidad que se manifiesta de la forma siguiente--> cuando la fuente sonora se acerca al observador el sonido parece mas agudo y cuando la fuente sonora se aleja del observador el sonido parece mas grave. Un ejemplo sencillo en el que se nota dicho efecto es cuando llega un tren a la estación y cuando se aleja dicho tren de la estación. Nivel de intensidad : El decibelio (dB) es la unidad en la que medimos la intensidad de los sonidos. El oído humano tiene una respuesta logarítmica a los estímulos o sonidos que le llegan por lo que la formula para obtener la intensidad de dichos sonidos será : dB = 10 * log ( I / Io) , donde Io = intensidad de referencia Debido a la respuesta logarítmica del oído respecto del sonido se tiene que el nivel de intensidad (en dB) de dos o mas fuentes no va a ser igual a la suma de los niveles de intensidades de cada fuente, es decir que por ejemplo dos fuentes de 10 dB de nivel de intensidad no es igual a una fuente de 20 dB sino que es igual a una fuente de 13 dB. La suma de diversas fuentes sigue la siguiente formula: Atenuación por la distancia : Debido al incremento de la separación del observador respecto de la fuente de sonido se produce una disminución del nivel de intensidad de dicha fuente. Esto es debido a que el nivel de intensidad de una fuente es proporcional a la potencia de dicha fuente e inversamente proporcional al cuadrado de la distancia, es decir I = W / A donde W es la potencia en watios y A es el area de la esfera que rodea ala fuente (ya que el sonido se propaga en todas las direcciones) y tiene un valor de 4*PI*radio al cuadrado. Por lo tanto sustituyendo en la formula de niveles de intensidad podemos obtener la atenuación o ganancia de decibelios debido a la distancia: Reverberación : Es cuando el sonido se refleja en todas las direcciones y con igual modulo y probabilidad pudiendo llegar al observador una vez que ha terminado de emitirse dicho sonido. Requerimientos: Windows: Librerias OpenAL32.lib, Alut.lib, archivos de encabezados, libreria dinamica OpenAL32.dll, estas se pueden obtener en modo binario o fuentes en : http://www.openal.org/home Tutoriales en español se pueden encontrar en : http://worldspace.berlios.de/openal/index.html Ejemplo de aplicacion OpenAL y OpenGL anotado : El objetivo de este programa es definir 3 emisores de sonido localizados en ubicaciones diferentes en el espacio, adicionalmente se define un receptor activo el cual se puede mover en el espacio demostrando el cambio del sonido percibido de cada fuente a medida que este se desplaza. /* Incluir librerias standard, OpenGL y OpenAL #include <gl/glut.h> #include "AL/alut.h" #include <stdlib.h> #include <stdio.h> */ /* definir numero de buffers y fuentes a utilizar (iguales en este caso) #define NUM_BUFFERS 3 #define NUM_SOURCES 3 /* definir numero de ambientes de sonido */ #define NUM_ENVIRONMENTS 1 /* definir la posicion velocidad y orientacion del receptor */ ALfloat listenerPos[]={0.0,0.0,4.0}; ALfloat listenerVel[]={0.0,0.0,0.0}; Alfloat listenerOri[]={0.0,0.0,1.0, 0.0,1.0,0.0}; /* definir las posiciones, velocidaded y orientaciones de cada emisor */ ALfloat ALfloat ALfloat ALfloat ALfloat ALfloat source0Pos[]={ source0Vel[]={ source1Pos[]={ source1Vel[]={ source2Pos[]={ source2Vel[]={ -2.0, 0.0, 0.0}; 0.0, 0.0, 0.0}; 2.0, 0.0, 0.0}; 0.0, 0.0, 0.0}; 0.0, 0.0, -4.0}; 0.0, 0.0, 0.0}; /* reservar buffers de sonido */ ALuint buffer[NUM_BUFFERS]; ALuint source[NUM_SOURCES]; ALuint environment[NUM_ENVIRONMENTS]; int GLwin ; ALsizei size,freq; ALenum format; ALvoid *data; int ch; */ void init(void) { glClearColor(0.0,0.0,0.0,1.0) ; ALint error; /* definir repeticion del sonido en loop */ ALboolean loop=1; /* asignar posicion, velocidad y orientacion al receptor */ alListenerfv(AL_POSITION,listenerPos); alListenerfv(AL_VELOCITY,listenerVel); alListenerfv(AL_ORIENTATION,listenerOri); /* pedir a openAL la generacion de los buffers */ alGenBuffers(NUM_BUFFERS,buffer); if ((error = alGetError()) != AL_NO_ERROR) { printf("- Error creating buffers !!\n"); exit(1); } /*cargar archivos de sonido y asignarlos a los emisores */ alutLoadWAVFile("c.wav",&format,&data,&size,&freq,&loop); alBufferData(buffer[0],format,data,size,freq); alutUnloadWAV(format,data,size,freq); alutLoadWAVFile("b.wav",&format,&data,&size,&freq,&loop); alBufferData(buffer[1],format,data,size,freq); alutUnloadWAV(format,data,size,freq); alutLoadWAVFile("a.wav",&format,&data,&size,&freq,&loop); alBufferData(buffer[2],format,data,size,freq); alutUnloadWAV(format,data,size,freq); alGenSources(NUM_SOURCES,source); if ((error = alGetError())!=AL_NO_ERROR) { printf("- Error creating sources !!\n"); exit(2); } /* definir parametros de control del sonido para cada emisor */ alSourcef(source[0],AL_PITCH,1.0f); alSourcef(source[0],AL_GAIN,1.0f); alSourcefv(source[0],AL_POSITION,source0Pos); alSourcefv(source[0],AL_VELOCITY,source0Vel); alSourcei(source[0],AL_BUFFER,buffer[0]); alSourcei(source[0],AL_LOOPING,AL_TRUE); alSourcef(source[1],AL_PITCH,1.0f); alSourcef(source[1],AL_GAIN,1.0f); alSourcefv(source[1],AL_POSITION,source1Pos); alSourcefv(source[1],AL_VELOCITY,source1Vel); alSourcei(source[1],AL_BUFFER,buffer[1]); alSourcei(source[1],AL_LOOPING,AL_TRUE); alSourcef(source[2],AL_PITCH,1.0f); alSourcef(source[2],AL_GAIN,1.0f); alSourcefv(source[2],AL_POSITION,source2Pos); alSourcefv(source[2],AL_VELOCITY,source2Vel); alSourcei(source[2],AL_BUFFER,buffer[2]); alSourcei(source[2],AL_LOOPING,AL_TRUE); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ; glPushMatrix() ; glRotatef(20.0,1.0,1.0,0.0) ; glPushMatrix() ; glTranslatef(source0Pos[0],source0Pos[1],source0Pos[2]) ; glColor3f(1.0,0.0,0.0) ; glutWireCube(0.5) ; glPopMatrix() ; glPushMatrix() ; glTranslatef(source2Pos[0],source2Pos[1],source2Pos[2]) ; glColor3f(0.0,0.0,1.0) ; glutWireCube(0.5) ; glPopMatrix() ; glPushMatrix() ; glTranslatef(source1Pos[0],source0Pos[1],source0Pos[2]) ; glColor3f(0.0,1.0,0.0) ; glutWireCube(0.5) ; glPopMatrix() ; //the listener glPushMatrix() ; glTranslatef(listenerPos[0],listenerPos[1],listenerPos[2]) ; glColor3f(1.0,1.0,1.0) ; glutWireCube(0.5) ; glPopMatrix() ; glPopMatrix() ; glutSwapBuffers() ; } void reshape(int w, int h) // the reshape function { glViewport(0,0,(GLsizei)w,(GLsizei)h) ; glMatrixMode(GL_PROJECTION) ; glLoadIdentity() ; gluPerspective(60.0,(GLfloat)w/(GLfloat)h,1.0,30.0) ; glMatrixMode(GL_MODELVIEW) ; glLoadIdentity() ; glTranslatef(0.0,0.0,-6.6) ; } void keyboard(unsigned char key, int x, int y) { switch(key) { case '1': /*activar emisor (loop infinito) */ alSourcePlay(source[0]); break; case '2': alSourcePlay(source[1]); break; case '3': alSourcePlay(source[2]); break; case '4': /*desactivar emisor (parar loop de sonido) */ case case case case /* cambiar posicion case case alSourceStop(source[0]); break; '5': alSourceStop(source[1]); break; '6': alSourceStop(source[2]); break; 'a': 'A': listenerPos[0] -= 0.1 ; del receptor */ alListenerfv(AL_POSITION,listenerPos); break ; 's': 'S': case case case case case listenerPos[0] += 0.1 ; alListenerfv(AL_POSITION,listenerPos); break ; 'q': 'Q': listenerPos[2] -= 0.1 ; alListenerfv(AL_POSITION,listenerPos); break ; 'z': 'Z': listenerPos[2] += 0.1 ; alListenerfv(AL_POSITION,listenerPos); break ; 27 : alSourceStop(source[2]); alSourceStop(source[1]); alSourceStop(source[0]); alutExit(); glutDestroyWindow(GLwin) ; exit(0) ; default: break ; } glutPostRedisplay() ; } int main(int argc, char** argv) //finaly the main function { //initialise glut glutInit(&argc, argv) ; glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH) ; glutInitWindowSize(400,400) ; //inicializar openAL alutInit(&argc, argv) ; GLwin = glutCreateWindow("OpenAL & OpenGL | www.dev-gallery.com") ; init() ; glutDisplayFunc(display) ; glutKeyboardFunc(keyboard) ; glutReshapeFunc(reshape) ; glutMainLoop() ; return 0; }