/** * The main class of the application. */ package spectrumanalyzer; import java.io.File; import java.io.IOException; import com.jsyn.JSyn; import com.jsyn.Synthesizer; import com.jsyn.data.Spectrum; import com.jsyn.unitgen.LineOut; import com.jsyn.unitgen.LineIn; import com.jsyn.unitgen.Multiply; import com.jsyn.unitgen.PassThrough; import com.jsyn.unitgen.SawtoothOscillatorBL; import com.jsyn.unitgen.SineOscillator; import com.jsyn.unitgen.SpectralFilter; import com.jsyn.unitgen.SpectralProcessor; import com.jsyn.unitgen.UnitOscillator; import com.jsyn.unitgen.WhiteNoise; import com.jsyn.util.WaveRecorder; import java.util.logging.Level; import java.util.logging.Logger; import com.jsyn.devices.AudioDeviceManager; import org.jdesktop.application.Application; import org.jdesktop.application.SingleFrameApplication; import javax.swing.JOptionPane; import org.jdesktop.application.ResourceMap; import org.jdesktop.application.SingleFrameApplication; import org.jdesktop.application.FrameView; import org.jdesktop.application.TaskMonitor; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.Timer; import javax.swing.Icon; import javax.swing.JDialog; import javax.swing.JFrame; /** * Play a sine sweep through an FFT/IFFT pair. * * @author Alex Schwarz - VE7DXW * */ /** * The main class of the application. */ public class SA_DSP extends SA_Display { public static Synthesizer synth; public static PassThrough center; public static UnitOscillator osc; public static UnitOscillator lfo; public static Multiply volumeControlLeft; // for Volume on-off left channel public static Multiply volumeControlRight; // for Volume on-off right channel public static PassThrough mixer; public static SpectralFilter filter; public static LineOut lineOut; public static LineIn lineIn; public static WaveRecorder recorder; public static boolean useRecorder = true; public static boolean useProcessor = true; public final static int NUM_FFTS = 1; //was originally set at 4 public static int SIZE_LOG_2 = 10; // 10 = 0 - 20, 11 = 0-10, 12 = 0-5, by mainatining the same bin# and sample rate public static int SIZE = 1 << SIZE_LOG_2; public static SpectralProcessor[] processors; public static WhiteNoise noise; public static int SAMPLE_RATE = 48000; // changing sample rate will affect the spectrum static double[] FFT_bins = new double[430]; static double[] FFT_bins1 = new double[430]; static double[] FFT_binsAverage = new double[430]; static double[] FFT_binsAverage1 = new double[430]; // static int count = 0; //count for altenate use of bin filter /** * At startup create and show the main frame of the application. **/ static void startup() { SA_Display.dominantFrequency(); //show(new SA_Display(this)); try { start(); } catch (IOException e) { System.out.println (AudioDeviceManager.USE_DEFAULT_DEVICE); e.printStackTrace(); } //begin(); } private static class CustomSpectralProcessor extends SpectralProcessor { public CustomSpectralProcessor() { super(SIZE); } public void processSpectrum(Spectrum inputSpectrum, Spectrum outputSpectrum) { //pitchUpOctave( inputSpectrum, outputSpectrum ); lowPassFilter(inputSpectrum, outputSpectrum, 20000.0); } public static void lowPassFilter(Spectrum inputSpectrum, Spectrum outputSpectrum, double frequency) { inputSpectrum.copyTo(outputSpectrum); double[] outReal = outputSpectrum.getReal(); double[] outImag = outputSpectrum.getImaginary(); // brickwall filter int size = outReal.length; int cutoff = (int) (frequency * size / SAMPLE_RATE); int nyquist = size / 2; for (int i = cutoff; i < nyquist; i++) { // Bins above nyquist are mirror of ones below. for (int c = 0; c < 429; c++) //load bins into the FTT_bins variable for recall as a spectum display { FFT_bins[c] = Math.sqrt((Math.pow(outReal[c],2)) + (Math.pow(outImag[c],2))); FFT_binsAverage[c] = Math.sqrt((Math.pow(outReal[c],2)) + (Math.pow(outImag[c],2))); } /** to create 2 x zoom that is in center * select bin that matches the BFO line, count in 105 in each direction * fill even bins with collected data and average the uneven bins from the values * of the neighboring bins */ //System.out.println (outReal[1023]); //outReal[i] = outReal[size - i] = 0.0; //outImag[i] = outImag[size - i] = 0.0; //System.out.println (outImag[i]); } } // TODO Figure out why this sounds bad. public static void pitchUpOctave(Spectrum inputSpectrum, Spectrum outputSpectrum) { outputSpectrum.clear(); double[] inReal = inputSpectrum.getReal(); double[] inImag = inputSpectrum.getImaginary(); double[] outReal = outputSpectrum.getReal(); double[] outImag = outputSpectrum.getImaginary(); int size = inReal.length; int nyquist = size / 2; // Octave doubling by shifting the spectrum. for (int i = nyquist - 2; i > 1; i--) { int h = i / 2; outReal[i] = inReal[h]; outImag[i] = inImag[h]; outReal[size - i] = inReal[size - h]; outImag[size - i] = inImag[size - h]; System.out.println (inImag[size - h]); } } } static void start() throws IOException { //System.out.println ("trying to start"); // Create a context for the synthesizer. if (useProcessor) //check if synth is already running if yes don't create - set false in stop methd. { synth = JSyn.createSynthesizer(); //System.out.println ("Synth started"); } synth.setRealTime(true); useRecorder = true; useProcessor = true; if (useRecorder) //if (recorder != null) { { File waveFile = new File(System.getProperty("user.home") + "/MDSR_SA/temp_recording.wav"); //File waveFile = new File("temp_recording.wav"); // Default is stereo, 16 bits. recorder = new WaveRecorder(synth, waveFile); //System.out.println("Writing to WAV file " + waveFile.getAbsolutePath()); } } if (useProcessor) { //if (processors[0] != null) { processors = new SpectralProcessor[NUM_FFTS]; for (int i = 0; i < NUM_FFTS; i++) { processors[i] = new CustomSpectralProcessor(); } } } // Add a tone generator. synth.add( lineIn = new LineIn() ); lineIn.start(); synth.add(center = new PassThrough()); synth.add(lfo = new SineOscillator()); synth.add(noise = new WhiteNoise()); synth.add(mixer = new PassThrough()); synth.add(osc = new SineOscillator()); // synth.add( osc = new SineOscillator() ); synth.add(filter = new SpectralFilter(NUM_FFTS, SIZE_LOG_2)); // Add a stereo audio output unit. synth.add(lineOut = new LineOut()); synth.add (volumeControlLeft = new Multiply ()); volumeControlLeft.inputA.set( 1.0 ); volumeControlLeft.inputB.set( 1.0 ); volumeControlLeft.start(); synth.add (volumeControlRight = new Multiply ()); volumeControlRight.inputA.set( 1.0 ); volumeControlRight.inputB.set( 1.0 ); volumeControlRight.start(); center.output.connect(osc.frequency); lfo.output.connect(osc.frequency); osc.output.connect(mixer.input); noise.output.connect(mixer.input); mixer.output.connect(filter.input); lineIn.output.connect(1,volumeControlLeft.inputA, 0); lineIn.output.connect(0,volumeControlRight.inputA, 0); volumeControlRight.output.connect(0,mixer.input,0); volumeControlLeft.output.connect(0,mixer.input,0); //(0,mixer.input,0); old code //lineIn.output.connect(1,mixer.input,0); old code if (useProcessor) { // Pass spectra through a custom processor. for (int i = 0; i < NUM_FFTS; i++) { filter.getSpectralOutput(i).connect(processors[i].input); processors[i].output.connect(filter.getSpectralInput(i)); } } else { for (int i = 0; i < NUM_FFTS; i++) { // Connect FFTs directly to IFFTs for passthrough. filter.getSpectralOutput(i).connect(filter.getSpectralInput(i)); } } //mixer.output.connect(0, lineOut.input, 0); //yellow //filter.output.connect(0, lineOut.input, 1); // Set the frequency and amplitude for the modulated sine wave. center.input.set(000.0); lfo.frequency.set(0.0); lfo.amplitude.set(0.0); osc.amplitude.set(0.0); noise.amplitude.set(0.0); //synth.start(SAMPLE_RATE); synth.start( SAMPLE_RATE, AudioDeviceManager.USE_DEFAULT_DEVICE, 2, AudioDeviceManager.USE_DEFAULT_DEVICE, 2 ); if (useRecorder) { mixer.output.connect(0, recorder.getInput(), 0); filter.output.connect(0, recorder.getInput(), 1); // When we start the recorder it will pull data from the oscillator // and sweeper. //recorder.start(); //set up button to activate recording recorder.stop(); } //lineIn.start(); lineOut.start(); //System.out.println("You should now be hearing a clean oscillator on the left channel,"); //System.out.println("and the FFT->IFFT processed signal on the right channel."); // Sleep while the sound is generated in the background. //exitSystem(); /**try { double time = synth.getCurrentTime(); // Sleep for a few seconds. synth.sleepUntil(time + 600.0); } catch (InterruptedException e) { e.printStackTrace(); } if (recorder != null) { recorder.stop(); recorder.close(); } System.out.println("Stop playing. -------------------"); // Stop everything. synth.stop(); **/ } public void exitSystem() { try { double time = synth.getCurrentTime(); // Sleep for a few seconds. synth.sleepUntil(time + 2.0); } catch (InterruptedException e) { e.printStackTrace(); } //CustomSpectralProcessor() // if (processors[0] != null) { //processors.stop(); //try { //processors.close(); // } catch (IOException ex) { // Logger.getLogger(SA_DSP.class.getName()).log(Level.SEVERE, null, ex); // } // } if (recorder != null) { recorder.stop(); try { recorder.close(); } catch (IOException ex) { Logger.getLogger(SA_DSP.class.getName()).log(Level.SEVERE, null, ex); } } //System.out.println("Stop playing. -------------------"); //lineIn.stop(); synth.stop(); dispose(); } public static void stopSystem() { try { double time = synth.getCurrentTime(); // Sleep for a few seconds. synth.sleepUntil(time + 0.0); } catch (InterruptedException e) { e.printStackTrace(); } if (recorder != null) { recorder.stop(); try { recorder.close(); } catch (IOException ex) { JOptionPane.showMessageDialog(null,"Error in DSP file"); } } //System.out.println("Stop playing. -------------------"); //lineIn.stop(); useRecorder = false; //avoid restarting after RST useProcessor = false; //avoid restarting synth after RST lineIn.stop(); filter.stop(); synth.stop(); } }