import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*; 
import javax.swing.border.*;  

public class SintePanel extends JPanel
    {
    // Componentes gráficos
    private static Dimension HGAP5 = new Dimension(5,1);
    private static Dimension HGAP10 = new Dimension(10,1);
    private static EmptyBorder border5 = new EmptyBorder(5,5,5,5);
    /**
     * Descripcion Paneles:
     * PanSup:      Panel Superior que contiene el panel PanSupCen y el 
     *              titulo "controles I".
     * PanSupCen:   Panel que contiene a los paneles Oscilador Principal
     *              y Filtro.
     * PanCen:      Panel central superior que contiene al panel PanCenCen
     *              y el titulo "controles II".
     * PanCenCen:   Panel que contiene a los paneles Envolvente de Amplitud
     *              y LFO.
     * PanCen2:     Panel central inferior que contiene al panel Filtro de
     *              Envolvente y el titulo "controles III".
     * PanInf:      Panel que contiene los botones que controlan las octavas,
     *              El panel en el que va el dibujo del teclado y el panel
     *              PanInfTxt.
     * PanInfTxt:   Panel que muestra el slider que se ha movido y su valor
     *              actual. Este panel es  una especie de barra de estado.
     * PanOsc:      Panel del Oscilador Principal.
     * PanLfo:      Panel del LFO.
     * PanAmpEnv:   Panel de la Envolvente de la Amplitud.
     * PanEnvFilter:        Panel del Filtro de Envolvente.
     * PanBotLfo:           Panel que contiene los botones On y Off del LFO.
     * PanBotFilter:        Panel que contiene los botones On y Off del Filtro.
     * PanBotEnvFil:        Panel que contiene los botones On y Off del Filtro
     *                      de envolvente.
     * radioPanelOsc:       Panel en el que van los botones de tipo radio del
     *                      Oscilador Principal.
     * radioPanelLfo:       Panel en el que van los botones de tipo radio del
     *                      LFO
     * radioPanelEnvFilter: Panel en el que van los botones de tipo radio del
     *                      Filtro de Envolvente.
     */
    private JPanel PanSup, PanSupCen, PanCen, PanCenCen, PanCen2, PanInf,
                   PanInfTxt, PanOsc, PanLfo, PanAmpEnv, PanEnvFilter,
                   PanBotLfo, PanBotFilter, PanBotEnvFil, radioPanelOsc,
                   radioPanelLfo, radioPanelEnvFilter;
    /**
     * Descripcion Etiquetas:
     * SupTit:  Titulo del panel superior "controles I"
     * CenTit:  Titulo del panel central superior "controles II"
     * TitCen2: Titulo del panel central inferior "controles III"
     */
    private JLabel SupTit, CenTit, TitCen2;
    private JLabel SV  = new JLabel("Slider Value: ");
    private GridLayout g, gl;
    /**
     * Descripcion Sliders:
     * SldAmp:           Slider de Amplitud del Oscilador Principal.
     * SldFreq:          Slider de Afinacion del Oscilador Principal.
     * SAmpLfo:          Slider de Amplitud del LFO.
     * SFreqLfo:         Slider de Frecuencia del LFO.
     * SldFreqFilter:    Slider de Frecuencia del Filtro.
     * SldQFilter:       Slider de Q del Filtro.
     * SldAmpFilter:     Slider de Amplitud del Filtro.
     * SldAmpAttack:     Slider de Attack del la Envolvente de la Amplitud.
     * SldAmpDecay:      Slider de Decay del la Envolvente de la Amplitud.
     * SldAmpRelease:    Slider de Release del la Envolvente de la Amplitud.
     * SldEnvFilAttack   Slider de Attack del Filtro de Envolvente.
     * SldEnvFilDecay:   Slider de Decay del Filtro de Envolvente.
     * SldEnvFilSustain: Slider de Sustain del Filtro de Envolvente.
     * SldEnvFilRelease: Slider de Release del Filtro de Envolvente.
     * SFreqHiEnvFil:    Slider de Frecuencia Alta del Filtro de Envolvente.
     * SQEnvFil:         Slider de Q del Filtro de Envolvente.
     * SFreqLoEnvFil:    Slider de Frecuencia Baja del Filtro de Envolvente.
     */
    private JSlider SldAmp, SldFreq, SAmpLfo, SFreqLfo, SldFreqFilter,
                    SldQFilter, SldAmpFilter, SldAmpAttack, SldAmpDecay,
                    SldAmpRelease, SldEnvFilAttack, SldEnvFilDecay,
                    SldEnvFilSustain, SldEnvFilRelease, SFreqHiEnvFil,
                    SQEnvFil, SFreqLoEnvFil;
    /**
     * Descripcion Botones:
     * boton1:       Boton de baja una octava la afinacion del teclado.
     * boton2:       Boton de reestablece la octava de afinacion del teclado.
     * boton3:       Boton de sube una octava la afinacion del teclado.
     * LfoOnBot:     Boton de encendido del LFO.
     * LfoOffBot:    Boton de apagado del LFO.
     * FilterOnBot:  Boton de encendido del Filtro.
     * FilterOffBot: Boton de apagado del Filtro.
     * EnvFilOnBot:  Boton de encendido del Filtro de Envolvente.
     * EnvFilOffBot: Boton de apagado del Filtro de Envolvente.
     */
    private JButton boton1, boton2, boton3, LfoOnBot, LfoOffBot, FilterOnBot,
                    FilterOffBot, EnvFilOnBot, EnvFilOffBot;
    /**
     * Descripcion Botones tipo Radio:
     * OscSinBut: Boton tipo radio que selecciona el tipo de onda sinusoidal
     *            en el Oscilador Principal.
     * OscSqrBut: Boton tipo radio que selecciona el tipo de onda cuadrado
     *            en el Oscilador Principal.
     * OscTriBut: Boton tipo radio que selecciona el tipo de onda triangular
     *            en el Oscilador Principal.
     * OscSawBut: Boton tipo radio que selecciona el tipo de onda diente de
     *            sierra en el Oscilador Principal.
     * EnvLPBut:  Boton tipo radio que selecciona el tipo filtro
     *            Pasa Bajo en el Filtro de Envolvente.
     * EnvHPBut:  Boton tipo radio que selecciona el tipo filtro
     *            Pasa Alto en el Filtro de Envolvente.
     * EnvBPBut:  Boton tipo radio que selecciona el tipo filtro
     *            Pasa Banda en el Filtro de Envolvente.
     * EnvBSBut:  Boton tipo radio que selecciona el tipo filtro
     *            Elimina banda en el Filtro de Envolvente.
     * LfoSinBut: Boton tipo radio que selecciona el tipo de onda sinusoidal
     *            en el LFO.
     * LfoSqrBut: Boton tipo radio que selecciona el tipo de onda cuadrado
     *            en el LFO.
     */
    private JRadioButton OscSinBut, OscSqrBut, OscTriBut, OscSawBut, EnvLPBut,
                         EnvHPBut, EnvBPBut, EnvBSBut, LfoSinBut, LfoSqrBut;
    private BevelBorder border;
    // Listeners:
    private KeyHandler keyList;
    private BotonHandler botList;
    private SliderHandler sliderList;
    // Variablews de control:
    private boolean DEBUG = false;
    private int WavTyp;
	private float amplitudOsc = 0.3F;
	private int ctlOctava = 0;
	private int amplitudOscilador = 40;
	// Instancias de otras clases
    private Notas nn;
	private SignalManager sig;
    private Keyboard PanPiano;
    /**
     * Constructor de SintePanel. En este constructor se arma la interfaz
     * gráfica de sistema.
     */
	public SintePanel()
        {
		nn = new Notas();
		sig = new SignalManager();
        sliderList = new SliderHandler(SV);
        botList = new BotonHandler();
        setBackground(Color.BLACK);
        border = new BevelBorder(BevelBorder.LOWERED);
        // =================== Panel Controles I ===================
		// Adicion de paneles Oscilador Ppal y LFO a PanSupCen
		PanSupCen = new JPanel();
		g = new GridLayout(1, 2); 
	 	g.setHgap(5); 
	 	g.setVgap(5); 
	 	PanSupCen.setLayout(g);
		PanSupCen.add(PanelOsciladorPrincipal());
        PanSupCen.add(PanelFiltro());
        // Agregar titulo y panel central a PanSup
		SupTit = new JLabel("Controles I");
		PanSup = new JPanel();
		PanSup.setLayout(new BoxLayout(PanSup, BoxLayout.Y_AXIS));
        PanSup.add(SupTit);
        PanSup.add(PanSupCen);

		// =================== Panel Controles II ==================
		// Adicion paneles a PanCen
		PanCenCen = new JPanel();
		gl = new GridLayout(1, 2); 
		gl.setHgap(5); 
 		gl.setVgap(5); 
 		PanCenCen.setLayout(gl);
		PanCenCen.add(PanelAmpEnv());
        PanCenCen.add(PanelLfo());
		// Agregar titulo y panel a PanCen
		CenTit = new JLabel("Controles II");
		PanCen = new JPanel();
		PanCen.setLayout(new BoxLayout(PanCen, BoxLayout.Y_AXIS));
        PanCen.add(CenTit);
        PanCen.add(PanCenCen);
		
		// ================= Panel Controles III ===================
		TitCen2 = new JLabel("Controles III");
		PanCen2 = new JPanel();
		PanCen2.setLayout(new BoxLayout(PanCen2, BoxLayout.Y_AXIS));
        PanCen2.add(TitCen2);
        PanCen2.add(PanelEnvFilter());

        // =============== Panel Controles Inferior =================
		PanInf = new JPanel();
		boton1 = new JButton("-1 Octava");
		boton1.addActionListener(botList);
		boton2 = new JButton("Normal");
		boton2.addActionListener(botList);
		boton3 = new JButton("+1 Octava");
		boton3.addActionListener(botList);

		PanInf.setLayout(new BorderLayout());
		JPanel botones = new JPanel();
		botones.setLayout(new BoxLayout(botones, BoxLayout.X_AXIS));
		botones.add(boton1);
		botones.add(boton2);
		botones.add(boton3);
		
		// Teclado:
		PanPiano = new Keyboard();
		keyList = new KeyHandler();
        PanPiano.addKeyListener(keyList);
     	PanPiano.setFocusable(true);
		// Texto sobre info sliders y switches
		PanInfTxt = new JPanel();
		PanInfTxt.setLayout(new BoxLayout(PanInfTxt, BoxLayout.X_AXIS));
		PanInfTxt.add(SV);
		//PanInfTxt.add(RadioLab);

		PanInf.setLayout(new BoxLayout(PanInf, BoxLayout.Y_AXIS));
		PanInf.add(botones);
		PanInf.add(PanPiano);
		PanInf.add(PanInfTxt);
		
		// Ordenamiento de los 3 paneles principales. 
        setLayout(new GridLayout(4, 1));
        this.add(PanSup);
		this.add(PanCen);
        this.add(PanCen2);
        this.add(PanInf);
        this.addKeyListener(keyList);
     	this.setFocusable(true);
		}
    //---------------------- Metodos Generales ---------------------------------
    /**
     * Metodo generico que crea un slider con una serie de parametros como
     * sus valores maximo, minimo, por defecto, etc.
     * @param minVal Valor inferior del slider.
     * @param maxVal Valor superior del slider.
     * @param defVal Valor por defecto del slider.
     * @param minS   Espaciamiento de las marcas grandes del slider.
     * @param maxS   Espaciamiento de las marcaa pequeñas del slider.
     * @return Retorna el slider creado
     */
	private JSlider Slider(int minVal, int maxVal, int defVal, int minS, int maxS)
		{ 
		JSlider sld = new JSlider(JSlider.VERTICAL, minVal, maxVal, defVal); 
 		sld.setPaintTicks(true); 
 		sld.setMajorTickSpacing(maxS); 
 		sld.setMinorTickSpacing(minS); 	 
 		sld.setPaintLabels( true );
		return sld;
		}
    /**
     * Metodo generico que crea un boton tipo radio, le agrega el
     * action listener y lo retorna.
     * @return Retorna el boton generado
     */
    private JRadioButton BotonRadio(String nombre)
		{
        JRadioButton rb = new JRadioButton(nombre);
        rb.setActionCommand(nombre);
		rb.addActionListener(botList);
        return rb;
        }
    //------------------- Metodos Panel Controles I ----------------------------
    /**
     * Metodo que crea un panel con controles como sliders y botones
     * para el oscilador principal.
     * @return Retorna el panel creado.
     */
	private JPanel PanelOsciladorPrincipal()
		{
		PanOsc = new JPanel();
		PanOsc.setLayout(new BoxLayout(PanOsc, BoxLayout.X_AXIS));
		PanOsc.setBorder(new TitledBorder(border, "Oscilador Principal",
								 TitledBorder.LEFT, TitledBorder.ABOVE_TOP));
 		SldAmp = Slider(0,100,30,5,20);
		SldAmp.addChangeListener(sliderList);
		PanOsc.add(new PanelSlider("Amplitud",SldAmp)); 
 		PanOsc.add(Box.createRigidArea(HGAP5));
		SldFreq = Slider(-20,20,0,2,10);
		SldFreq.addChangeListener(sliderList);
		PanOsc.add(new PanelSlider("Afinacion",SldFreq));
 		PanOsc.add(Box.createRigidArea(HGAP5));
		PanOsc.add(botTipoOndaOsc());
		return PanOsc;
		}
	/**
     * Metodo que crea un panel con botones tipo radio para seleccionar
     * el tipo de forma de onda del oscilador principal.
     * @return Retorna el panel creado.
     */
	private JPanel botTipoOndaOsc()
		{
        ButtonGroup group = new ButtonGroup();
        OscSinBut = BotonRadio("Sinusoidal");
        OscSqrBut = BotonRadio("Cuadrada");
        OscTriBut = BotonRadio("Triangular");
        OscSawBut = BotonRadio("Diente de Sierra");
        OscSawBut.setSelected(true);
        group.add(OscSinBut);
        group.add(OscSqrBut);
        group.add(OscTriBut);
        group.add(OscSawBut);
        radioPanelOsc = new JPanel(new GridLayout(0, 1));
        radioPanelOsc.add(OscSinBut);
        radioPanelOsc.add(OscSqrBut);
        radioPanelOsc.add(OscTriBut);
        radioPanelOsc.add(OscSawBut);
        radioPanelOsc.setBorder(new CompoundBorder(new TitledBorder(null,
			"Tipo de Onda", TitledBorder.CENTER, TitledBorder.TOP), border5));
        return radioPanelOsc;
		}		
    /**
     * Metodo que crea un panel con controles como sliders y botones
     * para el Filtro.
     * @return Retorna el panel creado.
     */
	private JPanel PanelFiltro()
		{
		JPanel PanFilt = new JPanel();
		PanFilt.setLayout(new BoxLayout(PanFilt, BoxLayout.X_AXIS));
		PanFilt.setBorder(new TitledBorder(border, "Filtro",
									 TitledBorder.LEFT, TitledBorder.ABOVE_TOP));
 		FilterOnBot = new JButton("Filter On");
		FilterOnBot.addActionListener(botList);
		FilterOffBot = new JButton("Filter Off");
		FilterOffBot.addActionListener(botList);
		PanBotFilter = new JPanel();
		PanBotFilter.setLayout(new BoxLayout(PanBotFilter, BoxLayout.Y_AXIS));
		PanBotFilter.add(FilterOnBot);
		PanBotFilter.add(FilterOffBot);
		PanFilt.add(PanBotFilter);
 		SldFreqFilter = Slider(0,10000,1000,500,2000);
		SldFreqFilter.addChangeListener(sliderList);
		PanFilt.add(new PanelSlider("Frecuencia",SldFreqFilter));
		PanFilt.add(Box.createRigidArea(HGAP5));
		SldQFilter = Slider(0,200,100,20,50);
		SldQFilter.addChangeListener(sliderList);
		PanFilt.add(new PanelSlider("Q",SldQFilter));
		PanFilt.add(Box.createRigidArea(HGAP5));
		SldAmpFilter = Slider(0,100,40,5,20);
		SldAmpFilter.addChangeListener(sliderList);
		PanFilt.add(new PanelSlider("Amplitud",SldAmpFilter));
		return PanFilt;
		}
    //------------------ Metodos Panel Controles II ----------------------------
    /**
     * Metodo que crea un panel con controles como sliders y botones
     * para el panel de la envolvente de amplitud.
     * @return Retorna el panel creado.
     */
	private JPanel PanelAmpEnv()
		{
		PanAmpEnv = new JPanel();
		PanAmpEnv.setLayout(new BoxLayout(PanAmpEnv, BoxLayout.X_AXIS));
		PanAmpEnv.setBorder(new TitledBorder(border, "Envolvente Amplitud",
										TitledBorder.LEFT, TitledBorder.ABOVE_TOP));													 
		SldAmpAttack = Slider(0,200,10,10,40);
		SldAmpAttack.addChangeListener(sliderList);
		PanAmpEnv.add(new PanelSlider("Attack",SldAmpAttack));
 		PanAmpEnv.add(Box.createRigidArea(HGAP5));
		SldAmpDecay = Slider(0,200,20,10,40);
		SldAmpDecay.addChangeListener(sliderList);
		PanAmpEnv.add(new PanelSlider("Decay",SldAmpDecay));
 		PanAmpEnv.add(Box.createRigidArea(HGAP5));
		SldAmpRelease = Slider(0,200,30,10,40);
		SldAmpRelease.addChangeListener(sliderList);
		PanAmpEnv.add(new PanelSlider("Release",SldAmpRelease));
		return PanAmpEnv;
		}
	 /**
     * Metodo que crea un panel con controles como sliders y botones
     * para el LFO.
     * @return Retorna el panel creado.
     */
	private JPanel PanelLfo()
		{
		PanLfo = new JPanel();
		PanLfo.setLayout(new BoxLayout(PanLfo, BoxLayout.X_AXIS));
		PanLfo.setBorder(new TitledBorder(border, "L F O",
									TitledBorder.LEFT, TitledBorder.ABOVE_TOP));
		LfoOnBot = new JButton("LFO On");
		LfoOnBot.addActionListener(botList);
		LfoOffBot = new JButton("LFO Off");
		LfoOffBot.addActionListener(botList);
		PanBotLfo = new JPanel();
		PanBotLfo.setLayout(new BoxLayout(PanBotLfo, BoxLayout.Y_AXIS));
		PanBotLfo.add(LfoOnBot);
		PanBotLfo.add(LfoOffBot);
		PanLfo.add(PanBotLfo);
 		PanLfo.add(Box.createRigidArea(HGAP5));
        SAmpLfo = Slider(0,100,40,5,20);
		SAmpLfo.addChangeListener(sliderList);
        PanLfo.add(new PanelSlider("Amplitud",SAmpLfo));
		SFreqLfo = Slider(0,10,5,1,2);
		SFreqLfo.addChangeListener(sliderList);
		PanLfo.add(new PanelSlider("Frecuencia",SFreqLfo));
        PanLfo.add(Box.createRigidArea(HGAP5));
		PanLfo.add(botTipoOndaLfo());
		return PanLfo;
		}
    /**
     * Metodo que crea un panel con botones tipo radio para seleccionar
     * el tipo de forma de onda del LFO.
     * @return Retorna el panel creado.
     */
    private JPanel botTipoOndaLfo()
		{
		// Agrupamiento
		ButtonGroup group = new ButtonGroup();
        LfoSinBut = BotonRadio("Sinusoidal");
        LfoSqrBut = BotonRadio("Cuadrada");
        LfoSinBut.setSelected(true);
        group.add(LfoSinBut);
        group.add(LfoSqrBut);
        // Adicion botones a radioPanelLfo:
        radioPanelLfo = new JPanel(new GridLayout(0, 1));
        radioPanelLfo.add(LfoSinBut);
        radioPanelLfo.add(LfoSqrBut);
        radioPanelLfo.setBorder(new CompoundBorder(new TitledBorder(null,
			"Tipo de Onda", TitledBorder.CENTER, TitledBorder.TOP), border5));
        return radioPanelLfo;
        }
    //------------------ Metodos Panel Controles III----------------------------
    /**
     * Metodo que crea un panel con controles como sliders y botones
     * para el Filtro de Envolvente.
     * @return Retorna el panel creado.
     */
    private JPanel PanelEnvFilter()
        {
        PanEnvFilter = new JPanel();
		PanEnvFilter.setLayout(new BoxLayout(PanEnvFilter, BoxLayout.X_AXIS));
		PanEnvFilter.setBorder(new TitledBorder(border, "Filtro de Envolvente",
									TitledBorder.LEFT, TitledBorder.ABOVE_TOP));
		EnvFilOnBot = new JButton("On");
		EnvFilOnBot.addActionListener(botList);
		EnvFilOffBot = new JButton("Off");
		EnvFilOffBot.addActionListener(botList);
		PanBotEnvFil = new JPanel();
		PanBotEnvFil.setLayout(new BoxLayout(PanBotEnvFil, BoxLayout.Y_AXIS));
		PanBotEnvFil.add(EnvFilOnBot);
		PanBotEnvFil.add(EnvFilOffBot);
		PanEnvFilter.add(PanBotEnvFil);
        SldEnvFilAttack = Slider(0,2000,200,100,500);
		SldEnvFilAttack.addChangeListener(sliderList);
		PanEnvFilter.add(new PanelSlider("Attack",SldEnvFilAttack));
		SldEnvFilDecay = Slider(0,2000,100,100,500);
		SldEnvFilDecay.addChangeListener(sliderList);
		PanEnvFilter.add(new PanelSlider("Decay",SldEnvFilDecay));
		SldEnvFilSustain = Slider(0,2000,300,100,500);
		SldEnvFilSustain.addChangeListener(sliderList);
        PanEnvFilter.add(new PanelSlider("Sustain",SldEnvFilSustain));
		SldEnvFilRelease = Slider(0,2000,300,100,500);
		SldEnvFilRelease.addChangeListener(sliderList);
		PanEnvFilter.add(new PanelSlider("Release",SldEnvFilRelease));
        PanEnvFilter.add(botTipoFiltroEnv());
        SFreqHiEnvFil = Slider(0,5000,3000,400,2500);
		SFreqHiEnvFil.addChangeListener(sliderList);
		PanEnvFilter.add(new PanelSlider("f alta",SFreqHiEnvFil));
        SFreqLoEnvFil = Slider(0,5000,200,400,2500);
		SFreqLoEnvFil.addChangeListener(sliderList);
		PanEnvFilter.add(new PanelSlider("f baja",SFreqLoEnvFil));
        SQEnvFil = Slider(0,10,3,1,5);
		SQEnvFil.addChangeListener(sliderList);
        PanEnvFilter.add(new PanelSlider("Q",SQEnvFil));
		return PanEnvFilter;
        }
    /**
     * Metodo que crea un panel con botones tipo radio para seleccionar
     * el tipo de filtro del Filtro de Envolvente.
     * @return Retorna el panel creado.
     */
    private JPanel botTipoFiltroEnv()
        {
		// Agrupamiento
		ButtonGroup group = new ButtonGroup();
        EnvLPBut = BotonRadio("LP");
        EnvHPBut = BotonRadio("HP");
        EnvBPBut = BotonRadio("BP");
        EnvBSBut = BotonRadio("BS");
        EnvBPBut.setSelected(true);
        group.add(EnvLPBut);
        group.add(EnvHPBut);
        group.add(EnvBPBut);
        group.add(EnvBSBut);
        // Adicion botones a radioPanelOsc:
        radioPanelEnvFilter = new JPanel(new GridLayout(0, 1));
        radioPanelEnvFilter.add(EnvLPBut);
        radioPanelEnvFilter.add(EnvHPBut);
        radioPanelEnvFilter.add(EnvBPBut);
        radioPanelEnvFilter.add(EnvBSBut);
        radioPanelEnvFilter.setBorder(new CompoundBorder(new TitledBorder(null,
			"Tipo de Filtro", TitledBorder.CENTER, TitledBorder.TOP), border5));
        return radioPanelEnvFilter;
		}
    //--------------------------- Subclases ------------------------------------
	/**
     * Clase interna de SintePanel encargada de crear paneles enlos cuiales
     * van los sliders del panel.
     */
    private class PanelSlider extends JPanel
		{
        /**
         * Constructor de PanelSlider. Este es método genérico ya que todos los
         * sliders del panel van montados sobre un PanelSlider el cual incluye
         * un borde con el nombre del slider y areas en blanco para que no que
         * muy comprimido.
         * @param nombre Etiqueta con la cual será nombrado este panel.
         * @param sld    Slider que sera incrustado en este panel.
         */
		public PanelSlider(String nombre, JSlider sld)
			{ 
	 		setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 
	 		setBorder(new TitledBorder(nombre));  
	 		add(Box.createRigidArea(HGAP10)); 
	 		add(sld); 
	 		add(Box.createRigidArea(HGAP10));
			retorna();
			}
        /**
         * Metodo que retorna el panel
         * @return Panel con sliders, nombre, borde, etc.
         */
		private JPanel retorna()
			{
			return this;
			}
		}
    /**
     * Clase interna de SintePanel que maneja los eventos producidos por
     * mover los Sliders del panel.
     */
	public class SliderHandler implements ChangeListener
		{
        private int afinacionOsc = 0;
		String txt = new String();
        /**
         * Constructor de la clase interna SliderHandler
         * @param txt texto que se imprime en la barra de estado del panel.
         */
		public SliderHandler(JLabel txt)
			{ 
 	    	SV = txt;
 			}
        /**
         * Metodo que maneja los eventos producidos por mover los
         * sliders.
         * @param e Evento generado por mover un slider.
         */
 		public void stateChanged(ChangeEvent e)
			{ 
 	    	JSlider s1 = (JSlider)e.getSource();
            // Sliders Oscilador Principal:
			if(s1.equals(SldAmp)){
				txt = "Oscillator Amplitude    ";
                amplitudOscilador = s1.getValue();
                sig.myOscAmpSum.inputB.set((float)s1.getValue()/100);
				}
			if(s1.equals(SldFreq)){
				txt = "Oscillator Afinacion    ";
				afinacionOsc = s1.getValue();
				nn.afinar(s1.getValue());
				}
            // Sliders LFO
			if(s1.equals(SAmpLfo)){
                txt = "L.F.O. Amplitude        ";
                sig.myLfoSin.amplitude.set((float)(amplitudOscilador*s1.getValue())/10000);
                sig.myLfoSqr.amplitude.set((float)(amplitudOscilador*s1.getValue())/10000);
                System.out.println("amp: " + sig.myLfoSin.amplitude.get());
				}
            if(s1.equals(SFreqLfo)){
                txt = "L.F.O. Frecuency        ";
                sig.myLfoSin.frequency.set(s1.getValue());
                sig.myLfoSqr.frequency.set(s1.getValue());
				}
            // Sliders Filter
			if(s1.equals(SldFreqFilter)){
                txt = "Filter Frecuency         ";
                sig.setFilterParameter(1,s1.getValue());
				}
			if(s1.equals(SldQFilter)){
                txt = "Filter Q         ";
                sig.setFilterParameter(2,(float)s1.getValue()/100);
				}
			if(s1.equals(SldAmpFilter)){
                txt = "Filter Amplitude         ";
                sig.setFilterParameter(3,(float)s1.getValue()/100);
				}
            // Sliders Envolvente de Amplitud del Oscilador Pincipal
			if(s1.equals(SldAmpAttack)){
                txt = "Oscillator Attack        ";
                sig.AmpEnvChange(0, (float)s1.getValue()/100 );
				}	
			if(s1.equals(SldAmpDecay)){
                txt = "Oscillator Decay        ";
                sig.AmpEnvChange(1, (float)s1.getValue()/100 );
				}	
			if(s1.equals(SldAmpRelease)){
                txt = "Oscillator Release       ";
                sig.AmpEnvChange(2, (float)s1.getValue()/100 );
				}
            // Sliders del Filtro de Envolvente
            if(s1.equals(SldEnvFilAttack)){
                txt = "Envelope Filter Attack   ";
                sig.EnvFilChange(0, (float)s1.getValue()/100 );
                }
            if(s1.equals(SldEnvFilDecay)){
                txt = "Envelope Filter Decay   ";
                sig.EnvFilChange(1, (float)s1.getValue()/100 );
                }
            if(s1.equals(SldEnvFilSustain)){
                txt = "Envelope Filter Sustain   ";
                sig.EnvFilChange(2, (float)s1.getValue()/100 );
                }
            if(s1.equals(SldEnvFilRelease)){
                txt = "Envelope Filter Release  ";
                sig.EnvFilChange(3, (float)s1.getValue()/100 );
                }
            if(s1.equals(SFreqHiEnvFil)){
                txt = "Envelope Filter High Freq ";
                sig.setEnvFilterParameter("hif",(float)s1.getValue());
                }
            if(s1.equals(SFreqLoEnvFil)){
                txt = "Envelope Filter Low Freq ";
                sig.setEnvFilterParameter("lof",(float)s1.getValue());
                }
            if(s1.equals(SQEnvFil)){
                txt = "Envelope Filter Q ";
                sig.setEnvFilterParameter("Q",(float)s1.getValue());
                }
			SV.setText(txt + " Slider Value: " + s1.getValue());
			PanPiano.requestFocus();
			if(DEBUG) System.out.println("Valor en slide cambiado");
			} 
    	}
    /**
     * Clase interna de SintePanel que maneja los eventos producidos por
     * presionar botones.
     */
	public class BotonHandler implements ActionListener
		{
			float f;
			float a;
			int veces;
            /**
             * Metodo que maneja los eventos producidos por presionar
             * un boton. Este metodo fue diseñado para discriminar si se
             * presiona un boton tipo JButton o un JRadioButton.
             * @param e Evento generado por presionar un boton.
             */
			public void actionPerformed(ActionEvent e)
				{
                if(DEBUG) System.out.println("BotonHandler.actionPerformed");
                // JButton
                if(e.getSource() instanceof JButton)
                    {
                    if(DEBUG) System.out.println("BotonHandler.actionPerformed.JButton");
                    JButton b = (JButton)e.getSource();
                    // control octava:
                    if(b.equals(boton1))
                        {
                        if(DEBUG) System.out.println("boton 1");
                        ctlOctava = -1;
                        }
                    if(b.equals(boton2))
                        {
                        if(DEBUG) System.out.println("boton 2");
                        ctlOctava = 0;
                        }
                    if(b.equals(boton3))
                        {
                        if(DEBUG) System.out.println("boton 3");
                        ctlOctava = 1;
                        }
                    // Control On/Off del LFO
                    if(b.equals(LfoOnBot))
                        {
                        if(DEBUG) System.out.println("LfoOnBot");
                        sig.LfoSwitch("ON");
                        }
                    if(b.equals(LfoOffBot))
                        {
                        if(DEBUG) System.out.println("LfoOffBot");
                        sig.LfoSwitch("OFF");
                        }
                    // Control On/Off del Filtro
                    if(b.equals(FilterOnBot))
                        {
                        if(DEBUG) System.out.println("FilterOnBot");
                        sig.FilterSwitch("ON");
                        }
                    if(b.equals(FilterOffBot))
                        {
                        if(DEBUG) System.out.println("FilterOffBot");
                        sig.FilterSwitch("OFF");
                        }
                    // Control On/Off del Filtro de Envolvente
                    if(b.equals(EnvFilOnBot))
                        {
                        if(DEBUG) System.out.println("EnvFilterOffBot");
                        sig.EnvelopeFilterSwitch("ON");
                        }
                    if(b.equals(EnvFilOffBot))
                        {
                        if(DEBUG) System.out.println("EnvFilterOffBot");
                        sig.EnvelopeFilterSwitch("OFF");
                        }
                    }
                // JRadioButton
                if(e.getSource() instanceof JRadioButton)
                    {
                    JRadioButton b = (JRadioButton)e.getSource();
                    // Seleccion tipo de onda para el Oscilador Principal
                    if(b.equals(OscSinBut))
                        {sig.OscSelector("Sine");}
                    if(b.equals(OscSqrBut))
                        {sig.OscSelector("Square");}
                    if(b.equals(OscTriBut))
                        {sig.OscSelector("Triangle");}
                    if(b.equals(OscSawBut))
                        {sig.OscSelector("Sawtooth");}
                    // Seleccion tipo de onda para el LFO
                    if(b.equals(LfoSinBut))
                        {sig.LfoSelector("Sine");}
                    if(b.equals(LfoSqrBut))
                        {sig.LfoSelector("Square");}
                    // Seleccion tipo filtro para el Filtro de Envolvente
                    if(b.equals(EnvLPBut))
                        {sig.EnvFilterSelector("LP");}
                    if(b.equals(EnvHPBut))
                        {sig.EnvFilterSelector("HP");}
                    if(b.equals(EnvBPBut))
                        {sig.EnvFilterSelector("BP");}
                    if(b.equals(EnvBSBut))
                        {sig.EnvFilterSelector("BS");}
                    }
				PanPiano.requestFocus();
				}
			 }
    /**
     * Clase interna de SintePanel que maneja los eventos producidos por
     * presionar las teclas del teclado del PC.
     */
	public class KeyHandler implements KeyListener
        {
        boolean pressed=false; // variable de control
        int cont=0; // control para pc RCE.
        int t;    // tipo de onda
        float a;  // amplitud de la onda
        int co;	 // para un control de subida o bajada de octava
        /**
         * Metodo que captura cuando una tecla es presionada.
         * @param event Evento generado por presionar una tecla.
         */
		public void keyPressed(KeyEvent event)
			{  
         	int keyCode = event.getKeyCode();
				a = amplitudOsc;
				t = WavTyp;
				co = ctlOctava;
				if( pressed )
					{	
					if(DEBUG) System.out.println("player.suena: sonando todavia");
					}
				else
					{
					if(DEBUG) System.out.println("Key: pressed");
					switch(keyCode)
						{// Notas naturales
						case 'Z': sonar(nn.get("C",1+co),keyCode); break;
                        case 'X': sonar(nn.get("D",1+co),keyCode); break;
                        case 'C': sonar(nn.get("E",1+co),keyCode); break;
                        case 'V': sonar(nn.get("F",1+co),keyCode); break;
                        case 'B': sonar(nn.get("G",1+co),keyCode); break;
                        case 'N': sonar(nn.get("A",1+co),keyCode); break;
                        case 'M': sonar(nn.get("B",1+co),keyCode); break;
                        case ',': sonar(nn.get("C",2+co),keyCode); break;
                        case '.': sonar(nn.get("D",2+co),keyCode); break;
                        case '-': sonar(nn.get("E",2+co),keyCode); break;
                        case 'Q': sonar(nn.get("F",2+co),keyCode); break;
                        case 'W': sonar(nn.get("G",2+co),keyCode); break;
                        case 'E': sonar(nn.get("A",2+co),keyCode); break;
                        case 'R': sonar(nn.get("B",2+co),keyCode); break;
                        case 'T': sonar(nn.get("C",3+co),keyCode); break;
                        case 'Y': sonar(nn.get("D",3+co),keyCode); break;
                        case 'U': sonar(nn.get("E",3+co),keyCode); break;
                        case 'I': sonar(nn.get("F",3+co),keyCode); break;
                        case 'O': sonar(nn.get("G",3+co),keyCode); break;
                        case 'P': sonar(nn.get("A",3+co),keyCode); break;
                        case '[': sonar(nn.get("B",3+co),keyCode); break;
						// Notas sostenidas
						case 'S': sonar(nn.get("C#",1+co),keyCode); break;
                        case 'D': sonar(nn.get("D#",1+co),keyCode); break;
                        case 'G': sonar(nn.get("F#",1+co),keyCode); break;
                        case 'H': sonar(nn.get("G#",1+co),keyCode); break;
                        case 'J': sonar(nn.get("A#",1+co),keyCode); break;
                        case 'L': sonar(nn.get("C#",2+co),keyCode); break;
                        case 'Ñ': sonar(nn.get("D#",2+co),keyCode); break;
						case '2': sonar(nn.get("F#",2+co),keyCode); break;
                        case '3': sonar(nn.get("G#",2+co),keyCode); break;
						case '4': sonar(nn.get("A#",2+co),keyCode); break;
                        case '6': sonar(nn.get("C#",3+co),keyCode); break;
                        case '7': sonar(nn.get("D#",3+co),keyCode); break;
                        case '9': sonar(nn.get("F#",3+co),keyCode); break;
                        case '0': sonar(nn.get("G#",3+co),keyCode); break;
                        case '=': sonar(nn.get("A#",3+co),keyCode); break;
						}
					}
      		}
        /**
         * Metodo recibe una nota y una tecla y se encarga de hacer 3 acciones
         * principalmente. Se encarga de mandar a pintar un punto en la tecla
         * que corresponde en el dibujo del teclado del panel principal. Las
         * otras tarea son configurar la frecuencia en el oscilador principal y
         * activar las envolventes de amplitud y frecuencia de la clase
         * SignalManager
         * @param f     frecuencia de la nota a tocar.
         * @param tecla codigo de la tecla presionada en el teclado del PC.
         */
		private void sonar(float f,int tecla)
			{
				if(DEBUG) System.out.println("player.suena: init");
                PanPiano.pintaPunto(tecla);
				sig.setOscFrequency(f);
                sig.tocar();
				pressed = true;
				cont++;
				}
        /**
         * Metodo que captura cuando una tecla es soltada.
         * @param event Evento generado por soltar una tecla.
         */
      	public void keyReleased(KeyEvent event) 
			{
				if(cont!=0)
					{
					if(DEBUG) System.out.println("Key: released");
					PanPiano.borraPunto();
					sig.parar();
					if(DEBUG) System.out.println("player.suena: parado");
					pressed = false;
					}
				}
      	public void keyTyped(KeyEvent event)
      		{  
      		}
		}
	}
	