/* * PercussionOp.java * (FScape) * * Copyright (c) 2001-2016 Hanns Holger Rutz. All rights reserved. * * This software is published under the GNU General Public License v3+ * * * For further information, please contact Hanns Holger Rutz at * contact@sciss.de */ package de.sciss.fscape.op; import de.sciss.fscape.gui.OpIcon; import de.sciss.fscape.gui.PropertyGUI; import de.sciss.fscape.prop.OpPrefs; import de.sciss.fscape.prop.Prefs; import de.sciss.fscape.prop.Presets; import de.sciss.fscape.prop.PropertyArray; import de.sciss.fscape.spect.Fourier; import de.sciss.fscape.spect.SpectFrame; import de.sciss.fscape.spect.SpectStream; import de.sciss.fscape.spect.SpectStreamSlot; import de.sciss.fscape.util.Slots; import java.io.EOFException; import java.io.IOException; public class PercussionOp extends Operator { // -------- private variables -------- protected static final String defaultName = "Percussion"; protected static Presets static_presets = null; protected static Prefs static_prefs = null; protected static PropertyArray static_pr = null; // Slots protected static final int SLOT_INPUT = 0; protected static final int SLOT_OUTPUT = 1; // Properties (defaults) private static final int PR_CRR = 0; // pr.intg private static final int PR_CRI = 1; private static final int PR_CLR = 2; private static final int PR_CLI = 3; private static final int PR_CCR = 4; private static final int PR_CCI = 5; private static final int PR_CAR = 6; private static final int PR_CAI = 7; private static final String PRN_CRR = "CRR"; private static final String PRN_CRI = "CRI"; private static final String PRN_CLR = "CLR"; private static final String PRN_CLI = "CLI"; private static final String PRN_CCR = "CCR"; private static final String PRN_CCI = "CCI"; private static final String PRN_CAR = "CAR"; private static final String PRN_CAI = "CAI"; private static final int prIntg[] = {2, 2, 1, 1, 2, 0, 1, 1}; private static final String prIntgName[] = {PRN_CRR, PRN_CRI, PRN_CLR, PRN_CLI, PRN_CCR, PRN_CCI, PRN_CAR, PRN_CAI}; // -------- public methods -------- public PercussionOp() { super(); // initialize only in the first instance // preferences laden if (static_prefs == null) { static_prefs = new OpPrefs(getClass(), getDefaultPrefs()); } // property-array defaults if (static_pr == null) { static_pr = new PropertyArray(); static_pr.intg = prIntg; static_pr.intgName = prIntgName; static_pr.superPr = Operator.op_static_pr; } // default preset if (static_presets == null) { static_presets = new Presets(getClass(), static_pr.toProperties(true)); } // superclass fields opName = "PercussionOp"; prefs = static_prefs; presets = static_presets; pr = (PropertyArray) static_pr.clone(); // slots slots.addElement(new SpectStreamSlot(this, Slots.SLOTS_READER)); // SLOT_INPUT slots.addElement(new SpectStreamSlot(this, Slots.SLOTS_WRITER)); // SLOT_OUTPUT // icon // XXX icon = new OpIcon(this, OpIcon.ID_FLIPFREQ, defaultName); } // -------- Runnable methods -------- public void run() { runInit(); int ch, i, j; float f1, f2; SpectStreamSlot runInSlot; SpectStreamSlot runOutSlot; SpectStream runInStream = null; SpectStream runOutStream; SpectFrame runInFr = null; SpectFrame runOutFr = null; // target frame int srcBands, fftSize, fullFFTsize, complexFFTsize; float[] fftBuf, convBuf1, convBuf2; int clr, cli, crr, cri, ccr, cci, car, cai; topLevel: try { // ------------------------------ Input-Slot ------------------------------ runInSlot = slots.elementAt(SLOT_INPUT); if (runInSlot.getLinked() == null) { runStop(); // threadDead = true -> successive for() will be skipped } // this while loop is needed since initReader may pause and an // InterruptException may be thrown; then we try again for (boolean initDone = false; !initDone && !threadDead; ) { try { runInStream = runInSlot.getDescr(); // throws InterruptedException initDone = true; } catch (InterruptedException ignored) {} runCheckPause(); } if (threadDead) break topLevel; // ------------------------------ Output-Slot ------------------------------ runOutSlot = slots.elementAt(SLOT_OUTPUT); runOutStream = new SpectStream(runInStream); runOutSlot.initWriter(runOutStream); // ------------------------------ prepare ------------------------------ srcBands = runInStream.bands; fftSize = srcBands - 1; fullFFTsize = fftSize << 1; complexFFTsize = fullFFTsize << 1; fftBuf = new float[complexFFTsize]; crr = pr.intg[PR_CRR] - 1; cri = pr.intg[PR_CRI] - 1; clr = pr.intg[PR_CLR] - 1; cli = pr.intg[PR_CLI] - 1; ccr = pr.intg[PR_CCR] - 1; cci = pr.intg[PR_CCI] - 1; car = pr.intg[PR_CAR] - 1; cai = pr.intg[PR_CAI] - 1; // ------------------------------ main loop ------------------------------ runSlotsReady(); mainLoop: while (!threadDead) { // ---------- read frame ---------- for (boolean readDone = false; (!readDone) && !threadDead; ) { try { runInFr = runInSlot.readFrame(); // throws InterruptedException readDone = true; runOutFr = runOutStream.allocFrame(); } catch (InterruptedException ignored) { } catch (EOFException e) { break mainLoop; } runCheckPause(); } if (threadDead) break mainLoop; // ---------- Process: calculate target frame ---------- for (ch = 0; ch < runOutStream.chanNum; ch++) { convBuf1 = runInFr .data[ch]; convBuf2 = runOutFr.data[ch]; // calculate complex log spectrum : // Re( target ) = Log( Mag( source )) // Im( target ) = Phase( source ) // convBuf1 is already in polar style // -> fftBuf will be in rect style for (i = 0; i <= fullFFTsize; ) { fftBuf[i] = (float) Math.log(Math.max(1.0e-24, convBuf1[i])); // Re( target ) i++; fftBuf[i] = convBuf1[i]; // Im( target ) i++; } // make full spectrum (negative frequencies = conjugate positive frequencies) for (i = fullFFTsize + 2, j = fullFFTsize - 2; i < complexFFTsize; j -= 2) { // bug but nice? - 1 fftBuf[i++] = fftBuf[j]; fftBuf[i++] = -fftBuf[j + 1]; } // cepstrum domain Fourier.complexTransform(fftBuf, fullFFTsize, Fourier.INVERSE); // fold cepstrum (make anticausal parts causal) fftBuf[0] *= crr; fftBuf[1] *= cri; for (i = 2, j = complexFFTsize - 2; i < fullFFTsize; i += 2, j -= 2) { f1 = fftBuf[i]; f2 = fftBuf[j]; fftBuf[i] = crr * f1 + ccr * f2; fftBuf[j] = clr * f2 + car * f1; f1 = fftBuf[i + 1]; f2 = fftBuf[j + 1]; fftBuf[i + 1] = cri * f1 + cci * f2; fftBuf[j + 1] = cli * f2 + cai * f1; // fftBuf[ i ] += causal[ k ] * fftBuf[ j ]; // add conjugate left wing to right wing // fftBuf[ j ] *= anticausal[ k ]; // fftBuf[ i+1 ] -= causal[ k ] * fftBuf[ j+1 ]; // fftBuf[ j+1 ] *= anticausal[ k ]; // fftBuf[ i ] *= anticausal[ k ]; // fftBuf[ j ] += causal[ k ] * fftBuf[ i ]; // add conjugate left wing to right wing // fftBuf[ i+1 ] *= anticausal[ k ]; // fftBuf[ j+1 ] -= causal[ k ] * fftBuf[ i+1 ]; // i+=2; } fftBuf[i++] *= ccr + clr; fftBuf[i++] *= cci + cli; // fftBuf[ i++ ] *= causal[ k ]; // fftBuf[ i++ ] *= -causal[ k ]; // fftBuf[ j ] *= causal[ k ]; // fftBuf[ j+1 ] *= -causal[ k ]; // back to frequency domain Fourier.complexTransform(fftBuf, fullFFTsize, Fourier.FORWARD); // calculate real exponential spectrum : // Mag( target ) = Exp( Re( source )) // Phase( target ) = Im( source ) // ->convBuf2 shall be polar style, that makes things easy for (i = 0; i <= fullFFTsize; ) { convBuf2[i] = (float) Math.exp(fftBuf[i]); i++; convBuf2[i] = fftBuf[i]; i++; } } // calculation done runInSlot.freeFrame(runInFr); for (boolean writeDone = false; (!writeDone) && !threadDead; ) { try { // interruption runOutSlot.writeFrame(runOutFr); // throws InterruptedException writeDone = true; runFrameDone(runOutSlot, runOutFr); runOutStream.freeFrame(runOutFr); } catch (InterruptedException ignored) {} // mainLoop will be left anyways runCheckPause(); } } // end of main loop runInStream.closeReader(); runOutStream.closeWriter(); } // break topLevel catch (IOException e) { runQuit(e); return; } catch (SlotAlreadyConnectedException e) { runQuit(e); return; } runQuit(null); } // -------- GUI methods -------- public PropertyGUI createGUI(int type) { PropertyGUI gui; if (type != GUI_PREFS) return null; String coeff = ",it -1,it 0,it +1\n"; gui = new PropertyGUI( "glCoefficients\n" + "lbRight Wing Real;ch,pr" +PRN_CRR+coeff+ "lbRight Wing Imag;ch,pr" +PRN_CRI+coeff+ "lbLeft Wing Real;ch,pr" +PRN_CLR+coeff+ "lbLeft Wing Imag;ch,pr" +PRN_CLI+coeff+ "lbCausal Real;ch,pr" +PRN_CCR+coeff+ "lbCausal Imag;ch,pr" +PRN_CCI+coeff+ "lbAnticausal Real;ch,pr" +PRN_CAR+coeff+ "lbAnticausal Imag;ch,pr" +PRN_CAI+coeff ); return gui; } }