/* * HilbertDlg.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.gui; import de.sciss.fscape.io.FloatFile; import de.sciss.fscape.io.GenericFile; import de.sciss.fscape.prop.Presets; import de.sciss.fscape.prop.PropertyArray; import de.sciss.fscape.session.ModulePanel; import de.sciss.fscape.spect.Fourier; import de.sciss.fscape.util.Constants; import de.sciss.fscape.util.Envelope; import de.sciss.fscape.util.Filter; import de.sciss.fscape.util.Param; import de.sciss.fscape.util.ParamSpace; import de.sciss.fscape.util.Util; import de.sciss.io.AudioFile; import de.sciss.io.AudioFileDescr; import de.sciss.io.IOUtil; import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.EOFException; import java.io.File; import java.io.IOException; /** * Following a paper by J.O.Smith, this * processing module implements a high * quality FIR hilbert quadrature filter * and allows frequency shifting and * high resolution amplitude envelope * calculation. */ public class HilbertDlg extends ModulePanel { // -------- private variables -------- // Properties (defaults) private static final int PR_INPUTFILE = 0; // pr.text private static final int PR_REOUTPUTFILE = 1; private static final int PR_IMOUTPUTFILE = 2; private static final int PR_OUTPUTTYPE = 0; // pr.intg private static final int PR_OUTPUTRES = 1; private static final int PR_GAINTYPE = 2; private static final int PR_MODE = 3; private static final int PR_GAIN = 0; // pr.para private static final int PR_FREQ = 1; private static final int PR_FREQMODDEPTH = 2; private static final int PR_ANTIALIAS = 0; // pr.bool private static final int PR_FREQMOD = 1; private static final int PR_FREQENV = 0; // pr.envl private static final int MODE_UNTOUCHED = 0; private static final int MODE_UPSHIFT = 1; private static final int MODE_DOWNSHIFT = 2; private static final int MODE_ENVELOPE = 3; private static final String[] modeStr = { "Untouched", "Shift up (re+im)", "Shift down (re-im)", "Envelope (re^2+im^2)" }; private static final String PRN_INPUTFILE = "InputFile"; private static final String PRN_REOUTPUTFILE = "ReOutFile"; private static final String PRN_IMOUTPUTFILE = "ImOutFile"; private static final String PRN_OUTPUTTYPE = "OutputType"; private static final String PRN_OUTPUTRES = "OutputReso"; private static final String PRN_MODE = "Mode"; private static final String PRN_FREQ = "Freq"; private static final String PRN_FREQMODDEPTH = "FreqModDepth"; private static final String PRN_ANTIALIAS = "AntiAlias"; private static final String PRN_FREQMOD = "FreqMod"; private static final String PRN_FREQENV = "FreqEnv"; private static final String prText[] = { "", "", "" }; private static final String prTextName[] = { PRN_INPUTFILE, PRN_REOUTPUTFILE, PRN_IMOUTPUTFILE }; private static final int prIntg[] = { 0, 0, 0, MODE_UNTOUCHED }; private static final String prIntgName[] = { PRN_OUTPUTTYPE, PRN_OUTPUTRES, PRN_GAINTYPE, PRN_MODE }; private static final boolean prBool[] = { true, false }; private static final String prBoolName[] = { PRN_ANTIALIAS, PRN_FREQMOD }; private static final Param prPara[] = { null, null, null }; private static final String prParaName[] = { PRN_GAIN, PRN_FREQ, PRN_FREQMODDEPTH }; private static final Envelope prEnvl[] = { null }; private static final String prEnvlName[] = { PRN_FREQENV }; private static final int GG_INPUTFILE = GG_OFF_PATHFIELD + PR_INPUTFILE; private static final int GG_REOUTPUTFILE = GG_OFF_PATHFIELD + PR_REOUTPUTFILE; private static final int GG_IMOUTPUTFILE = GG_OFF_PATHFIELD + PR_IMOUTPUTFILE; 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_MODE = GG_OFF_CHOICE + PR_MODE; private static final int GG_GAINTYPE = GG_OFF_CHOICE + PR_GAINTYPE; private static final int GG_GAIN = GG_OFF_PARAMFIELD + PR_GAIN; private static final int GG_FREQ = GG_OFF_PARAMFIELD + PR_FREQ; private static final int GG_FREQMODDEPTH = GG_OFF_PARAMFIELD + PR_FREQMODDEPTH; private static final int GG_ANTIALIAS = GG_OFF_CHECKBOX + PR_ANTIALIAS; private static final int GG_FREQMOD = GG_OFF_CHECKBOX + PR_FREQMOD; private static final int GG_FREQENV = GG_OFF_ENVICON + PR_FREQENV; private static PropertyArray static_pr = null; private static Presets static_presets = null; // -------- public methods -------- /** * !! setVisible() bleibt dem Aufrufer ueberlassen */ public HilbertDlg() { super( "Hilbert Filter" ); 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_FREQ ] = new Param( 200.0, Param.ABS_HZ ); static_pr.para[ PR_FREQMODDEPTH ] = new Param( 12.0, Param.OFFSET_SEMITONES ); static_pr.paraName = prParaName; static_pr.envl = prEnvl; static_pr.envl[ PR_FREQENV ] = Envelope.createBasicEnvelope( Envelope.BASIC_TIME ); static_pr.envlName = prEnvlName; // static_pr.superPr = DocumentFrame.static_pr; fillDefaultAudioDescr( static_pr.intg, PR_OUTPUTTYPE, PR_OUTPUTRES ); fillDefaultGain( static_pr.para, PR_GAIN ); static_presets = new Presets( getClass(), static_pr.toProperties( true )); } presets = static_presets; pr = (PropertyArray) static_pr.clone(); // -------- build GUI -------- GridBagConstraints con; PathField ggInputFile, ggReOutputFile, ggImOutputFile; PathField[] ggParent1, ggParent2; JComboBox ggMode; ParamField ggFreq, ggFreqModDepth; JCheckBox ggAntiAlias, ggFreqMod; ParamSpace[] spcFreqModDepth; EnvIcon ggFreqEnv; Component[] ggGain; 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 GG_MODE: pr.intg[ ID - GG_OFF_CHOICE ] = ((JComboBox) e.getSource()).getSelectedIndex(); reflectPropertyChanges(); break; case GG_FREQMOD: pr.bool[ ID - GG_OFF_CHECKBOX ] = ((JCheckBox) e.getSource()).isSelected(); reflectPropertyChanges(); break; } } }; // -------- I/O-Gadgets -------- con.fill = GridBagConstraints.BOTH; con.gridwidth = GridBagConstraints.REMAINDER; gui.addLabel( new GroupLabel( "Waveform I/O", GroupLabel.ORIENT_HORIZONTAL, GroupLabel.BRACE_NONE )); ggInputFile = new PathField( PathField.TYPE_INPUTFILE + PathField.TYPE_FORMATFIELD, "Select input file" ); ggInputFile.handleTypes( GenericFile.TYPES_SOUND ); 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, null ); ggReOutputFile = new PathField( PathField.TYPE_OUTPUTFILE + PathField.TYPE_FORMATFIELD + PathField.TYPE_RESFIELD, "Select output for real part" ); ggReOutputFile.handleTypes( GenericFile.TYPES_SOUND ); con.gridwidth = 1; con.weightx = 0.1; gui.addLabel( new JLabel( "Output [Real]", SwingConstants.RIGHT )); con.gridwidth = GridBagConstraints.REMAINDER; con.weightx = 0.9; gui.addPathField( ggReOutputFile, GG_REOUTPUTFILE, null ); gui.registerGadget( ggReOutputFile.getTypeGadget(), GG_OUTPUTTYPE ); gui.registerGadget( ggReOutputFile.getResGadget(), GG_OUTPUTRES ); ggImOutputFile = new PathField( PathField.TYPE_OUTPUTFILE, "Select output for imaginary part" ); // ggImOutputFile.handleTypes( GenericFile.TYPES_SOUND ); con.gridwidth = 1; con.weightx = 0.1; gui.addLabel( new JLabel( "Output [Imaginary]", SwingConstants.RIGHT )); con.gridwidth = GridBagConstraints.REMAINDER; con.weightx = 0.9; gui.addPathField( ggImOutputFile, GG_IMOUTPUTFILE, null ); ggParent1 = new PathField[ 1 ]; ggParent1[ 0 ] = ggInputFile; ggParent2 = new PathField[ 1 ]; ggParent2[ 0 ] = ggReOutputFile; ggReOutputFile.deriveFrom( ggParent1, "$D0$F0Hlb$E" ); ggImOutputFile.deriveFrom( ggParent2, "$D0$F0i$X0" ); ggGain = createGadgets( GGTYPE_GAIN ); con.weightx = 0.1; con.gridwidth = 1; gui.addLabel( new JLabel( "Gain", SwingConstants.RIGHT )); con.weightx = 0.4; gui.addParamField( (ParamField) ggGain[ 0 ], GG_GAIN, null ); con.weightx = 0.5; con.gridwidth = GridBagConstraints.REMAINDER; gui.addChoice( (JComboBox) ggGain[ 1 ], GG_GAINTYPE, il ); // -------- Settings-Gadgets -------- gui.addLabel( new GroupLabel( "Post processing", GroupLabel.ORIENT_HORIZONTAL, GroupLabel.BRACE_NONE )); ggMode = new JComboBox(); for( int i = 0; i < modeStr.length; i++ ) { ggMode.addItem( modeStr[ i ]); } con.gridwidth = 1; con.weightx = 0.1; gui.addLabel( new JLabel( "Operation", SwingConstants.RIGHT )); con.weightx = 0.4; gui.addChoice( ggMode, GG_MODE, il ); ggAntiAlias = new JCheckBox(); con.gridwidth = 2; con.weightx = 0.1; gui.addLabel( new JLabel( "Antialiasing", SwingConstants.RIGHT )); con.gridwidth = GridBagConstraints.REMAINDER; con.weightx = 0.4; gui.addCheckbox( ggAntiAlias, GG_ANTIALIAS, il ); ggFreq = new ParamField( Constants.spaces[ Constants.absHzSpace ]); con.weightx = 0.1; con.gridwidth = 1; gui.addLabel( new JLabel( "Shift amount", SwingConstants.RIGHT )); con.weightx = 0.4; gui.addParamField( ggFreq, GG_FREQ, null ); spcFreqModDepth = new ParamSpace[ 3 ]; spcFreqModDepth[0] = Constants.spaces[ Constants.offsetSemitonesSpace ]; spcFreqModDepth[1] = Constants.spaces[ Constants.offsetFreqSpace ]; spcFreqModDepth[2] = Constants.spaces[ Constants.offsetHzSpace ]; ggFreqModDepth = new ParamField( spcFreqModDepth ); ggFreqModDepth.setReference( ggFreq ); ggFreqMod = new JCheckBox(); con.weightx = 0.1; gui.addCheckbox( ggFreqMod, GG_FREQMOD, il ); con.weightx = 0.4; gui.addParamField( ggFreqModDepth, GG_FREQMODDEPTH, null ); ggFreqEnv = new EnvIcon( getComponent() ); con.weightx = 0.1; con.gridwidth = GridBagConstraints.REMAINDER; gui.addGadget( ggFreqEnv, GG_FREQENV ); initGUI( this, FLAGS_PRESETS | FLAGS_PROGBAR, gui ); } /** * Transfer values from prop-array to GUI */ public void fillGUI() { super.fillGUI(); super.fillGUI( gui ); } /** * Transfer values from GUI to prop-array */ public void fillPropertyArray() { super.fillPropertyArray(); super.fillPropertyArray( gui ); } // -------- Processor Interface -------- protected void process() { int i, j, k, len, off, ch, chunkLength; long progOff, progLen; double d1, d2; float f1; // io AudioFile inF = null; AudioFile reOutF = null; AudioFile imOutF = null; AudioFileDescr inStream; AudioFileDescr reOutStream; AudioFileDescr imOutStream = null; FloatFile[] reFloatF = null; FloatFile[] imFloatF = null; File reTempFile[] = null; File imTempFile[] = null; // buffers float[] fftBuf1; // holds filter float[] fftBuf2; // holds complex input float[][] reBuf; // holds real input/output float[][] imBuf = null; // holds imag input/output float[][] reOverBuf; // convolution overlap add buffer float[][] imOverBuf = null; float[] convBuf1, convBuf2; int inChanNum, inLength, fftLength, inputLen; int framesRead, framesWritten; Param ampRef = new Param( 1.0, Param.ABS_AMP ); // transform-Referenz Param peakGain; float gain = 1.0f; // gain abs amp float maxAmp = 0.0f; boolean modulate; double fltFreq, fltShift, shiftFreq; FilterBox fltBox; Point fltLength; // for FilterBox (.x = support, .y = rightWing) int skip; PathField ggOutput; topLevel: try { // ---- open input, output ---- // input inF = AudioFile.openAsRead( new File( pr.text[ PR_INPUTFILE ])); inStream = inF.getDescr(); inChanNum = inStream.channels; inLength = (int) inStream.length; // this helps to prevent errors from empty files! if( (inLength * inChanNum) < 1 ) throw new EOFException( ERR_EMPTY ); // .... check running .... if( !threadRunning ) break topLevel; // output ggOutput = (PathField) gui.getItemObj( GG_REOUTPUTFILE ); if( ggOutput == null ) throw new IOException( ERR_MISSINGPROP ); reOutStream = new AudioFileDescr( inStream ); ggOutput.fillStream( reOutStream ); reOutF = AudioFile.openAsWrite( reOutStream ); if( pr.intg[ PR_MODE ] == MODE_UNTOUCHED ) { imOutStream = new AudioFileDescr( reOutStream ); imOutStream.file = new File( pr.text[ PR_IMOUTPUTFILE ]); imOutF = AudioFile.openAsWrite( imOutStream ); } // .... check running .... if( !threadRunning ) break topLevel; // ---- parameter inits ---- modulate = (pr.intg[ PR_MODE ] == MODE_UPSHIFT) || (pr.intg[ PR_MODE ] == MODE_DOWNSHIFT); shiftFreq = pr.para[ PR_FREQ ].value; // ABS_HZ fltFreq = inStream.rate * 0.245; // account for lp transition band fltShift = fltFreq; if( modulate && pr.bool[ PR_ANTIALIAS ]) { // d1 = Math.max( 100.0, fltFreq - shiftFreq * 0.625 ); d1 = Math.max( 0.0, fltFreq - shiftFreq * 0.5 ); if( pr.intg[ PR_MODE ] == MODE_UPSHIFT ) { fltShift = d1; } else { fltShift += fltFreq - d1; } fltFreq = d1; } fltShift *= Constants.PI2 / inStream.rate; // normalized freq ready for Math.cos/sin shiftFreq *= Constants.PI2 / inStream.rate; //System.out.println( "fltFreq "+fltFreq+"; fltShift "+fltShift+"; modFreq "+shiftFreq ); fltBox = new FilterBox(); fltBox.filterType= FilterBox.FLT_LOWPASS; fltBox.cutOff = new Param( fltFreq, Param.ABS_HZ ); // fltBox.bandwidth= new Param( fltFreq, Param.OFFSET_HZ ); fltLength = fltBox.calcLength( inStream, FIRDesignerDlg.QUAL_VERYGOOD ); skip = fltLength.x * 2; // support not written out i = (fltLength.x + fltLength.y) * 2 - 1; // length after conv. filter with itself j = i + i - 1; // length after conv. with input for( fftLength = 2; fftLength < j; fftLength <<= 1 ) ; inputLen = fftLength - i - 1; // + 1 // !we don't optimize because overlap handling would get tricky! // j = (fftLength >> 1) + 1 - i; // if( (j > 0) && (((float) i / (float) j) < ((float) inputLen / (float) i)) ) { // optimum fft length // fftLength >>= 1; // inputLen = j; // } //System.out.println( "fftLength : "+fftLength+"; input "+inputLen+"; flt "+(fltLength.x+fltLength.y)+"; skip "+skip ); fftBuf1 = new float[ fftLength << 1 ]; fftBuf2 = new float[ fftLength << 1 ]; reBuf = new float[ inChanNum ][ fftLength + 2 ]; reOverBuf = new float[ inChanNum ][ fftLength - inputLen ]; if( imOutF != null ) { imBuf = new float[ inChanNum ][ fftLength ]; imOverBuf = new float[ inChanNum ][ fftLength - inputLen ]; } // we design a half-nyquist lp filter and shift it up by that freq. to have a real=>analytic filter // see comp.dsp algorithms-faq Q2.10 fltBox.calcIR( inStream, FIRDesignerDlg.QUAL_VERYGOOD, Filter.WIN_BLACKMAN, fftBuf1, fltLength ); Fourier.realTransform( fftBuf1, fftLength, Fourier.FORWARD ); // ---- "medium"-length sinc-lp convolved with itself produces a sharp and non-overshooting filter! ---- for( i = 0; i <= fftLength; i += 2 ) { j = i + 1; d1 = fftBuf1[ i ]; d2 = fftBuf1[ j ]; fftBuf1[ i ]= (float) (d1*d1 - d2*d2); // complex mult fftBuf1[ j ]= (float) (2*d1*d2); } Fourier.realTransform( fftBuf1, fftLength, Fourier.INVERSE ); // ---- real=>complex + modulation with exp(ismpRate/4 +/- (?) antialias) ---- // k is chosen so that the filter-centre is zero degrees, otherwise we introduce phase shift for( i = fftLength - 1, k = i - fltLength.x, j = fftBuf1.length - 1; i >= 0; i--, k-- ) { d1 = -fltShift * k; fftBuf1[ j-- ] = (float) (fftBuf1[ i ] * Math.sin( d1 )); // img fftBuf1[ j-- ] = (float) (fftBuf1[ i ] * Math.cos( d1 )); // real } Fourier.complexTransform( fftBuf1, fftLength, Fourier.FORWARD ); //for( i = 0; i < fftLength; i++ ) { //reBuf[ 0 ][ i ] = (float) Math.sqrt( fftBuf1[ i<<1 ]*fftBuf1[ i<<1 ]+fftBuf1[ (i<<1)+1 ]*fftBuf1[ (i<<1)+1 ]); //} //Debug.view( reBuf[ 0 ], "hilbert cmplx fft" ); progOff = 0; progLen = (long) inLength * (2 + inChanNum); // normalization requires temp files if( pr.intg[ PR_GAINTYPE ] == GAIN_UNITY ) { reTempFile = new File[ inChanNum ]; reFloatF = new FloatFile[ inChanNum ]; for( ch = 0; ch < inChanNum; ch++ ) { // first zero them because an exception might be thrown reTempFile[ ch ] = null; reFloatF[ ch ] = null; } for( ch = 0; ch < inChanNum; ch++ ) { reTempFile[ ch ] = IOUtil.createTempFile(); reFloatF[ ch ] = new FloatFile( reTempFile[ ch ], GenericFile.MODE_OUTPUT ); } if( imOutF != null ) { imTempFile = new File[ inChanNum ]; imFloatF = new FloatFile[ inChanNum ]; for( ch = 0; ch < inChanNum; ch++ ) { // first zero them because an exception might be thrown imTempFile[ ch ] = null; imFloatF[ ch ] = null; } for( ch = 0; ch < inChanNum; ch++ ) { imTempFile[ ch ] = IOUtil.createTempFile(); imFloatF[ ch ] = new FloatFile( imTempFile[ ch ], GenericFile.MODE_OUTPUT ); } } progLen += (long) inLength; } else { // account for gain loss RealFFT => CmplxIFFT d1 = 2.0; // 0.89 * (double) fftLength; gain = (float) ((Param.transform( pr.para[ PR_GAIN ], Param.ABS_AMP, ampRef, null )).value); } // .... check running .... if( !threadRunning ) break topLevel; // ----==================== the real stuff ====================---- // int b = 0; framesRead = 0; framesWritten = 0; while( threadRunning && (framesWritten < inLength) ) { chunkLength = Math.min( inputLen, inLength - framesRead ); // ---- read input chunk ---- for( off = 0; threadRunning && (off < chunkLength); ) { len = Math.min( 8192, chunkLength - off ); inF.readFrames( reBuf, off, len ); // framesRead += len; progOff += len; off += len; // .... progress .... setProgression( (float) progOff / (float) progLen ); } // .... check running .... if( !threadRunning ) break topLevel; // zero padding for( ch = 0; ch < inChanNum; ch++ ) { convBuf1 = reBuf[ ch ]; for( i = chunkLength; i < convBuf1.length; i++ ) { convBuf1[ i ] = 0.0f; } } for( ch = 0; threadRunning && (ch < inChanNum); ch++ ) { convBuf1 = reBuf[ ch ]; // ---- real fft input + convert to complex + convolve with filter + ifft ---- Fourier.realTransform( convBuf1, fftLength, Fourier.FORWARD ); System.arraycopy( convBuf1, 0, fftBuf2, 0, fftLength ); // pos.freq. via real transform for( i = fftLength, j = fftLength; i > 0; i -= 2, j += 2 ) { // neg.freq. complex conjugate fftBuf2[ j ] = fftBuf2[ i ]; fftBuf2[ j+1 ] = -fftBuf2[ i+1 ]; } Fourier.complexMult( fftBuf1, 0, fftBuf2, 0, fftBuf2, 0, fftLength << 1 ); Fourier.complexTransform( fftBuf2, fftLength, Fourier.INVERSE ); progOff += chunkLength; // .... progress .... setProgression( (float) progOff / (float) progLen ); // .... check running .... if( !threadRunning ) break topLevel; // ---- post proc ---- switch( pr.intg[ PR_MODE ]) { case MODE_UPSHIFT: for( i = 0, j = 0, k = framesRead; i < fftLength; i++ ) { d1 = shiftFreq * k++; convBuf1[ i ] = (float) (fftBuf2[ j++ ] * Math.cos( d1 ) + fftBuf2[ j++ ] * Math.sin( d1 )); } break; case MODE_DOWNSHIFT: for( i = 0, j = 0, k = framesRead; i < fftLength; i++ ) { d1 = shiftFreq * k++; convBuf1[ i ] = (float) (fftBuf2[ j++ ] * Math.cos( d1 ) - fftBuf2[ j++ ] * Math.sin( d1 )); } break; case MODE_ENVELOPE: for( i = 0, j = 0; i < fftLength; i++ ) { d1 = fftBuf2[ j++ ]; d2 = fftBuf2[ j++ ]; convBuf1[ i ] = (float) Math.sqrt( d1*d1 + d2*d2 ); // cos^2 + sin^2 = 1 } break; default: // MODE_UNTOUCHED convBuf2 = imBuf[ ch ]; for( i = 0, j = 0; i < fftLength; i++ ) { convBuf1[ i ] = fftBuf2[ j++ ]; convBuf2[ i ] = fftBuf2[ j++ ]; } break; } } // for channels framesRead += chunkLength; // ---- handle overlaps ---- for( ch = 0; ch < inChanNum; ch++ ) { Util.add( reOverBuf[ ch ], 0, reBuf[ ch ], 0, fftLength - inputLen ); System.arraycopy( reBuf[ ch ], chunkLength, reOverBuf[ ch ], 0, fftLength - inputLen ); if( imBuf != null ) { Util.add( imOverBuf[ ch ], 0, imBuf[ ch ], 0, fftLength - inputLen ); System.arraycopy( imBuf[ ch ], chunkLength, imOverBuf[ ch ], 0, fftLength - inputLen ); } } chunkLength = Math.min( inputLen, inLength - framesWritten ); // ---- write output chunk ---- if( reFloatF != null ) { for( off = skip; threadRunning && (off < chunkLength); ) { len = Math.min( 8192, chunkLength - off ); for( ch = 0; ch < inChanNum; ch++ ) { reFloatF[ ch ].writeFloats( reBuf[ ch ], off, len ); if( imFloatF != null ) { imFloatF[ ch ].writeFloats( imBuf[ ch ], off, len ); } } progOff += len; off += len; framesWritten += len; // .... progress .... setProgression( (float) progOff / (float) progLen ); } } else { for( ch = 0; ch < inChanNum; ch++ ) { Util.mult( reBuf[ ch ], 0, chunkLength, gain ); } for( off = skip; threadRunning && (off < chunkLength); ) { len = Math.min( 8192, chunkLength - off ); reOutF.writeFrames( reBuf, off, len ); if( imOutF != null ) { imOutF.writeFrames( imBuf, off, len ); } progOff += len; off += len; framesWritten += len; // .... progress .... setProgression( (float) progOff / (float) progLen ); } } // .... check running .... if( !threadRunning ) break topLevel; // check max amp for( ch = 0; ch < inChanNum; ch++ ) { convBuf1 = reBuf[ ch ]; for( i = skip; i < chunkLength; i++ ) { f1 = Math.abs( convBuf1[ i ]); if( f1 > maxAmp ) { maxAmp = f1; } } if( imBuf != null ) { convBuf1 = imBuf[ ch ]; for( i = skip; i < chunkLength; i++ ) { f1 = Math.abs( convBuf1[ i ]); if( f1 > maxAmp ) { maxAmp = f1; } } } } if( skip > 0 ) { skip = Math.max( 0, skip - chunkLength ); } } // until framesWritten == outLength // .... check running .... if( !threadRunning ) break topLevel; // ----==================== normalize output ====================---- if( pr.intg[ PR_GAINTYPE ] == GAIN_UNITY ) { peakGain = new Param( (double) maxAmp, Param.ABS_AMP ); gain = (float) (Param.transform( pr.para[ PR_GAIN ], Param.ABS_AMP, new Param( 1.0 / peakGain.value, peakGain.unit ), null )).value; f1 = (imOutF != null) ? ((1.0f + getProgression()) / 2) : 1.0f; normalizeAudioFile( reFloatF, reOutF, reBuf, gain, f1 ); if( imOutF != null ) { normalizeAudioFile( imFloatF, imOutF, reBuf, gain, 1.0f ); } maxAmp *= gain; for( ch = 0; ch < inChanNum; ch++ ) { reFloatF[ ch ].cleanUp(); reFloatF[ ch ] = null; reTempFile[ ch ].delete(); reTempFile[ ch ] = null; if( imFloatF != null ) { imFloatF[ ch ].cleanUp(); imFloatF[ ch ] = null; imTempFile[ ch ].delete(); imTempFile[ ch ] = null; } } } // .... check running .... if( !threadRunning ) break topLevel; // ---- Finish ---- reOutF.close(); reOutF = null; reOutStream = null; if( imOutF != null ) { imOutF.close(); imOutF = null; imOutStream = null; } inF.close(); inF = null; inStream = null; fftBuf1 = null; fftBuf2 = null; reBuf = null; imBuf = null; // inform about clipping/ low level handleClipping( maxAmp ); } catch( IOException e1 ) { setError( e1 ); } catch( OutOfMemoryError e2 ) { inStream = null; reOutStream = null; imOutStream = null; reBuf = null; imBuf = null; fftBuf1 = null; fftBuf2 = null; convBuf1 = null; convBuf2 = null; System.gc(); setError( new Exception( ERR_MEMORY )); } // ---- cleanup (topLevel) ---- if( inF != null ) { inF.cleanUp(); inF = null; } if( reOutF != null ) { reOutF.cleanUp(); reOutF = null; } if( imOutF != null ) { imOutF.cleanUp(); imOutF = null; } if( reFloatF != null ) { for( ch = 0; ch < reFloatF.length; ch++ ) { if( reFloatF[ ch ] != null ) { reFloatF[ ch ].cleanUp(); reFloatF[ ch ] = null; } if( reTempFile[ ch ] != null ) { reTempFile[ ch ].delete(); reTempFile[ ch ] = null; } } } if( imFloatF != null ) { for( ch = 0; ch < imFloatF.length; ch++ ) { if( imFloatF[ ch ] != null ) { imFloatF[ ch ].cleanUp(); imFloatF[ ch ] = null; } if( imTempFile[ ch ] != null ) { imTempFile[ ch ].delete(); imTempFile[ ch ] = null; } } } } // process() protected void reflectPropertyChanges() { super.reflectPropertyChanges(); Component c; boolean b; c = gui.getItemObj( GG_IMOUTPUTFILE ); if( c != null ) { c.setEnabled( pr.intg[ PR_MODE ] == MODE_UNTOUCHED ); } c = gui.getItemObj( GG_FREQ ); b = (pr.intg[ PR_MODE ] == MODE_UPSHIFT) || (pr.intg[ PR_MODE ] == MODE_DOWNSHIFT); if( c != null ) { c.setEnabled( b ); } c = gui.getItemObj( GG_FREQMOD ); if( c != null ) { c.setEnabled( b ); } c = gui.getItemObj( GG_FREQMODDEPTH ); if( c != null ) { c.setEnabled( b && pr.bool[ PR_FREQMOD ]); } c = gui.getItemObj( GG_FREQENV ); if( c != null ) { c.setEnabled( b && pr.bool[ PR_FREQMOD ]); } c = gui.getItemObj( GG_ANTIALIAS ); if( c != null ) { c.setEnabled( b ); } } }