/*
* ShrinkOp.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.GroupLabel;
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.Filter;
import de.sciss.fscape.util.Slots;
import java.io.EOFException;
import java.io.IOException;
public class ShrinkOp
extends Operator {
// -------- private variables --------
protected static final String defaultName = "Shrink";
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_FACTOR = 0; // pr.intg
private static final int PR_MODE = 1;
private static final String PRN_FACTOR = "Factor";
private static final String PRN_MODE = "Mode";
protected static final int MODE_SHRINK = 0;
protected static final int MODE_EXPAND = 1;
private static final int prIntg[] = { 0, MODE_SHRINK };
private static final String prIntgName[] = { PRN_FACTOR, PRN_MODE };
// -------- public methods --------
// public Container createGUI( int type );
public ShrinkOp()
{
super();
// initialize only in the first instance
// preferences laden
if( static_prefs == null ) {
static_prefs = new OpPrefs( getClass(), getDefaultPrefs() );
}
// propertyarray 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-Felder uebertragen
opName = "ShrinkOp";
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(); // superclass
// Haupt-Variablen fuer den Prozess
int ch, i, j;
int fltSmpPerCrossing, fltCrossings, fltLen;
float flt[], fltD[], filter[][], fltWin, fltRolloff;
float fltGain;
SpectStreamSlot runInSlot;
SpectStreamSlot runOutSlot;
SpectStream runInStream = null;
SpectStream runOutStream;
SpectFrame runInFr = null;
SpectFrame runOutFr = null;
// Ziel-Frame Berechnung
int shrinkFactor;
int srcBands, destBands;
float rsmpFactor;
float[] srcBuf, destBuf, rectBuf;
topLevel:
try {
// ------------------------------ Input-Slot ------------------------------
runInSlot = slots.elementAt( SLOT_INPUT );
if( runInSlot.getLinked() == null ) {
runStop(); // threadDead = true -> folgendes for() wird uebersprungen
}
// diese while Schleife ist noetig, da beim initReader ein Pause eingelegt werden kann
// und die InterruptException ausgeloest wird; danach versuchen wir es erneut
for( boolean initDone = false; !initDone && !threadDead; ) {
try {
runInStream = runInSlot.getDescr(); // throws InterruptedException
initDone = true;
}
catch( InterruptedException ignored) {}
runCheckPause();
}
if( threadDead ) break topLevel;
shrinkFactor= 2 << pr.intg[ PR_FACTOR ];
srcBands = runInStream.bands;
// ------------------------------ Output-Slot ------------------------------
runOutSlot = slots.elementAt( SLOT_OUTPUT );
runOutStream = new SpectStream( runInStream );
if( pr.intg[ PR_MODE ] == MODE_SHRINK ) {
destBands = (srcBands - 1) / shrinkFactor + 1;
rsmpFactor = (float) destBands / (float) srcBands;
runOutStream.smpPerFrame /= shrinkFactor;
} else {
destBands = (srcBands - 1) * shrinkFactor + 1;
rsmpFactor = (float) destBands / (float) srcBands;
runOutStream.smpPerFrame *= shrinkFactor;
}
runOutStream.bands = destBands;
runOutSlot.initWriter( runOutStream );
// ------------------------------ Vorberechnungen ------------------------------
fltSmpPerCrossing = 4096; // 2048 << quality;
fltCrossings = 5;
fltRolloff = 0.70f;
fltWin = 6.5f;
// quality = 1;
fltSmpPerCrossing = 4096;
fltLen = (int) ((float) (fltSmpPerCrossing * fltCrossings) / fltRolloff + 0.5f);
flt = new float[ fltLen ];
fltD = null; // new float[ fltLen ];
fltGain = Filter.createAntiAliasFilter( flt, fltD, fltLen, fltSmpPerCrossing, fltRolloff, fltWin );
filter = new float[ 3 ][];
filter[ 0 ] = flt;
filter[ 1 ] = fltD;
filter[ 2 ] = new float[ 2 ];
filter[ 2 ][ 0 ] = fltSmpPerCrossing;
filter[ 2 ][ 1 ] = fltGain;
rectBuf = new float[ Math.max( srcBands, destBands ) << 1 ];
srcBuf = new float[ srcBands + 1 ];
destBuf = new float[ destBands + 1 ];
// ------------------------------ Hauptschleife ------------------------------
runSlotsReady();
mainLoop:
while( !threadDead ) {
// ---------- Frame einlesen ----------
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: Ziel-Frame berechnen ----------
for( ch = 0; ch < runOutStream.chanNum; ch++ ) {
Fourier.polar2Rect( runInFr.data[ ch ], 0, rectBuf, 0, srcBands << 1 );
// 1. real part
for( i = 0, j = 0; i < srcBands; i++, j += 2 ) {
srcBuf[ i ] = rectBuf[ j ];
}
Filter.resample( srcBuf, 0.0, destBuf, 0, destBands, rsmpFactor, filter );
for( i = 0, j = 0; i < destBands; i++, j += 2 ) {
rectBuf[ j ] = destBuf[ i ];
}
// 1. img part
for( i = 0, j = 1; i < srcBands; i++, j += 2 ) {
srcBuf[ i ] = rectBuf[ j ];
}
Filter.resample( srcBuf, 0.0, destBuf, 0, destBands, rsmpFactor, filter );
for( i = 0, j = 1; i < destBands; i++, j += 2 ) {
rectBuf[ j ] = destBuf[ i ];
}
Fourier.rect2Polar( rectBuf, 0, runOutFr.data[ ch ], 0, destBands << 1 );
}
// calculation done
runInSlot.freeFrame( runInFr );
for( boolean writeDone = false; (!writeDone) && !threadDead; ) {
try { // Unterbrechung
runOutSlot.writeFrame( runOutFr ); // throws InterruptedException
writeDone = true;
runFrameDone( runOutSlot, runOutFr );
runOutStream.freeFrame( runOutFr );
}
catch( InterruptedException ignored) {} // mainLoop wird eh gleich verlassen
runCheckPause();
}
} // end of main loop
runInStream.closeReader();
runOutStream.closeWriter();
} // break topLevel
catch( IOException e ) {
runQuit( e );
return;
}
catch( SlotAlreadyConnectedException e ) {
runQuit( e );
return;
}
// catch( OutOfMemoryError e ) {
// abort( e );
// return;
// }
runQuit( null );
}
// -------- GUI methods --------
public PropertyGUI createGUI(int type) {
PropertyGUI gui;
if (type != GUI_PREFS) return null;
gui = new PropertyGUI(
"gl"+GroupLabel.NAME_GENERAL+"\n" +
"lbMode;ch,pr"+PRN_MODE+",itShrink,itExpand\n" +
"lbFactor;ch,pr"+PRN_FACTOR+"," +
"it1:2,it1:4,it1:8,it1:16" );
return gui;
}
}