5.5 El programa VolMeter

El medidor de volumen es un programa escrito en Java llamado VolMeter. Es un bucle sin fin que lee la entrada estándar y calcula el valor máximo (en valor absoluto) para cada canal de un conjunto de muestras. Este valor máximo es el que se utiliza para pintar las columnas con los volúmenes.

5.5.1 Entradas

VolMeter acepta una secuencia RAW (sin cabecera) de muestras a través de entrada estándar. Debe tratarse de una secuencia de muestras de 16 bits, con signo, en formato little endian (el usado en las máquinas Intel). Se esperan dos canales.

5.5.2 Controles

VolMeter sólo acepta un parámetro de entrada desde la línea de comandos: el tamaño del buffer de audio. Con él controlamos el número de muestras a las que se le calcula el máximo antes de calcular el valor del volumen.

5.5.3 Salidas

La única salida del programa es una ventana con una doble columna con el volumen de cada canal de la señal. La ventana es redimensionable.

5.5.4 VolMeter.java

/*  
 * Crea una ventana redimensionable en la que aparecen dos columnas  
 * que miden el volumen máximo registrado en dos canales de audio, a  
 * 16 bits por muestra y usando el endian de la máquina.  
 *  
 * Los datos son leídos de la entrada estándar.  
 *  
 * gse. 2006.  
 */  
 
/* Evento de manipulación de excepciones de entrada/salida. */  
import java.io.IOException;  
 
/* Un JComponent implementa las funciones más básicas de cualquier  
 * objeto de la biblioteca Swing. En este caso se utiliza para pintar  
 * el medidor de volumen. */  
import javax.swing.JComponent;  
 
/* Un Frame es una ventana con título y marco. */  
import javax.swing.JFrame;  
 
/* Almacena el contexto gráfico. */  
import java.awt.Graphics;  
 
/* Define un color. */  
import java.awt.Color;  
 
public class VolMeter  
    extends JComponent {  
 
    /* Muestras pintadas (máximo de cada canal). */  
    int leftSample, rightSample;  
 
    /* Anchura y altura por defecto de la ventana. */  
    static final int WINDOW_WIDTH = 100;  
    static final int WINDOW_HEIGHT = 100;  
 
    /* Tamaño por defecto del buffer de audio. */  
    static final int DEFAULT_BUF_SIZE = 22050;  
 
    /* Tamaño del buffer de audio. */  
    int buf_size;  
 
    /* El buffer de audio. */  
    byte[] audio_buf;;  
 
    /* Crea la ventana e inicializa las variables miembro. Finalmente  
     * lanza el resto de la aplicación. */  
    public VolMeter(int buf_size) {  
        JFrame frame = new JFrame("VolMeter");  
        frame.getContentPane().add(this);  
        frame.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);  
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
        frame.setVisible(true);  
        this.buf_size = buf_size;  
        audio_buf = new byte[buf_size];  
        run();  
    }  
 
    /* Calcula el máximo de cada canal y lo pinta. */  
    public void run() {  
        try {  
            for(;;) {  
                int bytes_read = System.in.read(audio_buf);  
                //System.out.write(audio_buf, 0, bytes_read);  
                leftSample = rightSample = 0;  
                for(int i=0; i<buf_size/4; i+=4) {  
                    int le = (int)(audio_buf[i*2+1])*256 + (int)(audio_buf[i*2]);  
                    int ri = (int)(audio_buf[i*2+3])*256 + (int)(audio_buf[i*2+2]);  
                    int abs_le = Math.abs(le);  
                    int abs_ri = Math.abs(ri);  
                    if(leftSample<abs_le) leftSample = abs_le;  
                    if(rightSample<abs_ri) rightSample = abs_ri;  
                }  
                //System.out.println(leftSample + " " + rightSample);  
                repaint();  
            }  
 
        } catch (IOException e) {  
            System.out.println("Error en el pipe");  
        }  
    }  
 
    /* Pinta las gráficas. */  
    public void paintComponent(Graphics g) {  
        Color color;  
 
        /* Canal izquierdo. */  
        color = Color.green;  
        g.setColor(color);  
        int l = (int)((double)(leftSample)/32768.0*getHeight());  
        if(leftSample >= 32000) {  
            color = Color.black;  
            g.setColor(color);  
        }  
        g.fillRect(0, 0, getWidth()/2-1, l);  
 
        /* Canal derecho. */  
        color = Color.blue;  
        g.setColor(color);  
        int r = (int)((double)(rightSample)/32768.0*getHeight());  
        if(rightSample >= 32000) {  
            color = Color.black;  
            g.setColor(color);  
        }  
        g.fillRect(getWidth()/2, 0, getWidth(), r);  
    }  
 
 
    public static void main(String args[]) throws Exception {  
        try {  
            if(args.length >=1) {  
                new VolMeter(Integer.parseInt(args[0]));  
            } else {  
                new VolMeter(DEFAULT_BUF_SIZE);  
            }  
        } catch (NumberFormatException e) {  
            System.out.println("Error parsing " + args[1]);  
        }  
    }  
}