import com.softsynth.jsyn.*; /** * Clase que crea dispositivos de audio tales como osciladores y filtros. * Estos dispositivos son importados de la biblioteca Jsyn. En general estos * dispositivos están compuestos por una serie de puertos que pueden * interconectarse con otros dispositivos. Por ejemplo un dispositivo Oscilador * tiene 4 puertos distintos: Amplitud, frecuencia, fase y salida. Estos puertos * pueden conectarse a otros dispositivos o bien escribirse con metodo tales * como set(). Para más información visitar la pagina de jsyn: * http://www.softsynth.com/jsyn/. *

Esta clase esta encargada de hacer la interconexion entre dispositivos, * coonfigurar sus parámetros y rutear por cuales dispositivos pasará la señal * de audio. *

La configuracion de esta version 1.0 es la siguiente: * Un oscilador principal es modulado en ampitud por un LFO y por una señal tipo * envolvente. La salida del oscilador principal esta conectada a un filtro * pasabajos que "suaviza" las señales con alto contenido armónico. El filtro * esta conectado a un filtro de envolvente. Esto consiste en un filtro cuya * frecuencia está modulada por una envolvente. La salida del filtro es la que * finalmente a la salida de audio. * @author Daniel Acevedo, Francisco Barros. * @version v1.0 */ public class SignalManager extends Thread { private boolean DEBUG = false; private LineOut myOutput; /** * Dispositivo que genera una onda con forma sinusoidal. */ public SineOscillator myOscSin, myLfoSin; /** * Dispositivo que genera una onda con forma cuadrada. */ public SquareOscillator myOscSqr, myLfoSqr; /** * Dispositivo que genera una onda con forma triangular. */ public TriangleOscillator myOscTri; /** * Dispositivo que genera una onda con forma diente de sierra. */ public SawtoothOscillator myOscSaw; /** * Dispositivo que selecciona la señal que hay en alguno de sus dos puertos * de entrada y lo rutea hacia su puerto de salida. */ private SelectUnit myLfoSelector, myLfoOnOff, myOscSelector1,myOscSelector2,myOscSelector3, myFilterOnOff, myEnvFilterOnOff, myEnvFilSelector1, myEnvFilSelector2, myEnvFilSelector3; /** * Dispositivo que suma las señales que hay en sus dos puertos entrada y * el resultado lo lleva a su puerto de salida. */ public AddUnit myOscAmpSum, myEnvFilSum; /** * Dispositivo que multiplica las señales que hay en sus dos puertos entrada * y el resultado lo lleva a su puerto de salida. */ private MultiplyUnit myOscMult; /** * Dispositivo que reproduce en su puerto de salida una señal de tipo * envolvente. */ private EnvelopePlayer myAmpEnvPlayer, myEnvFilPlayer; /** * Variable que almacena convierte una serie de datos en un tipo de dato * de envolvente. Se utiliza este bloque como entrada a un EnvelopePlayer. */ private SynthEnvelope myAmpEnvPoints, myEnvFilPoints; /** * Dispositivo que filtra la señal en su puerto de entrada, ruteando a su * puerto de salida la señal filtrada. El tipo de filtro es pasa bajos. */ private Filter_LowPass myLfoFilterLP, myOscFilterLP,myEnvFilLP; /** * Dispositivo que filtra la señal en su puerto de entrada, ruteando a su * puerto de salida la señal filtrada. El tipo de filtro es pasa altos. */ private Filter_HighPass myEnvFilHP; /** * Dispositivo que filtra la señal en su puerto de entrada, ruteando a su * puerto de salida la señal filtrada. El tipo de filtro es pasa banda. */ private Filter_BandPass myEnvFilBP; /** * Dispositivo que filtra la señal en su puerto de entrada, ruteando a su * puerto de salida la señal filtrada. El tipo de filtro es elimina banda. */ private Filter_BandStop myEnvFilBS; /** * Arreglo de datos que contiene la informacion sobre la envolvente de la * amplitud. */ private double[] AmpData = {0.1, 1.0, // 0.1 seg en llegar a vol 1.0 0.2, 0.7, // 0.3 seg en llegar a vol 0.7 0.3, 0.0}; // 1.0 seg en llegar a vol 0.0 /** * Arreglo de datos que contiene la informacion sobre la envolvente de la * frecuencia del filtro de envolvente. */ private double[] EnvFilData = {0.6, 1.0, // 0.3 seg en llegar a vol 1.0 0.4, 0.3, // 0.2 seg en llegar a vol 0.7 0.4, 0.8, // 0.7 seg en llegar a vol 0.7 0.8, 0.0}; // 0.5 seg en llegar a vol 0.0 /** * Variable asociada al dispositivo myLFOSelector que controla * que oscilador se seleccionará en el oscilador de baja frecuencia (LFO) */ private int ctlLfoSel = 0; /** * Variable asociada al dispositivo myLFOOnOff que controla si el LFO * está activo o no. */ private int ctlLfoOnOff = 0; /** * Variable asociada al dispositivo myOscSelector1 que controla que * oscilador se seleccionará entre el oscilador sinusoidal y el * oscilador cuadrado. */ private int ctlOscSel1 = 0; /** * Variable asociada al dispositivo myOscSelector2 que controla que * oscilador se seleccionará entre el oscilador triangular y el * oscilador diente de sierra. */ private int ctlOscSel2 = 1; /** * Variable asociada al dispositivo myOscSelector3 que controla que * oscilador se seleccionará entre el elegido en myOscSelector1 y * myOscSelector2. En pricipio con los valores que están inicializadas * estas variables se elige el oscilador diente de sierra. */ private int ctlOscSel3 = 1; /** * Variable que controla si el filtro está activo o no. */ private int ctlFiltOnOff = 0; /** * Variable que controla si el filtro de envolvente está activo o no. */ private int ctlEnvFiltOnOff = 0; /** * Variable asociada al dispositivo myEnvFilSelector1 que controla que * filtro se seleccionará entre el filtro pasa bajos y el pasa altos * en el banco de filtros de envolvente. */ private int ctlEnvFilSel1 = 0; /** * Variable asociada al dispositivo myEnvFilSelector2 que controla que * filtro se seleccionará entre el filtro pasa banda y el elimina banda * en el banco de filtros de envolvente. En pricipio con los valores que * están inicializadas estas variables se elige el filtro pasa bandas. */ private int ctlEnvFilSel2 = 0; /** * Variable asociada al dispositivo myEnvFilSelector3 que controla que * filtro se seleccionará entre el filtro elegido en myEnvFilSelector1 y * myEnvFilSelector2 en el banco de filtros de envolvente. */ private int ctlEnvFilSel3 = 1; /** * Contructor de la clase SignalManager. Se crean los dispositivos, se * interconectan y se dan valores iniciales a algunos parámetros. */ public SignalManager() { Synth.startEngine(0, Synth.DEFAULT_FRAME_RATE / 1.0 ); /** * oscilador sinusoidal del LFO... */ myLfoSin = new SineOscillator(); myLfoSqr = new SquareOscillator(); myLfoSelector = new SelectUnit(); myLfoOnOff = new SelectUnit(); myOscAmpSum = new AddUnit(); myOscSin = new SineOscillator(); myOscSqr = new SquareOscillator(); myOscTri = new TriangleOscillator(); myOscSaw = new SawtoothOscillator(); myOscSelector1 = new SelectUnit(); myOscSelector2 = new SelectUnit(); myOscSelector3 = new SelectUnit(); myOutput = new LineOut(); myOscMult = new MultiplyUnit(); myAmpEnvPlayer = new EnvelopePlayer(); myAmpEnvPoints = new SynthEnvelope(AmpData); myLfoFilterLP = new Filter_LowPass(); myOscFilterLP = new Filter_LowPass(); myFilterOnOff = new SelectUnit(); myEnvFilLP = new Filter_LowPass(); myEnvFilHP = new Filter_HighPass(); myEnvFilBP = new Filter_BandPass(); myEnvFilBS = new Filter_BandStop(); myEnvFilSelector1 = new SelectUnit(); myEnvFilSelector2 = new SelectUnit(); myEnvFilSelector3 = new SelectUnit(); myEnvFilPlayer = new EnvelopePlayer(); myEnvFilPoints = new SynthEnvelope(EnvFilData); myEnvFilterOnOff = new SelectUnit(); myEnvFilSum = new AddUnit(); // configuracion interconexiones myLfoSin.output.connect(myLfoSelector.inputA); myLfoSqr.output.connect(myLfoFilterLP.input); myLfoFilterLP.output.connect(myLfoSelector.inputB); myLfoSelector.output.connect(myLfoOnOff.inputB); myLfoOnOff.output.connect(myOscAmpSum.inputA); myOscAmpSum.output.connect(myOscMult.inputA); myAmpEnvPlayer.output.connect(myOscMult.inputB); myOscMult.output.connect(myOscSin.amplitude); myOscMult.output.connect(myOscSqr.amplitude); myOscMult.output.connect(myOscTri.amplitude); myOscMult.output.connect(myOscSaw.amplitude); myOscSin.output.connect(myOscSelector1.inputA); myOscSqr.output.connect(myOscSelector1.inputB); myOscTri.output.connect(myOscSelector2.inputA); myOscSaw.output.connect(myOscSelector2.inputB); myOscSelector1.output.connect(myOscSelector3.inputA); myOscSelector2.output.connect(myOscSelector3.inputB); myOscSelector3.output.connect(myOscFilterLP.input); myOscSelector3.output.connect(myFilterOnOff.inputA); myOscFilterLP.output.connect(myFilterOnOff.inputB); myFilterOnOff.output.connect(myEnvFilterOnOff.inputA); myFilterOnOff.output.connect(myEnvFilLP.input); myFilterOnOff.output.connect(myEnvFilHP.input); myFilterOnOff.output.connect(myEnvFilBP.input); myFilterOnOff.output.connect(myEnvFilBS.input); myEnvFilLP.output.connect(myEnvFilSelector1.inputA); myEnvFilHP.output.connect(myEnvFilSelector1.inputB); myEnvFilBP.output.connect(myEnvFilSelector2.inputA); myEnvFilBS.output.connect(myEnvFilSelector2.inputB); myEnvFilSelector1.output.connect(myEnvFilSelector3.inputA); myEnvFilSelector2.output.connect(myEnvFilSelector3.inputB); myEnvFilSelector3.output.connect(myEnvFilterOnOff.inputB); myEnvFilPlayer.output.connect(myEnvFilSum.inputA); myEnvFilSum.output.connect(myEnvFilLP.frequency); myEnvFilSum.output.connect(myEnvFilHP.frequency); myEnvFilSum.output.connect(myEnvFilBP.frequency); myEnvFilSum.output.connect(myEnvFilBS.frequency); myEnvFilterOnOff.output.connect( 0, myOutput.input, 0 ); myEnvFilterOnOff.output.connect( 0, myOutput.input, 1 ); inicializar(); } // metodo que inicializa los dispositivos. private void inicializar() { myLfoSin.amplitude.set(0.4); myLfoSin.frequency.set(5); myLfoSqr.amplitude.set(0.4); myLfoSqr.frequency.set(5); myOscAmpSum.inputB.set(0.4); myLfoSelector.select.set(ctlLfoSel); myLfoOnOff.select.set(ctlLfoOnOff); myOscSelector1.select.set(ctlOscSel1); myOscSelector2.select.set(ctlOscSel2); myOscSelector3.select.set(ctlOscSel3); myLfoFilterLP.frequency.set(200); myFilterOnOff.select.set(ctlFiltOnOff); myEnvFilSelector1.select.set(ctlEnvFilSel1); myEnvFilSelector2.select.set(ctlEnvFilSel2); myEnvFilSelector3.select.set(ctlEnvFilSel3); myEnvFilSum.inputB.set(200); myEnvFilLP.frequency.set(200); myEnvFilHP.frequency.set(200); myEnvFilBP.frequency.set(200); myEnvFilBS.frequency.set(200); myEnvFilLP.Q.set(5); myEnvFilHP.Q.set(5); myEnvFilBP.Q.set(5); myEnvFilBS.Q.set(5); myEnvFilLP.amplitude.set(1); myEnvFilHP.amplitude.set(1); myEnvFilBP.amplitude.set(5); myEnvFilBS.amplitude.set(1); myEnvFilPlayer.amplitude.set(3000); myEnvFilterOnOff.select.set(ctlEnvFiltOnOff); myLfoSin.start(); myLfoSqr.start(); myLfoSelector.start(); myLfoOnOff.start(); myOscAmpSum.start(); myOscSin.start(); myOscSqr.start(); myOscTri.start(); myOscSaw.start(); myOscSelector1.start(); myOscSelector2.start(); myOscSelector3.start(); myOutput.start(); myOscMult.start(); myLfoFilterLP.start(); myOscFilterLP.start(); myFilterOnOff.start(); myEnvFilSum.start(); myEnvFilLP.start(); myEnvFilHP.start(); myEnvFilBP.start(); myEnvFilBS.start(); myEnvFilSelector1.start(); myEnvFilSelector2.start(); myEnvFilSelector3.start(); myEnvFilterOnOff.start(); myAmpEnvPlayer.start(); myEnvFilPlayer.start(); } /** * Metodo que configura si el LFO está encendido o apagado * @param ctl variable de control. Valores posibles: ON u OFF. */ public void LfoSwitch(String ctl) { if(ctl.equals("ON")) ctlLfoOnOff = 1; if(ctl.equals("OFF")) ctlLfoOnOff = 0; myLfoOnOff.select.set(ctlLfoOnOff); } /** * Metodo que selecciona el tipo de onda para el oscilador del LFO. * @param sel Tipo de Onda. Valores posibles: Sine o Square. */ public void LfoSelector(String sel) { if(sel.equals("Square")) { ctlLfoSel = 1; out("Lfo: Square seleccionado."); myLfoSelector.select.set(ctlLfoSel); } if(sel.equals("Sine")) { ctlLfoSel = 0; out("Lfo: Sine seleccionado."); myLfoSelector.select.set(ctlLfoSel); } } /** * Metodo que configura el valor de la frecuencia en el oscilador principal * @param f frecuencia. */ public void setOscFrequency(float f) { myOscSin.frequency.set(f); myOscSqr.frequency.set(f); myOscTri.frequency.set(f); myOscSaw.frequency.set(f); } /** * Metodo que selecciona el tipo de onda que tendrá el oscilador * principal. * @param sel Tipo de onda. Valores posibles: Sine, Square, Triangle o Sawtooth */ public void OscSelector(String sel) { if(sel.equals("Sine")) { ctlOscSel1 = 0; ctlOscSel3 = 0; if(DEBUG) out("Osc: Sine seleccionado."); } if(sel.equals("Square")) { ctlOscSel1 = 1; ctlOscSel3 = 0; if(DEBUG) out("Osc: Square seleccionado."); } if(sel.equals("Triangle")) { ctlOscSel2 = 0; ctlOscSel3 = 1; if(DEBUG) out("Osc: Triangle seleccionado."); } if(sel.equals("Sawtooth")) { ctlOscSel2 = 1; ctlOscSel3 = 1; if(DEBUG) out("Osc: Sawtooth seleccionado."); } myOscSelector1.select.set(ctlOscSel1); myOscSelector2.select.set(ctlOscSel2); myOscSelector3.select.set(ctlOscSel3); } /** * Cambia la duracion en una seccion o segmento de la envolvente de * la amplitud del oscilador principal * @param index Indicador de la seccion a modificar. 0 es la corresponde al * attack, 1 al decay y 2 al release. * @param dur duracion del segmento, en milisegundos. */ public void AmpEnvChange(int index, float dur) { // index: 0-1=attack; 2-3=decay; 4-5=release; if(dur==0) { dur = 0.01F; if(index==1) AmpData[3] = AmpData[1]; } else if(index==1) AmpData[3] = 0.7; AmpData[2*index] = (double)dur; myAmpEnvPoints.write( index, AmpData, index, 1 ); //out(myAmpEnvPoints.toString()); } /** * Metodo que configura si el filtro puesto despues del oscilador * principal está encendido o apagado. * @param ctl variable de control. Valores posibles: ON u OFF. */ public void FilterSwitch(String ctl) { if(ctl.equals("ON")) ctlFiltOnOff = 1; if(ctl.equals("OFF")) ctlFiltOnOff = 0; myFilterOnOff.select.set(ctlFiltOnOff); } /** * Metodo que configura la frecuencia, selectividad o Q y la amplitud del * Filtro. * @param par Parametro a modificar. Valores posibles: * 1: frecuencia, 2: Q, 3: amplitud. * @param val Nuevo valor al cual se ajustará el parámetro seleccionado. */ public void setFilterParameter(int par, float val) { if(par==1) { if(val==0) val=50.0F; myOscFilterLP.frequency.set(val); } if(par==2) { if(val==0) val=0.01F; myOscFilterLP.Q.set(val); } if(par==3) { if(val==0) val=0.01F; myOscFilterLP.amplitude.set(val); } } /** * Metodo que configura si el Filtro de envolvente está encendido o apagado * @param ctl variable de control. Valores posibles: ON u OFF. */ public void EnvelopeFilterSwitch(String ctl) { if(ctl.equals("ON")) ctlEnvFiltOnOff = 1; if(ctl.equals("OFF")) ctlEnvFiltOnOff = 0; myEnvFilterOnOff.select.set(ctlEnvFiltOnOff); } /** * Metodo que configura la frecuencia maxima y minima y la selectividad o Q * Filtro. * @param par Parametro a modificar. Valores posibles: * hif: frecuencia máxima, lof: frecuencia mínima, Q: Q. * @param val Nuevo valor al cual se ajustará el parámetro seleccionado. */ public void setEnvFilterParameter(String par, float val) { if(par.equals("hif")) { myEnvFilPlayer.amplitude.set(val); } if(par.equals("lof")) { out("val freq antes: " + val); if(val<100F) val=100F; out("val freq despues: " + val); myEnvFilSum.inputB.set(val); } if(par.equals("Q")) { if(val==0) val=0.01F; myEnvFilLP.Q.set(val); myEnvFilHP.Q.set(val); myEnvFilBP.Q.set(val); myEnvFilBS.Q.set(val); } } /** * Metodo que selecciona el tipo de filtro para el filtro de envolvente. * @param sel Tipo de filtro. Valores posibles: * LP: Pasa bajos, HP: Pasa altos, BP: Pasa banda, BS: Elimina banda. */ public void EnvFilterSelector(String sel) { if(sel.equals("LP")) { ctlEnvFilSel1 = 0; ctlEnvFilSel3 = 0; if(DEBUG) out("Filter: LP seleccionado."); } if(sel.equals("HP")) { ctlEnvFilSel1 = 1; ctlEnvFilSel3 = 0; if(DEBUG) out("Filter: HP seleccionado."); } if(sel.equals("BP")) { ctlEnvFilSel2 = 0; ctlEnvFilSel3 = 1; if(DEBUG) out("Filter: BP seleccionado."); } if(sel.equals("BS")) { ctlEnvFilSel2 = 1; ctlEnvFilSel3 = 1; if(DEBUG) out("Filter: BS seleccionado."); } myEnvFilSelector1.select.set(ctlEnvFilSel1); myEnvFilSelector2.select.set(ctlEnvFilSel2); myEnvFilSelector3.select.set(ctlEnvFilSel3); } /** * Cambia la duracion en una seccion o segmento de la envolvente de * la frecuencia del filtro de envolvente. * @param index Indicador de la seccion a modificar. 0 es la corresponde al * attack, 1 al decay, 2 al sustain y 3 al release. * @param dur duracion del segmento, en milisegundos. */ public void EnvFilChange(int index, float dur) { if(dur==0) { dur = 0.01F; if(index==1) EnvFilData[3] = EnvFilData[1]; } else if(index==1) EnvFilData[3] = 0.7; EnvFilData[5] = EnvFilData[3]; EnvFilData[2*index] = (double)dur; myEnvFilPoints.write( index, EnvFilData, index, 1 ); } /** * Metodo que mediante la envolvente de amplitud hace sonar * el sistema. */ public void tocar() { myEnvFilPlayer.envelopePort.clear(); myEnvFilPlayer.envelopePort.queue(myEnvFilPoints); myAmpEnvPlayer.envelopePort.clear(); myAmpEnvPlayer.envelopePort.queue( myAmpEnvPoints, 0, 2); //myAmpEnvPoints.start(); } /** * Reproduce la ultima parte de la envolvente de la amplitud la cual * va disminuyendo hasta que el volumen de la onda llega a cero. */ public void parar() { try { myAmpEnvPlayer.envelopePort.queue( myAmpEnvPoints, 2, 1); Synth.verbosity = Synth.SILENT; } catch (SynthException e) { out("synth alert: " + e);//SynthAlert.showError(this,e); } } /** * Detiene todos los dispositivos deteniendo el sonido definitivamente. */ public void cerrarSistema() { Synth.stopEngine(); } /** * Funcion que simplifica la impresion por consola */ private static void out(String strMessage) { System.out.println(strMessage); } }