El programa usado en esta práctica para calcular el espectro de una señal de audio se llama RTASA (Real Time Audio Spectrum Analyzer).
RTASA 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.
RTASA acepta parámetros iniciales desde la línea de comandos e interactivamente (durante la ejecución), a través de diferentes elementos de entrada.
Los parámetros iniciales son:
Los otros controles interactivos son:
La única salida del programa es la gráfica del espectro (ventana Spectrum). En la parte superior aparece el espectro del canal izquierdo y abajo, el del canal derecho. La ventana es redimensionable.
/* Real Time Audio Spectrum Analyzer. */
/* * Versión inicial creada por Vicente González Ruiz <vruiz@ual.es>. * * Mejoras introducidas por Manuel Marín <niram@eresmas.net> * referentes al cálculo de la frecuencia con el puntero del ratón. * * gse. 2006. */ import java.awt.*; import javax.swing.*; import java.awt.event.*; //import java.net.DatagramSocket; //import java.net.InetAddress; //import java.net.DatagramPacket; import java.io.IOException; public class RTASA extends JComponent implements Runnable, ComponentListener,MouseMotionListener { ////////////////////////////////////////////////////// /* Variables y metodos relacionados con el raton */ //Variables para almacenar la posición actual del raton// Dimension d; int posX = 0, posY=0; int visualiza_frec; //Metodo de inicializacion de la funcion de rastreo del raton// public void init() { d = this.getSize(); addMouseMotionListener(this); } //Metodo de realizacion de acciones en el caso de arrastrar y soltar// public void mouseDragged(MouseEvent me) {} //Metodo de realizacion de acciones en el caso de movimiento del raton dentro de la pantalla //grafica. Dichas acciones consisten en calcular el valor de la frecuencia sobre el que //esta situado el puntero del raton. Para realizar el calculo, se multiplica la variable //bandWidth por la coordenada X de la posicion actual del raton en ese momento, restandole //a dicho resultado el desplazamiento de 20 pixeles existente, ya que la abcisa empieza en el //pixel 20. Para el calculo del valor de este desplazamiento se multiplica la variable //bandWidth por 20. El valor final de toda esta operacion lo recoge la variable visualiza_frec public void mouseMoved(MouseEvent me) { if (me.getX()>=20){ //Si el raton está situado a la derecha de los 20 pixeles de xoffset// visualiza_frec = (int)(bandWidth*me.getX()-(bandWidth*20)); //Obtiene la frecuencia con la coordenada x// //Escribe en la consola de texto el valor en Hz. Se puede prescindir de esta linea //ya que dicho valor ya aparece en la pantalla grafica System.out.println("Frecuencia: " + visualiza_frec +" Hz"); }else{ //Si se sale del margen izquierdo, para evitar escribir valores negativos// visualiza_frec = 0; System.out.println("Frecuencia: " + visualiza_frec +" Hz"); } //Se almacenan las coordenadas actuales x,y del raton// posX = me.getX(); posY = me.getY(); //Actualizar la pantalla grafica// this.repaint(); } /* Fin de las variables y metodos relacionados con el raton */ ////////////////////////////////////// /* Número de bandas (por defecto). */ static int NUMBER_OF_BANDS = 512; /* Número de muestras por segundo (por defecto). */ static int SAMPLE_RATE = 44100; /* Altura inicial de la ventana. */ static int WINDOW_HEIGHT = 512; /* Dimensiones de la ventana. */ int windowHeight, windowWidth; JFrame frame; Thread thread; /* Este hilo */ /* Número de bytes en cada muestra de audio. */ int bytesPerSample = 2; /* Número de canales. */ int channels = 2; /* Número de muestras por segundo (frecuencia de muestreo) */ float sampleRate; /* Ancho de banda mostrado */ float totalBandWidth; /* Ancho de banda de cada banda */ float bandWidth; YScale yScale; ElasticityControl ec; double elasticity; /* Factor de escala en el eje Y */ //float scale; /* Buffer de audio. */ byte[] audioBuffer; /* Tamaño del buffer de audio en bytes. */ int audioBufferSize; double[] leftSpectrum; double[] rightSpectrum; double[][] leftBuffer; double[][] rightBuffer; double[] window; /* Arena encima del espectro */ int[] leftSand, rightSand; /* Gravedad aplicada a la arena (0 -> ausencia de gravedad, 1 -> gravedad infinita */ double sandGravity=0.1; /* Tamaño del grano de arena */ int sandSize = 10; int numberOfBands; int numberOfSamples; //int numberOfSpectrumsPerPacket; //static final int PACKET_SIZE = 1024; //static final int SIZEOF_SAMPLE = 2; //static final int BUF_SIZE = 4096; //static final int PORT = 6789; //DatagramSocket socket; //DatagramPacket sendPacket; //DatagramPacket receivePacket; Color rojoOscuro; public RTASA(int numberOfBands, float sampleRate) throws IOException { System.out.println("+-----------------------------------+"); System.out.println("| Real Time Audio Spectrum Analizer |"); System.out.println("+-----------------------------------+"); this.sampleRate = sampleRate; System.out.println("Sample Rate = " + sampleRate + " samples/second"); this.numberOfBands = numberOfBands; int tmp = numberOfBands; boolean numberOfBandsIsAPowerOfTwo = true; int i = 0; while(tmp>1) { if((tmp%2)==1) { numberOfBandsIsAPowerOfTwo = false; break; } tmp >>= 1; i++; } if(numberOfBandsIsAPowerOfTwo==false) { System.out.println("I need a number of bands power of two ..."); numberOfSamples = (numberOfSamples>>i); } System.out.println("Number of bands = " + numberOfBands); numberOfSamples = numberOfBands*2; System.out.println("Number of samples = " + numberOfSamples); audioBufferSize = channels * numberOfSamples * bytesPerSample; audioBuffer = new byte[audioBufferSize]; //numberOfSpectrumsPerPacket = BUF_SIZE/numberOfSamples/2; leftBuffer = new double[numberOfSamples][2]; rightBuffer = new double[numberOfSamples][2]; leftSpectrum = new double[numberOfSamples]; rightSpectrum = new double[numberOfSamples]; window = new double[numberOfSamples]; leftSand = new int[numberOfSamples]; rightSand = new int[numberOfSamples]; computeWindow(1); totalBandWidth = computeTotalBandWidth(sampleRate); System.out.println("Total Band Width = " + totalBandWidth + " Hertzs"); bandWidth = computeBandWidth(sampleRate, numberOfBands); System.out.println("Band Width = " + bandWidth + " Hertzs"); //setDoubleBuffered(true); // Create and set up the RTASA window frame = new JFrame("RTASA - Spectrum"); //scale = numberOfSamples; // Controlador de la scala en el eje Y yScale = new YScale(numberOfSamples, numberOfSamples/10); frame.getContentPane().add(this); windowWidth = numberOfBands + 10; windowHeight = WINDOW_HEIGHT; frame.setSize(windowWidth, windowHeight); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.addComponentListener(this); Container content = frame.getContentPane(); content.setBackground(Color.black); frame.show(); // Controlador de la elasticidad del espectro azul ec = new ElasticityControl(); rojoOscuro = new Color(100, 0, 0); //Capturar movimiento del raton// init(); } /* Lanza el hilo */ public void start() { thread = new Thread(this); thread.setName("RealTimeAudioSpectrumAnalizer"); thread.start(); } /* Detiene el hilo */ public void stop() { thread = null; } public void computeWindow(int win_type) { Window.computeCoefficients(win_type, window); } public float computeTotalBandWidth(float sampleRate) { return sampleRate/2; } public float computeBandWidth(float sampleRate, int numberOfBands) { return (sampleRate/2)/numberOfBands; } public void setGravity(float gravity) { this.sandGravity = gravity; } public void run() { try { for(;;) { //int bytes_read = System.in.read(audioBuffer); //System.out.print("S"); //socket.send(sendPacket); //System.out.print("R"); //for(int i=0; i<numberOfSamples*SIZEOF_SAMPLE/PACKET_SIZE; i++) { //socket.receive(receivePacket); //for(int j=0; j<numberOfSpectrumsPerPacket; j++) { int total = 0; while(total<audioBufferSize) { total += System.in.read(audioBuffer,total,audioBufferSize-total); } //System.out.println(total + " "); for(int i=0; i<numberOfSamples; i++) { //System.out.print("."); /* Parte real, muestra izquierda. */ leftBuffer[i][0] = (double)(audioBuffer[4*i+1]*256 + audioBuffer[4*i]); /* Parte imaginaria, muestra izquierda. */ leftBuffer[i][1] = 0.0; /* Parte real, muestra derecha. */ rightBuffer[i][0] = (double)(audioBuffer[4*i+3]*256 + audioBuffer[4*i+2]); /* Parte imaginaria, muestra derecha. */ rightBuffer[i][1] = 0; } /* Transformada de Fourier del canal izquierdo. */ FFT.direct(leftBuffer); /* Transformada de Fourier del canal derecho. */ FFT.direct(rightBuffer); /* Obtenemos la elasticitad de la arena. */ elasticity = ec.getElasticity(); /* Calculamos el espectro (módulo). */ for(int i=0; i<numberOfSamples; i++) { leftSpectrum[i] = Math.sqrt(leftBuffer[i][0]*leftBuffer[i][0] + leftBuffer[i][1]*leftBuffer[i][1]); rightSpectrum[i] = Math.sqrt(rightBuffer[i][0]*rightBuffer[i][0] + rightBuffer[i][1]*rightBuffer[i][1]); } /* Calculamos la arena. */ for(int i=0; i<numberOfSamples; i++) { leftSand[i] = (int)((1-elasticity)*leftSand[i] + elasticity*leftSpectrum[i]); rightSand[i] = (int)((1-elasticity)*rightSand[i] + elasticity*rightSpectrum[i]); } /* Pintamos. */ repaint(); } } catch (IOException e) { System.out.println("Error in the pipe."); } } // Este método no debería estar aquí. Si creamos una clase para // controlar el tamaño de la ventana debería de llamarse desde // allí. Lo mismo debería de ocurrir si creamos una clase para // controlar la frecuencia de muestreo. Esto se debe de hacer así // porque sólo cuando estas clases están trabajando es cuando debe // de cambiar la escala y no debería de pintarse siempre que se // presenta el espectro. void drawHz(Graphics g) { Color color = Color.black; g.setColor(color); for(int i=10; i<numberOfSamples/2; i+=50) { g.drawString(i*bandWidth + "", i, 10); } } /* Pinta la ventana */ public void paintComponent(Graphics g) { int xOffset = 20; int yOffset = 25; Color color = Color.red; //g.setColor(color); /* Pintamos el espectro del canal izquiero arriba. */ //color = new Color(255,0,0); g.setXORMode(new Color(255,0,0)); for(int i=0; i<numberOfSamples/2/*256*/; i++) { //Double y = new Double(spectrum[i]/numberOfSamples); //int x = y.intValue(); int x = (int)(leftSpectrum[i]/yScale.getScale()); //System.out.print(spectrum[i] + " " + x + " "); g.drawLine(i+xOffset, /*460*/yOffset, i+xOffset, /*460-x*/x+yOffset); //paintLine(i,yOffset,i,x+yOffset,g); //int val_i = (data[2*i]*256+data[2*i+1])/256; //int val_i1 = (data[2*(i+1)]*256+data[2*(i+1)+1])/256; //g.drawLine(i,val_i+128,i+1,val_i1+128); } /* Pintamos el espectro del canal derecho abajo. */ g.setXORMode(/*Color.green*/new Color(0,255,0)); for(int i=0; i<numberOfSamples/2/*256*/; i++) { //Double y = new Double(spectrum[i]/numberOfSamples); //int x = y.intValue(); int x = (int)(rightSpectrum[i]/yScale.getScale()); //System.out.print(rightSpectrum[i] + " " + x + " "); g.drawLine(i+xOffset, /*460*/yOffset+windowHeight-85, i+xOffset, /*460-x*/windowHeight-85+yOffset-x); //paintLine(i,yOffset,i,x+yOffset,g); //int val_i = (data[2*i]*256+data[2*i+1])/256; //int val_i1 = (data[2*(i+1)]*256+data[2*(i+1)+1])/256; //g.drawLine(i,val_i+128,i+1,val_i1+128); } //color = Color.blue; //g.setColor(color); g.setXORMode(/*Color.blue*/new Color(0,0,255)); for(int i=0; i<numberOfSamples/2; i++) { int x = (int)(leftSand[i]/yScale.getScale()); g.drawLine(i+xOffset, /*460-x*/x+yOffset, i+xOffset, /*450-x*/x+sandSize+yOffset); } //color = Color.green; //g.setColor(color); //color = Color.cyan; //g.setColor(color); //g.setXORMode(Color.cyan); //g.setColor(Color.cyan); //color = new Color(10,10,200); //g.setXORMode(color); for(int i=0; i<numberOfSamples/2; i++) { int x = (int)(rightSand[i]/yScale.getScale()); g.drawLine(i+xOffset, /*460-x*/yOffset+windowHeight-85-x, i+xOffset, /*450-x*/yOffset+windowHeight-85-sandSize-x); } //if(dakl) drawHz(g); g.setXORMode(Color.white); for(int i=0; i<numberOfBands; i+= 50) { g.drawString("" + (int)(i*bandWidth), i+xOffset, 15); g.drawString("" + (int)(i*bandWidth), i+xOffset, /*505*/windowHeight-40); } //g.setColor(Color.red); for(int i=0; i<numberOfBands; i+= 50) { g.drawLine(i+xOffset,18,i+xOffset,21); g.drawLine(i+xOffset,windowHeight-84+yOffset+3,i+xOffset,windowHeight-84+yOffset+6); } //Mostrar la frecuencia siguiendo al puntero del raton// if (posX>=xOffset && posX<=windowWidth){ //para no salirse de los márgenes establecidos// g.drawString("" +visualiza_frec + " Hz", posX, posY); //Mostrar linea vertical cuyas coordenadas de inicio y fin son los siguientes dos puntos: // origen(posX, 0) // fin(posX, windowHeight) g.drawLine(posX,0,posX,windowHeight); } } public void componentHidden(ComponentEvent e) { } public void componentMoved(ComponentEvent e) { } public void componentResized(ComponentEvent e) { Component c = e.getComponent(); windowHeight = c.getSize().height; //System.out.println(c.getSize().width + " " + c.getSize().height); } public void componentShown(ComponentEvent e) { } public static void main(String[] args) throws Exception { int numberOfBands = NUMBER_OF_BANDS; float sampleRate = SAMPLE_RATE; if(args.length>=1) { try { numberOfBands = new Integer(args[0]).intValue(); } catch (NumberFormatException e) { System.out.println("Error parsing \"" + args[1] + "\""); } } if(args.length>=2) { try { sampleRate = new Float(args[1]).floatValue(); } catch (NumberFormatException e) { System.out.println("Error parsing \"" + args[2] + "\""); } } RTASA analizador = new RTASA(numberOfBands, sampleRate); analizador.start(); } } |
import java.awt.*;
import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.text.NumberFormatter; import java.beans.*; import java.util.*; /** * Esta clase maneja la elasticidad del espectro azul. * * @author Vicente González Ruiz * @version 1-Junio-2004 */ /* * SliderDemo3.java is a 1.4 application that requires all the * files in the images/doggy directory. It adds a formatted text * field to SliderDemo.java. */ public class ElasticityControl extends JPanel implements /*ActionListener,*/ WindowListener, ChangeListener, PropertyChangeListener { static final int ELASTICITY_MIN = 0; static final int ELASTICITY_MAX = 1000; static final int ELASTICITY_INIT = 50; // Initial elasticity double elasticity = (double)ELASTICITY_INIT/(double)ELASTICITY_MAX; JFormattedTextField textField; JSlider slider; public ElasticityControl() { // Colocamos el textField y el slider uno encima de otro setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); // Creamos el label del slider JLabel sliderLabel = new JLabel("Elasticity (x1000): ", JLabel.CENTER); sliderLabel.setAlignmentX(Component.CENTER_ALIGNMENT); // Create the formatted text field and its formatter. java.text.NumberFormat numberFormat = java.text.NumberFormat.getIntegerInstance(); NumberFormatter formatter = new NumberFormatter(numberFormat); formatter.setMinimum(new Double((double)ELASTICITY_MIN/(double)ELASTICITY_MAX)); formatter.setMaximum(new Double((double)ELASTICITY_MAX)); textField = new JFormattedTextField(formatter); textField.setValue(new Integer(ELASTICITY_INIT)); textField.setColumns(3); //get some space textField.addPropertyChangeListener(this); //React when the user presses Enter. textField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),"check"); textField.getActionMap().put("check", new AbstractAction() { public void actionPerformed(ActionEvent e) { if (!textField.isEditValid()) { //The text is invalid. Toolkit.getDefaultToolkit().beep(); textField.selectAll(); } else try { //The text is valid, textField.commitEdit(); //so use it. } catch (java.text.ParseException exc) { } } }); //Create the slider. slider = new JSlider(JSlider.HORIZONTAL, ELASTICITY_MIN, ELASTICITY_MAX, ELASTICITY_INIT); slider.addChangeListener(this); //Turn on labels at major tick marks. slider.setMajorTickSpacing(500); slider.setMinorTickSpacing(50); slider.setPaintTicks(true); slider.setPaintLabels(true); slider.setBorder(BorderFactory.createEmptyBorder(0,0,10,0)); // Le redefinimos las etiquetas al slider Dictionary labelTable = slider.getLabelTable(); JLabel cero = new JLabel("0.0"); JLabel puntocinco = new JLabel("0.5"); JLabel uno = new JLabel("1.0"); labelTable.put(new Integer(ELASTICITY_MIN), cero); labelTable.put(new Integer((ELASTICITY_MAX - ELASTICITY_MIN)/2), puntocinco); labelTable.put(new Integer(ELASTICITY_MAX), uno); slider.setLabelTable(labelTable); // Create a subpanel for the label and text field. JPanel labelAndTextField = new JPanel(); //use FlowLayout labelAndTextField.add(sliderLabel); labelAndTextField.add(textField); // Put everything together. add(labelAndTextField); add(slider); setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); //createAndShowGUI(); //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); //Create and set up the window. JFrame frame = new JFrame("RTASA - Elasticity Control"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the content pane. //ElasticityControl animator = new ElasticityControl(); this.setOpaque(true); //content panes must be opaque frame.setContentPane(this); //Display the window. frame.pack(); frame.setVisible(true); } double getElasticity() { return elasticity; } /** Add a listener for window events. */ void addWindowListener(Window w) {} //React to window events. public void windowIconified(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowOpened(WindowEvent e) {} public void windowClosing(WindowEvent e) {} public void windowClosed(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} /** Listen to the slider. */ public void stateChanged(ChangeEvent e) { JSlider source = (JSlider)e.getSource(); int elast = (int)source.getValue(); elasticity = (double)elast/(double)ELASTICITY_MAX; if (!source.getValueIsAdjusting()) { //done adjusting textField.setValue(new Integer(elast)); } else { //value is adjusting; just set the text textField.setText(String.valueOf(elast)); } } /** * Listen to the text field. This method detects when the * value of the text field (not necessarily the same * number as you’d get from getText) changes. */ public void propertyChange(PropertyChangeEvent e) { if ("value".equals(e.getPropertyName())) { Number value = (Number)e.getNewValue(); if (slider != null && value != null) { slider.setValue(value.intValue()); } } } } |
/** * This class implements the FFT (Fast Fourier Transform) routines. * * @author Vicente González Ruiz. */ public class FFT { /** * Constructor for objects of class FFT_1D */ public FFT() { } /** * The Fast Fourier Transform (FFT). * The array length must be a power of two. * The array size is [L][2], where each sample is complex. * array[n][0] is the real part and array[n][1] is the imaginary part of * the sample n. * * @author URL: http://www.nauticom.net/www/jdtaft/JavaFFT.htm */ static void direct(double[][] array) { double u_r,u_i, w_r,w_i, t_r,t_i; int ln, nv2, k, l, le, le1, j, ip, i, n; n = array.length; ln = (int)( Math.log( (double)n )/Math.log(2) + 0.5 ); nv2 = n / 2; j = 1; for (i = 1; i < n; i++ ) { if (i < j) { t_r = array[i - 1][0]; t_i = array[i - 1][1]; array[i - 1][0] = array[j - 1][0]; array[i - 1][1] = array[j - 1][1]; array[j - 1][0] = t_r; array[j - 1][1] = t_i; } k = nv2; while (k < j) { j = j - k; k = k / 2; } j = j + k; } for (l = 1; l <= ln; l++) /* loops thru stages */ { le = (int)(Math.exp( (double)l * Math.log(2) ) + 0.5 ); le1 = le / 2; u_r = 1.0; u_i = 0.0; w_r = Math.cos( Math.PI / (double)le1 ); w_i = -Math.sin( Math.PI / (double)le1 ); for (j = 1; j <= le1; j++) /* loops thru 1/2 twiddle values per stage */ { for (i = j; i <= n; i += le) /* loops thru points per 1/2 twiddle */ { ip = i + le1; t_r = array[ip - 1][0] * u_r - u_i * array[ip - 1][1]; t_i = array[ip - 1][1] * u_r + u_i * array[ip - 1][0]; array[ip - 1][0] = array[i - 1][0] - t_r; array[ip - 1][1] = array[i - 1][1] - t_i; array[i - 1][0] = array[i - 1][0] + t_r; array[i - 1][1] = array[i - 1][1] + t_i; } t_r = u_r * w_r - w_i * u_i; u_i = w_r * u_i + w_i * u_r; u_r = t_r; } } } double[][] inverse( double[][] array ) { double u_r,u_i, w_r,w_i, t_r,t_i; int ln, nv2, k, l, le, le1, j, ip, i, n; n = array.length; ln = (int)( Math.log( (double)n )/Math.log(2) + 0.5 ); nv2 = n / 2; j = 1; for (i = 1; i < n; i++ ) { if (i < j) { t_r = array[i - 1][0]; t_i = array[i - 1][1]; array[i - 1][0] = array[j - 1][0]; array[i - 1][1] = array[j - 1][1]; array[j - 1][0] = t_r; array[j - 1][1] = t_i; } k = nv2; while (k < j) { j = j - k; k = k / 2; } j = j + k; } for (l = 1; l <= ln; l++) /* loops thru stages */ { le = (int)(Math.exp( (double)l * Math.log(2) ) + 0.5 ); le1 = le / 2; u_r = 1.0; u_i = 0.0; w_r = Math.cos( Math.PI / (double)le1 ); w_i = Math.sin( Math.PI / (double)le1 ); for (j = 1; j <= le1; j++) /* loops thru 1/2 twiddle values per stage */ { for (i = j; i <= n; i += le) /* loops thru points per 1/2 twiddle */ { ip = i + le1; t_r = array[ip - 1][0] * u_r - u_i * array[ip - 1][1]; t_i = array[ip - 1][1] * u_r + u_i * array[ip - 1][0]; array[ip - 1][0] = array[i - 1][0] - t_r; array[ip - 1][1] = array[i - 1][1] - t_i; array[i - 1][0] = array[i - 1][0] + t_r; array[i - 1][1] = array[i - 1][1] + t_i; } t_r = u_r * w_r - w_i * u_i; u_i = w_r * u_i + w_i * u_r; u_r = t_r; } } return array; } /* end of ifft_1d */ } |
/** * Write a description of class Window here. * * @author (your name) * @version (a version number or a date) */ public class Window { /** * Constructor for objects of class Window */ public Window() { } /** * http://www.nauticom.net/www/jdtaft/JavaWindows.htm */ static double[] computeCoefficients( int win_type, double[] coeffs ) { int n; int m; double twopi; m = coeffs.length; twopi = 2.*Math.PI; switch( win_type ) { case 1: /* Hamming */ for( n = 0; n < m; n++ ) { coeffs[n] = 0.54 - 0.46*Math.cos( twopi*n/(m-1) ); coeffs[n] *= 0.5*(1. - Math.cos(twopi*n/(m-1)) ); } break; case 2: /* von Hann (sometimes improperly called Hanning) */ for( n = 0; n < m; n++ ) { coeffs[n] = 0.5*(1.0 - Math.cos(twopi*n/(m-1)) ); } break; case 3: /* Blackman */ for( n = 0; n < m; n++ ) { coeffs[n] = 0.42 - 0.5*Math.cos(twopi*n/(m-1)) + 0.08*Math.cos(2.*twopi*n/(m-1)); } case 4: /* Bartlett */ for( n = 0; n <= (m-1)/2; n++ ) { coeffs[n] = 2.*n/(m-1); } for( n = (m-1)/2; n < m; n++ ) { coeffs[n] = 2. - 2.*n/(m-1); } break; case 5: /* 4 term Blackman-Harris */ double a0; double a1; double a2; double a3; a0 = 0.35875; a1 = 0.48829; a2 = 0.14128; a3 = 0.01168; for( n = 0; n < m; n++ ) { coeffs[n] = a0 - a1* Math.cos(twopi*(double)(n+0.5)/m) + a2*Math.cos(twopi*2.*(double)(n+0.5)/m) - a3*Math.cos(twopi*3.*(double)(n+0.5)/m); } break; default: break; } return coeffs; } } |
import java.awt.*; import javax.swing.*; import java.awt.event.*; /** * Esta clase maneja la escala del eje Y (potencia). * * @author Vicente González Ruiz * @version 28-Mayo-2004 */ public class YScale { private JFrame frame; private JPanel panel; private JLabel scaleLabel, stepLabel; /* Factor de escala en el eje Y */ private double scale, step; class ScaleControl extends JLabel implements MouseWheelListener { ScaleControl(String str, int horizontalAlignment){ super(str,horizontalAlignment); super.addMouseWheelListener(this); } public void mouseWheelMoved(MouseWheelEvent e) { int wheelRotationDir = e.getWheelRotation(); if(wheelRotationDir < 0) { scale -= step; if(scale <= 1.0) scale = 1.0; } else { scale += step; } this.setText("Scale = " + scale); } } class StepControl extends JPanel implements ActionListener { String initialStepString; String x100String = "Step = 100.0"; String x10String = "Step = 10.0"; String x1String = "Step = 1.0"; double initialStep; StepControl(double initialStep) { this.initialStep = initialStep; Double initialStepObj = new Double(initialStep); initialStepString = new String("Step = " + initialStepObj.toString()); // 1. Creating the radio buttons JRadioButton initialStepButton = new JRadioButton(initialStepString); initialStepButton.setActionCommand(initialStepString); initialStepButton.setSelected(true); JRadioButton x100Button = new JRadioButton(x100String); x100Button.setActionCommand(x100String); //x100Button.setMnemonic(KeyEvent.VK_A); //x100Button.setSelected(true); JRadioButton x10Button = new JRadioButton(x10String); x10Button.setActionCommand(x10String); JRadioButton x1Button = new JRadioButton(x1String); x1Button.setActionCommand(x1String); // 2. Grouping the radio buttons ButtonGroup group = new ButtonGroup(); group.add(initialStepButton); group.add(x100Button); group.add(x10Button); group.add(x1Button); // 3. Registering a listener for the radio buttons initialStepButton.addActionListener(this); x100Button.addActionListener(this); x10Button.addActionListener(this); x1Button.addActionListener(this); // 4. Put the radio buttons in a column in a panel JPanel radioPanel = new JPanel(new GridLayout(0,1)); radioPanel.add(initialStepButton); radioPanel.add(x100Button); radioPanel.add(x10Button); radioPanel.add(x1Button); add(radioPanel, BorderLayout.LINE_START); setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); } // Listens to the radio buttons public void actionPerformed(ActionEvent e) { String choice = e.getActionCommand(); if(choice == x100String) { step = 100; } else if(choice == x10String) { step = 10; } else if(choice == x10String) { step = 1; } else { step = initialStep; } } } /** * Constructor for objects of class YScale */ public YScale(double scale, double step/*, JFrame panel*/) { this.scale = scale; this.step = step; // Create and set up the window frame = new JFrame("RTASA - Y-Scale Control"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(100,50); // Create and set up the panel panel = new JPanel(new GridLayout(1,0)); // Create and add the widgets Double scaleObj = new Double(scale); Double stepObj = new Double(step); ScaleControl scaleLabel2 = new ScaleControl("Scale = " + scaleObj.toString(), SwingConstants.LEFT); StepControl stepLabel = new StepControl(step); panel.add(scaleLabel2); panel.add(stepLabel); // Add the panel to the window frame.getContentPane().add(panel, BorderLayout.CENTER); // Display the window frame.pack(); frame.setVisible(true); //Register for mouse-wheel events on the text area. //scaleLabel.addMouseWheelListener(this); } /** * An example of a method - replace this comment with your own * * @param y a sample parameter for a method * @return the sum of x and y */ public double getScale() { return scale; } } |