Professional Documents
Culture Documents
Resumen de la modificacin.
Gua para el programador de sonido con Java.
Fecha
19-12-2000
Resumen.
Este documento es una gua para el programador que quiere empezar a utilizar el sonido que le proporciona el sistema multimedia que utiliza.
Palabras relacionadas.
Java, programacin, sonido, procesado, voz, seal, api.
ndice.
Historial del documento. ndice. Glosario. mbito y alcance del documento. Convenciones del documento. 1 Introduccin. 2 Clases principales. 2.1 Formatos de audio. 2.2 Arquitectura de los sistemas. 2.3 Mixers. 2.4 Lines. 2.5 Clases DataLine. 3 Acceso a los componentes del sistema. 3.1 Obtencin de los recursos. 4 Reproduccin de sonido. 4.1 Reproduccin del sonido mediante SourceDataLine. 4.2 Sincronizacin de lneas. 4.3 Captura de sonido. 4.4 Procesado de la seal. Bibliografa.
Glosario.
API: Application Program Interface. Es la interfaz proporcionada por un sistema al programador para poder acceder a los servicios de ese sistema. Array: Es un grupo de datos de un tipo determinado puestos uno a continuacin de otro. Coincide con los tipos de datos array de Java. Java: Lenguaje objetos. de programacin orientado a
JDK: Java Development Kit. Es el entorno de desarrollo para Java proporcionado por Sun. MIDI: Estndar para el almacenamiento y transporte de msica para o desde un sintetizador. Package: Paquete. Agrupamiento especificado por el programador de clases con caractersticas comunes. Sun: Empresa norteamericana que desarroll el lenguaje de programacin Java. Thread: Hilo de ejecucin.
1 Introduccin.
El API de Java dedicada al sonido es la llamada Java Sound API proporcionado ya con el entorno de desarrollo de Sun. Este API se compone de 4 packages(paquetes): javax.sound.sampled. javax.sound.sampled.spi. javax.sound.midi. javax.sound.midi.spi. El primero, javax.sound.sampled, contiene las clases necesarias para el manejo del sonido muestreado, esto incluye la captura, la mezcla y la reproduccin de audio, proporcionando adems algn control y efecto sobre el sonido as como interfaces para el almacenamiento, ser el package estudiado en este documento. El package javax.sound.midi proporciona las interfaces de sntesis, secuenciamiento y transporte MIDI. Los packages javax.sound.sampled.spi yjavax.sound.midi.spi pro porcionan una interfaz para los desarrolladores de servicios basados en las interfaces anteriores.
2 Clases principales.
Como paso previo es necesario contar cmo funcionan algunos de los objetos de javax.sound.sampled necesarios para comprender despus cada uno de los procedimientos a seguir.
float getSampleRate(); frecuencia de muestreo. int getSampleSizeInBits(); en bits de cada */ boolean isBigEndian(); alineamiento big endian y */
Adems de los mtodos boolean maches(AudioFormat) y String toString() y los heredados de la clase Object. Por otro lado existe la clase AudioFileFormat para definir el formato de un fichero de audio, esta clase permite utilizar las clases AudioImputStream yAudioOutputStream, que heredan de ImputStream y OutputStream respectivamente, permitiendo usar los mtodos estndar para la lectura y escritura del audio en ficheros. El funcionamiento de estas clases se escapa al mbito de este documento.
2.3 Mixers
Como se puede ver los Mixer (mezcladores) son unos casos particulares de los Lines. Estos Mixer son dispositivos hardware o software por lo que pueden ser proporcionados por el sistema. Los objetos Mixer contienen un objeto de la clase Mixer.Info con informacin del tipo de Mixer. Los mtodos de la claseMixer son los siguientes:
Line getLine(Line.Info); exixte, un Line del tipo el parmetro. */ int getMaxLines(Line.Info); numero de lineas que se de un tipo dado. */ Mixer.Info getMixerInfo(); objeto que indica el que es. */ Line.Info [] getSourceLineInfo(); con informacin de /* Obtiene, si indicado en
los SourceLines disponibles. */ Line.Info [] getSourceLineInfo(Line.Info); /* Array con informacin de los SourceLines de un tipo. */ Line [] getSourceLines(); /* Obtiene array con los SouceLines disponibles. */ Line.Info [] getTargetLineInfo(); /* Obtiene array con informacin de
los TargetLines disponibles. */ Line.Info [] getTargetLineInfo(Line.Info); /* Array con los TargetLines de un tipo. */ Line [] array getTargetLines(); con los TargetLines /* Obtiene disponibles. */ boolean isLineSupported(Line.Info); si tiene un Line /* Devuelve true informacin de
del tipo especificado. */ boolean isSincronizationSupported( Line[], boolean); /* Devuelve true si se soporta sincronizacin entre las lineas especificadas en el primer parmetro, el segundo parmetro indica el tipo de sincronizacin: muestra a muestra si es true o slo en los metodos start() y stop() si es false. */ void sincronize(Line[], boolean); /* Sincroniza las lineas especificadas en el primer parmetro, el segundo parmetro indica el tipo de sincronizacin: muestra a muestra si es true o slo en los metodos start() y stop() si es false. */ void unsincronize(Line[]); /* Desincroniza las lineas indicadas. */
2.4 Lines.
Un Line (lnea) es una conexin por la que pasa la seal desde o hacia un Mixer. Los tipos de Lines son los siguientes: Port: Puertos de entrada o salida del sistema como el micrfono, la salida de lnea, el altavoz, etc.
DataLine: Lneas de datos, pueden ser Clips que almacenan un sonido completo, SourceDataLine que proporcionan un buffer de entrada a un Mixer yTargetDataLine que proporcionan el buffer de salida de un Mixer. Mixer: Mezclador que representa dispositivo hardware o software del sistema. un
Los Lines proporcionan cierta funcionalidad al sistema por medio de objetos Control que incluyan capaces de variar alguna caracterstica del sonido (ganancia, reverberacin, etc.), del estado (el Status) que puede ser abierto y cerrado (Open y Closed) de tal manera que si el Line est cerrado no consume recursos del sistema y por ltimo por medio de los objetos Event (eventos) lanzados que permiten comunicacin y sincronizacin con otros objetos. Como ya veremos los objetos Line tienen un objeto (de clase Line.Info) de informacin sobre ellos. Como ocurre con la mayor parte de los atributos y mtodos, el objeto de informacin se redefine en los objetos que lo heredan siendo de tipo Mixer.Info, Port.Info, etc. en cada uno de los casos. Los mtodos de la clase Line son:
void addLineListener( LineListener); objeto al que se le Event generados. void close(); Status Closed) Line. */ /* Cierra (pasa a el */ objeto /* Especifica un envan los
Control getControl( Control.Type); objeto Control del tipo */ Control [] getControls(); array con los objetos
disponibles. */ Line.Info getLineInfo(); /* Devuelve informacin del objeto. */ boolean isControlSupported(Control.Type); /* Devuelve true si soporta el tipo de Control especificado. */ boolean isOpen(); /* Devuelve true si el Status es Open. */ void open(); /* Abre (pasa a Status Open) el objeto Line. */ void removeLineListener(LineListener); /* Deja de enviar objetos Event al LineListener especificado. */
void flush(); buffer. */ int getBufferSize(); buffer en bytes. */ AudioFormat getFormat(); audio.
/* Este metodo limpia el /* Devuelve el tamao del /* Devuelve el formato del manejado.
*/ int getFramePosition(); /* Devuelve la posicin de la trama. */ float getLevel(); /* Devuelve el nivel de la seal. */ long getMicrosecondPosition(); /* Obtiene la posicin actual de los datos de audio en microsegundos. */ boolean isActive(); /* Devuelve true si estan pasando datos (ejecutado el comando start) */ boolean isRunning(); /* Devuelve true si est abierto. */ void start(); /* Comienza la reproduccin. */ void stop(); /* Termina la reproduccin. */
/* Devuelve un AudioInputStream asuciado a un fichero static Line getLine(Line.Info); /* Obtiene un objeto Line del tipo especificado en el parmetro. */ static Mixer getMixer(Mixer.Info); /* Obtiene un objeto Mixer del tipo especificado en el parmetro. */ static Mixer.Info[] getMixerInfo(); /* Obtiene un array con la informacin de los objetos Mixer existentes en el sistema. */ static Line.Info[] getSourceLineInfo(Line.Info p1); /* Obtiene un array con la informacin de los objetos Line existentes en el sistema. */ static AudioFormat.Encoding[] getTargetEncodings(AudioFormat); static AudioFormat.Encoding[] getTargetEncodings(AudioFormat.Encoding); /* Obtiene los tipos de codificacin sopurtados para un determinado formato de audio. */ static AudioFormat[] getTargetFormats(AudioFormat.Encoding, AudioFormat); /* Obtiene los objetos AudioFormat de un determinado tipo. */ static Line.Info[] getTargetLineInfo(Line.Info); /* Obtiene informacin de los objetos TargetLine de un determinado tipo. */ static boolean isConversionSupported(AudioFormat, AudioFormat); static boolean isConversionSupported(AudioFormat.Encoding, AudioFormat);
/* Devuelve true si se permite la canversin entre los formatos especificados. */ static boolean isFileTypeSupported(AudioFileFormat.Type); static boolean isFileTypeSupported(AudioFileFormat.Type, AudioInputStream); /* Devuelve true si se soporta el tipo de formato de fichero (para el AudioInputStream en el segundo caso). */ static boolean isLineSupported(Line.Info); /* Devuelve true si en el sistema existe un objeto Line del tipo especificado. */ static int write(AudioInputStream, AudioFileFormat.Type, java.io.File); static int write(AudioInputStream, AudioFileFormat.Type, java.io.OutputStream); /* Graba los datos de audio en un fichero o en un OutputStream segn el formato especificado. Devuelve el nmero de datos guardados. */
Para poder acceder a los distintos objetos del sistema se crean las clases de informacin, cuyas instancias proporcionan informacin sobre las distintas interfaces. Estas interfaces son Line.Info y las clases derivadas Mixer.Info, Port.Info y DataLine.In fo.
Para obtener un objeto Line de un determinado tipo podemos obtenerlo de un Mixer (ver apartado dedicado a los objetos Mixer) o de la claseAudioSystem con el mtodo getLine(Line.Info). Se puede construir un objeto DataLine.Info indicando en el constructor la clase del objeto del que informa (TargetDataLine.class o SourceDataLine.clas s) y un objeto de la clase AudioFormat. Es conveniente ver si un objeto Line del tipo deseado se soporta por el sistema, para ello se utiliza el mtodo isLineSupported() de la clase AudioSystem antes de intentar obtenerlo. La clase Port.Info proporciona unas constantes (instancias final static de clase Port.Info) que definen algunas lneas bsicas (Port.Info.COMPACT_DISC, Port.Info.HEADPHON E,Port.Info.LINE_IN, Port.Info.LINE.OUT y Po rt.Info.SPEAKER). Para obtener un array con informacin de las lneas existentes en el sistema se usan las funciones getTargetLineInfo() y getSourcetLi neInfo(), de la clase AudioSystem, pasndoles los tipos de lneas que nos interesan. Por otro lado, los objetos Mixer implementan los mtodos getTargetLineInfo() ygetSourcetLine Info() que no necesitan parmetros y que devuelven informacin sobre sus objetos Line. Con el mtodo getLine(), del objeto Mixer, pasando como parmetro el Line.Info adecuado se obtiene la referencia al objeto Line deseado. Con estos datos es posible obtener un Line y manipularlo abrindolo, cerrndolo, etc. Hay que advertir que no es aconsejable cambiar el Status de losPorts ya que un usuario puede tener abierto o
cerrado estos puertos por conveniencia molestndole si la aplicacin los cambia de estado sin su consentimiento.
4 Reproduccin de sonido.
Antes de entrar en la reproduccin de sonido por medio de objetos SourceDataLine hay que hacer mencin as los objetos Clip. Un objeto de esta clase est pensado para almacenar el audio grabado de principio a fin, es la mejor solucin cuando se conoce de antemano el tamao de la seal a almacenar y es nica, as como cuando se desea repetir un sonido varias veces (por ejemplo en un lazo). Los ejemplo tpico de utilizacin es la reproduccin de sonido de ficheros no demasiado grandes, en este caso se lee el contenido del fichero en un clip y luego se reproduce, el control es ms sencillo y los recursos utilizados son menores. Sin embargo en los casos donde el audio es continuo o en ficheros de un gran tamao es preferible usar los otros tipos de DataLine(SourceDataLine o TargetDataLine) con el fin de no ocupar demasiada memoria del sistema. En nuestro caso nos centraremos en este segundo caso ya que nuestra fin es la adquisicin tratamiento y reproduccin de la seal sindonos de poca utilidad la clase Clip.
4.1
Reproduccin SourceDataLine
del
sonido
mediante
Los objetos SourceDataLine son la entrada de objetos Mixer, siendo necesario escribir en ellos los datos que se introducen en el Mixer. Los mtodos de estos objetos son:
void open(AudioFormat); void open(AudioFormat, int); // Redefinen el metodo de abir de Line pasando el formato de audio
// que van a manejar y, opcionalmente, el tamao en bytes del buffer. int write(byte [ ], int, int); // Escribe los datos en continuacin).
el
buffer
(ver
texto
El proceso a realizar para la escritura de datos en el SourceDataLine una vez obtenido es el siguiente: Se procede a abrirlo con el mtodo propio open(AudioFormat) o open(AudioFormat, int) donde el entero indica el tamao del buffer en bytes, si no se utilizan argumentos se pone un formato por defecto. Para conocer estos datos se pueden utilizar los mtodos getFormat() y getBufferSize() del objetoSourceDataLine. Con el mtodo start() la lnea empezar a reproducir sonido en cuanto tenga algo en el buffer. Para poner datos en el buffer se usa el mtodo int write(byte [] b, int offset, int length) donde b es el array de datos, offset indica a partir de donde, en el array b, se debe empezar a leer datos y length indica cuantos datos deben ser ledos. Esta funcin devuelve el nmero de datos ledos. Es muy importante tener en cuenta que todos estos datos vienen en bytes y no en nmero de muestras. Cuando sale la primera muestra del objeto Mixer (un instante despus de salir del SourceDataLine) se produce un evento de tipo START que puede ser recogido por el proceso a la salida del Mixer. El mtodo write() vuelve slo cuando ha escrito todos los datos en el buffer. Si se intenta
escribir ms datos de los que caben en el buffer el mtodo se bloquea hasta terminar. Para evitarlo con el mtodo available() se obtiene, en bytes, el tamao de la parte que queda libre en el buffer. Con el mtodo drain() el programa se bloquea hasta reproducir el sonido, vaciando el buffer antes de volver. Con el mtodo stop() se para la reproduccin, sin limpiar el buffer, y con start() contina dnde se qued, para evitar la reproduccin de un segmento antiguo al llamar a start() se puede utilizar el mtodo flush() que limpia el buffer. Todos estos mtodos de SourceDataLine son heredados de DataLine. Cuando deja de salir seal del Mixer procedente del SourceDataLine se genera un evento de tipo STOP. El mtodo isActive() devuelve true si estn saliendo datos (entre los eventos de tipo START y STOP), el mtodo isRunning() devuelve true si la lnea est abierta. Adems Line genera eventos de tipo OPEN y CLOSE al llamarse a las funciones correspondientes. Todos los eventos pertenecen a la clase LineEventy les debe de atender un objeto que implemente la interfaz LineListener. Para registrarlos se llama a la funcin de la clase Line, addLineListener(), pasando como parmetro el objeto LineListener. La interfaz LineListener slo define un mtodo: void update(LineEvent). Los objetos LineEvent implementan los mtodos:
final long getFramePosition(); osicion de la trama. // Obtiene la
final Line getLine(); // Obtiene el objeto Line que lanz el evento. final Line Event.Type getType(); // Obtiene el tipo de evento. LineEvent(Line, LineEvent.Type, long); // Constructor. java.lang.String toString(); // Obtiene un String para la representacin.
El tipo de evento es un objeto de clase LineEvent.Type, esta clase tiene definida las constantes LineEvent.Type.CLOSE, LineEvent.T ype.OPEN,LineEvent.Type.START y LineEvent.T ype.STOP.
apartado de captura de sonido ya que todo se hace prcticamente igual. En la captura de audio los Ports (puertos) ponen datos en el Mixer y este en un objeto TargetDataLine que tiene los mtodos:
void open(AudioFormat); void open(AudioFormat, int); // Redefinen el metodo de abir de Line pasando el formato de audio que //van a manejar y, opcionalmente, el tamao en bytes del buffer. int read(byte [], int, int); // Lee los datos desde el buffer (ver texto a continuacin).
Aparte de los mtodos heredados. As se puede observar la cantidad de datos en el buffer con available() y leerlos con read(). Lo primero es obtener un objeto TargetDataLine (antes es necesario DataLine.Info) y abrirlo con open(), indicando, si es necesario, el formato de audio (si no, pone uno por defecto) y el tamao del buffer. Para leer los datos de TargetDataLine hay que utilizar el mtodo read() donde el primer parmetro es el array de bytes donde dejar los datos, el segundo es el offset a partir del que se dejan los datos en el array y el tercero indica el nmero de datos a leer. Para limpiar mtodo drain(). el buffer se utiliza el
Esta clase genera los mismos eventos que los que hemos visto en el caso anterior LineEvent, con los mismos valores
Cada clase hija de Control tiene un una clase Type incluida que define constantes para cada tipo de control. Para obtener un Control de un Line se puede usar el mtodo de ese Line getControl(Control.Type) que devuelve la instancia del Control, si queremos ver que controles soporta cada Linepodemos llamar al mtodo de Line getControls() que devuelve un array con todos los objetos Control soportados. Para saber que tipo de Control es el mtodo
del Control getType() devuelve un objeto de clase Control.Type y con el mtodo de Object getClass() se puede saber la clase derivada a la que pertenece el objeto. Para cambiar los parmetros de un objeto Control se utiliza el mtodo setValue() el tipo del parmetro de este mtodo depende de la clase del mtodo.
Bibliografa.
[1] [2] Java Sound API Programmers Guide [ver 1.0]. Sun Microsystems, Inc. 1999-2000. Java Sound 1.0 API Specification. Sun Microsystems, Inc. http://java.sun.com/j2se/1.3/docs/guide/ sound/. Java Sound Home Page. Diciembre 2000. http://java.sun.com/products/javamedia/sound/index.html.
[3]