/*
* ConvertDlg.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
*
*
* Changelog:
* 07-Jan-05 removed deprecated soundfile methods
* 21-May-05 fixed bug in 16bit TIFF mode
*/
package de.sciss.fscape.gui;
import de.sciss.fscape.io.GenericFile;
import de.sciss.fscape.io.ImageFile;
import de.sciss.fscape.io.ImageStream;
import de.sciss.fscape.prop.Presets;
import de.sciss.fscape.prop.PropertyArray;
import de.sciss.fscape.session.ModulePanel;
import de.sciss.fscape.spect.SpectFrame;
import de.sciss.fscape.spect.SpectStream;
import de.sciss.fscape.spect.SpectralFile;
import de.sciss.fscape.spect.Wavelet;
import de.sciss.fscape.util.Constants;
import de.sciss.fscape.util.Filter;
import de.sciss.fscape.util.Param;
import de.sciss.fscape.util.Util;
import de.sciss.gui.AbstractWindowHandler;
import de.sciss.gui.PathEvent;
import de.sciss.gui.PathListener;
import de.sciss.io.AudioFile;
import de.sciss.io.AudioFileDescr;
import javax.swing.*;
import java.awt.*;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
/**
* Processing module for converting different
* data representations, e.g. sound file,
* spectral file, image file.
*/
public class ConvertDlg
extends ModulePanel {
// -------- private variables --------
private static PropertyArray static_pr = null;
private static Presets static_presets = null;
private PropertyGUI settingsGUI;
private int inType = TYPE_UNKNOWN;
private int outType = TYPE_UNKNOWN;
private static final int TYPE_UNKNOWN = -1;
private static final int TYPE_SOUND = 0;
private static final int TYPE_SPECT = 1;
private static final int TYPE_IMAGE = 2;
// Fehlermeldungen
private static final String ERR_CONVERSION = "Unsupported conversion";
// Properties (defaults)
private static final int PR_INPUTFILE = 0; // pr.text
private static final int PR_OUTPUTFILE = 1;
private static final int PR_OUTPUTTYPE = 0; // pr.intg
private static final int PRS_BANDS = 1;
private static final int PRS_BANDWIDTH = 2;
private static final int PRS_FRAMELEN = 3;
private static final int PRS_TRANSFORM = 4;
// private static final int PRS_FILTER = 5;
private static final int PRS_WINDOW = 6;
private static final int PRS_OVERLAP = 7;
private static final int PRS_COLORMODE = 8;
private static final int PRS_OVERHEAD = 9;
private static final int PRS_CHANNELS = 10;
private static final int PR_OUTPUTRES = 11;
private static final int PR_OUTPUTRATE = 12;
private static final int PR_ADJUSTGAIN = 0; // pr.bool
private static final int PR_GAIN = 0; // pr.para
private static final int PRS_NOISEFLOOR = 1;
private static final int PRS_TRANSFORM_FFT = 0;
private static final int PRS_TRANSFORM_DFT = 1;
private static final int PRS_TRANSFORM_FWT = 2;
private static final int PRS_FILTER_DAUB4 = 0;
// private static final int PRS_WINDOW_HAMMING = 0; // CORRESPONDIERT mit Filter.WIN_... !!
// private static final int PRS_WINDOW_BLACKMAN = 1;
// private static final int PRS_WINDOW_KAISER4 = 2;
private static final int PRS_WINDOW_KAISER5 = 3;
// private static final int PRS_WINDOW_KAISER6 = 4;
// private static final int PRS_WINDOW_KAISER8 = 5;
// private static final int PRS_OVERLAP_400 = 0;
// private static final int PRS_OVERLAP_200 = 1;
private static final int PRS_OVERLAP_100 = 2;
// private static final int PRS_OVERLAP_50 = 3;
private static final int PRS_COLORMODE_CHAN = 0;
private static final int PRS_COLORMODE_POLAR = 1;
private static final int PRS_OVERHEAD_TILE = 0;
// private static final int PRS_OVERHEAD_FILES = 1;
// private static final int PRS_CHANNELS_UNTOUCHED = 0;
// private static final int PRS_CHANNELS_1 = 1;
// private static final int PRS_CHANNELS_2 = 2;
private static final int PRS_CHANNELS_3 = 3;
private static final double freqScales[] = { 1.0036166659754628, 1.0048251256952678, // 1/16, 1/12 semitone
1.007246412223704, 1.0145453349375237, // 1/8, 1/4 semitone
1.029302236643492, 1.0594630943592953 }; // 1/2, 1/1 semitone
private static final String PRN_INPUTFILE = "InputFile";
private static final String PRN_OUTPUTFILE = "OutputFile";
private static final String PRN_OUTPUTTYPE = "OutputType";
private static final String PRN_OUTPUTRES = "OutputRes";
private static final String PRN_OUTPUTRATE = "OutputRate";
private static final String PRN_BANDS = "Bands";
private static final String PRN_BANDWIDTH = "Bandwidth";
private static final String PRN_FRAMELEN = "FrameLen";
private static final String PRN_TRANSFORM = "Transform";
private static final String PRN_FILTER = "Filter";
private static final String PRN_WINDOW = "Window";
private static final String PRN_OVERLAP = "Overlap";
private static final String PRN_COLORMODE = "ColorMode";
private static final String PRN_OVERHEAD = "Overhead";
private static final String PRN_CHANNELS = "Channels";
private static final String PRN_NOISEFLOOR = "NoiseFloor";
private static final String PRN_ADJUSTGAIN = "AdjustGain";
private static final String prText[] = { "", "" };
private static final String prTextName[] = { PRN_INPUTFILE, PRN_OUTPUTFILE };
private static final int prIntg[] = { 0, 1, 1, 1, PRS_TRANSFORM_FFT, PRS_FILTER_DAUB4,
PRS_WINDOW_KAISER5, PRS_OVERLAP_100,
PRS_COLORMODE_CHAN, PRS_OVERHEAD_TILE,
PRS_CHANNELS_3, 0, 0 };
private static final String prIntgName[] = { PRN_OUTPUTTYPE, PRN_BANDS, PRN_BANDWIDTH, PRN_FRAMELEN, PRN_TRANSFORM, PRN_FILTER,
PRN_WINDOW, PRN_OVERLAP, PRN_COLORMODE,
PRN_OVERHEAD, PRN_CHANNELS, PRN_OUTPUTRES, PRN_OUTPUTRATE };
private static final boolean prBool[] = { false };
private static final String prBoolName[] = { PRN_ADJUSTGAIN };
private static final Param prPara[] = { null, null };
private static final String prParaName[] = { PRN_GAIN, PRN_NOISEFLOOR };
private static final int GG_INPUTFILE = GG_OFF_PATHFIELD + PR_INPUTFILE;
private static final int GG_OUTPUTFILE = GG_OFF_PATHFIELD + PR_OUTPUTFILE;
private static final int GG_OUTPUTTYPE = GG_OFF_CHOICE + PR_OUTPUTTYPE;
private static final int GG_OUTPUTRES = GG_OFF_CHOICE + PR_OUTPUTRES;
private static final int GG_OUTPUTRATE = GG_OFF_CHOICE + PR_OUTPUTRATE;
private static final int GG_SETTINGS = GG_OFF_OTHER + 0;
// GUI Types
private static final int GUI_ANALYSIS = 0; // Waveform => Spect
private static final int GUI_SYNTHESIS = 1; // Spect => Waveform
private static final int GUI_TOIMAGE = 2; // Spect => Image
private static final int GUI_FROMIMAGE = 3; // Image => Spect
// -------- public methods --------
/**
* !! setVisible() bleibt dem Aufrufer ueberlassen
*/
public ConvertDlg()
{
super( "Convert files" );
init2();
}
protected void buildGUI()
{
// einmalig PropertyArray initialisieren
if( static_pr == null ) {
static_pr = new PropertyArray();
static_pr.text = prText;
static_pr.textName = prTextName;
static_pr.intg = prIntg;
static_pr.intgName = prIntgName;
static_pr.bool = prBool;
static_pr.boolName = prBoolName;
static_pr.para = prPara;
static_pr.para[ PR_GAIN ] = new Param( 0.0, Param.DECIBEL_AMP );
static_pr.para[ PRS_NOISEFLOOR ]= new Param( -120.0, Param.DECIBEL_AMP );
static_pr.paraName = prParaName;
// static_pr.superPr = DocumentFrame.static_pr;
}
// default preset
if( static_presets == null ) {
static_presets = new Presets( getClass(), static_pr.toProperties( true ));
}
presets = static_presets;
pr = (PropertyArray) static_pr.clone();
// -------- build GUI --------
GridBagConstraints con;
PathField ggInputFile, ggOutputFile;
PathField[] ggInputs;
int[][] handledTypes;
JScrollPane ggSettings;
gui = new GUISupport();
con = gui.getGridBagConstraints();
con.insets = new Insets( 1, 2, 1, 2 );
ItemListener il = new ItemListener() {
public void itemStateChanged( ItemEvent e )
{
int ID = gui.getItemID( e );
switch( ID ) {
case ConvertDlg.GG_OUTPUTTYPE:
outputChanged();
break;
default:
break;
}
}
};
PathListener pathL = new PathListener() {
public void pathChanged( PathEvent e )
{
int ID = gui.getItemID( e );
switch( ID ) {
case ConvertDlg.GG_INPUTFILE:
setInput( ((PathField) e.getSource()).getPath().getPath() );
outputChanged();
break;
}
}
};
AdjustmentListener al = new AdjustmentListener() {
public void adjustmentValueChanged( AdjustmentEvent e ) {}
};
// -------- I/O-Gadgets --------
con.fill = GridBagConstraints.BOTH;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addLabel( new GroupLabel( "Input / Output", GroupLabel.ORIENT_HORIZONTAL,
GroupLabel.BRACE_NONE ));
ggInputFile = new PathField( PathField.TYPE_INPUTFILE + PathField.TYPE_FORMATFIELD,
"Select input file" );
handledTypes = new int[3][];
handledTypes[0] = GenericFile.TYPES_SOUND;
handledTypes[1] = GenericFile.TYPES_SPECT;
handledTypes[2] = GenericFile.TYPES_IMAGE;
ggInputFile.handleTypes( handledTypes );
con.gridwidth = 1;
con.weightx = 0.1;
gui.addLabel( new JLabel( "Input file", SwingConstants.RIGHT ));
con.gridwidth = GridBagConstraints.REMAINDER;
con.weightx = 0.9;
gui.addPathField( ggInputFile, GG_INPUTFILE, pathL );
ggOutputFile = new PathField( PathField.TYPE_OUTPUTFILE + PathField.TYPE_FORMATFIELD +
PathField.TYPE_RESFIELD + PathField.TYPE_RATEFIELD, "Select output file" );
ggOutputFile.handleTypes( handledTypes );
ggInputs = new PathField[ 1 ];
ggInputs[ 0 ] = ggInputFile;
ggOutputFile.deriveFrom( ggInputs, "$D0$F0$E" );
con.gridwidth = 1;
con.weightx = 0.1;
gui.addLabel( new JLabel( "Output file", SwingConstants.RIGHT ));
con.gridwidth = GridBagConstraints.REMAINDER;
con.weightx = 0.9;
gui.addPathField( ggOutputFile, GG_OUTPUTFILE, pathL );
gui.registerGadget( ggOutputFile.getTypeGadget(), GG_OUTPUTTYPE );
ggOutputFile.getTypeGadget().addItemListener( il );
gui.registerGadget( ggOutputFile.getResGadget(), GG_OUTPUTRES );
gui.registerGadget( ggOutputFile.getRateGadget(), GG_OUTPUTRATE );
// -------- Conversion-Parameter --------
gui.addLabel( new JLabel( "Conversion settings", SwingConstants.CENTER ));
con.fill = GridBagConstraints.BOTH;
ggSettings = new JScrollPane(); // ( ScrollPane.SCROLLBARS_AS_NEEDED );
ggSettings.putClientProperty ( "styleId", "nofocus" );
ggSettings.setPreferredSize( new Dimension( 256, 256 )); // XXX
con.gridwidth = GridBagConstraints.REMAINDER;
con.weightx = 1.0;
con.weighty = 1.0;
gui.addScrollPane( ggSettings, GG_SETTINGS, al );
initGUI( this, FLAGS_PRESETS | FLAGS_PROGBAR, gui );
// outputChanged();
}
/*
* Settings-GUI in Abhaengigkeit von der jeweiligen Konvertierungs-Art
*/
protected PropertyGUI createGUI( int type )
{
PropertyGUI g;
String gain = "cbAdjust gain,actrue|100|en,acfalse|100|di,pr"+PRN_ADJUSTGAIN+";"+
"pf"+Constants.decibelAmpSpace+",id100,pr"+PRN_GAIN;
String transform = "lbTransform;ch,pr"+PRN_TRANSFORM+
",ac"+PRS_TRANSFORM_FFT+"|21|di|22|di|23|di"+
",ac"+PRS_TRANSFORM_DFT+"|21|di|22|en|23|en"+
",ac"+PRS_TRANSFORM_FWT+"|21|en|22|di|23|di,"+
"itFast Fourier,itDiscrete Fourier (log. Scale),itFast Wavelet\n"+
"lbFilter;ch,id21,pr"+PRN_FILTER+",itDaubechies 4\n";
String window = "lbWindow;ch,pr"+PRN_WINDOW+",itHamming,itBlackman,itKaiser \u03B2=4,itKaiser \u03B2=5,itKaiser \u03B2=6,itKaiser \u03B2=8\n";
String overlap = "lbOverlap;ch,pr"+PRN_OVERLAP+",it1x,it2x,it4x,it8x,it16x\n";
String bands = "lbBands;ch,pr"+PRN_BANDS+",it4096,it2048,it1024,it512,it256,it128,it64,it32\n"+
"lbBandwidth [semi];ch,id22,pr"+PRN_BANDWIDTH+",it1/16,it1/12,it1/8,it1/4,it1/2,it1/1\n"+
"lbFrame length;ch,id23,pr"+PRN_FRAMELEN+",it4096,it2048,it1024,it512,it256,it128,it64,it32\n";
String smpRate = "";
String smpRes = "";
String image = "lbSeparate colors for;ch,pr"+PRN_COLORMODE+",itEach channel,itAmp + Phase\n"+
"lbHandle overhead;ch,pr"+PRN_OVERHEAD+",itBy horizontal tiling,"+
"itBy creating separate files\n"+
"lbChannels;ch,pr"+PRN_CHANNELS+",itLeave untouched,it1,it2,it3\n"+
"lbNoisefloor;pf"+Constants.decibelAmpSpace+",pr"+PRN_NOISEFLOOR+"\n";
String image2 = "";
String guiDescr = null;
switch( type ) {
case GUI_ANALYSIS:
guiDescr = transform + bands + window + overlap + gain;
break;
case GUI_SYNTHESIS:
guiDescr = transform + window + smpRes + gain;
break;
case GUI_TOIMAGE:
guiDescr = image + image2 + gain;
break;
case GUI_FROMIMAGE:
guiDescr = transform + smpRate + overlap + image + gain;
break;
default:
return null;
}
g = new PropertyGUI( guiDescr );
g.setType( type );
return g;
}
/**
* Liefert PropertyGUI der Settings-Gadgets
*/
public PropertyGUI getSettingsGUI()
{
return settingsGUI;
}
/**
* Transfer values from prop-array to GUI
*/
public void fillGUI()
{
super.fillGUI();
super.fillGUI( gui );
PropertyGUI g = getSettingsGUI();
setInput( pr.text[ PR_INPUTFILE ]);
outputChanged();
if( g != null ) {
g.fillGUI( pr ); // load values
}
}
/**
* Transfer values from GUI to prop-array
*/
public void fillPropertyArray()
{
super.fillPropertyArray();
super.fillPropertyArray( gui );
PropertyGUI g = getSettingsGUI();
if( g != null ) {
g.fillPropertyArray( pr ); // save values
}
}
/**
* Wechselt das Settings-GUI
* bei ungueltigem type bleibt das Panel leer
*/
public void setSettingsGUI( int type )
{
Dimension dim;
JScrollPane ggSettings = (JScrollPane) gui.getItemObj( GG_SETTINGS );
if( ggSettings == null ) return;
settingsGUI = createGUI( type );
if( settingsGUI != null ) {
settingsGUI.fillGUI( getPropertyArray() );
dim = ggSettings.getSize();
settingsGUI.setSize( dim.width, dim.height );
// GUIUtil.setDeepFont( settingsGUI, Main.getFont( Main.FONT_GUI ));
ggSettings.setViewportView( settingsGUI );
// setFont( getFont() );
AbstractWindowHandler.setDeepFont( settingsGUI );
} else {
ggSettings.setViewportView( null );
}
}
/**
* Set new input file
*/
public void setInput( String fname )
{
GenericFile f;
int mode;
// ---- Typ ermitteln ----
inType = TYPE_UNKNOWN;
try { // ---- Spectral file ----
f = new GenericFile( fname, GenericFile.MODE_INPUT );
mode = f.mode & GenericFile.MODE_TYPEMASK;
if( Util.isValueInArray( mode, GenericFile.TYPES_IMAGE )) {
inType = TYPE_IMAGE;
} else if( Util.isValueInArray( mode, GenericFile.TYPES_SOUND )) {
inType = TYPE_SOUND;
} else if( Util.isValueInArray( mode, GenericFile.TYPES_SPECT )) {
inType = TYPE_SPECT;
} else {
inType = TYPE_UNKNOWN;
}
f.close();
} catch( IOException ignored) {}
}
/**
* automatischer Output Name bei geaendertem Input oder Output-Type
* veranlasst Aktivierung / Deaktivierung des Convert-JButtons
* und passt das Settings-Panel an die Einstellung an
* (inType muss korrekt sein dafuer!)
*/
public void outputChanged()
{
int mode;
int guiType = -1;
PathField ggOutput = (PathField) gui.getItemObj( GG_OUTPUTFILE );
outType = TYPE_UNKNOWN;
if( ggOutput != null ) {
mode = ggOutput.getType();
if( Util.isValueInArray( mode, GenericFile.TYPES_IMAGE )) {
outType = TYPE_IMAGE;
} else if( Util.isValueInArray( mode, GenericFile.TYPES_SOUND )) {
outType = TYPE_SOUND;
} else if( Util.isValueInArray( mode, GenericFile.TYPES_SPECT )) {
outType = TYPE_SPECT;
} else {
outType = TYPE_UNKNOWN;
}
}
switch( outType ) {
case TYPE_SPECT:
if( inType == TYPE_SOUND ) {
guiType = GUI_ANALYSIS;
} else if( inType == TYPE_IMAGE ) {
guiType = GUI_FROMIMAGE;
}
break;
case TYPE_SOUND:
if( inType == TYPE_SPECT ) {
guiType = GUI_SYNTHESIS;
}
break;
case TYPE_IMAGE:
if( inType == TYPE_SPECT ) {
guiType = GUI_TOIMAGE;
}
break;
default:
break;
}
// ---- Conversion Settings ----
settingsGUI = getSettingsGUI();
if( (settingsGUI == null) || (settingsGUI.getType() != guiType) ) {
setSettingsGUI( guiType );
}
}
// -------- Processor Interface --------
protected void process()
{
int m;
// io
Object inF = null;
Object outF = null;
Object inStream = null;
Object outStream = null;
SpectFrame frame = null;
PathField ggOutput;
// Convert
float progress = 0.0f;
int chanNum = pr.intg[ PRS_CHANNELS ];
float smpRate; // = smpRates[ pr.intg[ PRS_SMPRATE ]];
int frames = 0;
int bands = (1 << (12 - pr.intg[ PRS_BANDS ])) + 1;
int bandsD;
int frameLen = (1 << (12 - pr.intg[ PRS_FRAMELEN ]));
int overlap = pr.intg[ PRS_OVERLAP ];
float loFreq = 0.0f;
float hiFreq;
final float masterTune = 440.0f; // XXX let user pick it
int shorty;
float floaty;
float gain = 1.0f; // gain abs amp
final Param ampRef = new Param( 1.0, Param.ABS_AMP ); // transform-Referenz
// Image conversion
byte[] row = null;
int tile;
final float phasePerByte = (float) (Constants.PI2 / 255.0);
final float phasePerWord = (float) (Constants.PI2 / 65535.0);
final float ampPerByte = (float) ((20.0 * 255.0 / pr.para[ PRS_NOISEFLOOR ].value) / Constants.ln10);
final float ampPerWord = (float) ((20.0 * 65535.0 / pr.para[ PRS_NOISEFLOOR ].value) / Constants.ln10);
int smpPerPixel = 1; // will be filled with ImageStream-value!
// FFT, DFT, FWT
double freqScale = 0f; // DFT: Freq.factor von einem Band zum naechsthoeheren
float img, real;
float[] smpData = null;
float[] smpData2 = null; // gewindowte Version
float[][] cos = null; // 1. Dimension = Freq-Offset, 2. Dimension = Zeit-Offset
float[][] sin = null;
float[] fCos, fSin; // cos/sin mit aufgeloester erster Dimension
float[] win = null; // Window-Funktion
float[][] tempBuf = null;
long audioOutLength = 0;
topLevel: try {
// ---- other init ----
if( pr.bool[ PR_ADJUSTGAIN ]) {
gain = (float) (Param.transform( pr.para[ PR_GAIN ], Param.ABS_AMP, ampRef, null )).value;
}
// --- open input ----
switch( inType ) {
case TYPE_SPECT:
inF = new SpectralFile( pr.text[ PR_INPUTFILE ], GenericFile.MODE_INPUT );
inStream = ((SpectralFile) inF).getDescr();
// this helps to prevent errors from empty files!
if( ((SpectStream) inStream).frames <= 0 ) throw new EOFException( ERR_EMPTY );
break;
case TYPE_SOUND:
inF = AudioFile.openAsRead( new File( pr.text[ PR_INPUTFILE ]));
inStream = ((AudioFile) inF).getDescr();
// this helps to prevent errors from empty files!
if( ((AudioFileDescr) inStream).length <= 0 ) throw new EOFException( ERR_EMPTY );
break;
case TYPE_IMAGE:
inF = new ImageFile( pr.text[ PR_INPUTFILE ], GenericFile.MODE_INPUT );
inStream = ((ImageFile) inF).initReader();
// this helps to prevent errors from empty files!
if( ((ImageStream) inStream).height <= 0 ) throw new EOFException( ERR_EMPTY );
row = ((ImageFile) inF).allocRow();
break;
default:
throw new IOException( ERR_CONVERSION );
}
// .... check running ....
if( !threadRunning ) break topLevel;
// --- open + prepare output ----
switch( outType ) {
case TYPE_SPECT:
ggOutput = (PathField) gui.getItemObj( GG_OUTPUTFILE );
if( ggOutput == null ) throw new IOException( ERR_MISSINGPROP );
outF = new SpectralFile( pr.text[ PR_OUTPUTFILE ], GenericFile.MODE_OUTPUT | ggOutput.getType() );
outStream = new SpectStream();
ggOutput.fillStream( (SpectStream) outStream );
switch( inType ) {
case TYPE_IMAGE: // ------------------------------ TIFF ==> Spect ------------------------------
if( chanNum == 0 ) {
chanNum = 1;
}
if( pr.intg[ PRS_COLORMODE ] == PRS_COLORMODE_CHAN ) {
chanNum = Math.min( chanNum, ((ImageStream) inStream).smpPerPixel );
}
tile = (pr.intg[ PRS_OVERHEAD ] == PRS_OVERHEAD_TILE) ?
((pr.intg[ PRS_COLORMODE ] == PRS_COLORMODE_CHAN) ? 2 : chanNum) : 1;
bands = ((ImageStream) inStream).width / tile;
if( pr.intg[ PRS_TRANSFORM ] == PRS_TRANSFORM_FFT ) { // power of 2
for( m = bands - 1, bands = 1; m > 1; m >>= 1, bands <<= 1 ) ;
bands++;
}
smpRate = ((SpectStream) outStream).smpRate;
hiFreq = smpRate / 2;
smpPerPixel = ((ImageStream) inStream).smpPerPixel;
frames = ((ImageStream) inStream).height;
break;
case TYPE_SOUND: // ------------------------------ Waveform => Spect ------------------------------
chanNum = ((AudioFileDescr) inStream).channels;
smpRate = (float) ((AudioFileDescr) inStream).rate;
switch( pr.intg[ PRS_TRANSFORM ]) {
// case PRS_TRANSFORM_FFT: // .... fast fourier ....
// loFreq = 0.0f;
// hiFreq = smpRate/2;
// frameLen = bands-1;
// break;
case PRS_TRANSFORM_DFT: // .... discrete fourier w/ log scale ....
bands--;
// what we are doing here: Anhand der Bandbreite und Sampling-Rate die Frequenz
// des untersten Bandes errechnen und ggf. nach unten so anpassen, dass die
// Tuning Frequenz (masterTune=440 Hz) erreicht wird
freqScale = freqScales[ pr.intg[ PRS_BANDWIDTH ]];
loFreq = (float) (smpRate / (2 * Math.pow( freqScale, bands - 1 )));
m = (int) Math.ceil( Math.log( masterTune / loFreq ) / Math.log( freqScale ));
loFreq = (float) (masterTune / Math.pow( freqScale, m ));
hiFreq = (float) (loFreq * Math.pow( freqScale, bands - 1 ));
// Sin/Cos Tabellen anlegen
cos = new float[ bands ][ frameLen ];
sin = new float[ bands ][ frameLen ];
calcCosineTables( cos, sin, loFreq, hiFreq, smpRate, +1 );
break;
case PRS_TRANSFORM_FWT: // .... fast wavelet (pyramid) ....
bands--;
loFreq = 0.0f;
hiFreq = smpRate/2; // nicht wirklich sinnvoll ;)
frameLen = bands;
break;
default:
throw new IOException( ERR_CONVERSION );
}
win = Filter.createWindow( (frameLen >> 1), pr.intg[ PRS_WINDOW ]);
if( pr.bool[ PR_ADJUSTGAIN ]) {
for( int i = 0; i < win.length; i++ ) {
win[ i ] *= gain; // Gain-Adjustment gleich reinrechnen
}
}
smpData = new float[ frameLen * chanNum ];
smpData2= new float[ frameLen * chanNum ];
tempBuf = new float[ chanNum ][ frameLen ];
frames = (int) (((AudioFileDescr) inStream).length + frameLen-1) / frameLen;
break;
default:
throw new IOException( ERR_CONVERSION );
}
((SpectStream) outStream).setChannels( chanNum );
// XXX smpPerFrame = bands * (1 - overlap) ?!
// final int smpPerFrame = (bands - 1) << Math.max( 0, 2 - overlap ) >> Math.max( 0, overlap - 2 );
final int smpPerFrame = (bands - 1) >> overlap;
//System.out.println( "(bands - 1) = " + (bands - 1) + "; (overlap - 2) = " + (overlap - 2) + "; smpPerFrame = " + smpPerFrame );
((SpectStream) outStream).setRate( smpRate, smpPerFrame );
// ((SpectStream) outStream).setRate( smpRate, bands - 1 );
((SpectStream) outStream).setEstimatedLength( frames );
((SpectStream) outStream).setBands( loFreq, hiFreq, bands,
(pr.intg[ PRS_TRANSFORM ] == PRS_TRANSFORM_FFT) ?
SpectStream.MODE_LIN : SpectStream.MODE_LOG );
((SpectralFile) outF).initWriter( (SpectStream) outStream,
(pr.intg[ PRS_TRANSFORM ] == PRS_TRANSFORM_FWT) ?
SpectralFile.PVA_MAG : SpectralFile.PVA_POLAR ); // Wavelet: only magnitudes!
frame = ((SpectralFile) outF).allocFrame();
break;
case TYPE_SOUND:
ggOutput = (PathField) gui.getItemObj( GG_OUTPUTFILE );
if( ggOutput == null ) throw new IOException( ERR_MISSINGPROP );
outStream = new AudioFileDescr();
ggOutput.fillStream( (AudioFileDescr) outStream );
// outF = new AudioFile( pr.text[ PR_OUTPUTFILE ], AudioFile.MODE_OUTPUT | ggOutput.getType() );
switch( inType ) {
case TYPE_SPECT: // ------------------------------ Spect ==> Waveform --------------------
bands = ((SpectStream) inStream).bands;
chanNum = ((SpectStream) inStream).chanNum;
frameLen = ((SpectStream) inStream).smpPerFrame;
smpRate = ((SpectStream) inStream).smpRate;
((AudioFileDescr) outStream).channels = chanNum;
((AudioFileDescr) outStream).rate = smpRate;
audioOutLength = frameLen * ((SpectStream) inStream).frames;
switch( pr.intg[ PRS_TRANSFORM ]) {
// switch( ((SpectStream) inStream).freqMode ) {
// case SpectStream.MODE_LIN: // ---- inverse FFT ----
// case PRS_TRANSFORM_FFT:
// break;
// case SpectStream.MODE_LOG: // ---- inverse DFT ----
case PRS_TRANSFORM_DFT:
loFreq = ((SpectStream) inStream).loFreq;
hiFreq = ((SpectStream) inStream).hiFreq;
// Sin/Cos Tabellen anlegen
cos = new float[ bands ][ frameLen ];
sin = new float[ bands ][ frameLen ];
calcCosineTables( cos, sin, loFreq, hiFreq, smpRate, -1 );
break;
case PRS_TRANSFORM_FWT: // ---- inverse FWT ----
loFreq = 0.0f;
hiFreq = smpRate/2;
for( m = bands - 1, bands = 1; m > 1; m >>= 1, bands <<= 1 ) ;
frameLen = bands++;
break;
default:
throw new IOException( ERR_CONVERSION );
}
win = Filter.createWindow( (frameLen >> 1), pr.intg[ PRS_WINDOW ]);
if( pr.bool[ PR_ADJUSTGAIN ]) {
for( int i = 0; i < win.length; i++ ) {
win[ i ] *= gain; // Gain-Adjustment gleich reinrechnen
}
}
break;
default:
throw new IOException( ERR_CONVERSION );
}
outF = AudioFile.openAsWrite( (AudioFileDescr) outStream );
smpData = new float[ frameLen * chanNum ];
smpData2= new float[ frameLen * chanNum ];
tempBuf = new float[ chanNum ][ frameLen ];
break;
case TYPE_IMAGE:
ggOutput = (PathField) gui.getItemObj( GG_OUTPUTFILE );
if( ggOutput == null ) throw new IOException( ERR_MISSINGPROP );
outF = new ImageFile( pr.text[ PR_OUTPUTFILE ], GenericFile.MODE_OUTPUT | ggOutput.getType() );
outStream = new ImageStream();
ggOutput.fillStream( (ImageStream) outStream );
switch( inType ) {
case TYPE_SPECT: // ------------------------------ Spect ==> TIFF ------------------------------
((ImageStream) outStream).height = (int) ((SpectStream) inStream).frames;
((ImageStream) outStream).hRes = 1f / 72f;
((ImageStream) outStream).vRes = 1f / 72f;
((ImageStream) outStream).resUnit = ImageStream.RES_INCH;
// ((ImageStream) outStream).bitsPerSmp= 8 << pr.intg[ PRS_COLORDEPTH ];
bands = ((SpectStream) inStream).bands;
if( chanNum == 0 ) {
chanNum = ((SpectStream) inStream).chanNum;
}
chanNum = Math.min( chanNum, ((SpectStream) inStream).chanNum );
if( (pr.intg[ PRS_COLORMODE ] == PRS_COLORMODE_CHAN) && (chanNum > 3) ) {
chanNum = 3;
}
if( ((pr.intg[ PRS_COLORMODE ] == PRS_COLORMODE_CHAN) && (chanNum > 1)) ||
(pr.intg[ PRS_COLORMODE ] == PRS_COLORMODE_POLAR) ) {
((ImageStream) outStream).smpPerPixel = 3; // rgb for multichannel or amp/phase code
} else {
((ImageStream) outStream).smpPerPixel = 1; // grayscale else
}
smpPerPixel = ((ImageStream) outStream).smpPerPixel;
tile = (pr.intg[ PRS_OVERHEAD ] == PRS_OVERHEAD_TILE) ?
((pr.intg[ PRS_COLORMODE ] == PRS_COLORMODE_CHAN) ? 2 : chanNum) : 1;
((ImageStream) outStream).width = bands * tile;
//System.out.println( "width "+((ImageStream) outStream).width+"; smpPerPixel "+((ImageStream) outStream).smpPerPixel+"; bitsPerSmp "+((ImageStream) outStream).bitsPerSmp );
((ImageFile) outF).initWriter( (ImageStream) outStream );
row = ((ImageFile) outF).allocRow();
break;
default:
throw new IOException( ERR_CONVERSION );
}
break;
default:
throw new IOException( ERR_CONVERSION );
}
bandsD = bands << 1;
// ---- Conversion Loop ----
while( (progress < 1.0f) && threadRunning ) {
switch( inType ) {
case TYPE_IMAGE: // ------------------------------ TIFF ==> Spect ------------------------------
// System.out.println( "reading row " + ((ImageStream) inStream).rowsRead +
// " of " + ((ImageStream) inStream).width + " x " + ((ImageStream) inStream).height );
((ImageFile) inF).readRow( row );
switch( pr.intg[ PRS_COLORMODE ]) {
case PRS_COLORMODE_CHAN:
if( ((ImageStream) inStream).bitsPerSmp == 8 ) { // 8 bit
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0, bandD = 0; band < bands; band++, bandD += 2 ) {
frame.data[ ch ][ bandD + SpectFrame.AMP ] = (float) Math.exp( (float)
(255 - ((int) row[ band * smpPerPixel + ch ] & 0xFF)) / ampPerByte );
frame.data[ ch ][ bandD + SpectFrame.PHASE ] = phasePerByte * (float) ((int)
row[ (bands + band) * smpPerPixel + ch ] & 0xFF) - (float) Math.PI;
}
}
} else { // 16 bit
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0; band < bandsD; band += 2 ) {
shorty = (((int) row[ band * smpPerPixel + ch ] & 0xFF) << 8) |
((int) row[ band * smpPerPixel + ch+1 ] & 0xFF);
frame.data[ ch ][ band + SpectFrame.AMP ] = (float) Math.exp( (float)
(65535 - shorty) / ampPerWord );
shorty = (((int) row[ (bandsD + band) * smpPerPixel + ch ] & 0xFF) << 8) |
((int) row[ (bandsD + band) * smpPerPixel + ch+1 ] & 0xFF);
frame.data[ ch ][ band + SpectFrame.PHASE ] = phasePerWord *
(float) shorty - (float) Math.PI;
}
}
}
break;
default: // polar
if( ((ImageStream) inStream).bitsPerSmp == 8 ) { // 8 bit
if( ((ImageStream) inStream).smpPerPixel >= 2 ) {
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0, bandD = 0; band < bands; band++, bandD += 2 ) {
frame.data[ ch ][ bandD + SpectFrame.AMP ] = (float) Math.exp( (float)
(255 - ((int) row[ (band + bands * ch) * smpPerPixel + ch ] & 0xFF)) / ampPerByte );
frame.data[ ch ][ bandD + SpectFrame.PHASE ] = phasePerByte * (float) ((int)
row[ (band + bands * ch) * smpPerPixel + ch+1 ] & 0xFF) - (float) Math.PI;
}
}
} else { // grayscale pict => use it as amp-values, pad phases with zero
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0, bandD = 0; band < bands; band++, bandD += 2 ) {
frame.data[ ch ][ bandD + SpectFrame.AMP ] = (float) Math.exp( (float)
(255 - ((int) row[ (band + bands * ch) * smpPerPixel + ch ] & 0xFF)) / ampPerByte );
frame.data[ ch ][ bandD + SpectFrame.PHASE ] = 0.0f;
}
}
}
} else { // 16 bit
if( ((ImageStream) inStream).smpPerPixel >= 2 ) {
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0; band < bandsD; band += 2 ) {
shorty = (((int) row[ (band + bandsD * ch) * smpPerPixel + ch ] & 0xFF) << 8) |
((int) row[ (band + bandsD * ch) * smpPerPixel + ch+1 ] & 0xFF);
frame.data[ ch ][ band + SpectFrame.AMP ] = (float) Math.exp( (float)
(65535 - shorty) / ampPerWord );
shorty = (((int) row[ (band + bandsD * ch) * smpPerPixel + ch+2 ] & 0xFF) << 8) |
((int) row[ (band + bandsD * ch) * smpPerPixel + ch+3 ] & 0xFF);
frame.data[ ch ][ band + SpectFrame.PHASE ] = phasePerWord *
(float) shorty - (float) Math.PI;
}
}
} else { // grayscale pict => use it as amp-values, pad phases with zero
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0; band < bandsD; band += 2 ) {
shorty = (((int) row[ (band + bandsD * ch) * smpPerPixel + ch ] & 0xFF) << 8) |
((int) row[ (band + bandsD * ch) * smpPerPixel + ch+1 ] & 0xFF);
frame.data[ ch ][ band + SpectFrame.AMP ] = (float) Math.exp( (float)
(65535 - shorty) / ampPerWord );
frame.data[ ch ][ band + SpectFrame.PHASE ] = 0.0f;
}
}
}
}
break;
}
if( pr.bool[ PR_ADJUSTGAIN ]) {
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0; band < bandsD; band += 2 ) {
frame.data[ ch ][ band + SpectFrame.AMP ] *= gain; // XXX falsch; mit Bandwidth gewichten!
}
}
}
((SpectralFile) outF).writeFrame( frame );
progress = (float) ((ImageStream) inStream).rowsRead /
(float) ((ImageStream) inStream).height;
break;
case TYPE_SPECT: // ------------------------------ Spect input ------------------------------
frame = ((SpectralFile) inF).readFrame();
switch( outType ) {
case TYPE_IMAGE: // ------------------------------ Spect ==> TIFF ------------------------------
switch( pr.intg[ PRS_COLORMODE ]) {
case PRS_COLORMODE_CHAN:
if( ((ImageStream) outStream).bitsPerSmp == 8 ) { // 8 bit
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0, bandD = 0; band < bands; band++, bandD += 2 ) {
row[ band * smpPerPixel + ch ] = (byte) Math.max( 0, Math.min( 255, 255 - (int) Math.rint(
ampPerByte * Math.log( frame.data[ ch ][ bandD + SpectFrame.AMP ]))));
row[ (bands + band) * smpPerPixel + ch ] = (byte) Math.rint(
((frame.data[ ch ][ bandD + SpectFrame.PHASE ] + Math.PI) % Constants.PI2) / phasePerByte);
}
}
} else { // 16 bit
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0; band < bandsD; band += 2 ) {
shorty = Math.max( 0, Math.min( 65535, 65535 - (int) Math.rint(
ampPerWord * Math.log( frame.data[ ch ][ band + SpectFrame.AMP ]))));
row[ band * smpPerPixel + ch ] = (byte) ((shorty & 0xFF00) >> 8);
row[ band * smpPerPixel + ch+1 ] = (byte) (shorty & 0x00FF);
shorty = (int) Math.rint( ((frame.data[ ch ][ band + SpectFrame.PHASE ] + Math.PI) %
Constants.PI2) / phasePerWord);
row[ (bandsD + band) * smpPerPixel + ch ] = (byte) ((shorty & 0xFF00) >> 8);
row[ (bandsD + band) * smpPerPixel + ch+1 ] = (byte) (shorty & 0x00FF);
}
}
}
break;
default: // polar
if( ((ImageStream) outStream).bitsPerSmp == 8 ) { // 8 bit
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0; band < bands; band++ ) {
row[ (band + bands * ch) * smpPerPixel + ch ] = (byte) Math.max( 0, Math.min( 255, 255 - (int) Math.rint(
ampPerByte * Math.log( frame.data[ ch ][ (band << 1) + SpectFrame.AMP ]))));
row[ (band + bands * ch) * smpPerPixel + ch+1 ] = (byte) Math.rint(
((frame.data[ ch ][ (band << 1) + SpectFrame.PHASE ] + Math.PI) % Constants.PI2) / phasePerByte);
}
}
} else { // 16 bit
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0; band < bandsD; band += 2 ) {
shorty = Math.max( 0, Math.min( 65535, 65535 - (int) Math.rint(
ampPerWord * Math.log( frame.data[ ch ][ band + SpectFrame.AMP ]))));
row[ (band + bandsD * ch) * smpPerPixel + ch ] = (byte) ((shorty & 0xFF00) >> 8);
row[ (band + bandsD * ch) * smpPerPixel + ch+1 ] = (byte) (shorty & 0x00FF);
shorty = (int) Math.rint( ((frame.data[ ch ][ band + SpectFrame.PHASE ] + Math.PI) %
Constants.PI2) / phasePerWord);
row[ (band + bandsD * ch) * smpPerPixel + ch+2 ] = (byte) ((shorty & 0xFF00) >> 8);
row[ (band + bandsD * ch) * smpPerPixel + ch+3 ] = (byte) (shorty & 0x00FF);
}
}
}
break;
}
((ImageFile) outF).writeRow( row );
progress = (float) ((ImageStream) outStream).rowsWritten /
(float) ((ImageStream) outStream).height;
break;
case TYPE_SOUND: // ------------------------------ Spect ==> Waveform ----------------------
switch( pr.intg[ PRS_TRANSFORM ]) {
// case PRS_TRANSFORM_FFT: // ---- inverse FFT ----
// break;
case PRS_TRANSFORM_DFT: // ---- inverse DFT ----
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0; band < (bands << 1); band += 2 ) { // AMP = real, PHASE = img
real = frame.data[ ch ][ band + SpectFrame.AMP ];
img = frame.data[ ch ][ band + SpectFrame.PHASE ];
frame.data[ ch ][ band + SpectFrame.AMP ] = (float) (real * Math.cos( img ));
frame.data[ ch ][ band + SpectFrame.PHASE ] = (float) (real * Math.sin( img ));
}
}
for( int ch = 0; ch < chanNum; ch++ ) {
for( int i = 0, j = ch; i < frameLen; i++, j += chanNum ) {
real = 0f;
for( int band = 0, k = 0; band < bands; band++, k+= 2 ) {
real += frame.data[ ch ][ k + SpectFrame.AMP ] * cos[ band ][ i ];
real -= frame.data[ ch ][ k + SpectFrame.PHASE ] * sin[ band ][ i ];
}
smpData[ j ] = real;
}
}
break;
case PRS_TRANSFORM_FWT: // ---- inverse FWT ----
for( int ch = 0; ch < chanNum; ch++ ) {
// Deinterleave Amp/Phase (omit Phase)
for( int i = SpectFrame.AMP, j = 0; j < frameLen; j++, i += 2 ) {
frame.data[ ch ][ j ] = frame.data[ ch ][ i ];
}
Wavelet.invTransformDaub4( frame.data[ ch ], frameLen );
for( int j = 0, i = ch; j < frameLen; j++, i += chanNum ) {
smpData[ i ] = frame.data[ ch ][ j ];
}
}
break;
}
// XXX for( ch = 0; ch < chanNum; ch++ ) {
// for( i = 0, j = (frameLen >> 1) * chanNum + ch, k = j; i < win.length;
// i++, j += chanNum, k -= chanNum ) {
//
// smpData2[ j ] = smpData[ j ] * win[ i ];
// smpData2[ k ] = smpData[ k ] * win[ i ];
// }
// }
// ((AudioFile) outF).writeSamples( smpData2, 0, smpData2.length );
// ((AudioFile) outF).writeSamples( smpData, 0, smpData.length );
writeInterleaved( (AudioFile) outF, smpData, 0, smpData.length, tempBuf, chanNum );
progress = (float) ((AudioFileDescr) outStream).length /
(float) audioOutLength;
break;
default:
throw new IOException( ERR_CONVERSION );
}
((SpectralFile) inF).freeFrame( frame );
break;
case TYPE_SOUND: // ------------------------------ Waveform ==> Spect --------------------------
// ((AudioFile) inF).readSamples( smpData, 0, smpData.length );
readInterleaved( (AudioFile) inF, smpData, 0, smpData.length, tempBuf, chanNum );
for( int ch = 0; ch < chanNum; ch++ ) {
for( int i = 0, j = (frameLen >> 1) * chanNum + ch, k = j; i < win.length;
i++, j += chanNum, k -= chanNum ) {
smpData2[ j ] = smpData[ j ] * win[ i ];
smpData2[ k ] = smpData[ k ] * win[ i ];
}
}
switch( pr.intg[ PRS_TRANSFORM ]) {
// case PRS_TRANSFORM_FFT: // ---- FFT ----
// break;
case PRS_TRANSFORM_DFT: // ---- DFT ----
for( int ch = 0; ch < chanNum; ch++ ) {
for( int band = 0, k = 0; band < bands; band++, k += 2 ) {
real = 0f;
img = 0f;
fCos = cos[ band ];
fSin = sin[ band ];
for( int i = 0, j = ch; i < frameLen; i++, j += chanNum ) {
floaty = smpData2[ j ];
real += floaty * fCos[ i ];
img += floaty * fSin[ i ];
}
frame.data[ ch ][ k + SpectFrame.AMP ] = (float) Math.sqrt( img*img + real*real );
frame.data[ ch ][ k + SpectFrame.PHASE ]= (float) Math.atan2( img, real );
}
}
break;
case PRS_TRANSFORM_FWT: // ---- FWT ----
for( int ch = 0; ch < chanNum; ch++ ) {
for( int j = 0, i = ch; j < frameLen; j++, i += chanNum ) {
frame.data[ ch ][ j ] = smpData2[ i ];
}
Wavelet.fwdTransformDaub4( frame.data[ ch ], frameLen );
// Interleave Amp/Phase (create zero Phase)
for( int i = ((frameLen-1) << 1), j = frameLen-1; j >= 0; j--, i -= 2 ) {
frame.data[ ch ][ i + SpectFrame.AMP ] = frame.data[ ch ][ i ];
frame.data[ ch ][ i + SpectFrame.PHASE] = 0.0f;
}
}
break;
}
((SpectralFile) outF).writeFrame( frame );
progress = (float) ((AudioFile) inF).getFramePosition() /
(float) ((AudioFileDescr) inStream).length;
break;
default:
throw new IOException( ERR_CONVERSION );
}
// .... progress ....
setProgression( progress );
} // (while not progress == 100% and running)
// .... check running ....
if( !threadRunning ) break topLevel;
// ---- Finish ----
if( outF instanceof AudioFile ) {
((AudioFile) outF).close();
} else if( outF instanceof GenericFile ) {
((GenericFile) outF).close();
}
outF = null;
if( inF instanceof AudioFile ) {
((AudioFile) inF).close();
} else if( inF instanceof GenericFile ) {
((GenericFile) inF).close();
}
inF = null;
}
catch( IOException e1 ) {
setError( e1 );
}
catch( OutOfMemoryError e2 ) {
smpData = null;
smpData2= null;
frame = null;
sin = null;
cos = null;
System.gc();
setError( new Exception( ERR_MEMORY ));
}
// ---- cleanup ----
if( inF != null ) {
switch( inType ) {
case TYPE_SPECT:
if( frame != null ) ((SpectralFile) inF).freeFrame( frame );
((SpectralFile) inF).cleanUp();
break;
case TYPE_SOUND:
((AudioFile) inF).cleanUp();
break;
case TYPE_IMAGE:
((ImageFile) inF).cleanUp();
break;
default:
break;
}
}
if( outF != null ) {
switch( outType ) {
case TYPE_SPECT:
((SpectralFile) outF).cleanUp();
break;
case TYPE_SOUND:
((AudioFile) outF).cleanUp();
break;
case TYPE_IMAGE:
((ImageFile) outF).cleanUp();
break;
default:
break;
}
}
} // process()
// -------- private methods --------
// fuer DFT (run())
// iSign: +1 fuer Transformation, -1 fuer inverse Transformation
private void calcCosineTables( float[][] cos, float[][] sin, float loFreq, float hiFreq,
float smpRate, int iSign )
{
double d1, d2;
double freq, angle;
int i;
int bands = cos.length;
int frameLen = cos[ 0 ].length;
float fCos[], fSin[];
d1 = Math.log( (double) hiFreq / (double) loFreq ) / (double) (bands-1);
d2 = iSign * Constants.PI2 / smpRate;
for( int band = 0; band < bands; band++ ) {
freq = d2 * Math.exp( (double) band * d1 ) * loFreq;
fCos = cos[ band ];
fSin = sin[ band ];
for( i = 0; i < frameLen; i++ ) {
angle = freq * i;
fCos[ i ] = (float) (Math.cos( angle ) / frameLen); // Normalisierungs-Faktor 1/frameLen
fSin[ i ] = (float) (Math.sin( angle ) / frameLen); // bereits reinmultipliziert!!
}
}
}
private static int readInterleaved( AudioFile f, float[] iBuf, int iOff, int iLen, float[][] tempBuf, int numCh )
throws IOException
{
assert (iLen % numCh) == 0 : "invalid interleaved length";
int ch, i, j, len = iLen / numCh;
f.readFrames( tempBuf, 0, len );
for( ch = 0; ch < numCh; ch++ ) {
for( i = iOff + ch, j = 0; j < iLen; i++, j += numCh ) {
iBuf[ i ] = tempBuf[ ch ][ j ];
}
}
return iLen;
}
private static void writeInterleaved( AudioFile f, float[] iBuf, int iOff, int iLen, float[][] tempBuf, int numCh )
throws IOException
{
assert (iLen % numCh) == 0 : "invalid interleaved length";
int ch, i, j, len = iLen / numCh;
for( ch = 0; ch < numCh; ch++ ) {
for( i = iOff + ch, j = 0; j < iLen; i++, j += numCh ) {
tempBuf[ ch ][ j ] = iBuf[ i ];
}
}
f.writeFrames( tempBuf, 0, len );
}
}
// class ConvertDlg